This notebooks presents custom Data Generator combined with ConvNet and applied to CIFAR-10 dataset.
Resources
import numpy as np
import matplotlib.pyplot as plt
Limit TensorFlow GPU memory usage
import tensorflow as tf
gpu_options = tf.GPUOptions(allow_growth=True) # init TF ...
config=tf.ConfigProto(gpu_options=gpu_options) # w/o taking ...
with tf.Session(config=config): pass # all GPU memory
Load dataset and show example images
(x_train_raw, y_train_raw), (x_test_raw, y_test_raw) = tf.keras.datasets.cifar10.load_data()
class2txt = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
Show example images
fig, axes = plt.subplots(nrows=1, ncols=6, figsize=[16, 9])
for i in range(len(axes)):
axes[i].set_title(class2txt[y_train_raw[i, 0]])
axes[i].imshow(x_train_raw[i])
Normalize features
x_train = (x_train_raw - x_train_raw.mean()) / x_train_raw.std()
x_test = (x_test_raw - x_train_raw.mean()) / x_train_raw.std()
print('x_train.shape', x_train.shape)
print('x_test.shape', x_test.shape)
One-hot encode labels
y_train = tf.keras.utils.to_categorical(y_train_raw, num_classes=10)
y_test = tf.keras.utils.to_categorical(y_test_raw, num_classes=10)
print('y_train.shape', y_train.shape)
print(y_train[:3])
class CustomSequence(tf.keras.utils.Sequence):
def __init__(self, data_x, data_y, batch_size, shuffle=False):
"""Custom data generator for model.fit_generator()
Params:
data_x - np.ndarray with features, shape (dataset_size, ...)
data_y - np.ndarray with targets, shape (dataset_size, ...)
batch_size - mini-batch size
shuffle - shuffle features/targets between epochs
Note:
this class 'shuffle' param will shuffle all examples between epochs
model.fit_generator(shuffle=...) param shufles order of mini-batches,
but does not touch what is inside mini-batch
"""
self.data_x = data_x
self.data_y = data_y
self.batch_size = batch_size
self.shuffle = shuffle
self.on_epoch_end()
def __len__(self):
return int(np.ceil(len(self.data_x) / self.batch_size))
def __getitem__(self, idx):
batch_i = self.indices[idx*self.batch_size : (idx+1)*self.batch_size]
batch_x = self.data_x[batch_i]
batch_y = self.data_y[batch_i]
return batch_x, batch_y
def on_epoch_end(self):
self.indices = np.arange(len(self.data_x))
if self.shuffle:
np.random.shuffle(self.indices)
Create generators
train_generator = CustomSequence(x_train, y_train, batch_size=250, shuffle=True)
test_generator = CustomSequence(x_test, y_test, batch_size=250)
Show examples
batch_x, batch_y = train_generator[0]
batch_x = ( batch_x * x_train_raw.std() + x_train_raw.mean() ) / 255.0
fig, axes = plt.subplots(nrows=1, ncols=6, figsize=[16, 9])
for i in range(len(axes)):
axes[i].set_title(class2txt[np.argmax(batch_y[i])])
axes[i].imshow(batch_x[i])
from tensorflow.keras.layers import Input, InputLayer, Conv2D, MaxPooling2D
from tensorflow.keras.layers import Activation, Flatten, Dense, Dropout
Define model
model = tf.keras.Sequential()
model.add(InputLayer(input_shape=[32, 32, 3]))
model.add(Conv2D(filters=16, kernel_size=3, padding='same', activation='elu'))
model.add(MaxPooling2D(pool_size=[2,2], strides=[2, 2], padding='same'))
model.add(Conv2D(filters=32, kernel_size=3, padding='same', activation='elu'))
model.add(MaxPooling2D(pool_size=[2,2], strides=[2, 2], padding='same'))
model.add(Conv2D(filters=64, kernel_size=3, padding='same', activation='elu'))
model.add(MaxPooling2D(pool_size=[2,2], strides=[2, 2], padding='same'))
model.add(Flatten())
model.add(Dropout(0.2))
model.add(Dense(512, activation='elu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
Train model
hist = model.fit_generator(train_generator, epochs=20,
validation_data=test_generator, verbose=2)
Final results
loss, acc = model.evaluate(x_train, y_train, batch_size=250, verbose=0)
print(f'Accuracy on train set: {acc:.3f}')
loss, acc = model.evaluate(x_test, y_test, batch_size=250, verbose=0)
print(f'Accuracy on test set: {acc:.3f}')
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[16, 6])
axes[0].plot(hist.history['loss'], label='train_loss')
axes[0].plot(hist.history['val_loss'], label='val_loss')
axes[0].set_title('Loss')
axes[0].legend()
axes[0].grid()
axes[1].plot(hist.history['acc'], label='train_acc')
axes[1].plot(hist.history['val_acc'], label='val_acc')
axes[1].set_title('Accuracy')
axes[1].legend()
axes[1].grid()