Spaces:
Running on Zero
Running on Zero
Download diffusion/model/nets/basic_modules.py from Cryptobureau/hack2cortex-sana-video: direct link, hf CLI and curl.
- Browser
- Download file 19.3 kB
-
https://huggingface.co/spaces/Cryptobureau/hack2cortex-sana-video/resolve/main/diffusion/model/nets/basic_modules.py
- Command line
-
hf download hf://spaces/Cryptobureau/hack2cortex-sana-video/diffusion/model/nets/basic_modules.py
-
curl -L -o basic_modules.py https://huggingface.co/spaces/Cryptobureau/hack2cortex-sana-video/resolve/main/diffusion/model/nets/basic_modules.py
19.3 kB
| # Copyright 2024 NVIDIA CORPORATION & AFFILIATES | |
| # | |
| # 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. | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # This file is modified from https://github.com/PixArt-alpha/PixArt-sigma | |
| import torch | |
| import torch.distributed as dist | |
| import torch.nn as nn | |
| from timm.models.vision_transformer import Mlp | |
| from torch.distributed.nn import functional as dist_nn | |
| from diffusion.distributed.context_parallel.config import cp_enabled, get_cp_group | |
| from diffusion.distributed.context_parallel.halo_exchange import cp_halo_exchange | |
| from diffusion.model.act import build_act, get_act_name | |
| from diffusion.model.norms import build_norm, get_norm_name | |
| from diffusion.model.registry import FFN_BLOCKS | |
| from diffusion.model.utils import get_same_padding, val2tuple | |
| class ConvLayer(nn.Module): | |
| def __init__( | |
| self, | |
| in_dim: int, | |
| out_dim: int, | |
| kernel_size=3, | |
| stride=1, | |
| dilation=1, | |
| groups=1, | |
| padding: int or None = None, | |
| use_bias=False, | |
| dropout=0.0, | |
| conv_type="2d", | |
| norm="bn2d", | |
| act="relu", | |
| ): | |
| super().__init__() | |
| if padding is None: | |
| padding = get_same_padding(kernel_size) | |
| padding *= dilation | |
| self.in_dim = in_dim | |
| self.out_dim = out_dim | |
| self.kernel_size = kernel_size | |
| self.stride = stride | |
| self.dilation = dilation | |
| self.groups = groups | |
| self.padding = padding | |
| self.use_bias = use_bias | |
| self.dropout = nn.Dropout2d(dropout, inplace=False) if dropout > 0 else None | |
| if conv_type == "2d": | |
| self.conv = nn.Conv2d( | |
| in_dim, | |
| out_dim, | |
| kernel_size=(kernel_size, kernel_size), | |
| stride=(stride, stride), | |
| padding=padding, | |
| dilation=(dilation, dilation), | |
| groups=groups, | |
| bias=use_bias, | |
| ) | |
| elif conv_type == "3d": | |
| self.conv = nn.Conv3d( | |
| in_dim, | |
| out_dim, | |
| kernel_size=(kernel_size, kernel_size, kernel_size), | |
| stride=(stride, stride, stride), | |
| padding=padding, | |
| dilation=(dilation, dilation, dilation), | |
| groups=groups, | |
| bias=use_bias, | |
| ) | |
| else: | |
| self.conv = None | |
| self.norm = build_norm(norm, num_features=out_dim) | |
| self.act = build_act(act) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| if self.dropout is not None: | |
| x = self.dropout(x) | |
| x = self.conv(x) | |
| if self.norm: | |
| x = self.norm(x) | |
| if self.act: | |
| x = self.act(x) | |
| return x | |
| # Safe element-count threshold for a single conv call: PyTorch's 2D conv kernels | |
| # (both cuDNN and the ATEN fallback) use 32-bit indexing internally, so very | |
| # large ``(BT, C, H, W)`` inputs (e.g. minute-scale video at default CFG) can | |
| # overflow. Empirically a single call up to ~1 B elements is safe; above that | |
| # we chunk along the leading dim. Set so short videos stay on the original | |
| # fused path (no chunking, no overhead) and long videos transparently split. | |
| _INT32_SAFE_CONV_ELEMENTS = 1 << 30 # 1,073,741,824 | |
| class GLUMBConv(nn.Module): | |
| def __init__( | |
| self, | |
| in_features: int, | |
| hidden_features: int, | |
| out_feature=None, | |
| kernel_size=3, | |
| stride=1, | |
| padding: int or None = None, | |
| use_bias=False, | |
| norm=(None, None, None), | |
| act=("silu", "silu", None), | |
| dilation=1, | |
| ): | |
| out_feature = out_feature or in_features | |
| super().__init__() | |
| use_bias = val2tuple(use_bias, 3) | |
| norm = val2tuple(norm, 3) | |
| act = val2tuple(act, 3) | |
| self.glu_act = build_act(act[1], inplace=False) | |
| self.inverted_conv = ConvLayer( | |
| in_features, | |
| hidden_features * 2, | |
| 1, | |
| use_bias=use_bias[0], | |
| norm=norm[0], | |
| act=act[0], | |
| ) | |
| self.depth_conv = ConvLayer( | |
| hidden_features * 2, | |
| hidden_features * 2, | |
| kernel_size, | |
| stride=stride, | |
| groups=hidden_features * 2, | |
| padding=padding, | |
| use_bias=use_bias[1], | |
| norm=norm[1], | |
| act=None, | |
| dilation=dilation, | |
| ) | |
| self.point_conv = ConvLayer( | |
| hidden_features, | |
| out_feature, | |
| 1, | |
| use_bias=use_bias[2], | |
| norm=norm[2], | |
| act=act[2], | |
| ) | |
| def _apply_spatial(self, x: torch.Tensor) -> torch.Tensor: | |
| """Fused spatial pipeline: inverted_conv -> depth_conv -> GLU -> point_conv.""" | |
| x = self.inverted_conv(x) | |
| x = self.depth_conv(x) | |
| a, g = torch.chunk(x, 2, dim=1) | |
| g = self.glu_act(g) | |
| return self.point_conv(a * g) | |
| def _apply_spatial_autochunked(self, x: torch.Tensor) -> torch.Tensor: | |
| """Run :meth:`_apply_spatial`, chunking dim 0 to keep each call under | |
| PyTorch's 32-bit conv indexing limit. No-op for short inputs.""" | |
| BT, _, H, W = x.shape | |
| # Conservative estimate of the largest intermediate (after inverted_conv). | |
| elements_per_bt = self.inverted_conv.conv.out_channels * H * W | |
| max_bt = max(1, _INT32_SAFE_CONV_ELEMENTS // elements_per_bt) | |
| if BT <= max_bt: | |
| return self._apply_spatial(x) | |
| return torch.cat([self._apply_spatial(x[s : s + max_bt]) for s in range(0, BT, max_bt)], dim=0) | |
| def forward(self, x: torch.Tensor, HW=None) -> torch.Tensor: | |
| B, N, C = x.shape | |
| if HW is None: | |
| H = W = int(N**0.5) | |
| elif len(HW) == 2: | |
| H, W = HW | |
| x = x.reshape(B, H, W, C).permute(0, 3, 1, 2) | |
| elif len(HW) == 3: | |
| T, H, W = HW | |
| x = x.reshape(B * T, H, W, C).permute(0, 3, 1, 2) | |
| x = self._apply_spatial_autochunked(x) | |
| if len(HW) == 3: | |
| x = x.reshape(B * T, C, H * W).permute(0, 2, 1) | |
| x = x.reshape(B, N, C) | |
| else: | |
| x = x.reshape(B, C, N).permute(0, 2, 1) | |
| return x | |
| class GLUMBConvTemp(GLUMBConv): | |
| def __init__( | |
| self, | |
| in_features: int, | |
| hidden_features: int, | |
| out_feature=None, | |
| kernel_size=3, | |
| stride=1, | |
| padding: int or None = None, | |
| use_bias=False, | |
| norm=(None, None, None), | |
| act=("silu", "silu", None), | |
| t_kernel_size=3, | |
| ): | |
| super().__init__( | |
| in_features=in_features, | |
| hidden_features=hidden_features, | |
| out_feature=out_feature, | |
| kernel_size=kernel_size, | |
| stride=stride, | |
| padding=padding, | |
| use_bias=use_bias, | |
| norm=norm, | |
| act=act, | |
| ) | |
| out_feature = out_feature or in_features | |
| t_padding = t_kernel_size // 2 | |
| self.t_conv = nn.Conv2d( | |
| out_feature, | |
| out_feature, | |
| kernel_size=(t_kernel_size, 1), | |
| stride=1, | |
| padding=(t_padding, 0), | |
| bias=False, | |
| ) | |
| nn.init.zeros_(self.t_conv.weight) | |
| def forward(self, x: torch.Tensor, HW=None, **kwargs) -> torch.Tensor: | |
| B, N, C = x.shape | |
| assert len(HW) == 3, "HW must be a tuple of (T, H, W)" | |
| T, H, W = HW | |
| x = x.reshape(B * T, H, W, C).permute(0, 3, 1, 2) | |
| x = self._apply_spatial_autochunked(x) | |
| # Temporal aggregation | |
| x_reshaped = x.view(B, T, C, H * W).permute(0, 2, 1, 3) | |
| frame_mask = kwargs.get("frame_valid_mask", None) | |
| if frame_mask is not None: | |
| frame_mask = frame_mask.reshape(B, T).to(x_reshaped) | |
| x_reshaped = x_reshaped * frame_mask[:, None, :, None] | |
| cp_active = cp_enabled() and get_cp_group() is not None | |
| if cp_active and self.t_conv.padding[0] > 0: | |
| halo = int(self.t_conv.padding[0]) | |
| x_halo = cp_halo_exchange(x_reshaped, left_size=halo, right_size=halo, dim=2, group=get_cp_group()) | |
| t_out = self.t_conv(x_halo)[:, :, halo : halo + T, :] | |
| else: | |
| t_out = self.t_conv(x_reshaped) | |
| x_out = x_reshaped + t_out | |
| if frame_mask is not None: | |
| x_out = x_out * frame_mask[:, None, :, None] | |
| x_out = x_out.permute(0, 2, 3, 1).reshape(B, N, C) | |
| return x_out | |
| class ChunkGLUMBConvTemp(GLUMBConvTemp): | |
| def forward(self, x: torch.Tensor, HW=None, chunk_index=None, **kwargs) -> torch.Tensor: | |
| if chunk_index is None: | |
| chunk_index = [0] | |
| B, N, C = x.shape | |
| assert len(HW) == 3, "HW must be a tuple of (T, H, W)" | |
| T, H, W = HW | |
| x = x.reshape(B * T, H, W, C).permute(0, 3, 1, 2) | |
| x = self._apply_spatial_autochunked(x) | |
| x_reshaped = x.view(B, T, C, H * W).permute(0, 2, 1, 3) # B, C, T, H*W | |
| frame_mask = kwargs.get("frame_valid_mask") | |
| if frame_mask is not None: | |
| frame_mask = frame_mask.reshape(B, T).to(x_reshaped) | |
| x_reshaped = x_reshaped * frame_mask[:, None, :, None] | |
| x_local = x_reshaped | |
| cp_group = get_cp_group() if cp_enabled() else None | |
| if cp_group is not None and kwargs.get("chunk_index_global") is not None: | |
| cp_rank = dist.get_rank(cp_group) | |
| x_reshaped = torch.cat(dist_nn.all_gather(x_reshaped.contiguous(), group=cp_group), dim=2) | |
| chunk_index = kwargs["chunk_index_global"] | |
| T_work = x_reshaped.shape[2] | |
| else: | |
| cp_rank = 0 | |
| T_work = T | |
| padding_size = self.t_conv.kernel_size[0] // 2 | |
| chunk_boundaries = sorted({0, *(int(idx) for idx in chunk_index if 0 < int(idx) < T_work), T_work}) | |
| chunk_sizes = [end - start for start, end in zip(chunk_boundaries, chunk_boundaries[1:])] | |
| x_reshaped_list = x_reshaped.split(chunk_sizes, dim=-2) | |
| padded_x_reshaped_list = [] | |
| padded_x_reshaped_list.append( | |
| torch.cat([x_reshaped_list[0], x_reshaped.new_zeros(B, C, padding_size, H * W)], dim=-2) | |
| ) | |
| for i in range(1, len(x_reshaped_list)): | |
| prev_chunk = x_reshaped_list[i - 1][:, :, -padding_size:, :] | |
| cur_chunk = x_reshaped_list[i] | |
| padded_x_reshaped_list.append( | |
| torch.cat( | |
| [ | |
| prev_chunk, | |
| cur_chunk, | |
| x_reshaped.new_zeros(B, C, padding_size, H * W), | |
| ], | |
| dim=-2, | |
| ) | |
| ) | |
| x_reshaped_t_conv = torch.cat(padded_x_reshaped_list, dim=-2) | |
| t_conv_out = self.t_conv(x_reshaped_t_conv) | |
| padded_chunk_sizes = [chunk_sizes[0] + padding_size] + [ | |
| padding_size + chunk_size + padding_size for chunk_size in chunk_sizes[1:] | |
| ] | |
| t_conv_out_list = t_conv_out.split(padded_chunk_sizes, dim=-2) | |
| unpadded_chunks = [] | |
| for i, chunk in enumerate(t_conv_out_list): | |
| if i == 0: | |
| unpadded_chunk = chunk[:, :, : chunk_sizes[i], :] | |
| else: | |
| start_idx = padding_size | |
| end_idx = start_idx + chunk_sizes[i] | |
| unpadded_chunk = chunk[:, :, start_idx:end_idx, :] | |
| unpadded_chunks.append(unpadded_chunk) | |
| t_conv_out_final = torch.cat(unpadded_chunks, dim=-2) | |
| assert ( | |
| t_conv_out_final.shape[-2] == T_work | |
| ), f"Expected temporal dimension {T_work}, got {t_conv_out_final.shape[-2]}" | |
| if cp_group is not None and kwargs.get("chunk_index_global") is not None: | |
| t_conv_out_final = t_conv_out_final[:, :, cp_rank * T : (cp_rank + 1) * T] | |
| x_out = x_local + t_conv_out_final | |
| if frame_mask is not None: | |
| x_out = x_out * frame_mask[:, None, :, None] | |
| x_out = x_out.permute(0, 2, 3, 1).reshape(B, N, C) | |
| return x_out | |
| class CachedGLUMBConvTemp(GLUMBConvTemp): | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| def forward(self, x: torch.Tensor, HW=None, save_kv_cache=False, kv_cache=None, **kwargs) -> torch.Tensor: | |
| B, N, C = x.shape | |
| assert len(HW) == 3, "HW must be a tuple of (T, H, W)" | |
| T, H, W = HW | |
| x = x.reshape(B * T, H, W, C).permute(0, 3, 1, 2) | |
| x = self._apply_spatial_autochunked(x) | |
| # Temporal aggregation | |
| x_reshaped = x.view(B, T, C, H * W).permute(0, 2, 1, 3) # B,C,T,HW | |
| padding_size = self.t_conv.kernel_size[0] // 2 | |
| x_t_conv_in = x_reshaped | |
| padded_size = 0 | |
| # Tconv state lives in the last slot of the per-block KV cache list. | |
| # The streaming sampler's 10-slot layout uses indices 0-3 / 4-6 for | |
| # main + camera attention state and the final slot (-1) for the | |
| # temporal short conv left context written here. | |
| if kv_cache is not None: | |
| if kv_cache[-1] is not None: | |
| # Slice to the actual conv padding window in case the cache | |
| # spans multiple past chunks. | |
| x_t_conv_in = torch.cat([kv_cache[-1][:, :, -padding_size:], x_reshaped], dim=2) # B,C,P+T,HW | |
| padded_size = x_t_conv_in.shape[2] - x_reshaped.shape[2] | |
| if save_kv_cache: # Save current chunk's cache for next chunk | |
| kv_cache[-1] = x_reshaped[:, :, -padding_size:, :].detach().clone() | |
| t_conv_out = self.t_conv(x_t_conv_in)[:, :, padded_size:] | |
| x_out = x_reshaped + t_conv_out | |
| x_out = x_out.permute(0, 2, 3, 1).reshape(B, N, C) | |
| if kv_cache is not None: | |
| return x_out, kv_cache | |
| return x_out | |
| class MBConvPreGLU(nn.Module): | |
| def __init__( | |
| self, | |
| in_dim: int, | |
| out_dim: int, | |
| kernel_size=3, | |
| stride=1, | |
| mid_dim=None, | |
| expand=6, | |
| padding: int or None = None, | |
| use_bias=False, | |
| norm=(None, None, "ln2d"), | |
| act=("silu", "silu", None), | |
| ): | |
| super().__init__() | |
| use_bias = val2tuple(use_bias, 3) | |
| norm = val2tuple(norm, 3) | |
| act = val2tuple(act, 3) | |
| mid_dim = mid_dim or round(in_dim * expand) | |
| self.inverted_conv = ConvLayer( | |
| in_dim, | |
| mid_dim * 2, | |
| 1, | |
| use_bias=use_bias[0], | |
| norm=norm[0], | |
| act=None, | |
| ) | |
| self.glu_act = build_act(act[0], inplace=False) | |
| self.depth_conv = ConvLayer( | |
| mid_dim, | |
| mid_dim, | |
| kernel_size, | |
| stride=stride, | |
| groups=mid_dim, | |
| padding=padding, | |
| use_bias=use_bias[1], | |
| norm=norm[1], | |
| act=act[1], | |
| ) | |
| self.point_conv = ConvLayer( | |
| mid_dim, | |
| out_dim, | |
| 1, | |
| use_bias=use_bias[2], | |
| norm=norm[2], | |
| act=act[2], | |
| ) | |
| def forward(self, x: torch.Tensor, HW=None) -> torch.Tensor: | |
| B, N, C = x.shape | |
| if HW is None: | |
| H = W = int(N**0.5) | |
| else: | |
| H, W = HW | |
| x = x.reshape(B, H, W, C).permute(0, 3, 1, 2) | |
| x = self.inverted_conv(x) | |
| x, gate = torch.chunk(x, 2, dim=1) | |
| gate = self.glu_act(gate) | |
| x = x * gate | |
| x = self.depth_conv(x) | |
| x = self.point_conv(x) | |
| x = x.reshape(B, C, N).permute(0, 2, 1) | |
| return x | |
| def module_str(self) -> str: | |
| _str = f"{self.depth_conv.kernel_size}{type(self).__name__}(" | |
| _str += f"in={self.inverted_conv.in_dim},mid={self.depth_conv.in_dim},out={self.point_conv.out_dim},s={self.depth_conv.stride}" | |
| _str += ( | |
| f",norm={get_norm_name(self.inverted_conv.norm)}" | |
| f"+{get_norm_name(self.depth_conv.norm)}" | |
| f"+{get_norm_name(self.point_conv.norm)}" | |
| ) | |
| _str += ( | |
| f",act={get_act_name(self.inverted_conv.act)}" | |
| f"+{get_act_name(self.depth_conv.act)}" | |
| f"+{get_act_name(self.point_conv.act)}" | |
| ) | |
| _str += f",glu_act={get_act_name(self.glu_act)})" | |
| return _str | |
| class DWMlp(Mlp): | |
| """MLP as used in Vision Transformer, MLP-Mixer and related networks""" | |
| def __init__( | |
| self, | |
| in_features, | |
| hidden_features=None, | |
| out_features=None, | |
| act_layer=nn.GELU, | |
| bias=True, | |
| drop=0.0, | |
| kernel_size=3, | |
| stride=1, | |
| dilation=1, | |
| padding=None, | |
| ): | |
| super().__init__( | |
| in_features=in_features, | |
| hidden_features=hidden_features, | |
| out_features=out_features, | |
| act_layer=act_layer, | |
| bias=bias, | |
| drop=drop, | |
| ) | |
| hidden_features = hidden_features or in_features | |
| self.hidden_features = hidden_features | |
| if padding is None: | |
| padding = get_same_padding(kernel_size) | |
| padding *= dilation | |
| self.conv = nn.Conv2d( | |
| hidden_features, | |
| hidden_features, | |
| kernel_size=(kernel_size, kernel_size), | |
| stride=(stride, stride), | |
| padding=padding, | |
| dilation=(dilation, dilation), | |
| groups=hidden_features, | |
| bias=bias, | |
| ) | |
| def forward(self, x, HW=None): | |
| B, N, C = x.shape | |
| if HW is None: | |
| H = W = int(N**0.5) | |
| else: | |
| H, W = HW | |
| x = self.fc1(x) | |
| x = self.act(x) | |
| x = self.drop1(x) | |
| x = x.reshape(B, H, W, self.hidden_features).permute(0, 3, 1, 2) | |
| x = self.conv(x) | |
| x = x.reshape(B, self.hidden_features, N).permute(0, 2, 1) | |
| x = self.fc2(x) | |
| x = self.drop2(x) | |
| return x | |
| class Mlp(Mlp): | |
| """MLP as used in Vision Transformer, MLP-Mixer and related networks""" | |
| def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, bias=True, drop=0.0): | |
| super().__init__( | |
| in_features=in_features, | |
| hidden_features=hidden_features, | |
| out_features=out_features, | |
| act_layer=act_layer, | |
| bias=bias, | |
| drop=drop, | |
| ) | |
| def forward(self, x, HW=None): | |
| x = self.fc1(x) | |
| x = self.act(x) | |
| x = self.drop1(x) | |
| x = self.fc2(x) | |
| x = self.drop2(x) | |
| return x | |
| if __name__ == "__main__": | |
| model = GLUMBConv( | |
| 1152, | |
| 1152 * 4, | |
| 1152, | |
| use_bias=(True, True, False), | |
| norm=(None, None, None), | |
| act=("silu", "silu", None), | |
| ).cuda() | |
| input = torch.randn(4, 256, 1152).cuda() | |
| output = model(input) | |