Files
machine_learning/Midterm 2026_solution.ipynb
T
2026-08-31 19:49:16 +00:00

221 KiB

FILL IN YOUR NAME HERE: [LASTNAME] [FIRSTNAME]

Machine Learning Midterm Exam

Spring 2026 - 30 March 2026


Exam Rules and Conduct

  • You must use Colab with all AI assistance turned off

Allowed

  • Built-in IDE documentation
  • Standard autocomplete (e.g., showing available functions when typing torch.nn)
  • Use of help() and dir() functions
  • Locally saved files (including course materials, assignments, PDFs, summaries, books, etc.)
  • PDF editor/viewer
  • A locally installed dictionary app (English language with no translations)

Not Allowed

  • No AI coding assistance: no chatbots/LLMs, code generation, or explanation tools
  • No external help: no internet, communication apps, translation apps, or additional browser tabs

Timing

  • You have 5 minutes before the start to download the file and 5 minutes after the end to upload it
  • Late submissions will not be accepted without a documented reason

Answer Format

  • Answer directly below each question
    • Use Markdown cells for text (in English)
    • Use code cells for programming
  • 0 points for incorrect or incomplete answers
    • Partial credit only if the core idea is correct and instructions are followed
    • Ignoring instructions = 0 points, regardless of effort
  • Be clear and concise—extra detail doesn’t earn more points

Coding Guidelines

  • Use only packages covered in the course and assignments
  • Follow dataset instructions. Using a different dataset than instructed will result in 0 points for that question
  • Code that does not run = 50% deduction
  • Code quality (correctness, clarity, efficiency) counts

Academic Integrity

Violations (e.g., using AI tools or outside help) will result in:

  • A failing grade (1.0)
  • A disciplinary report to the Faculty of Science and Medicine

Good luck! 🍀

In [ ]:
points = 64

1. Theory (20 points)

Complete the quiz provided on Moodle.

For each topic, identify which statements are TRUE and which are FALSE . Each question may have 1, 2, 3, or 4 correct answers.

  • 4 correct answers: 2 points
  • 3 correct answers: 1 point
  • 2 or fewer correct answers: 0 points

2. Hands-On (20 points)

You may use Python as a calculator but all calculations must be shown in \LaTeX

2.1 (2pts) Which pair of vectors are orthogonal/perpendicular?

Let:

$ \mathbf{a}= \begin{pmatrix} 5\ 2 \end{pmatrix}, \quad \mathbf{b}= \begin{pmatrix} 4\ -10 \end{pmatrix}, \quad \mathbf{c}= \begin{pmatrix} 4\ -12 \end{pmatrix}, \quad \mathbf{d}= \begin{pmatrix} 1\ 3 \end{pmatrix} $

2.1.1 (1pt) Perpendicular vectors: \mathbf{a} & \mathbf{b}

2.1.2 (1pt) Calculation with $\LaTeX$:

$ \begin{pmatrix} 5\ 2 \end{pmatrix} \cdot \begin{pmatrix} 4\ -10 \end{pmatrix} = 20 - 20 = 0 $

2.2 (5pts) Give an example of two 2D vectors whose cosine similarity is -1.

  • Each vector should contain only the values 1 and -1.
  • Then, show your work by computing the dot product, the magnitude of each vector, and the cosine similarity to verify that the result is -1.

2.2.1 (1pt) Two vectors:

$ \mathbf{u}= \begin{pmatrix} 1\ 1 \end{pmatrix}, \quad \mathbf{v}= \begin{pmatrix} -1\ -1 \end{pmatrix} $

2.2.2 (4pt) Cosine Similarity Calculation with \LaTeX:

$ \begin{aligned} \mathbf{u} \cdot \mathbf{v} &= \begin{pmatrix} 1 \ 1 \end{pmatrix} \cdot \begin{pmatrix} -1 \ -1 \end{pmatrix} = 1 \cdot -1 + 1 \cdot -1 = -1 -1 = -2 \end{aligned} $

$\begin{aligned} \parallel \mathbf{u} \parallel &= \sqrt{1^2 + 1^2} = \sqrt{2} \ \parallel \mathbf{v} \parallel &= \sqrt{(-1)^2 + (-1)^2} = \sqrt{2} \end{aligned} $

$\cos(\theta) = \frac{-2}{\sqrt{2} \cdot \sqrt{2}} = \frac{-2}{2} = -1 $

2.3 (6pts) Compute one step of gradient descent.

Let: f(x,y)=2x^2+y^2

Suppose we start at (x_0, y_0) = (2, 1) with learning rate \eta = 0.1

2.3.1. (1pt) Determine the partial derivatives

Partial derivatives: \frac{\partial f}{\partial x} = 4x, \quad \frac{\partial f}{\partial y} = 2y

2.3.2 (1pt) Write down the gradient at (2, 1)

So, $\nabla f(2,1) = \begin{pmatrix} 4 \cdot 2 \ 2 \cdot 1 \end{pmatrix} = \begin{pmatrix} 8 \ 2 \end{pmatrix} $

2.3.3 (1pt) Compute one step of gradient descent

(x_1,y_1) = (2,1) - 0.1 \cdot (8,2) = (1.2,0.8)

2.3.4 (2pts) Compute the function value before and after the step (plug the original and first step (x,y) into the function)

f(2,1) = 2(2)^2 + (1)^2 = 8 + 1 = 9

f(1.2,0.8) = 2(1.2)^2 + (0.8)^2 = 2.88 + (0.64) = 3.52

2.3.5 (1pt) Interpret the change in function values by reporting the initial value, the new value after one gradient descent step, and the direction of the change

The function value decreases from 9 to 3.52, meaning the step moved downhill

2.4 (6pts) Activate this single-layer Perceptron with a LeakyReLU activation function.

You are working with a single-layer perceptron that has:

  • 3 input units (features)
  • 1 output unit (neuron)

These are your parameters:

  • x=[2.0, -2.0, 1.0]
  • w=[1.0, -1.0, 1.0]
  • b=-2
  • \alpha = 0.01

2.4.1 (2pts) Write the formula for the weighted sum of inputs.

z = \sum_{i=1}^n w_ix_i + b

2.4.2 (2pts) Show your calculations and give the final answer rounded to 1 decimal point.

$ \begin{aligned} z &= (12) + (-1-2) + (1*1) - 2 \ z &= 2 + 2 + 1 -2 \ z &= 3.0 \end{aligned}$

2.4.3 (2pts) Apply the LeakyReLU activation function to determine the final output of the perceptron.

Expected answer format \sigma(x.x) = x.x

\sigma(3.0) = 3.0

3. Coding (24 points)

In [1]:
### DO NOT EDIT THIS CELL ###

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

import numpy as np
import random
import matplotlib.pyplot as plt
from tqdm import tqdm


# Set random seed
def set_seed(seed):
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True)

set_seed(0)

g = torch.Generator().manual_seed(42)

device = torch.device("cpu")

#############################

3.1 (6pts) Debug the following Neural Network initialization.

The following code defines and trains a simple neural network with 3 linear layers, an __init__ and forward method. However, it contains six syntax errors that cause the code to crash during training. There are no structural problems so please do not edit the general structure.

Your task is to:

  • Identify all 6 mistakes
  • Fix each one and briefly explain why the change was necessary as a code comment

Once the script is error-free, the script will print ✅ Success!.

In [22]:
class NeuralNetworkBroken(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(input_dim, hidden_dim), # 2) input_din -> input_dim, 3) add hidden_dim
            nn.Linear(hidden_dim, hidden_dim), # 1) add comma, 6) correct output dimension
            nn.Linear(hidden_dim, output_dim),
        )

    def forward(self, x):
        return self.model(x) # 5) change from sigmoid -> x

device = device
model = NeuralNetworkBroken(input_dim=10, hidden_dim=8, output_dim=2)
model.to(device) # 4) move to device
Out [22]:
NeuralNetworkBroken(
  (model): Sequential(
    (0): Linear(in_features=10, out_features=8, bias=True)
    (1): Linear(in_features=8, out_features=8, bias=True)
    (2): Linear(in_features=8, out_features=2, bias=True)
  )
)
In [23]:
### DO NOT EDIT THIS CELL ###

X = torch.randn(32, 10)
y = torch.randint(0, 2, (32,))

dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=32)

# Model setup
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())

# Minimal training loop to trigger crash
model.train()

for inputs, targets in dataloader:
    outputs = model(inputs)
    loss = loss_fn(outputs, targets)
    break

print('✅ Success!')

#############################
✅ Success!

3.2 (12pts) Implement an MLP for Random Data in PyTorch.

You are given training and validation datasets for a 10-class image classification problem. Each sample is a randomly generated grayscale image of shape 1x28x28 and a randomly assigned label in {0,1,...,9}.

In [ ]:
## DO NOT EDIT THIS CELL
# number of samples
n_train = 100
n_val = 100

# define random training images (28x28) and labels (between 0-9)
X_train = torch.randn(n_train, 1, 28, 28)
y_train = torch.randint(0, 10, (n_train,))

# define random validation images (28x28) and labels (between 0-9)
X_val = torch.randn(n_val, 1, 28, 28)
y_val = torch.randint(0, 10, (n_val,))

# create datasets
train_dataset = TensorDataset(X_train, y_train)
val_dataset = TensorDataset(X_train, y_train)

# create data loaders
train_loader = DataLoader(train_dataset, batch_size=10, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=10, shuffle=False)

3.2.1 (4 pts) Implement the following MLP in PyTorch:

  • Use a sequential model with:
    • Flatten
    • Linear(28x28 → 128), ReLU
    • Linear(128 → 64), ReLU
    • Linear(64 → 10)
  • Define the forward function
In [ ]:
class MLP(nn.Module):
  def __init__(self):
      super().__init__()

      self.model = nn.Sequential(
          nn.Flatten(),
          nn.Linear(28*28, 128),
          nn.ReLU(),
          nn.Linear(128, 64),
          nn.ReLU(),
          nn.Linear(64, 10)
      )

  def forward(self, x):
    return self.model(x)

3.2.2 (3pts) Instantiate the model, move it to the device, and print the model.

In [ ]:
model = MLP()
model.to(device)

print(model)
MLP(
  (model): Sequential(
    (0): Flatten(start_dim=1, end_dim=-1)
    (1): Linear(in_features=784, out_features=128, bias=True)
    (2): ReLU()
    (3): Linear(in_features=128, out_features=64, bias=True)
    (4): ReLU()
    (5): Linear(in_features=64, out_features=10, bias=True)
  )
)
In [ ]:
### GRADING TOOL ###
# paste printed output here
stu_model="""
CNNModel(
  (features): Sequential(
    (0): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU()
    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (4): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2))
    (5): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (6): ReLU()
    (7): Flatten(start_dim=1, end_dim=-1)
  )
  (classifier): Sequential(
    (0): LazyLinear(in_features=0, out_features=128, bias=True)
    (1): ReLU()
    (2): Dropout(p=0.5, inplace=False)
    (3): Linear(in_features=128, out_features=10, bias=True)
  )
)
"""

# reference to compare to
ref_model = """
MLP(
  (model): Sequential(
    (0): Flatten(start_dim=1, end_dim=-1)
    (1): Linear(in_features=784, out_features=128, bias=True)
    (2): ReLU()
    (3): Linear(in_features=128, out_features=64, bias=True)
    (4): ReLU()
    (5): Linear(in_features=64, out_features=10, bias=True)
  )
)
"""

def compare_model_strings(stu, ref):
    if ref.strip() == stu.strip():
        print('✅ Correct')
    else:
        print('❌ Incorrect')
        # Optional: show the first point of difference
        import difflib
        diff = difflib.unified_diff(
            ref.strip().splitlines(),
            stu.strip().splitlines(),
            fromfile='Reference',
            tofile='Student',
            lineterm=''
        )
        print("\n".join(diff))

# Run the comparison
compare_model_strings(stu_model, ref_model)

3.2.3 (4pts) Define the hyperparameters.

  • Use:
    • The cross entropy loss function
    • Adam optimizer with learning rate 0.001
    • 20 training epochs
In [ ]:
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
n_epochs = 20

3.2.4 (1pt) Train, plot, and evaluate the model.

In [ ]:
### DO NOT EDIT THIS CELL ###

def train_epoch(model, train_dataloader, optimizer, loss_fn):
    losses = []
    correct_predictions = 0
    # Iterate mini batches over training dataset
    for features, labels in tqdm(train_dataloader):
        features = features.to(device)
        labels = labels.to(device)
        # Run predictions
        output = model(features)
        # Set gradients to zero
        optimizer.zero_grad()
        # Compute loss
        loss = loss_fn(output, labels)
        # Backpropagate (compute gradients)
        loss.backward()
        # Make an optimization step (update parameters)
        optimizer.step()
        # Log metrics
        losses.append(loss.item())
        predicted_labels = output.argmax(dim=1)
        correct_predictions += (predicted_labels == labels).sum().item()
    accuracy = 100.0 * correct_predictions / len(train_dataloader.dataset)
    # Return loss values for each iteration and accuracy
    mean_loss = np.array(losses).mean()
    return mean_loss, accuracy

def evaluate(model, dataloader, loss_fn):
    losses = []
    correct_predictions = 0
    with torch.no_grad():
        for features, labels in dataloader:
            features = features.to(device)
            labels = labels.to(device)
            # Run predictions
            output = model(features)
            # Compute loss
            loss = loss_fn(output, labels)
            # Save metrics
            predicted_labels = output.argmax(dim=1)
            correct_predictions += (predicted_labels == labels).sum().item()
            losses.append(loss.item())
    mean_loss = np.array(losses).mean()
    accuracy = 100.0 * correct_predictions / len(dataloader.dataset)
    # Return mean loss and accuracy
    return mean_loss, accuracy

def train(model, train_dataloader, val_dataloader, optimizer, n_epochs, loss_fn):
    # We will monitor loss functions as the training progresses
    train_losses = []
    val_losses = []
    train_accuracies = []
    val_accuracies = []

    for epoch in range(n_epochs):
        model.train()
        train_loss, train_accuracy = train_epoch(model, train_dataloader, optimizer, loss_fn)
        model.eval()
        val_loss, val_accuracy = evaluate(model, val_dataloader, loss_fn)
        train_losses.append(train_loss)
        val_losses.append(val_loss)
        train_accuracies.append(train_accuracy)
        val_accuracies.append(val_accuracy)
        print('Epoch {}/{}: train_loss: {:.4f}, train_accuracy: {:.4f}, val_loss: {:.4f}, val_accuracy: {:.4f}'.format(epoch+1, n_epochs,
                                                                                                      train_losses[-1],
                                                                                                      train_accuracies[-1],
                                                                                                      val_losses[-1],
                                                                                                      val_accuracies[-1]))
    return train_losses, val_losses, train_accuracies, val_accuracies

def plot(train_losses, val_losses, train_accuracies, val_accuracies, title):
    plt.figure()
    plt.plot(np.arange(len(train_losses)), train_losses)
    plt.plot(np.arange(len(val_losses)), val_losses)
    plt.legend(['train_loss', 'val_loss'])
    plt.xlabel('epoch')
    plt.xticks(np.arange(len(train_losses)), np.arange(1, len(train_losses)+1))
    plt.ylabel('loss value')
    plt.title('{}: Train/val loss'.format(title));

    plt.figure()
    plt.plot(np.arange(len(train_accuracies)), train_accuracies)
    plt.plot(np.arange(len(val_accuracies)), val_accuracies)
    plt.legend(['train_acc', 'val_acc'])
    plt.xlabel('epoch')
    plt.xticks(np.arange(len(train_losses)), np.arange(1, len(train_losses)+1))
    plt.ylabel('accuracy')
    plt.title('{}: Train/val accuracy'.format(title));

In [ ]:
# train model
train_losses, val_losses, train_acc, val_acc = train(model, train_loader, val_loader, optimizer, n_epochs, criterion)
100%|██████████| 10/10 [00:00<00:00, 48.54it/s]
Epoch 1/20: train_loss: 2.3117, train_accuracy: 10.0000, val_loss: 2.0470, val_accuracy: 55.0000
100%|██████████| 10/10 [00:00<00:00, 361.37it/s]
Epoch 2/20: train_loss: 1.9682, train_accuracy: 61.0000, val_loss: 1.7530, val_accuracy: 83.0000
100%|██████████| 10/10 [00:00<00:00, 527.82it/s]
Epoch 3/20: train_loss: 1.6262, train_accuracy: 83.0000, val_loss: 1.3396, val_accuracy: 92.0000
100%|██████████| 10/10 [00:00<00:00, 481.36it/s]
Epoch 4/20: train_loss: 1.1762, train_accuracy: 95.0000, val_loss: 0.8571, val_accuracy: 99.0000
100%|██████████| 10/10 [00:00<00:00, 560.92it/s]
Epoch 5/20: train_loss: 0.7054, train_accuracy: 99.0000, val_loss: 0.4589, val_accuracy: 99.0000
100%|██████████| 10/10 [00:00<00:00, 547.37it/s]
Epoch 6/20: train_loss: 0.3450, train_accuracy: 100.0000, val_loss: 0.2015, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 512.14it/s]
Epoch 7/20: train_loss: 0.1437, train_accuracy: 100.0000, val_loss: 0.0839, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 501.06it/s]
Epoch 8/20: train_loss: 0.0645, train_accuracy: 100.0000, val_loss: 0.0363, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 498.08it/s]
Epoch 9/20: train_loss: 0.0279, train_accuracy: 100.0000, val_loss: 0.0191, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 444.17it/s]
Epoch 10/20: train_loss: 0.0159, train_accuracy: 100.0000, val_loss: 0.0121, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 526.41it/s]
Epoch 11/20: train_loss: 0.0109, train_accuracy: 100.0000, val_loss: 0.0090, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 550.59it/s]
Epoch 12/20: train_loss: 0.0083, train_accuracy: 100.0000, val_loss: 0.0073, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 573.20it/s]
Epoch 13/20: train_loss: 0.0069, train_accuracy: 100.0000, val_loss: 0.0062, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 556.41it/s]
Epoch 14/20: train_loss: 0.0059, train_accuracy: 100.0000, val_loss: 0.0053, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 569.38it/s]
Epoch 15/20: train_loss: 0.0051, train_accuracy: 100.0000, val_loss: 0.0047, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 521.82it/s]
Epoch 16/20: train_loss: 0.0045, train_accuracy: 100.0000, val_loss: 0.0042, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 603.51it/s]
Epoch 17/20: train_loss: 0.0040, train_accuracy: 100.0000, val_loss: 0.0037, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 515.83it/s]
Epoch 18/20: train_loss: 0.0036, train_accuracy: 100.0000, val_loss: 0.0033, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 449.32it/s]
Epoch 19/20: train_loss: 0.0032, train_accuracy: 100.0000, val_loss: 0.0030, val_accuracy: 100.0000
100%|██████████| 10/10 [00:00<00:00, 431.87it/s]
Epoch 20/20: train_loss: 0.0029, train_accuracy: 100.0000, val_loss: 0.0028, val_accuracy: 100.0000
In [ ]:
# visualize results
plot(train_losses, val_losses, train_acc, val_acc, title='MLP')
In [ ]:
# evaluate on last model
val_loss, val_accuracy = evaluate(model, val_loader, criterion)
print('MLP. Validation loss: {:.2f}, validation accuracy: {:.2f}'.format(val_loss, val_accuracy))
MLP. Validation loss: 0.00, validation accuracy: 100.00

3.3 (6pts) Interpret, Diagnose, and Fix the above results

Keep your answers as short as possible (one-word answers are acceptable; maximum: one sentence per question).

If you were unable to complete the previous question, use the provided loss and accuracy curves below for your interpretation instead.

loss.png

acc.png

3.3.1 (1pt) What validation accuracy would you expect by chance for a 10-class problem?

~10%

3.3.2 (1pt) Is your model overfitting, underfitting, or generalizing well?

Overfitting

3.3.3 (1pt) If you believe the results are suspicious, what could be the problem?

Data leakage, the validation dataset was created using the training data.

3.3.4 (1pt) Fix the issue by copying the problematic code from above into the cell below and correcting it there. Add a comment indicating exactly where you made the change.

In [ ]:
# number of samples
n_train = 100
n_val = 100

# define random training images (28x28) and labels (between 0-9)
X_train = torch.randn(n_train, 1, 28, 28)
y_train = torch.randint(0, 10, (n_train,))

# define random validation images (28x28) and labels (between 0-9)
X_val = torch.randn(n_val, 1, 28, 28)
y_val = torch.randint(0, 10, (n_val,))

# create datasets
train_dataset = TensorDataset(X_train, y_train)
val_dataset = TensorDataset(X_val, y_val) # data leakage fixed!

# create data loaders
train_loader = DataLoader(train_dataset, batch_size=10, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=10, shuffle=False)

3.3.5 (1pt) Retrain, plot, and evaluate the model after the fix using the same model and hyperparameters.

In [ ]:
# train model
train_losses, val_losses, train_acc, val_acc = train(model, train_loader, val_loader, optimizer, n_epochs, criterion)

# visualize results
plot(train_losses, val_losses, train_acc, val_acc, title='MLP')
100%|██████████| 10/10 [00:00<00:00, 131.55it/s]
Epoch 1/20: train_loss: 0.0008, train_accuracy: 100.0000, val_loss: 2.9849, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 189.46it/s]
Epoch 2/20: train_loss: 0.0008, train_accuracy: 100.0000, val_loss: 2.9878, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 191.51it/s]
Epoch 3/20: train_loss: 0.0007, train_accuracy: 100.0000, val_loss: 2.9906, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 247.30it/s]
Epoch 4/20: train_loss: 0.0007, train_accuracy: 100.0000, val_loss: 2.9933, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 314.87it/s]
Epoch 5/20: train_loss: 0.0007, train_accuracy: 100.0000, val_loss: 2.9960, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 253.38it/s]
Epoch 6/20: train_loss: 0.0007, train_accuracy: 100.0000, val_loss: 2.9987, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 231.38it/s]
Epoch 7/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0012, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 315.04it/s]
Epoch 8/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0037, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 351.10it/s]
Epoch 9/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0063, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 527.42it/s]
Epoch 10/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0089, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 521.58it/s]
Epoch 11/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0113, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 525.58it/s]
Epoch 12/20: train_loss: 0.0006, train_accuracy: 100.0000, val_loss: 3.0139, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 498.42it/s]
Epoch 13/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0164, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 512.28it/s]
Epoch 14/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0188, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 508.19it/s]
Epoch 15/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0211, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 511.06it/s]
Epoch 16/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0233, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 420.79it/s]
Epoch 17/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0257, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 531.41it/s]
Epoch 18/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0280, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 552.12it/s]
Epoch 19/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0302, val_accuracy: 11.0000
100%|██████████| 10/10 [00:00<00:00, 403.98it/s]
Epoch 20/20: train_loss: 0.0005, train_accuracy: 100.0000, val_loss: 3.0325, val_accuracy: 11.0000
In [ ]:
# evaluate on last model
val_loss, val_accuracy = evaluate(model, val_loader, criterion)
print('MLP. Validation loss: {:.2f}, validation accuracy: {:.2f}'.format(val_loss, val_accuracy))
MLP. Validation loss: 3.03, validation accuracy: 11.00

3.3.6 (1pt) Are your new results reasonable?

Yes, they are as expected.


Before You Submit:

Please Restart Session and Run All to ensure your notebook runs cleanly from top to bottom without errors.

This helps us grade your work fairly and ensures everything is saved correctly.

Thank you and congratulations! 🥳

In [ ]:
## DO NOT EDIT THIS CELL
points
64