一、多层感知机MLP

1、MLP概述

对于含有单个隐含层的多层感知机(single-hidden-layer Multi-Layer Perceptron, MLP),可以将其看成是一个特殊的Logistic回归分类器,这个特殊的Logistic回归分类器首先通过一个非线性变换Φ(non-linear transformation)对样本的输入进行非线性变换,然后将变换后的值作为Logistic回归的输入。非线性变换的目的是将输入的样本映射到一个空间,在该空间中,这些样本是线性可分的。这个中间层我们称之为隐含层(a hidden layer)。

A single hidden layer is sufficient to make MLPs a universal approximator.

2、MLP模型

对于含有单隐层的MLP模型(也可以称为人工神经网络,ANN)可以由下图表示:

在上图中,对于含有一个隐含层的MLP可以表示为:

f:RD→RL

其中,D指的是输入向量x的大小,L表示的是输出向量f(x)的大小,输出向量f(x)可以表示为:

f(x)=G(b(2)+W(2)(s(b(1)+W(1)x)))

其中,b(1)和b(2)是偏置,W(1)和W(2)是权重矩阵,s和G是激活函数。

隐含层的输出为h(x)=Φ(x)=s(b(1)+W(1)x)。W(1)∈RD×Dh是输入层到隐含层的权重向量,W(1)中的每一列代表从输入单元到第i个隐含单元的权重。对于激活函数s,可以使用tanh或者sigmoid函数,其中,tanh函数为:

tanh(a)=ea−e−aea+e−a

sigmoid函数为:

sigmoid(a)=11+e−a

选择激活函数tanh有时具有更快的训练速度和训练精度

输出向量为o(x)=G(b(2)+W(2)h(x))。(在下面的程序中G选择的是sigmoid函数,类似于Logistic Regression的多类别分类)。

3、MLP模型的训练

为了训练处MLP模型中的所有参数,可以使用带mini-batch的随机梯度下降法。需要学习的参数为:

θ={W(2),b(2),W(1),b(1)}

在这里,要获得梯度∂l∂θ可以使用backpropagation algorithm,这是一个链式求导的法则。

二、Tips和Tricks

在代码中存在着很多的超参数,有些参数的选择是不能通过梯度下降法得到的。严格来讲,这些超参数的最优解是不可解的。首先,我们不能单独的优化每一个超参数。其次,我们不能直接使用梯度下降法,因为有些超参数是离散的,有些超参数是连续的。最后,这是非凸优化问题,找到一个局部最优解需要花费很大的功夫。

在过去的25年中,研究者们已经设计出大量的经验法则用于在一个神经网络中选择超参数。

1、非线性变换

两个最常见的非线性函数是sigmoid函数和tanh函数。其中,tanh函数的形式为:

tanh(a)=ea−e−aea+e−a

sigmoid函数的形式为:

sigmoid(a)=11+e−a

对于非线性变换的选择,通常是选择关于原点对称的非线性变换。这是因为具有这样特性的变换能够为下一层产生零均值的输入。[Nonlinearities that are symmetric around the origin are preferred because they tend to produce zero-mean inputs to the next layer (which is a desirable property)].

从经验上看,tanh函数具有更好的收敛性。

2、权重向量的初始化

在初始化阶段,我们希望权重在原点的周围,而且尽可能的小,这样,激活函数对其进行操作就像是线性函数,此处的梯度也是最大的。

At initialization we want the weights to be small enough around the origin so that the activation function operates in its linear regime, where gradients are the largest. Other desirable properties, especially for deep networks, are to conserve variance of the activation as well as variance of back-propagated gradients from layer to layer.

对于tanh激活函数,权重的激活方法为在区间:

[−6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√,6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√]

上以均匀分布的方式产生随机数。而对于sigmoid激活函数,则是在区间:

[−4∗6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√,4∗6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√]

上以均匀分布的方式产生随机数。其中,fanin是i−1层节点的个数,而fanout是i层节点的个数。

3、学习率

有很多文章在讲如何选择一个好的学习率。最简单的办法是选择一个固定的学习率,即常数。经验法则:尝试一些对数空间的数,如10−2,10−3,⋯和通过网格搜索(grid search)不断缩小对数值以获得最小的验证误差。

随着代数不断减小学习率是一个很好的想法,一个简单的做法是:

u01+d×t

其中,u0是初始的学习率(可以通过上述的网格搜索的办法取得),d称为减少常数(decrease constant),控制着学习率的下降速度,通常是一个很小的正数,如10−3或者更小。t是epoch/stage。

4、隐含层节点的个数

这个超参数在很大程度上是取决于数据集的。笼统的说,对于越复杂的数据分布,神经网络需要越强的能力去对这批数据建模,因此,需要越多的隐含层节点个数。

除非我们使用一些正则化的策略,例如early stopping或者L1/L2惩罚,隐含层节点个数与泛化能力在图上表现为U字形的。

5、正则化参数

对于L1或者L2正则的参数λ有一些经验值,如10−2,10−3,⋯。

三、基于Theano的MLP实现解析

在利用Theano实现单隐层的MLP的过程中,主要分为如下几个步骤:

  1. 导入数据集
  2. 建立模型
  3. 训练模型
  4. 利用模型进行预测 
    接下来,对每个部分的代码进行解析。

1、导入数据集

导入数据集的代码部分与利用Theano理解深度学习——Logistic Regression中一致,就不再细说。

2、建立模型

在实现的过程中,可以将单隐层的MLP想像成LR模型中增加了一个隐含层,故在实现的过程中使用到了LR中的LogisticRegression类。此外,还增加了一个MLP类和HiddenLayer类。其中,MLP类是整个MLP算法的模型,具体的代码如下:

class MLP(object):
"""含单隐层的多层感知机类
多层感知机是一个前馈人工神经网络模型,该模型有一个或者多个隐含层单元和非线性的激活函数。
隐层层单元在“HiddenLayer”类中定义
顶层是一个softmax层,在“LogisticRegression”类中定义
"""
def __init__(self, rng, input, n_in, n_hidden, n_out):
"""初始化参数
:type rng: numpy.random.RandomState
:param rng: 随机数生成器,用于随机生成权重 :type input: theano.tensor.TensorType
:param input: 符号,用于表示输入 :type n_in: int
:param n_in: 输入单元的个数 :type n_hidden: int
:param n_hidden: 隐含层单元的个数 :type n_out: int
:param n_out: 输出层单元的个数
""" # 输入层到单个隐含层的初始化
self.hiddenLayer = HiddenLayer(
rng=rng,#随机数生成器
input=input,#输入
n_in=n_in,#输入层的节点个数
n_out=n_hidden,#输出层的节点个数
activation=T.tanh#激活函数
) # 隐含层到输出层的初始化
self.logRegressionLayer = LogisticRegression(
input=self.hiddenLayer.output,
n_in=n_hidden,
n_out=n_out
)
# L1正则
self.L1 = (
abs(self.hiddenLayer.W).sum()
+ abs(self.logRegressionLayer.W).sum()
) # L2正则
self.L2_sqr = (
(self.hiddenLayer.W ** 2).sum()
+ (self.logRegressionLayer.W ** 2).sum()
) # 损失函数的定义
self.negative_log_likelihood = (
self.logRegressionLayer.negative_log_likelihood
)
# 用于计算validation和testing的错误率
self.errors = self.logRegressionLayer.errors
# 声明所有的参数
self.params = self.hiddenLayer.params + self.logRegressionLayer.params
#声明输入
self.input = input

MLP类中主要的部分包括声明输入层到隐含层以及隐含层到输出层的结构,正则化的方法以及损失函数的定义和模型中的主要参数。在MLP类中使用到了HiddenLayer类和LogisticRegression类。其中HiddenLayer类用于定义隐含层的结构以及基本操作,LogisticRegression类用于定义输出层的结构以及基本操作,LogisticRegression类在利用Theano理解深度学习——Logistic Regression已经解析过,下面是HiddenLayer类的代码:

class HiddenLayer(object):
def __init__(self, rng, input, n_in, n_out, W=None, b=None, activation=T.tanh):
"""在MLP中,典型的隐含层中的节点是全连接的,使用的是sigmoid激活函数,权重矩阵W的大小为(n_in, n_out),
偏置向量b的大小为(n_out,)。在这里激活函数使用的是tanh
:type rng: numpy.random.RandomState
:param rng: 用于生成权重的随机数生成器 :type input: theano.tensor.dmatrix
:param input: 符号,输入 :type n_in: int
:param n_in: 输入层的节点个数 :type n_out: int
:param n_out: 输出层的节点个数 :type activation: theano.Op or function
:param activation: 激活函数的类型
"""
self.input = input if W is None:
'''对于权重矩阵W中的元素的初始化,若使用的激活函数是tanh,则使用均匀分布在区间[sqrt(-6./(n_in+n_hidden)),sqrt(6./(n_in+n_hidden))]上生成。
权重矩阵的初始化与选择的激活函数是相关联的。若使用sigmoid激活函数,则生成的数是tanh激活函数的4倍。
'''
W_values = numpy.asarray(
rng.uniform(low=-numpy.sqrt(6. / (n_in + n_out)), high=numpy.sqrt(6. / (n_in + n_out)), size=(n_in, n_out)),
dtype=theano.config.floatX
)
if activation == theano.tensor.nnet.sigmoid:
W_values *= 4 W = theano.shared(value=W_values, name='W', borrow=True) if b is None:
'''对于偏置向量b的初始化,使用的是全部初始化为0
'''
b_values = numpy.zeros((n_out,), dtype=theano.config.floatX)
b = theano.shared(value=b_values, name='b', borrow=True) self.W = W
self.b = b lin_output = T.dot(input, self.W) + self.b#线性的输出
#判断是选择线性的激活函数还是非线性的激活函数
self.output = (
lin_output if activation is None
else activation(lin_output)
)
# 声明模型中的参数
self.params = [self.W, self.b]

在定义好上述的结构之后就可以建立模型,详细的代码如下:

#2、建立模型
print '... building the model'
# 分配全局的符号
index = T.lscalar() # 用于指示batch
x = T.matrix('x')
y = T.ivector('y') rng = numpy.random.RandomState(1234)#随机数生成器 # 构造函数
classifier = MLP(
rng=rng,#随机数生成器
input=x,#输入
n_in=28 * 28,#输入的节点个数
n_hidden=n_hidden,#隐含层节点个数
n_out=10#输出的节点个数
) # 在训练的时候,所有的损失是损失函数+L1正则+L2正则
cost = (
classifier.negative_log_likelihood(y)
+ L1_reg * classifier.L1
+ L2_reg * classifier.L2_sqr
) #构造验证模型的函数
validate_model = theano.function(
inputs=[index],#输入为batch的索引
outputs=classifier.errors(y),#输出为每个batch上的错误率
givens={#x:样本,y:标签
x: valid_set_x[index * batch_size:(index + 1) * batch_size],
y: valid_set_y[index * batch_size:(index + 1) * batch_size]
}
) # 对每一个参数求偏导数
gparams = [T.grad(cost, param) for param in classifier.params] # 更新规则
updates = [
(param, param - learning_rate * gparam)
for param, gparam in zip(classifier.params, gparams)
] # 训练模型的函数
train_model = theano.function(
inputs=[index],#输入为batch的索引
outputs=cost,#输出为所有的损失
updates=updates,#更新参数的规则
givens={
x: train_set_x[index * batch_size: (index + 1) * batch_size],
y: train_set_y[index * batch_size: (index + 1) * batch_size]
}
)

1、正则化方法

正则化方法是防止模型过拟合(overfitting)的重要的方法,模型过拟合是指训练出来的模型在训练集上表现的很好,但是在未知的数据集上表现较差。在前面的LR的模型训练中,我们没有考虑到正则项,只是使用到了early-stopping策略。在这里我们考虑L1和L2正则。

L1和L2正则是指在损失函数的基础上增加一个额外的正则项,这个正则项的目的是为了对模型中的参数进行惩罚。若损失函数如下所示:

NLL(θ,D)=−∑i=0|D|logP(Y=y(i)∣x(i),θ)

则加入正则项的损失函数就变成:

E(θ,D)=NLL(θ,D)+λR(θ)

其中,R(θ)=∥θ∥pp

这里

∥θ∥p=⎛⎝⎜⎜∑j=0∣∣θ∣∣∣∣θj∣∣p⎞⎠⎟⎟1p

2、权重W的初始化

在权重的初始化过程中,我们希望权重的初始值在原点的附近。一些经验的做法是对于激活函数为tanh的情况下,权重的激活方法为在区间:

[−6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√,6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√]

上以均匀分布的方式产生随机数。而对于sigmoid激活函数,则是在区间:

[−4∗6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√,4∗6‾‾√fanin+fanout‾‾‾‾‾‾‾‾‾‾‾‾‾√]

上以均匀分布的方式产生随机数。其中,fanin是i−1层节点的个数,而fanout是i层节点的个数。

3、激活函数的选择

在本程序中,主要牵涉到的激活函数有两个,一个是tanh函数,另一个是sigmoid函数。其中,tanh函数的形式为:

tanh(a)=ea−e−aea+e−a

sigmoid函数的形式为:

sigmoid(a)=11+e−a

3、训练模型

训练模型的具体代码如下:

#3、训练模型
print '... training'
# early-stopping参数
patience = 10000
patience_increase = 2
improvement_threshold = 0.995
validation_frequency = min(n_train_batches, patience / 2) best_validation_loss = numpy.inf
best_iter = 0
start_time = timeit.default_timer() epoch = 0
done_looping = False while (epoch < n_epochs) and (not done_looping):
epoch = epoch + 1
for minibatch_index in xrange(n_train_batches): minibatch_avg_cost = train_model(minibatch_index)
# iteration number
iter = (epoch - 1) * n_train_batches + minibatch_index if (iter + 1) % validation_frequency == 0:
# compute zero-one loss on validation set
validation_losses = [validate_model(i) for i
in xrange(n_valid_batches)]
this_validation_loss = numpy.mean(validation_losses) print(
'epoch %i, minibatch %i/%i, validation error %f %%' %
(
epoch,
minibatch_index + 1,
n_train_batches,
this_validation_loss * 100.
)
) if this_validation_loss < best_validation_loss:
if (
this_validation_loss < best_validation_loss *
improvement_threshold
):
patience = max(patience, iter * patience_increase) best_validation_loss = this_validation_loss
best_iter = iter if patience <= iter:
done_looping = True
break end_time = timeit.default_timer()
print(('Optimization complete. Best validation score of %f %% '
'obtained at iteration %i') %
(best_validation_loss * 100., best_iter + 1))
print >> sys.stderr, ('The code for file ' +
os.path.split(__file__)[1] +
' ran for %.2fm' % ((end_time - start_time) / 60.))

4、利用模型进行预测

这部分的代码主要是将训练好的模型应用在新的测试数据集上,具体的代码如下:

'''增加了一段预测的代码
'''
# 4、利用模型进行预测
predict_model = theano.function(
inputs=[classifier.input],
outputs=classifier.logRegressionLayer.y_pred) test_set_x = test_set_x.get_value() predicted_values = predict_model(test_set_x[:10])#进行预测
print ("Predicted values for the first 10 examples in test set:")
print predicted_values

参考文献

利用Theano理解深度学习——Multilayer Perceptron的更多相关文章

  1. 从极大似然估计的角度理解深度学习中loss函数

    从极大似然估计的角度理解深度学习中loss函数 为了理解这一概念,首先回顾下最大似然估计的概念: 最大似然估计常用于利用已知的样本结果,反推最有可能导致这一结果产生的参数值,往往模型结果已经确定,用于 ...

  2. (转) 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

    特别棒的一篇文章,仍不住转一下,留着以后需要时阅读 基于Theano的深度学习(Deep Learning)框架Keras学习随笔-01-FAQ

  3. 从Image Caption Generation理解深度学习

    0. 前面的话 建丁让我写一篇深度学习相关小文章,目标读者是国内的开发者.刚接到这个任务时我是颇为忐忑的,写文章要讲究厚积薄发,如果“水之积也不厚”,“则其负大舟也无力”.因为我自知水平很有限,又不是 ...

  4. 基于Theano的深度学习框架keras及配合SVM训练模型

    https://blog.csdn.net/a819825294/article/details/51334397 1.介绍 Keras是基于Theano的一个深度学习框架,它的设计参考了Torch, ...

  5. 如何正确理解深度学习(Deep Learning)的概念

    现在深度学习在机器学习领域是一个很热的概念,不过经过各种媒体的转载播报,这个概念也逐渐变得有些神话的感觉:例如,人们可能认为,深度学习是一种能够模拟出人脑的神经结构的机器学习方式,从而能够让计算机具有 ...

  6. win7上安装theano keras深度学习框架

    近期在学习深度学习,需要在本机上安装keras框架,好上手.上网查了一些资料,弄了几天今天终于完全搞好了.本次是使用GPU进行加速,使用cpu处理的请查看之前的随笔keras在win7下环境搭建 本机 ...

  7. 【深度学习】perceptron(感知机)

    目录 1.感知机的描述 2.感知机解决简单逻辑电路,与门的问题. 2.多层感应机,解决异或门 个人学习笔记,有兴趣的朋友可参考. 1.感知机的描述 感知机(perceptron)由美国学者Frank ...

  8. 【论文笔记】如何理解深度学习中的End to End

    End to end:指的是输入原始数据,输出的是最后结果,应用在特征学习融入算法,无需单独处理. end-to-end(端对端)的方法,一端输入我的原始数据,一端输出我想得到的结果.只关心输入和输出 ...

  9. 基于Windows,Python,Theano的深度学习框架Keras的配置

    1.安装Anaconda 面向科学计算的Python IDE--Anaconda 2.打开Anaconda Prompt 3.安装gcc环境 (1)conda update conda (2)cond ...

随机推荐

  1. [Xcode 实际操作]三、视图控制器-(5)使用UINavigationController视图入栈和出栈

    目录:[Swift]Xcode实际操作 本文将演示使用导航控制器的几个跳转方式 选择编辑第二个视图控制器文件 import UIKit //定义一个全局变量,用来记录当前显示区域的视图的编号 clas ...

  2. Mac安装vue

     Mac安装vue 一.安装brew 打开终端运行以下命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com ...

  3. 基于ECharts的股票行情分时、K线、MACD、DIF、DEA图表 (绝无仅有)

    先上效果图 源码和使用说明已经开源至GitHub,欢迎各位能提出宝贵的意见噢 https://github.com/2557606319/H5-Kline

  4. IPv6邻居发现协议

    IPv6邻居发现协议 邻居发现协议NDP 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议.邻居发现协议替代了IPv4的ARP(Add ...

  5. POJ3696 The Luckiest Number 欧拉定理

    昨天终于把欧拉定理的证明看明白了...于是兴冲冲地写了2道题,发现自己啥都不会qwq 题意:给定一个正整数L<=2E+9,求至少多少个8连在一起组成正整数是L的倍数. 这很有意思么... 首先, ...

  6. little w and Sum(思维)

    链接:https://ac.nowcoder.com/acm/contest/297/B 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5242 ...

  7. ACM-ICPC 2018 徐州赛区网络预赛-G Trace(线段树的应用

    Problem:Portal传送门 Problem:Portal传送门  原题目描述在最下面.  我理解的题意大概是:有n次涨潮和退潮,每次的范围是个x×y的矩形,求n次涨退潮后,潮水痕迹的长度.   ...

  8. ubuntu查看系统版本和内核版本

    查看系统版本: cat /etc/issue sudo lsb_release -a 查看内核版本: uname -r

  9. Hadoop TaskScheduler源码分析

    TaskScheduler是MapReduce中的任务调度器.在MapReduce中,JobTracker接收JobClient提交的Job,将它们按InputFormat的划分以及其他相关配置,生成 ...

  10. Maven的学习资料收集--(七) 构建Spring项目

    在这里,使用Maven构建一个Spring项目 构建单独项目的话,其实都差不多 1. 新建一个Web项目 参考之前的博客 2.修改 pom.xml,添加Spring依赖 <project xml ...