深度学习 | Why and How:神经网络中的权重初始化

前言

神经网络中的权重(weight)初始化是个常常被忽略的问题。

最近在手写一个Python的神经网络库(GitHub:hamaa——https://github.com/monitor1379/hamaa),刚开始为了测试代码是否写对,搭建了一个2->4->2的单隐层神经网络来拟合异或运算,拟合结果十分完美。但是在做MNIST手写数字识别,将网络扩展到了784->100->10时,发现损失函数一直不下降,训练准确率一直停留在10%左右(和随机猜的命中概率一样嘛)。

一直以为是back propagation的代码写错了,debug了整整两天都没发现错误,结果输出中间weights的梯度dw看看,发现两个权重矩阵的梯度都是在1e-10左右的数量级。后来查询了一些资料,原来是代码缺少了权重初始化(weight initialization)这及其重要的一步。增加了权重初始化后拟合结果终于正常。

在以前看一些关于神经网络的资料时,我也经常看到“权重初始化”这一步,但一直错误地以为“权重初始化”等价于“权重随机初始化”,以为仅仅将权重初始化为很小的随机数即可,但其实它的原因除了打破梯度更新对称性之外,还有更深层次的原因。所以接下来文章分为两部分,分别介绍为什么需要进行权重初始化,以及如何进行权重初始化。

权重初始化:why

在创建了神经网络后,通常需要对权重和偏置进行初始化,大部分的实现都是采取Gaussian distribution来生成随机初始值。假设现在输入层有1000个神经元,隐藏层有1个神经元,输入数据x为一个全为1的1000维向量,采取高斯分布来初始化权重矩阵w,偏置b取0。下面的代码计算隐藏层的输入z:

# -*- coding:utf-8 -*-

import numpy as np

import matplotlib.pyplot as plt def run(): x = np.ones(1000) w = np.random.randn(1000) b = 0 # z为加权和 z = np.sum(x * w) + b

print z

然而通过上述初始化后,因为w服从均值为0、方差为1的正太分布,x全为1,b全为0,输入层一共1000个神经元,所以z服从的是一个均值为0、方差为1000的正太分布。修改代码如下,生成20000万个z并查看其均值、方差以及分布图像:

def run(): # z的个数 t = 20000 z_lst = np.empty(t) x = np.ones(1000) b = 0 for i in xrange(t): w = np.random.randn(1000) z = np.sum(x * w) + b z_lst[i] = z print 'z 均值:', np.mean(z_lst) print 'z 方差:', np.var(z_lst) plt.hist(z_lst, bins=100)

plt.show()

输出结果如下:

z 均值: -0.0402106463845

z 方差: 997.082082524

输出图像如下:

z分布(1)

在此情况下,z有可能是一个远小于-1或者远大于1的数,通过激活函数(比如sigmoid)后所得到的输出会非常接近0或者1,也就是隐藏层神经元处于饱和的状态。所以当出现这样的情况时,在权重中进行微小的调整仅仅会给隐藏层神经元的激活值带来极其微弱的改变。而这种微弱的改变也会影响网络中剩下的神经元,然后会带来相应的代价函数的改变。结果就是,这些权重在我们进行梯度下降算法时会学习得非常缓慢[1]。

因此,我们可以通过改变权重w的分布,使|z|尽量接近于0。这就是我们为什么需要进行权重初始化的原因了。

权重初始化:How

一种简单的做法是修改w的分布,使得z服从均值为0、方差为1的标准正态分布。根据正太分布期望与方差的特性,将w除以sqrt(1000)即可。修改后代码如下:

def run(): # z的个数 t = 20000 z_lst = np.empty(t) # 输入神经元个数 m = 1000 x = np.ones(m) b = 0 for i in xrange(t): w = np.random.randn(m) / np.sqrt(m) z = np.sum(x * w) + b z_lst[i] = z print 'z 均值:', np.mean(z_lst) print 'z 方差:', np.var(z_lst)

# 保持与z分布(1)图像横坐标刻度不变,使得结果更加直观

plt.xlim([-150, 150]) plt.hist(z_lst, bins=10)

plt.show()

输出结果如下:

z 均值: 0.013468729222

z 方差: 1.00195898464

输出图像如下:

z分布(2)

这样的话z的分布就是一个比较接近于0的数,使得神经元处于不太饱和的状态,让BP过程能够正常进行下去。

除了这种方式之外(除以前一层神经元的个数n_in的开方),还有许多针对不同激活函数的不同权重初始化方法,比如兼顾了BP过程的除以( (n_in + n_out)/2 )。具体可以参考Stanford CS231n课程中提到的各种方法。

后记

最后强烈安利Stanford CS231n的官方授权中文翻译专栏知乎专栏:智能单元,感谢各位Zhihuer的辛勤翻译,为后辈的学习与快速上手提供了极大的便利。

参考

[1] www.neuralnetworksanddeeplearning.com,第三章 [2] Stanford CS231n [3] Stanford CS231n官方授权中文翻译,知乎专栏:智能单元

原文发布于微信公众号 - 人工智能LeadAI(atleadai)

原文发表时间:2017-12-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【前沿】 何恺明大神ICCV2017最佳论文Mask R-CNN的Keras/TensorFlow/Pytorch 代码实现

导读 何恺明大神的论文Mask R-CNN 获得ICCV最佳论文 ,而关于这篇论文的TensorFlow\Pytorch\Keras实现相继开源出来,让我们来看...

3659
来自专栏郭耀华‘s Blog

MaxPooling的作用

1242
来自专栏AI研习社

我们建了个模型,搞定了 MNIST 数字识别任务

对于图像分类任务,当前最先进的架构是卷积神经网络 (CNNs).。无论是面部识别、自动驾驶还是目标检测,CNN 得到广泛使用。在本文中,针对著名的 MNIST ...

662
来自专栏机器学习算法与Python学习

干货|多重预训练视觉模型的迁移学习

关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 源 | 全球人工智能 本文介绍的是基...

4507
来自专栏郭耀华‘s Blog

MaxPooling的作用

maxpooling主要有两大作用 1. invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺...

2837
来自专栏QQ会员技术团队的专栏

CNN网络介绍与实践:王者荣耀英雄图片识别

本文主要是对CS231n课程学习笔记的提炼,添加了一些Deep Learning Book和Tensorflow 实战,以及Caffe框架的知识。

1.4K3
来自专栏https://www.cnblogs.com/L

【神经网络篇】--基于数据集cifa10的经典模型实例

最终,在cifar-10数据集上,通过一个短时间小迭代的训练,可以达到大致73%的准确率,持续增加max_steps,可以期望准确率逐渐增加 如果max_ste...

1321
来自专栏Petrichor的专栏

深度学习: 随机失活 (dropout)

按概率p 随机 将神经元 置 0 [如下(b)图],以 缓解 神经元之间 隐形的协同适应,从而达到降低模型复杂度的目的:

1968
来自专栏机器学习算法与Python学习

扩展 | 3D 计算机视觉简介

随着 AR / VR 技术和自动驾驶汽车技术的发展,3D 视觉问题变得越来越重要,它提供了比 2D 更丰富的信息。本文将介绍两种用于 3D 场景分析的基本深度学...

602
来自专栏大数据智能实战

细小人脸检测的实践(Finding Tiny Faces论文代码复现)

https://www.cs.cmu.edu/~peiyunh/tiny/这个主页上介绍了CVPR中的一篇文章,关于细小人脸检测的。小物体检测一直还是CV界比较...

42810

扫码关注云+社区