mirror of
https://git.datalinker.icu/comfyanonymous/ComfyUI
synced 2026-08-23 06:57:52 +08:00
157 lines
4.7 KiB
Python
157 lines
4.7 KiB
Python
import torch
|
|
import torch.nn as nn
|
|
import torch.nn.functional as F
|
|
|
|
class DropPath(nn.Module):
|
|
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
|
|
"""
|
|
|
|
def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True):
|
|
super(DropPath, self).__init__()
|
|
self.drop_prob = drop_prob
|
|
self.scale_by_keep = scale_by_keep
|
|
|
|
def forward(self, x):
|
|
|
|
keep_prob = 1 - self.drop_prob
|
|
shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
|
|
|
|
random_tensor = x.new_empty(shape).bernoulli_(keep_prob)
|
|
|
|
if keep_prob > 0.0 and self.scale_by_keep:
|
|
random_tensor.div_(keep_prob)
|
|
|
|
return x * random_tensor
|
|
|
|
class MLP(nn.Module):
|
|
def __init__(self, width: int, ratio: int = 4, drop_path_rate: float = 0):
|
|
super().__init__()
|
|
self.gelu = nn.GELU()
|
|
self.c_fc = nn.Linear(width, width * ratio)
|
|
self.c_proj = nn.Linear(width * ratio, width)
|
|
self.drop_path = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
|
|
|
|
def forward(self, x):
|
|
return self.drop_path(self.c_proj(self.gelu(self.c_fc(x))))
|
|
|
|
|
|
class QKVMultiheadAttention(nn.Module):
|
|
def __init__(
|
|
self,
|
|
heads: int,
|
|
n_ctx: int,
|
|
width=None,
|
|
qk_norm=False,
|
|
norm_layer=nn.LayerNorm
|
|
):
|
|
super().__init__()
|
|
self.heads = heads
|
|
self.n_ctx = n_ctx
|
|
self.q_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
|
|
self.k_norm = norm_layer(width // heads, elementwise_affine=True, eps=1e-6) if qk_norm else nn.Identity()
|
|
|
|
def forward(self, qkv):
|
|
bs, n_ctx, width = qkv.shape
|
|
attn_ch = width // self.heads // 3
|
|
qkv = qkv.view(bs, n_ctx, self.heads, -1)
|
|
q, k, v = torch.split(qkv, attn_ch, dim=-1)
|
|
|
|
q = self.q_norm(q)
|
|
k = self.k_norm(k)
|
|
|
|
q, k, v = [t.permute(0, 2, 1, 3) for t in (q, k, v)]
|
|
out = F.scaled_dot_product_attention(q, k, v).transpose(1, 2).reshape(bs, n_ctx, -1)
|
|
return out
|
|
|
|
|
|
class MultiheadAttention(nn.Module):
|
|
def __init__(
|
|
self,
|
|
n_ctx: int,
|
|
width: int,
|
|
heads: int,
|
|
qkv_bias: bool,
|
|
norm_layer = nn.LayerNorm,
|
|
qk_norm: bool = False,
|
|
drop_path_rate: float = 0.0
|
|
):
|
|
super().__init__()
|
|
|
|
self.c_qkv = nn.Linear(width, width * 3, bias=qkv_bias)
|
|
self.c_proj = nn.Linear(width, width)
|
|
|
|
self.attention = QKVMultiheadAttention(
|
|
heads = heads,
|
|
n_ctx = n_ctx,
|
|
width = width,
|
|
norm_layer = norm_layer,
|
|
qk_norm = qk_norm
|
|
)
|
|
self.drop_path = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
|
|
|
|
def forward(self, x):
|
|
x = self.c_qkv(x)
|
|
x = self.attention(x)
|
|
x = self.drop_path(self.c_proj(x))
|
|
return x
|
|
|
|
|
|
class ResAttnBlock(nn.Module):
|
|
def __init__(
|
|
self,
|
|
*,
|
|
n_ctx: int,
|
|
width: int,
|
|
heads: int,
|
|
qkv_bias: bool = True,
|
|
norm_layer=nn.LayerNorm,
|
|
qk_norm: bool = False,
|
|
drop_path_rate: float = 0.0,
|
|
):
|
|
super().__init__()
|
|
self.attn = MultiheadAttention(
|
|
n_ctx=n_ctx,
|
|
width=width,
|
|
heads=heads,
|
|
qkv_bias=qkv_bias,
|
|
norm_layer=norm_layer,
|
|
qk_norm=qk_norm,
|
|
drop_path_rate=drop_path_rate
|
|
)
|
|
self.ln_1 = norm_layer(width, elementwise_affine=True, eps=1e-6)
|
|
self.mlp = MLP(width=width, drop_path_rate=drop_path_rate)
|
|
self.ln_2 = norm_layer(width, elementwise_affine=True, eps=1e-6)
|
|
|
|
def forward(self, x: torch.Tensor):
|
|
x = x + self.attn(self.ln_1(x))
|
|
x = x + self.mlp(self.ln_2(x))
|
|
return x
|
|
|
|
class Transformer(nn.Module):
|
|
def __init__(self, n_ctx: int, heads: int, width: int, depth: int,
|
|
qkv_bias: bool = True, qk_norm: bool = False, drop_path_rate: float = 0.0):
|
|
super().__init__()
|
|
|
|
self.resblocks = nn.ModuleList([
|
|
ResAttnBlock(n_ctx = n_ctx,
|
|
heads = heads,
|
|
width = width,
|
|
qkv_bias = qkv_bias,
|
|
qk_norm = qk_norm,
|
|
drop_path_rate = drop_path_rate)
|
|
for _ in range(depth)
|
|
])
|
|
|
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
|
|
for resnet in self.resblocks:
|
|
x = resnet(x)
|
|
|
|
return x
|
|
|
|
if __name__ == "__main__":
|
|
torch.manual_seed(2025)
|
|
model = Transformer(512, 8, 224, 3)
|
|
outputs = model(x = torch.randn(1, 512, 224))
|
|
print(outputs)
|