一般来说,按照教程将Lasagne配置完成就会带有example,如果没有的话,可以去Lasagne的Github下载。也可以到我的Github上面下载

其中Lasagne的官方文档有部分本文代码的英文讲解。

前言

安装的部分网络上有教程,我的前一篇文章也有提到需要安装的包和部分配置信息。

如果一切设置正确,您将得到如下输出:

Using gpu device 0: GeForce GT 640
Loading data…
Downloading train-images-idx3-ubyte.gz
Downloading train-labels-idx1-ubyte.gz
Downloading t10k-images-idx3-ubyte.gz
Downloading t10k-labels-idx1-ubyte.gz
Building model and compiling functions…
Starting training…

Epoch 1 of 500 took 1.858s
training loss: 1.233348
validation loss: 0.405868
validation accuracy: 88.78 %
Epoch 2 of 500 took 1.845s
training loss: 0.571644
validation loss: 0.310221
validation accuracy: 91.24 %
Epoch 3 of 500 took 1.845s
training loss: 0.471582
validation loss: 0.265931
validation accuracy: 92.35 %
Epoch 4 of 500 took 1.847s
training loss: 0.412204
validation loss: 0.238558
validation accuracy: 93.05 %

示例脚本允许您尝试三种不同的模型,通过第一个命令行参数选择。
使用python mnist.py --help运行脚本以获得更多信息,在知道代码是如何实现之前,我们就可以自由地使用它。

代码讲解

你可能注意到的第一件事是,除了Lasagne,我们还安装了numpy和theano:

import numpy as np
import theano
import theano.tensor as Timport lasagne

我们都知道Lasagne是在Theano的基础上封装的架构,它可以用作一些任务的补充与帮助,而不是替代。

在这里大致说明一下这几个包实现的功能和作用。numpy实现的是关于数组的运算,Theano实现的是关于矩阵的运算,而Lasagne在Theano的基础上定义了layer的概念,nolearn则是在Theano的基础上定义了神经网络训练的过程。所以可以将Lasagne和Theano的代码进行无缝衔接。

如果你想要定制layer,那就必须自己使用Theano来写。

载入数据

第一段代码定义了一个函数load_dataset()。 其目的是下载MNIST数据集(如果尚未下载),并以常规numpy数组的形式返回。 没有涉及Lasagne,所以为了本教程的目的,我们可以将其视为:

def load_dataset():...return X_train, y_train, X_val, y_val, X_test, y_test

X_train.shape是(50000,1,28,28),被解释成为:50,000个1通道的图像,每行28行和28列。注意,通道数为1,因为我们是单色输入。彩色图像将具有3个通道,光谱图也将具有单个通道。y_train.shape只是简单的(50000,),也就是说,它是一个向量,与X_train的长度相同,为每个图像给出一个整数类标签 - 即图像中描述的0和9之间的数字(手写体数字)。

构建模型

这里开始涉及Lasagne的操作了。它允许你通过创建和堆叠或合并层来定义任意结构的神经网络。由于每一层都知道它的下一层,网络的输出层(或多个输出层)作为整个网络的句柄,所以这通常是我们将传递给其余代码的唯一的东西。

如上所述,mnist.py支持三种类型的模型,我们通过同一接口的三个易于交换的函数来实现。首先,我们将定义一个创建固定架构的多层感知器(MLP)的函数,详细解释所有步骤。然后我们将展示一个生成自定义架构的MLP的函数。最后,我们将展示如何创建卷积神经网络(CNN)。

Multi-Layer Perceptron (MLP)

第一个函数build_mlp()创建了两个隐藏层的MLP,每个层有800个单元,后面是一个10个单元的softmax输出层。 它对输入数据应用20%的dropout,对隐藏层应用50%的dropout。它和[Hinton2012]中的最小MLP非常相似,但并不完全等同于(因为该论文使用的是不同的非线性函数,权重初始化和训练方式)。

Lasagne中每个神经网络的基础是一个InputLayer实例(或多个),用于表示随后将被送到网络的输入数据。 请注意,InputLayer不限制于任何特定数据,但只保留将传递到网络的数据的形状。

此外,它创建或可以链接到一个Theano变量,它将代表我们将从网络后面构建的Theano图中的网络输入。 因此,我们的函数开始如下:

def build_mlp(input_var=None):l_in = lasagne.layers.InputLayer(shape=(None, 1, 28, 28),input_var=input_var)

形状元组中的四个数字按顺序表示:(批处理大小,通道,行,列)。这里我们将batchsize设置为None,这意味着网络将在编译后接受任意batchsize的输入数据。 如果您事先知道批处理大小并且不需要这种灵活性,则应在此处给出批处理大小 - 尤其是对于卷积层,这可以允许Theano应用一些优化。

input_var表示我们想要链接网络的输入层的Theano变量,一般用于表示网络的输入。如果省略(或设置为None),层将只创建一个合适的变量本身,但是它可以方便地在创建时将现有变量链接到网络 - 特别是如果你正在创建多个输入层的网络。在这里,我们将它链接到一个变量作为参数给build_mlp()函数。

如果len(shape)和input_var维度不同,则会报错。本例中,input_var在传入网络前会通过Theano.tensor4进行转化。

在添加第一个隐藏层之前,我们将对输入数据应用20%的dropout。 这是通过DropoutLayer实例实现的:

l_in_drop = lasagne.layers.DropoutLayer(l_in, p=0.2)

请注意,第一个构造函数参数是传入层,因此l_in_drop现在连接在l_in的后面。 所有层的工作方式(除了合并多个输入层):那些它们接受的传入层的list作为它们的第一个构造函数参数。

我们将添加第一个800个单元的完全连接的隐藏层。 注意,当在高维输入向量上堆叠DenseLayer时,它们将被隐含地展开,所以我们不需要关心它。 在这种情况下,输入将从1x28x28图像平铺到784维向量。

l_hid1 = lasagne.layers.DenseLayer(l_in_drop, num_units=800,nonlinearity=lasagne.nonlinearities.rectify,W=lasagne.init.GlorotUniform())

第一个构造的变量表示,我们将l_hid1接在l_in_drop之后。num_units 表示一个全连接层的单元数量。 非线性函数使用的是rectify( = max(0, x)),所以我们就得到了ReLUs。当然这些函数都在Lasagne中有定义。

最后,lasagne.init.GlorotUniform()给出了权重矩阵W的初始化器。这个特定的初始化器从精心选择的范围的均匀分布中抽样设置权重。其他初始化器也可以通过lasagne.init得到,或者,W也可以从正确形状的Theano共享变量或numpy数组初始化(在这种情况下为784×800,因为该层的输入具有1 * 28 * 28 = 784 尺寸)。注意,lasagne.init.GlorotUniform()也是构造函数的默认值,因此我们也可以将它忽略 - 这里我只是提醒大家,这有一个选择。

我们现在将添加50%的dropout,另一个800单元的密集层和50%的dropout:

l_hid1_drop = lasagne.layers.DropoutLayer(l_hid1, p=0.5)l_hid2 = lasagne.layers.DenseLayer(l_hid1_drop, num_units=800,nonlinearity=lasagne.nonlinearities.rectify)l_hid2_drop = lasagne.layers.DropoutLayer(l_hid2, p=0.5)

最后,我们将添加完全连接的输出层。 主要区别是它使用softmax非线性,因为我们计划解决这个网络的10级分类问题。

l_out = lasagne.layers.DenseLayer(l_hid2_drop, num_units=10,nonlinearity=lasagne.nonlinearities.softmax)

如上所述,每个层都链接到其传入层,因此我们只需要输出层访问Lasagne中的网络:

return l_out

Custom MLP

第二个函数有一个稍微更广泛的签名:

def build_custom_mlp(input_var=None, depth=2, width=800, drop_input=.2,drop_hidden=.5):

默认情况下,它创建与上述build_mlp()是相同的网络,但它可以根据隐层的数量和大小以及输入和隐藏dropout的数量进行自定义。 这说明如何在Python代码中创建网络比配置文件更灵活。你自己看:

# Input layer and dropout (with shortcut `dropout` for `DropoutLayer`):
network = lasagne.layers.InputLayer(shape=(None, 1, 28, 28),input_var=input_var)
if drop_input:network = lasagne.layers.dropout(network, p=drop_input)
# Hidden layers and dropout:
nonlin = lasagne.nonlinearities.rectify
for _ in range(depth):network = lasagne.layers.DenseLayer(network, width, nonlinearity=nonlin)if drop_hidden:network = lasagne.layers.dropout(network, p=drop_hidden)
# Output layer:
softmax = lasagne.nonlinearities.softmax
network = lasagne.layers.DenseLayer(network, 10, nonlinearity=softmax)
return network

通过两个if和一个for循环,这个网络定义允许以对Pylearn2中的.yaml文件或cuda-convnet中的.cfg文件中不允许的方式改变架构。

因为Lasagne没有定义训练的过程以及层与层之间的关系,只有通过自己手工实现来做。之后会有代码介绍如果使用Lasagne对网络进行训练。

如果不想写训练的过程,也可以使用nolearn,这个框架里面定义了NerualNet,所以能够很方便地对layer进行组合、传递数据等。但是正如上文说的,nolearn等架构有一定局限性,如果想要定制训练的过程,还是需要手工写。

注意,为了使代码更容易,所有的层只是称为网络在这里 - 没有必要给他们不同的名称,如果我们返回的是我们创建的最后一个; 我们只是使用不同的名称之前为了清楚。

Convolutional Neural Network (CNN)

最后,用build_cnn()函数创建两个卷积和池化的CNN,一个完全连接的隐藏层和一个完全连接的输出层。该函数的开头和其他函数类似:

def build_cnn(input_var=None):network = lasagne.layers.InputLayer(shape=(None, 1, 28, 28),input_var=input_var)

我们不对输入应用dropout,因为这对于卷积层来说效果不太好。 我们现在添加一个Conv2DLayer,而不是DenseLayer,与顶部的32个大小5x5的过滤器:

network = lasagne.layers.Conv2DLayer(network, num_filters=32, filter_size=(5, 5),nonlinearity=lasagne.nonlinearities.rectify,W=lasagne.init.GlorotUniform())

非线性函数和权重初始化器可以像DenseLayer一样被给出(GlorotUniform()是默认的,我们从现在开始忽略它)。 条纹和填充的卷积也有被支持; 请参阅Conv2DLayer docstring。

对于专家:Conv2DLayer将创建一个卷积层使用T.nnet.conv2d,Theano的默认卷积。 在GPU编译时,Theano用基于cuDNN的实现(如果可用)替换它,否则会回到基于gemm的实现。 有关详细信息,请参阅Theano卷积文档。

Lasagne还提供直接实现特定实现的卷积层:lasagne.layers.dnn.Conv2DDNNLayer以强制执行cuDNN,lasagne.layers.corrmm.Conv2DMMLayer以强制执行基于gemm的层,lasagne.layers.cuda_convnet.Conv2DCCLayer用于Krizhevsky的cuda-convnet。

然后,我们使用MaxPool2DLayer实例,在两维中都应用因子为二的最大池:

network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))

我们像之前一样添加另一个卷积和池化阶段:

network = lasagne.layers.Conv2DLayer(network, num_filters=32, filter_size=(5, 5),nonlinearity=lasagne.nonlinearities.rectify)
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))

然后一个有256个单元的完全连接层,在其输入上有50%的dropout(使用lasagne.layers.dropout快捷方式直接内联):

network = lasagne.layers.DenseLayer(lasagne.layers.dropout(network, p=.5),num_units=256,nonlinearity=lasagne.nonlinearities.rectify)

最后是一个10单元的softmax输出层,同样有50%的dropout:

network = lasagne.layers.DenseLayer(lasagne.layers.dropout(network, p=.5),num_units=10,nonlinearity=lasagne.nonlinearities.softmax)return network

训练模型

之前强调多次,Lasagne只实现了layer的概念,但是对神经网络本身没有定义,所以没有相关的架构来进行直接训练。所以我们需要手写一部分代码来实现神经网络的训练过程。

 数据集迭代

它首先定义了一个短助手函数(short helper function),用于在给定数量的项目的小批量中分别同步迭代输入数据和目标的两个numpy数组。为了本教程的目的,我们可以将其缩短为:

def iterate_minibatches(inputs, targets, batchsize, shuffle=False):if shuffle:...for ...:yield inputs[...], targets[...]

与之相关的是,它是一个生成器函数(generator function),每次为一批输入和目标服务,直到给定的数据集(在输入和目标)用尽,无论是按顺序还是以随机顺序。 下面我们将把这个函数插入到我们的训练循环,验证循环和测试循环中。

准备

让我们现在关注main()函数。有点简化,它开头像这样:

# Load the dataset
X_train, y_train, X_val, y_val, X_test, y_test = load_dataset()
# Prepare Theano variables for inputs and targets
input_var = T.tensor4('inputs')
target_var = T.ivector('targets')
# Create neural network model
network = build_mlp(input_var)

第一行将MNIST数据集的输入和目标加载为numpy数组,分为训练、验证和测试数据。接下来的两个语句定义符号Theano变量,它将代表我们为网络训练和预测生成的所有Theano表达式中的一小批输入和目标。它们不与任何数据绑定,但它们的维度(也就是shape)和数据类型已经固定,并且与我们稍后将要处理的实际输入和目标匹配。 最后,我们调用构建Lasagne网络的三个函数之一,这取决于第一个命令行参数 - 为了清楚起见,我们刚刚删除了命令行处理。 请注意,我们将符号输入变量传递给build_mlp(),因此它将链接到网络的输入层。

损失与更新表达式

继续,我们创建损失表达式:

prediction = lasagne.layers.get_output(network)
loss = lasagne.objectives.categorical_crossentropy(prediction, target_var)
loss = loss.mean()

第一步是为网络输出生成一个Theano表达式,使得输入变量链接到网络的输入层。第二步定义用于所述网络输出和目标之间的分类交叉熵损失的Theano表达式。最后,因为我们需要一个标量损失函数,我们简单地取小批量的平均值。根据你解决的问题,你将需要不同的损失函数,请参见lasagne.objectives更多。

定义模型和损失函数后,我们创建用于训练网络的更新表达式。更新表达式描述了如何在每个呈现出的小批处理中更改网络的可训练参数。我们将在这里使用带有Nesterov动量的随机渐变下降(SGD),但是lasagne.updates模块提供了可以添加的其他几个:

params = lasagne.layers.get_all_params(network, trainable=True)
updates = lasagne.updates.nesterov_momentum(loss, params, learning_rate=0.01, momentum=0.9)

第一步收集构成层的可训练参数的所有Theano SharedVariable实例,第二步生成每个参数的更新表达式。

为了监控训练期间的进展,在每个时期之后,我们评估验证集上的网络。我们需要一个稍微不同的损失表达式:

test_prediction = lasagne.layers.get_output(network, deterministic=True)
test_loss = lasagne.objectives.categorical_crossentropy(test_prediction,target_var)
test_loss = test_loss.mean()

关键的区别是我们将deterministic = True传递给get_output调用。这导致所有非确定性层切换到确定性实现,因此在我们的示例中,它禁用了dropout层。作为附加的监测量,我们创建了分类精度的表达式:

test_acc = T.mean(T.eq(T.argmax(test_prediction, axis=1), target_var),dtype=theano.config.floatX)

它也建立在确定性的test_prediction表达式上。

编译

配置了所有必要的Theano表达式,我们现在可以编译一个执行训练步骤的函数:

train_fn = theano.function([input_var,target_var],loss,updates = updates)

这告诉Theano生成和编译一个函数,它需要两个输入 - 一个小批量的图像和一个相应的目标向量 - 并返回一个输出:训练损失。 此外,每次调用时,它都会在更新字典中应用所有参数的更新方程,从而执行带Nesterov动量的梯度下降步骤。

为了验证,我们编译第二个函数:

val_fn = theano.function([input_var,target_var],[test_loss,test_acc])

这个也需要一个小批次的图像和目标,然后返回(确定性)损失和分类的精度,不执行任何更新。

训练循环

我们终于准备好编写训练循环。实质上,我们只需要执行以下操作:

for epoch in range(num_epochs):for batch in iterate_minibatches(X_train, y_train, 500, shuffle=True):inputs, targets = batchtrain_fn(inputs, targets)

这使用我们的数据集迭代辅助函数以随机顺序迭代训练数据,每个小批量500个项目,针对num_epochs次迭代,并调用我们编译的训练函数以执行网络参数的更新步骤。

但为了能够监控培训进度,我们捕获培训损失,计算验证损失,并打印一些信息到控制台每次一个迭代完成:

for epoch in range(num_epochs):# In each epoch, we do a full pass over the training data:train_err = 0train_batches = 0start_time = time.time()for batch in iterate_minibatches(X_train, y_train, 500, shuffle=True):inputs, targets = batchtrain_err += train_fn(inputs, targets)train_batches += 1# And a full pass over the validation data:val_err = 0val_acc = 0val_batches = 0for batch in iterate_minibatches(X_val, y_val, 500, shuffle=False):inputs, targets = batcherr, acc = val_fn(inputs, targets)val_err += errval_acc += accval_batches += 1# Then we print the results for this epoch:print("Epoch {} of {} took {:.3f}s".format(epoch + 1, num_epochs, time.time() - start_time))print("  training loss:\t\t{:.6f}".format(train_err / train_batches))print("  validation loss:\t\t{:.6f}".format(val_err / val_batches))print("  validation accuracy:\t\t{:.2f} %".format(val_acc / val_batches * 100))

在最后,我们重用val_fn()函数来计算测试集上的丢失和准确性,完成脚本。

Lasagne 实现并测试MNIST相关推荐

  1. TF之DCGAN:基于TF利用DCGAN测试MNIST数据集并进行生成过程全记录

    TF之DCGAN:基于TF利用DCGAN测试MNIST数据集并进行生成 目录 测试结果 测试过程全记录 测试结果 train_00_0099 train_00_0799 train_00_0899 t ...

  2. caffe 下测试 MNIST数据

    详细说明可参考网页:http://blog.csdn.net/wangchuansnnu/article/details/44341753                                ...

  3. tensorflow00:windows下训练并测试MNIST数字识别详细笔记

    1.导入库 # 说明:由于windows下运行与tensorflow相关的程序会出现".......supports AVX2....."的 Warnning信息十分碍眼,于是在我 ...

  4. 使用caffemodel模型(由mnist训练)测试单张手写数字样本

    caffe中训练和测试mnist数据集都是批处理,可以反馈识别率,但是看不到单张样本的识别效果,这里使用windows自带的画图工具手写制作0~9的测试数字,然后使用caffemodel模型识别. 1 ...

  5. 深度学习框架之一:Theano | Lasagne简单教程

    北京 上海巡回站 | NVIDIA DLI深度学习培训 2018年1月26/1月12日 NVIDIA 深度学习学院 带你快速进入火热的DL领域 阅读全文                        ...

  6. 2021年人工神经网络第四次作业 - 第二题MNIST手写体识别

    简 介: ※MNIST数据集合是深度学习基础训练数据集合.改数据集合可以使用稠密前馈神经网络训练,也可以使用CNN.本文采用了单隐层BP网络和LeNet网络对于MNIST数据集合进行测试.实验结果标明 ...

  7. 实践详细篇-Windows下使用VS2015编译的Caffe训练mnist数据集

    上一篇记录的是学习caffe前的环境准备以及如何创建好自己需要的caffe版本.这一篇记录的是如何使用编译好的caffe做训练mnist数据集,步骤编号延用上一篇 <实践详细篇-Windows下 ...

  8. TensorFlow经典入门示例MNIST(识别手写的数字图片)

    文章目录 MNIST是什么? MNIST的组成 MNIST存储方式 使用Keras编码 运行说明与问题 图形化显示和理解 安装matplotlib 折线图简单示例 显示MNIST中的图 TensorF ...

  9. MNIST数据集手写数字分类

    参考   MNIST数据集手写数字分类 - 云+社区 - 腾讯云 目录 0.编程环境 1.下载并解压数据集 2.完整代码 3.数据准备 4.数据观察 4.1 查看变量mnist的方法和属性 4.2 对 ...

最新文章

  1. 在SunOS5.8/solaris7上使用Xerces-C解析器
  2. react native中有关日期的组件DatePicker 示例
  3. 程序员四大禁忌(同样适合向梦想冲刺的所有人~~)
  4. python的turtle库是另外下载嘛吗_python—turtle库的基本介绍
  5. 7-56 家庭房产 (25 分)
  6. java反射三种方法_Java基础入门要学哪些 怎么掌握反射和枚举
  7. 项目管理学习总结(13)——高效能技术Leader的30条军规
  8. 性能测试之JMeter接口关联【JSON提取器】详解
  9. php 常用时间处理函数,PHP date函数常用时间处理方法_PHP
  10. MySQL 计算字段长度函数LENGTH()与CHAR_LENGTH()
  11. 决策树系列(三)——ID3
  12. matlab插值计算
  13. ASP.NET 安全认证(三)
  14. 浅谈,如何获取MTK CPU信息 请看我是如何做的。一步步来吧
  15. 用安卓手机看小说,阅读器APP怎么选
  16. Ubuntu顶栏显示网速和硬件信息
  17. 广域网、城域网、局域网、个人区域网的不同
  18. Automated_bounty_Hunter全自动漏洞赏金猎人使用场景一
  19. 判断极值点是极大值还是极小值
  20. 安全计算:使用ClamWin为高级用户提供免费病毒防护

热门文章

  1. Jboot框架excel导入导出模板下载的简单封装
  2. 计算机技术与生物学的关系,生物信息学复习整理
  3. 编程语言 1 月排行榜:C 是年度语言,Python 增长量第二
  4. 隐藏HTML代码(禁用右键和F12)
  5. E-learning课件制作总结
  6. IT部门的KPI该如何制定?
  7. 我的大学生活10年(林锐)
  8. 英语与计算机整合课,浅谈计算机与英语教学的有效整合
  9. iOS底层原理之dyld应用程序加载
  10. 基于Html5的网页大头贴