docs(wiki): phase B training path and hardware decisions — recorded, not built
Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: Body-type classifier (phase B) — training path and hardware
|
||||
type: decision
|
||||
status: decided 2026-09-07; NOT built (user: "no build just yet")
|
||||
related: [vision-review-outbox, opencv-anpr-service, venue-modules, fleet-deployment-komodo, technology-stack]
|
||||
---
|
||||
|
||||
# Body-type classifier (phase B) — training path and hardware
|
||||
|
||||
The Car Wash category suggestion needs SUV vs sedan, which the phase-A COCO detector cannot give
|
||||
([[opencv-anpr-service]] §Vehicle body type). Phase B is a **classifier over the detector's crop**,
|
||||
trained on the reviewer's labels gathered through the [[vision-review-outbox]]. This page records
|
||||
what the loop looks like, what it runs on, and what is deliberately not done. Discussed and decided
|
||||
with the user on 2026-09-07; **nothing here is built yet** — the user will say when.
|
||||
|
||||
## The loop (as designed)
|
||||
|
||||
Today the loop stops at the reviewer's verdict: the collector holds labels + crops and can export
|
||||
`labels.csv`. Nothing trains, nothing updates a booth. The rest of the path, each step a place
|
||||
where a person decides:
|
||||
|
||||
1. **Train** — a one-off job (`apps/trainer`, Python/uv like the vision service) on the
|
||||
collector's host reads the export and the crops straight off the collector volume, splits by
|
||||
TIME (validation = newer cars than training, so the number reflects tomorrow's traffic), and
|
||||
fine-tunes a small **BSD-licensed torchvision backbone** (the licence rule applies to weights as
|
||||
much as code; timm/ImageNet weights only if their terms are checked). Outputs three files: the
|
||||
ONNX classifier, a sidecar (class list, preprocessing constants, version), and a metrics report
|
||||
(accuracy per class + confusion matrix). It **refuses to write the model** below a validation
|
||||
floor the owner sets — a bad model never becomes a file. Class imbalance (nine sedans in ten)
|
||||
is weighted in the loss and reported; classes with too few labels are dropped from that run.
|
||||
2. **Evaluate before anything ships** — the owner reads the report. 85–95 % on frontal gate views
|
||||
is the expectation once tuned; enough to *flag*, never to *bill* (the flag records, the site
|
||||
threshold exists for exactly this).
|
||||
3. **Publish** — weights are not code and do not live in git: a versioned file in the Gitea
|
||||
package registry / a release asset, fetched by URL like the YOLOX weights.
|
||||
4. **Bake and build** — the vision Dockerfile fetches that version at build time; a second stage in
|
||||
`vehicle.py` runs the classifier on the detector's box and replaces `car` with the finer class
|
||||
when confident, else keeps YOLOX's answer. One model path setting like the YOLOX one; off when
|
||||
unset. The contract, the mapping chips and the flag do not change — the vocabulary already holds
|
||||
sedan/hatchback/suv/minivan/pickup.
|
||||
5. **Deploy** — a TAG bump on the booth's stack. **A booth gets a model the way it gets code**: a
|
||||
pinned release you can see and roll back. No runtime model fetch (air-gapped appliance,
|
||||
read-only model path — [[vision-service-hardening]]).
|
||||
|
||||
Retrain when the labels have grown meaningfully (every few hundred new verdicts at first). First
|
||||
run needs roughly **200 reviewed crops per class that matters** (Vetura and SUV at least). Once a
|
||||
model exists, its predictions on the *unlabelled* pile checked against a small reviewed sample are
|
||||
the ongoing accuracy check without labelling everything — which is why every entry is sent, not a
|
||||
sample ([[vision-review-outbox]] §The entry stream).
|
||||
|
||||
## Hardware (decided 2026-09-07)
|
||||
|
||||
What the owner has: an **NVIDIA Quadro FX 3800** (in hand, not installed), and in
|
||||
`art-docker-station` an **Intel Xeon E3-1225 v5** (4 Skylake cores, AVX2, no AVX-512) with the
|
||||
**Intel HD P530** iGPU.
|
||||
|
||||
- **Quadro FX 3800 — stays in the drawer.** 2009, GT200, compute capability 1.3, 1 GB. CUDA dropped
|
||||
that generation in 2015; no PyTorch build of the last decade can use it. Installing it buys a
|
||||
heater and a driver problem.
|
||||
- **HD P530 — not for training.** Usable for *inference* via OpenVINO, irrelevant here: inference
|
||||
runs on the booths' CPUs, which already do YOLOX in ~250 ms.
|
||||
- **The Xeon does the job.** The problem is small (a few thousand 224-px crops, ten classes, a
|
||||
small pretrained backbone). Two modes the trainer should offer:
|
||||
- *Feature extraction + a small head* — run every crop once through the frozen backbone, cache
|
||||
the feature vectors, train a classifier on top: minutes for a few thousand crops, seconds to
|
||||
retrain when labels arrive. Expected to carry most of the accuracy on frontal gate views.
|
||||
- *Full fine-tune* — unfreeze and train end to end: roughly an hour per run on four cores with
|
||||
a mobile-sized backbone. The step to take when the cheap mode plateaus.
|
||||
Training is occasional and unattended, so an hour on a CPU is a non-issue; the data is already
|
||||
on that host, so nothing moves.
|
||||
- **Consequences for the build:** the trainer image is **CPU-only PyTorch** (< 1 GB, not the 5 GB
|
||||
CUDA build); the `trainer` seam in `docker-compose.collector.yml` drops the NVIDIA device
|
||||
reservation (one-line change if a modern card ever lands in the host; the trainer should pick
|
||||
up CUDA when present).
|
||||
- **If faster is ever wanted:** a used mid-range card of the last few generations (~€200) turns
|
||||
the hour into a minute, given a slot and a PSU. **Renting a cloud GPU is rejected**: the crops
|
||||
would leave the premises, and even scrubbed of plates and site that runs against the whole
|
||||
privacy design of the outbox.
|
||||
|
||||
## Not built
|
||||
|
||||
`apps/trainer`, the classifier stage in `vehicle.py`, the publish step, the compose `trainer`
|
||||
profile (still commented, still with the GPU reservation to remove). First real run waits for
|
||||
the first few hundred reviewed labels on the collector.
|
||||
Reference in New Issue
Block a user