炼数成金 门户 商业智能 深度学习 查看内容

李理:卷积神经网络之Dropout & 三层卷积网络和vgg的实现

2017-3-8 10:43| 发布者: 炼数成金_小数| 查看: 11209| 评论: 0|来自: 极客头条

摘要: dropout是一种防止模型过拟合的技术,这项技术也很简单,但是很实用。它的基本思想是在训练的时候随机的dropout(丢弃)一些神经元的激活,这样可以让模型更鲁棒,因为它不会太依赖某些局部的特征(因为局部特征有可能 ...

网络 工具 模型 测试 神经网络

《李理:卷积神经网络之Dropout》
4. Dropout
4.1 Dropout简介
dropout是一种防止模型过拟合的技术,这项技术也很简单,但是很实用。它的基本思想是在训练的时候随机的dropout(丢弃)一些神经元的激活,这样可以让模型更鲁棒,因为它不会太依赖某些局部的特征(因为局部特征有可能被丢弃)。
上图a是标准的一个全连接的神经网络,b是对a应用了dropout的结果,它会以一定的概率(dropout probability)随机的丢弃掉一些神经元。

4.2 Dropout的实现
实现Dropout最直观的思路就是按照dropout的定义来计算,比如上面的3层(2个隐藏层)的全连接网络,我们可以这样实现:
""" 最原始的dropout实现,不推荐使用 """p = 0.5 # 保留一个神经元的概率,这个值越大,丢弃的概率就越小。def train_step(X): 

  H1 = np.maximum(0, np.dot(W1, X) + b1)
  U1 = np.random.rand(*H1.shape) < p # first dropout mask
  H1 *= U1 # drop!
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  U2 = np.random.rand(*H2.shape) < p # second dropout mask
  H2 *= U2 # drop!
  out = np.dot(W3, H2) + b3  # 反向梯度计算,代码从略def predict(X):
  H1 = np.maximum(0, np.dot(W1, X) + b1) * p # NOTE: scale the activations
  H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # NOTE: scale the activations
  out = np.dot(W3, H2) + b3

我们看函数 train_step,正常计算第一层的激活H1之后,我们随机的生成dropout mask数组U1。它生成一个0-1之间均匀分布的随机数组,然后把小于p的变成1,大于p的变成0。极端的情况,p = 0,则所有数都不小于p,因此U1全是0;p=1,所有数都小于1,因此U1全是1。因此越大,U1中1越多,也就keep的越多,反之则dropout的越多。 

然后我们用U1乘以H1,这样U1中等于0的神经元的激活就是0,其余的仍然是H1。 

第二层也是一样的道理。
predict函数我们需要注意一下。因为我们训练的时候会随机的丢弃一些神经元,但是预测的时候就没办法随机丢弃了【我个人觉得也不是不能丢弃,但是这会带来结果会不稳定的问题,也就是给定一个测试数据,有时候输出a有时候输出b,结果不稳定,这是实际系统不能接受的,用户可能认为你的模型有”bug“】。那么一种”补偿“的方案就是每个神经元的输出都乘以一个p,这样在”总体上“使得测试数据和训练数据是大致一样的。比如一个神经元的输出是x,那么在训练的时候它有p的概率keep,(1-0)的概率丢弃,那么它输出的期望是p x+(1-p) 0=px。因此测试的时候把这个神经元乘以p可以得到同样的期望。

原文链接:
http://geek.csdn.net/news/detail/161276

《李理:三层卷积网络和vgg的实现》

卷积神经网络的原理已经在【推荐】李理:卷积神经网络之Batch Normalization的原理及实现以及《李理:卷积神经网络之Dropout》二文中详细讲过了,这里我们看怎么实现。

5.1 cell1-2
打开ConvolutionalNetworks.ipynb,运行cell1和2

5.2 cell3 实现最原始的卷积层的forward部分
打开layers.py,实现conv_forward_naive里的缺失代码:

N, C, H, W = x.shape
  F, _, HH, WW = w.shape
  stride = conv_param['stride']
  pad = conv_param['pad']
  H_out = 1 + (H + 2 * pad - HH) / stride
  W_out = 1 + (W + 2 * pad - WW) / stride  out = np.zeros((N,F,H_out,W_out))

  # Pad the input
  x_pad = np.zeros((N,C,H+2*pad,W+2*pad))
  for n in range(N):
      for c in range(C):
      x_pad[n,c] = np.pad(x[n,c],(pad,pad),'constant', constant_values=(0,0))
  for n in range(N):
      for i in range(H_out):
          for j in range(W_out):
          current_x_matrix = x_pad[n, :, i * stride: i * stride + HH, j * stride:j * stride + WW]
             for f in range(F):
                 current_filter = w[f]
                 out[n,f,i,j] = np.sum(current_x_matrix*current_filter) 
             out[n,:,i,j] = out[n,:,i,j]+b

我们来逐行来阅读上面的代码

5.2.1 第1行
首先输入x的shape是(N, C, H, W),N是batchSize,C是输入的channel数,H和W是输入的Height和Width

5.2.2 第2行
参数w的shape是(F, C, HH, WW),F是Filter的个数,HH是Filter的Height,WW是Filter的Width

5.2.3 第3-4行
从conv_param里读取stride和pad

5.2.4 第5-6行
计算输出的H_out和W_out

5.2.5 第7行
定义输出的变量out,它的shape是(N, F, H_out, W_out)

5.2.6 第8-11行
对x进行padding,所谓的padding,就是在一个矩阵的四角补充0。

首先我们来熟悉一下numpy.pad这个函数。

In [19]: x=np.array([[1,2],[3,4],[5,6]])

In [20]: x
Out[20]: 
array([[1, 2],
       [3, 4],
       [5, 6]])

首先我们定义一个3*2的矩阵
然后给它左上和右下都padding1个0。
In [21]: y=np.pad(x,(1,1),'constant', constant_values=(0,0))

In [22]: y
Out[22]: 
array([[0, 0, 0, 0],
       [0, 1, 2, 0],
       [0, 3, 4, 0],
       [0, 5, 6, 0],
       [0, 0, 0, 0]])
我们看到3*2的矩阵的上下左右都补了一个0。
我们也可以只给左上补0:

In [23]: y=np.pad(x,(1,0),'constant', constant_values=(0,0))

In [24]: y
Out[24]: 
array([[0, 0, 0],
       [0, 1, 2],
       [0, 3, 4],
       [0, 5, 6]])

了解了pad函数之后,上面的代码就很容易阅读了。对于每一个样本,对于每一个channel,这都是一个二位的数组,我们根据参数pad对它进行padding。

欢迎加入本站公开兴趣群
商业智能与数据分析群
兴趣范围包括各种让数据产生价值的办法,实际应用案例分享与讨论,分析工具,ETL工具,数据仓库,数据挖掘工具,报表系统等全方位知识
QQ群:81035754

鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

 

GMT+8, 2018-6-26 02:00 , Processed in 0.160082 second(s), 25 queries .