import theano
import os
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from lasagne import layers, nonlinearities
from lasagne.updates import nesterov_momentum
from nolearn.lasagne import NeuralNet
from sklearn.datasets import fetch_lfw_people
from sklearn.utils import shuffle
from nolearn.lasagne import BatchIterator
try:
from lasagne.layers.cuda_convnet import Conv2DCCLayer as Conv2DLayer
from lasagne.layers.cuda_convnet import MaxPool2DCCLayer as MaxPool2DLayer
except ImportError:
Conv2DLayer = layers.Conv2DLayer
MaxPool2DLayer = layers.MaxPool2DLayer
# reshape dataset/images
def reshapeDataset(dataset, newWidth, newHeight):
new_dataset = []
for data in dataset:
size = (newWidth, newHeight)
img = Image.fromarray(data)
img = img.resize(size)
img = np.array(img, dtype=np.float32)
new_dataset.append(img[np.newaxis, :, :])
return np.array(new_dataset) / 255
class PyroBatchIterator(BatchIterator):
def imageaugment(self, Xb, yb):
Xb, yb = super(PyroBatchIterator, self).transform(Xb, yb)
# flip half of the images in this batch at random:
bs = Xb.shape[0]
indices = np.random.choice(bs, bs / 2, replace=False)
Xb = flipImage(Xb,indices)
return Xb, yb
class EarlyStopping(object):
def __init__(self, patience=100):
self.patience = patience
self.best_valid = np.inf
self.best_valid_epoch = 0
self.best_weights = None
def __call__(self, nn, train_history):
current_valid = train_history[-1]['valid_loss']
current_epoch = train_history[-1]['epoch']
if current_valid < self.best_valid:
self.best_valid = current_valid
self.best_valid_epoch = current_epoch
self.best_weights = nn.get_all_params_values()
elif self.best_valid_epoch + self.patience < current_epoch:
print("Early stopping.")
print("Best valid loss was {:.6f} at epoch {}.".format(
self.best_valid, self.best_valid_epoch))
nn.load_params_from(self.best_weights)
raise StopIteration()
# acquire dataset
lfw_people = fetch_lfw_people(funneled=True, min_faces_per_person=4, resize=0.4)
# introspect the images arrays to find the shapes (for plotting)
n_samples, h, w = lfw_people.images.shape
# for machine learning we use the 2 data directly (as relative pixel
# positions info is ignored by this model)
X = reshapeDataset(lfw_people.images, 180, 180)
h, w = 180, 180
# the label to predict is the id of the person
y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]
nb_class = len(target_names)
#X = np.asarray(X)
y = np.asarray(y, dtype=np.int32)
X, y = shuffle(X, y, random_state = 42)
# print dataset info
print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_classes: %d" % n_classes)
# print shape of X and y presented to net
print X.shape
print y.shape
net3 = NeuralNet(
layers = [
('input', layers.InputLayer),
('conv1', layers.Conv2DLayer),
('pool1', layers.MaxPool2DLayer),
('conv2', layers.Conv2DLayer),
('pool2', layers.MaxPool2DLayer),
('conv3', layers.Conv2DLayer),
('pool3', layers.MaxPool2DLayer),
('conv4', layers.Conv2DLayer),
('pool4', layers.MaxPool2DLayer),
('conv5', layers.Conv2DLayer),
('pool5', layers.MaxPool2DLayer),
('conv6', layers.Conv2DLayer),
('pool6', layers.MaxPool2DLayer),
('conv7', layers.Conv2DLayer),
('pool7', layers.MaxPool2DLayer),
('dropout1', layers.DropoutLayer),
('conv8', layers.Conv2DLayer),
('pool8', layers.MaxPool2DLayer),
('dropout2', layers.DropoutLayer),
('hidden9', layers.DenseLayer),
('dropout3', layers.DropoutLayer),
('hidden10', layers.DenseLayer),
('output', layers.DenseLayer),
],
# layer params
input_shape = (None, 1, 180, 180),
conv1_num_filters = 64, conv1_filter_size = (3, 3), conv1_stride = 1, conv1_pad = 1,
conv1_nonlinearity = nonlinearities.rectify,
pool1_pool_size = (2, 2),
conv2_num_filters = 64, conv2_filter_size = (3, 3), conv2_stride = 1, conv2_pad = 1,
conv2_nonlinearity = nonlinearities.rectify,
pool2_pool_size = (2, 2),
conv3_num_filters = 128, conv3_filter_size = (3, 3), conv3_stride = 1, conv3_pad = 1,
conv3_nonlinearity = nonlinearities.rectify,
pool3_pool_size = (2, 2),
conv4_num_filters = 128, conv4_filter_size = (3, 3), conv4_stride = 1, conv4_pad = 1,
conv4_nonlinearity = nonlinearities.rectify,
pool4_pool_size = (2, 2),
conv5_num_filters = 256, conv5_filter_size = (3, 3), conv5_stride = 1, conv5_pad = 1,
conv5_nonlinearity = nonlinearities.rectify,
pool5_pool_size = (2, 2),
conv6_num_filters = 256, conv6_filter_size = (3, 3), conv6_stride = 1, conv6_pad = 1,
conv6_nonlinearity = nonlinearities.rectify,
pool6_pool_size = (2, 2),
conv7_num_filters = 256, conv7_filter_size = (2, 2), conv7_stride = 1, conv7_pad = 1,
conv7_nonlinearity = nonlinearities.rectify,
pool7_pool_size = (2, 2),
dropout1_p = 0.5,
conv8_num_filters = 512, conv8_filter_size = (2, 2), conv8_stride = 1, conv8_pad = 1,
conv8_nonlinearity = nonlinearities.rectify,
pool8_pool_size = (2, 2),
dropout2_p = 0.5,
hidden9_num_units = 500,
dropout3_p = 0.5,
hidden10_num_units = 500,
output_num_units = 610, output_nonlinearity = nonlinearities.softmax,
#update=nesterov_momentum,
update_learning_rate = 0.001,
update_momentum = 0.9,
regression = False, # not dealing with regression problem
batch_iterator_train = PyroBatchIterator(batch_size = 50),
on_epoch_finished=[
EarlyStopping(patience=200),
],
max_epochs = 1000, # want to train this many epochs
verbose = 1,
eval_size = 0.2
)
net3.fit(X, y)
# test/plot curves
train_loss = np.array([i["train_loss"] for i in net3.train_history_])
valid_loss = np.array([i["valid_loss"] for i in net3.train_history_])
plt.plot(train_loss, linewidth=3, label="train")
plt.plot(valid_loss, linewidth=3, label="valid")
plt.grid()
plt.legend()
plt.xlabel("epoch")
plt.ylabel("loss")
plt.yscale("log")
plt.show()
# training for 1000 epochs will take a while.
# pickle the trained model so that we can load it back later:
#import cPickle as pickle
#with open('net3.pickle', 'wb') as f:
# pickle.dump(net3, f, -1)