This document provides a detailed explanation of the main_2d.py script. The script's primary purpose is to train a Convolutional Variational Autoencoder (CVAE) to reconstruct a 2D surface from a sparse and noisy set of observations.
The dataset is synthetically generated. Each data sample represents a 2D surface.
- Purpose: To create a smooth 2D surface.
- Method: The surface is defined by the following function:
y(x1, x2) = A * s(2π(f1*x1 + f2*x2) + φ)(x1, x2)are coordinates on a 2D grid of sizeN x N, wherex1andx2range from 0.0 to 1.0.sis either asinorcosfunction, chosen randomly.A(amplitude) is a random value between 0.8 and 1.2.f1andf2(frequencies) are random integers chosen from {1, 2, 3}.φ(phase) is a random value between 0 and 2π.
- Output: A tuple containing the
(x1, x2)grid and the correspondingyvalues of the surface.
- Purpose: To simulate a real-world scenario where we only have a limited number of noisy measurements of the surface.
- Method:
- Select Observation Points:
Mrandom points are chosen from theN x Ngrid. - Add Noise: Gaussian noise with a mean of 0 and a standard deviation of
sigmais added to theyvalues at theseMobservation points. - Create Mask: A binary mask of size
N x Nis created. It has a value of 1 at theMobserved locations and 0 elsewhere. - Zero-out Unobserved Points: The
yvalues at the unobserved locations are set to 0.
- Select Observation Points:
- Output:
y_obs_masked: Theyvalues with noise added at observed points and zeros elsewhere.mask: The binary mask indicating the observed points.obs_idx: The indices of theMobserved points.
- Purpose: To create a PyTorch
Datasetthat can be used with aDataLoader. __getitem__method: For each sample, this method:- Generates a surface using
sample_surface. - Creates a gappy sample from the surface using
gappy_sample. - Concatenates the
y_obs_maskedand themaskto form the input tensor of shape(2, N, N).
- Generates a surface using
- Output of
__getitem__:inp: The input tensor for the model, of shape(2, N, N).y: The ground truth (original, complete) surface, of shape(N, N).mask: The observation mask, of shape(N, N).
The script uses a Convolutional Variational Autoencoder (CVAE) to learn a compressed representation of the surface and then reconstruct it.
- Input: A tensor of shape
(B, 2, N, N), whereBis the batch size, and the 2 channels arey_obs_maskedandmask. - Architecture:
- A series of
depth(default 3) convolutional layers (nn.Conv2d). - Each convolutional layer is followed by a ReLU activation function.
- The number of filters in the convolutional layers is defined by the
widthlist (default[32, 64, 128]). - After the convolutional layers, the output is flattened.
- A series of
- Output: The flattened feature vector is passed through two separate fully connected layers (
nn.Linear) to produce:mu: The mean of the latent distribution.logvar: The log variance of the latent distribution.
- Purpose: To allow gradients to flow back through the sampling process.
- Method: The latent vector
zis sampled from the learned distribution using the reparameterization trick:z = mu + eps * std, wherestd = exp(0.5 * logvar)andepsis a random sample from a standard normal distribution.
- Input: The latent vector
zof sizelatent_dim(default 32). - Architecture:
- A fully connected layer to project the latent vector back to the flattened size of the last encoder layer.
- An
nn.Unflattenlayer to reshape the vector into a 4D tensor. - A series of
depth(default 3) transposed convolutional layers (nn.ConvTranspose2d) to upsample the feature maps back to the originalN x Nsize. - Each transposed convolutional layer is followed by a ReLU activation function (except the last one).
- Output: A reconstructed surface
y_hatof shape(B, 1, N, N).
The total loss is a combination of three components:
- Full Reconstruction Loss (
loss_full): The Mean Squared Error (MSE) between the reconstructed surfacey_hatand the ground truth surfacey. This encourages the model to reconstruct the entire surface accurately. - Observed Reconstruction Loss (
loss_obs): The MSE between the reconstructed values at the observed locations (y_hat * mask) and the ground truth values at those locations (y * mask). This puts extra emphasis on getting the observed points right. - Kullback-Leibler (KL) Divergence Loss (
loss_kl): This is a regularization term that forces the learned latent distribution to be close to a standard normal distribution. It is calculated as:loss_kl = -0.5 * sum(1 + logvar - mu^2 - exp(logvar))
The final loss is a weighted sum of these three components:
loss = loss_full + obs_lambda * loss_obs + kl_lambda * loss_kl
obs_lambda(default 1.0) andkl_lambda(default 1e-6) are hyperparameters that control the weight of the observed reconstruction loss and the KL divergence loss, respectively.
- The script uses the Adam optimizer (
torch.optim.Adam) to update the model's weights.
- The training process iterates for a specified number of
epochs. - In each epoch, the script iterates through the training data, calculates the loss, and updates the model's parameters using backpropagation.
- After each epoch, the model is evaluated on a validation set to monitor its performance and prevent overfitting. The best validation loss is tracked.
- Purpose: To demonstrate the model's performance on a single example.
- Method:
- Generates a new surface and a gappy sample.
- Passes the gappy sample through the trained model to get a reconstruction.
- Calculates the Mean Squared Error (MSE) and Peak Signal-to-Noise Ratio (PSNR) between the reconstructed surface and the ground truth.
- Calls
results.plot_reconstruction_2dto generate and save a plot showing the ground truth, the observed data, and the reconstructed surface.
- Purpose: To analyze how the model's performance changes with the number of observations (
M). - Method:
- It trains a separate model for each value of
Min a predefined list (M_values). - For each trained model, it calls
demo_onceto get the PSNR. - It then calls
results.plot_observation_sweepto create and save a plot of PSNR vs.M.
- It trains a separate model for each value of
- The
mainfunction is the entry point of the script. - It sets up logging using the
logurulibrary. - It calls
observation_sweep_analysisto run the main experiment. - The hyperparameters for the training and the experiment are defined within the
mainandobservation_sweep_analysisfunctions.