File size: 9,693 Bytes
d4cbafd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1047290
 
 
d4cbafd
 
 
1047290
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4cbafd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# SRA β€” Spatial Reasoning Adapter: How to Run

SRA is a **modular future-interaction graph** (`FutureInteractionGraphV6`) that plugs into three
stochastic trajectory predictors at a single insertion point:

| Host | Type | Entry point (NBA) | Entry point (soccer/football) |
|---|---|---|---|
| **MID** | DDPM diffusion | `MID/main_nba_mid_graphv6_v3.py` | `MID/main_{soccer,football}_mid_graphv5_sigma*.py` |
| **LED** | leapfrog-DDPM | `LED/main_led_nba_graph.py` | `LED/main_sport_led.py` |
| **MoFlow** | flow matching | `MoFlow/fm_nba_graph_v6.py` | `MoFlow/fm_sport_graph_v6.py` |

Datasets: **NBA** (11 agents), **Soccer** / **Football** (23 agents). Metric: min-ADEβ‚‚β‚€ / min-FDEβ‚‚β‚€ @ 4.0 s.

---

## 0. CRITICAL: directory layout

**`MID/` and `LED/` do not contain the SRA graph module.** They import it from a *sibling*
`MoFlow/` directory at runtime:

```python
# MID/main_nba_mid_graphv6_v3.py
MOFLOW_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'MoFlow'))
sys.path.insert(0, MOFLOW_ROOT)
from models.graph_interaction_nba_v6 import FutureInteractionGraphV6
```

So you **must** preserve this layout β€” do not move the three folders apart:

```
<root>/
β”œβ”€β”€ MoFlow/          # owns the SRA graph + baseline modules
β”‚   └── models/
β”‚       β”œβ”€β”€ graph_interaction_nba_v6.py   # <-- SRA (the adapter itself)
β”‚       β”œβ”€β”€ interaction_baselines.py      # <-- E4 baselines (GameFormer / C2F) + factory
β”‚       └── backbone_graph_v6.py          # MoFlow's insertion point
β”œβ”€β”€ MID/
└── LED/
```

---

## 1. Environment

```bash
conda create -n sra python=3.11 -y && conda activate sra
pip install torch==2.4.0 --index-url https://download.pytorch.org/whl/cu121
pip install -r MoFlow/requirements.txt
pip install -r LED/requirements.txt
pip install easydict pyyaml tensorboard tqdm scipy matplotlib gitpython
```

Verified on: PyTorch 2.4.0 + CUDA 12.1, NVIDIA A6000 (48 GB) and RTX 3090 (24 GB).

**cuDNN gotcha (MID + LED).** If a system CUDA shadows the env's cuDNN you get
`Could not load library libcudnn_cnn_train.so.8 ... undefined symbol` at `.backward()`.
Fix by prepending the env's bundled NVIDIA libs:

```bash
ENV=$CONDA_PREFIX
export LD_LIBRARY_PATH="$(ls -d $ENV/lib/python3.11/site-packages/nvidia/*/lib | tr '\n' ':')$LD_LIBRARY_PATH"
```

---

## 2. Data (not included in this repo)

Place the arrays as follows, then pass the paths via `--data_dir`:

```
MoFlow/data/nba/original/nba_train.npy      # 32500 scenes, 30 frames x 11 agents x 2
MoFlow/data/nba/original/nba_test.npy       # 12500 scenes
<raw_data>/soccer/{train.npy,val.npy}       # 23 agents
<raw_data>/football/{train.npy,val.npy}     # 23 agents
```

NBA past/future = 10/20 frames @ 5 Hz (4.0 s horizon). Sport uses the same convention.

> **`--data_dir` points at the PARENT of `original/`** for NBA β€” the loader appends `original/`
> itself. So use `--data_dir ./data/nba`, not `./data/nba/original`.

> Several scripts still carry absolute `--data_dir` defaults from the development machine
> (`/mnt/...`). **Always pass `--data_dir` explicitly** β€” the CLI value overrides the default.

### Smoke test with the bundled 100-scene sample

`sample_data/nba/` contains a 100-scene NBA train/test subset (β‰ˆ0.5 MB) so you can verify the
pipeline before setting up the full data β€” see [`sample_data/README.md`](sample_data/README.md):

```bash
cd MoFlow
CUDA_VISIBLE_DEVICES=0 python fm_nba_graph_v6.py \
  --cfg cfg/nba/cor_fm.yml --exp smoke --data_dir ../sample_data/nba \
  --n_train 100 --n_test 100 --batch_size 8 --epochs 1 \
  --fm_in_scaling --tied_noise --top_n_neighbors 5 --uncertainty_weight 0.01
```

100 scenes cannot train a usable model β€” this only confirms the data path, model construction,
training step and eval loop execute.

---

## 3. Run β€” host Γ— dataset

All commands below are the exact recipes used to produce the reported numbers.
Set the GPU with `CUDA_VISIBLE_DEVICES=<id>` (MoFlow) or `--gpu <id>` (MID/LED).

### 3.1 MoFlow

```bash
cd MoFlow

# NBA + SRA
CUDA_VISIBLE_DEVICES=0 python fm_nba_graph_v6.py \
  --cfg cfg/nba/cor_fm.yml --exp nba_sra \
  --batch_size 192 --epochs 150 --fm_in_scaling --tied_noise \
  --top_n_neighbors 5 --uncertainty_weight 0.01 \
  --data_dir ./data/nba

# Soccer / Football + SRA   (swap football <-> soccer)
CUDA_VISIBLE_DEVICES=0 python fm_sport_graph_v6.py \
  --cfg cfg/sport/football.yml --exp football_sra \
  --batch_size 64 --epochs 100 \
  --top_n_neighbors 5 --uncertainty_weight 0.01 \
  --data_dir <raw_data>/football
```

`--resume <ckpt_name>` (e.g. `--resume checkpoint_epoch_20`) restores model+optimizer+EMA+step
from `<cfg_dir>/models/`. The run directory name is derived from the args, so **resume only works
if you pass the identical args** as the original run.

### 3.2 MID

```bash
cd MID

# NBA + SRA
CUDA_VISIBLE_DEVICES=0 python main_nba_mid_graphv6_v3.py \
  --data_dir <root>/MoFlow/data/nba/original --exp_name mid_nba_sra \
  --epochs 100 --batch_size 32 --lr 1e-3 --eval_every 5 \
  --sampling ddim --sampling_step 10

# Football + SRA
python main_football_mid_graphv5_sigma.py \
  --data_dir <raw_data>/football --exp_name mid_football_sra --gpu 0 \
  --epochs 100 --batch_size 64 --lr 1e-3 --graph_lr_mult 1.0 --eval_every 1 \
  --top_n_neighbors 5 --uncertainty_weight 0.01 \
  --train_mode two_pass --sampling ddim --sampling_step 20

# Soccer + SRA  -> same flags, script main_soccer_mid_graphv5_sigma_output.py
```

⚠️ **`--graph_lr_mult` matters.** `3.0` diverges for the sparse (top_n=5) sport configuration
(ADE stuck β‰ˆ0.46). Use **`1.0`** β€” that is what the reported results use.

### 3.3 LED

```bash
cd LED

# NBA + SRA
python main_led_nba_graph.py --cfg led_augment --gpu 0 --train 1 \
  --use_v6_graph --use_sigma --top_n 5 --uncertainty_weight 1.0 --residual_on eps

# Soccer / Football + SRA
python main_sport_led.py --cfg football --gpu 0 --train 1 \
  --use_v6_graph --residual_on eps
```

⚠️ **LED-sport Οƒ behaviour.** `main_sport_led.py` has **no `--use_sigma` flag**: it passes the
leapfrog initializer's `variance_estimation` to the graph **automatically**. To run a genuine
no-Οƒ ablation on sport you must set `LED_NO_SIGMA=1` (see Β§5), otherwise the "no-Οƒ" run silently
uses Οƒ and reproduces the full-SRA result.

---

## 4. E2 β€” cumulative ablation settings

The ablation adds one component at a time. `A` = number of agents (11 NBA / 23 sport).

| Configuration | `top_n_neighbors` | uncertainty (Οƒ) |
|---|---|---|
| host baseline | *(graph disabled)* | – |
| + relational encoding (all neighbors, no Οƒ) | `A-1` (10 NBA / 22 sport) | off |
| + sparse neighbor selection (no Οƒ) | `5` | off |
| **+ uncertainty = full SRA** | `5` | on |

Turning Οƒ **off**:

| Host | How |
|---|---|
| MoFlow | `--uncertainty_weight 0.0` (code sets `use_sigma_gating = uncertainty_weight > 0`) |
| MID | `--uncertainty_weight 0.0` |
| LED (NBA) | omit `--use_sigma` |
| LED (sport) | `LED_NO_SIGMA=1` environment variable |

**Memory note.** Dense sport (`top_n_neighbors 22`) does not fit at batch 64 on 48 GB β€” use
`--batch_size 32` (roughly doubles the wall-clock per epoch).

---

## 5. Environment variables

| Variable | Applies to | Meaning |
|---|---|---|
| `SRA_MODULE` | all hosts | which module fills the insertion slot: `sra` (default) / `gameformer` / `c2f` |
| `GF_LEVELS` | GameFormer baseline | number of level-k reasoning levels (default 3) |
| `C2F_REFINE` | C2F baseline | refiner type: `gru` / `cnn` |
| `MOFLOW_DAMP` | MoFlow | cap on the residual norm (flow-field stability); `0` = off |
| `LED_TOP_N` | LED sport | neighbor budget override |
| `LED_NO_SIGMA` | LED sport | `1` = do **not** feed Οƒ to the graph (required for no-Οƒ ablation) |

Example β€” swap SRA for the GameFormer baseline in the same slot:

```bash
SRA_MODULE=gameformer GF_LEVELS=2 CUDA_VISIBLE_DEVICES=0 python fm_nba_graph_v6.py \
  --cfg cfg/nba/cor_fm.yml --exp nba_gameformer \
  --batch_size 192 --epochs 150 --fm_in_scaling --tied_noise \
  --top_n_neighbors 5 --uncertainty_weight 0.01 --data_dir ./data/nba
```

---

## 6. The adapter contract

Any module in the slot must implement:

```python
forward(y_emb,        # [B, K, A, D]      per-agent embedding of the current estimate
        y_abs,        # [B, K, A, T, 2]   current future-trajectory estimate
        t_emb,        # [B, D]            denoising-timestep embedding
        tau,          # [B]               noise level
        sigma_agent,  # [B, K, A, T] or None   per-step uncertainty
        agent_mask,   # [B, A] or None    validity mask (padded agents)
        ) -> [B, K, A, D]                 # gated residual, same shape as y_emb
```

It must tolerate `K ∈ {1, 10, 20}` and any `A`. `MoFlow/models/interaction_baselines.py`
provides `build_interaction_module(...)`, which honours `SRA_MODULE` and is the single place
each host constructs its interaction module.

---

## 7. Known gotchas

| Symptom | Cause / fix |
|---|---|
| `undefined symbol ... libcudnn_cnn_train.so.8` at backward | system CUDA shadows env cuDNN β†’ set `LD_LIBRARY_PATH` (Β§1) |
| `ImportError: tensorboardX` (MID) | use `torch.utils.tensorboard` instead |
| `InvalidGitRepositoryError` (MoFlow) | `back_up_code_git` needs a git repo; already wrapped in try/except |
| MID sport ADE stuck β‰ˆ0.46 | `--graph_lr_mult 3.0` β†’ use `1.0` |
| Dense sport OOM at BS64 | use `--batch_size 32` |
| "no-Οƒ" LED-sport equals full SRA | missing `LED_NO_SIGMA=1` |
| Reported "best" keeps falling while eval worsens | `best ADE_MIN` is a monotone best-so-far tracker β€” inspect the **per-eval** `ADE_min(4.0s)` series to detect divergence |