u-moec-tiny GUI: Full Training & Evaluation Control Interface
Overhaul the existing Dash-based GUI from a stub-level dashboard into the primary interface for configuring, launching, monitoring, and evaluating the entire u-moec-tiny neural compression pipeline. The GUI must allow users to edit all YAML config parameters, control training (start/stop/resume), monitor live training metrics, inspect MoE routing and MoD gating, visualize activations and hidden-state flow, run compression/decompression jobs, and execute benchmarks with roundtrip verification.
- Python 3.10+ (matching project requirement)
- Dash 2.18+ + dash-bootstrap-components 1.6+ (existing framework)
- Plotly 5.20+ (existing charting)
- Pandas 2.0+ (existing data layer)
- SQLite 3 (existing metrics DB, with new tables)
- PyYAML 6.0+ (config read/write)
Target file: gui/panels/config_panel.py
Replace the minimal 4-field config sidebar with a comprehensive form covering every section of the YAML config. Use dbc.Accordion with the following sections:
- Model — d_model (number), d_state (number), d_conv (number), n_blocks (number), block_pattern (text display, read from YAML), context_len (number)
- MoE — n_routed (number), n_shared (number), top_k (number), d_ff (number), bias_lr (number)
- MoD — enabled (switch), capacity (slider 0-1), gate_kind (dropdown: scalar)
- Early Exit — enabled (switch), blocks (text input "4" or "4,7"), exit_threshold (number 0-1), exit_loss_weight (number)
- Cascade — enabled (switch), threshold (number), d_hidden (number)
- Conditioning — ada_ln_zero (switch), ada_ln_blocks (text "0,1"), cross_attn (switch)
- Patches — primary (number), scales (text "16" or "4,16,64"), multi_token_predict (switch), mtp_weight (number)
- Head — d_globals (number), n_early_exit_heads (number)
- Training — steps (number), batch_size (number), seq_len (number), grad_clip (number), warmup_steps (number), cosine_schedule (switch), precision (dropdown: bf16, bf16+fp8)
- Optimizer Muon — lr (number), momentum (number), ns_steps (number)
- Optimizer AdamW — lr (number), betas (text "0.9,0.95"), weight_decay (number)
- Loss — ce_weight (number), mtp_weight (number)
- Data — pack_documents (switch), seed (number)
- LoRA — enabled (switch), rank (number), alpha (number), target (dropdown: routed/all), trigger_bytes (number), adapt_steps (number), adapt_lr (number)
- Entropy — coder (dropdown: rans/tans), block_size (number), precision (number), prob_precision (number), probability_sharpening (switch)
- Logging — log_every (number), eval_every (number), save_every (number)
- Hardware — gpus (number), compile (switch)
Additional controls:
- Tier dropdown (existing, keep at top)
- Component checklist (existing, keep for quick toggles)
- "Load Config" button: opens a text input for a YAML file path, reads it, and populates all form fields
- "Save Config" button: writes current form state to a user-specified YAML file path
- "Reset to Default" button: reloads the selected tier's default YAML
- All form fields should have IDs like
config-model-d-model,config-moe-n-routed, etc. - The existing
config-start-btn,config-stop-btn, andconfig-statusmust remain
Target files: gui/panels/training_panel.py, gui/db.py
- Wire
training_panel.kpis()into the refresh callback. Add adcc.Graphorhtml.Divwith id="training-kpi-cards" to the layout, and in the refresh callback compute the KPIs from the latest metrics row. - Add ETA display:
html.Div(id="training-eta")showing estimated time remaining based on(target_steps - current_step) / throughput - Add checkpoint browser:
html.Div(id="checkpoint-list")— scan the checkpoint directory forstep*.ptfiles, display as a list with step number and file size - Add resume-from-checkpoint:
dcc.Dropdown(id="resume-checkpoint")+ buttonid="resume-btn" - Add live log tail:
html.Pre(id="training-log-tail", style={"maxHeight": "300px", "overflowY": "auto", "fontSize": "11px"})— read last 100 lines oftraining.logeach refresh cycle - Add per-head loss table:
html.Div(id="training-head-losses")— small table showing current loss for final, exit_4, etc.
Target files: gui/panels/routing_panel.py, gui/viz_utils.py, gui/db.py
- Populate
routing-bias-historygraph with time-series data fromdb.moe_routing_history(). Createviz_utils.moe_routing_history_fig()that plots expert load over time for all experts (line chart). - Add load-balance metrics: compute Gini coefficient =
1 - 2 * sum(cumsum(sorted(load)) / sum(load)) / nand max/min ratio for each logged step, plot over time. Createviz_utils.load_balance_fig(). - Add click-to-drill-down on heatmap: use
clickDatafromrouting-heatmapto show a single expert's load over time. Add a new graphid="routing-expert-detail".
Target files: gui/panels/mod_panel.py, gui/viz_utils.py
- Replace "TBD"
mod-historywith a proper time-series. Createviz_utils.mod_gate_history_fig()that reads fromdb.mod_gates_history()and plotsfraction_processedper block over training steps. - Add capacity utilization line: overlay target capacity as a dashed horizontal line.
- Add metric cards: average fraction processed, deviation from capacity.
Target files: bin/train.py, bin/simulate_training.py, gui/db.py, gui/panels/activations_panel.py, gui/panels/brain_panel.py
New DB tables:
activation_stats(step INTEGER, block_idx INTEGER, mean REAL, std REAL,
p1 REAL, p25 REAL, p50 REAL, p75 REAL, p99 REAL,
PRIMARY KEY (step, block_idx));
hidden_states(step INTEGER, block_idx INTEGER, sample_idx INTEGER,
pc1 REAL, pc2 REAL,
PRIMARY KEY (step, block_idx, sample_idx));Trainer changes (bin/train.py):
- Add
insert_activation_stat()andinsert_hidden_state()toTrainingDB - Every
eval_everysteps, on a single batch withtorch.no_grad():- Run a forward pass
- For each block, detach the hidden state, compute per-block activation stats (mean, std, percentiles) on CPU, write to
activation_stats - For a sample of 200 tokens per block (or all if fewer), PCA-project the hidden states to 2D (use SVD of centered data), write to
hidden_states
Simulate training changes (bin/simulate_training.py):
- Every
log_everysteps, generate syntheticactivation_statsrows with realistic distributions (mean ~1.0, std ~0.3, with slight variation per block) - Every
log_every * 5steps, generate synthetichidden_statesrows (2D Gaussian clusters per block, with block 0 being a single cluster and later blocks separating into sub-clusters)
DB queries (gui/db.py):
activation_stats_at(conn, step=None)— returns DataFrame of activation stats for latest or given stephidden_states_at(conn, step=None)— returns DataFrame of hidden states for latest or given step
Panel wiring:
- Activations panel: add callback on refresh-interval that reads
activation_stats_at(), feeds toactivation_dist_fig()andactivation_heatmap_fig() - Brain panel: add callback on refresh-interval that reads
hidden_states_at(), feeds topca_fig()
Target files: gui/panels/compression_panel.py, new gui/panels/eval_panel.py, gui/db.py, gui/viz_utils.py
Compression Panel:
- File path input:
dcc.Input(id="compress-file-path", type="text", placeholder="/path/to/file.bin") - File upload:
dcc.Upload(id="compress-file-upload")— stores uploaded file in/tmp/u-moec-uploads/ - Profile selector:
dcc.Dropdown(id="compress-profile", options=["turbo", "fast", "balanced"], value="turbo") - Checkpoint selector:
dcc.Dropdown(id="compress-checkpoint")— populated from checkpoint dir scan - "Compress" button:
html.Button("Compress", id="compress-btn")— runspython -m bin.compress {input} {output}.umc --config {config} --checkpoint {ckpt} --profile {profile}via subprocess - Results table:
html.Table(id="compression-results-table")with columns: File, Raw Size, Compressed Size, Ratio, Time - Comparison row: run
gzip -candzstd -22on the same file (if available), show their sizes - "Decompress & Verify" button:
html.Button("Verify Roundtrip", id="compress-verify-btn")— runs decompress, then sha256sum compare - Roundtrip result:
html.Div(id="compress-verify-result")showing "PASS" (green) or "FAIL" (red)
New compression_jobs DB table:
compression_jobs(job_id INTEGER PRIMARY KEY AUTOINCREMENT,
ts REAL, input_path TEXT, output_path TEXT,
profile TEXT, checkpoint TEXT, status TEXT,
raw_bytes INTEGER, compressed_bytes INTEGER, elapsed_s REAL);Evaluation Panel (new tab):
- "Run enwik8 benchmark" button:
html.Button("Run enwik8 Eval", id="eval-enwik8-btn")— runs./scripts/eval_enwik8.shor equivalent via subprocess - Results table:
html.Table(id="eval-results-table")— columns: Step, Dataset, BPB, Model Size, vs gzip (2.7), vs zstd-22 (1.95), vs CMIX (1.23), Delta from CMIX - Roundtrip verification status:
html.Div(id="eval-roundtrip-status")— shows PASS/FAIL - Historical chart:
dcc.Graph(id="eval-bpb-history")— bpb over evaluations, with reference lines
New eval_results DB table:
eval_results(step INTEGER, ts REAL, dataset TEXT, bpb REAL,
compressed_bytes INTEGER, original_bytes INTEGER,
roundtrip_ok INTEGER, PRIMARY KEY (step, dataset));Simulate training changes:
- Write synthetic eval_results: bpb decreasing toward target, roundtrip_ok=1
Target files: gui/callbacks/__init__.py, new callback modules, gui/app.py
New callback modules (one per tab, each with a register_callbacks(app) function):
gui/callbacks/training_callbacks.py— refresh charts, KPI cards, log tail, ETA, checkpoint listgui/callbacks/arch_callbacks.py— architecture diagram update on tier changegui/callbacks/routing_callbacks.py— heatmap, bias history, expert drill-down, load balancegui/callbacks/mod_callbacks.py— current MoD, historygui/callbacks/activation_callbacks.py— activation dist + heatmapgui/callbacks/brain_callbacks.py— PCA visualizationgui/callbacks/compression_callbacks.py— compress/decompress/verifygui/callbacks/eval_callbacks.py— benchmark running, results displaygui/callbacks/growth_callbacks.py— growth slidersgui/callbacks/config_callbacks.py— config CRUD, training start/stop/resume, export/import
gui/callbacks/__init__.py:
from .training_callbacks import register as reg_training
from .arch_callbacks import register as reg_arch
# ... etc
def register_all_callbacks(app):
for reg in [reg_training, reg_arch, reg_routing, reg_mod,
reg_activation, reg_brain, reg_compression, reg_eval,
reg_growth, reg_config]:
reg(app)gui/app.py simplification:
- Build layout (same structure, add new Evaluation tab)
- Call
register_all_callbacks(app) - Run server
- No inline callback definitions
Error handling:
- All DB reads:
try/exceptwithhtml.Div(f"Error: {e}", className="text-danger")returns - All subprocess calls: catch
FileNotFoundError,subprocess.TimeoutExpired, non-zero return codes - Display errors in status divs
Process health monitoring:
- In
config_callbacks.py, checktraining_process.poll()each refresh cycle - If process has exited with non-zero code, update status to "Crashed (exit code N)"
- If process has exited with code 0, update status to "Completed"
-- Activation statistics per block (periodic snapshots)
CREATE TABLE IF NOT EXISTS activation_stats (
step INTEGER, block_idx INTEGER,
mean REAL, std REAL,
p1 REAL, p25 REAL, p50 REAL, p75 REAL, p99 REAL,
PRIMARY KEY (step, block_idx)
);
-- PCA-projected hidden states for brain visualization
CREATE TABLE IF NOT EXISTS hidden_states (
step INTEGER, block_idx INTEGER, sample_idx INTEGER,
pc1 REAL, pc2 REAL,
PRIMARY KEY (step, block_idx, sample_idx)
);
-- Evaluation results
CREATE TABLE IF NOT EXISTS eval_results (
step INTEGER, ts REAL, dataset TEXT,
bpb REAL, compressed_bytes INTEGER, original_bytes INTEGER,
roundtrip_ok INTEGER,
PRIMARY KEY (step, dataset)
);
-- Compression job history
CREATE TABLE IF NOT EXISTS compression_jobs (
job_id INTEGER PRIMARY KEY AUTOINCREMENT,
ts REAL, input_path TEXT, output_path TEXT,
profile TEXT, checkpoint TEXT, status TEXT,
raw_bytes INTEGER, compressed_bytes INTEGER, elapsed_s REAL
);moe_routing_history_fig(routing_history_df)— multi-line time series of expert loadsload_balance_fig(routing_history_df)— Gini coefficient + max/min ratio over timemod_gate_history_fig(gates_history_df)— fraction_processed per block over timecompression_comparison_fig(jobs_df)— bar chart comparing compressed sizeseval_bpb_history_fig(eval_df)— bpb over evaluations with reference lines
Add new tab to the dbc.Tabs in app.py:
dbc.Tab(eval_panel.layout(), label="🏆 Evaluation", tab_id="tab-eval"),gui/
├── app.py (simplified: layout + callback registration only)
├── db.py (expanded: new table queries)
├── viz_utils.py (expanded: 5 new figure functions)
├── requirements.txt (unchanged)
├── callbacks/
│ ├── __init__.py (rewrite: import and register all)
│ ├── training_callbacks.py (new: refresh, KPIs, ETA, log tail, checkpoints)
│ ├── arch_callbacks.py (new: architecture diagram)
│ ├── routing_callbacks.py (new: heatmap, history, drill-down, balance)
│ ├── mod_callbacks.py (new: current + history)
│ ├── activation_callbacks.py (new: activation dist + heatmap)
│ ├── brain_callbacks.py (new: PCA visualization)
│ ├── compression_callbacks.py (new: compress/decompress/verify)
│ ├── eval_callbacks.py (new: benchmark running + results)
│ ├── growth_callbacks.py (new: growth sliders)
│ └── config_callbacks.py (new: config CRUD, start/stop/resume)
└── panels/
├── __init__.py (update: add eval_panel)
├── config_panel.py (major rewrite)
├── training_panel.py (expand: KPIs, ETA, checkpoint, log, head losses)
├── architecture_panel.py (minor: cleanup)
├── routing_panel.py (expand: add history, detail, balance)
├── mod_panel.py (expand: history, metrics)
├── activations_panel.py (minor: already has good layout)
├── brain_panel.py (minor: already has good layout)
├── compression_panel.py (major rewrite: full compression UX)
├── eval_panel.py (NEW: evaluation tab)
└── growth_panel.py (minor: cleanup)
- Config sidebar: every field from tier1_micro.yaml is editable; Load/Save/Reset work
- Training control: Start launches training, Stop kills it, Resume restarts from checkpoint; sidebar values propagate to CLI args
- Training panel: KPI cards render, ETA shows, log tail updates, checkpoint list populates
- Routing panel: heatmap + history + drill-down + balance plots all render with data
- MoD panel: current + history both render with real time-series data
- Activations panel: dist + heatmap render from DB data
- Brain panel: PCA scatter renders from DB data
- Compression panel: file path input + upload; compress runs; results table shows; verify works
- Evaluation panel: enwik8 eval button works; results table renders; roundtrip status shows
- All callbacks in separate modules; app.py has no inline callbacks
- Error handling: DB errors, subprocess errors, missing files all show user-visible messages
- Process health: crashed/completed training shows correct status
python -m bin.simulate_training --steps 5000populates ALL new tablespython gui/app.pystarts without error and all tabs render