cellmap_flow.finetune.distill
Distill a finetuned model into a small copy the browser can run, and export the copy for the browser.
The large cellmap UNets (about 800M parameters, 3.2 GB, such as
mito-aff-unet-setup-16) are too big for a browser to load, and export_web
gives them no browser form. This trains a small network to compute what a
finetuned model’s network computes, and exports it as export_web exports a
model’s browser form. The network surgery is cellmap-models’ (its
distill_student); this is the job around it:
The teacher is the network the serving YAML serves, as export_web builds it (
export_web.finetuned_network): the base as the trainer builds it, the finetune folded in, every layer a real one.The student is cellmap-models’
distill_student: for a funlib UNet (whatprune_funlib_unetcovers, such as the cellmap StandardUnets) the same network with fewer channels at every level, started from the teacher’s strongest channels (init“pruned”); for any other network (ResUNet, Unet3dIso…) a fly_organelles StandardUnet with the teacher’s channels and output activation, started at random (init“random”), at the largest block whose output fits inside the teacher’s. A random start has more to learn, so it gets more epochs and hours by default.The distillation trains the student to reproduce the teacher’s output as the network emits it, the mean squared difference over every voxel and channel (losses.distillation_loss, the finetune’s teacher term), on blocks of the raw the model was finetuned on, read and normalized as the trainer reads its patches (data.loader.dataset_from_manifest): half centred on what was annotated, half at random points of the volume. It needs no annotations. Each block is read large enough for both networks’ inputs; both read and write around the same centre, as the inference runner places a model’s output in the middle of what it reads (ModelGeometry.context), so the teacher’s input and the student’s are the middle of the block, and the student’s target is the middle of the teacher’s output. Squared difference of the raw output because the output may be logits, affinities or distances, which the network cannot tell apart (probe_output_class calls all three unbounded): what is used downstream of affinities and distances is their value, every level of it (watershed and agglomeration thresholds, distance cut-offs), and a student that matches the values matches any threshold or postprocessing on them, logits’ included. A sigmoid’s cross-entropy would read distances as logits and stop caring where both are far from 0. Adam takes the loss’s scale out of its steps, so logits of about 5 or about 1400 (export_merged’s finetunes) train alike.
It runs on the GPU when there is one (utils.device.best_device), the training steps in mixed precision (trainer.recovery.Precision: bf16 where the GPU has it), the held-out comparison in float32 with TF32 off, so that its numbers are the networks’ own.
How close: on held-out blocks drawn apart from the training’s, cellmap-models’
output_differenceof the student from the teacher (the export’s metrics: the mean squared, mean and largest absolute difference, and the share of voxels on the other side of the model’s decision boundary, 0.5 for a model that ends in a sigmoid and else 0, as portable.label_it.probability reads it), for the start and for the student exported.
What it writes in <output>:
<folder>-small/manifest.jsonand its ONNX files, as export_web writes a model’s browser form (<folder>is export_web’s folder for the finetuned model), with adistillationblock: the teacher’s folder (so that a publish can say “distilled from” its ref), the teacher’s parameters, the student’sinit, num_fmaps and fmap_inc_factor, the steps it trained, and the held-out closeness of thestartand of the student (distilled);student_best.pt: the best student so far, written each time the held-out difference improves, so a job killed before it exports keeps it; a run that makes the same student continues from it;result.jsonandexport_log.txt, as export_web’s:{"folder", "manifest"}or{"error"}, also printed as the output’s last line.
The progress lines are the trainer’s, “Starting epoch N of M” and “Epoch N/M - Loss: …” (markers’ patterns), each epoch’s with the held-out closeness after it.
The dashboard starts it and follows it as an export, with export_web’s
export_status:
run = start_distill(yaml_path, corrections_dir, run_dir)
export_web.export_status(run) # the answer start_export's gets
start_distill submits the job as start_export does (export_web.start_job:
in the environment the model finetunes in, on its YAML’s queue), into
<run_dir>/web_export/<YAML's name>-small/, with the training’s time
limit (the longer, a random start’s, unless given) and an hour for the rest
as its walltime, and returns at once. From the command line:
python -m cellmap_flow.finetune.distill --yaml <serving yaml> \
--corrections <session>/corrections --output <dir> \
[--parameters 12000000] [--epochs 100] [--steps-per-epoch 100] [--hours 3]
The student’s size: at most --parameters, by default a tenth of the
teacher’s and no more than BROWSER_PARAMETERS, about what the browser
catalog’s largest models have (distill_student says how the widths are
chosen). For mito-aff-unet-setup-16 (792M parameters) that is num_fmaps 13
and fmap_inc_factor 3, 10.8M parameters, 43 MB in fp32.
A 2D model (a block one z-slice thick) gets a 2D student (distill_student’s 1x3x3 kernels and 1x2x2 pooling), trained and exported on slices. The browser copy is exported at the block the student trained at and, for a StandardUnet student, at the larger blocks it computes too (BROWSER_SIDES, cellmap-models’ Student.blocks), each checked against the student on real raw.
What it refuses, before it trains: a model that writes at another voxel size than it reads (the student writes at the voxel size it reads); one that takes more than one input channel (the browser feeds one); a teacher served other than by its network’s forward (Cellpose); and a teacher whose output block holds no StandardUnet block.
Needs cellmap-models with model_export.student and model_export.onnx_web
(the pin in pixi.toml’s finetune feature) and its export extra, onnx and
onnxruntime, where it runs.
Attributes
Functions
|
cellmap-models' student of |
|
How far |
|
Distill the model |
|
Start distilling the model |
|
Module Contents
- cellmap_flow.finetune.distill.logger
- cellmap_flow.finetune.distill.MODULE = 'cellmap_flow.finetune.distill'
- cellmap_flow.finetune.distill.CHECKPOINT_NAME = 'student_best.pt'
- cellmap_flow.finetune.distill.BROWSER_PARAMETERS = 12000000
- cellmap_flow.finetune.distill.TEACHER_SHARE = 0.1
- cellmap_flow.finetune.distill.RANDOM_SHARE = 0.5
- cellmap_flow.finetune.distill.HELD_OUT_BLOCKS = 8
- cellmap_flow.finetune.distill.HELD_OUT_SEED = 1000000007
- cellmap_flow.finetune.distill.EPOCHS
- cellmap_flow.finetune.distill.HOURS
- cellmap_flow.finetune.distill.STEPS_PER_EPOCH = 100
- cellmap_flow.finetune.distill.LEARNING_RATE = 0.0001
- cellmap_flow.finetune.distill.WORKERS = 4
- cellmap_flow.finetune.distill.BROWSER_SIDES
- cellmap_flow.finetune.distill.SETUP_HOURS = 1.0
- cellmap_flow.finetune.distill.make_student(teacher, geometry, out_channels, output_class, parameters=None)
cellmap-models’ student of
teacher(itsStudent), for the model ofgeometry, whose output hasout_channelschannels and is ofoutput_class(probe_output_class): at mostparametersparameters, by default a tenth of the teacher’s and at most BROWSER_PARAMETERS.- Raises:
ValueError – no student is that small, or one that large would not fit an .onnx file, or no StandardUnet block fits in the teacher’s.
- cellmap_flow.finetune.distill.closeness(network, blocks, targets, input_size, threshold: float) dict
How far
network’s output onblocks(the middleinput_sizeof each) is fromtargets, the teacher’s: cellmap-models’ output_difference (mse,mean_abs,max_abs,flip_fraconthreshold) over all of them, computed in float32 with TF32 off.
- cellmap_flow.finetune.distill.distill(yaml_path, corrections_dir, output_dir, *, parameters=None, epochs=None, steps_per_epoch=STEPS_PER_EPOCH, hours=None, learning_rate=LEARNING_RATE, workers=WORKERS, variants=None) dict
Distill the model
yaml_pathserves into a small copy and export it intooutput_dir;{"folder", "manifest"}(see the module’s docstring).Trains for
epochsofsteps_per_epochblocks, or untilhourshave passed, whichever is first (by default EPOCHS and HOURS of how the student starts), and exports the student that came closest to the teacher on the held-out blocks.- Raises:
ValueError – the model is one this cannot distill or export (see the module’s docstring), or its session has no training manifest.
- cellmap_flow.finetune.distill.start_distill(yaml_path, corrections_dir, run_dir, *, parameters=None, hours=None) cellmap_flow.finetune.export_web.WebExport
Start distilling the model
yaml_pathserves, trained on the sessioncorrections_dir, into<run_dir>/web_export/<YAML's name>-small/; follow it with export_web.export_status.parameters: the student’s largest size (by default make_student’s);hours: the training’s time limit (by default HOURS of how the student starts, which the job decides; the walltime allows the longer). The job runs as start_export’s does (export_web.start_job), in the environment the model finetunes in on the YAML’s queue and charge group, and a result an earlier run left there is removed first, so that export_status does not read it as this one’s; its best student is kept, for this run to continue from.- Raises:
ValueError – the YAML serves no finetuned model, or its environment cannot run the job.
RuntimeError – the job could not be submitted.
- cellmap_flow.finetune.distill.main(argv=None) int