leochen085 commited on
Commit
c600982
·
verified ·
1 Parent(s): 0c7f3e3

Upload SLIP model, checkpoints, and source code

Browse files
Files changed (3) hide show
  1. config.json +1 -0
  2. configuration_slip.py +47 -0
  3. modeling_slip.py +536 -188
config.json CHANGED
@@ -4,6 +4,7 @@
4
  "SLIP"
5
  ],
6
  "auto_map": {
 
7
  "AutoModel": "modeling_slip.SLIPModel"
8
  },
9
  "llm_model_name": "google/gemma-3-270m",
 
4
  "SLIP"
5
  ],
6
  "auto_map": {
7
+ "AutoConfig": "configuration_slip.SLIPConfig",
8
  "AutoModel": "modeling_slip.SLIPModel"
9
  },
10
  "llm_model_name": "google/gemma-3-270m",
configuration_slip.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """SLIP model configuration for HuggingFace Hub."""
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ class SLIPConfig(PretrainedConfig):
7
+ model_type = "slip"
8
+
9
+ def __init__(
10
+ self,
11
+ llm_model_name="google/gemma-3-270m",
12
+ max_llm_len=768,
13
+ num_img_queries=64,
14
+ num_heads=5,
15
+ caption_loss_weight=1.0,
16
+ contrastive_loss_weight=1.0,
17
+ use_lora=False,
18
+ unlocked_layers=4,
19
+ split_layer=12,
20
+ common_dim=640,
21
+ post_train=True,
22
+ sensor_encoder=None,
23
+ **kwargs,
24
+ ):
25
+ super().__init__(**kwargs)
26
+ self.llm_model_name = llm_model_name
27
+ self.max_llm_len = max_llm_len
28
+ self.num_img_queries = num_img_queries
29
+ self.num_heads = num_heads
30
+ self.caption_loss_weight = caption_loss_weight
31
+ self.contrastive_loss_weight = contrastive_loss_weight
32
+ self.use_lora = use_lora
33
+ self.unlocked_layers = unlocked_layers
34
+ self.split_layer = split_layer
35
+ self.common_dim = common_dim
36
+ self.post_train = post_train
37
+ self.sensor_encoder = sensor_encoder or {
38
+ "embed_dim": 768,
39
+ "num_heads": 12,
40
+ "mlp_ratio": 4,
41
+ "depth": 12,
42
+ "dropout_rate": 0.1,
43
+ "learnable_pos_emb": False,
44
+ "max_position_embeddings": 4880,
45
+ "patch_size": None,
46
+ "channel_attn_type": "all_attn",
47
+ }
modeling_slip.py CHANGED
@@ -1,40 +1,467 @@
1
  """
2
- SLIP Model - HuggingFace Hub Loading Interface
 
3
 
4
  Usage:
5
- from modeling_slip import SLIPModel
6
- model = SLIPModel.from_pretrained("LeoChen085/SLIP")
7
-
8
- # Or load a task-specific checkpoint:
9
- model = SLIPModel.from_pretrained("LeoChen085/SLIP", checkpoint="har.safetensors")
 
 
 
 
10
  """
11
 
12
- import os
13
- import sys
14
- import json
15
  import math
16
  import torch
17
  import torch.nn as nn
18
- from pathlib import Path
19
- from typing import Optional
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- # Ensure model_factory and util are importable from the HF cache directory
22
- _THIS_DIR = Path(__file__).resolve().parent
23
- if str(_THIS_DIR) not in sys.path:
24
- sys.path.insert(0, str(_THIS_DIR))
25
 
26
- from model_factory.ts_transformer import (
27
- SensorTransformerModel,
28
- AttentionPooling,
29
- CrossAttention,
30
- )
31
- from model_factory.multimodal_gemma import (
32
- Gemma3MultimodalModel,
33
- Residual,
34
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
 
37
- # ── Lightweight helpers (from SLIP.py, no distributed deps) ──
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  def masked_mean(t, mask, dim=1, eps=1e-6):
40
  t = t.masked_fill(~mask, 0.)
@@ -49,54 +476,56 @@ class EmbedToLatents(nn.Module):
49
  self.to_latents = nn.Linear(dim, dim_latents, bias=False)
50
 
51
  def forward(self, x):
52
- latents = self.to_latents(x)
53
- return torch.nn.functional.normalize(latents, dim=-1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
 
56
- class SLIPModel(nn.Module):
57
  """
58
- SLIP model for inference. Loads from HuggingFace Hub without Hydra dependency.
59
 
60
- Supports:
61
- - get_embedding(text, sensors) -> (text_emb, sensor_emb)
62
- - get_sensor_embedding(input_ids, mask, time_index) -> sensor_emb
63
- - generate(text, sensors) -> generated_token_ids
64
- - sft_training(text, sensors) -> loss_dict
65
  """
66
 
67
- def __init__(self, config: dict):
68
- super().__init__()
69
 
70
- # Build sensor encoder directly (no Hydra)
71
- sensor_cfg = config["sensor_encoder"]
72
  self.sensor_encoder = SensorTransformerModel(**sensor_cfg)
 
73
 
74
- dim = self.sensor_encoder.embed_dim # 768
75
- self.embed_dim = dim
76
-
77
- # Build multimodal LLM
78
- llm_model_name = config.get("llm_model_name", "google/gemma-3-270m")
79
- post_train = config.get("post_train", True)
80
- split_layer = config.get("split_layer", 12)
81
  self.multimodalModel = Gemma3MultimodalModel(
82
- llm_model_name, post_train, split_layer
 
 
83
  )
84
 
85
- lm_dim = self.multimodalModel.hidden_size # 640
86
- self.lm_dim = lm_dim
87
- common_dim = config.get("common_dim", lm_dim)
88
 
89
  # Attention pooling
90
- num_img_queries = config.get("num_img_queries", 0)
91
  if num_img_queries > 0:
92
- self.img_queries = nn.Parameter(
93
- torch.randn(num_img_queries + 1, common_dim)
94
- )
95
  self.img_attn_pool = AttentionPooling(
96
- dim=common_dim,
97
- context_dim=dim,
98
- num_heads=config.get("num_heads", 5),
99
- )
100
  dim = common_dim
101
 
102
  # Bridge projections
@@ -107,166 +536,85 @@ class SLIPModel(nn.Module):
107
  self.temperature = nn.Parameter(torch.tensor(math.log(1 / 0.07)))
108
  self.temperature_max = math.log(1 / 0.07)
109
 
110
- # Store config
111
- self.config_dict = config
112
-
113
- @classmethod
114
- def from_pretrained(
115
- cls,
116
- repo_id_or_path: str,
117
- checkpoint: str = "model.safetensors",
118
- device: str = "cpu",
119
- dtype: torch.dtype = torch.bfloat16,
120
- **kwargs,
121
- ) -> "SLIPModel":
122
- """
123
- Load SLIP from a HuggingFace repo or local directory.
124
-
125
- Args:
126
- repo_id_or_path: HuggingFace repo ID (e.g., "LeoChen085/SLIP")
127
- or local directory path.
128
- checkpoint: Which checkpoint file to load.
129
- Default "model.safetensors" (base pretrained).
130
- Options: "har.safetensors", "sleep.safetensors",
131
- "ecg.safetensors", "tsqa.safetensors",
132
- "caption.safetensors"
133
- device: Device to load model on.
134
- dtype: Model dtype (default bfloat16).
135
- """
136
- local_path = Path(repo_id_or_path)
137
-
138
- if local_path.is_dir():
139
- # Load from local directory
140
- config_path = local_path / "config.json"
141
- weights_path = local_path / checkpoint
142
- else:
143
- # Download from HuggingFace Hub
144
- from huggingface_hub import hf_hub_download
145
-
146
- config_path = hf_hub_download(repo_id_or_path, "config.json")
147
- weights_path = hf_hub_download(repo_id_or_path, checkpoint)
148
-
149
- # Also download source files (needed for model classes)
150
- for src_file in [
151
- "model_factory/__init__.py",
152
- "model_factory/SLIP.py",
153
- "model_factory/multimodal_gemma.py",
154
- "model_factory/ts_transformer.py",
155
- "util/__init__.py",
156
- "util/pos_embed.py",
157
- ]:
158
- try:
159
- hf_hub_download(repo_id_or_path, src_file)
160
- except Exception:
161
- pass # File may not exist separately
162
-
163
- # Load config
164
- with open(config_path) as f:
165
- config = json.load(f)
166
-
167
- # Build model
168
- print(f"Building SLIP model...")
169
- model = cls(config)
170
-
171
- # Load weights
172
- print(f"Loading weights from {checkpoint}...")
173
- if str(weights_path).endswith(".safetensors"):
174
- from safetensors.torch import load_file
175
- state_dict = load_file(weights_path, device=device)
176
- else:
177
- state_dict = torch.load(weights_path, map_location=device, weights_only=False)
178
- if isinstance(state_dict, dict):
179
- if "model" in state_dict:
180
- state_dict = state_dict["model"]
181
- elif "state_dict" in state_dict:
182
- state_dict = state_dict["state_dict"]
183
- # Remove DDP module. prefix
184
- state_dict = {
185
- k.replace("module.", "", 1) if k.startswith("module.") else k: v
186
- for k, v in state_dict.items()
187
- if isinstance(v, torch.Tensor)
188
- }
189
-
190
- # Load state dict
191
- missing, unexpected = model.load_state_dict(state_dict, strict=False)
192
- if missing:
193
- print(f"Missing keys ({len(missing)}): {missing[:5]}{'...' if len(missing) > 5 else ''}")
194
- if unexpected:
195
- print(f"Unexpected keys ({len(unexpected)}): {unexpected[:5]}{'...' if len(unexpected) > 5 else ''}")
196
-
197
- model = model.to(dtype=dtype, device=device)
198
- model.eval()
199
- print("Model loaded successfully.")
200
- return model
201
-
202
- # ── Inference methods ─────────────────────────────────────
203
-
204
  def embed_sensor(self, sensors, sensor_attn_mask=None, time_index=None):
205
- from einops import repeat
206
- sensor_tokens, attn_mask = self.sensor_encoder(
207
- sensors, sensor_attn_mask, time_index=time_index
208
- )
209
  if hasattr(self, "img_attn_pool"):
210
- img_queries = repeat(
211
- self.img_queries, "n d -> b n d", b=sensor_tokens.shape[0]
212
- )
213
  sensor_tokens = self.img_attn_pool(img_queries, sensor_tokens, attn_mask)
214
  return sensor_tokens, attn_mask.bool()
215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  @torch.no_grad()
217
  def get_embedding(self, text, sensors):
218
- from einops import rearrange
219
  sensor_hidden, sensor_mask = self.embed_sensor(
220
- sensors=sensors["input_ids"],
221
- sensor_attn_mask=sensors["attention_mask"],
222
- time_index=sensors["time_index"],
223
- )
224
  self.multimodalModel.condition_image(sensor_hidden)
225
  text_hidden, _ = self.multimodalModel(
226
- input_ids=text["input_ids"][:, :-1],
227
- attention_mask=text["attention_mask"][:, :-1],
228
- )
229
  text_hidden = self.text_to_latents(text_hidden)
230
  sensor_hidden = self.img_to_latents(sensor_hidden)
231
  if hasattr(self, "img_attn_pool"):
232
  sensor_hidden = sensor_hidden[:, 0, :]
233
  else:
234
- sensor_hidden = masked_mean(
235
- sensor_hidden,
236
- rearrange(sensor_mask, "b n p -> b (n p) 1"),
237
- dim=1,
238
- )
239
  return text_hidden, sensor_hidden
240
 
241
  @torch.no_grad()
242
  def get_sensor_embedding(self, input_ids, mask, time_index):
243
- from einops import rearrange
244
- sensor_hidden, sensor_mask = self.embed_sensor(
245
- sensors=input_ids, sensor_attn_mask=mask, time_index=time_index
246
- )
247
  sensor_hidden = self.img_to_latents(sensor_hidden)
248
  if hasattr(self, "img_attn_pool"):
249
  sensor_hidden = sensor_hidden[:, 0, :]
250
  else:
251
- sensor_hidden = masked_mean(
252
- sensor_hidden,
253
- rearrange(sensor_mask, "b n p -> b (n p) 1"),
254
- dim=1,
255
- )
256
  return sensor_hidden
257
 
258
  @torch.no_grad()
259
  def generate(self, text, sensors, **generate_kwargs):
260
  sensor_hidden, _ = self.embed_sensor(
261
- sensors=sensors["input_ids"],
262
- sensor_attn_mask=sensors["attention_mask"],
263
- time_index=sensors["time_index"],
264
- )
265
  self.multimodalModel.condition_image(sensor_hidden)
266
  return self.multimodalModel.model.generate(
267
- input_ids=text["input_ids"],
268
- attention_mask=text["attention_mask"],
269
  max_new_tokens=generate_kwargs.get("max_new_tokens", 300),
270
  do_sample=generate_kwargs.get("do_sample", False),
271
- num_beams=generate_kwargs.get("num_beams", 1),
272
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
+ SLIP: Sensor Language Integrated Pre-training
3
+ Self-contained model file for HuggingFace Hub (trust_remote_code=True).
4
 
5
  Usage:
6
+ from transformers import AutoModel, AutoTokenizer
7
+ model = AutoModel.from_pretrained("LeoChen085/SLIP", trust_remote_code=True, device_map="auto")
8
+ tokenizer = AutoTokenizer.from_pretrained("LeoChen085/SLIP", trust_remote_code=True)
9
+
10
+ # Task-specific checkpoint (download manually):
11
+ from huggingface_hub import hf_hub_download
12
+ from safetensors.torch import load_file
13
+ state_dict = load_file(hf_hub_download("LeoChen085/SLIP", "har.safetensors"))
14
+ model.load_state_dict(state_dict, strict=False)
15
  """
16
 
 
 
 
17
  import math
18
  import torch
19
  import torch.nn as nn
20
+ import torch.nn.functional as F
21
+ from typing import Optional, Tuple, List
22
+ from einops import rearrange, repeat, reduce
23
+ from transformers import AutoConfig, AutoModelForCausalLM, PreTrainedModel
24
+ from transformers.activations import ACT2FN
25
+ from configuration_slip import SLIPConfig
26
+
27
+
28
+ # ═══════════════════════════════════════════════════════════════
29
+ # Positional Embeddings
30
+ # ═══════════════════════════════════════════════════════════════
31
+
32
+ class RotaryEmbedding(nn.Module):
33
+ def __init__(self, dim, max_position_embeddings=10000, base=10000, device=None):
34
+ super().__init__()
35
+ self.dim = dim
36
+ self.max_position_embeddings = max_position_embeddings
37
+ self.base = base
38
+ inv_freq = 1.0 / (self.base ** (torch.arange(0, self.dim,
39
+ 2, dtype=torch.int64).float().to(device) / self.dim))
40
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
41
+ self._set_cos_sin_cache(
42
+ seq_len=max_position_embeddings, device=self.inv_freq.device, dtype=torch.get_default_dtype())
43
+
44
+ def _set_cos_sin_cache(self, seq_len, device, dtype):
45
+ self.max_seq_len_cached = seq_len
46
+ t = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq)
47
+ freqs = torch.outer(t, self.inv_freq)
48
+ emb = torch.cat((freqs, freqs), dim=-1)
49
+ self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)
50
+ self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)
51
+
52
+ def forward(self, x, seq_len=None):
53
+ if seq_len > self.max_seq_len_cached:
54
+ self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype)
55
+ return (self.cos_cached[:seq_len].to(dtype=x.dtype), self.sin_cached[:seq_len].to(dtype=x.dtype))
56
+
57
+
58
+ def rotate_half(x):
59
+ x1 = x[..., : x.shape[-1] // 2]
60
+ x2 = x[..., x.shape[-1] // 2:]
61
+ return torch.cat((-x2, x1), dim=-1)
62
+
63
+
64
+ def apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1):
65
+ cos = cos[position_ids].unsqueeze(unsqueeze_dim)
66
+ sin = sin[position_ids].unsqueeze(unsqueeze_dim)
67
+ return (q * cos) + (rotate_half(q) * sin), (k * cos) + (rotate_half(k) * sin)
68
+
69
+
70
+ def apply_rotary_pos_emb_2d(q, k, cos_h, sin_h, cos_w, sin_w, pos_h, pos_w, unsqueeze_dim=1):
71
+ Dh = q.shape[-1]
72
+ q_h, q_w = q.split(Dh // 2, dim=-1)
73
+ k_h, k_w = k.split(Dh // 2, dim=-1)
74
+ q_h, k_h = apply_rotary_pos_emb(q_h, k_h, cos_h, sin_h, pos_h.long(), unsqueeze_dim=unsqueeze_dim)
75
+ q_w, k_w = apply_rotary_pos_emb(q_w, k_w, cos_w, sin_w, pos_w.long(), unsqueeze_dim=unsqueeze_dim)
76
+ return torch.cat([q_h, q_w], dim=-1), torch.cat([k_h, k_w], dim=-1)
77
+
78
+
79
+ def build_2d_position_ids(attention_mask, flatten=True):
80
+ B, V, P = attention_mask.shape
81
+ mask = attention_mask.to(dtype=torch.long)
82
+ pos_patch = (mask.cumsum(dim=-1) - 1) * mask
83
+ var_valid = mask.any(dim=-1).to(dtype=torch.long)
84
+ pos_var_base = (var_valid.cumsum(dim=1) - 1) * var_valid
85
+ pos_var = pos_var_base.unsqueeze(-1).expand(B, V, P) * mask
86
+ if flatten:
87
+ return pos_var.reshape(B, V * P).long(), pos_patch.reshape(B, V * P).long()
88
+ return pos_var.long(), pos_patch.long()
89
+
90
+
91
+ # ═══════════════════════════════════════════════════════════════
92
+ # Sensor Encoder Components
93
+ # ═══════════════════════════════════════════════════════════════
94
+
95
+ def flatten_list(input_list):
96
+ return [item for sublist in input_list for item in sublist]
97
+
98
+
99
+ class MLP(nn.Module):
100
+ def __init__(self, hidden_size, intermediate_size, hidden_act):
101
+ super().__init__()
102
+ self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
103
+ self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
104
+ self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
105
+ self.act_fn = ACT2FN[hidden_act]
106
+
107
+ def forward(self, hidden_state):
108
+ return self.down_proj(self.act_fn(self.gate_proj(hidden_state)) * self.up_proj(hidden_state))
109
+
110
+
111
+ class TsRoPEAttention(nn.Module):
112
+ def __init__(self, layer_idx, **cfg):
113
+ super().__init__()
114
+ self.hidden_size = cfg.get("embed_dim", 768)
115
+ self.num_heads = cfg.get("num_heads", 12)
116
+ self.head_dim = self.hidden_size // self.num_heads
117
+ self.attention_dropout = cfg.get("dropout_rate", 0.1)
118
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
119
+ self.k_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
120
+ self.v_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
121
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
122
+ self.rotary_emb = RotaryEmbedding(self.head_dim // 2, max_position_embeddings=cfg.get("max_position_embeddings"))
123
+
124
+ def forward(self, hidden_states, attention_mask=None, **kwargs):
125
+ bsz, q_len, _ = hidden_states.size()
126
+ tmp_attn_mask = rearrange(attention_mask, 'b nvar p -> b (nvar p)')
127
+ query_states = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
128
+ key_states = self.k_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
129
+ value_states = self.v_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
130
+ tmp_attn_mask = tmp_attn_mask.unsqueeze(1).unsqueeze(2).expand(-1, 1, q_len, q_len).bool()
131
+ pos_var, pos_patch = build_2d_position_ids(attention_mask, flatten=True)
132
+ cos_h, sin_h = self.rotary_emb(query_states, seq_len=int(pos_var.max().item()) + 1)
133
+ cos_w, sin_w = self.rotary_emb(query_states, seq_len=int(pos_patch.max().item()) + 1)
134
+ query_states, key_states = apply_rotary_pos_emb_2d(
135
+ query_states, key_states, cos_h, sin_h, cos_w, sin_w, pos_var, pos_patch)
136
+ attn_output = F.scaled_dot_product_attention(
137
+ query_states, key_states, value_states, tmp_attn_mask, dropout_p=self.attention_dropout)
138
+ attn_output = attn_output.transpose(1, 2).contiguous().reshape(bsz, q_len, self.hidden_size)
139
+ return self.o_proj(attn_output)
140
+
141
+
142
+ class MultiSizePatchEmbed(nn.Module):
143
+ def __init__(self, base_patch=32, **cfg):
144
+ super().__init__()
145
+ self.base_patch = base_patch
146
+ hidden_size = cfg['embed_dim']
147
+ intermediate_size = cfg['mlp_ratio'] * hidden_size
148
+ self.intermediate_size = intermediate_size
149
+ self.hidden_size = hidden_size
150
+ self.shared_linear = nn.Linear(base_patch * 3, intermediate_size)
151
+ self.shared_residual = nn.Linear(base_patch * 3, hidden_size)
152
+ self.dropout = nn.Dropout(cfg['dropout_rate'])
153
+ self.act = ACT2FN['silu']
154
+ self.output_layer = nn.Linear(intermediate_size, hidden_size)
155
+
156
+ def resize_weight(self, patch_size):
157
+ base_w, base_b = self.shared_linear.weight, self.shared_linear.bias
158
+ res_w, res_b = self.shared_residual.weight, self.shared_residual.bias
159
+ new_w = F.interpolate(base_w.unsqueeze(1), size=patch_size, mode="linear", align_corners=False).squeeze(1).to(base_w.dtype)
160
+ new_res_w = F.interpolate(res_w.unsqueeze(1), size=patch_size, mode="linear", align_corners=False).squeeze(1).to(res_w.dtype)
161
+ return new_w, base_b, new_res_w, res_b
162
+
163
+ def forward(self, x_list, attention_mask, time_idx):
164
+ amp_dtype = torch.get_autocast_gpu_dtype() if torch.is_autocast_enabled() else torch.float32
165
+ device = torch.device("cuda", torch.cuda.current_device()) if torch.cuda.is_available() else torch.device("cpu")
166
+ sizes = torch.tensor([x.shape[-1] for x in x_list])
167
+ unique_sizes = sizes.unique(sorted=True)
168
+ N = x_list[0].shape[0]
169
+ outputs = torch.empty(len(x_list), N, self.intermediate_size, device=device, dtype=amp_dtype)
170
+ res_outputs = torch.empty(len(x_list), N, self.hidden_size, device=device, dtype=amp_dtype)
171
+ for psize in unique_sizes.tolist():
172
+ idxs = (sizes == psize).nonzero(as_tuple=True)[0]
173
+ xs = torch.stack([x_list[i] for i in idxs]).to(device=device, non_blocking=True)
174
+ mask = torch.stack([attention_mask[i] for i in idxs]).to(device=device, non_blocking=True)
175
+ ti = torch.stack([time_idx[i] for i in idxs]).to(device=device, non_blocking=True)
176
+ xs = torch.cat([xs, mask, ti], dim=-1)
177
+ w, b, r_w, r_b = self.resize_weight(psize * 3)
178
+ res_outputs[idxs] = F.linear(xs, r_w, r_b)
179
+ outputs[idxs] = F.linear(xs, w, b)
180
+ return self.dropout(self.output_layer(self.act(outputs))) + res_outputs
181
+
182
+
183
+ class PatchEmbedding(nn.Module):
184
+ def __init__(self, **cfg):
185
+ super().__init__()
186
+ patch_size = cfg['patch_size']
187
+ self.patch_size = patch_size
188
+ self.dropout = nn.Dropout(cfg.get('dropout_rate', 0.1))
189
+ hidden_size = cfg['embed_dim']
190
+ self.hidden_layer = nn.Linear(patch_size * 3, hidden_size)
191
+ self.act = ACT2FN['silu']
192
+ self.output_layer = nn.Linear(hidden_size, hidden_size)
193
+ self.residual_layer = nn.Linear(patch_size * 3, hidden_size)
194
+
195
+ def forward(self, x, mask, time_idx):
196
+ x = rearrange(x, 'bs nvar (nump ps) -> (bs nvar) nump ps', ps=self.patch_size)
197
+ mask = rearrange(mask, 'bs nvar (nump ps) -> (bs nvar) nump ps', ps=self.patch_size)
198
+ time_idx = rearrange(time_idx, 'bs nvar (nump ps) -> (bs nvar) nump ps', ps=self.patch_size)
199
+ x = torch.cat([x, mask, time_idx], dim=-1)
200
+ return self.dropout(self.output_layer(self.act(self.hidden_layer(x)))) + self.residual_layer(x)
201
+
202
+
203
+ class Attention(nn.Module):
204
+ def __init__(self, layer_idx, is_rope=True, **cfg):
205
+ super().__init__()
206
+ self.is_rope = is_rope
207
+ self.hidden_size = cfg.get("embed_dim", 768)
208
+ self.num_heads = cfg.get("num_heads", 12)
209
+ self.head_dim = self.hidden_size // self.num_heads
210
+ self.attention_dropout = cfg.get("dropout_rate", 0.1)
211
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
212
+ self.k_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
213
+ self.v_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=True)
214
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
215
+ if self.is_rope:
216
+ self.rotary_emb = RotaryEmbedding(self.head_dim, max_position_embeddings=cfg.get("sensor_max_len", 2880))
217
+
218
+ def forward(self, hidden_states, attention_mask=None, position_ids=None, **kwargs):
219
+ bsz, q_len, _ = hidden_states.size()
220
+ query_states = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
221
+ key_states = self.k_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
222
+ value_states = self.v_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
223
+ if self.is_rope:
224
+ cos, sin = self.rotary_emb(value_states, seq_len=key_states.shape[-2])
225
+ query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
226
+ attn_output = F.scaled_dot_product_attention(
227
+ query_states, key_states, value_states, attention_mask, dropout_p=self.attention_dropout)
228
+ return self.o_proj(attn_output.transpose(1, 2).contiguous().reshape(bsz, q_len, self.hidden_size))
229
+
230
+
231
+ class CrossAttention(nn.Module):
232
+ def __init__(self, dim=768, *, context_dim=384, num_heads=12, dropout_rate=0.1):
233
+ super().__init__()
234
+ self.dim = dim
235
+ self.num_heads = num_heads
236
+ self.head_dim = dim // num_heads
237
+ self.attn_dropout = dropout_rate
238
+ self.norm = nn.LayerNorm(dim)
239
+ self.context_norm = nn.LayerNorm(context_dim)
240
+ self.q_proj = nn.Linear(dim, dim, bias=True)
241
+ self.k_proj = nn.Linear(context_dim, dim, bias=True)
242
+ self.v_proj = nn.Linear(context_dim, dim, bias=True)
243
+ self.o_proj = nn.Linear(dim, dim, bias=False)
244
+
245
+ def forward(self, query, context, attention_mask=None, **kwargs):
246
+ bsz, q_len, _ = query.size()
247
+ k_len = context.size(1)
248
+ query = self.norm(query)
249
+ context = self.context_norm(context)
250
+ q = self.q_proj(query).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
251
+ k = self.k_proj(context).view(bsz, k_len, self.num_heads, self.head_dim).transpose(1, 2)
252
+ v = self.v_proj(context).view(bsz, k_len, self.num_heads, self.head_dim).transpose(1, 2)
253
+ attn_output = F.scaled_dot_product_attention(q, k, v, attention_mask, dropout_p=self.attn_dropout)
254
+ return self.o_proj(attn_output.transpose(1, 2).contiguous().reshape(bsz, q_len, self.dim))
255
+
256
+
257
+ class AllAttention(nn.Module):
258
+ def __init__(self, layer_idx, **cfg):
259
+ super().__init__()
260
+ self.self_attention = TsRoPEAttention(layer_idx=layer_idx, **cfg)
261
+ self.layer_norm = nn.LayerNorm(cfg.get('embed_dim'))
262
+ self.dropout = nn.Dropout(cfg.get('dropout_rate', 0.1))
263
+
264
+ def forward(self, hidden_states, attention_mask):
265
+ return hidden_states + self.dropout(self.self_attention(self.layer_norm(hidden_states), attention_mask))
266
+
267
+
268
+ class TimeSelfAttention(nn.Module):
269
+ def __init__(self, layer_idx, **cfg):
270
+ super().__init__()
271
+ self.self_attention = Attention(layer_idx=layer_idx, is_rope=True, **cfg)
272
+ self.layer_norm = nn.LayerNorm(cfg.get('embed_dim', 768))
273
+ self.dropout = nn.Dropout(cfg.get('dropout_rate', 0.1))
274
+
275
+ def forward(self, hidden_states, attention_mask, position_ids):
276
+ q_len = hidden_states.size(1)
277
+ am = rearrange(attention_mask, 'b nvar p -> (b nvar) p')
278
+ am = am.unsqueeze(1).unsqueeze(2).expand(-1, 1, q_len, q_len).bool()
279
+ return hidden_states + self.dropout(self.self_attention(self.layer_norm(hidden_states), am, position_ids))
280
+
281
+
282
+ class GroupSelfAttention(nn.Module):
283
+ def __init__(self, layer_idx, **cfg):
284
+ super().__init__()
285
+ self.self_attention = Attention(layer_idx, is_rope=False, **cfg)
286
+ self.layer_norm = nn.LayerNorm(cfg.get('embed_dim', 768))
287
+ self.dropout = nn.Dropout(cfg.get('dropout_rate', 0.1))
288
+
289
+ def forward(self, hidden_states, attention_mask, group_ids):
290
+ BS, nvar, _ = attention_mask.shape
291
+ hidden_states = rearrange(hidden_states, '(bs nvar) l d -> (bs l) nvar d', bs=BS, nvar=nvar)
292
+ am = rearrange(attention_mask, 'bs nvar l -> (bs l) nvar')
293
+ group_attn_mask = am.unsqueeze(1).unsqueeze(2).expand(-1, 1, nvar, nvar).bool()
294
+ hidden_states = hidden_states + self.dropout(self.self_attention(self.layer_norm(hidden_states), group_attn_mask))
295
+ return rearrange(hidden_states, '(bs l) nvar d -> (bs nvar) l d', bs=BS, nvar=nvar)
296
+
297
+
298
+ class AttentionPooling(nn.Module):
299
+ def __init__(self, dim=768, mlp_ratio=4, context_dim=384, num_heads=12, dropout_rate=0.1):
300
+ super().__init__()
301
+ self.cross_attn = CrossAttention(dim=dim, context_dim=context_dim, num_heads=num_heads, dropout_rate=dropout_rate)
302
+ self.ffn_norm = nn.LayerNorm(dim)
303
+ self.ffn_layer = MLP(hidden_size=dim, intermediate_size=dim * mlp_ratio, hidden_act='silu')
304
+ self.post_norm = nn.LayerNorm(dim)
305
+
306
+ def forward(self, x, context, attn_mask=None):
307
+ b, n, _ = x.shape
308
+ kv_len = context.shape[1]
309
+ attn_mask = rearrange(attn_mask, 'b nvar p -> b (nvar p)')
310
+ attn_mask = attn_mask.view(b, 1, 1, kv_len).expand(b, 1, n, kv_len).bool()
311
+ x = self.cross_attn(x, context, attn_mask)
312
+ x = x + self.ffn_layer(self.ffn_norm(x))
313
+ return self.post_norm(x)
314
+
315
+
316
+ class SensorEncoderLayer(nn.Module):
317
+ def __init__(self, layer_idx, **cfg):
318
+ super().__init__()
319
+ hidden_size = cfg['embed_dim']
320
+ self.channel_attn_type = cfg.get('channel_attn_type', 'group_attn')
321
+ if self.channel_attn_type == 'group_attn':
322
+ self.ts_attn = TimeSelfAttention(layer_idx=layer_idx, **cfg)
323
+ self.group_attn = GroupSelfAttention(layer_idx=layer_idx, **cfg)
324
+ elif self.channel_attn_type == 'univariate':
325
+ self.ts_attn = TimeSelfAttention(layer_idx=layer_idx, **cfg)
326
+ else:
327
+ self.ts_attn = AllAttention(layer_idx=layer_idx, **cfg)
328
+ self.norm = nn.LayerNorm(hidden_size)
329
+ self.ffn_layer = MLP(hidden_size=hidden_size, intermediate_size=cfg['mlp_ratio'] * hidden_size, hidden_act='silu')
330
+
331
+ def forward(self, hidden_states, attention_mask=None, group_ids=None, position_ids=None):
332
+ if self.channel_attn_type == 'group_attn':
333
+ hidden_states = self.ts_attn(hidden_states, attention_mask, position_ids)
334
+ hidden_states = self.group_attn(hidden_states, attention_mask, group_ids)
335
+ elif self.channel_attn_type == 'univariate':
336
+ hidden_states = self.ts_attn(hidden_states, attention_mask, position_ids)
337
+ else:
338
+ hidden_states = self.ts_attn(hidden_states, attention_mask)
339
+ residual = hidden_states
340
+ return residual + self.ffn_layer(self.norm(hidden_states))
341
 
 
 
 
 
342
 
343
+ class SensorTransformerModel(nn.Module):
344
+ def __init__(self, **cfg):
345
+ super().__init__()
346
+ patch_size = cfg.get('patch_size', None)
347
+ self.patch_size = patch_size
348
+ self.patch_embed = PatchEmbedding(**cfg) if patch_size else MultiSizePatchEmbed(**cfg)
349
+ self.blocks = nn.ModuleList([SensorEncoderLayer(i, **cfg) for i in range(cfg['depth'])])
350
+ self.norm = nn.LayerNorm(cfg['embed_dim'])
351
+ self.embed_dim = cfg['embed_dim']
352
+ self.channel_attn_type = cfg.get('channel_attn_type', 'group_attn')
353
+
354
+ def forward(self, input_ids, attention_mask, time_index):
355
+ if self.patch_size is None:
356
+ BS = len(input_ids)
357
+ hidden_states = self.patch_embed(flatten_list(input_ids), flatten_list(attention_mask), flatten_list(time_index))
358
+ attention_mask = self._get_self_attn_mask(attention_mask).to(hidden_states.device)
359
+ position_ids = rearrange(self._build_rope_position_ids(attention_mask), 'b nvar p -> (b nvar) p')
360
+ else:
361
+ BS = input_ids.shape[0]
362
+ hidden_states = self.patch_embed(input_ids, attention_mask, time_index)
363
+ attention_mask = reduce(attention_mask, 'b v (p ps) -> b v p', 'max', ps=self.patch_size)
364
+ position_ids = rearrange(self._build_rope_position_ids(attention_mask), 'b nvar p -> (b nvar) p')
365
+
366
+ if self.channel_attn_type == 'all_attn':
367
+ hidden_states = rearrange(hidden_states, '(b nvar) l d -> b (nvar l) d', b=BS)
368
+ for blk in self.blocks:
369
+ hidden_states = blk(hidden_states, attention_mask=attention_mask, group_ids=None, position_ids=position_ids)
370
+ if self.channel_attn_type == 'group_attn':
371
+ hidden_states = rearrange(hidden_states, '(b nvar) l d -> b (nvar l) d', b=BS)
372
+ return self.norm(hidden_states), attention_mask
373
+
374
+ def _build_rope_position_ids(self, attention_mask):
375
+ mask = attention_mask.to(torch.long)
376
+ return (mask.cumsum(dim=-1) - 1) * mask
377
+
378
+ def _get_self_attn_mask(self, attn_mask_list):
379
+ collapsed = []
380
+ for sample_masks in attn_mask_list:
381
+ collapsed.append(torch.stack([(m.sum(dim=-1) > 0).to(m.dtype) for m in sample_masks], dim=0))
382
+ return torch.stack(collapsed, dim=0)
383
+
384
+
385
+ # ═══════════════════════════════════════════════════════════════
386
+ # Multimodal Gemma
387
+ # ═══════════════════════════════════════════════════════════════
388
+
389
+ class Residual(nn.Module):
390
+ def __init__(self, fn):
391
+ super().__init__()
392
+ self.fn = fn
393
+
394
+ def forward(self, x, *args, **kwargs):
395
+ return self.fn(x, *args, **kwargs) + x
396
 
397
 
398
+ class Gemma3MultimodalLayer(nn.Module):
399
+ def __init__(self, original_layer, cross_attn_block):
400
+ super().__init__()
401
+ self.original_layer = original_layer
402
+ self.cross_attn_block = cross_attn_block
403
+ self.vis_x = None
404
+
405
+ def condition_vis_x(self, vis_x):
406
+ self.vis_x = vis_x
407
+
408
+ def __getattr__(self, name):
409
+ try:
410
+ return super().__getattr__(name)
411
+ except AttributeError:
412
+ return getattr(self.original_layer, name)
413
+
414
+ def forward(self, hidden_states, **kwargs):
415
+ assert self.vis_x is not None, "vis_x must be set before forward pass."
416
+ outputs = self.original_layer(hidden_states, **kwargs)
417
+ hidden_states = self.cross_attn_block(outputs[0], context=self.vis_x)
418
+ return (hidden_states,) + outputs[1:]
419
+
420
+
421
+ class Gemma3MultimodalModel(nn.Module):
422
+ def __init__(self, model_id="google/gemma-3-270m", init_from_pretrained=False, split_layer=12):
423
+ super().__init__()
424
+ # When loading from HF (from_pretrained), we init from scratch
425
+ # since the safetensors file already contains all weights.
426
+ # Only init from pretrained when training from scratch.
427
+ if init_from_pretrained:
428
+ self.model = AutoModelForCausalLM.from_pretrained(
429
+ model_id, dtype=torch.bfloat16, trust_remote_code=True)
430
+ else:
431
+ config = AutoConfig.from_pretrained(model_id, trust_remote_code=True)
432
+ self.model = AutoModelForCausalLM.from_config(
433
+ config, torch_dtype=torch.bfloat16, trust_remote_code=True)
434
+
435
+ self.split_layer = split_layer
436
+ hidden_size = self.model.config.hidden_size
437
+ num_heads = self.model.config.num_attention_heads
438
+ self.hidden_size = hidden_size
439
+
440
+ for i in range(split_layer, len(self.model.model.layers)):
441
+ cross_attn = CrossAttention(
442
+ dim=hidden_size, context_dim=hidden_size, num_heads=num_heads, dropout_rate=0.1)
443
+ self.model.model.layers[i] = Gemma3MultimodalLayer(
444
+ self.model.model.layers[i], Residual(cross_attn))
445
+ self.to(torch.bfloat16)
446
+
447
+ def condition_image(self, image_embeds):
448
+ self.image_embeds = image_embeds.to(next(self.parameters()).device, dtype=torch.bfloat16)
449
+ for layer in self.model.model.layers:
450
+ if isinstance(layer, Gemma3MultimodalLayer):
451
+ layer.condition_vis_x(self.image_embeds)
452
+
453
+ def forward(self, input_ids, attention_mask=None, return_embeddings=False, **kwargs):
454
+ outputs = self.model(
455
+ input_ids=input_ids, attention_mask=attention_mask, output_hidden_states=True, **kwargs)
456
+ text_sentence_embedding = outputs.hidden_states[self.split_layer][:, -1, :]
457
+ if return_embeddings:
458
+ return outputs
459
+ return text_sentence_embedding, outputs.logits
460
+
461
+
462
+ # ═══════════════════════════════════════════════════════════════
463
+ # SLIP Model (PreTrainedModel for HuggingFace Auto* classes)
464
+ # ═════════════════════════════════���═════════════════════════════
465
 
466
  def masked_mean(t, mask, dim=1, eps=1e-6):
467
  t = t.masked_fill(~mask, 0.)
 
476
  self.to_latents = nn.Linear(dim, dim_latents, bias=False)
477
 
478
  def forward(self, x):
479
+ return F.normalize(self.to_latents(x), dim=-1)
480
+
481
+
482
+ class SLIPPreTrainedModel(PreTrainedModel):
483
+ config_class = SLIPConfig
484
+ base_model_prefix = "slip"
485
+ supports_gradient_checkpointing = False
486
+
487
+ def _init_weights(self, module):
488
+ if isinstance(module, nn.Linear):
489
+ nn.init.xavier_uniform_(module.weight)
490
+ if module.bias is not None:
491
+ nn.init.constant_(module.bias, 0)
492
+ elif isinstance(module, nn.LayerNorm):
493
+ nn.init.constant_(module.bias, 0)
494
+ nn.init.constant_(module.weight, 1.0)
495
 
496
 
497
+ class SLIPModel(SLIPPreTrainedModel):
498
  """
499
+ SLIP: Sensor Language Integrated Pre-training.
500
 
501
+ Usage:
502
+ model = AutoModel.from_pretrained("LeoChen085/SLIP", trust_remote_code=True)
 
 
 
503
  """
504
 
505
+ def __init__(self, config: SLIPConfig):
506
+ super().__init__(config)
507
 
508
+ # Sensor encoder
509
+ sensor_cfg = config.sensor_encoder
510
  self.sensor_encoder = SensorTransformerModel(**sensor_cfg)
511
+ dim = self.sensor_encoder.embed_dim
512
 
513
+ # Multimodal LLM (init from scratch — weights come from safetensors)
 
 
 
 
 
 
514
  self.multimodalModel = Gemma3MultimodalModel(
515
+ config.llm_model_name,
516
+ init_from_pretrained=False,
517
+ split_layer=config.split_layer,
518
  )
519
 
520
+ lm_dim = self.multimodalModel.hidden_size
521
+ common_dim = config.common_dim
 
522
 
523
  # Attention pooling
524
+ num_img_queries = config.num_img_queries
525
  if num_img_queries > 0:
526
+ self.img_queries = nn.Parameter(torch.randn(num_img_queries + 1, common_dim))
 
 
527
  self.img_attn_pool = AttentionPooling(
528
+ dim=common_dim, context_dim=dim, num_heads=config.num_heads)
 
 
 
529
  dim = common_dim
530
 
531
  # Bridge projections
 
536
  self.temperature = nn.Parameter(torch.tensor(math.log(1 / 0.07)))
537
  self.temperature_max = math.log(1 / 0.07)
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  def embed_sensor(self, sensors, sensor_attn_mask=None, time_index=None):
540
+ sensor_tokens, attn_mask = self.sensor_encoder(sensors, sensor_attn_mask, time_index=time_index)
 
 
 
541
  if hasattr(self, "img_attn_pool"):
542
+ img_queries = repeat(self.img_queries, "n d -> b n d", b=sensor_tokens.shape[0])
 
 
543
  sensor_tokens = self.img_attn_pool(img_queries, sensor_tokens, attn_mask)
544
  return sensor_tokens, attn_mask.bool()
545
 
546
+ def forward(self, text=None, sensors=None, **kwargs):
547
+ """
548
+ Forward pass for contrastive + captioning training.
549
+ For inference, use get_embedding(), get_sensor_embedding(), or generate().
550
+ """
551
+ sensor_hidden, sensor_mask = self.embed_sensor(
552
+ sensors=sensors["input_ids"], sensor_attn_mask=sensors["attention_mask"],
553
+ time_index=sensors["time_index"])
554
+ self.multimodalModel.condition_image(sensor_hidden)
555
+ text_hidden, logits = self.multimodalModel(
556
+ input_ids=text["input_ids"][:, :-1], attention_mask=text["attention_mask"][:, :-1])
557
+ text_hidden = self.text_to_latents(text_hidden)
558
+ sensor_hidden = self.img_to_latents(sensor_hidden)
559
+ return {"text_hidden": text_hidden, "sensor_hidden": sensor_hidden, "logits": logits}
560
+
561
  @torch.no_grad()
562
  def get_embedding(self, text, sensors):
 
563
  sensor_hidden, sensor_mask = self.embed_sensor(
564
+ sensors=sensors["input_ids"], sensor_attn_mask=sensors["attention_mask"],
565
+ time_index=sensors["time_index"])
 
 
566
  self.multimodalModel.condition_image(sensor_hidden)
567
  text_hidden, _ = self.multimodalModel(
568
+ input_ids=text["input_ids"][:, :-1], attention_mask=text["attention_mask"][:, :-1])
 
 
569
  text_hidden = self.text_to_latents(text_hidden)
570
  sensor_hidden = self.img_to_latents(sensor_hidden)
571
  if hasattr(self, "img_attn_pool"):
572
  sensor_hidden = sensor_hidden[:, 0, :]
573
  else:
574
+ sensor_hidden = masked_mean(sensor_hidden, rearrange(sensor_mask, "b n p -> b (n p) 1"), dim=1)
 
 
 
 
575
  return text_hidden, sensor_hidden
576
 
577
  @torch.no_grad()
578
  def get_sensor_embedding(self, input_ids, mask, time_index):
579
+ sensor_hidden, sensor_mask = self.embed_sensor(sensors=input_ids, sensor_attn_mask=mask, time_index=time_index)
 
 
 
580
  sensor_hidden = self.img_to_latents(sensor_hidden)
581
  if hasattr(self, "img_attn_pool"):
582
  sensor_hidden = sensor_hidden[:, 0, :]
583
  else:
584
+ sensor_hidden = masked_mean(sensor_hidden, rearrange(sensor_mask, "b n p -> b (n p) 1"), dim=1)
 
 
 
 
585
  return sensor_hidden
586
 
587
  @torch.no_grad()
588
  def generate(self, text, sensors, **generate_kwargs):
589
  sensor_hidden, _ = self.embed_sensor(
590
+ sensors=sensors["input_ids"], sensor_attn_mask=sensors["attention_mask"],
591
+ time_index=sensors["time_index"])
 
 
592
  self.multimodalModel.condition_image(sensor_hidden)
593
  return self.multimodalModel.model.generate(
594
+ input_ids=text["input_ids"], attention_mask=text["attention_mask"],
 
595
  max_new_tokens=generate_kwargs.get("max_new_tokens", 300),
596
  do_sample=generate_kwargs.get("do_sample", False),
597
+ num_beams=generate_kwargs.get("num_beams", 1))
598
+
599
+ def sft_training(self, text, sensors, return_output=False):
600
+ sensor_hidden, _ = self.embed_sensor(
601
+ sensors=sensors["input_ids"], sensor_attn_mask=sensors["attention_mask"],
602
+ time_index=sensors["time_index"])
603
+ self.multimodalModel.condition_image(sensor_hidden)
604
+ outputs = self.multimodalModel.model(
605
+ input_ids=text["input_ids"], attention_mask=text["attention_mask"], return_dict=True)
606
+ if return_output:
607
+ return outputs
608
+ logits = outputs.logits
609
+ labels = text["labels"]
610
+ shift_logits = logits[:, :-1, :].contiguous()
611
+ shift_labels = labels[:, 1:].contiguous()
612
+ ce = F.cross_entropy(
613
+ shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1),
614
+ reduction="none", ignore_index=-100)
615
+ if "loss_weights" in text:
616
+ loss_weights = text["loss_weights"][:, 1:].contiguous().view(-1)
617
+ loss = (ce * loss_weights).sum() / loss_weights.sum()
618
+ else:
619
+ loss = ce.mean()
620
+ return {"loss": loss}