Chapter 42
02. Neural Network classification with PyTorch
02. Neural Network classification with PyTorch
Classification is a problem of predicting whether something is one thing or another (there can be multiple things as the options).
- Book version of this notebook - https://www.learnpytorch.io/02_pytorch_classification/
- All other resources - https://github.com/mrdbourke/pytorch-deep-learning
- Stuck? Ask a question - https://github.com/mrdbourke/pytorch-deep-learning/discussions
1. Make classification data and get it ready
import sklearnfrom sklearn.datasets import make_circles
# Make 1000 samples
n_samples = 1000
# Create circles
X, y = make_circles(n_samples,
noise=0.03,
random_state=42)len(X), len(y)Output
(1000, 1000)
print(f"First 5 samples of X:\n {X[:5]}")
print(f"First 5 samples of y:\n {y[:5]}")Output
First 5 samples of X: [[ 0.75424625 0.23148074] [-0.75615888 0.15325888] [-0.81539193 0.17328203] [-0.39373073 0.69288277] [ 0.44220765 -0.89672343]] First 5 samples of y: [1 1 1 1 0]
# Make DataFrame of circle data
import pandas as pd
circles = pd.DataFrame({"X1": X[:, 0],
"X2": X[:, 1],
"label": y})
circles.head(10)Output
X1 X2 label 0 0.754246 0.231481 1 1 -0.756159 0.153259 1 2 -0.815392 0.173282 1 3 -0.393731 0.692883 1 4 0.442208 -0.896723 0 5 -0.479646 0.676435 1 6 -0.013648 0.803349 1 7 0.771513 0.147760 1 8 -0.169322 -0.793456 1 9 -0.121486 1.021509 0
| X1 | X2 | label | |
|---|---|---|---|
| 0 | 0.754246 | 0.231481 | 1 |
| 1 | -0.756159 | 0.153259 | 1 |
| 2 | -0.815392 | 0.173282 | 1 |
| 3 | -0.393731 | 0.692883 | 1 |
| 4 | 0.442208 | -0.896723 | 0 |
| 5 | -0.479646 | 0.676435 | 1 |
| 6 | -0.013648 | 0.803349 | 1 |
| 7 | 0.771513 | 0.147760 | 1 |
| 8 | -0.169322 | -0.793456 | 1 |
| 9 | -0.121486 | 1.021509 | 0 |
circles.label.value_counts() Output
1 500 0 500 Name: label, dtype: int64
# Visualize, visualize, visualize
import matplotlib.pyplot as plt
plt.scatter(x=X[:, 0],
y=X[:, 1],
c=y,
cmap=plt.cm.RdYlBu);Output
<Figure size 432x288 with 1 Axes>
Note: The data we're working with is often referred to as a toy dataset, a dataset that is small enough to experiment but still sizeable enough to practice the fundamentals.
1.1 Check input and output shapes
X.shape, y.shapeOutput
((1000, 2), (1000,))
XOutput
array([[ 0.75424625, 0.23148074],
[-0.75615888, 0.15325888],
[-0.81539193, 0.17328203],
...,
[-0.13690036, -0.81001183],
[ 0.67036156, -0.76750154],
[ 0.28105665, 0.96382443]])# View the first example of features and labels
X_sample = X[0]
y_sample = y[0]
print(f"Values for one sample of X: {X_sample} and the same for y: {y_sample}")
print(f"Shapes for one sample of X: {X_sample.shape} and the same for y: {y_sample.shape}")Output
Values for one sample of X: [0.75424625 0.23148074] and the same for y: 1 Shapes for one sample of X: (2,) and the same for y: ()
1.2 Turn data into tensors and create train and test splits
import torch
torch.__version__Output
'1.10.0+cu111'
type(X), X.dtypeOutput
(numpy.ndarray, dtype('float64'))# Turn data into tensors
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
X[:5], y[:5]Output
(tensor([[ 0.7542, 0.2315],
[-0.7562, 0.1533],
[-0.8154, 0.1733],
[-0.3937, 0.6929],
[ 0.4422, -0.8967]]), tensor([1., 1., 1., 1., 0.]))type(X), X.dtype, y.dtypeOutput
(torch.Tensor, torch.float32, torch.float32)
# Split data into training and test sets
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.2, # 0.2 = 20% of data will be test & 80% will be train
random_state=42) len(X_train), len(X_test), len(y_train), len(y_test)Output
(800, 200, 800, 200)
n_samplesOutput
1000
2. Building a model
Let's build a model to classify our blue and red dots.
To do so, we want to:
- Setup device agonistic code so our code will run on an accelerator (GPU) if there is one
- Construct a model (by subclassing
nn.Module) - Define a loss function and optimizer
- Create a training and test loop
# Import PyTorch and nn
import torch
from torch import nn
# Make device agnostic code
device = "cuda" if torch.cuda.is_available() else "cpu"
deviceOutput
'cuda'
X_trainOutput
tensor([[ 0.6579, -0.4651],
[ 0.6319, -0.7347],
[-1.0086, -0.1240],
...,
[ 0.0157, -1.0300],
[ 1.0110, 0.1680],
[ 0.5578, -0.5709]])Now we've setup device agnostic code, let's create a model that:
- Subclasses
nn.Module(almost all models in PyTorch subclassnn.Module) - Create 2
nn.Linear()layers that are capable of handling the shapes of our data - Defines a
forward()method that outlines the forward pass (or forward computation) of the model - Instatiate an instance of our model class and send it to the target
device
X_train.shapeOutput
torch.Size([800, 2])
y_train[:5]Output
tensor([1., 0., 0., 0., 1.])
from sklearn import datasets
# 1. Construct a model that subclasses nn.Module
class CircleModelV0(nn.Module):
def __init__(self):
super().__init__()
# 2. Create 2 nn.Linear layers capable of handling the shapes of our data
self.layer_1 = nn.Linear(in_features=2, out_features=5) # takes in 2 features and upscales to 5 features
self.layer_2 = nn.Linear(in_features=5, out_features=1) # takes in 5 features from previous layer and outputs a single feature (same shape as y)
# 3. Define a forward() method that outlines the forward pass
def forward(self, x):
return self.layer_2(self.layer_1(x)) # x -> layer_1 -> layer_2 -> output
# 4. Instantiate an instance of our model class and send it to the target device
model_0 = CircleModelV0().to(device)
model_0Output
CircleModelV0( (layer_1): Linear(in_features=2, out_features=5, bias=True) (layer_2): Linear(in_features=5, out_features=1, bias=True) )
deviceOutput
'cuda'
next(model_0.parameters()).deviceOutput
device(type='cuda', index=0)
# Let's replicate the model above using nn.Sequential()
model_0 = nn.Sequential(
nn.Linear(in_features=2, out_features=5),
nn.Linear(in_features=5, out_features=1)
).to(device)
model_0Output
Sequential( (0): Linear(in_features=2, out_features=5, bias=True) (1): Linear(in_features=5, out_features=1, bias=True) )
model_0.state_dict()Output
OrderedDict([('0.weight', tensor([[-0.1962, 0.3652],
[ 0.2764, 0.2147],
[ 0.5723, -0.5955],
[-0.2329, 0.0170],
[ 0.6259, 0.6916]], device='cuda:0')),
('0.bias',
tensor([ 0.4193, 0.6624, 0.2594, -0.1640, -0.0477], device='cuda:0')),
('1.weight',
tensor([[ 0.4129, 0.2358, 0.4115, 0.4045, -0.0853]], device='cuda:0')),
('1.bias', tensor([-0.4294], device='cuda:0'))])# Make predictions
with torch.inference_mode():
untrained_preds = model_0(X_test.to(device))
print(f"Length of predictions: {len(untrained_preds)}, Shape: {untrained_preds.shape}")
print(f"Length of test samples: {len(X_test)}, Shape: {X_test.shape}")
print(f"\nFirst 10 predictions:\n{torch.round(untrained_preds[:10])}")
print(f"\nFirst 10 labels:\n{y_test[:10]}")Output
Length of predictions: 200, Shape: torch.Size([200, 1])
Length of test samples: 200, Shape: torch.Size([200, 2])
First 10 predictions:
tensor([[-0.],
[-0.],
[-0.],
[-0.],
[0.],
[0.],
[-0.],
[-0.],
[-0.],
[-0.]], device='cuda:0')
First 10 labels:
tensor([1., 0., 1., 0., 1., 1., 0., 0., 1., 0.])
X_test[:10], y_test[:10]Output
(tensor([[-0.3752, 0.6827],
[ 0.0154, 0.9600],
[-0.7028, -0.3147],
[-0.2853, 0.9664],
[ 0.4024, -0.7438],
[ 0.6323, -0.5711],
[ 0.8561, 0.5499],
[ 1.0034, 0.1903],
[-0.7489, -0.2951],
[ 0.0538, 0.9739]]),
tensor([1., 0., 1., 0., 1., 1., 0., 0., 1., 0.]))2.1 Setup loss function and optimizer
Which loss function or optimizer should you use?
Again... this is problem specific.
For example for regression you might want MAE or MSE (mean absolute error or mean squared error).
For classification you might want binary cross entropy or categorical cross entropy (cross entropy).
As a reminder, the loss function measures how wrong your models predictions are.
And for optimizers, two of the most common and useful are SGD and Adam, however PyTorch has many built-in options.
- For some common choices of loss functions and optimizers - https://www.learnpytorch.io/02_pytorch_classification/#21-setup-loss-function-and-optimizer
- For the loss function we're going to use
torch.nn.BECWithLogitsLoss(), for more on what binary cross entropy (BCE) is, check out this article - https://towardsdatascience.com/understanding-binary-cross-entropy-log-loss-a-visual-explanation-a3ac6025181a - For a defintion on what a logit is in deep learning - https://stackoverflow.com/a/52111173/7900723
- For different optimizers see
torch.optim
# Setup the loss function
# loss_fn = nn.BCELoss() # BCELoss = requires inputs to have gone through the sigmoid activation function prior to input to BCELoss
loss_fn = nn.BCEWithLogitsLoss() # BCEWithLogitsLoss = sigmoid activation function built-in
optimizer = torch.optim.SGD(params=model_0.parameters(),
lr=0.1)# Calculate accuracy - out of 100 examples, what percentage does our model get right?
def accuracy_fn(y_true, y_pred):
correct = torch.eq(y_true, y_pred).sum().item()
acc = (correct/len(y_pred)) * 100
return acc3. Train model
To train our model, we're going to need to build a training loop with the following steps:
- Forward pass
- Calculate the loss
- Optimizer zero grad
- Loss backward (backpropagation)
- Optimizer step (gradient descent)
3.1 Going from raw logits -> prediction probabilities -> prediction labels
Our model outputs are going to be raw logits.
We can convert these logits into prediction probabilities by passing them to some kind of activation function (e.g. sigmoid for binary classification and softmax for multiclass classification).
Then we can convert our model's prediction probabilities to prediction labels by either rounding them or taking the argmax().
# View the first 5 outputs of the forward pass on the test data
model_0.eval()
with torch.inference_mode():
y_logits = model_0(X_test.to(device))[:5]
y_logits Output
tensor([[-0.1481],
[-0.1465],
[-0.0762],
[-0.1688],
[ 0.0445]], device='cuda:0')y_test[:5]Output
tensor([1., 0., 1., 0., 1.])
# Use the sigmoid activation function on our model logits to turn them into prediction probabilities
y_pred_probs = torch.sigmoid(y_logits)
y_pred_probsOutput
tensor([[0.4630],
[0.4634],
[0.4810],
[0.4579],
[0.5111]], device='cuda:0')For our prediction probability values, we need to perform a range-style rounding on them:
y_pred_probs>= 0.5,y=1(class 1)y_pred_probs< 0.5,y=0(class 0)
# Find the predicted labels
y_preds = torch.round(y_pred_probs)
# In full (logits -> pred probs -> pred labels)
y_pred_labels = torch.round(torch.sigmoid(model_0(X_test.to(device))[:5]))
# Check for equality
print(torch.eq(y_preds.squeeze(), y_pred_labels.squeeze()))
# Get rid of extra dimension
y_preds.squeeze()Output
tensor([True, True, True, True, True], device='cuda:0')
tensor([0., 0., 0., 0., 1.], device='cuda:0')
y_test[:5]Output
tensor([1., 0., 1., 0., 1.])
3.2 Building a training and testing loop
torch.manual_seed(42)
torch.cuda.manual_seed(42)
# Set the number of epochs
epochs = 100
# Put data to target device
X_train, y_train = X_train.to(device), y_train.to(device)
X_test, y_test = X_test.to(device), y_test.to(device)
# Build training and evaluation loop
for epoch in range(epochs):
### Training
model_0.train()
# 1. Forward pass
y_logits = model_0(X_train).squeeze()
y_pred = torch.round(torch.sigmoid(y_logits)) # turn logits -> pred probs -> pred labels
# 2. Calculate loss/accuracy
# loss = loss_fn(torch.sigmoid(y_logits), # nn.BCELoss expects prediction probabilities as input
# y_train)
loss = loss_fn(y_logits, # nn.BCEWithLogitsLoss expects raw logits as input
y_train)
acc = accuracy_fn(y_true=y_train,
y_pred=y_pred)
# 3. Optimizer zero grad
optimizer.zero_grad()
# 4. Loss backward (backpropagation)
loss.backward()
# 5. Optimizer step (gradient descent)
optimizer.step()
### Testing
model_0.eval()
with torch.inference_mode():
# 1. Forward pass
test_logits = model_0(X_test).squeeze()
test_pred = torch.round(torch.sigmoid(test_logits))
# 2. Calculate test loss/acc
test_loss = loss_fn(test_logits,
y_test)
test_acc = accuracy_fn(y_true=y_test,
y_pred=test_pred)
# Print out what's happenin'
if epoch % 10 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.5f}, Acc: {acc:.2f}% | Test loss: {test_loss:.5f}, Test acc: {test_acc:.2f}%")Output
Epoch: 0 | Loss: 0.69461, Acc: 47.88% | Test loss: 0.69301, Test acc: 48.50% Epoch: 10 | Loss: 0.69402, Acc: 48.75% | Test loss: 0.69296, Test acc: 48.00% Epoch: 20 | Loss: 0.69369, Acc: 49.50% | Test loss: 0.69308, Test acc: 46.50% Epoch: 30 | Loss: 0.69348, Acc: 50.62% | Test loss: 0.69325, Test acc: 45.50% Epoch: 40 | Loss: 0.69334, Acc: 50.12% | Test loss: 0.69341, Test acc: 48.50% Epoch: 50 | Loss: 0.69324, Acc: 49.25% | Test loss: 0.69357, Test acc: 51.00% Epoch: 60 | Loss: 0.69317, Acc: 49.50% | Test loss: 0.69372, Test acc: 50.50% Epoch: 70 | Loss: 0.69312, Acc: 50.38% | Test loss: 0.69385, Test acc: 49.00% Epoch: 80 | Loss: 0.69308, Acc: 50.12% | Test loss: 0.69396, Test acc: 49.50% Epoch: 90 | Loss: 0.69305, Acc: 50.50% | Test loss: 0.69406, Test acc: 48.00%
4. Make predictions and evaluate the model
From the metrics it looks like our model isn't learning anything...
So to inspect it let's make some predictions and make them visual!
In other words, "Visualize, visualize, visualize!"
To do so, we're going to import a function called plot_decision_boundary() - https://github.com/mrdbourke/pytorch-deep-learning/blob/main/helper_functions.py
import requests
from pathlib import Path
# Download helper functions from Learn PyTorch repo (if it's not already downloaded)
if Path("helper_functions.py").is_file():
print("helper_functions.py already exists, skipping download")
else:
print("Downloading helper_functions.py")
request = requests.get("https://raw.githubusercontent.com/mrdbourke/pytorch-deep-learning/main/helper_functions.py")
with open("helper_functions.py", "wb") as f:
f.write(request.content)
from helper_functions import plot_predictions, plot_decision_boundaryOutput
Downloading helper_functions.py
# Plot decision boundary of the model
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("Train")
plot_decision_boundary(model_0, X_train, y_train)
plt.subplot(1, 2, 2)
plt.title("Test")
plot_decision_boundary(model_0, X_test, y_test) Output
<Figure size 864x432 with 2 Axes>
[省略较大 image/png 输出]
5. Improving a model (from a model perspective)
- Add more layers - give the model more chances to learn about patterns in the data
- Add more hidden units - go from 5 hidden units to 10 hidden units
- Fit for longer
- Changing the activation functions
- Change the learning rate
- Change the loss function
These options are all from a model's perspective because they deal directly with the model, rather than the data.
And because these options are all values we (as machine learning engineers and data scientists) can change, they are referred as hyperparameters.
Let's try and improve our model by:
- Adding more hidden units: 5 -> 10
- Increase the number of layers: 2 -> 3
- Increase the number of epochs: 100 -> 1000
X_train[:5], y_train[:5]Output
(tensor([[ 0.6579, -0.4651],
[ 0.6319, -0.7347],
[-1.0086, -0.1240],
[-0.9666, -0.2256],
[-0.1666, 0.7994]], device='cuda:0'),
tensor([1., 0., 0., 0., 1.], device='cuda:0'))# Create a model
class CircleModelV1(nn.Module):
def __init__(self):
super().__init__()
self.layer_1 = nn.Linear(in_features=2, out_features=10)
self.layer_2 = nn.Linear(in_features=10, out_features=10)
self.layer_3 = nn.Linear(in_features=10, out_features=1)
def forward(self, x):
# z = self.layer_1(x)
# z = self.layer_2(z)
# z = self.layer_3(z)
return self.layer_3(self.layer_2(self.layer_1(x))) # this way of writing operations leverages speed ups where possible behind the scenes
model_1 = CircleModelV1().to(device)
model_1Output
CircleModelV1( (layer_1): Linear(in_features=2, out_features=10, bias=True) (layer_2): Linear(in_features=10, out_features=10, bias=True) (layer_3): Linear(in_features=10, out_features=1, bias=True) )
# Create a loss function
loss_fn = nn.BCEWithLogitsLoss()
# Create an optimizer
optimizer = torch.optim.SGD(params=model_1.parameters(),
lr=0.1)# Write a training and evaluation loop for model_1
torch.manual_seed(42)
torch.cuda.manual_seed(42)
# Train for longer
epochs = 1000
# Put data on the target device
X_train, y_train = X_train.to(device), y_train.to(device)
X_test, y_test = X_test.to(device), y_test.to(device)
for epoch in range(epochs):
### Training
model_1.train()
# 1. Forward pass
y_logits = model_1(X_train).squeeze()
y_pred = torch.round(torch.sigmoid(y_logits)) # logits -> pred probabilities -> prediction labels
# 2. Calculate the loss/acc
loss = loss_fn(y_logits, y_train)
acc = accuracy_fn(y_true=y_train,
y_pred=y_pred)
# 3. Optimizer zero grad
optimizer.zero_grad()
# 4. Loss backward (backpropagation)
loss.backward()
# 5. Optimizer step (gradient descent)
optimizer.step()
### Testing
model_1.eval()
with torch.inference_mode():
# 1. Forward pass
test_logits = model_1(X_test).squeeze()
test_pred = torch.round(torch.sigmoid(test_logits))
# 2. Calculate loss
test_loss = loss_fn(test_logits,
y_test)
test_acc = accuracy_fn(y_true=y_test,
y_pred=test_pred)
# Print out what's happenin'
if epoch % 100 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.5f}, Acc: {acc:.2f}% | Test loss: {test_loss:.5f}, Test acc: {test_acc:.2f}%")Output
Epoch: 0 | Loss: 0.69396, Acc: 50.88% | Test loss: 0.69261, Test acc: 51.00% Epoch: 100 | Loss: 0.69305, Acc: 50.38% | Test loss: 0.69379, Test acc: 48.00% Epoch: 200 | Loss: 0.69299, Acc: 51.12% | Test loss: 0.69437, Test acc: 46.00% Epoch: 300 | Loss: 0.69298, Acc: 51.62% | Test loss: 0.69458, Test acc: 45.00% Epoch: 400 | Loss: 0.69298, Acc: 51.12% | Test loss: 0.69465, Test acc: 46.00% Epoch: 500 | Loss: 0.69298, Acc: 51.00% | Test loss: 0.69467, Test acc: 46.00% Epoch: 600 | Loss: 0.69298, Acc: 51.00% | Test loss: 0.69468, Test acc: 46.00% Epoch: 700 | Loss: 0.69298, Acc: 51.00% | Test loss: 0.69468, Test acc: 46.00% Epoch: 800 | Loss: 0.69298, Acc: 51.00% | Test loss: 0.69468, Test acc: 46.00% Epoch: 900 | Loss: 0.69298, Acc: 51.00% | Test loss: 0.69468, Test acc: 46.00%
# Plot decision boundary of the model
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("Train")
plot_decision_boundary(model_1, X_train, y_train)
plt.subplot(1, 2, 2)
plt.title("Test")
plot_decision_boundary(model_1, X_test, y_test) Output
<Figure size 864x432 with 2 Axes>
[省略较大 image/png 输出]
5.1 Preparing data to see if our model can fit a straight line
One way to troubleshoot to a larger problem is to test out a smaller problem.
# Create some data (same as notebook 01)
weight = 0.7
bias = 0.3
start = 0
end = 1
step = 0.01
# Create data
X_regression = torch.arange(start, end, step).unsqueeze(dim=1)
y_regression = weight * X_regression + bias # Linear regression formula (without epsilon)
# Check the data
print(len(X_regression))
X_regression[:5], y_regression[:5]Output
100
(tensor([[0.0000],
[0.0100],
[0.0200],
[0.0300],
[0.0400]]), tensor([[0.3000],
[0.3070],
[0.3140],
[0.3210],
[0.3280]]))# Create train and test splits
train_split = int(0.8 * len(X_regression))
X_train_regression, y_train_regression = X_regression[:train_split], y_regression[:train_split]
X_test_regression, y_test_regression = X_regression[train_split:], y_regression[train_split:]
# Check the lengths of each
len(X_train_regression), len(X_test_regression), len(y_train_regression), len(y_test_regression)Output
(80, 20, 80, 20)
plot_predictions(train_data=X_train_regression,
train_labels=y_train_regression,
test_data=X_test_regression,
test_labels=y_test_regression);Output
<Figure size 720x504 with 1 Axes>
5.2 Adjusting model_1 to fit a straight line
# Same architecture as model_1 (but using nn.Sequential())
model_2 = nn.Sequential(
nn.Linear(in_features=1, out_features=10),
nn.Linear(in_features=10, out_features=10),
nn.Linear(in_features=10, out_features=1)
).to(device)
model_2Output
Sequential( (0): Linear(in_features=1, out_features=10, bias=True) (1): Linear(in_features=10, out_features=10, bias=True) (2): Linear(in_features=10, out_features=1, bias=True) )
# Loss and optimizer
loss_fn = nn.L1Loss() # MAE loss with regression data
optimizer = torch.optim.SGD(params=model_2.parameters(),
lr=0.01)# Train the model
torch.manual_seed(42)
torch.cuda.manual_seed(42)
# Set the number of epochs
epochs = 1000
# Put the data on the target device
X_train_regression, y_train_regression = X_train_regression.to(device), y_train_regression.to(device)
X_test_regression, y_test_regression = X_test_regression.to(device), y_test_regression.to(device)
# Training
for epoch in range(epochs):
y_pred = model_2(X_train_regression)
loss = loss_fn(y_pred, y_train_regression)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Testing
model_2.eval()
with torch.inference_mode():
test_pred = model_2(X_test_regression)
test_loss = loss_fn(test_pred, y_test_regression)
# Print out what's happenin'
if epoch % 100 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.5f} | Test loss: {test_loss:.5f}")Output
Epoch: 0 | Loss: 0.75986 | Test loss: 0.91103 Epoch: 100 | Loss: 0.02858 | Test loss: 0.00081 Epoch: 200 | Loss: 0.02533 | Test loss: 0.00209 Epoch: 300 | Loss: 0.02137 | Test loss: 0.00305 Epoch: 400 | Loss: 0.01964 | Test loss: 0.00341 Epoch: 500 | Loss: 0.01940 | Test loss: 0.00387 Epoch: 600 | Loss: 0.01903 | Test loss: 0.00379 Epoch: 700 | Loss: 0.01878 | Test loss: 0.00381 Epoch: 800 | Loss: 0.01840 | Test loss: 0.00329 Epoch: 900 | Loss: 0.01798 | Test loss: 0.00360
# Turn on evaluation mode
model_2.eval()
# Make predictions (inference)
with torch.inference_mode():
y_preds = model_2(X_test_regression)
# Plot data and predictions
plot_predictions(train_data=X_train_regression.cpu(),
train_labels=y_train_regression.cpu(),
test_data=X_test_regression.cpu(),
test_labels=y_test_regression.cpu(),
predictions=y_preds.cpu()); Output
<Figure size 720x504 with 1 Axes>
6. The missing piece: non-linearity
"What patterns could you draw if you were given an infinite amount of a straight and non-straight lines?"
Or in machine learning terms, an infinite (but really it is finite) of linear and non-linear functions?
6.1 Recreating non-linear data (red and blue circles)
# Make and plot data
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
n_samples = 1000
X, y = make_circles(n_samples,
noise=0.03,
random_state=42)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu);Output
<Figure size 432x288 with 1 Axes>
# Convert data to tensors and then to train and test splits
import torch
from sklearn.model_selection import train_test_split
# Turn data into tensors
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
# Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.2,
random_state=42)
X_train[:5], y_train[:5]Output
(tensor([[ 0.6579, -0.4651],
[ 0.6319, -0.7347],
[-1.0086, -0.1240],
[-0.9666, -0.2256],
[-0.1666, 0.7994]]), tensor([1., 0., 0., 0., 1.]))6.2 Building a model with non-linearity
- Linear = straight lines
- Non-linear = non-straight lines
Artificial neural networks are a large combination of linear (straight) and non-straight (non-linear) functions which are potentially able to find patterns in data.
# Build a model with non-linear activation functions
from torch import nn
class CircleModelV2(nn.Module):
def __init__(self):
super().__init__()
self.layer_1 = nn.Linear(in_features=2, out_features=10)
self.layer_2 = nn.Linear(in_features=10, out_features=10)
self.layer_3 = nn.Linear(in_features=10, out_features=1)
self.relu = nn.ReLU() # relu is a non-linear activation function
def forward(self, x):
# Where should we put our non-linear activation functions?
return self.layer_3(self.relu(self.layer_2(self.relu(self.layer_1(x)))))
model_3 = CircleModelV2().to(device)
model_3Output
CircleModelV2( (layer_1): Linear(in_features=2, out_features=10, bias=True) (layer_2): Linear(in_features=10, out_features=10, bias=True) (layer_3): Linear(in_features=10, out_features=1, bias=True) (relu): ReLU() )
# Setup loss and optimizer
loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.SGD(model_3.parameters(),
lr=0.1)6.3 Training a model with non-linearity
len(X_test), len(y_test)Output
(200, 200)
# Random seeds
torch.manual_seed(42)
torch.cuda.manual_seed(42)
# Put all data on target device
X_train, y_train = X_train.to(device), y_train.to(device)
X_test, y_test = X_test.to(device), y_test.to(device)
# Loop through data
epochs = 1000
for epoch in range(epochs):
### Training
model_3.train()
# 1. Forward pass
y_logits = model_3(X_train).squeeze()
y_pred = torch.round(torch.sigmoid(y_logits)) # logits -> prediction probabilities -> prediction labels
# 2. Calculate the loss
loss = loss_fn(y_logits, y_train) # BCEWithLogitsLoss (takes in logits as first input)
acc = accuracy_fn(y_true=y_train,
y_pred=y_pred)
# 3. Optimizer zero grad
optimizer.zero_grad()
# 4. Loss backward
loss.backward()
# 5. Step the optimizer
optimizer.step()
### Testing
model_3.eval()
with torch.inference_mode():
test_logits = model_3(X_test).squeeze()
test_pred = torch.round(torch.sigmoid(test_logits))
test_loss = loss_fn(test_logits, y_test)
test_acc = accuracy_fn(y_true=y_test,
y_pred=test_pred)
# Print out what's this happenin'
if epoch % 100 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.4f}, Acc: {acc:.2f}% | Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.2f}%")Output
Epoch: 0 | Loss: 0.6928, Acc: 50.00% | Test Loss: 0.6931, Test Acc: 50.00% Epoch: 100 | Loss: 0.6911, Acc: 53.12% | Test Loss: 0.6910, Test Acc: 53.00% Epoch: 200 | Loss: 0.6897, Acc: 53.50% | Test Loss: 0.6894, Test Acc: 55.50% Epoch: 300 | Loss: 0.6879, Acc: 53.00% | Test Loss: 0.6872, Test Acc: 56.00% Epoch: 400 | Loss: 0.6851, Acc: 52.75% | Test Loss: 0.6840, Test Acc: 56.50% Epoch: 500 | Loss: 0.6809, Acc: 52.75% | Test Loss: 0.6793, Test Acc: 56.50% Epoch: 600 | Loss: 0.6750, Acc: 54.62% | Test Loss: 0.6727, Test Acc: 56.50% Epoch: 700 | Loss: 0.6664, Acc: 58.38% | Test Loss: 0.6630, Test Acc: 59.50% Epoch: 800 | Loss: 0.6512, Acc: 64.25% | Test Loss: 0.6472, Test Acc: 68.00% Epoch: 900 | Loss: 0.6228, Acc: 74.00% | Test Loss: 0.6208, Test Acc: 79.00%
6.4 Evaluating a model trained with non-linear activation functions
# Makes predictions
model_3.eval()
with torch.inference_mode():
y_preds = torch.round(torch.sigmoid(model_3(X_test))).squeeze()
y_preds[:10], y_test[:10]Output
(tensor([1., 0., 1., 0., 0., 1., 0., 0., 1., 0.], device='cuda:0'), tensor([1., 0., 1., 0., 1., 1., 0., 0., 1., 0.], device='cuda:0'))
# Plot decision boundaries
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("Train")
plot_decision_boundary(model_1, X_train, y_train) # model_1 = no non-linearity
plt.subplot(1, 2, 2)
plt.title("Test")
plot_decision_boundary(model_3, X_test, y_test) # model_3 = has non-linearityOutput
<Figure size 864x432 with 2 Axes>
[省略较大 image/png 输出]
Challenge: Can you improve model_3 to do better than 80% accuracy on the test data?
7. Replicating non-linear activation functions
Neural networks, rather than us telling the model what to learn, we give it the tools to discover patterns in data and it tries to figure out the patterns on its own.
And these tools are linear & non-linear functions.
# Create a tensor
A = torch.arange(-10, 10, 1, dtype=torch.float32)
A.dtypeOutput
torch.float32
AOutput
tensor([-10., -9., -8., -7., -6., -5., -4., -3., -2., -1., 0., 1.,
2., 3., 4., 5., 6., 7., 8., 9.])# Visualize the tensor
plt.plot(A); Output
<Figure size 432x288 with 1 Axes>
plt.plot(torch.relu(A));Output
<Figure size 432x288 with 1 Axes>
AOutput
tensor([-10., -9., -8., -7., -6., -5., -4., -3., -2., -1., 0., 1.,
2., 3., 4., 5., 6., 7., 8., 9.])def relu(x: torch.Tensor) -> torch.Tensor:
return torch.maximum(torch.tensor(0), x) # inputs must be tensors
relu(A)Output
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 2., 3., 4., 5., 6., 7.,
8., 9.])# Plot ReLU activation function
plt.plot(relu(A)); Output
<Figure size 432x288 with 1 Axes>
# Now let's do the same for Sigmoid = https://pytorch.org/docs/stable/generated/torch.nn.Sigmoid.html#torch.nn.Sigmoid
def sigmoid(x):
return 1 / (1 + torch.exp(-x))plt.plot(torch.sigmoid(A)); Output
<Figure size 432x288 with 1 Axes>
plt.plot(sigmoid(A));Output
<Figure size 432x288 with 1 Axes>
8. Putting it all together with a multi-class classification problem
- Binary classification = one thing or another (cat vs. dog, spam vs. not spam, fraud or not fraud)
- Multi-class classification = more than one thing or another (cat vs. dog vs. chicken)
8.1 Creating a toy multi-class dataset
# Import dependencies
import torch
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs # https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_blobs.html#sklearn.datasets.make_blobs
from sklearn.model_selection import train_test_split
# Set the hyperparameters for data creation
NUM_CLASSES = 4
NUM_FEATURES = 2
RANDOM_SEED = 42
# 1. Create multi-class data
X_blob, y_blob = make_blobs(n_samples=1000,
n_features=NUM_FEATURES,
centers=NUM_CLASSES,
cluster_std=1.5, # give the clusters a little shake up
random_state=RANDOM_SEED)
# 2. Turn data into tensors
X_blob = torch.from_numpy(X_blob).type(torch.float)
y_blob = torch.from_numpy(y_blob).type(torch.LongTensor)
# 3. Split into train and test
X_blob_train, X_blob_test, y_blob_train, y_blob_test = train_test_split(X_blob,
y_blob,
test_size=0.2,
random_state=RANDOM_SEED)
# 4. Plot data (visualize, visualize, visualize)
plt.figure(figsize=(10, 7))
plt.scatter(X_blob[:, 0], X_blob[:, 1], c=y_blob, cmap=plt.cm.RdYlBu);Output
<Figure size 720x504 with 1 Axes>
[省略较大 image/png 输出]
8.2 Building a multi-class classification model in PyTorch
# Create device agnostic code
device = "cuda" if torch.cuda.is_available() else "cpu"
deviceOutput
'cuda'
# Build a multi-class classification model
class BlobModel(nn.Module):
def __init__(self, input_features, output_features, hidden_units=8):
"""Initializes multi-class classification model.
Args:
input_features (int): Number of input features to the model
output_features (int): Number of outputs features (number of output classes)
hidden_units (int): Number of hidden units between layers, default 8
Returns:
Example:
"""
super().__init__()
self.linear_layer_stack = nn.Sequential(
nn.Linear(in_features=input_features, out_features=hidden_units),
# nn.ReLU(),
nn.Linear(in_features=hidden_units, out_features=hidden_units),
# nn.ReLU(),
nn.Linear(in_features=hidden_units, out_features=output_features)
)
def forward(self, x):
return self.linear_layer_stack(x)
# Create an instance of BlobModel and send it to the target device
model_4 = BlobModel(input_features=2,
output_features=4,
hidden_units=8).to(device)
model_4Output
BlobModel(
(linear_layer_stack): Sequential(
(0): Linear(in_features=2, out_features=8, bias=True)
(1): Linear(in_features=8, out_features=8, bias=True)
(2): Linear(in_features=8, out_features=4, bias=True)
)
)X_blob_train.shape, y_blob_train[:5]Output
(torch.Size([800, 2]), tensor([1, 0, 2, 2, 0], device='cuda:0'))
torch.unique(y_blob_train)Output
tensor([0, 1, 2, 3], device='cuda:0')
8.3 Create a loss function and an optimizer for a multi-class classification model
# Create a loss function for multi-class classification - loss function measures how wrong our model's predictions are
loss_fn = nn.CrossEntropyLoss()
# Create an optimizer for multi-class classification - optimizer updates our model parameters to try and reduce the loss
optimizer = torch.optim.SGD(params=model_4.parameters(),
lr=0.1) # learning rate is a hyperparameter you can change8.4 Getting prediction probabilities for a multi-class PyTorch model
In order to evaluate and train and test our model, we need to convert our model's outputs (logtis) to predicition probabilities and then to prediction labels.
Logits (raw output of the model) -> Pred probs (use torch.softmax) -> Pred labels (take the argmax of the prediction probabilities)
# Let's get some raw outputs of our model (logits)
model_4.eval()
with torch.inference_mode():
y_logits = model_4(X_blob_test.to(device))
y_logits[:10]Output
tensor([[-1.2549, -0.8112, -1.4795, -0.5696],
[ 1.7168, -1.2270, 1.7367, 2.1010],
[ 2.2400, 0.7714, 2.6020, 1.0107],
[-0.7993, -0.3723, -0.9138, -0.5388],
[-0.4332, -1.6117, -0.6891, 0.6852],
[ 2.0878, -1.3728, 2.1248, 2.5052],
[ 1.8310, 0.8851, 2.1674, 0.6006],
[ 0.1412, -1.4742, -0.0360, 1.0373],
[ 2.9426, 0.7047, 3.3670, 1.6184],
[-0.0645, -1.5006, -0.2666, 0.8940]], device='cuda:0')y_blob_test[:10]Output
tensor([1, 3, 2, 1, 0, 3, 2, 0, 2, 0], device='cuda:0')
# Convert our model's logit outputs to prediction probabilities
y_pred_probs = torch.softmax(y_logits, dim=1)
print(y_logits[:5])
print(y_pred_probs[:5])Output
tensor([[-1.2549, -0.8112, -1.4795, -0.5696],
[ 1.7168, -1.2270, 1.7367, 2.1010],
[ 2.2400, 0.7714, 2.6020, 1.0107],
[-0.7993, -0.3723, -0.9138, -0.5388],
[-0.4332, -1.6117, -0.6891, 0.6852]], device='cuda:0')
tensor([[0.1872, 0.2918, 0.1495, 0.3715],
[0.2824, 0.0149, 0.2881, 0.4147],
[0.3380, 0.0778, 0.4854, 0.0989],
[0.2118, 0.3246, 0.1889, 0.2748],
[0.1945, 0.0598, 0.1506, 0.5951]], device='cuda:0')
# Convert our model's prediction probabilities to prediction labels
y_preds = torch.argmax(y_pred_probs, dim=1)
y_predsOutput
tensor([3, 3, 2, 1, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 2,
2, 2, 3, 3, 3, 3, 3, 1, 1, 2, 1, 2, 1, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3,
3, 3, 1, 3, 3, 1, 3, 2, 3, 1, 3, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 2, 3, 3, 3, 3, 1, 3, 2, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3, 1, 3, 3, 3,
1, 3, 3, 2, 3, 3, 3, 3, 2, 3, 1, 3, 3, 2, 1, 1, 3, 2, 2, 3, 3, 3, 1, 2,
2, 3, 3, 1, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 1, 1, 3, 2, 2,
2, 2, 3, 3, 3, 2, 2, 1, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 2, 3,
2, 2, 2, 3, 3, 1, 1, 1, 1, 1, 3, 1, 3, 2, 2, 3, 2, 2, 3, 3, 2, 2, 3, 3,
1, 3, 2, 3, 3, 1, 2, 3], device='cuda:0')y_blob_testOutput
tensor([1, 3, 2, 1, 0, 3, 2, 0, 2, 0, 0, 1, 0, 0, 0, 3, 3, 2, 3, 3, 3, 0, 1, 2,
2, 2, 3, 0, 1, 0, 3, 1, 1, 3, 1, 2, 1, 3, 0, 2, 0, 3, 3, 2, 0, 3, 1, 1,
0, 3, 1, 0, 1, 1, 3, 2, 1, 1, 3, 2, 2, 0, 3, 2, 2, 0, 0, 3, 3, 0, 0, 3,
3, 3, 2, 3, 3, 3, 3, 1, 0, 2, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3, 1, 3, 3, 3,
1, 0, 3, 2, 0, 0, 3, 0, 2, 3, 1, 0, 3, 2, 1, 1, 0, 2, 2, 3, 0, 0, 1, 2,
2, 3, 0, 1, 2, 0, 0, 0, 2, 3, 1, 2, 3, 2, 0, 3, 0, 0, 1, 1, 1, 0, 2, 2,
2, 2, 0, 3, 3, 2, 2, 1, 3, 2, 0, 0, 3, 3, 2, 1, 2, 0, 3, 2, 0, 3, 2, 0,
2, 2, 2, 0, 3, 1, 1, 1, 1, 1, 3, 1, 0, 2, 2, 1, 2, 2, 0, 1, 2, 2, 0, 0,
1, 3, 2, 0, 3, 1, 2, 1], device='cuda:0')8.5 Creating a training loop and testing loop for a multi-class PyTorch model
y_blob_train.dtypeOutput
torch.int64
# Fit the multi-class model to the data
torch.manual_seed(42)
torch.cuda.manual_seed(42)
# Set number of epochs
epochs = 100
# Put data to the target device
X_blob_train, y_blob_train = X_blob_train.to(device), y_blob_train.to(device)
X_blob_test, y_blob_test = X_blob_test.to(device), y_blob_test.to(device)
# Loop through data
for epoch in range(epochs):
### Training
model_4.train()
y_logits = model_4(X_blob_train)
y_pred = torch.softmax(y_logits, dim=1).argmax(dim=1)
loss = loss_fn(y_logits, y_blob_train)
acc = accuracy_fn(y_true=y_blob_train,
y_pred=y_pred)
optimizer.zero_grad()
loss.backward()
optimizer.step()
### Testing
model_4.eval()
with torch.inference_mode():
test_logits = model_4(X_blob_test)
test_preds = torch.softmax(test_logits, dim=1).argmax(dim=1)
test_loss = loss_fn(test_logits, y_blob_test)
test_acc = accuracy_fn(y_true=y_blob_test,
y_pred=test_preds)
# Print out what's happenin'
if epoch % 10 == 0:
print(f"Epoch: {epoch} | Loss: {loss:.4f}, Acc: {acc:.2f}% | Test loss: {test_loss:.4f}, Test acc: {test_acc:.2f}%")Output
Epoch: 0 | Loss: 1.0432, Acc: 65.50% | Test loss: 0.5786, Test acc: 95.50% Epoch: 10 | Loss: 0.1440, Acc: 99.12% | Test loss: 0.1304, Test acc: 99.00% Epoch: 20 | Loss: 0.0806, Acc: 99.12% | Test loss: 0.0722, Test acc: 99.50% Epoch: 30 | Loss: 0.0592, Acc: 99.12% | Test loss: 0.0513, Test acc: 99.50% Epoch: 40 | Loss: 0.0489, Acc: 99.00% | Test loss: 0.0410, Test acc: 99.50% Epoch: 50 | Loss: 0.0429, Acc: 99.00% | Test loss: 0.0349, Test acc: 99.50% Epoch: 60 | Loss: 0.0391, Acc: 99.00% | Test loss: 0.0308, Test acc: 99.50% Epoch: 70 | Loss: 0.0364, Acc: 99.00% | Test loss: 0.0280, Test acc: 99.50% Epoch: 80 | Loss: 0.0345, Acc: 99.00% | Test loss: 0.0259, Test acc: 99.50% Epoch: 90 | Loss: 0.0330, Acc: 99.12% | Test loss: 0.0242, Test acc: 99.50%
8.6 Making and evaluating predictions with a PyTorch multi-class model
# Make predictions
model_4.eval()
with torch.inference_mode():
y_logits = model_4(X_blob_test)
# View the first 10 predictions
y_logits[:10]Output
tensor([[ 4.3377, 10.3539, -14.8948, -9.7642],
[ 5.0142, -12.0371, 3.3860, 10.6699],
[ -5.5885, -13.3448, 20.9894, 12.7711],
[ 1.8400, 7.5599, -8.6016, -6.9942],
[ 8.0726, 3.2906, -14.5998, -3.6186],
[ 5.5844, -14.9521, 5.0168, 13.2890],
[ -5.9739, -10.1913, 18.8655, 9.9179],
[ 7.0755, -0.7601, -9.5531, 0.1736],
[ -5.5918, -18.5990, 25.5309, 17.5799],
[ 7.3142, 0.7197, -11.2017, -1.2011]], device='cuda:0')# Go from logits -> Prediction probabilities
y_pred_probs = torch.softmax(y_logits, dim=1)
y_pred_probs[:10]Output
tensor([[2.4332e-03, 9.9757e-01, 1.0804e-11, 1.8271e-09],
[3.4828e-03, 1.3698e-10, 6.8363e-04, 9.9583e-01],
[2.8657e-12, 1.2267e-15, 9.9973e-01, 2.6959e-04],
[3.2692e-03, 9.9673e-01, 9.5436e-08, 4.7620e-07],
[9.9168e-01, 8.3089e-03, 1.4120e-10, 8.2969e-06],
[4.5039e-04, 5.4288e-13, 2.5532e-04, 9.9929e-01],
[1.6306e-11, 2.4030e-13, 9.9987e-01, 1.3003e-04],
[9.9860e-01, 3.9485e-04, 5.9938e-08, 1.0045e-03],
[3.0436e-14, 6.8305e-20, 9.9965e-01, 3.5218e-04],
[9.9843e-01, 1.3657e-03, 9.0768e-09, 2.0006e-04]], device='cuda:0')# Go from pred probs to pred labels
y_preds = torch.argmax(y_pred_probs, dim=1)
y_preds[:10]Output
tensor([1, 3, 2, 1, 0, 3, 2, 0, 2, 0], device='cuda:0')
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title("Train")
plot_decision_boundary(model_4, X_blob_train, y_blob_train)
plt.subplot(1, 2, 2)
plt.title("Test")
plot_decision_boundary(model_4, X_blob_test, y_blob_test)Output
<Figure size 864x432 with 2 Axes>
[省略较大 image/png 输出]
9. A few more classification metrics... (to evaluate our classification model)
- Accuracy - out of 100 samples, how many does our model get right?
- Precision
- Recall
- F1-score
- Confusion matrix
- Classification report
See this article for when to use precision/recall - https://towardsdatascience.com/beyond-accuracy-precision-and-recall-3da06bea9f6c
If you want access to a lot of PyTorch metrics, see TorchMetrics - https://torchmetrics.readthedocs.io/en/latest/
!pip install torchmetricsOutput
Collecting torchmetrics Downloading torchmetrics-0.7.2-py3-none-any.whl (397 kB) [?25l [K |▉ | 10 kB 23.4 MB/s eta 0:00:01 [K |█▋ | 20 kB 27.3 MB/s eta 0:00:01 [K |██▌ | 30 kB 22.5 MB/s eta 0:00:01 [K |███▎ | 40 kB 18.3 MB/s eta 0:00:01 [K |████▏ | 51 kB 11.7 MB/s eta 0:00:01 [K |█████ | 61 kB 13.5 MB/s eta 0:00:01 [K |█████▊ | 71 kB 12.5 MB/s eta 0:00:01 [K |██████▋ | 81 kB 12.1 MB/s eta 0:00:01 [K |███████▍ | 92 kB 13.2 MB/s eta 0:00:01 [K |████████▎ | 102 kB 12.6 MB/s eta 0:00:01 [K |█████████ | 112 kB 12.6 MB/s eta 0:00:01 [K |██████████ | 122 kB 12.6 MB/s eta 0:00:01 [K |██████████▊ | 133 kB 12.6 MB/s eta 0:00:01 [K |███████████▌ | 143 kB 12.6 MB/s eta 0:00:01 [K |████████████▍ | 153 kB 12.6 MB/s eta 0:00:01 [K |█████████████▏ | 163 kB 12.6 MB/s eta 0:00:01 [K |██████████████ | 174 kB 12.6 MB/s eta 0:00:01 [K |██████████████▉ | 184 kB 12.6 MB/s eta 0:00:01 [K |███████████████▊ | 194 kB 12.6 MB/s eta 0:00:01 [K |████████████████▌ | 204 kB 12.6 MB/s eta 0:00:01 [K |█████████████████▎ | 215 kB 12.6 MB/s eta 0:00:01 [K |██████████████████▏ | 225 kB 12.6 MB/s eta 0:00:01 [K |███████████████████ | 235 kB 12.6 MB/s eta 0:00:01 [K |███████████████████▉ | 245 kB 12.6 MB/s eta 0:00:01 [K |████████████████████▋ | 256 kB 12.6 MB/s eta 0:00:01 [K |█████████████████████▌ | 266 kB 12.6 MB/s eta 0:00:01 [K |██████████████████████▎ | 276 kB 12.6 MB/s eta 0:00:01 [K |███████████████████████ | 286 kB 12.6 MB/s eta 0:00:01 [K |████████████████████████ | 296 kB 12.6 MB/s eta 0:00:01 [K |████████████████████████▊ | 307 kB 12.6 MB/s eta 0:00:01 [K |█████████████████████████▋ | 317 kB 12.6 MB/s eta 0:00:01 [K |██████████████████████████▍ | 327 kB 12.6 MB/s eta 0:00:01 [K |███████████████████████████▎ | 337 kB 12.6 MB/s eta 0:00:01 [K |████████████████████████████ | 348 kB 12.6 MB/s eta 0:00:01 [K |████████████████████████████▉ | 358 kB 12.6 MB/s eta 0:00:01 [K |█████████████████████████████▊ | 368 kB 12.6 MB/s eta 0:00:01 [K |██████████████████████████████▌ | 378 kB 12.6 MB/s eta 0:00:01 [K |███████████████████████████████▍| 389 kB 12.6 MB/s eta 0:00:01 [K |████████████████████████████████| 397 kB 12.6 MB/s [?25hRequirement already satisfied: torch>=1.3.1 in /usr/local/lib/python3.7/dist-packages (from torchmetrics) (1.10.0+cu111) Collecting pyDeprecate==0.3.* Downloading pyDeprecate-0.3.2-py3-none-any.whl (10 kB) Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from torchmetrics) (21.3) Requirement already satisfied: numpy>=1.17.2 in /usr/local/lib/python3.7/dist-packages (from torchmetrics) (1.21.5) Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch>=1.3.1->torchmetrics) (3.10.0.2) Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->torchmetrics) (3.0.7) Installing collected packages: pyDeprecate, torchmetrics Successfully installed pyDeprecate-0.3.2 torchmetrics-0.7.2
from torchmetrics import Accuracy
# Setup metric
torchmetric_accuracy = Accuracy().to(device)
# Calculuate accuracy
torchmetric_accuracy(y_preds, y_blob_test)Output
tensor(0.9950, device='cuda:0')
torchmetric_accuracy.deviceOutput
device(type='cpu')
Exercises & Extra-curriculum
See exercises and extra-curriculum here: https://www.learnpytorch.io/02_pytorch_classification/#exercises
