为纯Python搭建的神经网络添加Dropout

为什么写这篇文章

之前在自学神经网络的时候,一般都是调用当前主流的框架,例如KerasTensorflow等等。不得不说Keras是一个极其简单的框架,在它的中文文档可以轻松找到关于Dropout的调用方法。然而最近由于学习的需要,网络是自己手动搭建的,又在训练中遇到了过拟合的情况,于是需要自己在网络中手动加入Dropout。

Dropout防止过拟合的原理

关于Dropout的原理,这里推荐一篇介绍的极为详细的知乎文章,若是不想去看长篇文字,这里我用一句话概括,就是通过随机屏蔽网络中的一部分神经元,达到网络始终在变化的效果,这样每轮都在训练不同的网络,从而使它们达到相互制衡的目的。

python实现

本代码的基本思路是:我们的权重矩阵可以看成是一个从输入层到隐层的突触连接集合。假设我们的权重矩阵是一个有 J J J I I I列的矩阵,代表有 J J J个输入神经元和 I I I个隐层的神经元。若需要屏蔽第 i i i个隐层神经元时,只需要将权重矩阵的第 i i i列置0即可。这样输入的数据全部进入该神经元时都会变为0,这个神经元输出的数据也是0,可以想象成这个神经元不存在。

  1. 每次屏蔽固定数量的神经元
def dropout0(x, dropRate=0.2):  # x是复制的权重矩阵
    num = dropRate * x.shape[1]  # 计算在隐层要丢弃的神经元数
    for i in range(int(num)):
        col = np.random.randint(1, x.shape[1])  #选取要屏蔽的列值   
        x[:, col] = 0.  # 将该列置0
    return x

以上的方法可以在每次屏蔽固定数量的神经元,虽然在实际操作中够用,但是该方式在公式推导中是不严谨的,我们需要按照概率 p p p产生要屏蔽的神经元数量,而不是一个固定值。

  1. 按照伯努利分布来屏蔽神经元
    此代码使用了伯努利分布来生成未屏蔽的神经元索引,dropout是要屏蔽的比例,retain是要保留的比例。
def dropout1(x, dropRate=0.2):  # x是复制的权重矩阵
    retain = 1 - dropRate  # 计算得要保留的神经元数量
    random_tensor = np.random.binomial(n=1, p=retain, size=x.shape[1])  # 一维的数组,按照概率为p的伯努利分布生成1,其余是0
    for i in range(x.shape[1]):
        if (random_tensor[i] == 0):
            x[:, i] = 0  # 索引对应一维数组索引为0的列置0
    return x
  1. 伯努利分布,不使用循环的版本
    众所周知能用矩阵乘法就不用循环,为了代码效率,看循环贼不顺眼的本人又写了一个不用循环的版本。然而实测这个是最慢的emmm…
def dropout2(x, dropRate=0.2):
    retain = 1 - dropRate
    random_array = np.random.binomial(n=1, p=retain, size=x.shape[1])
    random_tensor = np.tile(random_array, (x.shape[0], 1))
    x = x * random_tensor
    return x

最后来一段代码来测一下效率:
矩阵有 2304 2304 2304行,有 150 150 150列,循环12000次,前两种方法基本是两分钟左右,第三种是两分半钟左右(i5-8265u)

for i in tqdm(range(12000)):
    weight_h = np.random.randn(16 * 12 * 12, 150)
    w_h = np.array(weight_h)
    w_h = dropout1(w_h, 0.2)

重要的补充说明

  1. 切记使用函数时,使用矩阵的副本,不要使用原矩阵来输入函数,否则会在原矩阵上做出改变。
  2. 为了使矩阵屏蔽前后的期望保持一致,在预测时要先将权重矩阵缩小,比如丢弃比例为 p p p,则预测时要先将矩阵乘以 ( 1 − p ) (1-p) (1p)
  3. 为了使网络加速收敛,函数可以灵活使用,根据训练集准确率灵活调整dropRate。

结语

本文仅用一个从输入层到隐层的权重矩阵进行说明,在使用中还是要根据自身需要灵活调整。另外,本文仅供交流学习,若有效率更高的方法,希望大神不吝赐教!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值