python做神经网络选择scikit-learn neurolab keras_《Scikit-Learn、Keras与TensorFlow机器学习实用指南(第二版)》第10章 使用Keras搭建人...

Aurélien 在写第二版时,对下半部分深度学习各章节的修订非常非常大(前面机器学习的部分更改只有10%,只是新加了一个第9章),所以还是先看变动大的深度学习部分吧。看了第10章,真是比第一版强太多了,讲的特别细,特别有耐心。

鸟类启发人类飞翔,东洋参启发了魔术贴的发明,大自然启发人类实现了无数发明创造。通过研究大脑来制造智能机器,也符合这个逻辑。人工神经网络(ANN)就是沿着这条逻辑诞生的:人工神经网络是受大脑中的生物神经元启发而来的机器学习模型。但是,虽然飞机是受鸟儿启发而来的,飞机却不用挥动翅膀。相似的,人工神经网络和生物神经元网络也是具有不同点的。一些研究者甚至认为,应该彻底摒弃这种生物学类比:例如,用“单元”取代“神经元”,以免人们将创造力局限于生物学系统的合理性上。

人工神经网络是深度学习的核心,它不仅样式多样、功能强大,还具有可伸缩性,这让人工神经网络适宜处理庞大且复杂的机器学习任务,例如对数十亿张图片分类(谷歌图片)、语音识别(苹果Siri)、向数亿用户每天推荐视频(Youtube)、或者通过学习几百围棋世界冠军(DeepMind的AlphaGo)。

本章的第一部分会介绍人工神经网络,从一个简单的ANN架构开始,然后过渡到多层感知机(MLP),后者的应用非常广泛(后面的章节会介绍其他的架构)。第二部分会介绍如何使用流行的Keras API搭建神经网络,Keras API是一个设计优美、简单易用的高级API,可以用来搭建、训练、评估、运行神经网络。Keras的易用性,并不妨碍它具有强大的实现能力,Keras足以帮你搭建多种多样的神经网络。事实上,Keras足以完成大多数的任务啦!要是你需要实现更多的功能,你可以用Keras的低级API(第12章介绍)自己写一些组件。

从生物神经元到人工神经元

颇让人惊讶的地方是,其实ANN已经诞生相当长时间了:神经生理学家Warren McCulloch和数学家Walter Pitts在1943年首次提出了ANN。在他们里程碑的论文《A Logical Calculus of Ideas Immanent in Nervous Activity》中(https://scholar.google.com/scholar?q=A+Logical+Calculus+of+Ideas+Immanent+in+Nervous+Activity+author%3Amcculloch),McCulloch 和 Pitts介绍一个简单的计算模型,关于生物大脑的神经元是如何通过命题逻辑协同工作的。这是第一个ANN架构,后来才出现更多的ANN架构。

ANN的早期成功让人们广泛相信,人类马上就能造出真正的智能机器了。1960年代,当这个想法落空时,资助神经网络的钱锐减,ANN进入了寒冬。1980年代早期,诞生了新的神经网络架构和新的训练方法,连结主义(研究神经网络)复苏,但是进展很慢。到了1990年代,出现了一批强大的机器学习方法,比如支持向量机(见第05章)。这些新方法的结果更优,也比ANN具有更扎实的理论基础,神经网络研究又一次进入寒冬。我们正在经历的是第三次神经网络浪潮。这波浪潮会像前两次那样吗?这次与前两次有所不同,这一次会对我们的生活产生更大的影响,理由如下:

我们现在有更多的数据,用于训练神经网络,在大而复杂的问题上,ANN比其它ML技术表现更好;

自从1990年代,计算能力突飞猛进,现在已经可以在理想的时间内训练出大规模的神经网络了。一部分原因是摩尔定律(在过去50年间,集成电路中的组件数每两年就翻了一倍),另外要归功于游戏产业,后者生产出了强大的GPU显卡。还有,云平台使得任何人都能使用这些计算能力;

训练算法得到了提升。虽然相比1990年代,算法变化不大,但这一点改进却产生了非常大的影响;

在实践中,人工神经网络的一些理论局限没有那么强。例如,许多人认为人工神经网络训练算法效果一般,因为它们很可能陷入局部最优,但事实证明,这在实践中是相当罕见的(或者如果它发生,它们也通常相当接近全局最优);

ANN已经进入了资助和进步的良性循环。基于ANN的惊艳产品常常上头条,从而吸引了越来越多的关注和资金,促进越来越多的进步和更惊艳的产品。

生物神经元

在讨论人工神经元之前,先来看看生物神经元(见图10-1)。这是动物大脑中一种不太常见的细胞,包括:细胞体(含有细胞核和大部分细胞组织),许多貌似树枝的树突,和一条非常长的轴突。轴突的长度可能是细胞体的几倍,也可能是一万倍。在轴突的末梢,轴突分叉成为终树突,终树突的末梢是突触,突触连接着其它神经元的树突或细胞体。

生物神经元会产生被称为“动作电位”(或称为信号)的短促电脉冲,信号沿轴突传递,使突触释放出被称为神经递质的化学信号。当神经元在几毫秒内接收了足够量的神经递质,这个神经元也会发送电脉冲(事实上,要取决于神经递质,一些神经递质会禁止发送电脉冲)。

图10-1 生物神经元

独立的生物神经元就是这样工作的,但因为神经元是处于数十亿神经元的网络中的,每个神经元都连着几千个神经元。简单神经元的网络可以完成高度复杂的计算,就好像蚂蚁齐心协力就能建成复杂的蚁冢一样。生物神经网络(BNN)如今仍是活跃的研究领域,人们通过绘制出了部分大脑的结构,发现神经元分布在连续的皮层上,尤其是在大脑皮质上(大脑外层),见图10-2。

图10-2 人类大脑皮质的多层神经元网络

神经元的逻辑计算

McCulloch和Pitts提出了一个非常简单的生物神经元模型,它后来演化成了人工神经元:一个或多个二元(开或关)输入,一个二元输出。当达到一定的输入量时,神经元就会产生输出。在论文中,两位作者证明就算用如此简单的模型,就可以搭建一个可以完成任何逻辑命题计算的神经网络。为了展示网络是如何运行的,我们自己亲手搭建一些不同逻辑计算的ANN(见图10-3),假设有两个活跃的输入时,神经元就被激活。

图10-3 不同逻辑计算的ANN

这些网络的逻辑计算如下:

左边第一个网络是确认函数:如果神经元 A 被激活,那么神经元 C 也被激活(因为它接收来自神经元 A 的两个输入信号),但是如果神经元 A 关闭,那么神经元 C 也关闭。

第二个网络执行逻辑 AND:神经元 C 只有在激活神经元 A 和 B(单个输入信号不足以激活神经元 C)时才被激活。

第三个网络执行逻辑 OR:如果神经元 A 或神经元 B 被激活(或两者),神经元 C 被激活。

最后,如果我们假设输入连接可以抑制神经元的活动(生物神经元是这样的情况),那么第四个网络计算一个稍微复杂的逻辑命题:如果神经元 B 关闭,只有当神经元A是激活的,神经元 C 才被激活。如果神经元 A 始终是激活的,那么你得到一个逻辑 NOT:神经元 C 在神经元 B 关闭时是激活的,反之亦然。

你可以很容易地想到,如何将这些网络组合起来计算复杂的逻辑表达式(参见本章末尾的练习)。

感知机

感知器是最简单的人工神经网络结构之一,由 Frank Rosenblatt 发明于 1957年。它基于一种稍微不同的人工神经元(见图 10-4),阈值逻辑单元(TLU),或称为线性阈值单元(LTU):输入和输出是数字(而不是二元开/关值),并且每个输入连接都一个权重。TLU计算其输入的加权和(z = W1x1 + W2x2 + ... + Wnxn = xT·W),然后将阶跃函数应用于该和,并输出结果:hW(x) = step(z),其中z = xT·W。

图10-4 阈值逻辑单元:人工神经元做权重求和,然后对和做阶跃函数

感知机最常用的阶跃函数是单位阶跃函数(Heaviside step function),见公式10-1。有时候也使用符号函数sgn。

公式10-1 感知机常用的阶跃函数,阈值为0

单一TLU 可用于简单的线性二元分类。它计算输入的线性组合,如果结果超过阈值,它输出正类或者输出负类(就像逻辑回归分类或线性SVM分类)。例如,你可以使用单一 TLU,基于花瓣长度和宽度分类鸢尾花(也可添加额外的偏置特征x0=1,就像我们在前面章节所做的那样)。训练 TLU 意味着去寻找合适的W0、W1和W2值(训练算法稍后提到)。

感知器只由一层 TLU 组成,每个TLU连接到所有输入。当一层的神经元连接着前一层的每个神经元时,该层被称为全连接层,或紧密层。感知机的输入来自输入神经元,输入神经元只输出从输入层接收的任何输入。所有的输入神经元位于输入层。此外,通常再添加一个偏置特征(X0=1):这种偏置特性通常用一种称为偏置神经元的特殊类型的神经元来表示,它总是输出 1。图10-5展示了一个具有两个输入和三个输出的感知机,它可以将实例同时分成为三个不同的二元类,这使它成为一个多输出分类器。。

图10-5 一个具有两个输入神经元、一个偏置神经元和三个输出神经元的感知机架构

借助线性代数,利用公式10-2可以方便地同时算出几个实例的一层神经网络的输出。

公式10-2 计算一个全连接层的输出

在这个公式中,

X表示输入特征矩阵,每行是一个实例,每列是一个特征;

权重矩阵W包含所有的连接权重,除了偏置神经元。每有一个输入神经元权重矩阵就有一行,神经层每有一个神经元权重矩阵就有一列;

偏置矢量b含有所有偏置神经元和人工神经元的连接权重。每有一个人工神经元就对应一个偏置项;

函数

被称为激活函数,当人工神经网络是TLU时,激活函数是阶跃函数(后面会讨论更多的激活函数)。

那么感知器是如何训练的呢?Frank Rosenblatt 提出的感知器训练算法在很大程度上受到 Hebb 规则的启发。在 1949 出版的《行为组织》一书中,Donald Hebb 提出,当一个生物神经元经常触发另一个神经元时,这两个神经元之间的联系就会变得更强。这个想法后来被 Siegrid Löwel 总结为一经典短语:“一起燃烧的细胞,汇合在一起。”这个规则后来被称为 Hebb 规则(或 Hebbian learning)。使用这个规则的变体来训练感知器,该规则考虑了网络所犯的误差。更具体地,感知器一次被馈送一个训练实例,对于每个实例,它进行预测。对于每一个产生错误预测的输出神经元,修正输入的连接权重,以获得正确的预测。公式 10-3 展示了Hebb 规则。

公式10-3 感知机的学习规则(权重更新)

在这个公式中:

其中wi,j是第i个输入神经元与第j个输出神经元之间的连接权重;

xi是当前训练实例的第i个输入值;

j是当前训练实例的第j个输出神经元的输出;

yj是当前训练实例的第j个输出神经元的目标输出;

η是学习率。

每个输出神经元的决策边界是线性的,因此感知器不能学习复杂的模式(比如 Logistic 回归分类器)。然而,如果训练实例是线性可分的,Rosenblatt 证明该算法将收敛到一个解。这被称为感知器收敛定理。

Scikit-Learn 提供了一个Perceptron类,它实现了一个 单TLU 网络。它可以实现大部分功能,例如用于 iris 数据集(第4章中介绍过):

import numpy as np

from sklearn.datasets import load_iris

from sklearn.linear_model import Perceptron

iris = load_iris()

X = iris.data[:, (2, 3)] # petal length, petal width

y = (iris.target == 0).astype(np.int) # Iris setosa?

per_clf = Perceptron()

per_clf.fit(X, y)

y_pred = per_clf.predict([[2, 0.5]])

你可能注意到,感知器学习算法和随机梯度下降很像。事实上,sklearn 的Perceptron类相当于使用具有以下超参数的 SGDClassifier:loss="perceptron",learning_rate="constant",eta0=1(学习率),penalty=None(无正则化)。

与逻辑回归分类器相反,感知机不输出类概率,而是基于硬阈值进行预测。这是逻辑回归优于感知机的一点。

在1969 年题为“感知机”的专著中,Marvin Minsky 和 Seymour Papert 强调了感知器的许多严重缺陷,特别是它们不能解决一些琐碎的问题(例如,异或(XOR)分类问题);参见图 10-6 的左侧)。当然,其他的线性分类模型(如 Logistic 回归分类器)也都实现不了,但研究人员期望从感知器中得到更多,他们的失望是很大的,导致许多人彻底放弃了神经网络,而是转向高层次的问题,如逻辑、问题解决和搜索。

然而,事实证明,感知机的一些局限性可以通过堆叠多个感知机消除。由此产生的人工神经网络被称为多层感知机(MLP)。特别地,MLP 可以解决 XOR 问题,你可以通过计算图 10-6 右侧所示的 MLP 的输出来验证输入的每一个组合:输入(0, 0)或(1, 1)网络输出 0,输入(0, 1)或(1, 0)它输出 1。除了四个连接的权重不是1,其它连接都是1。

图10-6 XOR分类问题和MLP

多层感知机与反向传播

MLP 由一个输入层、一个或多个称为隐藏层的 TLU 组成,一个 TLU 层称为输出层(见图 10-7)。靠近输入层的层,通常被称为浅层,靠近输出层的层通常被称为上层。除了输出层,每一层都有一个偏置神经元,并且全连接到下一层。

图10-7 多层感知器

注意:信号是从输入到输出单向流动的,因此这种架构被称为前馈神经网络(FNN)。

当人工神经网络有多个隐含层时,称为深度神经网络(DNN)。深度学习研究的是DNN和深层计算模型。但是大多数人用深度学习泛化代替神经网络,即便网络很浅时。

多年来,研究人员努力寻找一种训练 MLP 的方法,但没有成功。但在 1986,David Rumelhart、Geoffrey Hinton、Ronald Williams 发表了一篇突破性的论文(https://scholar.google.com/scholar?q=Learning+Internal+Representations+by+Error+Propagation+author%3Arumelhart),提出了至今仍在使用的反向传播训练算法。总而言之,反向传播算法是使用了高效梯度计算的梯度下降算法(见第4章):只需要两次网络传播(一次向前,一次向后),就可以算出网络误差的、和每个独立模型参数相关的梯度。换句话说,反向传播算法为了减小误差,可以算出每个连接权重和每个偏置项的调整量。当得到梯度之后,就做一次常规的梯度下降,不断重复这个过程,直到网络得到收敛解。

笔记:自动计算梯度被称为自动微分。有多种自动微分的方法,各有优缺点。反向传播使用的是反向模式自微分。这种方法快而准,当函数有多个变量(连接权重)和多个输出(损失函数)要微分时也能应对。附录D介绍了自微分。

对BP做详细分解:

每次处理一个微批次(假如每个批次包含32个实例),用训练集多次训练BP,每次被称为一个周期(epoch);

每个微批次先进入输入层,输入层再将其发到第一个隐藏层。计算得到该层所有神经元的(微批次的每个实例的)输出。输出接着传到下一层,直到得到输出层的输出。这个过程就是前向传播:就像做预测一样,只是保存了每个中间结果,中间结果要用于反向传播;

然后计算输出误差(使用损失函数比较目标值和实际输出值,然后返回误差);

接着,计算每个输出连接对误差的贡献量。这是通过链式法则(就是对多个变量做微分的方法)实现的;

然后还是使用链式法则,计算最后一个隐藏层的每个连接对误差的贡献,这个过程不断向后传播,直到到达输入层。

最后,BP算法做一次梯度下降步骤,用刚刚计算的误差梯度调整所有连接权重。

BP算法十分重要,再归纳一下:对每个训练实例,BP算法先做一次预测(前向传播),然后计算误差,然后反向通过每一层以测量误差贡献量(反向传播),最后调整所有连接权重以降低误差(梯度下降)。(译者注:我也总结下吧,每次训练都先是要设置周期epoch数,每次epoch其实做的就是三件事,向前传一次,向后传一次,然后调整参数,接着再进行下一次epoch。)

警告:随机初始化隐藏层的连接权重是很重要的。假如所有的权重和偏置都初始化为0,则在给定一层的所有神经元都是一样的,BP算法对这些神经元的调整也会是一样的。换句话,就算每层有几百个神经元,模型的整体表现就像每层只有一个神经元一样,模型会显得笨笨的。如果权重是随机初始化的,就可以打破对称性,训练出不同的神经元。

为了使BP算法正常工作,作者对 MLP 的架构做了一个关键调整:用Logistic函数(sigmoid)代替阶跃函数,σ(z) = 1 / (1 + exp(–z))。这是必要的,因为阶跃函数只包含平坦的段,因此没有梯度(梯度下降不能在平面上移动),而 Logistic函数处处都有一个定义良好的非零导数,允许梯度下降在每步上取得一些进展。反向传播算法也可以与其他激活函数一起使用,下面就是两个流行的激活函数:

双曲正切函数: tanh (z) = 2σ(2z) – 1

类似 Logistic 函数,它是 S 形、连续可微的,但是它的输出值范围从-1到1(不是 Logistic 函数的 0 到 1),这往往使每层的输出在训练开始时或多或少都变得以 0 为中心,这常常有助于加快收敛速度。

ReLU 函数:ReLU(z) = max(0, z)

ReLU 函数是连续的,但是在z=0时不可微(斜率突然改变,导致梯度下降在0点左右跳跃),ReLU的变体是当z<0时,z=0。但在实践中,ReLU效果很好,并且具有计算快速的优点,于是成为了默认激活函数。最重要的是,它没有最大输出值,这有助于减少梯度下降期间的一些问题(第 11 章再介绍)。

这些流行的激活函数及其变体如图 10-8 所示。但是,究竟为什么需要激活函数呢?如果将几个线性变化链式组合起来,得到的还是线性变换。比如,对于 f(x) = 2x + 3 和 g(x) = 5x – 1 ,两者组合起来仍是线性变换:f(g(x)) = 2(5x – 1) + 3 = 10x + 1。如果层之间不具有非线性,则深层网络和单层网络其实是等同的,这样就不能解决复杂问题。相反的,足够深且有非线性激活函数的DNN,在理论上可以近似于任意连续函数。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值