-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtrain.py
More file actions
187 lines (162 loc) · 7.27 KB
/
Copy pathtrain.py
File metadata and controls
187 lines (162 loc) · 7.27 KB
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
import argparse
import os
import torch
from torchvision import datasets as ds
from torchvision import transforms as tf
from torch import nn, optim
from torch.utils.data import DataLoader
from classifier import img_classifier, fc_net, freeze_parameters, save_classifier
def folder_count(path):
count = 0
for file in os.listdir(path):
child = os.path.join(path, file)
if os.path.isdir(child):
count += 1
return count
def data_preprocess(train_dir, valid_dir, test_dir, mean, std, batch_size):
img_transforms = {'train' : tf.Compose([tf.RandomRotation(30),
tf.RandomResizedCrop(224),
tf.RandomHorizontalFlip(),
tf.ToTensor(),
tf.Normalize(mean, std)]),
'valid' : tf.Compose([tf.Resize(256),
tf.CenterCrop(224),
tf.ToTensor(),
tf.Normalize(mean, std)]),
'test' : tf.Compose([tf.Resize(256),
tf.CenterCrop(224),
tf.ToTensor(),
tf.Normalize(mean, std)]) }
img_datasets = {'train' : ds.ImageFolder(train_dir,
transform=img_transforms['train']),
'valid' : ds.ImageFolder(valid_dir,
transform=img_transforms['valid']),
'test' : ds.ImageFolder(test_dir,
transform=img_transforms['test']) }
dataloaders = {'train' : DataLoader(img_datasets['train'],
batch_size=batch_size,
shuffle=True),
'valid' : DataLoader(img_datasets['valid'],
batch_size=batch_size,
shuffle=True),
'test' : DataLoader(img_datasets['test'],
batch_size=batch_size,
shuffle=True) }
return img_datasets, dataloaders
def train_classifer(classifier, dataloaders, device, epochs, print_every=20):
'''
Trains and validates the classifier
Arguments
---------
classifier: class
dataloaders: torch.utils.data.DataLoader
device: str
epochs: int
print_every: int
'''
print("Training...")
train_loss = 0
steps = 0
classifier.model.to(device)
for epoch in range(epochs):
classifier.model.train()
for images, labels in dataloaders['train']:
steps += 1
images, labels = images.to(device), labels.to(device)
classifier.optimizer.zero_grad()
# Loss and gradient calculation
output = classifier.model(images)
loss = classifier.criterion(output, labels)
loss.backward()
classifier.optimizer.step()
train_loss += loss.item() / print_every
# Validation
if steps % print_every == 0:
classifier.model.eval()
valid_loss, valid_accuracy = validate_classifier(
classifier, dataloaders, device)
print("Epoch: {}/{}...".format(epoch+1, epochs),
"Training loss: {:.3f}...".format(train_loss),
"Validation loss: {:.3f}...".format(valid_loss),
"Validation accuracy: {:.3f}...".format(valid_accuracy),)
train_loss = 0
classifier.model.train()
print("Training complete!")
def validate_classifier(classifier, dataloaders, device):
'''
Calculates the validation loss and accuracy for the classifier
Arguments
---------
classifier: nn.Module
dataloaders: torch.utils.data.DataLoader
device: str
'''
steps = 0
loss = 0
accuracy = 0
with torch.no_grad():
for images, labels in dataloaders['valid']:
steps += 1
images, labels = images.to(device), labels.to(device)
output = classifier.model(images)
loss += classifier.criterion(output, labels).item()
pred_classes = torch.exp(output).max(dim=1)[1]
corr_classes = (labels.data == pred_classes).type(torch.FloatTensor)
accuracy += corr_classes.mean()
return loss/steps, accuracy/steps
def test_classifier(classifier, dataloaders, device):
'''
Tests the classifier
Arguments
---------
classifier: nn.Module
dataloaders: torch.utils.data.DataLoader
device: str
'''
print("Testing...")
accuracy = 0
steps = 0
classifier.model.eval()
classifier.model.to(device)
for images, labels in dataloaders['test']:
steps += 1
images, labels = images.to(device), labels.to(device)
pred_classes = torch.exp(classifier.model(images)).max(dim=1)[1]
corr_classes = (labels.data == pred_classes).type(torch.FloatTensor)
accuracy += corr_classes.mean()
print("Test accuracy: {:.3f}".format(accuracy/steps))
return accuracy/steps
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-cnn', type=str, default='vgg',
choices=['vgg', 'resnet', 'densenet'],
help='The feature network (CNN)')
parser.add_argument('-hidden', type=int, nargs='+', default=[512,256,128],
help='Hidden layer sizes')
parser.add_argument('-lr', type=float, default=1e-3, help='Learning rate')
parser.add_argument('-dp', type=float, default=0.2, help='Dropout prob.')
parser.add_argument('-dir', type=str, help='Data directory')
parser.add_argument('-mean', type=float, nargs='+',
default=[0.485,0.456,0.406], help='Mean')
parser.add_argument('-std', type=float, nargs='+',
default=[0.229,0.224,0.225], help='Standard deviation')
parser.add_argument('-bs', type=int, default=32, help='Batch size')
parser.add_argument('-ep', type=int, default=7, help='Training epochs')
parser.add_argument('-dev', type=str, default='cpu', choices=['cpu','cuda'],
help='Device')
parser.add_argument('-save', type=str, default='default', help='Save path')
args = parser.parse_args()
train_dir = args.dir + '/train'
valid_dir = args.dir + '/valid'
test_dir = args.dir + '/test'
output_size = folder_count(train_dir)
datasets, dataloaders = data_preprocess(train_dir, valid_dir, test_dir,
args.mean, args.std, args.bs)
classifier = img_classifier(args.hidden, output_size,
datasets['train'].class_to_idx, args.cnn,
args.dp, args.lr)
train_classifer(classifier, dataloaders, args.dev, args.ep)
test_classifier(classifier, dataloaders, args.dev)
save_classifier(classifier, args.save)
if (__name__ == "__main__"):
main();