-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathtraining.py
188 lines (153 loc) · 6.98 KB
/
training.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
# Mute tensorflow debugging information console
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
from keras.layers import Conv2D, MaxPooling2D, Convolution2D, Dropout, Dense, Flatten, LSTM
from keras.models import Sequential, save_model
from keras.utils import np_utils
from scipy.io import loadmat
import pickle
import argparse
import keras
import numpy as np
def load_data(mat_file_path, width=28, height=28, max_=None, verbose=True):
''' Load data in from .mat file as specified by the paper.
Arguments:
mat_file_path: path to the .mat, should be in sample/
Optional Arguments:
width: specified width
height: specified height
max_: the max number of samples to load
verbose: enable verbose printing
Returns:
A tuple of training and test data, and the mapping for class code to ascii value,
in the following format:
- ((training_images, training_labels), (testing_images, testing_labels), mapping)
'''
# Local functions
def rotate(img):
# Used to rotate images (for some reason they are transposed on read-in)
flipped = np.fliplr(img)
return np.rot90(flipped)
def display(img, threshold=0.5):
# Debugging only
render = ''
for row in img:
for col in row:
if col > threshold:
render += '@'
else:
render += '.'
render += '\n'
return render
# Load convoluted list structure form loadmat
mat = loadmat(mat_file_path)
# Load char mapping
mapping = {kv[0]:kv[1:][0] for kv in mat['dataset'][0][0][2]}
pickle.dump(mapping, open('bin/mapping.p', 'wb' ))
# Load training data
if max_ == None:
max_ = len(mat['dataset'][0][0][0][0][0][0])
training_images = mat['dataset'][0][0][0][0][0][0][:max_].reshape(max_, height, width, 1)
training_labels = mat['dataset'][0][0][0][0][0][1][:max_]
# Load testing data
if max_ == None:
max_ = len(mat['dataset'][0][0][1][0][0][0])
else:
max_ = int(max_ / 6)
testing_images = mat['dataset'][0][0][1][0][0][0][:max_].reshape(max_, height, width, 1)
testing_labels = mat['dataset'][0][0][1][0][0][1][:max_]
# Reshape training data to be valid
if verbose == True: _len = len(training_images)
for i in range(len(training_images)):
if verbose == True: print('%d/%d (%.2lf%%)' % (i + 1, _len, ((i + 1)/_len) * 100), end='\r')
training_images[i] = rotate(training_images[i])
if verbose == True: print('')
# Reshape testing data to be valid
if verbose == True: _len = len(testing_images)
for i in range(len(testing_images)):
if verbose == True: print('%d/%d (%.2lf%%)' % (i + 1, _len, ((i + 1)/_len) * 100), end='\r')
testing_images[i] = rotate(testing_images[i])
if verbose == True: print('')
# Convert type to float32
training_images = training_images.astype('float32')
testing_images = testing_images.astype('float32')
# Normalize to prevent issues with model
training_images /= 255
testing_images /= 255
nb_classes = len(mapping)
return ((training_images, training_labels), (testing_images, testing_labels), mapping, nb_classes)
def build_net(training_data, width=28, height=28, verbose=False):
''' Build and train neural network. Also offloads the net in .yaml and the
weights in .h5 to the bin/.
Arguments:
training_data: the packed tuple from load_data()
Optional Arguments:
width: specified width
height: specified height
epochs: the number of epochs to train over
verbose: enable verbose printing
'''
# Initialize data
(x_train, y_train), (x_test, y_test), mapping, nb_classes = training_data
input_shape = (height, width, 1)
# Hyperparameters
nb_filters = 32 # number of convolutional filters to use
pool_size = (2, 2) # size of pooling area for max pooling
kernel_size = (3, 3) # convolution kernel size
model = Sequential()
model.add(Convolution2D(nb_filters,
kernel_size,
padding='valid',
input_shape=input_shape,
activation='relu'))
model.add(Convolution2D(nb_filters,
kernel_size,
activation='relu'))
model.add(MaxPooling2D(pool_size=pool_size))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
if verbose == True: print(model.summary())
return model
def train(model, training_data, callback=True, batch_size=256, epochs=10):
(x_train, y_train), (x_test, y_test), mapping, nb_classes = training_data
# convert class vectors to binary class matrices
y_train = np_utils.to_categorical(y_train, nb_classes)
y_test = np_utils.to_categorical(y_test, nb_classes)
if callback == True:
# Callback for analysis in TensorBoard
tbCallBack = keras.callbacks.TensorBoard(log_dir='./Graph', histogram_freq=0, write_graph=True, write_images=True)
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test),
callbacks=[tbCallBack] if callback else None)
score = model.evaluate(x_test, y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])
# Offload model to file
model_yaml = model.to_yaml()
with open("bin/model.yaml", "w") as yaml_file:
yaml_file.write(model_yaml)
save_model(model, 'bin/model.h5')
if __name__ == '__main__':
parser = argparse.ArgumentParser(usage='A training program for classifying the EMNIST dataset')
parser.add_argument('-f', '--file', type=str, help='Path .mat file data', required=True)
parser.add_argument('--width', type=int, default=28, help='Width of the images')
parser.add_argument('--height', type=int, default=28, help='Height of the images')
parser.add_argument('--max', type=int, default=None, help='Max amount of data to use')
parser.add_argument('--epochs', type=int, default=10, help='Number of epochs to train on')
parser.add_argument('--verbose', action='store_true', default=False, help='Enables verbose printing')
args = parser.parse_args()
bin_dir = os.path.dirname(os.path.realpath(__file__)) + '/bin'
if not os.path.exists(bin_dir):
os.makedirs(bin_dir)
training_data = load_data(args.file, width=args.width, height=args.height, max_=args.max, verbose=args.verbose)
model = build_net(training_data, width=args.width, height=args.height, verbose=args.verbose)
train(model, training_data, epochs=args.epochs)