File size: 6,348 Bytes
a596b0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a85f4eb
a596b0a
a85f4eb
 
a596b0a
 
 
ee38494
 
 
 
a85f4eb
 
da3fef1
a596b0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a85f4eb
a596b0a
 
 
 
a85f4eb
a596b0a
 
 
 
 
 
 
 
 
 
 
a85f4eb
 
 
 
 
a596b0a
da3fef1
 
 
 
 
 
 
 
 
 
 
 
 
a596b0a
da3fef1
 
 
 
 
 
a85f4eb
 
da3fef1
a596b0a
da3fef1
 
a596b0a
 
 
 
 
a85f4eb
 
a596b0a
 
 
 
 
da3fef1
 
 
a596b0a
 
 
 
 
 
 
 
 
 
 
 
 
 
a85f4eb
 
 
 
a596b0a
 
 
2f27948
a596b0a
 
 
 
 
 
 
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
---
license: mit
library_name: transformers
pipeline_tag: feature-extraction
base_model:
  - google/siglip2-so400m-patch14-384
  - Qwen/Qwen3-Embedding-0.6B
tags:
  - video
  - representation-learning
  - view-invariant
  - cross-view
  - egocentric
  - egoexo4d
  - emnlp2026
---

# PRISM

Predictive Recomposition via Semantic Latent Decomposition for View-invariant Video
Representation Learning. EMNLP 2026, main conference.

[Paper][paper] · [Project page][project] · [Code][code]

PRISM is a video encoder that captures viewpoint-invariant action semantics, matching the
same action across egocentric and exocentric views. It decomposes each video into
view-invariant and view-variant latents and recomposes them across videos under language
supervision, which stays semantically valid beyond the co-occurrences observed in training.

This checkpoint is trained on EgoExo4D, using both ego and exo views and captions generated
by Gemini 3.

## Usage

```python
import torch
from transformers import AutoModel, AutoImageProcessor

model = AutoModel.from_pretrained(
    "litcoderr/prism", trust_remote_code=True, dtype=torch.bfloat16
).eval().cuda()
proc = AutoImageProcessor.from_pretrained(model.config.vision_backbone_name)

frames = [...]                                              # list[PIL.Image], sampled at 4 fps
pixel_values = proc(images=frames, return_tensors="pt").pixel_values[None]
pixel_values = pixel_values.to("cuda", torch.bfloat16)      # (1, T, 3, 384, 384)
valid_mask = torch.ones(pixel_values.shape[:2], dtype=torch.bool, device="cuda")

emb = model.encode(pixel_values, valid_mask)                # (1, 512), L2-normalized
```

| | |
|:---|:---|
| `model.encode(pixel_values, valid_mask)` | `(B, 512)` L2-normalized clip embedding, mean-pooled `z_vi` over valid frames |
| `model.encode_streams(pixel_values, valid_mask)` | `{"z_vi_seq", "z_vv_seq"}`, each `(B, T, 512)` per-frame |

**Inputs.** `pixel_values` is `(B, T, 3, 384, 384)`, frames sampled at 4 fps, up to
`T = 128` (32 s), preprocessed by the SigLIP2 image processor. `valid_mask` is `(B, T)`
bool marking real frames in a padded batch. Both encode paths run under `torch.no_grad()`
and use the EMA target encoder θ̄.

For batched encoding of a clip manifest, see `scripts/encode.sh` in the [code repo][code].

## Results

**Cross-view semantic alignment.** Gains over the best baseline, ViewpointRosetta: +10.4 on
Retrieval, +11.5 on Association, +7.46 on Recognition, +7.32 on Anticipation. Skill
Assessment is the exception, where PRISM (55.28) only matches ViewpointRosetta (55.82);
proficiency cues depend on execution style rather than action identity, so they land in the
view-variant stream.

| Method | <sub>**EgoExo4D**</sub><br>Retr. ego→exo | <br>exo→ego | <br>avg | <br>Recog. top-1 | <br>Skill | <sub>**EgoExoLearn**</sub><br>Assoc. avg | <br>Antic. avg | <br>Skill |
|:---|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
| CLIP | 19.11 | 12.24 | 15.68 | 10.49 | 54.93 | 15.82 | 38.70 | 73.48 |
| SigLIP2 | 35.08 | 19.72 | 27.40 | 13.86 | 55.57 | 26.6 | 64.60 | **76.03** |
| LaViLa | 34.91 | 12.02 | 23.47 | 26.43 | 54.10 | 27.20 | 62.83 | 68.44 |
| SUM-L | 47.14 | 32.77 | 39.96 | 24.83 | 55.10 | 4.64 | 45.50 | 65.31 |
| ViewpointRosetta | 58.14 | 47.21 | 52.68 | 34.47 | **55.82** | 32.32 | 62.14 | 73.70 |
| **PRISM** | **75.89** | **50.27** | **63.08** | **41.93** | 55.28 | **43.86** | **69.46** | 68.53 |

**Fine-grained temporal modeling (AE2).** Best among out-of-domain models on all four
tasks, and ahead of the best in-domain model on phase ordering and phase progression.

| Method | AE2 videos | Frame retr.<br><sub>mAP@10</sub> | Phase order<br><sub>Kendall's τ</sub> | Phase class.<br><sub>F1</sub> | Phase prog.<br><sub></sub> |
|:---|:--:|:--:|:--:|:--:|:--:|
| GTA | ✔ | 68.08 | 0.464 | 67.77 | 0.322 |
| AE2 | ✔ | 73.20 | 0.562 | 74.47 | 0.480 |
| SigLIP2 | ✘ | 45.56 | 0.020 | 43.91 | −1.322 |
| ViewpointRosetta | ✘ | 54.17 | 0.047 | 46.93 | −0.150 |
| **PRISM** | ✘ | **70.53** | **0.601** | **73.57** | **0.647** |

**Robustness to background correlation (UNSCENE).** On videos whose action contradicts the
background, averaged over three text encoders, PRISM reaches 14.9 R@10 and 0.181 RSA,
against 7.5 / 0.098 for ViewpointRosetta and 14.1 / 0.146 for DINOv2.

Full tables, ablations, and the DEVIAS stream-probe analysis are in the [paper][paper] and
the [code repo][code].

## Architecture

| Component | |
|:---|:---|
| Vision backbone | `google/siglip2-so400m-patch14-384`, frozen and not stored here |
| Text backbone | `Qwen/Qwen3-Embedding-0.6B`, frozen and not stored here |
| Decompositional Encoder θ | 4-layer Q-Former (2 queries → `z_vi`, `z_vv`) + 12-layer causal temporal stack per stream |
| Compositional Latent Predictor φ | 4-layer causal transformer over `concat(z_vv, z_vi)`, with `cls_head` / `vi_head` / `vv_head` |
| Target encoder θ̄ | EMA of θ, decay 0.998 |
| Embedding dim | 512 |

This repo holds trained weights only: θ, φ, θ̄, and the logit scale. The two backbones are
re-downloaded from the Hub when the model is constructed, so nothing about them is
duplicated here.

## Training

EgoExo4D, 6 epochs, batch 4 × 7 GPUs (DDP), constant-with-warmup lr 7e-5 (10% warmup),
weight decay 0.01, grad-clip 1.0, bf16, seed 42. Video sampled at 4 fps, clips capped at
32 s / 128 frames, 384×384. Objective `L = 1.0 · L_decomp + 0.5 · L_temp`, InfoNCE
all-gathered across ranks, sliding-shift augmentation on.

Per-clip view-invariant / view-variant captions are a *provided input*; recomposed captions
are generated online by a local vLLM server running `Qwen/Qwen3-1.7B`. Full recipe in the
[code repo][code].

## Limitations

Trained on EgoExo4D, which is skill-centric, mostly indoor, and recorded as ego/exo camera
pairs. Domains far from that distribution are untested. Clips longer than 32 s are truncated
to the first 128 sampled frames. The training pipeline needs decoupled view-invariant and
view-variant captions, which most datasets do not ship.

## Citation

- [ ] TODO: Add citation once published.

MIT licensed. The frozen backbones keep their own licenses.

<!-- swap these when the links go live -->
[paper]:   https://github.com/litcoderr/prism
[project]: https://github.com/litcoderr/prism
[code]:    https://github.com/litcoderr/prism