88# Action repeat is inspired by CogACT
99
1010
11+ from __future__ import annotations
12+
1113from dataclasses import dataclass , field
14+ from typing import TYPE_CHECKING
1215
1316import torch
1417import torch .nn .functional as F
1720from transformers import PretrainedConfig
1821from transformers .feature_extraction_utils import BatchFeature
1922
23+ if TYPE_CHECKING :
24+ from omegaconf import DictConfig
25+
26+ from flagscale .models .utils .constants import ACTION
2027from flagscale .models .vla .action_model .flow_matching_head .cross_attention_dit import DiT
2128from flagscale .models .vla .action_model .flow_matching_head .encoding_utils import (
2229 SinusoidalPositionalEncoding ,
2330 swish ,
2431)
32+ from flagscale .models .vla .registry import register_action_model
33+
34+
35+ @dataclass
36+ class GR00TActionHeadConfig :
37+ type : str = "gr00t_action_head"
38+ action_model_type : str = "DiT-B"
39+ hidden_size : int = 1024
40+ action_dim : int = 7
41+ state_dim : int = 7
42+ future_action_window_size : int = 7
43+ action_horizon : int = 8
44+ use_state : bool = False
45+ repeated_diffusion_steps : int = 4
46+ add_pos_embed : bool = True
47+ max_seq_len : int = 1024
48+ noise_beta_alpha : float = 1.5
49+ noise_beta_beta : float = 1.0
50+ noise_s : float = 0.999
51+ num_timestep_buckets : int = 1000
52+ num_inference_timesteps : int = 4
53+ num_target_vision_tokens : int = 32
54+ diffusion_model_cfg : dict = field (default_factory = dict )
55+
56+ @classmethod
57+ def from_omegaconf (cls , cfg : DictConfig ) -> GR00TActionHeadConfig :
58+ if cfg .get ("diffusion_model_cfg" ) is None :
59+ raise ValueError ("diffusion_model_cfg is required in action_model config" )
60+ diffusion_cfg = dict (cfg .diffusion_model_cfg )
61+ return cls (
62+ type = cfg .get ("type" , "gr00t_action_head" ),
63+ action_model_type = cfg .get ("action_model_type" , "DiT-B" ),
64+ hidden_size = cfg .get ("hidden_size" , 1024 ),
65+ action_dim = cfg .get ("action_dim" , 7 ),
66+ state_dim = cfg .get ("state_dim" , 7 ),
67+ future_action_window_size = cfg .get ("future_action_window_size" , 7 ),
68+ action_horizon = cfg .get ("action_horizon" , 8 ),
69+ use_state = cfg .get ("use_state" , False ),
70+ repeated_diffusion_steps = cfg .get ("repeated_diffusion_steps" , 4 ),
71+ add_pos_embed = cfg .get ("add_pos_embed" , True ),
72+ max_seq_len = cfg .get ("max_seq_len" , 1024 ),
73+ noise_beta_alpha = cfg .get ("noise_beta_alpha" , 1.5 ),
74+ noise_beta_beta = cfg .get ("noise_beta_beta" , 1.0 ),
75+ noise_s = cfg .get ("noise_s" , 0.999 ),
76+ num_timestep_buckets = cfg .get ("num_timestep_buckets" , 1000 ),
77+ num_inference_timesteps = cfg .get ("num_inference_timesteps" , 4 ),
78+ num_target_vision_tokens = cfg .get ("num_target_vision_tokens" , 32 ),
79+ diffusion_model_cfg = diffusion_cfg ,
80+ )
81+
2582
2683# TODO try to merge DiT Modules with follow_match_head, they are just the same arch, but diff loss, use diffusers package will be simple
2784
@@ -37,7 +94,6 @@ def __init__(self, num_categories, input_dim, hidden_dim):
3794 def forward (self , x , cat_ids ):
3895 selected_W = self .W [cat_ids ]
3996 selected_b = self .b [cat_ids ]
40- # import ipdb; ipdb.set_trace()
4197 return torch .bmm (x , selected_W ) + selected_b .unsqueeze (1 )
4298
4399
@@ -218,12 +274,10 @@ def __init__(self, **kwargs):
218274class FlowmatchingActionHead (nn .Module ):
219275 def __init__ (
220276 self ,
221- full_config ,
277+ config : GR00TActionHeadConfig ,
222278 ):
223279 super ().__init__ ()
224- config = full_config .model .action_model
225280 self .hidden_size = config .hidden_size # @JinhuiYE
226- self .full_config = full_config
227281 action_model_type = config .action_model_type
228282 action_model_cfg = DiTConfig [action_model_type ]
229283
@@ -405,3 +459,47 @@ def device(self):
405459 @property
406460 def dtype (self ):
407461 return next (iter (self .parameters ())).dtype
462+
463+
464+ @register_action_model ("gr00t_action_head" )
465+ class GR00TActionHead (nn .Module ):
466+ """
467+ GR00T action head wrapper for VLA framework.
468+
469+ Adapts the FlowmatchingActionHead (tensor-based interface) to the
470+ dict-based interface expected by the VLA framework (QwenGr00t).
471+ """
472+
473+ def __init__ (self , config : GR00TActionHeadConfig ):
474+ super ().__init__ ()
475+ self ._head = FlowmatchingActionHead (config = config )
476+
477+ def forward (
478+ self , vlm_output : dict [str , torch .Tensor ], action_input : dict [str , torch .Tensor ]
479+ ) -> dict [str , torch .Tensor ]:
480+ vl_embs = vlm_output ["hidden_states" ]
481+ actions = action_input ["actions" ]
482+ state = action_input .get ("state" )
483+ encoder_attention_mask = action_input .get ("attention_mask" )
484+ mask = action_input .get ("mask" )
485+
486+ loss = self ._head .forward (
487+ vl_embs = vl_embs ,
488+ actions = actions ,
489+ state = state ,
490+ encoder_attention_mask = encoder_attention_mask ,
491+ mask = mask ,
492+ )
493+ return {"loss" : loss }
494+
495+ def predict_action (
496+ self , vlm_output : dict [str , torch .Tensor ], action_input : dict [str , torch .Tensor ]
497+ ) -> dict [str , torch .Tensor ]:
498+ vl_embs = vlm_output ["hidden_states" ]
499+ state = action_input .get ("state" )
500+
501+ actions = self ._head .predict_action (vl_embs = vl_embs , state = state )
502+ return {ACTION : actions }
503+
504+ def fsdp_units (self ) -> list [nn .Module ]:
505+ return list (self ._head .model .transformer_blocks )
0 commit comments