Download Isaac-GR00T/gr00t/model/modules/dit.py from Timsty/groot_deployment: direct link, hf CLI and curl.
- Browser
- Download file 18.3 kB
-
https://huggingface.co/Timsty/groot_deployment/resolve/main/Isaac-GR00T/gr00t/model/modules/dit.py
- Command line
-
hf download hf://Timsty/groot_deployment/Isaac-GR00T/gr00t/model/modules/dit.py
-
curl -L -o dit.py https://huggingface.co/Timsty/groot_deployment/resolve/main/Isaac-GR00T/gr00t/model/modules/dit.py
18.3 kB
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| from contextlib import nullcontext | |
| import os | |
| from typing import Optional | |
| from diffusers import ConfigMixin, ModelMixin | |
| from diffusers.configuration_utils import register_to_config | |
| from diffusers.models.attention import Attention, FeedForward | |
| from diffusers.models.embeddings import SinusoidalPositionalEmbedding, TimestepEmbedding, Timesteps | |
| import torch | |
| from torch import nn | |
| import torch.nn.functional as F | |
| def _is_spark_sm121() -> bool: | |
| if not torch.cuda.is_available(): | |
| return False | |
| major, minor = torch.cuda.get_device_capability() | |
| return (major, minor) == (12, 1) | |
| def _should_force_math_sdpa() -> bool: | |
| override = os.environ.get("GR00T_DIT_SDPA_MODE") | |
| if override == "math": | |
| return True | |
| if override == "default": | |
| return False | |
| return _is_spark_sm121() | |
| def _sdpa_context(): | |
| # Spark (sm121) currently hits noisy/broken PyTorch mem-efficient SDPA kernel dispatch. | |
| # Force the safe math backend there; on every other platform this returns a no-op context. | |
| if not _should_force_math_sdpa(): | |
| return nullcontext() | |
| return torch.backends.cuda.sdp_kernel( | |
| enable_flash=False, | |
| enable_math=True, | |
| enable_mem_efficient=False, | |
| enable_cudnn=False, | |
| ) | |
| class TimestepEncoder(nn.Module): | |
| def __init__(self, embedding_dim, compute_dtype=torch.float32): | |
| super().__init__() | |
| self.time_proj = Timesteps(num_channels=256, flip_sin_to_cos=True, downscale_freq_shift=1) | |
| self.timestep_embedder = TimestepEmbedding(in_channels=256, time_embed_dim=embedding_dim) | |
| def forward(self, timesteps): | |
| dtype = next(self.parameters()).dtype | |
| timesteps_proj = self.time_proj(timesteps).to(dtype) | |
| timesteps_emb = self.timestep_embedder(timesteps_proj) # (N, D) | |
| return timesteps_emb | |
| class AdaLayerNorm(nn.Module): | |
| def __init__( | |
| self, | |
| embedding_dim: int, | |
| norm_elementwise_affine: bool = False, | |
| norm_eps: float = 1e-5, | |
| chunk_dim: int = 0, | |
| ): | |
| super().__init__() | |
| self.chunk_dim = chunk_dim | |
| output_dim = embedding_dim * 2 | |
| self.silu = nn.SiLU() | |
| self.linear = nn.Linear(embedding_dim, output_dim) | |
| self.norm = nn.LayerNorm(output_dim // 2, norm_eps, norm_elementwise_affine) | |
| def forward( | |
| self, | |
| x: torch.Tensor, | |
| temb: Optional[torch.Tensor] = None, | |
| ) -> torch.Tensor: | |
| temb = self.linear(self.silu(temb)) | |
| scale, shift = temb.chunk(2, dim=1) | |
| x = self.norm(x) * (1 + scale[:, None]) + shift[:, None] | |
| return x | |
| class BasicTransformerBlock(nn.Module): | |
| def __init__( | |
| self, | |
| dim: int, | |
| num_attention_heads: int, | |
| attention_head_dim: int, | |
| dropout=0.0, | |
| cross_attention_dim: Optional[int] = None, | |
| activation_fn: str = "geglu", | |
| attention_bias: bool = False, | |
| upcast_attention: bool = False, | |
| norm_elementwise_affine: bool = True, | |
| norm_type: str = "layer_norm", # 'layer_norm', 'ada_norm', 'ada_norm_zero', 'ada_norm_single', 'ada_norm_continuous', 'layer_norm_i2vgen' | |
| norm_eps: float = 1e-5, | |
| final_dropout: bool = False, | |
| attention_type: str = "default", | |
| positional_embeddings: Optional[str] = None, | |
| num_positional_embeddings: Optional[int] = None, | |
| ff_inner_dim: Optional[int] = None, | |
| ff_bias: bool = True, | |
| attention_out_bias: bool = True, | |
| ): | |
| super().__init__() | |
| self.dim = dim | |
| self.num_attention_heads = num_attention_heads | |
| self.attention_head_dim = attention_head_dim | |
| self.dropout = dropout | |
| self.cross_attention_dim = cross_attention_dim | |
| self.activation_fn = activation_fn | |
| self.attention_bias = attention_bias | |
| self.norm_elementwise_affine = norm_elementwise_affine | |
| self.positional_embeddings = positional_embeddings | |
| self.num_positional_embeddings = num_positional_embeddings | |
| self.norm_type = norm_type | |
| if positional_embeddings and (num_positional_embeddings is None): | |
| raise ValueError( | |
| "If `positional_embedding` type is defined, `num_positition_embeddings` must also be defined." | |
| ) | |
| if positional_embeddings == "sinusoidal": | |
| self.pos_embed = SinusoidalPositionalEmbedding( | |
| dim, max_seq_length=num_positional_embeddings | |
| ) | |
| else: | |
| self.pos_embed = None | |
| # Define 3 blocks. Each block has its own normalization layer. | |
| # 1. Self-Attn | |
| if norm_type == "ada_norm": | |
| self.norm1 = AdaLayerNorm(dim) | |
| else: | |
| self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine, eps=norm_eps) | |
| self.attn1 = Attention( | |
| query_dim=dim, | |
| heads=num_attention_heads, | |
| dim_head=attention_head_dim, | |
| dropout=dropout, | |
| bias=attention_bias, | |
| cross_attention_dim=cross_attention_dim, | |
| upcast_attention=upcast_attention, | |
| out_bias=attention_out_bias, | |
| ) | |
| # 3. Feed-forward | |
| self.norm3 = nn.LayerNorm(dim, norm_eps, norm_elementwise_affine) | |
| self.ff = FeedForward( | |
| dim, | |
| dropout=dropout, | |
| activation_fn=activation_fn, | |
| final_dropout=final_dropout, | |
| inner_dim=ff_inner_dim, | |
| bias=ff_bias, | |
| ) | |
| if final_dropout: | |
| self.final_dropout = nn.Dropout(dropout) | |
| else: | |
| self.final_dropout = None | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| attention_mask: Optional[torch.Tensor] = None, | |
| encoder_hidden_states: Optional[torch.Tensor] = None, | |
| encoder_attention_mask: Optional[torch.Tensor] = None, | |
| temb: Optional[torch.LongTensor] = None, | |
| ) -> torch.Tensor: | |
| # 0. Self-Attention | |
| if self.norm_type == "ada_norm": | |
| norm_hidden_states = self.norm1(hidden_states, temb) | |
| else: | |
| norm_hidden_states = self.norm1(hidden_states) | |
| if self.pos_embed is not None: | |
| norm_hidden_states = self.pos_embed(norm_hidden_states) | |
| with _sdpa_context(): | |
| attn_output = self.attn1( | |
| norm_hidden_states, | |
| encoder_hidden_states=encoder_hidden_states, | |
| attention_mask=( | |
| encoder_attention_mask if encoder_hidden_states is not None else attention_mask | |
| ), | |
| ) | |
| if self.final_dropout: | |
| attn_output = self.final_dropout(attn_output) | |
| hidden_states = attn_output + hidden_states | |
| if hidden_states.ndim == 4: | |
| hidden_states = hidden_states.squeeze(1) | |
| # 4. Feed-forward | |
| norm_hidden_states = self.norm3(hidden_states) | |
| ff_output = self.ff(norm_hidden_states) | |
| hidden_states = ff_output + hidden_states | |
| if hidden_states.ndim == 4: | |
| hidden_states = hidden_states.squeeze(1) | |
| return hidden_states | |
| class DiT(ModelMixin, ConfigMixin): | |
| _supports_gradient_checkpointing = True | |
| def __init__( | |
| self, | |
| num_attention_heads: int = 8, | |
| attention_head_dim: int = 64, | |
| output_dim: int = 26, | |
| num_layers: int = 12, | |
| dropout: float = 0.1, | |
| attention_bias: bool = True, | |
| activation_fn: str = "gelu-approximate", | |
| num_embeds_ada_norm: Optional[int] = 1000, | |
| upcast_attention: bool = False, | |
| norm_type: str = "ada_norm", | |
| norm_elementwise_affine: bool = False, | |
| norm_eps: float = 1e-5, | |
| max_num_positional_embeddings: int = 512, | |
| compute_dtype=torch.float32, | |
| final_dropout: bool = True, | |
| positional_embeddings: Optional[str] = "sinusoidal", | |
| interleave_self_attention=False, | |
| cross_attention_dim: Optional[int] = None, | |
| ): | |
| super().__init__() | |
| self.attention_head_dim = attention_head_dim | |
| self.inner_dim = self.config.num_attention_heads * self.config.attention_head_dim | |
| self.gradient_checkpointing = False | |
| # Timestep encoder | |
| self.timestep_encoder = TimestepEncoder( | |
| embedding_dim=self.inner_dim, compute_dtype=self.compute_dtype | |
| ) | |
| all_blocks = [] | |
| for idx in range(self.config.num_layers): | |
| use_self_attn = idx % 2 == 1 and interleave_self_attention | |
| curr_cross_attention_dim = cross_attention_dim if not use_self_attn else None | |
| all_blocks += [ | |
| BasicTransformerBlock( | |
| self.inner_dim, | |
| self.config.num_attention_heads, | |
| self.config.attention_head_dim, | |
| dropout=self.config.dropout, | |
| activation_fn=self.config.activation_fn, | |
| attention_bias=self.config.attention_bias, | |
| upcast_attention=self.config.upcast_attention, | |
| norm_type=norm_type, | |
| norm_elementwise_affine=self.config.norm_elementwise_affine, | |
| norm_eps=self.config.norm_eps, | |
| positional_embeddings=positional_embeddings, | |
| num_positional_embeddings=self.config.max_num_positional_embeddings, | |
| final_dropout=final_dropout, | |
| cross_attention_dim=curr_cross_attention_dim, | |
| ) | |
| ] | |
| self.transformer_blocks = nn.ModuleList(all_blocks) | |
| # Output blocks | |
| self.norm_out = nn.LayerNorm(self.inner_dim, elementwise_affine=False, eps=1e-6) | |
| self.proj_out_1 = nn.Linear(self.inner_dim, 2 * self.inner_dim) | |
| self.proj_out_2 = nn.Linear(self.inner_dim, self.output_dim) | |
| print( | |
| "Total number of DiT parameters: ", | |
| sum(p.numel() for p in self.parameters() if p.requires_grad), | |
| ) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, # Shape: (B, T, D) | |
| encoder_hidden_states: torch.Tensor, # Shape: (B, S, D) | |
| timestep: Optional[torch.LongTensor] = None, | |
| encoder_attention_mask: Optional[torch.Tensor] = None, | |
| return_all_hidden_states: bool = False, | |
| ): | |
| # Encode timesteps | |
| temb = self.timestep_encoder(timestep) | |
| # Process through transformer blocks - single pass through the blocks | |
| hidden_states = hidden_states.contiguous() | |
| encoder_hidden_states = encoder_hidden_states.contiguous() | |
| all_hidden_states = [hidden_states] | |
| # Process through transformer blocks | |
| for idx, block in enumerate(self.transformer_blocks): | |
| if idx % 2 == 1 and self.config.interleave_self_attention: | |
| hidden_states = block( | |
| hidden_states, | |
| attention_mask=None, | |
| encoder_hidden_states=None, | |
| encoder_attention_mask=None, | |
| temb=temb, | |
| ) | |
| else: | |
| hidden_states = block( | |
| hidden_states, | |
| attention_mask=None, | |
| encoder_hidden_states=encoder_hidden_states, | |
| encoder_attention_mask=None, | |
| temb=temb, | |
| ) | |
| all_hidden_states.append(hidden_states) | |
| # Output processing | |
| conditioning = temb | |
| shift, scale = self.proj_out_1(F.silu(conditioning)).chunk(2, dim=1) | |
| hidden_states = self.norm_out(hidden_states) * (1 + scale[:, None]) + shift[:, None] | |
| if return_all_hidden_states: | |
| return self.proj_out_2(hidden_states), all_hidden_states | |
| else: | |
| return self.proj_out_2(hidden_states) | |
| class AlternateVLDiT(DiT): | |
| """ | |
| Alternate Vision-Language DiT that separates image and non-image tokens | |
| during cross-attention processing. | |
| """ | |
| def __init__(self, *args, attend_text_every_n_blocks: int = 2, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| self.attend_text_every_n_blocks = attend_text_every_n_blocks | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, # Shape: (B, T, D) | |
| encoder_hidden_states: torch.Tensor, # Shape: (B, S, D) | |
| timestep: Optional[torch.LongTensor] = None, | |
| encoder_attention_mask: Optional[torch.Tensor] = None, | |
| return_all_hidden_states: bool = False, | |
| image_mask: Optional[torch.Tensor] = None, | |
| backbone_attention_mask: Optional[torch.Tensor] = None, | |
| ): | |
| assert image_mask is not None, "Image mask is required" | |
| # Encode timesteps | |
| temb = self.timestep_encoder(timestep) | |
| # Process through transformer blocks - single pass through the blocks | |
| hidden_states = hidden_states.contiguous() | |
| encoder_hidden_states = encoder_hidden_states.contiguous() | |
| # Create attention masks for image and non-image tokens | |
| # image_mask shape: (B, S) where True indicates image tokens | |
| # For attention, we need to invert: False means "don't attend to this token" | |
| image_attention_mask = image_mask & backbone_attention_mask | |
| non_image_attention_mask = (~image_mask) & backbone_attention_mask | |
| all_hidden_states = [hidden_states] | |
| assert self.config.interleave_self_attention, "Interleave self attention must be enabled" | |
| # Process through transformer blocks | |
| for idx, block in enumerate(self.transformer_blocks): | |
| if idx % 2 == 1: | |
| # Self-attention blocks | |
| hidden_states = block( | |
| hidden_states, | |
| attention_mask=None, | |
| encoder_hidden_states=None, | |
| encoder_attention_mask=None, | |
| temb=temb, | |
| ) | |
| else: | |
| # Cross-attention blocks - alternate between non-image and image tokens | |
| if idx % (2 * self.attend_text_every_n_blocks) == 0: | |
| # Attend to non-image tokens | |
| curr_encoder_attention_mask = non_image_attention_mask | |
| else: | |
| # Attend to image tokens | |
| curr_encoder_attention_mask = image_attention_mask | |
| hidden_states = block( | |
| hidden_states, | |
| attention_mask=None, | |
| encoder_hidden_states=encoder_hidden_states, | |
| encoder_attention_mask=curr_encoder_attention_mask, | |
| temb=temb, | |
| ) | |
| all_hidden_states.append(hidden_states) | |
| # Output processing | |
| conditioning = temb | |
| shift, scale = self.proj_out_1(F.silu(conditioning)).chunk(2, dim=1) | |
| hidden_states = self.norm_out(hidden_states) * (1 + scale[:, None]) + shift[:, None] | |
| if return_all_hidden_states: | |
| return self.proj_out_2(hidden_states), all_hidden_states | |
| else: | |
| return self.proj_out_2(hidden_states) | |
| class SelfAttentionTransformer(ModelMixin, ConfigMixin): | |
| _supports_gradient_checkpointing = True | |
| def __init__( | |
| self, | |
| num_attention_heads: int = 8, | |
| attention_head_dim: int = 64, | |
| output_dim: int = 26, | |
| num_layers: int = 12, | |
| dropout: float = 0.1, | |
| attention_bias: bool = True, | |
| activation_fn: str = "gelu-approximate", | |
| num_embeds_ada_norm: Optional[int] = 1000, | |
| upcast_attention: bool = False, | |
| max_num_positional_embeddings: int = 512, | |
| compute_dtype=torch.float32, | |
| final_dropout: bool = True, | |
| positional_embeddings: Optional[str] = "sinusoidal", | |
| interleave_self_attention=False, | |
| ): | |
| super().__init__() | |
| self.attention_head_dim = attention_head_dim | |
| self.inner_dim = self.config.num_attention_heads * self.config.attention_head_dim | |
| self.gradient_checkpointing = False | |
| self.transformer_blocks = nn.ModuleList( | |
| [ | |
| BasicTransformerBlock( | |
| self.inner_dim, | |
| self.config.num_attention_heads, | |
| self.config.attention_head_dim, | |
| dropout=self.config.dropout, | |
| activation_fn=self.config.activation_fn, | |
| attention_bias=self.config.attention_bias, | |
| upcast_attention=self.config.upcast_attention, | |
| positional_embeddings=positional_embeddings, | |
| num_positional_embeddings=self.config.max_num_positional_embeddings, | |
| final_dropout=final_dropout, | |
| ) | |
| for _ in range(self.config.num_layers) | |
| ] | |
| ) | |
| print( | |
| "Total number of SelfAttentionTransformer parameters: ", | |
| sum(p.numel() for p in self.parameters() if p.requires_grad), | |
| ) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, # Shape: (B, T, D) | |
| return_all_hidden_states: bool = False, | |
| ): | |
| # Process through transformer blocks - single pass through the blocks | |
| hidden_states = hidden_states.contiguous() | |
| all_hidden_states = [hidden_states] | |
| # Process through transformer blocks | |
| for idx, block in enumerate(self.transformer_blocks): | |
| hidden_states = block(hidden_states) | |
| all_hidden_states.append(hidden_states) | |
| if return_all_hidden_states: | |
| return hidden_states, all_hidden_states | |
| else: | |
| return hidden_states | |