text.html 12.4 KB
Newer Older
ToTensor's avatar
ToTensor 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
 
<p class="content">理论内容讲了不少,同学们可能听得有点发懵。现在可以轻松一点了,接下来用更深的神经网络来处理那个银行客户流失案例。你们会发现搭建深层神经网络完全没有想象的那么难。因为神经网络模型的各种组件在Keras中都已经封装好了,我们拿过来组合一下就能用。</p> 
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0203-0291.jpg">咖哥发言</p> 
<p class="content">随着网络加深,参数增多,对硬件的要求提高,可以在Kaggle的Settings中把GPU选项设置为打开,如右图所示。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0203-0292.jpg"> 
 <p class="imgtitle">打开GPU设置</p> 
</div> 
<h3 class="thirdTitle" id="bw157"><a >5.7.1 构建深度神经网络</a></h3> 
<p class="content">搭建多层的神经网络,还是使用序贯模型。下面随意地添加几层看一看效果:</p> 
<p class="content">ann = Sequential() # 创建一个序贯ANN模型</p> 
<div class="content_106"> 
 <p class="content_105">ann.add(Dense(units=12, input_dim=12, activation = 'relu')) # 添加输入层</p> 
 <p class="content_105">ann.add(Dense(units=24, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dense(units=48, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dense(units=96, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dense(units=192, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层</p> 
 <p class="content_105"># 编译神经网络, 指定优化器、损失函数, 以及评估指标</p> 
 <p class="content_105">ann.compile(optimizer = 'rmsprop', # 此处我们先试试RMSP优化器</p> 
 <p class="content_111">loss = 'binary_crossentropy', # 损失函数</p> 
 <p class="content_111">metrics = ['acc']) # 评估指标</p> 
</div> 
<p class="content">不管是浅层网络,还是深层网络,构建起来真的很简单。因为深度学习背后的思想本来就很简单,那么它的实现过程又何必要那么痛苦呢?—这话可不是我说的,是Keras的发明者François Chollet说的。我表示很赞同。</p> 
<p class="content">来看看这个网络的效果:</p> 
<div class="content_106"> 
 <p class="content_105">history = ann.fit(X_train, y_train, # 指定训练集</p> 
 <p class="content_119">epochs=30,    # 指定轮次</p> 
 <p class="content_119">batch_size=64,  # 指定批量大小</p> 
 <p class="content_119">validation_data=(X_test, y_test)) # 指定验证集</p> 
</div> 
<p class="content">训练结束之后,采用同样的方法对测试集进行预测,并显示损失曲线和准确率曲线,同时显示分类报告(这里就不重复展示相同的代码了)。</p> 
<p class="content">观察训练及预测结果之后我们有一些发现。</p> 
<p class="content">第一,发现较深的神经网络训练效率要高于小型网络,一两个轮次之后,准确率迅速提升到0.84以上,而单隐层神经网络需要好几轮才能达到这个准确率:</p> 
<div class="content_106"> 
 <p class="content_109">Train on 8000 samples, validate on 2000 samples</p> 
 <p class="content_109">Epoch 1/30</p> 
 <p class="content_109">8000/8000 [===================] - 3s 320us/step - loss: 0.4359 - acc: 0.8199</p> 
 <p class="content_156">- val_loss: 0.4229 - val_acc: 0.8290</p> 
 <p class="content_109">Epoch 2/30</p> 
 <p class="content_109">8000/8000 [===================] - 1s 180us/step - loss: 0.3780 - acc: 0.8475</p> 
 <p class="content_156">- val_loss: 0.3893 - val_acc: 0.8445</p> 
 <p class="content_109">Epoch 3/30</p> 
 <p class="content_109">8000/8000 [===================] - 1s 180us/step - loss: 0.3670 - acc: 0.8574</p> 
 <p class="content_156">- val_loss: 0.3818 - val_acc: 0.8445</p> 
 <p class="content_109">Epoch 4/30</p> 
 <p class="content_109">8000/8000 [===================] - 1s 182us/step - loss: 0.3599 - acc: 0.8581</p> 
 <p class="content_156">- val_loss: 0.3842 - val_acc: 0.8480</p> 
</div> 
<p class="content">第二,从准确率上看,没有什么提升;而从F1分数上看,目前这个比较深的神经网络反而不如简单的单隐层神经网络,从0.58下降到0.55:</p> 
<div class="content_106"> 
 <p class="content_117">precision  recall f1-score  support</p> 
 <p class="content_116">0    0.87   0.97   0.92    1583</p> 
 <p class="content_116">1    0.80   0.42   0.55     417</p> 
</div> 
<p class="content">第三,从损失函数图像上看(如下图所示),深度神经网络在几轮之后就开始出现过拟合的问题,而且验证集上损失的波动也很大。因为随着轮次的增加,训练集的误差值逐渐减小,但是验证集的误差反而越来越大了。也就是说,网络的参数逐渐地对训练集的数据形成了过高的适应性。这对于较大网络来说的确是常见情况。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0204-0293.jpg"> 
 <p class="imgtitle">验证集上损失的波动很大</p> 
</div> 
<h3 class="thirdTitle" id="bw158"><a >5.7.2 换一换优化器试试</a></h3> 
<p class="content_105">网络变深了,预测准确率和F1分数反而降低了。大家的心情十分沮丧。该如何是好呢?</p> 
<p class="content_105">没有任何经验的同学们只好看着咖哥,希望他给出一些方向。</p> 
<p class="content_105">咖哥咳嗽两声,说:“对于某些简单问题,本来小网络的效能就是要高于深的网络。网络参数多,有时并不是一件好事。当然,我们还是可以做一些尝试。第一步,先更换一下优化器,把它从RMSProp换成Adam,如下段代码所示。”</p> 
<div class="content_106"> 
 <p class="content_105">ann.compile(optimizer = 'adam', # 换一下优化器</p> 
 <p class="content_111">loss = 'binary_crossentropy', # 损失函数</p> 
 <p class="content_111">metrics = ['acc']) # 评估指标</p> 
</div> 
<p class="content">更换优化器之后,重新训练、测试网络。发现最为关心的F1分数有所上升,上升至0.56,如下输出结果所示。但这仍然低于单隐层神经网络的0.58:</p> 
<div class="content_106"> 
 <p class="content_117">precision  recall f1-score  support</p> 
 <p class="content_116">0    0.87   0.96   0.91   1583</p> 
 <p class="content_116">1    0.75   0.45   0.56    417</p> 
</div> 
<p class="content">损失曲线显示(如下图所示),过拟合现象仍然十分严重。也许这个过拟合问题就是深层神经网络效率低的症结所在。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0205-0294.jpg"> 
 <p class="imgtitle">过拟合现象仍然存在</p> 
</div> 
<h3 class="thirdTitle" id="bw159"><a >5.7.3 神经网络正则化:添加Dropout层</a></h3> 
<p class="content_105">咖哥说:“从损失曲线上判断,对于小数据而言,深度神经网络由于参数数量太多,已经出现了过拟合的风险。因此,我们决定针对过拟合问题来做一些事情,优化网络。在神经网络中,最常用的对抗过拟合的工具就是Dropout。在Keras中,Dropout也是神经网络中的层组件之一,其真正目的是实现网络正则化,避免过拟合。大家还记得正则化的原理吗?”</p> 
<p class="content_105">有一位同学答道:“为了让模型粗犷一点儿,不要过分追求完美。”</p> 
<p class="content_105">咖哥说:“意思基本正确。大家想一想,对于神经网络那么复杂的模型来说,要避免过拟合还挺难做到的。而Dropout就是专门对付神经网络过拟合的有效正则化方法之一。这个方法也是Hinton和他的学生开发的。”</p> 
<p class="content">它的原理非常奇特:在某一层之后添加Dropout层,意思就是随机将该层的一部分神经元的输出特征丢掉(设为0),相当于随机消灭一部分神经元。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0205-0295.jpg"> 
 <p class="imgtitle">Dropout示意</p> 
</div> 
<p class="content">假设在训练过程中,某一层对特定数据样本输出一个中间向量。</p> 
<p class="content">■使用Dropout之前,中间向量为[0.5,0.2,3.1,2,5.9,4]。</p> 
<p class="content">■使用Dropout之后,中间向量变为[0.5,0,0,2,5.9,0]。</p> 
<p class="content">Dropout比率就是被设为0的输出特征所占的比例,通常为0.2~0.5。注意,Dropout只是对训练集起作用,在测试时没有神经元被丢掉。</p> 
<p class="content">据Hinton 说,这个小窍门的灵感来自银行的防欺诈机制。他去银行办理业务时,发现柜员不停地换人。他就猜想,银行工作人员要想成功欺诈银行,他们之间要互相合作才行,因此一个柜员不能在同一个岗位待得过久。这让他意识到,在某些神经网络层中随机删除一部分神经元,可以阻止它们的阴谋,从而降低过拟合。</p> 
<p class="content">下面就在刚才的深度神经网络中添加一些Dropout层,并重新训练它:</p> 
<div class="content_106"> 
 <p class="content_105">from keras.layers import Dropout # 导入Dropout</p> 
 <p class="content_105">ann = Sequential() # 创建一个序贯ANN模型</p> 
 <p class="content_105">ann.add(Dense(units=12, input_dim=12, activation = 'relu')) # 添加输入层</p> 
 <p class="content_105">ann.add(Dense(units=24, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p> 
 <p class="content_105">ann.add(Dense(units=48, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p> 
 <p class="content_105">ann.add(Dense(units=96, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p> 
 <p class="content_105">ann.add(Dense(units=192, activation = 'relu')) # 添加隐层</p> 
 <p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p> 
 <p class="content_105">ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层</p> 
 <p class="content_105">ann.compile(optimizer = 'adam', # 优化器</p> 
 <p class="content_119">loss = 'binary_crossentropy', #损失函数</p> 
 <p class="content_119">metrics = ['acc']) # 评估指标</p> 
</div> 
<p class="content">损失曲线显示(如下图所示),添加Dropout层之后,过拟合现象被大幅度地抑制了。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0206-0296.jpg"> 
 <p class="imgtitle">添加Dropout层之后,过拟合现象被大幅度地抑制了</p> 
</div> 
<p class="content">现在,针对客户流失样本的F1分数上升到了令人惊讶的0.62,如下输出结果所示。对于难以预测的客户流失现象来说,这是一个相当棒的成绩!这样说明对于这个问题,加深网络同时辅以Dropout正则化的策略比用单隐层神经网络更好。</p> 
<div class="content_106"> 
 <p class="content_117">precision  recall f1-score  support</p> 
 <p class="content_116">0    0.89   0.92   0.91   1583</p> 
 <p class="content_116">1    0.67   0.58   0.62    417</p> 
</div> 
<p class="content">新的混淆矩阵显示(如下图所示),400多个即将流失的客户中,我们成功地捕捉到了200多人。这是非常有价值的商业信息。</p> 
<div class="pic"> 
 <img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0207-0297.jpg"> 
 <p class="imgtitle">新的混淆矩阵</p> 
</div> 
<p class="content_105">看到这样的效果,小冰和同学们都对咖哥竖起大拇指。咖哥说:“其实准确率或者F1分数本身的提升并不重要,更有价值的是网络优化过程中所做的各种尝试和背后的思路。”</p>