140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
import torch
|
|
import torch.nn as nn
|
|
import torch.nn.functional as F
|
|
from torch.utils.data import DataLoader
|
|
from torchvision import datasets, transforms
|
|
|
|
# Super parameters
|
|
batch_size_small = 64
|
|
learning_rate = 0.01
|
|
momentum = 0.5
|
|
EPOCH = 10
|
|
|
|
# Prepare dataset
|
|
transform = transforms.Compose(
|
|
[transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
|
|
)
|
|
|
|
train_dataset = datasets.MNIST(
|
|
root="./data/mnist", train=True, download=True, transform=transform
|
|
)
|
|
test_dataset = datasets.MNIST(
|
|
root="./data/mnist", train=False, download=True, transform=transform
|
|
)
|
|
|
|
batch_size_full = len(train_dataset)
|
|
train_loader_small = DataLoader(
|
|
train_dataset, batch_size=batch_size_small, shuffle=True
|
|
)
|
|
train_loader_full = DataLoader(train_dataset, batch_size=batch_size_full, shuffle=True)
|
|
test_loader = DataLoader(test_dataset, batch_size=batch_size_small, shuffle=False)
|
|
|
|
|
|
class Net(torch.nn.Module):
|
|
def __init__(self):
|
|
super(Net, self).__init__()
|
|
self.fc1 = torch.nn.Linear(28 * 28, 512)
|
|
self.fc2 = torch.nn.Linear(512, 128)
|
|
self.fc3 = torch.nn.Linear(128, 10)
|
|
|
|
def forward(self, x):
|
|
x = x.view(-1, 28 * 28)
|
|
x = F.relu(self.fc1(x))
|
|
x = F.relu(self.fc2(x))
|
|
x = self.fc3(x)
|
|
return x
|
|
|
|
|
|
# Create two models
|
|
model_small_batch = Net()
|
|
model_full_batch = Net()
|
|
|
|
# Create optimizers
|
|
optimizer_small = torch.optim.SGD(
|
|
model_small_batch.parameters(), lr=learning_rate, momentum=momentum
|
|
)
|
|
optimizer_full = torch.optim.SGD(
|
|
model_full_batch.parameters(), lr=learning_rate, momentum=momentum
|
|
)
|
|
|
|
criterion = torch.nn.CrossEntropyLoss()
|
|
|
|
|
|
def train(epoch, model, optimizer, loader, name=""):
|
|
model.train()
|
|
running_loss = 0.0
|
|
running_total = 0
|
|
running_correct = 0
|
|
|
|
for batch_idx, (inputs, target) in enumerate(loader):
|
|
optimizer.zero_grad()
|
|
outputs = model(inputs)
|
|
loss = criterion(outputs, target)
|
|
|
|
loss.backward()
|
|
optimizer.step()
|
|
|
|
running_loss += loss.item()
|
|
_, predicted = torch.max(outputs.data, dim=1)
|
|
running_total += target.shape[0]
|
|
running_correct += (predicted == target).sum().item()
|
|
|
|
avg_loss = running_loss / len(loader)
|
|
avg_acc = 100 * running_correct / running_total
|
|
print(
|
|
f"[{epoch + 1} / {EPOCH}]: {name} Training Loss: {avg_loss:.3f}, Training Accuracy: {avg_acc:.2f} %"
|
|
)
|
|
|
|
|
|
def test(epoch, model, name=""):
|
|
model.eval()
|
|
correct = 0
|
|
total = 0
|
|
with torch.no_grad():
|
|
for data in test_loader:
|
|
images, labels = data
|
|
outputs = model(images)
|
|
_, predicted = torch.max(outputs.data, dim=1)
|
|
total += labels.size(0)
|
|
correct += (predicted == labels).sum().item()
|
|
|
|
acc = 100 * correct / total
|
|
print(
|
|
f"[{epoch + 1} / {EPOCH}]: {name} Accuracy on test set after epoch {epoch + 1}: {acc:.1f} %"
|
|
)
|
|
return acc
|
|
|
|
|
|
if __name__ == "__main__":
|
|
acc_list_small = []
|
|
acc_list_full = []
|
|
|
|
for epoch in range(EPOCH):
|
|
train(
|
|
epoch, model_small_batch, optimizer_small, train_loader_small, "Small Batch"
|
|
)
|
|
train(epoch, model_full_batch, optimizer_full, train_loader_full, "Full Batch")
|
|
|
|
acc_small = test(epoch, model_small_batch, "Small Batch")
|
|
acc_full = test(epoch, model_full_batch, "Full Batch")
|
|
|
|
acc_list_small.append(acc_small)
|
|
acc_list_full.append(acc_full)
|
|
|
|
plt.figure(figsize=(10, 6))
|
|
plt.plot(
|
|
range(1, EPOCH + 1),
|
|
acc_list_small,
|
|
label=f"Batch Size={batch_size_small}",
|
|
marker="o",
|
|
)
|
|
plt.plot(range(1, EPOCH + 1), acc_list_full, label="Full Batch", marker="s")
|
|
plt.xlabel("Epoch")
|
|
plt.ylabel("Accuracy On TestSet (%)")
|
|
plt.title("Comparison of Batch Sizes")
|
|
plt.legend()
|
|
plt.grid(True)
|
|
plt.show()
|