es-ude / es-ude/OnDeviceTraining
examples: run-log completeness follow-ups (2026-07-28 log audit)
- Dominant language
- C
- Stars
- 1
- Forks
- 3
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 8
Description
Collective issue for the side findings of the 2026-07-28 example run-log audit (the audit's value bugs are fixed on the `examples-log-audit` branch). None of these is a wrong-value bug; they are completeness/robustness gaps in what the logs record.
## Findings
1. **`step_losses` is always an empty literal in every C emitter** (`har_classifier/train_c.c:272`, `train_c_sym.c`, `train_c_adamw.c`, `train_c_finetune.c`, `mnist_mlp`, `mnist_cnn`, `kws_mfcc`, `kws_raw`, `ecg_anomaly_ae`). The real per-step losses are computed and discarded; the PyTorch twins fill real values. Step-level cross-impl comparison is impossible today. Either collect them (needs a per-batch hook or buffer in the epoch callback path) or document the key as PyTorch-only.
2. **Default log-path collision**: `har_classifier/train_c.c` and `train_c_adamw.c` both default to `logs/c.json`. Running both without `LOG_PATH` silently clobbers the SGD log with the AdamW one; only the `impl` field reveals which survived. Give the AdamW binary its own default (e.g. `logs/c_adamw.json`).
3. **AdamW hyperparameters not logged**: `kBeta1`/`kBeta2`/`kEps` (`train_c_adamw.c:77`) are real run hyperparameters with no config record — a log cannot be reconstructed if the constants ever change. Schema has no keys for them; add `betas`/`eps` as NotRequired keys on both sides.
4. **`KWS_CLASSES` only path-encoded**: both `kws_mfcc` and `kws_raw` (C and Python sides) encode the 6-vs-35-class arm only in the log *path* (`logs/class/…`), not in the config block. A moved/renamed log loses its identity.
5. **sym config block lacks the sweep arms**: `train_c_sym.c` records neither `SYM_ROUNDING` (SR vs deterministic write-back, the #279 A/B variable) nor `SYM_WIRES` (#206) in config — run identity for `sym8` vs `sym8det` vs `sym8w` rests solely on the run_matrix.py filename, and run_matrix's resume-identity check (config `epochs`+`seed`) doesn't include the arm either.
6. **continual `exemplar_state_bytes_per_class` is a hand-computed formula** (`train_c_continual.c:540`): `exemplars*D*sizeof(float) + sizeof(uint32_t)` counts raw payload only and silently diverges if the `ExemplarBuffer` layout changes. Derive it from the live buffer (like `ppcaReplayBytes` does for PPCA mode) or add a comment-anchored static assert tying it to the struct.
## Seen and deliberately left as-is
- `train_c_finetune.c` / `train_c_continual.c` log shapes deviate from `log_schema.py` (stage-keyed config/final, no epochs/final block) — deliberate, they have their own comparators and never match the sweep globs.
- sym per-epoch `lr` prints `%.8f` — cosmetic precision floor at 1e-8, irrelevant at current LR ranges.
Contributor guide
Research direction
Start with the six findings and the named entry points, including har_classifier/train_c.c, train_c_adamw.c, train_c_sym.c, train_c_continual.c, log_schema.py, and run_matrix.py; compare the C and PyTorch logging paths and existing schema handling. Done means each completeness or collision gap is fixed or explicitly documented, with run identity and log contents remaining unambiguous across the affected examples.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, python
- Domain
- machine-learning, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100