SII-CDZ commited on
Commit
d23d652
·
verified ·
1 Parent(s): 04da911

Delete modeling_prismatic.py.back.20260315_132404

Browse files
modeling_prismatic.py.back.20260315_132404 DELETED
@@ -1,1272 +0,0 @@
1
- """
2
- modeling_prismatic.py
3
-
4
- Core HuggingFace-style PrismaticPreTrainedModel and PrismaticForConditionalGeneration class definitions.
5
- Inherits from the default `transformers.PretrainedModel`. Meant to be standalone and self-contained,
6
- but exactly replicate the logic in `prismatic.models.vlms.prismatic.py`.
7
- """
8
-
9
- import logging
10
- from dataclasses import dataclass
11
- from functools import partial
12
- import math
13
- import random
14
- from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple, Union
15
- import numpy as np
16
- import timm
17
- import tokenizers
18
- import torch
19
- import torch.nn as nn
20
- import transformers
21
- from timm.models.vision_transformer import LayerScale
22
- from transformers import AutoModelForCausalLM, PretrainedConfig, PreTrainedModel
23
- from transformers.modeling_outputs import ModelOutput
24
-
25
- from prismatic.training.train_utils import (
26
- get_current_action_mask,
27
- get_next_actions_mask,
28
- )
29
- from prismatic.vla.constants import (
30
- ACTION_DIM,
31
- ACTION_PROPRIO_NORMALIZATION_TYPE,
32
- ACTION_TOKEN_BEGIN_IDX,
33
- IGNORE_INDEX,
34
- NUM_ACTIONS_CHUNK,
35
- STOP_INDEX,
36
- NormalizationType,
37
- NUM_TOKENS
38
- )
39
- from .configuration_prismatic import OpenVLAConfig, PrismaticConfig
40
-
41
-
42
-
43
- # Set up logger
44
- logger = logging.getLogger(__name__)
45
-
46
-
47
- # === Utility Functions for Monkey-Patching ===
48
- def unpack_tuple(fn: Callable[[Any], Tuple[Any]]) -> Callable[[Any], Any]:
49
- def wrapper(*args: Any, **kwargs: Any) -> Any:
50
- result = fn(*args, **kwargs)
51
- return result[0] if isinstance(result, tuple) else result
52
-
53
- return wrapper
54
-
55
-
56
-
57
- # HF Transformers overwrites parameters with names containing `gamma`; we're going to patch VisionBackbone.LayerScale.
58
- # =>> TIMM :: https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/vision_transformer.py#L109
59
- # =>> Transformers :: https://github.com/huggingface/transformers/blob/main/src/transformers/modeling_utils.py#L3960
60
- def _ls_new_forward(self, x: torch.Tensor) -> torch.Tensor:
61
- return x.mul_(self.scale_factor) if self.inplace else x * self.scale_factor
62
-
63
-
64
-
65
- def ls_apply_patch(ls_module: LayerScale):
66
- ls_module.scale_factor = nn.Parameter(ls_module.gamma.clone())
67
- ls_module.forward = _ls_new_forward.__get__(ls_module, LayerScale)
68
- del ls_module.gamma
69
-
70
-
71
-
72
- # === Prismatic Vision Backbone (nn.Module) Definitions (w/ Fused Backbone Support) ===
73
- class PrismaticVisionBackbone(nn.Module):
74
- """
75
- Vision backbone for Prismatic models that handles image feature extraction.
76
-
77
- Supports both single backbone (e.g., SigLIP) and fused backbone (e.g., SigLIP + DINOv2) configurations.
78
- For fused backbones, features from both models are concatenated along the feature dimension.
79
- """
80
-
81
- def __init__(
82
- self,
83
- use_fused_vision_backbone: bool,
84
- image_sizes: List[int],
85
- timm_model_ids: List[str],
86
- timm_override_act_layers: List[Optional[str]],
87
- ) -> None:
88
- """
89
- Initialize the vision backbone.
90
-
91
- Args:
92
- use_fused_vision_backbone: Whether to use two backbones and fuse their features
93
- image_sizes: List of image sizes for each backbone
94
- timm_model_ids: List of TIMM model IDs to use for each backbone
95
- timm_override_act_layers: List of activation layer overrides for each backbone
96
- """
97
- super().__init__()
98
- self.use_fused_vision_backbone = use_fused_vision_backbone
99
- self.num_images_in_input = 1 # Default value, can be overridden later
100
-
101
- # Validate number of (fused) vision backbones
102
- if len(timm_model_ids) > 2:
103
- raise ValueError("Prismatic models only support up to 2 (fused) vision backbones!")
104
-
105
- # Create primary featurizer
106
- self.featurizer = self._create_featurizer(
107
- model_id=timm_model_ids[0], img_size=image_sizes[0], act_layer=timm_override_act_layers[0]
108
- )
109
- self.embed_dim = self.featurizer.embed_dim
110
-
111
- # Create secondary featurizer if using fused backbone
112
- if self.use_fused_vision_backbone:
113
- self.fused_featurizer = self._create_featurizer(
114
- model_id=timm_model_ids[1], img_size=image_sizes[1], act_layer=timm_override_act_layers[1]
115
- )
116
- self.embed_dim += self.fused_featurizer.embed_dim
117
-
118
- # Patch LayerScale modules for HF compatibility
119
- self._patch_layer_scales()
120
-
121
-
122
- def _create_featurizer(self, model_id: str, img_size: int, act_layer: Optional[str]) -> nn.Module:
123
- """
124
- Create a TIMM-based featurizer model with appropriate configurations.
125
-
126
- Args:
127
- model_id: The TIMM model ID to load
128
- img_size: Input image size for the model
129
- act_layer: Override for the activation layer type
130
-
131
- Returns:
132
- A configured featurizer model
133
- """
134
- featurizer = timm.create_model(
135
- model_id,
136
- pretrained=False,
137
- num_classes=0,
138
- img_size=img_size,
139
- act_layer=act_layer,
140
- )
141
-
142
- # Monkey-patch the forward function to extract the second-to-last layer features
143
- num_blocks = len(featurizer.blocks)
144
- featurizer.forward = unpack_tuple(partial(featurizer.get_intermediate_layers, n={num_blocks - 2}))
145
-
146
- return featurizer
147
-
148
-
149
- def _patch_layer_scales(self) -> None:
150
- """
151
- Patch all LayerScale modules to be compatible with HF's parameter naming.
152
-
153
- HF Transformers overwrites parameters with names containing 'gamma',
154
- so we need to rename and modify the forward method.
155
- """
156
- # Patch primary featurizer
157
- for module in self.featurizer.modules():
158
- if isinstance(module, LayerScale):
159
- ls_apply_patch(module)
160
-
161
- # Patch secondary featurizer if it exists
162
- if self.use_fused_vision_backbone:
163
- for module in self.fused_featurizer.modules():
164
- if isinstance(module, LayerScale):
165
- ls_apply_patch(module)
166
-
167
-
168
- def get_num_patches(self) -> int:
169
- """
170
- Returns the number of vision patches output by the vision backbone.
171
-
172
- Returns:
173
- Number of patches per image
174
- """
175
- return self.featurizer.patch_embed.num_patches
176
-
177
-
178
- def get_num_images_in_input(self) -> int:
179
- """
180
- Returns the number of input images for the vision backbone.
181
-
182
- Returns:
183
- Number of images expected in the input
184
- """
185
- return self.num_images_in_input
186
-
187
-
188
- def set_num_images_in_input(self, num_images_in_input: int) -> None:
189
- """
190
- Sets the number of input images for the vision backbone.
191
-
192
- Args:
193
- num_images_in_input: Number of images to expect in the input
194
- """
195
- self.num_images_in_input = num_images_in_input
196
-
197
-
198
- def forward(self, pixel_values: torch.Tensor) -> torch.Tensor:
199
- """
200
- Implements the forward pass for the vision backbone.
201
-
202
- If `self.use_fused_vision_backbone == True`, uses both SigLIP and DINOv2 transformers to extract visual features
203
- (otherwise uses SigLIP only). Allows multi-image inputs (but only for fused vision backbone).
204
-
205
- Args:
206
- pixel_values (torch.Tensor): Pixels for input image(s), (B, C, H, W).
207
- """
208
- if self.num_images_in_input == 1:
209
- if not self.use_fused_vision_backbone:
210
- return self.featurizer(pixel_values)
211
-
212
- # Split `pixel_values :: [bsz, 2 * 3, resolution, resolution]` =>> featurize =>> channel stack
213
- img, img_fused = torch.split(pixel_values, [3, 3], dim=1)
214
- patches, patches_fused = self.featurizer(img), self.fused_featurizer(img_fused)
215
-
216
- return torch.cat([patches, patches_fused], dim=2)
217
-
218
- else:
219
- assert self.use_fused_vision_backbone, "Multi-image inputs require using fused backbone!"
220
-
221
- # Split `pixel_values` into individual images (each with 6 channels: 3 for SigLIP + 3 for DINOv2)
222
- images = torch.split(pixel_values, [6] * self.num_images_in_input, dim=1)
223
-
224
- # Process each image and collect patches
225
- all_patches = []
226
- for img in images:
227
- # Split each image further into two stacks of channels (each with 3 channels)
228
- img_regular, img_fused = torch.split(img, [3, 3], dim=1)
229
-
230
- # Get patches from both SigLIP and DINOv2 vision transformers
231
- patches = self.featurizer(img_regular)
232
- patches_fused = self.fused_featurizer(img_fused)
233
-
234
- # Concatenate SigLIP and DINOv2 patches along the hidden dimension
235
- combined_patches = torch.cat([patches, patches_fused], dim=2)
236
- all_patches.append(combined_patches)
237
-
238
- # Concatenate all patches along the patch dimension
239
- return torch.cat(all_patches, dim=1)
240
-
241
-
242
-
243
- # === Prismatic Projector (nn.Module) Definitions ===
244
- class PrismaticProjector(nn.Module):
245
- def __init__(self, use_fused_vision_backbone: bool, vision_dim: int, llm_dim: int) -> None:
246
- super().__init__()
247
- self.use_fused_vision_backbone = use_fused_vision_backbone
248
- self.vision_dim, self.llm_dim = vision_dim, llm_dim
249
-
250
- # Switch on `use_fused_vision_backbone` =>> use slightly different MLPs and projection factors!
251
- if not self.use_fused_vision_backbone:
252
- self.fc1 = nn.Linear(self.vision_dim, self.llm_dim, bias=True)
253
- self.fc2 = nn.Linear(self.llm_dim, self.llm_dim, bias=True)
254
- self.act_fn1 = nn.GELU()
255
- else:
256
- initial_projection_dim = 4 * vision_dim
257
- self.fc1 = nn.Linear(self.vision_dim, initial_projection_dim, bias=True)
258
- self.fc2 = nn.Linear(initial_projection_dim, self.llm_dim, bias=True)
259
- self.fc3 = nn.Linear(self.llm_dim, self.llm_dim, bias=True)
260
- self.act_fn1 = nn.GELU()
261
- self.act_fn2 = nn.GELU()
262
-
263
- def forward(self, img_patches: torch.Tensor) -> torch.Tensor:
264
- if not self.use_fused_vision_backbone:
265
- projected_features = self.fc1(img_patches)
266
- projected_features = self.act_fn1(projected_features)
267
- projected_features = self.fc2(projected_features)
268
- else:
269
- projected_features = self.fc1(img_patches)
270
- projected_features = self.act_fn1(projected_features)
271
- projected_features = self.fc2(projected_features)
272
- projected_features = self.act_fn2(projected_features)
273
- projected_features = self.fc3(projected_features)
274
-
275
- return projected_features
276
-
277
-
278
-
279
- # === Main HF Class Definitions ===
280
- @dataclass
281
- class PrismaticCausalLMOutputWithPast(ModelOutput):
282
- """Base class for Prismatic casual (visually-conditioned) language model outputs; also exposes visual features."""
283
-
284
- loss: Optional[torch.FloatTensor] = None
285
- logits: torch.FloatTensor = None
286
- past_key_values: Optional[Tuple[Tuple[torch.FloatTensor]]] = None
287
- hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None
288
- attentions: Optional[Tuple[torch.FloatTensor]] = None
289
-
290
- # Additions for VLMs
291
- projector_features: Optional[torch.FloatTensor] = None
292
-
293
-
294
-
295
- class PrismaticPreTrainedModel(PreTrainedModel):
296
- config_class: PretrainedConfig = PrismaticConfig
297
- base_model_prefix: str = "model"
298
- supports_gradient_checkpointing: bool = True
299
-
300
- _no_split_modules: ClassVar[List[str]] = ["PrismaticProjector"]
301
- _skip_keys_device_placement: str = "past_key_values"
302
- _supports_flash_attn_2: bool = True
303
-
304
- def _init_weights(self, module: nn.Module) -> None:
305
- # Important :: this HF ported version is *not* meant for training from scratch; only inference and fine-tuning!
306
- # => As such, this init_weights code is not correct; if training VLMs from scratch, use the main codebase at
307
- # https://github.com/TRI-ML/prismatic-vlms
308
- std = (
309
- self.config.initializer_range
310
- if hasattr(self.config, "initializer_range")
311
- else self.config.text_config.initializer_range
312
- )
313
-
314
- if hasattr(module, "class_embedding"):
315
- module.class_embedding.data.normal_(mean=0.0, std=std)
316
-
317
- if isinstance(module, (nn.Linear, nn.Conv2d)):
318
- module.weight.data.normal_(mean=0.0, std=std)
319
- if module.bias is not None:
320
- module.bias.data.zero_()
321
- elif isinstance(module, nn.Embedding):
322
- module.weight.data.normal_(mean=0.0, std=std)
323
- if module.padding_idx is not None:
324
- module.weight.data[module.padding_idx].zero_()
325
-
326
- @property
327
- def _supports_sdpa(self) -> bool:
328
- """Check LLM supports SDPA Attention"""
329
- return self.language_model._supports_sdpa
330
-
331
-
332
-
333
- class PrismaticForConditionalGeneration(PrismaticPreTrainedModel):
334
- def __init__(self, config: PrismaticConfig) -> None:
335
- super().__init__(config)
336
-
337
- # [Validation] Lightweight Validate on `config` Fields + Dependency Versions
338
- if config.use_fused_vision_backbone is None:
339
- raise ValueError("Missing config field `use_fused_vision_backbone`")
340
-
341
- if timm.__version__ not in {"0.9.10", "0.9.11", "0.9.12", "0.9.16"}:
342
- raise NotImplementedError(
343
- "TIMM Version must be >= 0.9.10 and < 1.0.0 (breaking); please raise a GitHub Issue "
344
- "if you urgently need support for latest TIMM versions."
345
- )
346
-
347
- if (transformers.__version__ != "4.40.1") or (tokenizers.__version__ != "0.19.1"):
348
- logger.warning(
349
- f"Expected `transformers==4.40.1` and `tokenizers==0.19.1` but got "
350
- f"`transformers=={transformers.__version__}` and `tokenizers=={tokenizers.__version__}`; "
351
- f"there might be inference-time regressions due to dependency changes. If in doubt, please"
352
- f"use the above versions."
353
- )
354
-
355
- # Instantiate PrismaticVisionBackbone (w/ Potential Fused Backbone)
356
- self.vision_backbone = PrismaticVisionBackbone(
357
- config.use_fused_vision_backbone, config.image_sizes, config.timm_model_ids, config.timm_override_act_layers
358
- )
359
-
360
- # Create Multimodal Projector
361
- self.projector = PrismaticProjector(
362
- config.use_fused_vision_backbone,
363
- vision_dim=self.vision_backbone.embed_dim,
364
- llm_dim=config.text_config.hidden_size,
365
- )
366
-
367
- # Instantiate LLM Backbone
368
- self.language_model = AutoModelForCausalLM.from_config(
369
- config.text_config, attn_implementation=config._attn_implementation
370
- )
371
-
372
- self.vocab_size = config.text_config.vocab_size
373
- self.pad_token_id = config.pad_token_id
374
- self.llm_dim = config.text_config.hidden_size
375
-
376
- if config.use_reg_version == True:
377
- # Register token (same as action_queries but for modality separation)
378
- self.register_token = nn.Embedding(NUM_TOKENS, self.llm_dim)
379
- self.register_token.weight.data.zero_()
380
- # Action query token
381
- self.action_queries = nn.Embedding(NUM_ACTIONS_CHUNK, self.llm_dim)
382
- self.action_queries.weight.data.zero_()
383
- else:
384
- self.register_token = None
385
- # Action query token
386
- self.action_queries = nn.Embedding(NUM_TOKENS, self.llm_dim)
387
- self.action_queries.weight.data.zero_()
388
-
389
- # Uniform wrist dropout / language conditioning flags (persisted via config)
390
- self.uniform_vision_dropout_enabled = getattr(config, "uniform_vision_dropout_enabled", False)
391
- self.uniform_vision_dropout_ratio = getattr(config, "uniform_vision_dropout_ratio", 0.0)
392
- self.language_conditioning_enabled = getattr(config, "language_conditioning_enabled", False)
393
-
394
- # HF Boilerplate =>> initializes weights via `_init_weights()` and sets gradient checkpointing
395
- self.post_init()
396
-
397
- # === `PreTrainedModel` Boilerplate ===
398
- def get_input_embeddings(self) -> nn.Module:
399
- return self.language_model.get_input_embeddings()
400
- def set_version(self, version: str):
401
- self.version = version
402
- return self.version
403
-
404
-
405
- def set_input_embeddings(self, value: nn.Module) -> None:
406
- self.language_model.set_input_embeddings(value)
407
-
408
- def get_output_embeddings(self) -> nn.Module:
409
- return self.language_model.get_output_embeddings()
410
-
411
- def set_output_embeddings(self, new_embeddings: nn.Module) -> None:
412
- self.language_model.set_output_embeddings(new_embeddings)
413
-
414
- def get_decoder(self) -> nn.Module:
415
- return self.language_model.get_decoder()
416
-
417
- def set_decoder(self, decoder: nn.Module) -> None:
418
- self.language_model.set_decoder(decoder)
419
-
420
- def tie_weights(self) -> None:
421
- self.language_model.tie_weights() # Note: `Llama-2` and `Mistral` don't tie weights (no-op)
422
-
423
- def resize_token_embeddings(
424
- self, new_num_tokens: Optional[int] = None, pad_to_multiple_of: Optional[int] = None
425
- ) -> nn.Embedding:
426
- updated_embeddings = self.language_model.resize_token_embeddings(new_num_tokens, pad_to_multiple_of)
427
-
428
- # Update config/instance variables
429
- self.config.text_config.vocab_size = updated_embeddings.num_embeddings
430
- self.vocab_size = updated_embeddings.num_embeddings
431
-
432
- return updated_embeddings
433
-
434
- def set_uniform_vision_dropout(self, enabled: bool, dropout_ratio: float) -> None:
435
- """Enable or disable uniform wrist patch dropout during multimodal masking."""
436
- self.uniform_vision_dropout_enabled = enabled
437
- self.uniform_vision_dropout_ratio = dropout_ratio
438
- setattr(self.config, "uniform_vision_dropout_enabled", enabled)
439
- setattr(self.config, "uniform_vision_dropout_ratio", float(dropout_ratio))
440
-
441
- def set_language_conditioning(self, enabled: bool) -> None:
442
- """Toggle language conditioning inputs for the action head."""
443
- self.language_conditioning_enabled = enabled
444
- setattr(self.config, "language_conditioning_enabled", enabled)
445
-
446
- def _replace_input_embeddings(self, input_embeddings, all_actions_mask, noisy_action_features):
447
- """
448
- Replace embeddings in input_embeddings at positions where all_actions_mask is True
449
- with embeddings from noisy_action_features, using vectorized operations.
450
-
451
- Args:
452
- input_embeddings: Tensor of shape (B, S, D)
453
- all_actions_mask: Boolean tensor of shape (B, S)
454
- noisy_action_features: Tensor of shape (B, K, D) where K is the number of True values in mask per sample
455
-
456
- Returns:
457
- Modified input_embeddings tensor
458
- """
459
- # Clone input to avoid modifying the original tensor
460
- new_input_embeddings = input_embeddings.clone()
461
-
462
- # Create a tensor with the same shape of input_embeddings to hold the noisy action features
463
- repositioned_noisy_action_features = torch.zeros_like(input_embeddings)
464
-
465
- # Create batch indices for splicing
466
- batch_indices = torch.arange(input_embeddings.shape[0], device=input_embeddings.device)
467
- batch_indices = batch_indices.unsqueeze(1).expand(-1, noisy_action_features.shape[1])
468
-
469
- # Get indices where mask is True for each sample
470
- masked_indices = torch.stack([torch.where(mask)[0] for mask in all_actions_mask])
471
-
472
- # Move the noisy action features into their correct positions
473
- # print(noisy_action_features.size())
474
-
475
- repositioned_noisy_action_features[batch_indices, masked_indices] = noisy_action_features
476
-
477
- # Combine original input embeddings and noisy action embeddings using the mask
478
- new_input_embeddings = torch.where(
479
- all_actions_mask.unsqueeze(-1), repositioned_noisy_action_features, new_input_embeddings
480
- )
481
-
482
- return new_input_embeddings
483
-
484
- def _apply_pre_alignment(self, action_queries, projected_patch_embeddings, pre_align_module):
485
- """
486
- Apply pre-alignment between action queries and visual features.
487
-
488
- Args:
489
- action_queries: Action query embeddings (B, num_queries, D)
490
- projected_patch_embeddings: Visual patch embeddings (B, num_patches, D)
491
- pre_align_module: Pre-alignment module for cross-attention
492
-
493
- Returns:
494
- Tuple of (aligned_queries, aligned_vision_features)
495
- """
496
- if pre_align_module is not None:
497
- return pre_align_module(action_queries, projected_patch_embeddings)
498
- return action_queries, projected_patch_embeddings
499
-
500
- def _process_action_masks(self, labels):
501
- """Helper to get action masks from labels"""
502
- current_action_mask = get_current_action_mask(labels)
503
- next_actions_mask = get_next_actions_mask(labels)
504
- all_actions_mask = current_action_mask | next_actions_mask # (B, seq_len)
505
- return all_actions_mask
506
-
507
- def _process_vision_features(self, pixel_values, language_embeddings=None, use_film=False):
508
- """Process vision features with optional FiLM conditioning"""
509
- if use_film:
510
- # FiLM: Infuse language inputs into visual features
511
- patch_features = self.vision_backbone(pixel_values, language_embeddings) # (bsz, 256 * num_images, D)
512
- else:
513
- patch_features = self.vision_backbone(pixel_values) # (bsz, 256 * num_images, D)
514
-
515
- # Project patch embeddings into language embedding space
516
- return self.projector(patch_features)
517
-
518
- def _process_proprio_features(self, projected_patch_embeddings, proprio, proprio_projector):
519
- """Process proprioceptive features and append to vision features"""
520
- if proprio_projector is not None and proprio is not None:
521
- # projected_patch_embeddings: (bsz, num_patches * num_images, llm_dim)
522
- # proprio: (bsz, proprio_dim) or (propro_dim,)
523
- proprio = proprio.reshape(projected_patch_embeddings.shape[0], -1) # (bsz, proprio_dim)
524
- proprio_features = proprio_projector(proprio) # (bsz, llm_dim)
525
- proprio_features = proprio_features.unsqueeze(dim=1) # (bsz, 1, llm_dim)
526
- # For simplicity, just append proprio token to the end of projected vision patch tokens
527
- return torch.cat((projected_patch_embeddings, proprio_features), dim=1)
528
- return projected_patch_embeddings
529
-
530
- def _build_multimodal_attention(
531
- self,
532
- input_embeddings,
533
- projected_patch_embeddings,
534
- attention_mask,
535
- modality_mask=None,
536
- action_mask: Optional[torch.Tensor] = None,
537
- use_query_mask: bool = False,
538
- query_mask_ratio: float = 0.0,
539
- ):
540
- """Build multimodal embeddings and attention mask, with optional intra-query masking."""
541
-
542
- projected_patch_attention_mask = None
543
- if attention_mask is not None:
544
- device = attention_mask.device
545
- dtype_mask = input_embeddings.dtype
546
- attention_keep = attention_mask.bool().clone()
547
-
548
- batch_size = attention_keep.shape[0]
549
- vision_enabled = torch.ones(batch_size, dtype=torch.bool, device=device)
550
- query_enabled = torch.ones(batch_size, dtype=torch.bool, device=device)
551
- proprio_enabled = torch.ones(batch_size, dtype=torch.bool, device=device)
552
-
553
- if modality_mask is not None:
554
- modality_mask = modality_mask.to(device)
555
- if modality_mask.dim() == 1:
556
- modality_mask = modality_mask.unsqueeze(0)
557
- num_modalities = modality_mask.shape[1]
558
- if num_modalities >= 2:
559
- vision_enabled = modality_mask[:, 1].bool()
560
- if num_modalities >= 3:
561
- query_enabled = modality_mask[:, 2].bool()
562
- if num_modalities >= 4:
563
- proprio_enabled = modality_mask[:, 3].bool()
564
-
565
- wrist_patch_dropout_mask = None
566
- if (
567
- self.training
568
- and self.uniform_vision_dropout_enabled
569
- and self.vision_backbone.get_num_images_in_input() > 1
570
- ):
571
- wrist_patch_dropout_mask = self._build_uniform_wrist_dropout_mask(
572
- projected_patch_embeddings, vision_enabled, dtype=projected_patch_embeddings.dtype, device=device
573
- )
574
-
575
- if (
576
- self.training
577
- and use_query_mask
578
- and query_mask_ratio > 0.0
579
- and action_mask is not None
580
- ):
581
- action_mask_bool = action_mask.to(device=device).bool()
582
- for b in range(batch_size):
583
- if query_enabled[b]:
584
- continue
585
- query_indices = torch.where(action_mask_bool[b] & attention_keep[b])[0]
586
- if query_indices.numel() == 0:
587
- continue
588
- keep = torch.rand(query_indices.numel(), device=device) > query_mask_ratio
589
- if not keep.any():
590
- keep[torch.randint(query_indices.numel(), (1,), device=device)] = True
591
- attention_keep[b, query_indices] = keep
592
-
593
- keep_float = keep.to(input_embeddings.dtype)
594
- input_embeddings[b, query_indices] *= keep_float.unsqueeze(-1)
595
- kept_tokens = keep_float.sum()
596
- if kept_tokens > 0:
597
- scale = query_indices.numel() / kept_tokens
598
- input_embeddings[b, query_indices] *= scale
599
-
600
- attention_mask = attention_keep.to(dtype_mask)
601
-
602
- projected_patch_attention_mask = torch.ones(
603
- (projected_patch_embeddings.shape[0], projected_patch_embeddings.shape[1]),
604
- dtype=dtype_mask,
605
- device=device,
606
- )
607
- if modality_mask is not None:
608
- patches_per_image = self.vision_backbone.get_num_patches()
609
- num_vision_tokens = patches_per_image * self.vision_backbone.get_num_images_in_input()
610
- vision_mask = vision_enabled.to(projected_patch_attention_mask.dtype).unsqueeze(1)
611
- wrist_start = patches_per_image
612
- wrist_end = num_vision_tokens
613
- if wrist_end > wrist_start:
614
- projected_patch_attention_mask[:, wrist_start:wrist_end] *= vision_mask
615
- if projected_patch_attention_mask.shape[1] > num_vision_tokens:
616
- proprio_mask = proprio_enabled.to(projected_patch_attention_mask.dtype).unsqueeze(1)
617
- projected_patch_attention_mask[:, num_vision_tokens:] *= proprio_mask
618
-
619
- if wrist_patch_dropout_mask is not None:
620
- projected_patch_attention_mask = projected_patch_attention_mask * wrist_patch_dropout_mask
621
- projected_patch_embeddings = projected_patch_embeddings * wrist_patch_dropout_mask.unsqueeze(-1)
622
-
623
- multimodal_embeddings = torch.cat(
624
- [input_embeddings[:, :1, :], projected_patch_embeddings, input_embeddings[:, 1:, :]], dim=1
625
- )
626
-
627
- multimodal_attention_mask = None
628
- if attention_mask is not None:
629
- multimodal_attention_mask = torch.cat(
630
- [attention_mask[:, :1], projected_patch_attention_mask, attention_mask[:, 1:]], dim=1
631
- )
632
-
633
- return multimodal_embeddings, multimodal_attention_mask
634
-
635
- def _build_multimodal_labels(self, labels, projected_patch_embeddings):
636
- """Build multimodal labels with IGNORE_INDEX for patch embeddings"""
637
- if labels is not None:
638
- projected_patch_labels = torch.full(
639
- (projected_patch_embeddings.shape[0], projected_patch_embeddings.shape[1]),
640
- fill_value=IGNORE_INDEX,
641
- dtype=labels.dtype,
642
- device=labels.device,
643
- )
644
- return torch.cat([labels[:, :1], projected_patch_labels, labels[:, 1:]], dim=1)
645
- return None
646
-
647
- def _build_uniform_wrist_dropout_mask(
648
- self,
649
- projected_patch_embeddings: torch.Tensor,
650
- vision_enabled: torch.Tensor,
651
- dtype: torch.dtype,
652
- device: torch.device,
653
- ) -> Optional[torch.Tensor]:
654
- """Build DropPath-style mask for wrist patches ensuring even coverage."""
655
-
656
- batch_size, total_tokens = projected_patch_embeddings.shape[:2]
657
- patches_per_image = self.vision_backbone.get_num_patches()
658
- num_images = self.vision_backbone.get_num_images_in_input()
659
- if patches_per_image == 0 or num_images <= 1:
660
- return None
661
-
662
- mask = torch.ones((batch_size, total_tokens), device=device, dtype=dtype)
663
- grid_size = max(int(math.sqrt(patches_per_image)), 1)
664
- wrist_ranges = [
665
- (img_idx * patches_per_image, (img_idx + 1) * patches_per_image)
666
- for img_idx in range(1, num_images)
667
- ]
668
-
669
- dropout_ratio = max(0.0, min(float(self.uniform_vision_dropout_ratio), 1.0))
670
-
671
- for b in range(batch_size):
672
- if not vision_enabled[b]:
673
- continue
674
- for start_idx, end_idx in wrist_ranges:
675
- num_patches = end_idx - start_idx
676
- if num_patches <= 0:
677
- continue
678
- dropout_tokens = int(round(num_patches * dropout_ratio))
679
- dropout_tokens = min(dropout_tokens, max(num_patches - 1, 0))
680
-
681
- keep_mask = torch.ones(num_patches, device=device, dtype=dtype)
682
- if dropout_tokens > 0:
683
- selected_indices = self._sample_uniform_patch_indices(num_patches, dropout_tokens, grid_size)
684
- if selected_indices:
685
- keep_mask[selected_indices] = 0.0
686
- kept = keep_mask.sum()
687
- if kept > 0 and kept < num_patches:
688
- keep_mask = keep_mask * (num_patches / kept)
689
- mask[b, start_idx:end_idx] = keep_mask
690
-
691
- if torch.all(mask == 1):
692
- return None
693
- return mask
694
-
695
- def _sample_uniform_patch_indices(
696
- self,
697
- patches_per_image: int,
698
- num_to_drop: int,
699
- grid_size: int,
700
- ) -> List[int]:
701
- if num_to_drop <= 0:
702
- return []
703
-
704
- selected: List[int] = []
705
- attempts = 0
706
- max_attempts = max(num_to_drop * 20, 1)
707
-
708
- while len(selected) < num_to_drop and attempts < max_attempts:
709
- candidate = random.randrange(patches_per_image)
710
- row, col = divmod(candidate, grid_size)
711
- if any(abs(row - r0) <= 1 and abs(col - c0) <= 1 for idx0 in selected for r0, c0 in [divmod(idx0, grid_size)]):
712
- attempts += 1
713
- continue
714
- selected.append(candidate)
715
-
716
- if len(selected) < num_to_drop:
717
- remaining = [idx for idx in range(patches_per_image) if idx not in selected]
718
- if remaining:
719
- needed = min(num_to_drop - len(selected), len(remaining))
720
- selected.extend(random.sample(remaining, needed))
721
-
722
- return selected[:num_to_drop]
723
-
724
- # === Core Prismatic VLM `forward()` Logic ===
725
- def forward(
726
- self,
727
- input_ids: Optional[torch.LongTensor] = None,
728
- attention_mask: Optional[torch.Tensor] = None,
729
- pixel_values: Optional[torch.FloatTensor] = None,
730
- labels: Optional[torch.LongTensor] = None,
731
- inputs_embeds: Optional[torch.FloatTensor] = None,
732
- past_key_values: Optional[List[torch.FloatTensor]] = None,
733
- use_cache: Optional[bool] = None,
734
- output_attentions: Optional[bool] = None,
735
- output_hidden_states: Optional[bool] = None,
736
- output_projector_features: Optional[bool] = None,
737
- return_dict: Optional[bool] = None,
738
- proprio=None,
739
- proprio_projector=None,
740
- noisy_actions=None,
741
- noisy_action_projector=None,
742
- diffusion_timestep_embeddings=None,
743
- use_film: bool = False,
744
- use_sim_version: bool = False,
745
- use_reg_version: bool = False,
746
- pre_align_module=None,
747
- modality_mask: Optional[torch.Tensor] = None,
748
- use_query_mask: bool = False,
749
- query_mask_ratio: float = 0.0,
750
- ) -> Union[Tuple, PrismaticCausalLMOutputWithPast]:
751
- """Run a forward pass through the VLM, returning a PrismaticCausalLMOutputWithPast instance."""
752
- output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
753
- output_hidden_states = (
754
- output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
755
- )
756
- output_projector_features = output_projector_features if output_projector_features is not None else False
757
- return_dict = return_dict if return_dict is not None else self.config.use_return_dict
758
-
759
- # Respect `use_cache` only if not training (even if `gradient_checkpointing` is off)
760
- use_cache = use_cache and not self.training
761
-
762
- # Instantiate Placeholder for Projector Features / Language Conditioning
763
- projected_patch_embeddings = None
764
-
765
- # === Handle Generation with Cache (`input_ids.shape[1] == 1`) =>> requires `past_keys_values` ===
766
- if input_ids.shape[1] == 1:
767
- assert input_ids.shape[0] == 1, "Generation is only currently supported for batch size of 1!"
768
- assert past_key_values is not None, "You must provide `past_key_values` during cached generation!"
769
- assert labels is None, "Unexpected key `labels` provided during cached generation!"
770
-
771
- language_model_output = self.language_model(
772
- input_ids=input_ids,
773
- attention_mask=None,
774
- position_ids=None,
775
- past_key_values=past_key_values,
776
- inputs_embeds=None,
777
- labels=None,
778
- use_cache=use_cache,
779
- output_attentions=output_attentions,
780
- output_hidden_states=output_hidden_states,
781
- return_dict=return_dict,
782
- )
783
-
784
- # === Handle Unimodal Forward ===
785
- elif pixel_values is None:
786
- assert (input_ids is not None) and (inputs_embeds is None), "Missing `input_ids` in language-only forward!"
787
- assert past_key_values is None, "Unexpected key `past_key_values` provided during language-only forward!"
788
-
789
- language_model_output = self.language_model(
790
- input_ids=input_ids,
791
- attention_mask=attention_mask,
792
- position_ids=None,
793
- past_key_values=None,
794
- inputs_embeds=None,
795
- labels=labels,
796
- use_cache=use_cache,
797
- output_attentions=output_attentions,
798
- output_hidden_states=output_hidden_states,
799
- return_dict=return_dict,
800
- )
801
-
802
- # === Handle Multimodal Forward ===
803
- elif (input_ids.shape[0] == pixel_values.shape[0]) or (inputs_embeds.shape[0] == pixel_values.shape[0]):
804
- assert past_key_values is None, "Unexpected key `past_key_values` provided during multimodal forward!"
805
-
806
- # Get input embeddings (from language model embeddings)
807
- input_embeddings = self.get_input_embeddings()(input_ids) # (B, seq_len, D)
808
-
809
-
810
- # Extract action masks
811
- all_actions_mask = self._process_action_masks(labels)
812
-
813
- # Extract the language portion of the input embeddings (i.e. remove the action tokens portion)
814
-
815
- # print(input_embeddings[~all_actions_mask].size())
816
- language_embeddings = input_embeddings[~all_actions_mask].reshape(
817
- input_embeddings.shape[0], -1, input_embeddings.shape[2]
818
- ) # (B, lang_seq_len, llm_dim)
819
-
820
- # Get visual features
821
- projected_patch_embeddings = self._process_vision_features(pixel_values, language_embeddings, use_film)
822
-
823
- if modality_mask is not None:
824
- modality_mask = modality_mask.to(projected_patch_embeddings.device)
825
- if modality_mask.dim() == 1:
826
- modality_mask = modality_mask.unsqueeze(0)
827
- modality_mask = modality_mask.to(projected_patch_embeddings.dtype)
828
-
829
- #NOTE Add proprioceptive state if provided
830
- if use_sim_version and proprio_projector is not None:
831
- projected_patch_embeddings = self._process_proprio_features(
832
- projected_patch_embeddings,
833
- proprio,
834
- proprio_projector,
835
- )
836
-
837
- # Process action embeddings
838
- if use_reg_version:
839
- # Combine register_token and action_queries for modality separation
840
- # register_token serves as modality separator, action_queries follows
841
- register_weight = self.register_token.weight # (NUM_TOKENS, h)
842
- action_weight = self.action_queries.weight # (NUM_TOKENS, h)
843
- combined_queries = torch.cat([register_weight, action_weight], dim=0) # (2*NUM_TOKENS, h)
844
- action_queries = combined_queries.unsqueeze(0).repeat(input_embeddings.shape[0], 1, 1) # (B, 2*NUM_TOKENS, h)
845
- else:
846
- # Standard action queries without register token
847
- action_queries = self.action_queries.weight # (NUM_TOKENS, h)
848
- action_queries = action_queries.unsqueeze(0).repeat(input_embeddings.shape[0], 1, 1) # (B, NUM_TOKENS, h)
849
-
850
- # Apply pre-alignment if module is provided
851
- if pre_align_module is not None:
852
- action_queries, projected_patch_embeddings = self._apply_pre_alignment(
853
- action_queries, projected_patch_embeddings, pre_align_module
854
- )
855
-
856
- # Replace action token embeddings with (aligned) action queries
857
- all_actions_mask = self._process_action_masks(labels)
858
- input_embeddings = self._replace_input_embeddings(
859
- input_embeddings, all_actions_mask, action_queries
860
- )
861
-
862
- # Build multimodal embeddings & attention mask
863
- multimodal_embeddings, multimodal_attention_mask = self._build_multimodal_attention(
864
- input_embeddings,
865
- projected_patch_embeddings,
866
- attention_mask,
867
- modality_mask=modality_mask,
868
- action_mask=all_actions_mask,
869
- use_query_mask=use_query_mask,
870
- query_mask_ratio=query_mask_ratio,
871
- )
872
-
873
- # Build labels for multimodal sequence if needed
874
- multimodal_labels = self._build_multimodal_labels(labels, projected_patch_embeddings)
875
-
876
- # Dispatch to language model
877
- language_model_output = self.language_model(
878
- input_ids=None,
879
- attention_mask=multimodal_attention_mask,
880
- position_ids=None,
881
- past_key_values=None,
882
- inputs_embeds=multimodal_embeddings,
883
- labels=None,
884
- use_cache=use_cache,
885
- output_attentions=output_attentions,
886
- output_hidden_states=output_hidden_states,
887
- return_dict=return_dict,
888
- )
889
-
890
- # === Otherwise =>> Assume Invalid! ===
891
- elif (input_ids.shape[0] != pixel_values.shape[0]) or (inputs_embeds.shape[0] != pixel_values.shape[0]):
892
- raise ValueError("Non-homogenous batch of (text, image) input -- forward() does not support mixed batches!")
893
-
894
- else:
895
- raise ValueError(
896
- "Invalid PrismaticForConditionalGeneration `forward()` call with provided arguments:\n"
897
- f"=> `input_ids` = {input_ids is not None}\n"
898
- f"=> `attention_mask` = {attention_mask is not None}\n"
899
- f"=> `pixel_values` = {pixel_values is not None}\n"
900
- f"=> `labels` = {labels is not None}\n"
901
- f"=> `input_embeds` = {inputs_embeds is not None}\n"
902
- f"=> `past_key_values` = {past_key_values is not None}\n"
903
- f"=> `use_cache` = {use_cache}"
904
- )
905
-
906
- # Unpack `language_model_output` and return PrismaticCausalLMOutputWithPast (or tuple if not `return_dict`)
907
- if not return_dict:
908
- if output_projector_features and (projected_patch_embeddings is not None):
909
- return *language_model_output, projected_patch_embeddings
910
-
911
- return language_model_output
912
-
913
- return PrismaticCausalLMOutputWithPast(
914
- loss=language_model_output.loss,
915
- logits=language_model_output.logits,
916
- past_key_values=language_model_output.past_key_values,
917
- hidden_states=language_model_output.hidden_states,
918
- attentions=language_model_output.attentions,
919
- projector_features=projected_patch_embeddings,
920
- )
921
-
922
-
923
- # === GenerationMixin Methods ===
924
- def prepare_inputs_for_generation(
925
- self,
926
- input_ids: Optional[torch.Tensor] = None,
927
- past_key_values: Optional[List[torch.FloatTensor]] = None,
928
- inputs_embeds: Optional[torch.FloatTensor] = None,
929
- pixel_values: Optional[torch.FloatTensor] = None,
930
- attention_mask: Optional[torch.Tensor] = None,
931
- **kwargs: str,
932
- ) -> Dict[str, torch.Tensor]:
933
- """Borrowed from `LlamaForCausalLM` and simplified for batch size = 1; mirrors original PrismaticVLM logic."""
934
- if ((input_ids is not None) and (input_ids.shape[0] > 1)) or (
935
- (inputs_embeds is not None) and (inputs_embeds.shape[0] > 1)
936
- ):
937
- raise ValueError("Generation with batch size > 1 is not currently supported!")
938
-
939
- # Handle `past_key_values` (cache) =>> assume `input_ids` just has unprocessed tokens
940
- if past_key_values is not None:
941
- input_ids = input_ids[:, -1:]
942
-
943
- # If `input_embeds` are passed, we only want to use them in the 1st generation step
944
- if inputs_embeds is not None and past_key_values is None:
945
- model_inputs = {"input_embeds": inputs_embeds}
946
- else:
947
- model_inputs = {"input_ids": input_ids}
948
-
949
- # Make sure `pixel_values` are preserved in `model_inputs`
950
- model_inputs.update(
951
- {
952
- "attention_mask": attention_mask,
953
- "pixel_values": pixel_values,
954
- "past_key_values": past_key_values,
955
- "use_cache": kwargs.get("use_cache"),
956
- }
957
- )
958
-
959
- return model_inputs
960
-
961
- # Defer to Language Model (all handle this differently, with different return types)
962
- def _reorder_cache(self, *args, **kwargs) -> Any:
963
- return self.language_model._reorder_cache(*args, **kwargs)
964
-
965
-
966
-
967
- class OpenVLAForActionPrediction(PrismaticForConditionalGeneration):
968
- config_class: PretrainedConfig = OpenVLAConfig
969
-
970
- def __init__(self, config: OpenVLAConfig) -> None:
971
- super().__init__(config)
972
- self.norm_stats = config.norm_stats
973
-
974
-
975
- # Compute action bins
976
- self.bins = np.linspace(-1, 1, config.n_action_bins)
977
- self.bin_centers = (self.bins[:-1] + self.bins[1:]) / 2.0
978
-
979
- # Compute vocab size for de-tokenization -- revert added "multiple of"
980
- self.vocab_size = self.config.text_config.vocab_size - self.config.pad_to_multiple_of
981
-
982
- def _prepare_input_for_action_prediction(self, input_ids, attention_mask):
983
- """Prepares input for action prediction by adding necessary tokens"""
984
- # Add (ACTION_DIM * NUM_ACTIONS_CHUNK) placeholder tokens to input_ids to simulate action tokens
985
- placeholder_action_token_ids = (
986
- torch.ones((input_ids.shape[0], NUM_TOKENS)).to(input_ids.device).to(input_ids.dtype)
987
- )
988
- input_ids = torch.cat([input_ids, placeholder_action_token_ids], dim=-1)
989
-
990
- # Add stop token to sequence (needed in non-causal bi-directional self-attention, as it appears at train time)
991
- stop_token_id = torch.ones((input_ids.shape[0], 1)).to(input_ids.device).to(input_ids.dtype) * STOP_INDEX
992
- input_ids = torch.cat([input_ids, stop_token_id], dim=-1)
993
-
994
- # Extend the attention mask to fit the new shape of input
995
- # Note: Only batch size == 1 supported right now
996
- mask_extension = (
997
- torch.ones((attention_mask.shape[0], input_ids.shape[-1] - attention_mask.shape[-1]))
998
- .to(attention_mask.device)
999
- .to(attention_mask.dtype)
1000
- )
1001
- attention_mask = torch.cat([attention_mask, mask_extension], dim=-1)
1002
-
1003
- return input_ids, attention_mask
1004
-
1005
- def _prepare_labels_for_action_prediction(self, labels, input_ids):
1006
- """Creates labels tensor for action prediction if not provided"""
1007
- # Extend labels tensor with fake action labels
1008
- ARBITRARY_ACTION_TOKEN_IDX = ACTION_TOKEN_BEGIN_IDX + 1
1009
- labels_extension = (
1010
- torch.ones((labels.shape[0], input_ids.shape[-1] - labels.shape[-1])).to(labels.device).to(labels.dtype)
1011
- * ARBITRARY_ACTION_TOKEN_IDX
1012
- )
1013
- labels = torch.cat([labels, labels_extension], dim=-1)
1014
-
1015
- # Replace last label token with stop token
1016
- labels[:, -1] = STOP_INDEX
1017
-
1018
- return labels
1019
-
1020
- def _unnormalize_actions(self, normalized_actions, unnorm_key=None):
1021
- """Unnormalize actions using dataset statistics"""
1022
- action_norm_stats = self.get_action_stats(unnorm_key)
1023
-
1024
- if ACTION_PROPRIO_NORMALIZATION_TYPE == NormalizationType.BOUNDS:
1025
- mask = action_norm_stats.get("mask", np.ones_like(action_norm_stats["min"], dtype=bool))
1026
- action_high, action_low = np.array(action_norm_stats["max"]), np.array(action_norm_stats["min"])
1027
- elif ACTION_PROPRIO_NORMALIZATION_TYPE == NormalizationType.BOUNDS_Q99:
1028
- mask = action_norm_stats.get("mask", np.ones_like(action_norm_stats["q01"], dtype=bool))
1029
- action_high, action_low = np.array(action_norm_stats["q99"]), np.array(action_norm_stats["q01"])
1030
- else:
1031
- raise ValueError("Unsupported action/proprio normalization type detected!")
1032
-
1033
- actions = np.where(
1034
- mask,
1035
- 0.5 * (normalized_actions + 1) * (action_high - action_low + 1e-8) + action_low,
1036
- normalized_actions,
1037
- )
1038
-
1039
- return actions
1040
-
1041
-
1042
- def _regression_or_discrete_prediction(
1043
- self,
1044
- input_embeddings,
1045
- all_actions_mask,
1046
- projected_patch_embeddings,
1047
- attention_mask,
1048
- labels,
1049
- NUM_PATCHES,
1050
- NUM_PROMPT_TOKENS,
1051
- action_head=None,
1052
- proprio=None,
1053
- proprio_projector=None,
1054
- use_rec_head=False,
1055
- use_reg_version=False,
1056
- pre_align_module=None,
1057
- ):
1058
- """Run L1 regression-based continuous action prediction or discrete action tokens prediction."""
1059
-
1060
- # Process action embeddings based on use_reg_version flag
1061
- if use_reg_version and self.register_token is not None:
1062
- # Combine register_token and action_queries for modality separation
1063
- register_weight = self.register_token.weight # (NUM_TOKENS, h)
1064
- action_weight = self.action_queries.weight # (NUM_TOKENS, h)
1065
- combined_queries = torch.cat([register_weight, action_weight], dim=0) # (2*NUM_TOKENS, h)
1066
- action_queries = combined_queries.unsqueeze(0).repeat(input_embeddings.shape[0], 1, 1) # (B, 2*NUM_TOKENS, h)
1067
- else:
1068
- # Standard action queries without register token
1069
- action_queries = self.action_queries.weight # (num_tokens, h)
1070
- action_queries = action_queries.unsqueeze(0).repeat(input_embeddings.shape[0], 1, 1) # (B, num_tokens, h)
1071
-
1072
- # Apply pre-alignment if module is provided
1073
- if pre_align_module is not None:
1074
- action_queries, projected_patch_embeddings = self._apply_pre_alignment(
1075
- action_queries, projected_patch_embeddings, pre_align_module
1076
- )
1077
-
1078
- # Replace action token embeddings with (aligned) action queries
1079
- input_embeddings = self._replace_input_embeddings(input_embeddings.clone(), all_actions_mask, action_queries)
1080
-
1081
- # Build multimodal embeddings and attention mask
1082
- multimodal_embeddings, multimodal_attention_mask = self._build_multimodal_attention(
1083
- input_embeddings, projected_patch_embeddings, attention_mask
1084
- )
1085
-
1086
- # Forward pass through language model
1087
- language_model_output = self.language_model(
1088
- input_ids=None,
1089
- attention_mask=multimodal_attention_mask,
1090
- position_ids=None,
1091
- past_key_values=None,
1092
- inputs_embeds=multimodal_embeddings,
1093
- labels=None,
1094
- use_cache=None,
1095
- output_attentions=False,
1096
- output_hidden_states=True,
1097
- return_dict=True,
1098
- )
1099
-
1100
- # Extract hidden states for action tokens
1101
- multi_layer_hidden_states = []
1102
-
1103
- for item in language_model_output.hidden_states[0:]:
1104
- # last_hidden_states = output.hidden_states[-1] # (B, seq_len, D)
1105
- # Get hidden states for text portion of prompt+response (after the vision patches)
1106
- text_hidden_states = item
1107
- # Get hidden states for action portion of response
1108
- actions_hidden_states = text_hidden_states[:, NUM_PATCHES+ NUM_PROMPT_TOKENS : NUM_PATCHES + NUM_PROMPT_TOKENS + NUM_TOKENS, :,].reshape(1, 1, NUM_TOKENS , -1).to(torch.bfloat16)
1109
-
1110
- batch_size = item.shape[0]
1111
- task_latten_states = item[:, :NUM_PATCHES].reshape(batch_size, 1, NUM_PATCHES , -1)
1112
- all_hidden_states = torch.cat((task_latten_states, actions_hidden_states),2)
1113
- multi_layer_hidden_states.append(all_hidden_states)
1114
-
1115
- multi_layer_hidden_states = torch.cat(multi_layer_hidden_states, dim = 1)
1116
-
1117
-
1118
- # Handle different prediction methods
1119
- if action_head is not None:
1120
- # L1 regression prediction
1121
- normalized_actions = action_head.predict_action(
1122
- multi_layer_hidden_states,
1123
- proprio=proprio,
1124
- proprio_projector=proprio_projector,
1125
- )
1126
- if use_rec_head:
1127
- normalized_actions = normalized_actions[-1]
1128
- normalized_actions = normalized_actions.reshape(NUM_ACTIONS_CHUNK, ACTION_DIM)
1129
- normalized_actions = normalized_actions.float().cpu().detach().numpy()
1130
- else:
1131
- # Discrete token-based prediction
1132
- predicted_action_token_ids = (
1133
- language_model_output.logits[
1134
- :,
1135
- NUM_PATCHES + NUM_PROMPT_TOKENS : NUM_PATCHES + NUM_PROMPT_TOKENS + ACTION_DIM * NUM_ACTIONS_CHUNK,
1136
- ]
1137
- .argmax(dim=2)
1138
- .cpu()
1139
- .numpy()
1140
- )
1141
- discretized_actions = self.vocab_size - predicted_action_token_ids
1142
- discretized_actions = np.clip(discretized_actions - 1, a_min=0, a_max=self.bin_centers.shape[0] - 1)
1143
- normalized_actions = self.bin_centers[discretized_actions]
1144
- normalized_actions = normalized_actions.reshape(NUM_ACTIONS_CHUNK, ACTION_DIM)
1145
-
1146
- return normalized_actions, actions_hidden_states
1147
-
1148
-
1149
- def predict_action(
1150
- self,
1151
- input_ids: Optional[torch.LongTensor] = None,
1152
- unnorm_key: Optional[str] = None,
1153
- proprio=None,
1154
- proprio_projector=None,
1155
- action_head=None,
1156
- noisy_action_projector=None,
1157
- use_film: bool = False,
1158
- use_sim_version: bool = False,
1159
- use_rec_head: bool = False,
1160
- use_reg_version: bool = False,
1161
- pre_align_module=None,
1162
- **kwargs: str,
1163
- ) -> np.ndarray:
1164
- """Predict actions from input sequence, with options for different prediction methods.
1165
-
1166
- Args:
1167
- input_ids: Input token ids
1168
- unnorm_key: Key for unnormalization statistics
1169
- proprio: Proprioceptive features
1170
- proprio_projector: Projector for proprioceptive features
1171
- action_head: Optional head for L1 regression or diffusion-based prediction
1172
- noisy_action_projector: Projector for noisy actions in diffusion-based prediction
1173
- use_film: Whether to use FiLM conditioning
1174
- **kwargs: Additional arguments including pixel_values and attention_mask
1175
-
1176
- Returns:
1177
- Tuple of (unnormalized_actions, action_hidden_states)
1178
- """
1179
-
1180
- pixel_values = kwargs["pixel_values"] # [1, 12, 224, 224]
1181
- attention_mask = kwargs["attention_mask"] #
1182
-
1183
- # Create fake labels tensor (needed for action mask)
1184
- labels = input_ids.clone()
1185
- labels[:] = IGNORE_INDEX
1186
-
1187
- # Get number of tokens in prompt (excluding the start token)
1188
- NUM_PROMPT_TOKENS = input_ids.shape[-1] - 1 # Subtract action tokens and stop token
1189
-
1190
- # Prepare inputs by adding necessary tokens
1191
- input_ids, attention_mask = self._prepare_input_for_action_prediction(input_ids, attention_mask)
1192
-
1193
- # Update labels tensor for action mask computation later
1194
- labels = self._prepare_labels_for_action_prediction(labels, input_ids)
1195
-
1196
- # Get input embeddings and action masks
1197
- input_embeddings = self.get_input_embeddings()(input_ids)
1198
- all_actions_mask = self._process_action_masks(labels)
1199
-
1200
- # Extract language embeddings
1201
- language_embeddings = input_embeddings[~all_actions_mask].reshape(
1202
- input_embeddings.shape[0], -1, input_embeddings.shape[2]
1203
- )
1204
-
1205
- # Process vision features
1206
- projected_patch_embeddings = self._process_vision_features(pixel_values, language_embeddings, use_film)
1207
-
1208
- # Add proprioceptive features if provided
1209
- use_proprio = proprio_projector is not None and proprio is not None
1210
- if use_proprio:
1211
- proprio = torch.Tensor(proprio).to(projected_patch_embeddings.device, dtype=projected_patch_embeddings.dtype)
1212
- #NOTE: Add proprioceptive state if provided
1213
- if use_sim_version:
1214
- projected_patch_embeddings = self._process_proprio_features(
1215
- projected_patch_embeddings, proprio, proprio_projector
1216
- )
1217
-
1218
- # Calculate number of patches (including proprio token and/or diffusion timestep embedding if present)
1219
- NUM_PATCHES = self.vision_backbone.get_num_patches() * self.vision_backbone.get_num_images_in_input()
1220
- if use_proprio and use_sim_version:
1221
- NUM_PATCHES += 1
1222
-
1223
- # Run regression or discrete token-based prediction
1224
- normalized_actions, actions_hidden_states = self._regression_or_discrete_prediction(
1225
- input_embeddings,
1226
- all_actions_mask,
1227
- projected_patch_embeddings,
1228
- attention_mask,
1229
- labels,
1230
- NUM_PATCHES,
1231
- NUM_PROMPT_TOKENS,
1232
- action_head=action_head,
1233
- proprio=proprio,
1234
- proprio_projector=proprio_projector,
1235
- use_rec_head=use_rec_head,
1236
- use_reg_version=use_reg_version,
1237
- pre_align_module=pre_align_module,
1238
- )
1239
-
1240
- # Unnormalize predicted actions
1241
- actions = self._unnormalize_actions(normalized_actions, unnorm_key)
1242
-
1243
- return actions, actions_hidden_states
1244
-
1245
-
1246
-
1247
- @staticmethod
1248
- def _check_unnorm_key(norm_stats: Dict[str, Dict[str, Any]], unnorm_key: Optional[str]) -> str:
1249
- """Validate and resolve the unnormalization key for action statistics"""
1250
- if unnorm_key is None:
1251
- assert len(norm_stats) == 1, (
1252
- f"Your model was trained on more than one dataset, "
1253
- f"please pass a `unnorm_key` from the following options to choose the statistics "
1254
- f"used for un-normalizing actions: {norm_stats.keys()}"
1255
- )
1256
- unnorm_key = next(iter(norm_stats.keys()))
1257
-
1258
- assert unnorm_key in norm_stats, (
1259
- f"The `unnorm_key` you chose is not in the set of available dataset statistics, "
1260
- f"please choose from: {norm_stats.keys()}"
1261
- )
1262
- return unnorm_key
1263
-
1264
- def get_action_dim(self, unnorm_key: Optional[str] = None) -> int:
1265
- """Get the dimensionality of the policy's action space."""
1266
- unnorm_key = self._check_unnorm_key(self.norm_stats, unnorm_key)
1267
- return len(self.norm_stats[unnorm_key]["action"]["min"])
1268
-
1269
- def get_action_stats(self, unnorm_key: Optional[str] = None) -> Dict[str, Any]:
1270
- """Get all the logged statistics for the given dataset."""
1271
- unnorm_key = self._check_unnorm_key(self.norm_stats, unnorm_key)
1272
- return self.norm_stats[unnorm_key]["action"]