1 Lasagne是什么
说了这么久的开源框架,我们好像一直忘了一个很老牌的框架,就是theano对不对,在2008年的时候,这个框架就由Yoshua Bengio领导的蒙特利尔LISA组开源了。
一直没说theano是因为它的使用成本真的有点高,需要从底层开始写代码构建模型,不过今天说的这个是封装了theano的高层框架,即Lasagen,它使得theano使用起来更简单。
官网地址:http://lasagne.readthedocs.io/en/latest/index.html GitHub: https://github.com/Lasagne/Lasagne
2 Lasagne训练准备
2.1 Lasagne安装
Lasagne安装很简单,只需要在终端输入下面命令即可安装:
pip install Lasagne
2.2 数据读取
由于没有特别好的接口,因此我们自己定义一个类就行了,实现从数据集中读取,以及产生list,格式就是每一个类存在一个单独的文件夹下,主体代码如下。
class Dataset:
def __init__(self, rootpath, imgwidth, imgheight, trainratio=0.9):
self.rootpath = rootpath
list_dirs = os.walk(self.rootpath)
count = 0
numofclasses = 0
self.subdirs = []
##遍历文件夹
for root, dirs, files in list_dirs:
for d in dirs:
self.subdirs.append(os.path.join(root,d))
label = 0
self.imagedatas = []
self.labeldatas = []
for subdir in self.subdirs:
images = glob.iglob(os.path.join(subdir,'*.jpg'))
for image in images:
imagedata = cv2.imread(image,1)
imagedata = cv2.resize(imagedata,(imgwidth,imgheight))
imagedata = imagedata.astype(np.float) / 255.0
imagedata = imagedata - [0.5,0.5,0.5]
imagedata = imagedata.transpose((2,0,1))
self.imagedatas.append(imagedata)
self.labeldatas.append(label)
label = label + 1
self.imagedatas = np.array(self.imagedatas).astype(np.float32)
self.labeldatas = np.array(self.labeldatas).astype(np.int32)
indices = np.arange(len(self.imagedatas))
np.random.shuffle(indices)
splitindex = int(trainratio*self.imagedatas.shape[0])
self.imagetraindatas = self.imagedatas[0:splitindex].copy()
self.labeltraindatas = self.labeldatas[0:splitindex].copy()
self.imagevaldatas = self.imagedatas[splitindex:].copy()
self.labelvaldatas = self.labeldatas[splitindex:].copy()
##定义数据迭代接口
def iterate_minibatches(self, inputs, targets, batchsize, shuffle=False):
assert len(inputs) == len(targets)
if shuffle:
indices = np.arange(len(inputs))
print "indices type=",type(indices)
np.random.shuffle(indices)
for start_idx in range(0, len(inputs) - batchsize + 1, batchsize):
if shuffle:
excerpt = indices[start_idx:start_idx + batchsize]
else:
excerpt = slice(start_idx, start_idx + batchsize)
yield inputs[excerpt], targets[excerpt]
以上就实现了将一个数据集下的不同子文件夹的图片随机分成了训练集和测试集,并提供了统一的接口。当然这里只做了最简单的数据预处理而没有做数据增强,这就留待读者自己去完成了。
2.3 网络定义
基本上和所有python库的方法是一样的,调用接口就行。
def simpleconv3(input_var=None):
network = lasagne.layers.InputLayer(shape=(None, 3, 48, 48),
input_var=input_var)
network = lasagne.layers.Conv2DLayer(
network, num_filters=12, filter_size=(3, 3),
nonlinearity=lasagne.nonlinearities.rectify,
W=lasagne.init.GlorotUniform())
network = batch_norm(network)
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))
network = lasagne.layers.Conv2DLayer(
network, num_filters=24, filter_size=(3, 3),
nonlinearity=lasagne.nonlinearities.rectify,
W=lasagne.init.GlorotUniform())
network = batch_norm(network)
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))
network = lasagne.layers.Conv2DLayer(
network, num_filters=48, filter_size=(3, 3),
nonlinearity=lasagne.nonlinearities.rectify,
W=lasagne.init.GlorotUniform())
network = batch_norm(network)
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))
network = lasagne.layers.DenseLayer(
lasagne.layers.dropout(network, p=.5),
num_units=128,
nonlinearity=lasagne.nonlinearities.rectify)
network = lasagne.layers.DenseLayer(
lasagne.layers.dropout(network, p=.5),
num_units=2,
nonlinearity=lasagne.nonlinearities.softmax)
return network
以上定义的就是一个3层卷积2层全连接的网络,使用lasagne.layers接口。
3 模型训练
1、首先通过Theano里的tensor对输入和输出进行定义
input_var = T.tensor4('inputs')
target_var = T.ivector('targets')
inputs是一个四维的张量,targets是一个ivector变量。
2、调用lasagne.objectives里的损失函数接口:
network = simpleconv3(input_var)
prediction = lasagne.layers.get_output(network)
loss =lasagne.objectives.categorical_crossentropy(prediction, target_var)
loss = loss.mean()
network即网络模型,prediction表示它的输出,损失函数categorical_crossentropy就是交叉熵了。
验证集和测试集上的定义与此类似,只需要更改deterministic为deterministic=True,这样会屏蔽掉所有的dropout层,如下:
test_prediction = lasagne.layers.get_output(network, deterministic=True)
test_loss = lasagne.objectives.categorical_crossentropy(test_prediction, target_var)
test_loss = test_loss.mean()
接下来就是训练方法,使用nesterov_momentum法:
params = lasagne.layers.get_all_params(network, trainable=True)
updates = lasagne.updates.nesterov_momentum( loss, params, learning_rate=0.01, momentum=0.9
)
最后定义训练函数:
train_fn = theano.function([input_var, target_var], loss, updates=updates)
接收两个输入input_var, target_var,利用updates表达式更新参数。如果是用于验证和测试,就不需要进行网络参数的更新,而且可以增加精度等变量,这时这样定义:
test_acc = T.mean(T.eq(T.argmax(test_prediction, axis=1), target_var), dtype=theano.config.floatX
)
val_fn = theano.function([input_var, target_var], [test_loss, test_acc])
最后,每一个epoch取得数据训练进行训练:
train_data = mydataset.iterate_minibatches(mydataset.imagetraindatas,mydataset.labeltraindatas,16,True)
train_batches = 0 for input_batch, target_batch in train_data: train_loss += train_fn(input_batch, target_batch) prediction = lasagne.layers.get_output(network) train_batches += 1 print("Epoch %d: Train Loss %g" % (epoch + 1, train_loss / train_batches))
结果如下,老样子,测试集合精度90%,模型过拟合。
以上就是Lasagne从数据准备,模型定义到输出结果的整个流程,想要体验可以去参考git代码。
总结
Lasagne/Theano给我最大的感觉就是慢,比至今用过的每一个框架都要慢,不过了解一下并没有坏处,毕竟Theano曾经辉煌。