Movies over changing inputs¶
animate_inputs renders the cinematic flow once per input and writes an MP4 (or GIF). The point
of a movie is comparison across frames, so everything that should not change is held fixed:
| held fixed across frames | how |
|---|---|
| stages | selected on the first frame, then passed as explicit layers |
| channels on every page | ranked by activity summed over all frames (force_channels) |
| per-channel display range | 1st–99.5th percentile over all frames |
| PCA colour basis of the front pages | fitted on the middle frame and reused (force_pca) |
| latent-vector colour range | percentiles over all frames |
These are recomputed for every frame: activations, beams, receptive-field circles, contribution lines, Grad-CAM evidence and outputs.
Under the flow, a timeline tracks every output (top classes, sigmoid probabilities, regressed values, segmented volume %), and a film strip of the inputs marks the current frame.
Usage¶
from neural_flow import animate_inputs
animate_inputs(
model,
frames, # tensor [T, ...] or list of per-frame inputs (tensors or dicts)
output="sweep.mp4", # .mp4 (imageio-ffmpeg) or .gif
fps=8,
frame_labels=[...], # optional text per frame, e.g. "true age 64"
title="…", subtitle="…",
class_names=labels, # any visualize_model option
figsize=(16, 9), dpi=120,
)
Input sequences¶
from neural_flow.sequences import pan, crossfade, zoom, occlusion_sweep, slices_to_frames
pan(img_chw, window=256, steps=48, out_size=224) # camera pan across a wide image
crossfade(img_a, img_b, steps=32) # morph between two inputs
zoom(img_chw, start=1.0, end=0.3, center=(0.4, 0.6)) # zoom into a point
occlusion_sweep(img_chw, patch=56, stride=28) # does the decision need this region?
slices_to_frames(volume, axis=-1) # 2-D model applied through a volume
Any list of inputs works, for example longitudinal scans of one subject, a dose-response series, augmentations, or adversarial steps.
Movies that make sense¶
A movie is most informative when the expected behaviour is known in advance. Then it tests the model rather than decorating it:
- Camera pan (
movie_pan_resnet.mp4): the predicted class should switch exactly when the window moves from one photograph to the next. - Ageing subject (
movie_aging.mp4): ventricles enlarge with age while a lesion appears and grows. Predicted brain age should rise (it goes 29 → 72), lesion probability should switch on, and the segmented volume should grow. - Occlusion sweep (
movie_cxr_occlusion.mp4): Cardiomegaly should drop when the heart is covered. It does, and the model then prefers Hernia. - 3-D inference (
movie_sliding_window_unetr.mp4): a 3-D segmentation network sees one window at a time. Each frame is one sliding window; the stages follow the window through the head while the fused whole-head segmentation assembles in the output card, and the film strip shows where the window is.sliding_window_movie(...),neural-flow movie MODEL --inference scan.nii.gz, orpython examples/transformer_3d.py --movie. See 3-D models. The same with a real nnU-Net on a CT:movie_sliding_window_totalseg_organs.mp4(neural-flow movie totalseg-organs --inference sample:ct, see nnU-Net).
Cost¶
Each frame needs three forward passes (ranking, capture, gradients) plus rendering. On a laptop CPU that is roughly 2–5 s per frame for 2-D models and 5–10 s for small 3-D models. A 48-frame movie takes a few minutes.