Spaces:
Sleeping
Sleeping
File size: 13,912 Bytes
47fccfe 358bf71 47fccfe f5961bc 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe f5961bc 202cb33 f5961bc 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 f5961bc 358bf71 47fccfe f5961bc 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 202cb33 47fccfe 358bf71 47fccfe 202cb33 f5961bc 202cb33 47fccfe 202cb33 47fccfe 358bf71 47fccfe f5961bc 358bf71 47fccfe 358bf71 f5961bc 358bf71 202cb33 358bf71 f5961bc 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 f5961bc 358bf71 47fccfe 358bf71 f5961bc 358bf71 f5961bc 358bf71 f5961bc 358bf71 47fccfe ec8bdfc 47fccfe 358bf71 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | # smolvla-inspect
See what SmolVLA's vision encoder and action expert are looking at when the model predicts robot actions.

*5-row attention grid for a pick-and-place episode. Row 1: original frames. Row 2: SigLIP self-attention heatmap. Row 3: self-attention overlay. Row 4: action cross-attention heatmap. Row 5: co-attention (self x cross) overlay in cyan.*
---
## What this does
SmolVLA is a **vision-language-action** policy: it takes camera images and a language instruction, then outputs robot actions. This tool has two modes:
1. **Attention visualization** (default) -- extracts and visualizes attention heatmaps showing where the model looks
2. **Model health diagnostics** (`--model-health`) -- runs spectral analysis, attention entropy, and head redundancy checks across all model components
### Attention visualization
Extracts attention maps from two places:
1. **SigLIP vision encoder** (self-attention) -- which image patches the encoder considers important during feature extraction
2. **Action expert** (cross-attention) -- which image regions the action decoder actually reads when predicting actions
That lets you check whether the model attends to task-relevant regions (gripper, object, goal) or background (walls, table texture) -- useful for debugging overfitting or distribution shift.
**Input:** A pretrained or fine-tuned SmolVLA policy + a LeRobot dataset (e.g. episodes of pick-and-place).
**Output:** A multi-row grid PNG per episode, optional per-frame PNGs, and an optional per-head attention grid.
### Model health diagnostics
Runs three diagnostic checks across all model components (SigLIP vision encoder, VLM text model, action expert, connector, and projection heads):
1. **Weight spectral analysis** -- fits a power-law to singular values of each weight matrix using WeightWatcher. The alpha exponent indicates training quality (2-4 = healthy, >6 = severely undertrained).
2. **Attention entropy** -- measures how focused or diffuse each attention head is across three attention operations: SigLIP self-attention, VLM+Expert joint self-attention, and Expert-to-VLM cross-attention.
3. **Head redundancy** -- measures pairwise cosine similarity between attention heads within each layer. High similarity means wasted capacity.
**Output:** Terminal report, markdown report (`model_health_report.md`), and a 3-panel plot (`model_health_report.png`).

*Example 3-panel health report: spectral alpha distribution, attention entropy by layer, and head redundancy matrix. See the full [markdown report](assets/example_health_report.md) for per-layer details.*
For a detailed visual walkthrough of the architecture and how it maps to the report, see **[Architecture Diagrams](assets/architecture.md)**.
---
## How it works

*Left: Where the vision encoder lives and where we hook to capture attention. Right: How attention weights become a spatial heatmap.*
### Pipeline
1. **Load model and dataset** -- loads a SmolVLA policy (e.g. `lerobot/smolvla_base`) and a LeRobot dataset. The dataset provides image sequences; the script uses images as input and runs inference.
2. **Capture self-attention from SigLIP** -- the vision encoder (SigLIP ViT, 12 layers, 12 heads) splits each image into patches (32x32 grid for 512px images with 16px patches) and runs self-attention. Forward hooks on the attention layers capture the weight matrices.
3. **Aggregate across layers** (`--method`):
- `last-layer` -- uses only the final encoder layer
- `rollout` -- multiplies attention across all layers with residual connections, giving a more complete picture of information flow
- `all-layers` -- keeps each layer separately
4. **Capture cross-attention** (`--cross-attention`) -- SmolVLA's VLM builds a KV cache from the prefix (vision + language + state tokens). The action expert queries that cache. The script monkey-patches `eager_attention_forward()` on the expert layers to intercept the softmax attention when expert Q attends to prefix K. Only columns corresponding to vision tokens are kept, giving a heatmap of which image regions the action decoder reads.
5. **Turn attention into spatial heatmaps** -- patch-level importance scores are reshaped into a 2D grid, upsampled with bilinear interpolation to image size, and normalized to [0, 1].
6. **Visualize** -- the output grid has up to 5 rows per frame:
| Row | Content | Colormap |
|-----|---------|----------|
| 1 | Original frame | -- |
| 2 | SigLIP self-attention heatmap | jet (blue-to-red) |
| 3 | Self-attention overlay on frame | jet |
| 4 | Action cross-attention heatmap | Greens |
| 5 | Co-attention overlay (self x cross) | cyan (black-cyan-white) |
Rows 4-5 only appear when cross-attention is enabled. The co-attention overlay multiplies self-attention and cross-attention element-wise, highlighting regions that are **both** visually salient and action-relevant.
### Per-head grid
With `--show-heads`, a separate grid shows each of the 12 SigLIP attention heads individually for the first frame:

*Each subplot is one attention head. Look for specialization -- e.g. one head tracking the gripper, another tracking the object.*
---
## Setup
**Requirements:** Python 3.10+, and FFmpeg 4-7 for video decoding (LeRobot uses TorchCodec). On macOS, Homebrew's default `ffmpeg` is often v8; install FFmpeg 6:
```bash
brew install ffmpeg@6
```
Then:
```bash
cd smolvla-inspect
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
```
---
## Run
Use `run.sh` so TorchCodec finds FFmpeg 6's libs:
```bash
source .venv/bin/activate
./run.sh
```
Or set the library path yourself:
```bash
export DYLD_LIBRARY_PATH="/opt/homebrew/opt/ffmpeg@6/lib:$DYLD_LIBRARY_PATH"
python inspect_attention.py
```
### Examples
```bash
# Default: rollout aggregation + cross-attention + per-head grid
./run.sh
# Your fine-tuned model
./run.sh --model path/to/finetuned_checkpoint --dataset path/to/dataset
# More frames, specific episode
./run.sh --episode 3 --num-frames 12
# Last-layer method instead of rollout
./run.sh --method last-layer
# Skip cross-attention capture (faster, omits rows 4-5)
./run.sh --no-cross-attention
# Skip per-head attention grid
./run.sh --no-show-heads
# Raw attention without positional baseline subtraction
./run.sh --raw-attention
# Model health diagnostics (spectral analysis + entropy + redundancy)
./run.sh --model-health
# Health check with more sample frames for stable entropy estimates
./run.sh --model-health --health-frames 10
# Custom thresholds for health warnings
./run.sh --model-health --entropy-warn 0.85 --redundancy-warn 0.75
# Explicit device override (auto-detected by default: mps > cuda > cpu)
./run.sh --device cuda
```
Results land in `outputs/`.
### CLI flags
**Attention visualization:**
| Flag | Default | Description |
|------|---------|-------------|
| `--model` | `lerobot/smolvla_base` | HuggingFace model ID or local path |
| `--dataset` | `lerobot/svla_so101_pickplace` | LeRobot dataset ID or local path |
| `--episode` | `0` | Episode index to visualize |
| `--num-frames` | `8` | Number of frames to sample |
| `--image-key` | auto-detected | Dataset image key override |
| `--output-dir` | `./outputs` | Output directory |
| `--device` | `auto` | `auto`, `cpu`, `cuda`, or `mps` |
| `--save-individual` | `true` | Save each frame as a separate PNG |
| `--method` | `rollout` | `last-layer`, `rollout`, or `all-layers` |
| `--cross-attention` | `true` | Capture action-expert cross-attention |
| `--show-heads` | `true` | Save per-head attention grid for first frame |
| `--raw-attention` | `false` | Skip positional baseline subtraction |
**Model health diagnostics:**
| Flag | Default | Description |
|------|---------|-------------|
| `--model-health` | `false` | Run health diagnostics instead of attention heatmaps |
| `--health-frames` | `5` | Number of sample frames for entropy/redundancy |
| `--entropy-warn` | `0.8` | Entropy ratio threshold for "unfocused" warning |
| `--entropy-critical` | `0.95` | Entropy ratio threshold for "dead" heads |
| `--entropy-low` | `0.1` | Entropy ratio threshold for "collapsed" heads |
| `--redundancy-warn` | `0.7` | Cosine similarity threshold for "high redundancy" |
| `--redundancy-critical` | `0.9` | Cosine similarity threshold for "collapsed" heads |
Defaults can be changed in `configs/defaults.yaml`.
---
## What to look for
### Self-attention (SigLIP vision encoder -- rows 2-3)
| Attention pattern | Interpretation |
|-------------------|----------------|
| Bright on gripper + object + goal | **Healthy** -- model attends to task-relevant regions |
| Bright on shelves, cables, table grain | **Background overfitting** -- model may be using scene cues |
| Uniform / diffuse everywhere | Model may not have learned focused visual features yet |
| Shifts from background to object across frames | Model is tracking the task over time (good sign) |
### Cross-attention (action expert -- rows 4-5)
| Attention pattern | Interpretation |
|-------------------|----------------|
| Tight focus on gripper tip + target object | **Healthy** -- action decoder reads exactly what it needs |
| Diffuse across all vision tokens | Decoder hasn't specialized; may predict generic actions |
| Self-attn diffuse but cross-attn focused | Decoder learned to select useful tokens despite a noisy encoder |
| Self-attn focused but cross-attn diffuse | Encoder features are good but the decoder doesn't exploit them |
### Co-attention (row 5)
The cyan overlay highlights regions where **both** the vision encoder and the action expert agree something is important. Bright cyan = high self-attention AND high cross-attention. This is the strongest signal for task-relevant regions.
### Per-head patterns
Look for heads that specialize: one head tracking the gripper, another tracking the object, another attending globally. Specialization is a sign of a well-trained encoder. Heads that all look identical suggest the model hasn't learned diverse attention strategies.
### Model health report
| Metric | Healthy | Warning | Critical |
|--------|---------|---------|----------|
| Spectral alpha | 2-4 | 4-6 (undertrained) | >6 (severely undertrained) or <2 (overcorrelated) |
| Attention entropy | 0.10-0.80 | >0.80 (unfocused) | >0.95 (dead) or <0.10 (collapsed) |
| Head redundancy | <0.70 (diverse) | >0.70 (redundant) | >0.90 (collapsed) |
The report covers three attention components mapped to distinct operations in the architecture:
| Report component | Architecture operation | When it runs |
|-----------------|----------------------|-------------|
| SigLIP Vision (12L, 12H) | Self-attention inside the vision encoder | Image encoding |
| VLM+Expert Joint Self-Attn (16L, 15H) | VLM and Expert tokens concatenated, attend to each other | Prefill (initial encoding) |
| Expert-to-VLM Cross-Attn (16L, 8H) | Expert queries VLM's cached keys/values | Generation (action decoding, 10 steps) |
See **[Architecture Diagrams](assets/architecture.md)** for visual explanations of each component.
---
## Project layout
```
smolvla-inspect/
βββ inspect_attention.py # All logic: model loading, hooks, heatmaps, health diagnostics
βββ assets/
β βββ architecture.md # Architecture diagrams and report reference
β βββ how_it_works_architecture.png
β βββ example_grid.png
β βββ example_per_head.png
βββ configs/
β βββ defaults.yaml # Default CLI values (model, dataset, method, flags)
βββ docs/
β βββ ELI5.md # Plain-language explanation of the interpretability approach
β βββ TESTING.md # CLI test commands and expected output
βββ outputs/ # Generated images and reports (gitignored)
β βββ model_health_report.md
β βββ model_health_report.png
βββ run.sh # Wrapper that sets FFmpeg lib path
βββ requirements.txt
βββ README.md
```
---
## Roadmap
Attention maps show where the model allocates compute, but not whether those regions actually drive the output. The following interpretability methods would complement the current tooling:
- [ ] **Gradient-based attribution** -- compute `d(action) / d(patch_embedding)` via vanilla saliency, GradCAM, or Integrated Gradients to measure which image patches *causally influence* the predicted action (not just where attention points)
- [ ] **Occlusion / perturbation sensitivity** -- mask out image regions or zero out specific prefix tokens (vision, language, state) and measure action MSE change; model-agnostic and directly answers "if I cover the gripper, does the model break?"
- [ ] **Representation probing** -- train small linear classifiers on intermediate layer representations to test what information is encoded at each stage (e.g., can layer N predict object position? does the Expert encode gripper state?)
- [ ] **Causal tracing / activation patching** -- replace activations at specific (layer, token) positions with corrupted versions and measure output change; builds a causal map of information flow through the model
- [ ] **Temporal consistency analysis** -- track attention patterns across frames in an episode to check if attention follows the object smoothly, whether cross-attention shifts predict upcoming actions, and correlation between attention movement and action direction
---
## Note on FFmpeg
If you installed `ffmpeg@6` and linked it (`brew link --overwrite ffmpeg@6`), your default `ffmpeg` is now 6.x. To switch back later: `brew unlink ffmpeg@6 && brew link ffmpeg`.
|