python深度学习中经过卷积神经网络训练后的输出怎样查看

摘要:本文展示了如何基于nolearn使用一些卷积层和池化层来建立一个简单的ConvNet体系结构,以及如何使用ConvNet去训练一个特征提取器,然后在使用如SVM、Logistic回归等不同的模型之前使用它来进行特征提取。卷积神经网络(ConvNets)是受生物启发的MLPs(多层感知器),它们有着不同类别的层,并且每层的工作方式与普通的MLP层也有所差异。如果你对ConvNets感兴趣,这里有个很好的教程。CNNs的体系结构如下所示:常规的神经网络ConvNet网络体系结构如你所见,ConvNets工作时伴随着3D卷积并且在不断转变着这些3D卷积。我在这篇文章中不会再重复整个CS231n的教程,所以如果你真的感兴趣,请在继续阅读之前先花点时间去学习一下。Lasagne 和 nolearnLasagne和nolearn是我最喜欢使用的深度学习Python包。Lasagne是基于Theano的,所以GPU的加速将大有不同,并且其对神经网络创建的声明方法也很有帮助。nolearn库是一个神经网络软件包实用程序集(包含Lasagne),它在神经网络体系结构的创建过程上、各层的检验等都能够给我们很大的帮助。在这篇文章中我要展示的是,如何使用一些卷积层和池化层来建立一个简单的ConvNet体系结构。我还将向你展示如何使用ConvNet去训练一个特征提取器,在使用如SVM、Logistic回归等不同的模型之前使用它来进行特征提取。大多数人使用的是预训练ConvNet模型,然后删除最后一个输出层,接着从ImageNets数据集上训练的ConvNets网络提取特征。这通常被称为是迁移学习,因为对于不同的问题你可以使用来自其它的ConvNets层,由于ConvNets的第一层过滤器被当做是一个边缘探测器,所以它们可以用来作为其它问题的普通特征探测器。加载MNIST数据集MNIST数据集是用于数字识别最传统的数据集之一。我们使用的是一个面向Python的版本,但先让我们导入需要使用的包:import matplotlibimport matplotlib.pyplot as pltimport matplotlib.cm as cmfrom urllib import urlretrieveimport cPickle as pickleimport osimport gzipimport numpy as npimport theanoimport lasagnefrom lasagne import layersfrom lasagne.updates import nesterov_momentumfrom nolearn.lasagne import NeuralNetfrom nolearn.lasagne import visualizefrom sklearn.metrics import classification_reportfrom sklearn.metrics import confusion_matrix正如你所看到的,我们导入了用于绘图的matplotlib包,一些用于下载MNIST数据集的原生Python模块,numpy, theano,lasagne,nolearn 以及 scikit-learn库中用于模型评估的一些函数。然后,我们定义一个加载MNIST数据集的函数(这个功能与Lasagne教程上使用的非常相似)def load_dataset():url = 'http://deeplearning.net/data/mnist/mnist.pkl.gz'filename = 'mnist.pkl.gz'if not os.path.exists(filename):print(&Downloading MNIST dataset...&)urlretrieve(url, filename)with gzip.open(filename, 'rb') as f:data = pickle.load(f)X_train, y_train = data[0]X_val, y_val = data[1]X_test, y_test = data[2]X_train = X_train.reshape((-1, 1, 28, 28))X_val = X_val.reshape((-1, 1, 28, 28))X_test = X_test.reshape((-1, 1, 28, 28))y_train = y_train.astype(np.uint8)y_val = y_val.astype(np.uint8)y_test = y_test.astype(np.uint8)return X_train, y_train, X_val, y_val, X_test, y_test正如你看到的,我们正在下载处理过的MNIST数据集,接着把它拆分为三个不同的数据集,分别是:训练集、验证集和测试集。然后重置图像内容,为之后的Lasagne输入层做准备,与此同时,由于GPU/theano数据类型的限制,我们还把numpy的数据类型转换成了uint8。随后,我们准备加载MNIST数据集并检验它:X_train, y_train, X_val, y_val, X_test, y_test = load_dataset()plt.imshow(X_train[0][0], cmap=cm.binary)这个代码将输出下面的图像(我用的是IPython Notebook)一个MNIST数据集的数字实例(该实例是5)ConvNet体系结构与训练现在,定义我们的ConvNet体系结构,然后使用单GPU/CPU来训练它(我有一个非常廉价的GPU,但它很有用)net1 = NeuralNet(layers=[('input', layers.InputLayer),('conv2d1', layers.Conv2DLayer),('maxpool1', layers.MaxPool2DLayer),('conv2d2', layers.Conv2DLayer),('maxpool2', layers.MaxPool2DLayer),('dropout1', layers.DropoutLayer),('dense', layers.DenseLayer),('dropout2', layers.DropoutLayer),('output', layers.DenseLayer),],# input layerinput_shape=(None, 1, 28, 28),# layer conv2d1conv2d1_num_filters=32,conv2d1_filter_size=(5, 5),conv2d1_nonlinearity=lasagne.nonlinearities.rectify,conv2d1_W=lasagne.init.GlorotUniform(),# layer maxpool1maxpool1_pool_size=(2, 2),# layer conv2d2conv2d2_num_filters=32,conv2d2_filter_size=(5, 5),conv2d2_nonlinearity=lasagne.nonlinearities.rectify,# layer maxpool2maxpool2_pool_size=(2, 2),# dropout1dropout1_p=0.5,# densedense_num_units=256,dense_nonlinearity=lasagne.nonlinearities.rectify,# dropout2dropout2_p=0.5,# outputoutput_nonlinearity=lasagne.nonlinearities.softmax,output_num_units=10,# optimization method paramsupdate=nesterov_momentum,update_learning_rate=0.01,update_momentum=0.9,max_epochs=10,verbose=1,)# Train the networknn = net1.fit(X_train, y_train)如你所视,在layers的参数中,我们定义了一个有层名称/类型的元组字典,然后定义了这些层的参数。在这里,我们的体系结构使用的是两个卷积层,两个池化层,一个全连接层(稠密层,dense layer)和一个输出层。在一些层之间也会有dropout层,dropout层是一个正则化矩阵,随机的设置输入值为零来避免过拟合(见下图)。Dropout层效果(来自CS231n网站)调用训练方法后,nolearn包将会显示学习过程的状态,我的机器使用的是低端的的GPU,得到的结果如下:# Neural Network with 160362 learnable parameters## Layer information# name size--- -------- --------0 input 1x28x281 conv2d1 32x24x242 maxpool1 32x12x123 conv2d2 32x8x84 maxpool2 32x4x45 dropout1 32x4x46 dense 2567 dropout2 2568 output 10epoch train loss valid loss train/val valid acc dur------- ------------ ------------ ----------- --------- ---1 0.07 5.74 33.71s2 0.32 2.25 33.34s3 0.67 2.88 33.51s4 0.95 2.05 33.50s5 0.03 2.61 34.38s6 0.67 2.39 34.02s7 0.32 2.27 33.78s8 0.71 1.48 34.17s9 0.59 1.07 33.80s10 0.58 1.26 33.40s正如你看到的,最后一次的精度可以达到0.98526,是这10个单元训练中的一个相当不错的性能。预测和混淆矩阵现在,我们使用这个模型来预测整个测试集:preds = net1.predict(X_test)我们还可以绘制一个混淆矩阵来检查神经网络的分类性能:cm = confusion_matrix(y_test, preds)plt.matshow(cm)plt.title('Confusion matrix')plt.colorbar()plt.ylabel('True label')plt.xlabel('Predicted label')plt.show()上面的代码将绘制下面的混淆矩阵:混淆矩阵如你所视,对角线上的分类更密集,表明我们的分类器有一个良好的性能。过滤器的可视化我们还可以从第一个卷积层中可视化32个过滤器:visualize.plot_conv_weights(net1.layers_['conv2d1'])上面的代码将绘制下面的过滤器:第一层的5x5x32过滤器如你所视,nolearn的plot_conv_weights函数在我们指定的层中绘制出了所有的过滤器。Theano层的功能和特征提取现在可以创建theano编译的函数了,它将前馈输入数据输送到结构体系中,甚至是你感兴趣的某一层中。接着,我会得到输出层的函数和输出层前面的稠密层函数。dense_layer = layers.get_output(net1.layers_['dense'], deterministic=True)output_layer = layers.get_output(net1.layers_['output'], deterministic=True)input_var = net1.layers_['input'].input_varf_output = theano.function([input_var], output_layer)f_dense = theano.function([input_var], dense_layer)如你所视,我们现在有两个theano函数,分别是f_output和f_dense(用于输出层和稠密层)。请注意,在这里为了得到这些层,我们使用了一个额外的叫做“deterministic”的参数,这是为了避免dropout层影响我们的前馈操作。现在,我们可以把实例转换为输入格式,然后输入到theano函数输出层中:instance = X_test[0][None, :, :]%timeit -n 500 f_output(instance)500 loops, best of 3: 858 us per loop如你所视,f_output函数平均需要858us。我们同样可以为这个实例绘制输出层激活值结果:pred = f_output(instance)N = pred.shape[1]plt.bar(range(N), pred.ravel())上面的代码将绘制出下面的图:输出层激活值正如你所看到的,数字被认为是7。事实是为任何网络层创建theano函数都是非常有用的,因为你可以创建一个函数(像我们以前一样)得到稠密层(输出层前一个)的激活值,然后你可以使用这些激活值作为特征,并且使用你的神经网络作为特征提取器而不是分类器。现在,让我们为稠密层绘制256个激活单元:pred = f_dense(instance)N = pred.shape[1]plt.bar(range(N), pred.ravel())上面的代码将绘制下面的图:稠密层激活值现在,你可以使用输出的这256个激活值作为线性分类器如Logistic回归或支持向量机的特征了。最后,我希望你会喜欢这个教程。原文链接:(译者/刘帝伟 审校/刘翔宇、朱正贵 责编/周建丁)&作者简介:Christian S.Peron,遗传算法框架Pyevolve(基于Python编写的)的作者,现任惠普软件设计师。可通过christian dot perone at gmail dot com 联系。关于译者:,中南大学软件学院在读研究生,关注机器学习、数据挖掘及生物信息领域。文章来源:
联系邮件:
联系电话: 3-8062&&&&  介绍了CNN的基本结构。博文、、依次介绍了卷积操作、LR模型的建立及实现,MLP模型及实现。这些都是作为实现LeNet的铺垫。因为LeNet的实现就是由它们组成的。
  今天我们就来讨论一下LeNet的模型建立及实现。
  先来看一下LeNet的结构图。由图中可得到其结构分别为输入层、s1、c1、s2、c2和输出层。
  其中,输入层到s1是卷积运算;输入层输入数据batch_size个样本,每个样本是一个28*28的图片,s1层滤波器大小为5*5,滤波器为20个。
  经过卷积运算,s1的特征图数目为20个,每个特征图的大小为(28-5+1)*(28-5+1)=24*24。为什么会是这个样子呢?这就涉及到卷积运算是怎么回事了。卷积运算一个最重要的特点就是可以使原信号特征增强,并且能降低噪音。具体运算过程,。
  当计算完第一组5*5区域后(比如计算的是原数据第一行下标0-4,第一列0-4构成的方阵),5*5的滤波器整体向右移动步长=1,那么下一次就是计算原数据第一行下标1-5,第一列0-4的方阵。以此类推,原数据第一行28个数据,那么就会向右移动(28-5+1)次。因此,最终的结果图大小就是(28-5+1)*(28-5+1)。如何还不太清楚,可以自己手动画一下,画一个4*4的原数据,2*2的滤波器,最终生成的图像大小为(4-2+1)*(4-2+1)。
  下面我们计算一下s1层需要训练的参数个数:s1生成有20个特征图,每个特征图的滤波器不同,同一个特征图的滤波器相同(这不废话吗)每个特征图含24*24个元素,每个元素的生成是由本图的滤波器与原图像卷积计算得出。本图的滤波器含有5*5个W元素+1个b元素(共5*5+1=26个参数)。那么总的计算就是:共有
20*(5*5+1)=520个参数;20*(24*24)*(5*5+1)=299520个连接。
  s1层到c1层是下采样层。计算过程就是将s1的输出数据作为c1的输入数据。因此,输入数据为20个24*24的特征图。经过采样大小为2*2感受野的计算后,结果仍然是20个特征图,每个特征图变为了12*12。
  滤波器的移动是有重叠的。而下采样是无重叠的。采样计算过程如下:结果特征图中的每一个元素对应输入特征图中的2*2元素,将2*2区域元素累加,然后乘以一个可训练参数,再加上一个偏置值,最后通过sigmoid函数计算得到一个数值。然后结果图的下一个元素就是输入图中下一个2*2区域,以此类推。最终原图是24*24的,经过下采样之后,就变成12*12了(就是行和列分别是原来的一半。因此整体就是原来的1/4)。
  总体就是在特征图数目不变的前提下,将每个特征图进行了类似压缩的操作,这样元素个数大大降低,这就是所谓的下采样。同样我们计算一下c1层需要训练的参数个数:c1仍然生成20个特征图,每个特征图含12*12个元素,每个元素的生成是由原图的2*2区域元素累加,然后乘以1个可训练参数+1个偏置b参数。相当于本图的滤波器含有1*1个W元素+1个b元素(共1*1+1=2个参数)。那么总的计算就是:共有20*(1*1+1)=40个参数;20*(12*12)*(2*2+1)=14400个连接。。
  c1到s2是卷积运算;输入是batch_size个样本,每个样本是20个12*12的特征图,s2层是50个滤波器,每个滤波器5*5大小。然后经过卷积运算,生成50个8*8的特征图。【c1与s2的全连接,但尚不清楚是如何计算的,因此未能算出其参数和连接。从其他资料经验看,应该有20*50*(5*5+1)=26000个参数;20*50*(8*8)*(5*5+1)=1664000个连接。】
  s2层到c3层是下采样层,输入是50个8*8特征图,采用2*2感受野,结果是50个4*4特征图。
  c3层到输出层经过一个MLP层。输入数据是将c3的4维输出转换为2维矩阵,即把后三维50*4*4转换为行数据,送入MLP的隐层,激活函数是tanh,输出是batch_size;然后再把结果送入MLP的LR层,经过softmax函数,将结果分为10类。
  至此,整个模型介绍完毕。经过注释后的代码  ,包含2个文件:mlp.py和LeNetConvPoolLayer.py。
  肯定会有纰漏和错误,欢迎指出,共同进步。
参考目录:
转载来自:http://blog.csdn.net/niuwei22007/article/details/
本文已收录于以下专栏:
相关文章推荐
本文原链接可以查看更多文章
  博文01介绍了CNN的基本结构。博文02、03、04依次介绍了卷积操作、LR模型的建立及实现,MLP模型及实现。这些都是作为实现LeNet的铺垫。因为LeNe...
本文主要参考于:Multilayer Perceptron
  python源代码(github下载  CSDN免费下载)  本文主要介绍含有单隐层的MLP的建模及实现。建议在阅读本博文之前,先看一...
本文主要参考于:Classifying MNIST digits using Logistic Regression
python源代码(GitHub下载  CSDN免费下载)  0阶张量叫标量(s...
深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-02-基于Python的卷积运算 -- 在python中对图片进行卷积操作运算的一个示例程序, 源代码分析:(注意,如果直接保存以下代码,一定要另...
《CNN基础知识点》From:Convolutional Neural Networks (LeNet)原文链接可以查看更多信息:http://blog.csdn.net/niuwei22007/ar...
欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld。
技术交流QQ群:,欢迎对算法、技术感兴趣的同学加入。关于卷积神经网络CNN,网络和文献...
图片均来自百度网络搜集
o LeNet,这是最早用于数字识别的CNN
o AlexNet,2012 ILSVRC比赛远超第2名的CNN,比LeNet更深,用多层小卷积层叠加替换单大...
各处整理了一些资料,有时间好好看
先来一张不是很相关的有趣的对比图。
关于卷积神经网络CNN,网络和文献中有非常多的资料,简单整理一下,以备查阅之需。
Alexnet,2012年Google...
序深度学习现在大火,虽然自己上过深度学习课程、用过keras做过一些实验,始终觉得理解不透彻。最近仔细学习前辈和学者的著作,感谢他们的无私奉献,整理得到本文,共勉。1.前言(1)神经网络的缺陷在神经网...
他的最新文章
讲师:王哲涵
讲师:韦玮
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)藤本植物导航
&>&&>&&>&正文
这两个概念实际上是互相交叉的,例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。
python深度学习中经过卷积神经网络训练后的输出怎样查看
这两个概念实际上是互相交叉的,例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。python深度学习中经过卷积神经网络训练后的输出怎样查看这两个概念实际上是互相交叉的,例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Dee
这两个概念实际上是互相交叉的,例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。honey既然没有人回答就把分给我吧~调整cnn网络结构需要增加或者减少layer的层数,并且更改layer的类型,比如在现有的conv层和pooling层后面继续增加conv层和pooling层,目的是为了提取更高层次的特征。当然你也可以增加全连接层数目(那么做训练会变慢--、),修改激活函数和填充...作者:杨延生 链接: 来源:知乎 著作权归作者所有,转载请联系作者获得授权。 "深度学习"是为了让层数较多的多层神经网络可以训练,能够work而演化出来的一系列的 新的结构和新的方法。 新的网络结构中最著名的就是CNN,它解决了传统较深的网络...深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形成更加抽象的高层表示属性类别或特征,以发现数据的分布式特征表示。 多层神经网络是指单计算层感知器只能解决线性可分问题,而大...“深度学习”和“多层神经网络”不存在区别关系。 深度学习的网络结构是多层神经网络的一种。深度学习中最著名的卷积神经网络CNN,在原来多层神经网络的基础上,加入了特征学习部分,这部分是模仿人脑对信号处理上的分级的。 广义上说深度学习的网络...深度学习与神经网络关系
最近开始学习深度学习,基本上都是zouxy09博主的文章,写的蛮好,很全面,也会根据自己的思路,做下删减,细化。 五、Deep Learning的基本思想 假设我们有一个系统S,它有n层(S1,…Sn),它的输入是I,输出是...这两个概念实际上是互相交叉的,例如,卷积神经网络(Convolutional neural networks,简称CNNs)就是一种深度的监督学习下的机器学习模型,而深度置信网(Deep Belief Nets,简称DBNs)就是一种无监督学习下的机器学习模型。 深度学习的概念源...这两个现在半斤八两吧,R更强一些,但是Python也差不多了,推荐用Python中的sklearn和tensorflow第三方模块深度学习本身是一个非常庞大的知识体系。本文更多想从程序员的视角出发,让大家观察一下深度学习对程序员意味着什么,以及我们如何利用这样一个高速发展的学科,来帮助程序员提升软件开发的能力。 本文根据费良宏在2016QCon全球软件开发大会(上...
种植经验最新
种植经验推荐
& 6种植网 版权所有
渝ICP备号-23来自集智百科
本页面主要内容来自
有多层神经元
高层神经元控制(接受)底层神经元的输入
使用卷积来定义不同层神经元之间的作用,回忆一维卷积的效果
可以将一维卷积推广到二维卷积
卷积是很有意思的东西,是The common patterns in nature一文中的核心概念。可以简单解释如下(来自我以前写的文章《统计之道:墨子见鬼谷子》):
图层之间的作用示例
更具体完整的模型如下所示(lenet)
我们将使用以下对图片进行处理
import theano
import theano.tensor as T
import pylab
from PIL import Image
import cPickle, gzip, numpy
from theano.tensor.nnet import conv
rng = numpy.random.RandomState(23455)
input = T.tensor4(name='input')
# initialize shared variable for weights.
w_shp = (2, 3, 9, 9)
w_bound = numpy.sqrt(3 * 9 * 9)
W = theano.shared( numpy.asarray(
rng.uniform(
low=-1.0 / w_bound,
high=1.0 / w_bound,
size=w_shp),
dtype=input.dtype), name ='W')
b_shp = (2,)
b = theano.shared(numpy.asarray(
rng.uniform(low=-.5, high=.5, size=b_shp),
dtype=input.dtype), name ='b')
conv_out = conv.conv2d(input, W)
output = T.nnet.sigmoid(conv_out + b.dimshuffle('x', 0, 'x', 'x'))
f = theano.function([input], output)
# open random image of dimensions 639x516
img = Image.open('E:/wulingfei/pkuwinter.jpg')
(width, height) = img.size
img = numpy.asarray(img, dtype='float64') / 256.
# put image in 4D tensor of shape (1, 3, height, width)
img_ = img.swapaxes(0, 2).swapaxes(1, 2).reshape(1, 3, height, width)
filtered_img = f(img_)
plt.figure(1,figsize=(7,15))
# plot original image and first and second components of output
pylab.subplot(3, 1, 1); pylab.axis('off'); pylab.imshow(img)
pylab.gray();
# recall that the convOp output (filtered image) is actually a "minibatch",
# of size 1 here, so we take index 0 in the first dimension:
pylab.subplot(3, 1, 2); pylab.axis('off'); pylab.imshow(filtered_img[0, 0, :, :])
pylab.subplot(3, 1, 3); pylab.axis('off'); pylab.imshow(filtered_img[0, 1, :, :])
处理的结果如下图所示
所谓的“深度学习”(deep learning)里的“深度”其实就是人工神经网络的层次。我们这里介绍的卷积神经网络是各类深度学习模型中的一种。因为机器的增强-特别是并行计算,和数据量的加大,使得构建多层的人工神经网络模型变得可行。经过多层的处理,高层的神经元可以以非线性的方式储藏底层神经元的信息,最终形成对原始图像的抽象特征的理解。例如在这个例子中,我们识别出了图象的“边缘”。这样的学习,比起单纯地用一个分线性的分类器,例如logistic或者SVM,来理解数据里的非线性结构,无疑是更深刻的,也更贴近人脑的工作方式:使用抽象概念描述世界。深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-04-基于Python的LeNet之MLP - 技术博客 - CSDN博客
深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-04-基于Python的LeNet之MLP
NLP/DeepLearning
  本文主要参考于:
  python源代码  
  本文主要介绍含有单隐层的MLP的建模及实现。建议在阅读本博文之前,先看一下。因为LR是简化版的MLP。LR不含有单隐层,则其输入层直接连接到输出层。从何处可以看出LR是输入层直接连接输出层?借用上一博文的公式:P(Y=i|x,W,b)=softmaxi(Wx+b)。其中,x是输入层,softmax是激活函数,P就是输出层了。我们将其化简并转换为一般神经网络表达式:f(x)=g(Wx+b),其中g就是激活函数,f(x)就是输出层了。可见输入层经过激活函数得到的结果就是输出了。很简单吧。
  那么MLP的模型公式和LR又有什么不同呢?下面来看一下MLP的模型建立。
  从MLP的结构图中可以看出输入层与隐藏层全连接,然后,隐藏层与输出层全连接。那么整体的函数映射就是f:RD→RL,其中D是输入向量x的维度,L是输出向量f(x)的维度。用矩阵表示整个三层之间的关系如下:
  f(x)=G(W(2)(S(W(1)x+b(1)))+b(2))
  其中,b(1),b(2)分别是三层之间(输入层与隐层、隐层与输出层之间)的偏置向量;W(1),W(2)分别是三层之间的权值矩阵;而S,G是分别是三层之间的激活函数。
  对于连接单隐层的的表达式h(x)=Φ(x)=S(W(1)x+b(1)),其激活函数S常用的有tanh(a)=(ea-e-a)(ea+e-a)和sigmoid(a)=1(1+e-a)函数。在这里,我们将使用tanh作为激活函数,因为它通常能更快的达到训练目标。
  对于连接输出层的表达式o(x)=G(W(2)h(x)+b(2)),我们应该不是很陌生,就是在篇头或上一篇博文中讲到的LR的模型表达式,在那里面其激活函数用的是softmax,它可以用来多分类,那么在这里,G也是采用softmax多分类器来分类。
  接下来就是训练模型获取最佳参数,我们这里仍然采用MSGD(批量随机梯度下降法)方法。这里我们需要学习的参数为θ={W(2),b(2),W(1),b(1)}。同样,对于用链式法则求梯度?l/?θ,我们就用theano已经实现的T.grad()方法。
  讲到这里小伙伴们或许有疑问了:没有代价函数怎么求梯度啊?也就是?l/?θ中的l是什么啊?很简单,就是和LR中的代价函数基本是一样的(在后边还会讲到cost代价函数为什么是基本一样而不是一样),因为结构都是一样的,我们同样要处理的是对于手写数字MNIST的识别。最小化方法也是采用负对数似然函数,所以这里的l一清二楚了吧,还不清楚的,可以翻看LR的。
二、MLP代码实现
  我们主要关注实现含单隐层的MLP(只要单隐层的实现了,多隐层的就是多实例化几个隐层而已)。MLP的实现包括3部分:输入层、隐层、输出层。
  第一层:输入层就是我们直接的输入数据x,将其直接输入到第二层;
  第二层:隐层的功能是用tanh函数处理第一层的输入数据,并将结果作为第三层的输入数据。因此需要我们用代码实现,即根据LR实现一个隐层类;
  第三层:输出层的功能是将第二层的输入数据经过softmax函数,然后进行分类输出。因此和LR是一样的,所以这里直接调用上一篇定义的。
  先提前讲一下隐层权值的初始化问题。在LR类中,权值矩阵初始化为0。然而在隐层中就不能再初始化为0了,而是依据激活函数从symmetric interval(对称间隔)中均匀采样。这样初始化是为了确保在训练早期,每一个神经元都可以向后传播(upward)激活信息,向前传播(backward )梯度数据。也就是说在这一层用到了梯度反向传播,那么权值矩阵就不能初始化为0,不知道解释的如何?原文:(This
initialization ensures that, early in training, each neuron operates in a regime of its activation function where information can easily be propagated both upward (activations flowing from inputs to outputs) and backward (gradients flowing from outputs to
inputs))。
  那么具体的均匀采样范围是什么呢?
  对于函数tanh来说,interval为:[-6fanin+fanout--------√,6fanin+fanout--------√],其中fanin是第(i-1)层的单元个数;fanout是第i层的单元个数。如果对应到本实验,第(i-1)层就是输入层,输入层输入数据是样本数据,因此其单元个数是样本数据的长度;第i层就是隐层,其单元个数是需要实例化时传入的。具体的看下方代码。
  对于函数sigmoid来说,interval为:[-46fanin+fanout--------√,46fanin+fanout--------√]。
  可以从文献中获取以上范围的来因。是一个大牛写的论文,如果能看懂也很牛。
部分代码:
&code class=&language-python hljs
has-numbering&& &span class=&hljs-class&&&span class=&hljs-keyword&&class&/span& &span class=&hljs-title&&HiddenLayer&/span&&span class=&hljs-params&&(object)&/span&:&/span&
&span class=&hljs-function&&&span class=&hljs-keyword&&def&/span& &span class=&hljs-title&&__init__&/span&&span class=&hljs-params&&(self, rng, input, n_in, n_out, W=None, b=None, activation=T.tanh)&/span&:&/span&
&span class=&hljs-string&&'''
初始化函数!HiddenLayer实例化时调用该函数。该层与输入层是全连接,激活函数为tanh。
参数介绍:
rng 类型为:numpy.random.RandomState。
rng 功能为:rng是用来产生随机数的实例化对象。本类中用于对W进行随机数初始化。而非0值初始化。
input 类型为:符号变量T.dmatrix
input 功能为:代表输入数据(在这里其实就是传入的图片数据x,其shape为[n_examples, n_in],n_examples是样本的数量)
n_in 类型为:int
n_in 功能为:每一个输入样本数据的长度。和LR中一样,比如一张图片是28*28=784,
那么这里n_in=784,意思就是把图片数据转化为1维。
n_out 类型为:int
n_out 功能为:隐层单元的个数(隐层单元的个数决定了最终结果向量的长度)
activation 类型为:theano.Op 或者 function
activation 功能为:隐层的非线性激活函数
'''&/span&
self.input = input
&span class=&hljs-comment&&# 根据博文中的介绍,W应该按照均匀分布来随机初始化,其样本数据范围为:&/span&
&span class=&hljs-comment&&# [sqrt(-6./(fin+fout)),sqrt(6./(fin+fout))]&/span&
&span class=&hljs-comment&&# 根据博文中的说明,fin很显然就是n_in了,因为n_in就是样本数据的长度,即输入层的单元个数。&/span&
&span class=&hljs-comment&&# 同样,fout就是n_out,因为n_out是隐层单元的个数。&/span&
&span class=&hljs-comment&&# rng.uniform()的意思就是产生一个大小为size的矩阵,&/span&
&span class=&hljs-comment&&# 矩阵的每个元素值最小是low,最大是high,且所有元素值是随机均匀采样。&/span&
&span class=&hljs-keyword&&if&/span& W &span class=&hljs-keyword&&is&/span& &span class=&hljs-keyword&&None&/span&:
W_values = numpy.asarray(
rng.uniform(
low=-numpy.sqrt(&span class=&hljs-number&&6.&/span& / (n_in + n_out)),
high=numpy.sqrt(&span class=&hljs-number&&6.&/span& / (n_in + n_out)),
size=(n_in, n_out)
dtype=theano.config.floatX
&span class=&hljs-comment&&# 如果激活函数是sigmoid的话,每个元素的值是tanh的4倍。&/span&
&span class=&hljs-keyword&&if&/span& activation == theano.tensor.nnet.sigmoid:
W_values *= &span class=&hljs-number&&4&/span&
W = theano.shared(value=W_values, name=&span class=&hljs-string&&'W'&/span&, borrow=&span class=&hljs-keyword&&True&/span&)
&span class=&hljs-comment&&# 偏置b初始化为0,因为梯度反向传播对b无效&/span&
&span class=&hljs-keyword&&if&/span& b &span class=&hljs-keyword&&is&/span& &span class=&hljs-keyword&&None&/span&:
b_values = numpy.zeros((n_out,), dtype=theano.config.floatX)
b = theano.shared(value=b_values, name=&span class=&hljs-string&&'b'&/span&, borrow=&span class=&hljs-keyword&&True&/span&)
self.W = W
self.b = b
&span class=&hljs-comment&&# 计算线性输出,即无激活函数的结果,就等于最基本的公式 f(x)=Wx+b&/span&
&span class=&hljs-comment&&# 如果我们传入了自己的激活函数,那么就把该线性输出送入我们自己的激活函数,&/span&
&span class=&hljs-comment&&# 此处激活函数为非线性函数tanh,因此产生的结果是非线性的。&/span&
lin_output = T.dot(input, self.W) + self.b
self.output = (
&span class=&hljs-comment&&# 这个表达式其实很简单,就是其他高级语言里边的三目运算&/span&
&span class=&hljs-comment&&# condition?&True&:&false& 如果条件(activation is None)成立,&/span&
&span class=&hljs-comment&&# 则self.output=lin_ouput&/span&
&span class=&hljs-comment&&# 否则,self.output=activation(lin_output)&/span&
lin_output &span class=&hljs-keyword&&if&/span& activation &span class=&hljs-keyword&&is&/span& &span class=&hljs-keyword&&None&/span&
&span class=&hljs-keyword&&else&/span& activation(lin_output)
self.params = [self.W, self.b]&/code&&ul style=&display:& class=&pre-numbering&&&li&1&/li&&li&2&/li&&li&3&/li&&li&4&/li&&li&5&/li&&li&6&/li&&li&7&/li&&li&8&/li&&li&9&/li&&li&10&/li&&li&11&/li&&li&12&/li&&li&13&/li&&li&14&/li&&li&15&/li&&li&16&/li&&li&17&/li&&li&18&/li&&li&19&/li&&li&20&/li&&li&21&/li&&li&22&/li&&li&23&/li&&li&24&/li&&li&25&/li&&li&26&/li&&li&27&/li&&li&28&/li&&li&29&/li&&li&30&/li&&li&31&/li&&li&32&/li&&li&33&/li&&li&34&/li&&li&35&/li&&li&36&/li&&li&37&/li&&li&38&/li&&li&39&/li&&li&40&/li&&li&41&/li&&li&42&/li&&li&43&/li&&li&44&/li&&li&45&/li&&li&46&/li&&li&47&/li&&li&48&/li&&li&49&/li&&li&50&/li&&li&51&/li&&li&52&/li&&li&53&/li&&li&54&/li&&li&55&/li&&li&56&/li&&li&57&/li&&li&58&/li&&li&59&/li&&li&60&/li&&li&61&/li&&li&62&/li&&li&63&/li&&li&64&/li&&li&65&/li&&/ul&
  根据HiddenLayer类计算完结果后,我们相当于计算了公式h(x)=Φ(x)=S(W(1)x+b(1)),下面我们需要计算公式o(x)=G(W(2)h(x)+b(2)),然后根据前文的分析,第二个公式就是我们之前实现的LR。因此,我们只需要将隐层的结果作为LR的输入,即可实现MLP的功能。下面,我们来写一下MLP的代码:
&code class=&hljs python has-numbering&&&span class=&hljs-class&&&span class=&hljs-keyword&&class&/span& &span class=&hljs-title&&MLP&/span&&span class=&hljs-params&&(object)&/span&:&/span&
&span class=&hljs-string&&'''
多层感知机是一个前馈人工神经网络模型。它包含一个或多个隐层单元以及非线性激活函数。
中间层通常使用tanh或sigmoid作为激活函数,顶层(输出层)通常使用softmax作为分类器。
'''&/span&
&span class=&hljs-function&&&span class=&hljs-keyword&&def&/span& &span class=&hljs-title&&__init__&/span&&span class=&hljs-params&&(self, rng, input, n_in, n_hidden, n_out)&/span&:&/span&
&span class=&hljs-string&&'''
rng, input在前边已经介绍过。
n_in : int类型,输入数据的数目,此处对应的是输入的样本数据。
n_hidden : int类型,隐层单元数目
n_out : int类型,输出层单元数目,此处对应的是输入样本的标签数据的数目。
'''&/span&
&span class=&hljs-comment&&# 首先定义一个隐层,用来连接输入层和隐层。&/span&
self.hiddenLayer = HiddenLayer(
input=input,
n_in=n_in,
n_out=n_hidden,
activation=T.tanh
&span class=&hljs-comment&&# 然后定义一个LR层,用来连接隐层和输出层&/span&
self.logRegressionLayer = LR(
input=self.hiddenLayer.output,
n_in=n_hidden,
n_out=n_out
&span class=&hljs-comment&&# 规则化,常用的是L1和L2。是为了防止过拟合。&/span&
&span class=&hljs-comment&&# 其计算方式很简单。具体规则化的内容在文章下方详细说一下&/span&
&span class=&hljs-comment&&# L1项的计算公式是:将W的每个元素的绝对值累加求和。此处有2个W,因此两者相加。&/span&
self.L1 = (
abs(self.hiddenLayer.W).sum()
+ abs(self.logRegressionLayer.W).sum()
&span class=&hljs-comment&&# L2项的计算公式是:将W的每个元素的平方累加求和。此处有2个W,因此两者相加。&/span&
self.L2_sqr = (
(self.hiddenLayer.W ** &span class=&hljs-number&&2&/span&).sum()
+ (self.logRegressionLayer.W ** &span class=&hljs-number&&2&/span&).sum()
&span class=&hljs-comment&&# 和LR一样,计算负对数似然函数,计算误差。&/span&
self.negative_log_likelihood = (
self.logRegressionLayer.negative_log_likelihood
self.errors = self.logRegressionLayer.errors
self.params = self.hiddenLayer.params + self.logRegressionLayer.params
self.input = input&/code&&ul style=&display:& class=&pre-numbering&&&li&1&/li&&li&2&/li&&li&3&/li&&li&4&/li&&li&5&/li&&li&6&/li&&li&7&/li&&li&8&/li&&li&9&/li&&li&10&/li&&li&11&/li&&li&12&/li&&li&13&/li&&li&14&/li&&li&15&/li&&li&16&/li&&li&17&/li&&li&18&/li&&li&19&/li&&li&20&/li&&li&21&/li&&li&22&/li&&li&23&/li&&li&24&/li&&li&25&/li&&li&26&/li&&li&27&/li&&li&28&/li&&li&29&/li&&li&30&/li&&li&31&/li&&li&32&/li&&li&33&/li&&li&34&/li&&li&35&/li&&li&36&/li&&li&37&/li&&li&38&/li&&li&39&/li&&li&40&/li&&li&41&/li&&li&42&/li&&li&43&/li&&li&44&/li&&li&45&/li&&li&46&/li&&li&47&/li&&li&48&/li&&li&49&/li&&li&50&/li&&li&51&/li&&/ul&
  现在就来解释一下篇头中提到的代价函数是基本一样的原因。
  首先来说一下规则化。当我们训练模型试图让它在面对新的输入样本时产生更好的结果(就是有更好的泛化能力),我们往往会采用梯度下降方法。而本实验中用到的MSGD方法却没有考虑到一个问题,那就是过拟合现象。一旦出现过拟合,那么在面对新的样本时很难有好的结果。为了控制过拟合,一个比较有效的方法就是规格化。就是给每个参数θ(对应于W中的每一个元素)增加一个惩罚项,如果某个参数的系数非常大那么θ就会接近于0了。那么什么是L1和L2规格化呢?下面看一个公式,假设我们的代价函数是:
NLL(θ,D)=-∑i=0|D|logP(Y=y(i)|x(i),θ)(R-1)
  那么规则化后的代价函数就是:
E(θ,D)=NLL(θ,D)+λR(θ)(R-2)
  就是加入了一个λR(θ)。在我们的实验中,具体的公式如下:
E(θ,D)=NLL(θ,D)+λ||θ||pp(R-3)
  其中:
||θ||p=??∑j=0|θ||θj|p??1p(R-4)
  不难发现,当把公式(R-4)带入到公式(R-3)后,1p次方与p次方约掉,就剩下了:
E(θ,D)=NLL(θ,D)+λ∑j=0|θ||θj|p(R-5)
  (R-5)就是θ的Lp项;λ是一个很重的规则化参数。我们通常令Lp中的p取值为1或者2,这就是命名为L1和L2的原因。
  原则上,当代价函数中增添了规则化项之后会使得网络拟合函数时更加平滑。所以,理论上,最小化NLL与R(θ)的和等价于在拟合训练数据和找到一般性的解(分类超平面)之间找到最佳的权衡。根据Occam’s
razor规则,最小化加入规则化项的公式会使得我们更容易找到拟合训练数据的解(分类超平面)。
  实际上一个模型有一个简单的超平面解并不意味着它的泛化能力很好。实验证明,含有这种规格化项的神经网络的泛化能力更好,尤其是在比较小的数据集上。
下面来看一下带有规则化项的代价函数代码如何写:
&code class=&language-python hljs
has-numbering&&&span class=&hljs-comment&&# 代价函数,这是一个符号变量,cost并不是一个具体的数值。当传入具体的数据后,&/span&
&span class=&hljs-comment&&# 其才会有具体的数据产生。在原代价函数的基础上加入规则参数*规则项。&/span&
classifier.negative_log_likelihood(y)
+ L1_reg * classifier.L1
+ L2_reg * classifier.L2_sqr
)&/code&&ul style=&display:& class=&pre-numbering&&&li&1&/li&&li&2&/li&&li&3&/li&&li&4&/li&&li&5&/li&&li&6&/li&&li&7&/li&&/ul&
  最后就是参数求梯度以及参数更新,基本和LR的区别不大。训练模型函数、测试模型函数、验证模型函数和LR相同。至此,代码实现基本告一段落,可以运行测试。其他的代码注释不多,因为应该比较简单。只有一个mlp.py文件。下载来,直接python
mlp.py即可运行。如果有不懂的地方可以留言,也可以翻看上一篇。本文所介绍的mlp去对mnist分类官方给出的一个结果是:
&code class=&hljs livecodeserver has-numbering&&Optimization complete. Best validation score &span class=&hljs-operator&&of&/span& &span class=&hljs-number&&1.690000&/span& % obtained &span class=&hljs-keyword&&at&/span& iteration &span class=&hljs-number&&2070000&/span&, &span class=&hljs-operator&&with&/span& test performance &span class=&hljs-number&&1.650000&/span& %
The code &span class=&hljs-keyword&&for&/span& &span class=&hljs-built_in&&file&/span& mlp.py ran &span class=&hljs-keyword&&for&/span& &span class=&hljs-number&&97.34&/span&m&/code&&ul style=&display:& class=&pre-numbering&&&li&1&/li&&li&2&/li&&/ul&
  我也正在跑代码,因为还是比较耗时的。里边记录了目前为止所做过的实验以及结果。有兴趣的可以看一下。最好的误差能达到0.23%了,天呢,接近100%的识别率了。
参考目录:
转载来自:http://blog.csdn.net/niuwei22007/article/details/
我的热门文章}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信