r""" Causal self-attention with a single head. Args: dim (int): The number of channels in the input tensor.
| 383 | |
| 384 | |
| 385 | class WanAttentionBlock(nn.Module): |
| 386 | r""" |
| 387 | Causal self-attention with a single head. |
| 388 | |
| 389 | Args: |
| 390 | dim (int): The number of channels in the input tensor. |
| 391 | """ |
| 392 | |
| 393 | def __init__(self, dim): |
| 394 | super().__init__() |
| 395 | self.dim = dim |
| 396 | |
| 397 | # layers |
| 398 | self.norm = WanRMS_norm(dim) |
| 399 | self.to_qkv = nn.Conv2d(dim, dim * 3, 1) |
| 400 | self.proj = nn.Conv2d(dim, dim, 1) |
| 401 | |
| 402 | def forward(self, x): |
| 403 | identity = x |
| 404 | batch_size, channels, time, height, width = x.size() |
| 405 | |
| 406 | x = x.permute(0, 2, 1, 3, 4).reshape(batch_size * time, channels, height, width) |
| 407 | x = self.norm(x) |
| 408 | |
| 409 | # compute query, key, value |
| 410 | qkv = self.to_qkv(x) |
| 411 | qkv = qkv.reshape(batch_size * time, 1, channels * 3, -1) |
| 412 | qkv = qkv.permute(0, 1, 3, 2).contiguous() |
| 413 | q, k, v = qkv.chunk(3, dim=-1) |
| 414 | |
| 415 | # apply attention |
| 416 | x = F.scaled_dot_product_attention(q, k, v) |
| 417 | |
| 418 | x = x.squeeze(1).permute(0, 2, 1).reshape(batch_size * time, channels, height, width) |
| 419 | |
| 420 | # output projection |
| 421 | x = self.proj(x) |
| 422 | |
| 423 | # Reshape back: [(b*t), c, h, w] -> [b, c, t, h, w] |
| 424 | x = x.view(batch_size, time, channels, height, width) |
| 425 | x = x.permute(0, 2, 1, 3, 4) |
| 426 | |
| 427 | return x + identity |
| 428 | |
| 429 | |
| 430 | class WanMidBlock(nn.Module): |