{ "schema_version": "1.0.0", "note": "The single source of truth for pixel handling. scripts/build_frame_dataset.py, scripts/train.py, src/organscan/preprocess.py and the exported ONNX graph all read this file, and scripts/export_onnx.py copies it into models/ so the shipped artifact carries its own contract. If training and serving ever disagree about normalisation, the model silently loses several points and nothing errors - hence one file, not four constants.", "input_name": "pixel_values", "dtype": "float32", "dtype_note": "float32 in, even for the INT8 model. Static quantization inserts QuantizeLinear at the graph head; handing it uint8 is a silent accuracy loss.", "layout": "NCHW", "channels": 3, "channels_note": "Always 3. Grayscale B-mode replicates across channels; colour Doppler uses them for real.", "image_size": 224, "dynamic_axes": { "batch": 0 }, "spatial_dims_fixed": true, "spatial_dims_note": "H and W are fixed at 224. Dynamic spatial dims block ORT/NNAPI kernel selection and cost real latency on edge hardware.", "pipeline": [ { "step": 1, "op": "decode", "detail": "Honour TransferSyntaxUID. Multi-frame ultrasound is sampled by temporal stride, never frame-by-frame." }, { "step": 2, "op": "photometric", "detail": "Invert when PhotometricInterpretation == MONOCHROME1." }, { "step": 3, "op": "crop_scan_region", "detail": "Ultrasound: crop to SequenceOfUltrasoundRegions (0018,6011) RegionLocationMinX0/MinY0/MaxX1/MaxY1. Non-negotiable - vendor UI text often reads the organ name outright." }, { "step": 4, "op": "intensity", "detail": "US is already 8-bit. CT/MR apply RescaleSlope/RescaleIntercept, then the fixed window below." }, { "step": 5, "op": "resize", "detail": "Shortest side to 224, bilinear, antialias on." }, { "step": 6, "op": "center_crop", "detail": "224 x 224." }, { "step": 7, "op": "to_float", "detail": "Divide by 255 into [0, 1]." }, { "step": 8, "op": "normalize", "detail": "Subtract mean, divide by std." }, { "step": 9, "op": "layout", "detail": "HWC -> CHW, stack to [B, 3, 224, 224]." } ], "resize": { "shortest_side": 224, "interpolation": "bilinear", "antialias": true }, "center_crop": 224, "rescale_factor": 0.00392156862745098, "image_mean": [0.485, 0.456, 0.406], "image_std": [0.229, 0.224, 0.225], "normalization_note": "ImageNet statistics, because the student is ImageNet-initialised. scripts/export_onnx.py re-reads the chosen timm config at export time and fails if it disagrees with these values rather than letting them drift.", "ct_windows": { "note": "Fixed window per region, applied to Hounsfield units after rescale. `pseudo_rgb` stacks three windows into the three channels instead of replicating one - free accuracy on CT, and the reason channels is 3 rather than 1.", "default": { "center": 40, "width": 400 }, "abdomen": { "center": 40, "width": 400 }, "chest": { "center": -600, "width": 1500 }, "head": { "center": 40, "width": 80 }, "extremity": { "center": 300, "width": 1500 }, "pseudo_rgb": { "enabled": true, "channels": [ { "center": 40, "width": 400, "label": "soft_tissue" }, { "center": -600, "width": 1500, "label": "lung" }, { "center": 300, "width": 1500, "label": "bone" } ] } }, "mr_intensity": { "note": "MR has no absolute scale, so a fixed window is meaningless. Percentile clip then min-max into [0,1].", "clip_percentiles": [0.5, 99.5] }, "ultrasound": { "require_region_crop": true, "require_region_crop_note": "A US frame without a successful region crop is rejected by scripts/build_frame_dataset.py rather than used. Burned-in annotation is a label leak that produces a 99% model which fails on every other scanner (plan section 8.1).", "frames_per_loop": { "min": 5, "max": 20, "selection": "temporal_stride" } }, "train_augmentation": { "note": "Deliberately mild. Anatomy classification is left/right sensitive - a horizontal flip turns KIDNEY_LEFT into KIDNEY_RIGHT, so it is off everywhere.", "horizontal_flip": 0.0, "horizontal_flip_note": "Zero, permanently. Enabling it silently destroys every laterality label in the corpus.", "vertical_flip": 0.0, "random_resized_crop": { "enabled": true, "scale": [0.7, 1.0], "ratio": [0.85, 1.18] }, "rotation_degrees": 10, "brightness": 0.2, "contrast": 0.2, "gamma": [0.8, 1.25], "gaussian_noise_std": 0.02, "speckle_noise": { "enabled": true, "modalities": ["US"], "std": 0.05 }, "random_erasing": 0.1 } }