feat(trainer): phase-B body-type classifier — trainer job on the collector host + the classifier stage on the booth
Build & push images / images (push) Successful in 6m31s

apps/trainer (parking-trainer): inspect / train / evaluate / publish. Reads the wash
collector's SQLite + crops read-only off its volume; time split (validation = newest
slice); thin classes dropped; damped class weights; `features` mode (frozen ImageNet
backbone, on-disk feature cache, seconds to retrain) and `finetune` mode (light
augmentation). CPU-only torch from PyTorch's wheel index. ONNX export checked against
the torch model; NO model file below the validation floor (exit 3, report still written);
exit 2 = not enough labels. `evaluate` scores a shipped model on labels reviewed after
training + the unlabelled pile; `publish` PUTs a version folder to a Gitea generic package.
Light core deps; the `train` extra is heavy — CI syncs without it, torch tests skip.

apps/vision: BodyTypeClassifier (bodytype.onnx + sidecar = the preprocessing contract:
crop margin, input size, RGB 0-255, normalisation inside the graph) and
RefinedVehicleDetector over YOLOX — refines only `car` or a class the classifier trained
on, min-confidence, `detector_class` on the result; path set but no file = phase B off
without an error; a broken file is a health detail. models/bodytype.version (tracked,
empty) pins the published version the Dockerfile fetches at build (BuildKit secret;
a pin that cannot be fetched fails the build). Verified: a trainer model gives identical
probabilities inside the vision service; both images built and smoke-tested.

Delivery: parking-trainer image in build-images.yml, the `trainer` compose profile on the
collector stack (CPU, read-only data, TRAINER_OUT), commented TRAINER_OUT/PUBLISH_TOKEN in
the wash-collector stack, .dockerignore for both Python contexts, trainer deps synced in CI.

Wiki: bodytype-classifier-training rewritten as built (+ one fleet model not per site,
secrets/access, where the crops live), opencv-anpr-service §Phase B, vision-review-outbox,
vision-service-packaging, fleet-deployment-komodo, index, log.

Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
2026-09-07 11:14:50 +02:00
parent f9cb973fe9
commit f7a262ac9a
41 changed files with 3797 additions and 76 deletions
+17
View File
@@ -3144,6 +3144,23 @@ run; the Quadro FX 3800 is unusable (cc 1.3), the HD P530 irrelevant, the Xeon E
compose seam drops the GPU reservation; cloud GPU rejected (crops stay on premises). Linked from
[[opencv-anpr-service]], [[vision-review-outbox]], index. User: "No build just yet."
## [2026-09-07] build | Phase B trainer + the classifier stage on the booth
User: "Shall we go and build the trainer for the Xeon?" Built `apps/trainer` (`parking-trainer`:
`inspect` / `train` / `evaluate` / `publish`; reads the collector volume read-only, time split,
thin classes dropped, damped class weights, `features` mode with an on-disk feature cache and
`finetune` mode with light augmentation, CPU-only torch from PyTorch's wheel index, ONNX export
checked against the torch model, **no model file below the floor** — exit 3 with the report; exit
2 = not enough labels), its image + a `.dockerignore`, and the `trainer` compose profile on the
collector stack (CPU, read-only data volume, `TRAINER_OUT`). Vision side: `BodyTypeClassifier` +
`RefinedVehicleDetector` (car or a known class only; min-confidence; `detector_class`; missing
file = off without an error, broken file = health detail), `models/bodytype.version` pin fetched
at build from the Gitea generic package (BuildKit secret; a pin that cannot be fetched fails the
build). The sidecar is the preprocessing contract; verified a trainer model gives identical
probabilities inside the vision service. CI: trainer synced without the `train` extra, torch tests
skip. Tests: trainer 10 (6 in CI mode), vision 18. Pages: [[bodytype-classifier-training]]
rewritten as built, [[opencv-anpr-service]] §Phase B, [[vision-review-outbox]],
[[vision-service-packaging]], [[fleet-deployment-komodo]], index.
## [2026-09-07] ingest | Collector live on park-2; secrets shape, DNS vs bind, token format, CI rule
Deployed: collector on art-docker-station + park-2 at stage-dbbb051, every entry sampled; review
screen filling. Recorded on [[vision-review-outbox]]: one secret per booth referenced by both stacks