deeplearning.net 0.1 document - Multilayer Perceptron

Multilayer Perceptron

下面我们使用Theano来介绍一下单隐藏层的多层感知机(MLP)。MLP可以看成一个logistic回归分类器,它使用一个已经学习的非线性转换器处理输入。这个转换器把输入变成一个线性可分离的空间。中间层被看作是隐藏层。单个隐藏层足够让MLPs普遍逼近,但是我们会在后面看到使用多层隐藏层是很有效的。

The Model

一个只有单层隐藏层的MLP可以表示成一下形式:

通常地,一个单隐藏层的MLP是一个函数。其中D是输入x的大小,L是输出向量f(x)的大小,f(x)的矩阵表示如下:

其中偏置项b,权重项W和激活函数G和s。

向量组成了隐藏层。是一个权值矩阵链接输入层和隐藏层。每一列代表到第i个隐藏层每个输入的权值。s的传统选择包括tanh函数,,或者sigmoid函数,。本教程我们使用tanh函数因为它训练得更快(有时会达到一个更好的局部最小值).tanh和sigmoid函数都是标量到标量的函数但是它们可以使用元素依次运算自然地扩展到向量或张量。

输出向量是。读者需知道我们之前在前一课的形式。以前,类别的成员概率可以被softmax函数来表示。

要训练一个MLP,我们要学习所有的参数,这里我们使用小批量随机下降。要学习的参数集是。使用梯度可以进行后向传播算法。值得感谢的是,Theano会自动实现这个过程,这里就不详述。

Going from logistic regression to MLP

本教程会关注单隐藏层的MLP。我们实现一个类来表示一个隐藏层。为了构造MLP我们将在后面在顶层使用logistic回归层。

class HiddenLayer(object):
    def __init__(self, rng, input, n_in, n_out, W=None, b=None, activation=T.tanh):
    ‘‘‘
    传统MLP的隐藏层:全链接并且使用sigmoid激活函数。权重矩阵大小为(n_in, n_out)
    偏置项b是(n_out,)

    提醒:非线性转换器使用tanh

    隐藏层单元的激活函数: tanh(dot(input, W) + b)

    :rng 类型: numpy.random.RandomState
    :rng 参数: 随机初始化权值

    :input 类型: theano.tensor.dmatrix
    :input 参数:符号张量,形状(n_examples, n_in)

    :n_in 类型: 整数
    :n_in 参数: 输入的维数

    :n_out 类型: 整数
    :n_out 参数: 隐藏层的维数

    :activation 类型: theano.Op
    :actibation 参数: 应用在隐藏层的非线性
    ‘‘‘
    self.input = input

隐藏层权值的初始化需要在对应激活函数的对称区间内抽样。对于tanh函数,,其中(fan)in是第i-1层单元的数量,(fan)out是第i层单元的数量。对于sigmoid函数。这样初始化保证了在训练的时候,激活函数的神经运算信息可以更容易地前向或者后向传播。

    # ‘W‘被‘W_values‘初始化,区间为tanh的[sqrt(-6./(n_in+n_hidden))
    # 到 sqrt(6./(n_in+n_hidden))]。
    # 定义输出的dtype为theano.config.floatX有利于在GPU上运算。
    # 提示:最佳的权值初始化取决于激活函数的使用。
    #      例如:[Xavier10]的结果建议你,对比tanh使用4倍大的sigmoid的权重
    #      但是我们没有其他函数的信息,所以我们使用和tanh相同的。
    if W is None:
        W_values = numpy.array(
            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 = thenao.shared(value=W_values, name=‘W‘, borrow=True)
    if b is None:
        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

我们使用一个给定的非线性函数当作隐藏层的激活函数。默认使用tanh,但是有些情况我们会使用其他函数。

    lin_output = T.dot(input, self.W) + self.b
    self.output = (
        lin_output if activation is None
        else activation(lin_output)
    )

如果你看过类实现图的理论计算。如果给定这个图当作输入传给之前实现的LogisticRegression类,你会获得MLP的输出。

class MLP(object):
    """Muti-Layer Perceptron Class

    一个多层感知机是一个前馈人工神经网络,它有一个或多个隐藏单元和非线性的激活器。
    中间层有一个激活函数tanh或者sigmoid函数(HiddenLayer类),另外顶层是一个
    softmax层(LogisticRegression)
    """

    def __init__(self, rng, input, n_in, n_hidden, n_out):
        # 当我们处理一个隐藏层,它链接一个激活函数tanh和一个Logistic回归层。
        # 激活函数可以被sigmoid函数或其他代替

        self.hiddenLayer = HiddenLayer(
            rng = rng,
            input=input,
            n_in=n_in,
            n_out=n_hidden,
            activation=T.tanh
        )

        # Logistic回归成获得隐藏层的输入
        self.logRegressionLayer = LogisticRegression(
            input = self.hiddenLayer.output,
            n_in = n_hidden,
            n_out=n_out
        )

本教程我们会使用L1和L2正则

    # 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
    )

    # 错误率
    self.errors = self.logRegressionLayer.errors

    # 两层的参数
    self.params = self.hiddenLayer.params + self.logRegressionLayer.parmas

在之前,我们用小批量随机下降法来训练模型。不同的是我们使用损失函数是带有L1和L2正则式的。L1_reg和L2_reg是控制权重的正则式。

    cost = (
        classifier.negative_log_likelihood(y)
        + L1_reg * classifier.L1
        + L2_reg * classifier.L2_sqr
    )

然后我们使用梯度来更新模型的参数。这段代码类似logsitic函数。只是参数数量不同而已。为了做到这样(可以运行在不同数量参数的代码),我们会使用参数列表,在每一代计算梯度。

    # 对列表的参数一个个求导
    gparams = [T.grad(cost, param) for param in classfier.params]

    # 约定怎样更新权值,形式是(值, 更新表达式)对

    # 给定两个相同长度的列表 A=[a1, a2, a3, a4]和
    # B = [b1, b2, b3, b4],zip操作生成一个
    # C = [(a1, b1), ..., (a4, b4)]
    updates = [
        (param, param - learning_rate * gparam)
        for param, gparam in zip(classifier.params, gparams)
    ]

    # 编译一个Theano函数‘train_model’返回损失并且更新权值
    train_model = theano.function(
        inputs = [index],
        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]
        }
    )

Putting it All Together

Tips and Tricks for training MLPs

在上面的代码中有一些超参数,它不能用梯度下降来优化。严格来说,找到一个最佳的解集不是一个可行的问题。第一,我们不能独立地优化每一个参数。第二,我们不能一下子应用前面说的梯度下降技术(一部分是因为一些参数是离散的,而另一些是实数的)。第三,优化问题不是一个凸优化,找到一个(局部)最优解会涉及一堆不重要的工作。

在过去的25年里,好消息是研究者在神经网络设计了很多选择超参数的规则。想了解更多可以看Yann LeCun,Leon Bottou,Genevieve Orr和Klaus-Robert的Efficient BackPro。在这里,我们总结一些方法,是一些我们应用在代码中的重点。

Nonlinearity

两个常用的方法是sigmoid和tanh,原因在Section 4.4中。非线性在刚开始对称因为它使输入变成平均值为0的输入到下一层。经验告诉我们,tanh有更好地收敛性质。

Weight initialization

在初始化我们想权值在刚开始时足够小,那样的话激活函数的运算就会在线性工作状态,这样导数最大。另外合适的性质,特别在深度网络,是保存激活器的方差和层与层之间的反向传播梯度的方差。这允许信息在向上和向下都很好地流动,减少层之间的差异。在某些假设下,两个限制的妥协导致了下面的初始化方式:

tanh初始化权值

sigmoid初始化权值

数学推导请看Xavier10

Learning rate

在文献上有好的处理方法。最简单的方法就是常数学习率。经验法则是:尝试几个对数空间值(10的-1, 10的-2, …)和缩小(对数的)格子去搜索哪里获得最小检验错误。

多次降低学习率有时是一个很好的方法。一个简单的规则就是,其中u0是初始学习率,d是下降常数来控制下降速度(通常一个小的正数,10的-3或更小),t是epoch/stage。

Section 4.7参看更多信息。

Number of hidden units

超参数很依赖于数据集。含糊地说,输入的分布越复杂,网络要建模的能力越强,就需要越多的隐藏层。

除非我们使用正则化,典型数量的隐藏层 vs. 泛化表现就像一个U字。

Regularization parameter

经典的方法就是使用L1/L2正则参数,10的-2,10的-3, …,在以后的框架里,优化这个参数不会带来什么显著的变化,但是有时也值得尝试。

时间: 2024-10-13 01:18:22

deeplearning.net 0.1 document - Multilayer Perceptron的相关文章

利用Theano理解深度学习——Multilayer Perceptron

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

MLP(multi-layer perceptron)

神经元neuron(基本计算单元) xi为输入,wi为各项输入的权重,b为偏差,f为激活函数,h为输出.输入的加权和,经过激活函数映射为输出. 参数的物理意义:权重(各输入的重要程度)偏差(该神经元被激活的难易程度≈阈值) 激活函数:常见有sigmoid函数,tanh(双曲正切)函数,线性整流函数ReLu sigmoid函数    将加权和缩放到[0,1],微分形式为   tanh函数   将加权和缩放到[-1,1] ,微分形式为 线性整流函数   分段函数,实际神经网络中更好用.梯度=0(z<

(翻译)deeplearning.net/tutorial —— 栈式去噪自编码器(SdA)

前言 栈式去噪自编码器是栈式自动编码器的扩展[Bengio07],并且它在[Vincent08]里有介绍. 这次教程建立在之前的去噪自编码器Denoising Autoencoders.如果你对自编码器没什么了解,建议你先了解一下. 栈式自编码器 通过把上一层去噪自编码器找到的隐藏输入(output code)当作下一层的输入,我们可以把去噪自编码器以栈的形式构成一个深度网络.这种无监督预训练的结构在一层里同时实现.每一层当作一个去噪自编码器,通过重构输入(上一层的输出)最小化损失.一旦前面 层

Apache Spark 1.5.0正式发布

Spark 1.5.0是1.x线上的第6个发行版.这个版本共处理了来自230+contributors和80+机构的1400+个patches.Spark 1.5的许多改变都是围绕在提升Spark的性能.可用性以及操作稳定性.Spark 1.5.0焦点在Tungsten项目,它主要是通过对低层次的组建进行优化从而提升Spark的性能.Spark 1.5版本为Streaming增加了operational特性,比如支持backpressure.另外比较重要的更新就是新增加了一些机器学习算法和工具,

DeepLearning tutorial(3)MLP多层感知机原理简介+代码详解

DeepLearning tutorial(3)MLP多层感知机原理简介+代码详解 @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43221829 本文介绍多层感知机算法,特别是详细解读其代码实现,基于python theano,代码来自:Multilayer Perceptron,如果你想详细了解多层感知机算法,可以参考:UFLDL教程,或者参考本文第一部分的算法简介. 经详细注释的代码:放在我的gith

DeepLearning之路(三)MLP

DeepLearning tutorial(3)MLP多层感知机原理简介+代码详解 @author:wepon @blog:http://blog.csdn.net/u012162613/article/details/43221829 本文介绍多层感知机算法,特别是详细解读其代码实现,基于Python theano,代码来自:Multilayer Perceptron,如果你想详细了解多层感知机算法,可以参考:UFLDL教程,或者参考本文第一部分的算法简介. 经详细注释的代码:放在我的gith

Apache Spark 2.2.0新特性介绍(转载)

这个版本是 Structured Streaming 的一个重要里程碑,因为其终于可以正式在生产环境中使用,实验标签(experimental tag)已经被移除.在流系统中支持对任意状态进行操作:Apache Kafka 0.10 的 streaming 和 batch API支持读和写操作.除了在 SparkR, MLlib 和 GraphX 里面添加新功能外,该版本更多的工作在系统的可用性(usability).稳定性(stability)以及代码的润色(polish)并解决了超过 110

支持向量机(SVM)选择训练方式使误差率尽可能减为0

今天看了有关支持向量机(Support vector machine,简称SVM )用来分类的内容,分别实现了对于判别城市消费水平和乳腺癌诊断的问题,在做乳腺癌诊断时,误差率问题卡壳了一个晚上,始终保持在0.014水平,无法减小到0.结果连SVM的基本原理都没有弄清,svmtrain(训练数据,分类组别,'Method','具体的方法','Kernel_Function','训练方式)函数的训练方式主要有:"linear"(线性,默认属性)."quadratic"(

经典网络复现(0)多层感知机和lenet

对于mnist数据集,我实现了一些简单的网络,同样在20epochs训练获得的loss和acc 序号 网络结构 loss和acc 2 model = Sequential() model.add(Dense(units = 121,input_dim = 28 * 28)) model.add(Activation('relu')) model.add(Dense(units = 81)) model.add(Activation('relu')) model.add(Dense(units =