Transformer block for image-like data. First, project the input (aka embedding) and reshape to b, t, d. Then apply standard transformer action. Finally, reshape to image NEW: use_linear for more efficiency instead of the 1x1 convs
| 276 | |
| 277 | |
| 278 | class SpatialTransformer(nn.Module): |
| 279 | """ |
| 280 | Transformer block for image-like data. |
| 281 | First, project the input (aka embedding) |
| 282 | and reshape to b, t, d. |
| 283 | Then apply standard transformer action. |
| 284 | Finally, reshape to image |
| 285 | NEW: use_linear for more efficiency instead of the 1x1 convs |
| 286 | """ |
| 287 | def __init__(self, in_channels, n_heads, d_head, |
| 288 | depth=1, dropout=0., context_dim=None, |
| 289 | disable_self_attn=False, use_linear=False, |
| 290 | use_checkpoint=True): |
| 291 | super().__init__() |
| 292 | if exists(context_dim) and not isinstance(context_dim, list): |
| 293 | context_dim = [context_dim] |
| 294 | self.in_channels = in_channels |
| 295 | inner_dim = n_heads * d_head |
| 296 | self.norm = Normalize(in_channels) |
| 297 | if not use_linear: |
| 298 | self.proj_in = nn.Conv2d(in_channels, |
| 299 | inner_dim, |
| 300 | kernel_size=1, |
| 301 | stride=1, |
| 302 | padding=0) |
| 303 | else: |
| 304 | self.proj_in = nn.Linear(in_channels, inner_dim) |
| 305 | |
| 306 | self.transformer_blocks = nn.ModuleList( |
| 307 | [BasicTransformerBlock(inner_dim, n_heads, d_head, dropout=dropout, context_dim=context_dim[d], |
| 308 | disable_self_attn=disable_self_attn, checkpoint=use_checkpoint) |
| 309 | for d in range(depth)] |
| 310 | ) |
| 311 | if not use_linear: |
| 312 | self.proj_out = zero_module(nn.Conv2d(inner_dim, |
| 313 | in_channels, |
| 314 | kernel_size=1, |
| 315 | stride=1, |
| 316 | padding=0)) |
| 317 | else: |
| 318 | self.proj_out = zero_module(nn.Linear(in_channels, inner_dim)) |
| 319 | self.use_linear = use_linear |
| 320 | |
| 321 | def forward(self, x, context=None): |
| 322 | # note: if no context is given, cross-attention defaults to self-attention |
| 323 | if not isinstance(context, list): |
| 324 | context = [context] |
| 325 | b, c, h, w = x.shape |
| 326 | x_in = x |
| 327 | x = self.norm(x) |
| 328 | if not self.use_linear: |
| 329 | x = self.proj_in(x) |
| 330 | x = rearrange(x, 'b c h w -> b (h w) c').contiguous() |
| 331 | if self.use_linear: |
| 332 | x = self.proj_in(x) |
| 333 | for i, block in enumerate(self.transformer_blocks): |
| 334 | x = block(x, context=context[i]) |
| 335 | if self.use_linear: |