File size: 7,081 Bytes
c02eab1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
license: mit
library_name: wan2.2
pipeline_tag: image-to-video
tags:
- video-generation
- diffusion
- camera-control
- causal-video
- wan2.2
- ucpe
base_model: Wan-AI/Wan2.2-TI2V-5B
---

# RayStream CF++ β€” bidirectional teacher + AR-diffusion student

Checkpoints from the **Causal Forcing++ (CF++)** frame-wise rebuild: camera-controlled,
image-conditioned video generation on **Wan2.2-TI2V-5B at 704Γ—1280**, with UCPE camera
conditioning (PRoPE) throughout.

Code: [github.com/weijielyu/RayStream_CF](https://github.com/weijielyu/RayStream_CF) (`main`)

This repo holds the two checkpoints at the **front** of the CF++ pipeline:

```
UCPE bidirectional teacher  (this repo: bidirectional_teacher/)
   └─> AR-diffusion         (this repo: ar_diffusion/)   teacher-forced warmup, step 6200
         └─> Causal-CD                                   consistency distillation, effective step 3000
               └─> DMD                                   final few-step causal student
```

## Contents

```
.
β”œβ”€β”€ bidirectional_teacher/
β”‚   └── last.ckpt            # 10.1 GiB β€” PyTorch Lightning ckpt, run ti2v_relray_absmap_comp8_704_fixedloss
└── ar_diffusion/
    └── model.pt             # 19.2 GiB β€” CF++ AR-diffusion, step 6200 (generator only)
```

| File | Format | Top-level keys |
|---|---|---|
| `bidirectional_teacher/last.ckpt` | Lightning (DeepSpeed stage-1 consolidated) | `state_dict` with `pipe.dit.*` prefix |
| `ar_diffusion/model.pt` | CF++ trainer save | `generator` |

The AR checkpoint is **generator-only** β€” do not pass `--use_ema` when loading it
(`ema_start_step` was set past the run length, so no EMA weights exist).

## Model configuration

Both share the same geometry and camera setup:

- **Base**: Wan2.2-TI2V-5B β€” DiT dim 3072, 24 heads (head_dim 128), 30 layers, `in_dim`/`z_dim` 48
- **Resolution**: 704Γ—1280, 81 pixel frames @ 16 fps
- **VAE**: `WanVideoVAE38` (48-ch, temporal 4Γ—) β†’ 21 latent frames = 81 pixel frames
- **Latent shape**: `[1, 21, 48, 44, 80]`; patch factor 32 β†’ `frame_seq_length` 880, `seq_len` 18480
- **Camera**: UCPE Unified Camera Model (`x_fov`, `xi`), method `relray_absmap`
  (Relative Ray Encoding + absolute orientation via up-vector and latitude map),
  `attn_compress=8`. Injected as a parallel `cam_self_attn` (PRoPE) branch next to DiT
  self-attention β€” ~300 tensors / 142 M params (2.8% of the model). PRoPE is KV-cache
  compatible, which is what lets the camera branch survive autoregressive distillation.
- **I2V**: frame 0 is the clean condition image β€” pinned at timestep 0, kept clean, excluded
  from the loss, never noised or augmented.

The AR student grafts the teacher's camera branch **frozen** (`freeze_camera_branch: true`).

## ⚠️ This is the *corrected* teacher

An earlier bidirectional teacher (published in `wlyu/ucpe_checkpoints` as
`wan22_bidirectional_ucpe/`) baked in an I2V training bug: `training_loss` noised **and**
supervised frame 0, even though TI2V-5B pins frame 0 clean at t=0 and inference re-pins it every
step. Frame 0 was therefore fed noised while labeled t=0 β€” so it never learned the clean
first-frame anchor, and first-frame content ghosted onto later frames through bidirectional
attention.

The fix re-pins frame 0 after `add_noise` and excludes it from both `noise_pred` and the training
target. The model was **retrained from scratch** with the fix; that retrain is the checkpoint here
(run `ti2v_relray_absmap_comp8_704_fixedloss`, 10 epochs / 10000 steps, batch 32 on 4Γ—8 B200).

**Use this one, not `wlyu/ucpe_checkpoints/wan22_bidirectional_ucpe/`**, which is superseded.

## Usage

### Load the teacher's camera branch into a CF++ model

The teacher is consumed by CF++ as the frozen camera branch. `load_ucpe_camera_weights` accepts
this Lightning checkpoint directly β€” it unwraps `state_dict`, keeps keys containing
`cam_self_attn`, strips the `pipe.dit.` prefix, and loads with `strict=False`:

```python
from utils.camera_control import patch_causal_dit, load_ucpe_camera_weights

patch_causal_dit(model, method="relray_absmap", attn_compress=8)
load_ucpe_camera_weights(model, "bidirectional_teacher/last.ckpt")
# -> Loaded 300 camera branch params, 825 missing (expected: base model keys), 0 unexpected
```

In CF++ configs this is just `ucpe_ckpt: /path/to/last.ckpt`.

### Continue training from the AR checkpoint

Warm-start Causal-CD (or resume AR) by pointing `generator_ckpt` at the AR weights. Note this is
a **weights-only** warm start β€” the optimizer state and step counter are not restored, so the step
counter restarts at 0 and the effective step is `6200 + new_step`:

```yaml
# configs/cfpp_causal_cd_framewise_ti2v704.yaml
generator_ckpt: /path/to/ar_diffusion/model.pt
ucpe_ckpt:      /path/to/bidirectional_teacher/last.ckpt
```

```bash
export PYTHONPATH=$PWD TOKENIZERS_PARALLELISM=false HF_HUB_OFFLINE=1
torchrun --nnodes=1 --nproc_per_node=8 --master_port=29562 train.py \
  --config_path configs/cfpp_causal_cd_framewise_ti2v704.yaml \
  --disable-wandb --no_visualize --logdir /path/to/out
```

You also need the Wan2.2-TI2V-5B base weights (`hf download Wan-AI/Wan2.2-TI2V-5B`) symlinked as
`wan_models/Wan2.2-TI2V-5B` in the code tree.

### Download

```bash
hf download wlyu/raystream_cfpp --local-dir ./raystream_cfpp

# or just one:
hf download wlyu/raystream_cfpp --include 'ar_diffusion/*' --local-dir ./raystream_cfpp
```

## Training

Both trained on 8Γ—B200 (teacher: 4 nodes), data = **PanShot** panoramic video with ground-truth
camera poses at 704p.

**AR-diffusion** used upstream Causal-Forcing's optimizer recipe verbatim β€” lr 2e-6, beta1 0.0,
no weight decay, `num_frame_per_block: 1` (frame-wise), teacher forcing on, batch 8 β€” with only
the 704p/5B geometry, camera control, and I2V conditioning added. It ran to step 6200 (~6 s/step),
past the ~5700 plateau of an earlier run.

Expect **low-motion, near-static output** from the AR checkpoint. That is inherent to teacher
forcing on panoramic data and is normal at this stage; motion dynamics are restored later, at the
DMD stage. Upstream guidance is AR β‰₯2K steps (5–10K better), Causal-CD β‰₯3K, and DMD ≀1K at bs64 β€”
beyond ~1K, DMD over-fits to the teacher's static-biased distribution and motion degrades.

## Evaluation

PanShot test split, held out at **clip** level (0/340 exact overlap with train) but **not
scene-disjoint** β€” roughly 33 of 51 test source videos also appear in training as different
segments. Metrics span video quality (FVD, FID, CLIP-T) and camera accuracy (FOV error,
distortion k1/k2, pitch/roll, rotation/translation error, CAMMC), computed with the UCPE metric
harness.

## Citation

```bibtex
@misc{raystream_cfpp_2026,
  author = {Lyu, Weijie},
  title  = {RayStream CF++: Causal Forcing with UCPE Camera Control},
  year   = {2026},
  url    = {https://huggingface.co/wlyu/raystream_cfpp}
}
```

Built on [thu-ml/Causal-Forcing](https://github.com/thu-ml/Causal-Forcing) (arXiv 2602.02214) and
UCPE. Contact: Weijie Lyu (`weijielyu1@gmail.com`)