-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtestCNN.py
217 lines (164 loc) · 8.03 KB
/
testCNN.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
from __future__ import print_function
import argparse
import os
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torch.utils.tensorboard import SummaryWriter
from ConvNet import ConvNet
import argparse
import numpy as np
def train(model, device, train_loader, optimizer, criterion, epoch, batch_size, writer):
'''
Trains the model for an epoch and optimizes it.
model: The model to train. Should already be in correct device.
device: 'cuda' or 'cpu'.
train_loader: dataloader for training samples.
optimizer: optimizer to use for model parameter updates.
criterion: used to compute loss for prediction and target
epoch: Current epoch. Only used for logging.
batch_size: Batch size used. Only used for logging.
'''
# Set model to train mode before each epoch
model.train()
# Empty list to store losses
losses = []
correct = 0
# Iterate over entire training samples (1 epoch)
for batch_idx, batch_sample in enumerate(train_loader):
data, target = batch_sample
# Push data/label to correct device
data, target = data.to(device), target.to(device)
# Reset optimizer gradients. Avoids grad accumulation (accumulation used in RNN).
optimizer.zero_grad()
# Do forward pass for current set of data
output = model(data)
# Compute loss based on criterion
loss = criterion(output, target)
# Computes gradient based on final loss
loss.backward()
# Store loss
losses.append(loss.item())
# Optimize model parameters based on learning rate and gradient
optimizer.step()
# Get predicted index by selecting maximum log-probability
pred = output.argmax(dim=1, keepdim=True)
# Count correct predictions overall
correct += pred.eq(target.view_as(pred)).sum().item()
train_loss = float(np.mean(losses))
train_acc = correct / ((batch_idx+1) * batch_size)
output = 'Train set: Epoch: {} Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)'.format( epoch,
train_loss, correct, (batch_idx+1) * batch_size, 100. * train_acc)
writer.add_text('Train', output, epoch)
print(output)
return train_loss, train_acc
def test(model, device, test_loader, epoch, writer):
'''
Tests the model.
model: The model to train. Should already be in correct device.
device: 'cuda' or 'cpu'.
test_loader: dataloader for test samples.
'''
# Set model to eval mode to notify all layers.
model.eval()
losses = []
correct = 0
# Set torch.no_grad() to disable gradient computation and backpropagation
with torch.no_grad():
for batch_idx, sample in enumerate(test_loader):
data, target = sample
data, target = data.to(device), target.to(device)
# Predict for data by doing forward pass
output = model(data)
# Compute loss based on same criterion as training
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)
# Append loss to overall test loss
losses.append(loss.item())
# Get predicted index by selecting maximum log-probability
pred = output.argmax(dim=1, keepdim=True)
# Count correct predictions overall
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss = float(np.mean(losses))
accuracy = 100. * correct / len(test_loader.dataset)
output = 'Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)'.format(
test_loss, correct, len(test_loader.dataset), accuracy)
writer.add_text('Test', output, epoch)
print('Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset), accuracy))
return test_loss, accuracy
def run_main(FLAGS):
writer = SummaryWriter(FLAGS.log_dir)
# Check if cuda is available
use_cuda = torch.cuda.is_available()
# Set proper device based on cuda availability
device = torch.device("cuda" if use_cuda else "cpu")
print("Torch device selected: ", device)
# Initialize the model and send to device
model = ConvNet(FLAGS.mode).to(device)
# Define loss function.
criterion = nn.CrossEntropyLoss()
# Define optimizer function.
optimizer = optim.SGD(model.parameters(), lr=FLAGS.learning_rate, momentum=0.9)
# Create transformations to apply to each data sample
# Can specify variations such as image flip, color flip, random crop, ...
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# Load datasets for training and testing
# Inbuilt datasets available in torchvision (check documentation online)
dataset1 = datasets.MNIST('./data/', train=True, download=True,
transform=transform)
dataset2 = datasets.MNIST('./data/', train=False,
transform=transform)
train_loader = DataLoader(dataset1, batch_size = FLAGS.batch_size,
shuffle=True, num_workers=4)
test_loader = DataLoader(dataset2, batch_size = FLAGS.batch_size,
shuffle=False, num_workers=4)
best_accuracy = 0.0
# Run training for n_epochs specified in config
for epoch in range(1, FLAGS.num_epochs + 1):
train_loss, train_accuracy = train(model, device, train_loader,
optimizer, criterion, epoch, FLAGS.batch_size, writer)
test_loss, test_accuracy = test(model, device, test_loader, epoch, writer)
if test_accuracy > best_accuracy:
best_accuracy = test_accuracy
print("epoch: {:d}, best test accuracy: {:2.2f}".format(epoch, best_accuracy))
writer.add_scalar('Loss/train', train_loss, epoch)
writer.add_scalar('Loss/test', test_loss, epoch)
writer.add_scalar('Accuracy/train', train_accuracy, epoch)
writer.add_scalar('Accuracy/test', test_accuracy, epoch)
print("accuracy is {:2.2f}".format(best_accuracy))
print("Training and evaluation finished")
# python testCNN.py --mode 1 --learning_rate 0.0005 --num_epochs 60 --batch_size 10 --log_dir log1 > log1/output.txt
# python testCNN.py --mode 2 --learning_rate 0.0005 --num_epochs 60 --batch_size 10 --log_dir log2 > log2/output.txt
# python testCNN.py --mode 3 --learning_rate 0.0005 --num_epochs 60 --batch_size 10 --log_dir log3 > log3/output.txt
# python testCNN.py --mode 4 --learning_rate 0.0005 --num_epochs 60 --batch_size 10 --log_dir log4 > log4/output.txt
# python testCNN.py --mode 5 --learning_rate 0.0005 --num_epochs 40 --batch_size 10 --log_dir log5 > log5/output.txt
if __name__ == '__main__':
# Set parameters for Sparse Autoencoder
parser = argparse.ArgumentParser('CNN Exercise.')
parser.add_argument('--mode',
type=int, default=1,
help='Select mode between 1-5.')
parser.add_argument('--learning_rate',
type=float, default=0.1,
help='Initial learning rate.')
parser.add_argument('--num_epochs',
type=int,
default=60,
help='Number of epochs to run trainer.')
parser.add_argument('--batch_size',
type=int, default=10,
help='Batch size. Must divide evenly into the dataset sizes.')
parser.add_argument('--log_dir',
type=str,
default='logs',
help='Directory to put logging.')
FLAGS = None
FLAGS, unparsed = parser.parse_known_args()
run_main(FLAGS)