feat: make code pep8 compliant

This commit is contained in:
Krzysztof Rudnicki 2023-05-13 15:41:16 +02:00
parent f0c02993d9
commit e6693df39b
5 changed files with 186 additions and 69 deletions

3
.gitignore vendored
View File

@ -462,3 +462,6 @@ TSWLatexianTemp*
# option is specified. Footnotes are the stored in a file with suffix Notes.bib. # option is specified. Footnotes are the stored in a file with suffix Notes.bib.
# Uncomment the next line to have this generated file ignored. # Uncomment the next line to have this generated file ignored.
#*Notes.bib #*Notes.bib
# MNSIT data
data/MNIST/raw

View File

@ -5,6 +5,7 @@
"mikoz.black-py", "mikoz.black-py",
"james-yu.latex-workshop", "james-yu.latex-workshop",
"kisstkondoros.vscode-gutter-preview", "kisstkondoros.vscode-gutter-preview",
"streetsidesoftware.code-spell-checker" "streetsidesoftware.code-spell-checker",
"wesbos.theme-cobalt2"
] ]
} }

View File

@ -5,8 +5,11 @@
"cSpell.words": [ "cSpell.words": [
"dtype", "dtype",
"loadtxt", "loadtxt",
"MNIST",
"optim", "optim",
"Xbatch", "Xbatch",
"ybatch" "ybatch"
] ],
"python.linting.pylintEnabled": true,
"python.linting.enabled": true
} }

9
lab5/code/.pylintrc Normal file
View File

@ -0,0 +1,9 @@
[TYPECHECK]
# List of members which are set dynamically and missed by Pylint inference
# system, and so shouldn't trigger E1101 when accessed. (Module 'torch' has no 'max' member)
generated-members=numpy.*, torch.*
[DESIGN]
# Maximum number of statements in function / method body
max-statements=16

View File

@ -1,92 +1,193 @@
""" Implementation of a network analyzing MNIST dataset """
import torch import torch
import torch.nn as nn from torch import nn
import torch.optim as optim from torch import optim
from torchvision import datasets, transforms from torchvision import datasets, transforms
# Set random seed for reproducibility
torch.manual_seed(42)
# Define hyperparameters def set_hyperparameters():
learning_rate = 0.001 """ sets hyperparameters used throughout the network """
batch_size = 64 return {
num_epochs = 10 "learning_rate": 0.001,
input_size = 28 * 28 # MNIST images are 28x28 pixels "batch_size": 64,
hidden_size = 128 "num_epochs": 2,
num_classes = 10 "input_size": 28 * 28, # MNIST images are 28x28 pixels
"hidden_size": 128,
"num_classes": 10,
}
# Load MNIST dataset and apply transformations
train_dataset = datasets.MNIST(
root='./data', train=True, transform=transforms.ToTensor(), download=True
)
test_dataset = datasets.MNIST(
root='./data', train=False, transform=transforms.ToTensor(), download=True
)
# Create data loaders def load_datasets():
train_loader = torch.utils.data.DataLoader( """ Loads train and test dataset from MNIST """
dataset=train_dataset, batch_size=batch_size, shuffle=True train_dataset = datasets.MNIST(
) root="./data", train=True, transform=transforms.ToTensor(), download=True
test_loader = torch.utils.data.DataLoader( )
dataset=test_dataset, batch_size=batch_size, shuffle=False test_dataset = datasets.MNIST(
) root="./data", train=False, transform=transforms.ToTensor(), download=True
)
return train_dataset, test_dataset
# Define the multilayer perceptron model
model = nn.Sequential(
nn.Linear(input_size, hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, num_classes)
)
# Loss function def create_data_loaders(train_dataset, test_dataset, hyperparameters):
criterion = nn.CrossEntropyLoss() """ Create train and test data loaders """
train_loader = torch.utils.data.DataLoader(
dataset=train_dataset, batch_size=hyperparameters["batch_size"], shuffle=True
)
test_loader = torch.utils.data.DataLoader(
dataset=test_dataset, batch_size=hyperparameters["batch_size"], shuffle=False
)
return train_loader, test_loader
# Optimizer
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# Training loop def define_model(hyperparameters):
for epoch in range(num_epochs): """ Define the multilayer perceptron training_parameters['model'] """
for batch_idx, (data, targets) in enumerate(train_loader): model = nn.Sequential(
# Reshape the input data nn.Linear(hyperparameters["input_size"],
data = data.view(data.size(0), -1) hyperparameters["hidden_size"]),
nn.ReLU(),
# Forward pass nn.Linear(hyperparameters["hidden_size"],
outputs = model(data) hyperparameters["num_classes"]),
loss = criterion(outputs, targets) )
return model
# Backward pass and optimization
optimizer.zero_grad()
loss.backward() def initial_configuration():
optimizer.step() """
Perform all operations needed for training network
# Print loss value for every learning step """
if (batch_idx+1) % 100 == 0: # Set random seed for reproducibility
print(f'Epoch [{epoch+1}/{num_epochs}], Step [{batch_idx+1}/{len(train_loader)}], Loss: {loss.item():.4f}') torch.manual_seed(42)
hyperparameters = set_hyperparameters()
# Calculate accuracy on train set after each epoch # Load MNIST dataset and apply transformations
train_dataset, test_dataset = load_datasets()
train_loader, test_loader = create_data_loaders(
train_dataset, test_dataset, hyperparameters
)
model = define_model(hyperparameters)
# Loss function
criterion = nn.CrossEntropyLoss()
# training_parameters['optimizer']
optimizer = optim.Adam(
model.parameters(), lr=hyperparameters["learning_rate"])
return hyperparameters, train_loader, test_loader, model, criterion, optimizer
def single_train_iteration(
data, training_parameters, targets, batch_idx, epoch
):
"""
Train network for single batch
"""
# Reshape the input data
data = data.view(data.size(0), -1)
# Forward pass
outputs = training_parameters['model'](data)
loss = training_parameters['criterion'](outputs, targets)
# Backward pass and optimization
training_parameters['optimizer'].zero_grad()
loss.backward()
training_parameters['optimizer'].step()
# Print loss value for every learning step
if (batch_idx + 1) % 100 == 0:
print(
f'''
Epoch [{epoch+1}/{training_parameters['hyperparameters']["num_epochs"]}],
Step [{batch_idx+1}/ \
{len(training_parameters['loaders']['train_loader'])}],
Loss: {loss.item():.4f}
'''
)
return data, training_parameters['optimizer']
def set_loaders(train_loader, test_loader):
"""
Put train and test loaders into one object
"""
return {
'train_loader': train_loader,
'test_loader': test_loader
}
def set_training_parameters(hyperparameters, loaders, model, criterion, optimizer):
"""
Put all training parameters into one object
"""
return {
'hyperparameters': hyperparameters,
'loaders': {
'train_loader': loaders['train_loader'],
'test_loader': loaders['test_loader']
},
'model': model,
'criterion': criterion,
'optimizer': optimizer,
}
def training_loop(training_parameters):
"""
Train network for all epochs
"""
epochs_num = training_parameters["hyperparameters"]["num_epochs"]
# Training loop
for epoch in range(epochs_num):
for batch_idx, (data, targets) in enumerate(training_parameters['loaders']['train_loader']):
data, training_parameters['optimizer'] = single_train_iteration(
data, training_parameters, targets, batch_idx, epoch
)
calculate_accuracy_epoch(
training_parameters, epoch)
calculate_validation_set_accuracy(
training_parameters, epoch)
return epoch, training_parameters['loaders']['train_loader']
def calculate_accuracy_epoch(training_parameters, epoch):
""" Calculate accuracy on train set after each epoch """
correct = 0 correct = 0
total = 0 total = 0
for data, targets in train_loader: for data, targets in training_parameters['loaders']['train_loader']:
data = data.view(data.size(0), -1) data = data.view(data.size(0), -1)
outputs = model(data) outputs = training_parameters['model'](data)
_, predicted = torch.max(outputs.data, 1) _, predicted = torch.max(outputs.data, 1)
total += targets.size(0) total += targets.size(0)
correct += (predicted == targets).sum().item() correct += (predicted == targets).sum().item()
train_accuracy = 100 * correct / total train_accuracy = 100 * correct / total
print(f'Accuracy on Train Set after Epoch {epoch+1}: {train_accuracy:.2f}%') print(
f"Accuracy on Train Set after Epoch {epoch+1}: {train_accuracy:.2f}%")
# Calculate accuracy on validation set after each epoch
def calculate_validation_set_accuracy(training_parameters, epoch):
""" Calculate accuracy on validation set after each epoch """
correct = 0 correct = 0
total = 0 total = 0
for data, targets in test_loader: for data, targets in training_parameters['loaders']['test_loader']:
data = data.view(data.size(0), -1) data = data.view(data.size(0), -1)
outputs = model(data) outputs = training_parameters['model'](data)
_, predicted = torch.max(outputs.data, 1) _, predicted = torch.max(outputs.data, 1)
total += targets.size(0) total += targets.size(0)
correct += (predicted == targets).sum().item() correct += (predicted == targets).sum().item()
validation_accuracy = 100 * correct / total
print(f'Accuracy on Validation Set after Epoch {epoch+1}: {validation_accuracy:.2f}%')
print('---')
# Conclusions and observations can be included in the report validation_accuracy = 100 * correct / total
print(
f"Accuracy on Validation Set after Epoch {epoch+1}: {validation_accuracy:.2f}%"
)
print("---")
if __name__ == "__main__":
(
HYPERPARAMETERS,
TRAIN_LOADER,
TEST_LOADER,
MODEL,
CRITERION,
OPTIMIZER,
) = initial_configuration()
LOADERS = set_loaders(
TRAIN_LOADER, TEST_LOADER)
TRAINING_PARAMETERS = set_training_parameters(
HYPERPARAMETERS, LOADERS, MODEL, CRITERION, OPTIMIZER)
training_loop(TRAINING_PARAMETERS)