Delete lecture_2
Browse files
lecture_2/README.md
DELETED
|
@@ -1,115 +0,0 @@
|
|
| 1 |
-
# Lecture 2 · MNIST Flow Matching
|
| 2 |
-
|
| 3 |
-
This lecture contains one Python script:
|
| 4 |
-
[flow_matching_unet_lecture.py](flow_matching_unet_lecture.py).
|
| 5 |
-
It covers MNIST downloading and data loading, a simple U-Net class, conditional
|
| 6 |
-
flow-matching training, and Euler sampling. Digit labels are ignored during
|
| 7 |
-
training, so generation is unconditional.
|
| 8 |
-
|
| 9 |
-
## Train and generate
|
| 10 |
-
|
| 11 |
-
After installing the [repository requirements](../requirements.txt), run this
|
| 12 |
-
command from the repository root:
|
| 13 |
-
|
| 14 |
-
```bash
|
| 15 |
-
python lecture_2/flow_matching_unet_lecture.py
|
| 16 |
-
```
|
| 17 |
-
|
| 18 |
-
The script downloads the 60,000-image MNIST training split into `data/`,
|
| 19 |
-
normalizes pixel values to the range [-1, 1], trains for 20 epochs, and saves
|
| 20 |
-
these files in `flow_matching_outputs/`:
|
| 21 |
-
|
| 22 |
-
| File | Contents |
|
| 23 |
-
| --- | --- |
|
| 24 |
-
| `flow_unet_mnist.pt` | Learned model weights, loss history, channel width, and training seed |
|
| 25 |
-
| `samples.png` | A grid of 16 generated images |
|
| 26 |
-
| `trajectory.png` | Four samples progressing from noise to images |
|
| 27 |
-
|
| 28 |
-
Paths are relative to the working directory. Change the constants in section 02
|
| 29 |
-
to adjust epochs, batch size, sampling steps, or output paths. CUDA, Apple MPS,
|
| 30 |
-
and CPU are selected automatically according to availability.
|
| 31 |
-
|
| 32 |
-
## Saved checkpoint
|
| 33 |
-
|
| 34 |
-
The bundled [flow_unet_mnist.pt](https://huggingface.co/ChatterjeeLab/CIS6270/resolve/main/lecture_2/flow_unet_mnist.pt?download=true)
|
| 35 |
-
was trained using the script's model, training function, and sampler.
|
| 36 |
-
|
| 37 |
-
| Setting | Saved run |
|
| 38 |
-
| --- | --- |
|
| 39 |
-
| Training data | All 60,000 MNIST training images |
|
| 40 |
-
| Completed epochs | 5 |
|
| 41 |
-
| Optimizer updates | 2,345 |
|
| 42 |
-
| Batch size | 128 |
|
| 43 |
-
| Optimizer | AdamW, learning rate 0.0002, weight decay 0 |
|
| 44 |
-
| U-Net widths | 32, 64, 128 channels |
|
| 45 |
-
| Trainable parameters | 471,265 |
|
| 46 |
-
| Training seed | 7 |
|
| 47 |
-
| Sampling | 100 forward Euler steps |
|
| 48 |
-
|
| 49 |
-
The saved run used CPU execution with PyTorch 2.14.0 and TorchVision 0.29.0.
|
| 50 |
-
The checkpoint contains `model`, `losses`, `base_channels`, `seed`, and
|
| 51 |
-
`epochs_completed`. It has five completed epochs; the script's default for a
|
| 52 |
-
new training run is twenty. Optimizer state is not included.
|
| 53 |
-
|
| 54 |
-
## Generate from the checkpoint
|
| 55 |
-
|
| 56 |
-
In Python or a notebook, with the repository root as the working directory:
|
| 57 |
-
|
| 58 |
-
```python
|
| 59 |
-
from pathlib import Path
|
| 60 |
-
import torch
|
| 61 |
-
from torchvision.utils import save_image
|
| 62 |
-
from lecture_2.flow_matching_unet_lecture import DEVICE, FlowUNet, sample_images
|
| 63 |
-
|
| 64 |
-
# Read the supplied weights and reconstruct the same U-Net.
|
| 65 |
-
checkpoint = torch.load(
|
| 66 |
-
"lecture_2/flow_unet_mnist.pt", map_location="cpu", weights_only=True,
|
| 67 |
-
)
|
| 68 |
-
model = FlowUNet(base_channels=checkpoint["base_channels"]).to(DEVICE)
|
| 69 |
-
model.load_state_dict(checkpoint["model"])
|
| 70 |
-
|
| 71 |
-
# Generate new images directly from Gaussian noise.
|
| 72 |
-
torch.manual_seed(8)
|
| 73 |
-
samples, trajectory = sample_images(model, num_samples=16, steps=100)
|
| 74 |
-
|
| 75 |
-
# Convert the generated values to display pixels and save the results.
|
| 76 |
-
output = Path("flow_matching_outputs")
|
| 77 |
-
output.mkdir(exist_ok=True)
|
| 78 |
-
save_image(((samples.cpu() + 1) / 2).clamp(0, 1),
|
| 79 |
-
output / "checkpoint_samples.png", nrow=4)
|
| 80 |
-
display_path = ((trajectory[:4] + 1) / 2).clamp(0, 1)
|
| 81 |
-
save_image(display_path.flatten(0, 1), output / "checkpoint_trajectory.png",
|
| 82 |
-
nrow=trajectory.shape[1])
|
| 83 |
-
```
|
| 84 |
-
|
| 85 |
-
Importing the module does not start training or download MNIST. The images are
|
| 86 |
-
generated entirely from the saved weights and freshly sampled Gaussian noise.
|
| 87 |
-
Clipping occurs only when preparing the PNGs; intermediate ODE states remain
|
| 88 |
-
unclipped.
|
| 89 |
-
|
| 90 |
-
## Selected generated examples
|
| 91 |
-
|
| 92 |
-
These 16 images were manually selected from 512 outputs of the five-epoch
|
| 93 |
-
checkpoint. They illustrate the clearest generated digits in that batch.
|
| 94 |
-
The sampling example above generates a fresh, unselected batch.
|
| 95 |
-
|
| 96 |
-

|
| 97 |
-
|
| 98 |
-
The following trajectories show the first four selected images at times
|
| 99 |
-
0, 0.25, 0.5, 0.75, and 1:
|
| 100 |
-
|
| 101 |
-

|
| 102 |
-
|
| 103 |
-
## Script sections
|
| 104 |
-
|
| 105 |
-
| Sections | Lecture material |
|
| 106 |
-
| --- | --- |
|
| 107 |
-
| 01–03 | Imports, configuration, and MNIST data loading |
|
| 108 |
-
| 04 | Noise, interpolation time, intermediate image, and target velocity |
|
| 109 |
-
| 05–07 | Convolution blocks, the U-Net, and its forward pass |
|
| 110 |
-
| 08 | Loss, backpropagation, and optimizer updates |
|
| 111 |
-
| 09 | Sampling by integrating the learned velocity |
|
| 112 |
-
| 10–13 | Complete training run, checkpoint saving, and image export |
|
| 113 |
-
|
| 114 |
-
Continue with [Lecture 3](../lecture_3/README.md) for flow matching, diffusion,
|
| 115 |
-
and guidance using ESM-2 residue embeddings.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lecture_2/flow_matching_unet_lecture.py
DELETED
|
@@ -1,175 +0,0 @@
|
|
| 1 |
-
"""CIS 6270, Lecture 2: unconditional MNIST generation with flow matching.
|
| 2 |
-
|
| 3 |
-
Install: python -m pip install torch torchvision
|
| 4 |
-
Run: python flow_matching_unet_lecture.py
|
| 5 |
-
Notation: x0 = prior noise, x1 = data, xt = state, ut = target, v_pred = prediction.
|
| 6 |
-
"""
|
| 7 |
-
|
| 8 |
-
# %% 01. Imports
|
| 9 |
-
from pathlib import Path # Dataset and output paths.
|
| 10 |
-
|
| 11 |
-
import torch # Tensors, gradients, and optimization.
|
| 12 |
-
import torch.nn as nn # Layers and model classes.
|
| 13 |
-
import torch.nn.functional as F # Resize feature maps in the decoder.
|
| 14 |
-
from torch.utils.data import DataLoader # Shuffle and batch real images.
|
| 15 |
-
from torchvision import datasets
|
| 16 |
-
from torchvision.transforms import v2 # Convert and normalize image pixels.
|
| 17 |
-
from torchvision.utils import save_image # Export tensors as PNG grids.
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
# %% 02. Configuration
|
| 21 |
-
BATCH_SIZE = 128 # Images per training batch.
|
| 22 |
-
EPOCHS = 20 # Passes through the training set.
|
| 23 |
-
LEARNING_RATE = 2e-4 # Optimizer step size.
|
| 24 |
-
BASE_CHANNELS = 32 # U-Net widths: 32, 64, 128.
|
| 25 |
-
SAMPLE_STEPS = 100 # Euler steps from t=0 to t=1.
|
| 26 |
-
NUM_SAMPLES = 16 # Generate a 4-by-4 image grid.
|
| 27 |
-
SEED = 7 # Seed for initialization and training.
|
| 28 |
-
DATA_DIR = Path("data") # MNIST download location.
|
| 29 |
-
OUTPUT_DIR = Path("flow_matching_outputs") # Checkpoint and generated image folder.
|
| 30 |
-
|
| 31 |
-
DEVICE = torch.device(
|
| 32 |
-
"cuda" if torch.cuda.is_available() # NVIDIA GPU.
|
| 33 |
-
else "mps" if torch.backends.mps.is_available() # Apple GPU.
|
| 34 |
-
else "cpu" # CPU fallback.
|
| 35 |
-
)
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
# %% 03. Load real images
|
| 39 |
-
def make_loader():
|
| 40 |
-
transform = v2.Compose([
|
| 41 |
-
v2.ToImage(), # Channel-first image: [1, 28, 28].
|
| 42 |
-
v2.ToDtype(torch.float32, scale=True), # Integer pixels 0-255 -> floats 0-1.
|
| 43 |
-
v2.Normalize(mean=(0.5,), std=(0.5,)), # Real data pixels: [0, 1] -> [-1, 1].
|
| 44 |
-
])
|
| 45 |
-
dataset = datasets.MNIST(
|
| 46 |
-
root=DATA_DIR, train=True, download=True, transform=transform, # Use the training split.
|
| 47 |
-
)
|
| 48 |
-
return DataLoader(
|
| 49 |
-
dataset, batch_size=BATCH_SIZE, shuffle=True, # Batch shape: [B, 1, 28, 28].
|
| 50 |
-
num_workers=0, pin_memory=(DEVICE.type == "cuda"), # Load in the main process.
|
| 51 |
-
)
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
# %% 04. Sample the conditional path
|
| 55 |
-
def sample_conditional_path(x1): # x1 contains normalized real images.
|
| 56 |
-
x0 = torch.randn_like(x1) # Independent Gaussian prior; same shape as x1.
|
| 57 |
-
t = torch.rand(x1.shape[0], device=x1.device) # One random time per image; [B].
|
| 58 |
-
t_image = t[:, None, None, None] # [B, 1, 1, 1]; share time across pixels.
|
| 59 |
-
xt = (1.0 - t_image) * x0 + t_image * x1 # Noise at t=0; real image at t=1.
|
| 60 |
-
ut = x1 - x0 # Derivative of the straight interpolation.
|
| 61 |
-
return xt, t, ut # Network input, time, and target velocity.
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
# %% 05. Define a simple convolution block
|
| 65 |
-
def conv_block(in_channels, out_channels):
|
| 66 |
-
return nn.Sequential(
|
| 67 |
-
nn.Conv2d(in_channels, out_channels, 3, padding=1), nn.SiLU(), # Keep H and W.
|
| 68 |
-
nn.Conv2d(out_channels, out_channels, 3, padding=1), nn.SiLU(), # Refine features.
|
| 69 |
-
)
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
# %% 06. Define the small U-Net
|
| 73 |
-
class FlowUNet(nn.Module):
|
| 74 |
-
def __init__(self, base_channels=BASE_CHANNELS):
|
| 75 |
-
super().__init__()
|
| 76 |
-
c = base_channels # Base width; c=32 by default.
|
| 77 |
-
self.encoder1 = conv_block(2, c) # Image + time -> c channels.
|
| 78 |
-
self.encoder2 = conv_block(c, 2 * c) # Encoder: c -> 2c.
|
| 79 |
-
self.middle = conv_block(2 * c, 4 * c) # Bottleneck: 2c -> 4c.
|
| 80 |
-
self.decoder2 = conv_block(6 * c, 2 * c) # Upsampled 4c + skip 2c -> 2c.
|
| 81 |
-
self.decoder1 = conv_block(3 * c, c) # Upsampled 2c + skip c -> c.
|
| 82 |
-
self.output = nn.Conv2d(c, 1, 1) # One signed velocity per pixel.
|
| 83 |
-
self.pool = nn.MaxPool2d(2) # Halve the image height and width.
|
| 84 |
-
|
| 85 |
-
# %% 07. Compute the velocity field
|
| 86 |
-
def forward(self, xt, t):
|
| 87 |
-
t_image = t[:, None, None, None].expand_as(xt) # Constant time channel.
|
| 88 |
-
x = torch.cat([xt, t_image], dim=1) # [B, 2, 28, 28].
|
| 89 |
-
skip1 = self.encoder1(x) # Keep full-resolution features.
|
| 90 |
-
skip2 = self.encoder2(self.pool(skip1)) # 28x28 -> 14x14.
|
| 91 |
-
x = self.middle(self.pool(skip2)) # 14x14 -> 7x7.
|
| 92 |
-
x = F.interpolate(x, size=skip2.shape[-2:], mode="nearest") # 7x7 -> 14x14.
|
| 93 |
-
x = self.decoder2(torch.cat([x, skip2], dim=1)) # Restore encoder detail.
|
| 94 |
-
x = F.interpolate(x, size=skip1.shape[-2:], mode="nearest") # 14x14 -> 28x28.
|
| 95 |
-
x = self.decoder1(torch.cat([x, skip1], dim=1)) # Restore fine detail.
|
| 96 |
-
v_pred = self.output(x) # Predict v_theta(xt, t).
|
| 97 |
-
return v_pred # [B, 1, 28, 28], matching xt.
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
# %% 08. Train for one epoch
|
| 101 |
-
def train_one_epoch(model, loader, optimizer):
|
| 102 |
-
model.train() # Select training mode.
|
| 103 |
-
total_loss, num_images = 0.0, 0 # Accumulate an image-weighted epoch loss.
|
| 104 |
-
for x1, _ in loader: # Ignore digit labels: unconditional generation.
|
| 105 |
-
x1 = x1.to(DEVICE) # Move real images to the model device.
|
| 106 |
-
xt, t, ut = sample_conditional_path(x1) # Fresh noise and times for this batch.
|
| 107 |
-
v_pred = model(xt, t) # The model receives only xt and t.
|
| 108 |
-
squared_error = (v_pred - ut).square() # Velocity error at every pixel.
|
| 109 |
-
loss = squared_error.flatten(1).sum(1).mean() # Sum pixels, average images.
|
| 110 |
-
optimizer.zero_grad(set_to_none=True) # Clear old gradients.
|
| 111 |
-
loss.backward() # Compute gradients with respect to weights.
|
| 112 |
-
optimizer.step() # Update the U-Net weights.
|
| 113 |
-
total_loss += loss.item() * x1.shape[0] # Weight by the actual batch size.
|
| 114 |
-
num_images += x1.shape[0] # Include the smaller final batch.
|
| 115 |
-
return total_loss / num_images # Average training loss per image.
|
| 116 |
-
|
| 117 |
-
# Save snapshots every quarter of the default 100-step run; keep ODE states unclipped.
|
| 118 |
-
# %% 09. Generate images with Euler integration
|
| 119 |
-
@torch.no_grad() # Sampling needs no gradient tracking.
|
| 120 |
-
def sample_images(model, num_samples=NUM_SAMPLES, steps=SAMPLE_STEPS):
|
| 121 |
-
if num_samples < 1 or steps < 1:
|
| 122 |
-
raise ValueError("num_samples and steps must be positive")
|
| 123 |
-
model.eval() # Select evaluation mode.
|
| 124 |
-
device = next(model.parameters()).device # Use the model device.
|
| 125 |
-
xt = torch.randn(num_samples, 1, 28, 28, device=device) # Initial x0.
|
| 126 |
-
dt = 1.0 / steps # Positive time increment.
|
| 127 |
-
snapshots = [xt.cpu().clone()] # Keep the initial noise for plotting.
|
| 128 |
-
for step in range(steps): # Integrate forward in time.
|
| 129 |
-
t = torch.full((num_samples,), step * dt, device=device) # Shared time grid.
|
| 130 |
-
v_pred = model(xt, t) # Reevaluate velocity at the current state.
|
| 131 |
-
xt = xt + dt * v_pred # Euler: state += time increment * velocity.
|
| 132 |
-
if (step + 1) % max(steps // 4, 1) == 0 or step + 1 == steps:
|
| 133 |
-
snapshots.append(xt.cpu().clone()) # Save intermediate and final states.
|
| 134 |
-
return xt, torch.stack(snapshots, dim=1) # Raw images; [B, snapshots, 1, 28, 28].
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
# %% 10. Set up the complete run
|
| 138 |
-
def main():
|
| 139 |
-
torch.manual_seed(SEED) # Seed training randomness.
|
| 140 |
-
OUTPUT_DIR.mkdir(parents=True, exist_ok=True) # Create the output folder.
|
| 141 |
-
loader = make_loader() # Download, normalize, and batch MNIST.
|
| 142 |
-
model = FlowUNet().to(DEVICE) # Create the velocity network.
|
| 143 |
-
optimizer = torch.optim.AdamW(
|
| 144 |
-
model.parameters(), lr=LEARNING_RATE, weight_decay=0.0, # Optimize the flow loss.
|
| 145 |
-
)
|
| 146 |
-
num_parameters = sum(p.numel() for p in model.parameters()) # Count weights and biases.
|
| 147 |
-
print(f"device={DEVICE} parameters={num_parameters:,}")
|
| 148 |
-
|
| 149 |
-
# %% 11. Train and save the learned parameters
|
| 150 |
-
losses = [] # Record the training loss after each epoch.
|
| 151 |
-
for epoch in range(1, EPOCHS + 1): # Complete EPOCHS passes through the data.
|
| 152 |
-
loss = train_one_epoch(model, loader, optimizer) # Run the training loop.
|
| 153 |
-
losses.append(loss) # Keep the loss history.
|
| 154 |
-
print(f"epoch={epoch:02d} squared_norm_loss={loss:.3f}")
|
| 155 |
-
torch.save({
|
| 156 |
-
"model": model.state_dict(), "losses": losses, # Weights and training curve.
|
| 157 |
-
"base_channels": BASE_CHANNELS, # Width needed to reconstruct the model.
|
| 158 |
-
"seed": SEED, # Record the training seed.
|
| 159 |
-
}, OUTPUT_DIR / "flow_unet_mnist.pt")
|
| 160 |
-
|
| 161 |
-
# %% 12. Sample and save images
|
| 162 |
-
torch.manual_seed(SEED + 1) # Fix the starting noise for generation.
|
| 163 |
-
samples, trajectory = sample_images(model) # Integrate the learned ODE.
|
| 164 |
-
display_samples = ((samples.cpu() + 1.0) / 2.0).clamp(0.0, 1.0) # Clip for display only.
|
| 165 |
-
save_image(display_samples, OUTPUT_DIR / "samples.png", nrow=4) # Final images.
|
| 166 |
-
display_path = ((trajectory[:4] + 1.0) / 2.0).clamp(0.0, 1.0) # First four sample paths.
|
| 167 |
-
save_image(
|
| 168 |
-
display_path.flatten(0, 1), OUTPUT_DIR / "trajectory.png", # One row per sample.
|
| 169 |
-
nrow=trajectory.shape[1], # Time increases across columns.
|
| 170 |
-
)
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
# %% 13. Run the script
|
| 174 |
-
if __name__ == "__main__": # Execute when launched directly.
|
| 175 |
-
main() # Load data, train, sample, and save.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lecture_2/flow_unet_mnist.pt
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:20373a7d33489c0b596a4bd2f54750795570eda7dd0bef1f064b51a1367bd2d7
|
| 3 |
-
size 1893377
|
|
|
|
|
|
|
|
|
|
|
|
lecture_2/mnist_selected_examples.png
DELETED
|
Binary file (45 kB)
|
|
|
lecture_2/mnist_selected_trajectories.png
DELETED
|
Binary file (85.4 kB)
|
|
|