Skip to content

Commit d01c4b9

Browse files
revisions to code examples
1 parent b1e2379 commit d01c4b9

File tree

3 files changed

+396
-0
lines changed

3 files changed

+396
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
"""
2+
Example code of a simple RNN, GRU, LSTM on the MNIST dataset.
3+
4+
Programmed by Aladdin Persson <aladdin.persson at hotmail dot com>
5+
* 2020-05-09 Initial coding
6+
7+
"""
8+
9+
# Imports
10+
import torch
11+
import torchvision # torch package for vision related things
12+
import torch.nn.functional as F # Parameterless functions, like (some) activation functions
13+
import torchvision.datasets as datasets # Standard datasets
14+
import torchvision.transforms as transforms # Transformations we can perform on our dataset for augmentation
15+
from torch import optim # For optimizers like SGD, Adam, etc.
16+
from torch import nn # All neural network modules
17+
from torch.utils.data import DataLoader # Gives easier dataset managment by creating mini batches etc.
18+
from tqdm import tqdm # For a nice progress bar!
19+
20+
# Set device
21+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
22+
23+
# Hyperparameters
24+
input_size = 28
25+
hidden_size = 256
26+
num_layers = 2
27+
num_classes = 10
28+
sequence_length = 28
29+
learning_rate = 0.005
30+
batch_size = 64
31+
num_epochs = 3
32+
33+
# Recurrent neural network (many-to-one)
34+
class RNN(nn.Module):
35+
def __init__(self, input_size, hidden_size, num_layers, num_classes):
36+
super(RNN, self).__init__()
37+
self.hidden_size = hidden_size
38+
self.num_layers = num_layers
39+
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
40+
self.fc = nn.Linear(hidden_size * sequence_length, num_classes)
41+
42+
def forward(self, x):
43+
# Set initial hidden and cell states
44+
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
45+
46+
# Forward propagate LSTM
47+
out, _ = self.rnn(x, h0)
48+
out = out.reshape(out.shape[0], -1)
49+
50+
# Decode the hidden state of the last time step
51+
out = self.fc(out)
52+
return out
53+
54+
55+
# Recurrent neural network with GRU (many-to-one)
56+
class RNN_GRU(nn.Module):
57+
def __init__(self, input_size, hidden_size, num_layers, num_classes):
58+
super(RNN_GRU, self).__init__()
59+
self.hidden_size = hidden_size
60+
self.num_layers = num_layers
61+
self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True)
62+
self.fc = nn.Linear(hidden_size * sequence_length, num_classes)
63+
64+
def forward(self, x):
65+
# Set initial hidden and cell states
66+
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
67+
68+
# Forward propagate LSTM
69+
out, _ = self.gru(x, h0)
70+
out = out.reshape(out.shape[0], -1)
71+
72+
# Decode the hidden state of the last time step
73+
out = self.fc(out)
74+
return out
75+
76+
77+
# Recurrent neural network with LSTM (many-to-one)
78+
class RNN_LSTM(nn.Module):
79+
def __init__(self, input_size, hidden_size, num_layers, num_classes):
80+
super(RNN_LSTM, self).__init__()
81+
self.hidden_size = hidden_size
82+
self.num_layers = num_layers
83+
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
84+
self.fc = nn.Linear(hidden_size * sequence_length, num_classes)
85+
86+
def forward(self, x):
87+
# Set initial hidden and cell states
88+
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
89+
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
90+
91+
# Forward propagate LSTM
92+
out, _ = self.lstm(
93+
x, (h0, c0)
94+
) # out: tensor of shape (batch_size, seq_length, hidden_size)
95+
out = out.reshape(out.shape[0], -1)
96+
97+
# Decode the hidden state of the last time step
98+
out = self.fc(out)
99+
return out
100+
101+
102+
# Load Data
103+
train_dataset = datasets.MNIST(root="dataset/", train=True, transform=transforms.ToTensor(), download=True)
104+
test_dataset = datasets.MNIST(root="dataset/", train=False, transform=transforms.ToTensor(), download=True)
105+
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
106+
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
107+
108+
# Initialize network (try out just using simple RNN, or GRU, and then compare with LSTM)
109+
model = RNN_LSTM(input_size, hidden_size, num_layers, num_classes).to(device)
110+
111+
# Loss and optimizer
112+
criterion = nn.CrossEntropyLoss()
113+
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
114+
115+
# Train Network
116+
for epoch in range(num_epochs):
117+
for batch_idx, (data, targets) in enumerate(tqdm(train_loader)):
118+
# Get data to cuda if possible
119+
data = data.to(device=device).squeeze(1)
120+
targets = targets.to(device=device)
121+
122+
# forward
123+
scores = model(data)
124+
loss = criterion(scores, targets)
125+
126+
# backward
127+
optimizer.zero_grad()
128+
loss.backward()
129+
130+
# gradient descent update step/adam step
131+
optimizer.step()
132+
133+
# Check accuracy on training & test to see how good our model
134+
def check_accuracy(loader, model):
135+
num_correct = 0
136+
num_samples = 0
137+
138+
# Set model to eval
139+
model.eval()
140+
141+
with torch.no_grad():
142+
for x, y in loader:
143+
x = x.to(device=device).squeeze(1)
144+
y = y.to(device=device)
145+
146+
scores = model(x)
147+
_, predictions = scores.max(1)
148+
num_correct += (predictions == y).sum()
149+
num_samples += predictions.size(0)
150+
151+
# Toggle model back to train
152+
model.train()
153+
return num_correct / num_samples
154+
155+
156+
print(f"Accuracy on training set: {check_accuracy(train_loader, model)*100:2f}")
157+
print(f"Accuracy on test set: {check_accuracy(test_loader, model)*100:.2f}")
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
A simple walkthrough of how to code a convolutional neural network (CNN)
3+
using the PyTorch library. For demonstration we train it on the very
4+
common MNIST dataset of handwritten digits. In this code we go through
5+
how to create the network as well as initialize a loss function, optimizer,
6+
check accuracy and more.
7+
8+
Programmed by Aladdin Persson
9+
* 2020-04-08: Initial coding
10+
* 2021-03-24: More detailed comments and small revision of the code
11+
12+
"""
13+
14+
# Imports
15+
import torch
16+
import torchvision # torch package for vision related things
17+
import torch.nn.functional as F # Parameterless functions, like (some) activation functions
18+
import torchvision.datasets as datasets # Standard datasets
19+
import torchvision.transforms as transforms # Transformations we can perform on our dataset for augmentation
20+
from torch import optim # For optimizers like SGD, Adam, etc.
21+
from torch import nn # All neural network modules
22+
from torch.utils.data import DataLoader # Gives easier dataset managment by creating mini batches etc.
23+
from tqdm import tqdm # For nice progress bar!
24+
25+
# Simple CNN
26+
class CNN(nn.Module):
27+
def __init__(self, in_channels=1, num_classes=10):
28+
super(CNN, self).__init__()
29+
self.conv1 = nn.Conv2d(
30+
in_channels=in_channels,
31+
out_channels=8,
32+
kernel_size=(3, 3),
33+
stride=(1, 1),
34+
padding=(1, 1),
35+
)
36+
self.pool = nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2))
37+
self.conv2 = nn.Conv2d(
38+
in_channels=8,
39+
out_channels=16,
40+
kernel_size=(3, 3),
41+
stride=(1, 1),
42+
padding=(1, 1),
43+
)
44+
self.fc1 = nn.Linear(16 * 7 * 7, num_classes)
45+
46+
def forward(self, x):
47+
x = F.relu(self.conv1(x))
48+
x = self.pool(x)
49+
x = F.relu(self.conv2(x))
50+
x = self.pool(x)
51+
x = x.reshape(x.shape[0], -1)
52+
x = self.fc1(x)
53+
return x
54+
55+
56+
# Set device
57+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
58+
59+
# Hyperparameters
60+
in_channels = 1
61+
num_classes = 10
62+
learning_rate = 0.001
63+
batch_size = 64
64+
num_epochs = 3
65+
66+
# Load Data
67+
train_dataset = datasets.MNIST(root="dataset/", train=True, transform=transforms.ToTensor(), download=True)
68+
test_dataset = datasets.MNIST(root="dataset/", train=False, transform=transforms.ToTensor(), download=True)
69+
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
70+
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
71+
72+
# Initialize network
73+
model = CNN(in_channels=in_channels, num_classes=num_classes).to(device)
74+
75+
# Loss and optimizer
76+
criterion = nn.CrossEntropyLoss()
77+
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
78+
79+
# Train Network
80+
for epoch in range(num_epochs):
81+
for batch_idx, (data, targets) in enumerate(tqdm(train_loader)):
82+
# Get data to cuda if possible
83+
data = data.to(device=device)
84+
targets = targets.to(device=device)
85+
86+
# forward
87+
scores = model(data)
88+
loss = criterion(scores, targets)
89+
90+
# backward
91+
optimizer.zero_grad()
92+
loss.backward()
93+
94+
# gradient descent or adam step
95+
optimizer.step()
96+
97+
# Check accuracy on training & test to see how good our model
98+
def check_accuracy(loader, model):
99+
num_correct = 0
100+
num_samples = 0
101+
model.eval()
102+
103+
with torch.no_grad():
104+
for x, y in loader:
105+
x = x.to(device=device)
106+
y = y.to(device=device)
107+
108+
scores = model(x)
109+
_, predictions = scores.max(1)
110+
num_correct += (predictions == y).sum()
111+
num_samples += predictions.size(0)
112+
113+
114+
model.train()
115+
return num_correct/num_samples
116+
117+
118+
print(f"Accuracy on training set: {check_accuracy(train_loader, model)*100:.2f}")
119+
print(f"Accuracy on test set: {check_accuracy(test_loader, model)*100:.2f}")
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""
2+
A simple walkthrough of how to code a fully connected neural network
3+
using the PyTorch library. For demonstration we train it on the very
4+
common MNIST dataset of handwritten digits. In this code we go through
5+
how to create the network as well as initialize a loss function, optimizer,
6+
check accuracy and more.
7+
8+
Programmed by Aladdin Persson
9+
* 2020-04-08: Initial coding
10+
* 2021-03-24: Added more detailed comments also removed part of
11+
check_accuracy which would only work specifically on MNIST.
12+
13+
"""
14+
15+
# Imports
16+
import torch
17+
import torchvision # torch package for vision related things
18+
import torch.nn.functional as F # Parameterless functions, like (some) activation functions
19+
import torchvision.datasets as datasets # Standard datasets
20+
import torchvision.transforms as transforms # Transformations we can perform on our dataset for augmentation
21+
from torch import optim # For optimizers like SGD, Adam, etc.
22+
from torch import nn # All neural network modules
23+
from torch.utils.data import DataLoader # Gives easier dataset managment by creating mini batches etc.
24+
from tqdm import tqdm # For nice progress bar!
25+
26+
# Here we create our simple neural network. For more details here we are subclassing and
27+
# inheriting from nn.Module, this is the most general way to create your networks and
28+
# allows for more flexibility. I encourage you to also check out nn.Sequential which
29+
# would be easier to use in this scenario but I wanted to show you something that
30+
# "always" works.
31+
class NN(nn.Module):
32+
def __init__(self, input_size, num_classes):
33+
super(NN, self).__init__()
34+
# Our first linear layer take input_size, in this case 784 nodes to 50
35+
# and our second linear layer takes 50 to the num_classes we have, in
36+
# this case 10.
37+
self.fc1 = nn.Linear(input_size, 50)
38+
self.fc2 = nn.Linear(50, num_classes)
39+
40+
def forward(self, x):
41+
"""
42+
x here is the mnist images and we run it through fc1, fc2 that we created above.
43+
we also add a ReLU activation function in between and for that (since it has no parameters)
44+
I recommend using nn.functional (F)
45+
"""
46+
47+
x = F.relu(self.fc1(x))
48+
x = self.fc2(x)
49+
return x
50+
51+
52+
# Set device cuda for GPU if it's available otherwise run on the CPU
53+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
54+
55+
# Hyperparameters of our neural network which depends on the dataset, and
56+
# also just experimenting to see what works well (learning rate for example).
57+
input_size = 784
58+
num_classes = 10
59+
learning_rate = 0.001
60+
batch_size = 64
61+
num_epochs = 3
62+
63+
# Load Training and Test data
64+
train_dataset = datasets.MNIST(root="dataset/", train=True, transform=transforms.ToTensor(), download=True)
65+
test_dataset = datasets.MNIST(root="dataset/", train=False, transform=transforms.ToTensor(), download=True)
66+
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
67+
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
68+
69+
# Initialize network
70+
model = NN(input_size=input_size, num_classes=num_classes).to(device)
71+
72+
# Loss and optimizer
73+
criterion = nn.CrossEntropyLoss()
74+
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
75+
76+
# Train Network
77+
for epoch in range(num_epochs):
78+
for batch_idx, (data, targets) in enumerate(tqdm(train_loader)):
79+
# Get data to cuda if possible
80+
data = data.to(device=device)
81+
targets = targets.to(device=device)
82+
83+
# Get to correct shape
84+
data = data.reshape(data.shape[0], -1)
85+
86+
# forward
87+
scores = model(data)
88+
loss = criterion(scores, targets)
89+
90+
# backward
91+
optimizer.zero_grad()
92+
loss.backward()
93+
94+
# gradient descent or adam step
95+
optimizer.step()
96+
97+
98+
# Check accuracy on training & test to see how good our model
99+
def check_accuracy(loader, model):
100+
num_correct = 0
101+
num_samples = 0
102+
model.eval()
103+
104+
with torch.no_grad():
105+
for x, y in loader:
106+
x = x.to(device=device)
107+
y = y.to(device=device)
108+
x = x.reshape(x.shape[0], -1)
109+
110+
scores = model(x)
111+
_, predictions = scores.max(1)
112+
num_correct += (predictions == y).sum()
113+
num_samples += predictions.size(0)
114+
115+
model.train()
116+
return num_correct/num_samples
117+
118+
119+
print(f"Accuracy on training set: {check_accuracy(train_loader, model)*100:.2f}")
120+
print(f"Accuracy on test set: {check_accuracy(test_loader, model)*100:.2f}")

0 commit comments

Comments
 (0)