Predict noise ε_θ(x_t, t). Args: x: (batch, C, H, W) — noisy image x_t t: (batch,) — integer timesteps Returns: (batch, C, H, W) — predicted noise ε_θ
(self, x: torch.Tensor, t: torch.Tensor)
| 314 | nn.init.zeros_(self.output_conv.bias) |
| 315 | |
| 316 | def forward(self, x: torch.Tensor, t: torch.Tensor) -> torch.Tensor: |
| 317 | """Predict noise ε_θ(x_t, t). |
| 318 | |
| 319 | Args: |
| 320 | x: (batch, C, H, W) — noisy image x_t |
| 321 | t: (batch,) — integer timesteps |
| 322 | |
| 323 | Returns: |
| 324 | (batch, C, H, W) — predicted noise ε_θ |
| 325 | """ |
| 326 | # Time embedding |
| 327 | t_emb = self.time_embed(t) # (batch, time_embed_dim) |
| 328 | |
| 329 | # Initial conv |
| 330 | h = self.input_conv(x) # (batch, base_channels, H, W) |
| 331 | |
| 332 | # Downsampling with skip connections |
| 333 | skips = [h] |
| 334 | block_idx = 0 |
| 335 | for level in range(len(self.config.channel_mults)): |
| 336 | for _ in range(self.config.num_res_blocks): |
| 337 | layers = self.down_blocks[block_idx] |
| 338 | h = layers[0](h, t_emb) # ResidualBlock |
| 339 | if len(layers) > 1: |
| 340 | h = layers[1](h) # AttentionBlock (if present) |
| 341 | skips.append(h) |
| 342 | block_idx += 1 |
| 343 | |
| 344 | h = self.down_samples[level](h) |
| 345 | if not isinstance(self.down_samples[level], nn.Identity): |
| 346 | skips.append(h) |
| 347 | |
| 348 | # Middle |
| 349 | h = self.mid_block1(h, t_emb) |
| 350 | h = self.mid_attn(h) |
| 351 | h = self.mid_block2(h, t_emb) |
| 352 | |
| 353 | # Upsampling with skip connections |
| 354 | block_idx = 0 |
| 355 | for level in reversed(range(len(self.config.channel_mults))): |
| 356 | for _ in range(self.config.num_res_blocks + 1): |
| 357 | skip = skips.pop() |
| 358 | h = torch.cat([h, skip], dim=1) # Concatenate skip connection |
| 359 | layers = self.up_blocks[block_idx] |
| 360 | h = layers[0](h, t_emb) # ResidualBlock |
| 361 | if len(layers) > 1: |
| 362 | h = layers[1](h) # AttentionBlock (if present) |
| 363 | block_idx += 1 |
| 364 | |
| 365 | h = self.up_samples[level - len(self.config.channel_mults)](h) if level > 0 else h |
| 366 | |
| 367 | # Output |
| 368 | h = self.output_norm(h) |
| 369 | h = F.silu(h) |
| 370 | return self.output_conv(h) # (batch, C, H, W) — predicted noise |
| 371 | |
| 372 | def __repr__(self) -> str: |
| 373 | total_params = sum(p.numel() for p in self.parameters()) |
nothing calls this directly
no outgoing calls
no test coverage detected