zhicao commited on
Commit
5af2f9e
·
verified ·
1 Parent(s): 3559772

Scheduled Commit

Browse files
groot/vla/model/trex_track_force/model.py CHANGED
@@ -121,13 +121,14 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
121
  gradient_checkpointing: bool = False,
122
  diffusion_model_pretrained_path: str | None = None,
123
  concat_first_frame_latent: bool = False,
 
124
  **_: Any,
125
  ) -> None:
126
  if action_dim != PADDED_ACTION_DIM:
127
  raise ValueError("physical 62-D action must use WAN width 64")
128
  if action_horizon != TRACK_HORIZON:
129
  raise ValueError("action and track future horizons must both be 16")
130
- if track_points != NUM_TRACK_POINTS:
131
  raise ValueError("T-Rex track layout is fixed at 250 points")
132
 
133
  super().__init__(
@@ -158,7 +159,10 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
158
  concat_first_frame_latent=concat_first_frame_latent,
159
  )
160
  self.action_horizon = action_horizon
161
- self.track_points = track_points
 
 
 
162
  self.track_horizon = track_horizon
163
  self.max_track_history = max_track_history
164
  self.max_blocks = max_blocks
@@ -188,16 +192,17 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
188
  compatible_blocks.append(block)
189
  self.blocks = compatible_blocks
190
 
191
- self.track_encoder = TrackEncoder(
192
- dim,
193
- num_points=track_points,
194
- future_horizon=track_horizon,
195
- max_history_frames=max_track_history,
196
- max_blocks=max_blocks,
197
- )
198
- self.track_decoder = TrackDecoder(
199
- dim, num_points=track_points, future_horizon=track_horizon
200
- )
 
201
  self.modality_embedding = nn.Embedding(len(TokenType), dim)
202
  self.obs_input_projection = (
203
  nn.Identity()
@@ -212,7 +217,8 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
212
  )
213
 
214
  head_dim = dim // num_heads
215
- self.freqs_track = rope_params(max_blocks * 2 * track_points, head_dim)
 
216
  self.freqs_obs_1d = rope_params(
217
  max_blocks * max(frame_seqlen * num_frame_per_block, 1) + frame_seqlen,
218
  head_dim,
@@ -507,8 +513,8 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
507
  obs: torch.Tensor,
508
  action: torch.Tensor,
509
  state: torch.Tensor,
510
- track_past: torch.Tensor,
511
- track_future: torch.Tensor,
512
  ) -> tuple[torch.Tensor, BlockTokenLayout]:
513
  layout = BlockTokenLayout(
514
  num_blocks=obs.shape[1],
@@ -527,13 +533,20 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
527
  ].view(1, 1, self.dim)
528
  )
529
  for block_index in range(layout.num_blocks):
530
- for values, token_type in (
531
  (obs[:, block_index], TokenType.OBS),
532
  (action[:, block_index], TokenType.ACTION),
533
  (state[:, block_index], TokenType.STATE),
534
- (track_past[:, block_index], TokenType.TRACK_PAST),
535
- (track_future[:, block_index], TokenType.TRACK_FUTURE),
536
- ):
 
 
 
 
 
 
 
537
  groups.append(
538
  values
539
  + self.modality_embedding.weight[int(token_type)].view(
@@ -564,21 +577,26 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
564
  -1, layout.action_tokens_per_block
565
  ),
566
  zeros.expand(-1, layout.state_tokens_per_block),
567
- zeros.expand(-1, layout.track_points),
568
- track_tau[:, block : block + 1].expand(
569
- -1, layout.track_points
570
- ),
571
  )
572
  )
 
 
 
 
 
 
 
 
 
573
  return torch.cat(groups, dim=1)
574
 
575
  def _pack_rope(
576
  self, layout: BlockTokenLayout, video_rope: torch.Tensor, device: torch.device
577
  ) -> torch.Tensor:
578
- tables = (self.freqs_action, self.freqs_state, self.freqs_track)
579
- self.freqs_action, self.freqs_state, self.freqs_track = (
580
- table.to(device) for table in tables
581
- )
582
  video_rope = self._squeeze_rope(video_rope).to(device)
583
  groups: list[torch.Tensor] = []
584
  video_cursor = 0
@@ -606,21 +624,22 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
606
  ]
607
  )
608
  )
609
- track_start = block * 2 * self.track_points
610
- groups.append(
611
- self._squeeze_rope(
612
- self.freqs_track[track_start : track_start + self.track_points]
 
 
613
  )
614
- )
615
- groups.append(
616
- self._squeeze_rope(
617
- self.freqs_track[
618
- track_start
619
- + self.track_points : track_start
620
- + 2 * self.track_points
621
- ]
622
  )
623
- )
624
  packed = torch.cat(groups, dim=0)
625
  if packed.shape[0] != layout.sequence_length:
626
  raise RuntimeError("packed RoPE does not match token layout")
@@ -629,17 +648,23 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
629
  @staticmethod
630
  def _unpack(
631
  values: torch.Tensor, layout: BlockTokenLayout
632
- ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
 
 
633
  obs, action, past, future = [], [], [], []
634
  for block in range(layout.num_blocks):
635
  slices = layout.slices(block)
636
  obs.append(values[:, slices[TokenType.OBS]])
637
  action.append(values[:, slices[TokenType.ACTION]])
638
- past.append(values[:, slices[TokenType.TRACK_PAST]])
639
- future.append(values[:, slices[TokenType.TRACK_FUTURE]])
640
- return tuple(
641
- torch.stack(group, dim=1) for group in (obs, action, past, future)
642
- ) # type: ignore[return-value]
 
 
 
 
643
 
644
  def _causal_coarse_memory(
645
  self,
@@ -707,11 +732,11 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
707
  *,
708
  action: torch.Tensor,
709
  state: torch.Tensor,
710
- past_track_xy: torch.Tensor,
711
- past_track_visibility: torch.Tensor | None,
712
- future_track_xy: torch.Tensor,
713
- future_track_visibility: torch.Tensor | None,
714
- tau: float | torch.Tensor,
715
  obs_tokens: torch.Tensor | None = None,
716
  conditioning_obs_tokens: torch.Tensor | None = None,
717
  video_latents: torch.Tensor | None = None,
@@ -767,23 +792,30 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
767
  action_tokens, state_tokens = self._encode_action_state(
768
  action, state, action_tau_tensor
769
  )
770
- track_tokens = self.track_encoder(
771
- past_track_xy.to(device, dtype),
772
- None
773
- if past_track_visibility is None
774
- else past_track_visibility.to(device, dtype),
775
- future_track_xy.to(device, dtype),
776
- # Future visibility is a supervision mask, not an input. Feeding
777
- # it here would leak target occlusion unavailable at inference.
778
- None,
779
- )
 
 
 
 
 
 
 
780
  hidden, layout = self._pack_tokens(
781
  conditioning,
782
  obs,
783
  action_tokens,
784
  state_tokens,
785
- track_tokens.past_tokens,
786
- track_tokens.future_tokens,
787
  )
788
 
789
  token_tau = self._pack_scalar_by_layout(
@@ -838,7 +870,9 @@ class CausalWanTrackForceModel(DreamZeroCausalWanModel):
838
  action_flow = self.action_decoder(
839
  action_hidden.flatten(1, 2), category
840
  ).view(batch, num_blocks, self.action_horizon, self.action_dim)
841
- track_flow = self.track_decoder(future_hidden)
 
 
842
  obs_flow_tokens = self.obs_token_decoder(obs_hidden)
843
 
844
  memory_indices = layout.indices(
 
121
  gradient_checkpointing: bool = False,
122
  diffusion_model_pretrained_path: str | None = None,
123
  concat_first_frame_latent: bool = False,
124
+ use_track: bool = True,
125
  **_: Any,
126
  ) -> None:
127
  if action_dim != PADDED_ACTION_DIM:
128
  raise ValueError("physical 62-D action must use WAN width 64")
129
  if action_horizon != TRACK_HORIZON:
130
  raise ValueError("action and track future horizons must both be 16")
131
+ if use_track and track_points != NUM_TRACK_POINTS:
132
  raise ValueError("T-Rex track layout is fixed at 250 points")
133
 
134
  super().__init__(
 
159
  concat_first_frame_latent=concat_first_frame_latent,
160
  )
161
  self.action_horizon = action_horizon
162
+ self.use_track = use_track
163
+ # With tracks disabled the packed layout carries zero track tokens,
164
+ # which every layout/mask helper already supports.
165
+ self.track_points = track_points if use_track else 0
166
  self.track_horizon = track_horizon
167
  self.max_track_history = max_track_history
168
  self.max_blocks = max_blocks
 
192
  compatible_blocks.append(block)
193
  self.blocks = compatible_blocks
194
 
195
+ if use_track:
196
+ self.track_encoder = TrackEncoder(
197
+ dim,
198
+ num_points=track_points,
199
+ future_horizon=track_horizon,
200
+ max_history_frames=max_track_history,
201
+ max_blocks=max_blocks,
202
+ )
203
+ self.track_decoder = TrackDecoder(
204
+ dim, num_points=track_points, future_horizon=track_horizon
205
+ )
206
  self.modality_embedding = nn.Embedding(len(TokenType), dim)
207
  self.obs_input_projection = (
208
  nn.Identity()
 
217
  )
218
 
219
  head_dim = dim // num_heads
220
+ if use_track:
221
+ self.freqs_track = rope_params(max_blocks * 2 * track_points, head_dim)
222
  self.freqs_obs_1d = rope_params(
223
  max_blocks * max(frame_seqlen * num_frame_per_block, 1) + frame_seqlen,
224
  head_dim,
 
513
  obs: torch.Tensor,
514
  action: torch.Tensor,
515
  state: torch.Tensor,
516
+ track_past: torch.Tensor | None,
517
+ track_future: torch.Tensor | None,
518
  ) -> tuple[torch.Tensor, BlockTokenLayout]:
519
  layout = BlockTokenLayout(
520
  num_blocks=obs.shape[1],
 
533
  ].view(1, 1, self.dim)
534
  )
535
  for block_index in range(layout.num_blocks):
536
+ entries: list[tuple[torch.Tensor, TokenType]] = [
537
  (obs[:, block_index], TokenType.OBS),
538
  (action[:, block_index], TokenType.ACTION),
539
  (state[:, block_index], TokenType.STATE),
540
+ ]
541
+ if layout.track_points:
542
+ assert track_past is not None and track_future is not None
543
+ entries.extend(
544
+ (
545
+ (track_past[:, block_index], TokenType.TRACK_PAST),
546
+ (track_future[:, block_index], TokenType.TRACK_FUTURE),
547
+ )
548
+ )
549
+ for values, token_type in entries:
550
  groups.append(
551
  values
552
  + self.modality_embedding.weight[int(token_type)].view(
 
577
  -1, layout.action_tokens_per_block
578
  ),
579
  zeros.expand(-1, layout.state_tokens_per_block),
 
 
 
 
580
  )
581
  )
582
+ if layout.track_points:
583
+ groups.extend(
584
+ (
585
+ zeros.expand(-1, layout.track_points),
586
+ track_tau[:, block : block + 1].expand(
587
+ -1, layout.track_points
588
+ ),
589
+ )
590
+ )
591
  return torch.cat(groups, dim=1)
592
 
593
  def _pack_rope(
594
  self, layout: BlockTokenLayout, video_rope: torch.Tensor, device: torch.device
595
  ) -> torch.Tensor:
596
+ self.freqs_action = self.freqs_action.to(device)
597
+ self.freqs_state = self.freqs_state.to(device)
598
+ if self.use_track:
599
+ self.freqs_track = self.freqs_track.to(device)
600
  video_rope = self._squeeze_rope(video_rope).to(device)
601
  groups: list[torch.Tensor] = []
602
  video_cursor = 0
 
624
  ]
625
  )
626
  )
627
+ if layout.track_points:
628
+ track_start = block * 2 * self.track_points
629
+ groups.append(
630
+ self._squeeze_rope(
631
+ self.freqs_track[track_start : track_start + self.track_points]
632
+ )
633
  )
634
+ groups.append(
635
+ self._squeeze_rope(
636
+ self.freqs_track[
637
+ track_start
638
+ + self.track_points : track_start
639
+ + 2 * self.track_points
640
+ ]
641
+ )
642
  )
 
643
  packed = torch.cat(groups, dim=0)
644
  if packed.shape[0] != layout.sequence_length:
645
  raise RuntimeError("packed RoPE does not match token layout")
 
648
  @staticmethod
649
  def _unpack(
650
  values: torch.Tensor, layout: BlockTokenLayout
651
+ ) -> tuple[
652
+ torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None
653
+ ]:
654
  obs, action, past, future = [], [], [], []
655
  for block in range(layout.num_blocks):
656
  slices = layout.slices(block)
657
  obs.append(values[:, slices[TokenType.OBS]])
658
  action.append(values[:, slices[TokenType.ACTION]])
659
+ if layout.track_points:
660
+ past.append(values[:, slices[TokenType.TRACK_PAST]])
661
+ future.append(values[:, slices[TokenType.TRACK_FUTURE]])
662
+ return (
663
+ torch.stack(obs, dim=1),
664
+ torch.stack(action, dim=1),
665
+ torch.stack(past, dim=1) if past else None,
666
+ torch.stack(future, dim=1) if future else None,
667
+ )
668
 
669
  def _causal_coarse_memory(
670
  self,
 
732
  *,
733
  action: torch.Tensor,
734
  state: torch.Tensor,
735
+ past_track_xy: torch.Tensor | None = None,
736
+ past_track_visibility: torch.Tensor | None = None,
737
+ future_track_xy: torch.Tensor | None = None,
738
+ future_track_visibility: torch.Tensor | None = None,
739
+ tau: float | torch.Tensor = 1.0,
740
  obs_tokens: torch.Tensor | None = None,
741
  conditioning_obs_tokens: torch.Tensor | None = None,
742
  video_latents: torch.Tensor | None = None,
 
792
  action_tokens, state_tokens = self._encode_action_state(
793
  action, state, action_tau_tensor
794
  )
795
+ if self.use_track:
796
+ if past_track_xy is None or future_track_xy is None:
797
+ raise ValueError("track inputs are required when use_track=True")
798
+ track_tokens = self.track_encoder(
799
+ past_track_xy.to(device, dtype),
800
+ None
801
+ if past_track_visibility is None
802
+ else past_track_visibility.to(device, dtype),
803
+ future_track_xy.to(device, dtype),
804
+ # Future visibility is a supervision mask, not an input. Feeding
805
+ # it here would leak target occlusion unavailable at inference.
806
+ None,
807
+ )
808
+ track_past_tokens = track_tokens.past_tokens
809
+ track_future_tokens = track_tokens.future_tokens
810
+ else:
811
+ track_past_tokens = track_future_tokens = None
812
  hidden, layout = self._pack_tokens(
813
  conditioning,
814
  obs,
815
  action_tokens,
816
  state_tokens,
817
+ track_past_tokens,
818
+ track_future_tokens,
819
  )
820
 
821
  token_tau = self._pack_scalar_by_layout(
 
870
  action_flow = self.action_decoder(
871
  action_hidden.flatten(1, 2), category
872
  ).view(batch, num_blocks, self.action_horizon, self.action_dim)
873
+ track_flow = (
874
+ self.track_decoder(future_hidden) if self.use_track else None
875
+ )
876
  obs_flow_tokens = self.obs_token_decoder(obs_hidden)
877
 
878
  memory_indices = layout.indices(