Description
Create the train_step()
def train_step(model: torch.nn.Module,
dataloader: torch.utils.data.DataLoader,
loss_fn: torch.nn.Module,
optimizer: torch.optim.Optimizer,
device=device):
Put the model in train mode
model.train()
Setup train loss and train accuracy values
train_loss, train_acc = 0, 0
Loop through data loader and data batches
for batch, (X, y) in enumerate(dataloader):
# Send data to the target device
X, y = X.to(device), y.to(device)
# 1. Forward pass
y_pred = model(X) # output model logits
# 2. Calculate loss
loss = loss_fn(y_pred, y)
train_loss += loss.item()
# 3. Optimizer zero grad
optimizer.zero_grad()
# 4. Loss backward
loss.backward()
# 5. Optimizer step
optimizer.step()
# Caclulate the accuracy metric
y_pred_class = torch.argmax(torch.softmax(y_pred, dim=1), dim=1)
train_acc += (y_pred_class == y).sun().item() / len(y_pred)
Adjust metrics to get the average loss and accuracy per batch
train_loss = train_loss / len(dataloader)
train_acc = train_acc / len(dataloader)
return train_loss, train_acc
Define the test step function
def test_step(model: torch.nn.Module,
data_loader: torch.utils.data.DataLoader,
loss_fn: torch.nn.Module,
device=device):
"""Performs testing loop on model for data_loader"""
Put model in training mode
model.eval()
Setup test loss and test accuracy
test_loss, test_acc = 0, 0
Testing
Turn on inference mode context manager
with torch.inference_mode():
for batch, (X, y) in enumerate(data_loader):
# Put data on device
X, y = X.to(device), y.to(device)
# 1. forward pass
test_pred_logits = model(X)
# 2. Cacl the loss (accumulative)
test_loss += loss_fn(test_pred_logits, y.long())
# test_loss += loss.item() # Remove this line, it's causing the loss to accumulate incorrectly
# Calculate the accuracy
test_pred_labels = test_pred_logits.argmax(dim=1)
test_acc += ((test_pred_labels == y).sum().item()/len(test_pred_labels))
Adjust metrics to get average loss and accuracy per batch
test_loss = test_loss / len(data_loader)
test_acc = test_acc / len(data_loader)
return test_loss, test_acc
from tqdm.auto import tqdm
1. Create a train function that takes in various model params + optimizer + etc
def train(model: torch.nn.Module,
train_dataloader: torch.utils.data.DataLoader,
test_dataloader: torch.utils.data.DataLoader,
optimizer: torch.optim.Optimizer,
loss_fn: torch.nn.Module = nn.CrossEntropyLoss(),
epochs: int = 5,
seed: int = 42,
device=device):
2. Create an empty results dict
results = {"train_loss": [],
"train_acc": [],
"test_loss": [],
"test_acc": []}
3. Loop through training and testing steps for number of epochs
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
epochs = epochs
for epoch in tqdm(range(epochs)):
train_loss, train_acc = train_step(model=model,
dataloader=train_dataloader,
loss_fn=loss_fn,
optimizer=optimizer,
device=device)
test_loss, test_acc = test_step(model=model,
data_loader=test_dataloader,
loss_fn=loss_fn,
device=device)
# 4. Print out whats happening
print(f"Epoch: {epoch} | Train loss: {train_loss:.4f} | Train acc: {train_acc:.4f} | Test loss: {test_loss:.4f} | Test acc: {test_acc:.4f}")
# 5. Update results dict
results["train_loss"].append(train_loss)
results["train_acc"].append(train_acc)
results["test_loss"].append(test_loss)
results["test_acc"].append(test_acc)
6. Return the filled results at the end of the epochs
return results
Set random seeds
torch.manual_seed(42)
torch.cuda.manual_seed(42)
Set number of epochs
NUM_EPOCHS = 5
Recreate an instance of TinyVGG
model_0 = TinyVGG(input_shape=3, # number of color channels of our target images
hidden_units=10,
output_shape=len(train_data.classes)).to(device)
Setup loss function and optimizer
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(params=model_0.parameters(),
lr=0.001)
Start the timer
from timeit import default_timer as timer
start_time = timer()
Train model_0
model_0_results = train(model=model_0,
train_dataloader=train_dataloader_simple,
test_dataloader=test_dataloader_simple,
optimizer=optimizer,
epochs=NUM_EPOCHS)
End the timer and print out how long it took
end_time = timer()
print(f"Total training time: {end_time - start_time:.3f} seconds")
#####Error
torch.Size([32, 3, 64, 64])
torch.Size([32, 3, 64, 64])
torch.Size([32, 3, 64, 64])
RuntimeError Traceback (most recent call last)
in <cell line: 25>()
23
24 # Train model_0
---> 25 model_0_results = train(model=model_0,
26 train_dataloader=train_dataloader_simple,
27 test_dataloader=test_dataloader_simple,
5 frames
/usr/local/lib/python3.10/dist-packages/torch/nn/functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce, reduction, label_smoothing)
3084 if size_average is not None or reduce is not None:
3085 reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 3086 return torch._C._nn.cross_entropy_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index, label_smoothing)
3087
3088
RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 1