深度学习 | 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 条评论
登录 后参与评论

相关文章

来自专栏PPV课数据科学社区

机器学习系列:(八)感知器

感知器 前面,我们介绍了广义线性模型,用联接方程描述解释变量、超参数和响应变量的线性关系。这一章,我们将介绍另一种线性模型,称为感知器(perceptron)。...

33312
来自专栏人工智能

深度学习之激活函数详解

激活函数是什么 激活函数,即Activation Function,有时候也称作激励函数。它是为了解决线性不可分的问题引出的。但是也不是说线性可分就不能用激活函...

1978
来自专栏深度学习自然语言处理

深度学习之激活函数详解

激活函数是什么 激活函数,即Activation Function,有时候也称作激励函数。它是为了解决线性不可分的问题引出的。但是也不是说线性可分就不能用激活函...

2817
来自专栏人工智能LeadAI

梯度下降法快速教程 | 第三章:学习率衰减因子(decay)的原理与Python实现

前言 梯度下降法(Gradient Descent)是机器学习中最常用的优化方法之一,常用来求解目标函数的极值。 其基本原理非常简单:沿着目标函数梯度下降的方向...

3475
来自专栏数据科学学习手札

(数据科学学习手札40)tensorflow实现LSTM时间序列预测

  上一篇中我们较为详细地铺垫了关于RNN及其变种LSTM的一些基本知识,也提到了LSTM在时间序列预测上优越的性能,本篇就将对如何利用tensorflow,在...

2984
来自专栏技术小站

吴恩达深度学习笔记 course 2 1.1~1.14 深度学习的实用层面

在构建一个神经网络的时候我们往往需要设计很多参数,如:layers,learning rates ,acivation functions,hidden uni...

792
来自专栏Spark学习技巧

基于Spark Mllib的文本分类

基于Spark Mllib的文本分类 文本分类是一个典型的机器学习问题,其主要目标是通过对已有语料库文本数据训练得到分类模型,进而对新文本进行类别标签的预测。这...

1948
来自专栏YoungGy

词向量综述

词向量综述 one-hot by neighbor 基于全文档的词向量 基于window的词向量 SVD Skip-Gram 结构 输入输出 学习算法 优化角度...

3316
来自专栏杨熹的专栏

Sklearn 快速入门

学习资料:大家可以去莫烦的学习网站学到更多的知识。 本文结构: Sklearn 简介 选择模型流程 应用模型 ---- Sklearn 简介 Scikit...

3398
来自专栏闪电gogogo的专栏

IEEE Trans 2008 Gradient Pursuits论文学习

之前所学习的论文中求解稀疏解的时候一般采用的都是最小二乘方法进行计算,为了降低计算复杂度和减少内存,这篇论文梯度追踪,属于贪婪算法中一种。主要为三种:梯度(gr...

2079

扫码关注云+社区