Spaces:
Sleeping
Sleeping
File size: 8,735 Bytes
47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 47fccfe 358bf71 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 | # 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 **visualizes where the model looks** by extracting 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.
---
## 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` (default) -- 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`, on by default) -- 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 config: rollout method, cross-attention enabled, per-head grid enabled
./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 only (faster, no rollout)
./run.sh --method last-layer
# Skip cross-attention (faster, 3-row grid only) β edit configs/defaults.yaml:
# cross_attention: false
# Raw attention without positional baseline subtraction
./run.sh --raw-attention
# Explicit device override (auto-detected by default: mps > cuda > cpu)
./run.sh --device cuda
```
Results land in `outputs/`.
### CLI flags
| 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 |
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.
---
## Project layout
```
smolvla-inspect/
βββ inspect_attention.py # All logic: model loading, hooks, heatmaps, visualization
βββ assets/
β βββ 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 (gitignored)
βββ run.sh # Wrapper that sets FFmpeg lib path
βββ requirements.txt
βββ README.md
```
---
## 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`.
|