[转]从零开始:用Python搭建神经网络

在这篇博客里,我们将从零开始搭建一个三层的神经网络。我们不会对用到的数学原理一一赘述,但我保证你可以直观地了解到我们在做什么。另外,你也可以通过文章内的链接来获取更详细的信息。
这儿我就假定你已经熟悉基础的微积分和机器学习的一些概念,比如分类和规范化,最好还能懂得一些优化神经网络的技术,比如梯度下降法。当然,即便你对以上提到的这些都不是很了解,我相信你还是能从这篇文章找到乐子的;-)
那从头来做到底有什么意义?我想,即便是以后使用神经网络库来做开发,比如PyBrain,一次(甚至多次)从头开始搭建网络的经历仍然可以作为极其宝贵的练习经验。它能够帮助你更好地了解神经网络的运作机制。而这也是设计高效的模型必经之路。
本文所展示的实例代码追求简单易懂,因此在效率上会打折扣。在我的下一篇推文中,我将展示如何通过Theano来实现一个高效率的神经网络。

生成数据集

让我们从生成所需要的数据集开始吧。幸运的是,scikit-learn提供了一些很有用的数据集生成器,让我们不必为之再造轮子,我们先试试make_moons。



生成了两类数据集,分别用红点和蓝点表示。你可以把蓝点想象成男性病人,红点想象成女性病人,把x轴和y轴想象成药物治疗剂量。
我们希望通过训练使得机器学习分类器能够在给定的x轴y轴坐标上预测正确的分类情况。我们无法用直线就把数据划分,可见这些数据样本呈非线性。那么,除非你手动构造非线性功能(例如多项式),否则,诸如逻辑回归(Logistic Regression)这类线性分类器将无法适用于这个案例。
事实上,这也正是神经网络的一大主要优势。神经网络的隐藏层会为你去学习特征,所以你不需要为构造特征这件事去操心。

逻辑回归

为了证明(学习特征)这点,让我们来训练一个逻辑回归分类器吧。以x轴,y轴的值为输入,它将输出预测的类(0或1)。为了简单起见,这儿我们将直接使用scikit-learn里面的逻辑回归分类器。


图表向我们展示了逻辑回归分类器经过学习最终得到的决策边界。尽管它尽可能地将数据区分为两类,却不能捕获到数据呈“月亮形状”的特性。

训练一个神经网络

现在,我们搭建由一个输入层,一个隐藏层,一个输出层组成的三层神经网络。输入层中的节点数由数据的维度来决定,也就是2个。相应的,输出层的节点数则是由类的数量来决定,也是2个。(因为我们只有一个预测0和1的输出节点,所以我们只有两类输出,实际中,两个输出节点将更易于在后期进行扩展从而获得更多类别的输出)。以x,y坐标作为输入,输出的则是两种概率,一种是0(代表女),另一种是1(代表男)。结果如下:



我们可以选择隐藏层的维度。放进去的节点越多,实现的功能就可以越复杂。但是维度过高也是会有代价的。首先,更多的预测以及学习网络参数意味着更高的计算强度,更多的参数也会带来过拟合的风险。
那么该如何判断隐藏层的规模呢?尽管总会有许多通用性很好的引导和推荐,但问题的差异性也不该被忽视。在我看来,选择规模这件事绝不仅仅是门科学,它更像是一门艺术。通过待会儿的演示,我们可以看到隐藏层里的节点数是怎么影响我们的输出的。
另外,我们还需要为隐藏层选择激活函数(activation function)。激活函数会将输入转化成输出。非线性的激活函数可以帮助我们处理非线性的假设。通常选用的激活函数有tanh, the sigmoid function, ReLUs。在这里我们将使用tanh这样一个适用性很好地函数。这些函数有一个优点,就是通过原始的函数值便可以计算出它们的导数。例如tanh的导数就是1-tanh2x。这让我们可以在推算出tanh⁡x一次后就重复利用这个得到导数值。
鉴于我们希望我们的网络输出的值为概率,所以我们将使用softmax作为输出层的激活函数,这个函数可以将原始的数值转化为概率。如果你很熟悉逻辑回归函数,你可以把它当做是逻辑回归的一般形式。

我们的网络是如何做出预测的呢?

神经网络通过前向传播做出预测。前向传播仅仅是做了一堆矩阵乘法并使用了我们之前定义的激活函数。如果该网络的输入x是二维的,那么我们可以通过以下方法来计算其预测值:


zi是第i层的输入,ai是该层应用激活函数后的输出i,Wi,bi是需要我们通过训练数据来获取的神经网络参数,你可以把它们当作在网络的层与层之间用于转化数据的矩阵。这些矩阵的维度可以通过上面的矩阵乘法看出来。如果我们在隐藏层上使用500个节点,那么就有 , , , 。可以看出,隐藏层的规模与可以用在隐藏层的节点数是呈正相关的。

研究参数

研究参数是为了找到能够使我们的训练数据集错误率最小化的参数()。但该如何定义错误呢?我们在这里会用损失函数(loss function)来检测错误。通常对softmax的输出,我们会选择明确的交叉熵损失(cross-entropy loss)(或者叫负对数似然)。如果我们有 N个训练示例,C个类别,那么预测相对于真实的有标签数据的损失则可以通过如下方法来计算获得:

这个公式看起来很复杂,它的功能就是对我们的训练示例进行求和,并加上预测值错误造成的损失。所以,标签值与预测值相差越大,损失就越大。通过寻找降低错误率的参数,我们可以实现最大似然。
我们可以使用梯度下降法来找到这些参数,这里,我会使用一种最普遍的方法:批量梯度下降法。这种方法的学习速率是固定的。它的衍化版例如SGD(随机梯度下降stochastic gradient descent)或者最小批量梯度下降(minibatch gradient descent)通常在实际使用中会有更好的效果。所以,如果您真的想要学习或者使用,那么请选择这些方法,最好还要能够实现逐渐衰减学习速率。
作为输入,梯度下降法需要各参数对应损失函数的梯度(导数的参数), , ,
。为了计算这些梯度,我们使用著名的后向传播算法。这种方法在通过输出计算梯度方面效率很高。您可以通过这些链接(链接1,链接2)来了解它,在这里我就不详细介绍它的原理了。
通过后向传播公式,我们找到了下面这些数据:

实现
接下来我们就要实现这个三层的神经网络了。首先,我们需要定义一些对用于梯度下降法的变量和参数。

首先,我们先实现之前定义的损失函数,这将用来评估我们的模型。

我们还要实现一个用于计算输出的辅助函数。它会通过定义好的前向传播方法来返回拥有最大概率的类别。

最后是训练神经网络的函数。它会使用我们之前找到的后向传播导数来进行批量梯度下降运算。

一个隐藏层规模为3的网络
让我们看看训练一个隐藏层规模为3的网络会发生什么。

喔~这看起来相当不错。我们的神经网络能够成功地找到区分不同类别的决策边界了。
变更隐藏层规模
在刚刚的示例中,我们选择了一个隐藏层规模为3的网络,现在我们来看看不同规模的隐藏层会带来什么样的效果。

我们可以看到,低维度的隐藏层很好地抓住了数据的整体趋势。高维度的隐藏层则显现出过拟合的状态。相对于整体性适应,它们更倾向于精确记录各个点。如果我们要在一个分散的数据集上进行测试(你也应该这么做),那么隐藏层规模较小的模型会因为更好的通用性从而获得更好的表现。虽然我们可以通过强化规范化来抵消过拟合,但选择正确的隐藏层规模相对来说会更“经济实惠”一点。
小练习
这儿有些可以帮助你更进一步理解代码的干货:

  1. 用最小批量梯度下降法替换梯度下降法来训练网络,这会帮助你的模型在实战中获得更好的表现。
  2. 我们使用的是固定学习速率来进行梯度下降。试着去实现学习速率逐步衰减的方法。
  3. 本文中,我们用tanh作为激活函数。试试其他的激活函数(有些我们之前已经提到过)。记住,改变激活函数也就意味着改变了后向传播导数。
  4. 将网络从两个类别拓展到三个类别。您将需要为此准备一个合适的数据集。
  5. 将网络拓展到四层,对不同层的规模进行测试。增加新的隐藏层意味着你的前向传播和后向传播代码都需要调整。
    所有的代码都可以在Github的iPython notebook上找到。欢迎您提出问题或者反馈:-)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容