Cách debug code khi code vẫn chạy ngon và không biết sai chỗ nào

Nhiều khi chúng ta phải debug code cho đồng đội của mình, nhưng code bản mình viết lại hơi khó hiểu. Đã thế code lại vẫn chạy ngon, chỉ là kết quả ra hơi lạ nên không biết sai chỗ nào. Trong bài viết này mình sẽ nói 1 mánh dùng prompt để debug mà không phải đọc code quá nhiều.

Giả sử chúng ta đang debug code về VAE để đo lường tham số. Code đúng thì nó sẽ như thế này

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

class VAE(nn.Module):
    def __init__(self, input_dim, hidden_dim, latent_dim):
        super(VAE, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc21 = nn.Linear(hidden_dim, latent_dim)
        self.fc22 = nn.Linear(hidden_dim, latent_dim)
        self.fc3 = nn.Linear(latent_dim, hidden_dim)
        self.fc4 = nn.Linear(hidden_dim, input_dim)

    def encode(self, x):
        h1 = torch.relu(self.fc1(x))
        return self.fc21(h1), self.fc22(h1)

    def reparameterize(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def decode(self, z):
        h3 = torch.relu(self.fc3(z))
        return torch.sigmoid(self.fc4(h3))

    def forward(self, x):
        mu, logvar = self.encode(x.view(-1, input_dim))
        z = self.reparameterize(mu, logvar)
        return self.decode(z), mu, logvar

def loss_function(recon_x, x, mu, logvar):
    BCE = nn.functional.binary_cross_entropy(recon_x, x.view(-1, input_dim), reduction='sum')
    KLD = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
    return BCE + KLD

input_dim = 784  # Ví d?, hình 28x28
hidden_dim = 400
latent_dim = 20
batch_size = 64
epochs = 10
learning_rate = 1e-3

vae = VAE(input_dim, hidden_dim, latent_dim)
optimizer = optim.Adam(vae.parameters(), lr=learning_rate)

# Dữ liệu ví dụ
data = torch.randn(1000, input_dim)
dataset = TensorDataset(data, data)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

for epoch in range(epochs):
    for batch_idx, (data, _) in enumerate(dataloader):
        recon_batch, mu, logvar = vae(data)
        loss = loss_function(recon_batch, data, mu, logvar)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

print("Hoàn thành training.")

Những một bé lại code nhầm hàm loss thành MSE (đây là ví dụ nên chúng ta không bàn về chuyện dùng loss gì là đúng nha), nên nó thành ra thế này:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

class VAE(nn.Module):
    def __init__(self, input_dim, hidden_dim, latent_dim):
        super(VAE, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc21 = nn.Linear(hidden_dim, latent_dim)
        self.fc22 = nn.Linear(hidden_dim, latent_dim)
        self.fc3 = nn.Linear(latent_dim, hidden_dim)
        self.fc4 = nn.Linear(hidden_dim, input_dim)

    def encode(self, x):
        h1 = torch.relu(self.fc1(x))
        return self.fc21(h1), self.fc22(h1)

    def reparameterize(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def decode(self, z):
        h3 = torch.relu(self.fc3(z))
        return torch.sigmoid(self.fc4(h3))

    def forward(self, x):
        mu, logvar = self.encode(x.view(-1, input_dim))
        z = self.reparameterize(mu, logvar)
        return self.decode(z), mu, logvar

def loss_function_mse(recon_x, x):
    MSE = nn.functional.mse_loss(recon_x, x.view(-1, input_dim), reduction='sum')
    return MSE

input_dim = 784  # Ví dụ, hình ảnh 28x28
hidden_dim = 400
latent_dim = 20
batch_size = 64
epochs = 10
learning_rate = 1e-3

vae = VAE(input_dim, hidden_dim, latent_dim)
optimizer = optim.Adam(vae.parameters(), lr=learning_rate)

# Dữ liệu ví dụ
data = torch.randn(1000, input_dim)
dataset = TensorDataset(data, data)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

for epoch in range(epochs):
    for batch_idx, (data, _) in enumerate(dataloader):
        recon_batch, mu, logvar = vae(data)
        loss = loss_function_mse(recon_batch, data)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

print("Hoàn thành training")

Khi này, thay vì đọc code người khác viết, mình sẽ dùng prompt write algorithm based on this code và sau đó thì dán phần code mà bé kia viết vào. Thế là ChatGPT trả về kết quả như vậy.

Algorithm for the Variational Autoencoder (VAE) Implementation
Initialize Model Parameters:
Define the dimensions for input (input_dim), hidden layers (hidden_dim), and latent space (latent_dim).
Set training hyperparameters: batch size, learning rate, and number of epochs.
Define Model Architecture:
Create a class VAE inheriting from nn.Module.
Define the encoder with two linear layers: one for the mean (mu) and one for the log variance (logvar) of the latent space.
Define the reparameterization method to sample latent variables z from a normal distribution using the formula:
z = \mu + \epsilon \cdot {std}, \epsilon \sim \mathcal{N}(0, I)
Define the decoder with two linear layers to reconstruct the input.
Implement Forward Pass:
Pass the input through the encoder to obtain mu and logvar.
Use the reparameterization trick to sample z .
Pass z through the decoder to reconstruct the input.
Define Loss Function:
Use Mean Squared Error (MSE) loss to compute reconstruction loss between the input and its reconstruction:
{MSE} = {sum}\left(({reconstructed_x} - {x})^2\right)
Prepare Data:
Simulate or load a dataset with features of size input_dim.
Use a data loader to divide the dataset into batches of size batch_size.
Training Loop:
For each epoch: Iterate through batches in the dataset.
Pass the batch data through the VAE model to compute the reconstructed batch, mu, and logvar.
Calculate the loss using the MSE loss function.
Perform backpropagation to update the model weights using the Adam optimizer.
Print the loss after each epoch.
End Training:
Output a message indicating the completion of training.
This algorithm provides a step-by-step overview of how the VAE model is defined, trained, and optimized for reconstructing input data.

thì cái này sẽ đơn giản hơn. Và mình có thể nhanh chóng nhìn ra vấn đề nằm ở chỗ loss function bị nhầm sang MSE. Nếu bạn đang viết một bài báo khoa học thì bạn có thể dùng prompt “use latex algorithm environment” để nó cho mình code latex. Code này có thể sửa đổi được. Sau khi sửa xong, bạn có thể lưu lại và tiếp tục dùng prompt để nhờ ChatGPT sửa.


Discover more from Science Comics

Subscribe to get the latest posts sent to your email.

Leave a Reply

error: Content is protected !!