读书笔记:neuralnetworksanddeeplearning chapter3(3)

(本文是根据 neuralnetworksanddeeplearning 这本书的第三章Improving the way neural networks learn整理而成的读书笔记,根据个人口味做了删减)

上一章,我们介绍了神经网络容易出现的过拟合问题,并学习了最常用的正则化方法,以及其他一些技巧,今天,我们将介绍本章节最后两个问题:权重初始化超参数的选择

权重初始化

到目前为止,我们都是用归一化高斯分布来初始化权值,但是,我们很想知道是否有其他初始化方法可以让网络训练得更好。

事实上,确实存在比高斯分布更好的方法。不过,我们需要先了解高斯分布的初始化会存在哪些缺陷。

假设我们有如下的网络结构,其中包含 1000 个输入神经元:

现在,我们聚焦于隐藏层第一个神经元。假设输入中,有一半的神经元是 0,一半的神经元是 1。输入到隐藏层的权重和为 \(z=\sum_j{w_j x_j}+b\)。由于有一半的 \(x_j=0\),所以 \(z\) 相当于是 501 个归一化的高斯分布随机变量的和。因此,\(z\) 本身也是一个高斯分布,其均值为 0,标准差为 \(\sqrt{501} \approx 22.4\)。这是一个很「宽」的分布:

也就是说,大部分情况下 \(z \gg 1\) 或者 \(z \ll 1\)。对于采用 sigmoid 函数的 \(\sigma(z)\) 来说,这就意味着隐藏层可能已经收敛了(所谓收敛,就是训练开始变缓或停止了,而导致收敛的原因在于,偏导中的 \(\sigma‘(z)\) 在 \(|z|>1\) 时趋于 0,这样梯度下降就没法更新参数了)。之前我们用交叉熵函数解决了输出层中学习率低的问题,但对于中间的隐藏层并没有作用。而且,前一层隐藏层的输出如果也成高斯分布,那么再往后的隐藏层也会收敛。

改善这种问题的措施也很简单,既然问题根源在于高斯分布太「宽」,那么我们就想办法让它变「窄」,也就是标准差要变小。假设一个神经元有 \(n_{in}\) 个输入权值,那么我们只需要将所有权值按照均值为 0,标准差为 \(1/\sqrt{n_{in}}\) 的高斯分布初始化即可。这样得到的新的高斯分布就会「瘦高」得多。对于之前的例子,在 500 个输入为 0,500 个为 1 的情况下,新高斯分布的均值为 0,标准差为 \(\sqrt{3/2}=1.22…\),如下图所示:

这样一来,\(z\) 的值普遍在 \([0, 1]\) 内,隐藏层过早收敛的情况也就有所缓解了。

我们再通过一组实验来看看不同初始化方法的效果:

其中,橙线是用上面提及的新的高斯分布初始化,而蓝线则是一般的高斯分布。从结果来看,新的初始化方法可以加速网络的训练,但最终的准确率两者相当。不过在某些情况下,\(1/\sqrt{n_{in}}\) 的初始化方式会提高准确率,在下一章中,我们将看到类似的例子。

要注意的一点是,以上的初始化都是针对权值 weight 的,对偏差 bias 的初始化不影响网络的训练(原因暂时没想明白)。

如何选择超参数

到目前为止,我们都没有仔细讨论超参数该如何选择(如学习率 \(\eta\),正则化参数 \(\lambda\) 等等)。超参数的选择对网络的训练和性能都会产生影响。由于神经网络的复杂性,一旦网络出现问题,我们将很难定位问题的根源,搞不清楚到底是网络结构有问题,还是数据集有问题,还是超参数本身没选好。因此,这一节我们将学习一些选择超参数的「灵感」或者「准则」,减少在超参数选择上的失误。

宽泛的策略

之所以称之为宽泛,是因为这种策略不告诉如何调整超参数,而是让你尽可能快地得到反馈。只有尽快把握网络的学习情况,我们才有耐心和信息继续 debug(总不能每调整一次要等个十来分钟才出结果吧)。我自己在 debug 网络的时候也经常采用这些做法,比如,只用很小的数据集训练,或者将网络的结构变小等等。这些做法只有一个目的:让网络尽可能快地反馈结果,不管结果好坏,这是我们能继续调试下去的前提。在反复调试后,我们往往能得到一些「灵感」,之后再慢慢将问题变的更复杂一些,然后继续调试。

好了,下面我们针对学习率 \(\eta\)、L2 正则化参数 \(\lambda\) 和批训练的数据集大小学习一些比较有效的准则。

学习率

关于学习率的选择,Andrew Ng 在他的 Machine Learning 课程中有过详细的讲解。这里面最重要的是要避免学习率过大给梯度下降带来「抖动」的问题,如下图中的橙线所示。在设置学习率时,我们可以先设置一个小一点的数值,如 0.1,如果这个数值太大,则调低一个数量级到 0.01,甚至 0.001...如果发现学习过程中代价函数没有出现「抖动」的情况,再适当提高学习率,如由原来的 0.1 提高到 0.2、0.5...但最终不能超过造成「抖动」的阈值。

early stopping 选择训练轮数

在神经网络中,并不是训练得越多越好,之前已经提到过,训练太多轮可能导致过拟合。因此,我们要采取尽可能合适的训练轮数。early stopping 的具体做法是:在每一轮训练后观察验证集上的准确率,当验证集准确率不再上升时,就停止训练。这里的准确率不再上升指的是,在连续几轮(比如 10 轮)的训练后,准确率都不再有新的突破,始终维持在一个稳定的数值。

调整学习率

前面说过,学习率过大可能导致梯度下降出现「抖动」,过小又会导致网络训练太慢。在实际过程中,我们常常会遇到这样的问题:当网络开始训练时,由于 weights 不够好,这个时候加大学习率可以快速改善网络;当网络训练一段时间后,梯度下降开始到达最低点,这个时候小一点的学习率可以防治其越过最低点而出现「抖动」。因此,在训练过程中,更好的方法不是固定一个学习率,而是根据验证集上的准确率情况,逐步调整学习率(比如一开始设为 0.1,当准确率上升到 80% 后,调低到 0.01,上升到 90% 后,再继续调低,直到学习率只有初始值的千分之一为止)。

正则化参数

刚开始训练时,最好将正则化参数 \(\lambda\) 设为 0.0,等学习率确定并且网络可以正常训练后,再设置 \(\lambda\)。具体该设置为什么,没有通用的准则,只能根据实际情况判断,可以是 1.0,或者 0.1,或者 10.0。总之,要根据验证集上的准确率来判断。

批训练的数据集大小

理论上,我们完全可以在每次训练时只用一个样本,但这样会导致训练过程相当漫长,而多个样本进行批训练,在当今计算机的快速矩阵运算下并不比单个样本慢,这样相当于同时训练多个样本的时间和单个样本一样(当然,将所有样本都用于训练还是会影响速度,所以才会采用随机梯度训练的批样本)。另外,个人认为,综合多个样本再取均值进行训练,可以抵消部分噪音样本的影响。

参考

原文地址:https://www.cnblogs.com/jermmyhsu/p/8227957.html

时间: 2024-10-06 22:20:51

读书笔记:neuralnetworksanddeeplearning chapter3(3)的相关文章

读书笔记(chapter3)

进程管理 3.1进程 1.进程:进程就是处于执行期的程序,实际上,进程就是正在执行的程序代码的实时结果: 2.执行线程,简称线程,是进程中活动的对象(每个线程拥有独立的程序计数器.进程栈.和一组进程寄存器),内核调度的对象是线程,不是进程 3.进程提供的两种虚拟进制:虚拟处理器和虚拟内存 4.程序本身不是进程 5.调用fork(),该系统调用通过复制一个现有进程来创建一个全新的进程:接这调用exce()函数,可以创建新的地址空间,并把程序载入其中:最后,程序通过exit()系统调用退出调用.这个

《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2)

Chapter3: The C in C++ (2) Bitwise operators (1)The bitwise exclusive or, or xor (^) produces a one in the output bit if one or the other input bit is a one, but not both. (2)Bitwise operators can be combined with the = sign to unite the operation an

读书笔记:neuralnetworkanddeeplearning chapter5

(本文是根据 neuralnetworksanddeeplearning 这本书的第五章Why are deep neural networks hard to train? 整理而成的读书笔记,根据个人口味做了删减) 在之前的笔记中,我们已经学习了神经网络最核心的 BP 算法,以及一些改进的方案(如:引入交叉熵函数)来提高网络训练的速度.但如果仔细思考会发现,前面例子中的网络都很「浅」,最多就一两个隐藏层,而一旦网络层数增加,有很多问题将不可避免地暴露出来.今天,我们就来认识一个最蛋疼的问题:

《C#图解教程》读书笔记之三:方法

本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.方法那些事儿 (1)方法的结构:方法头-指定方法的特征,方法体-可执行代码的语句序列: (2)方法的调用:参数.值参数.引用参数.输出参数.参数数组: ①参数: 形参-本地变量,声明在参数列表中:形参的值在代码开始之前被初始化: 实参-实参的值用于初始化形参: ②值参数: 为形参在栈上分配内存,将实参的值复制到形参: ③引用参数: 不为形参在栈上分配内存,形参的参数名作为实参变量的别名指向同一位置,必须使用ref关

《C#图解教程》读书笔记之五:委托和事件

本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.委托初窥:一个拥有方法的对象 (1)本质:持有一个或多个方法的对象:委托和典型的对象不同,执行委托实际上是执行它所"持有"的方法.如果从C++的角度来理解委托,可以将其理解为一个类型安全的.面向对象的函数指针. (2)如何使用委托? ①声明委托类型(delegate关键字) ②使用该委托类型声明一个委托变量 ③为委托类型增加方法 ④调用委托执行方法 (3)委托的恒定性: 组合委托.为委托+=增加

《Effective C++》读书笔记汇总

我之前边读<Effective C++>边写下每个条款的读书笔记,这一版是C++11之前的版本.这里我将每个条款令我印象深刻的点小结一下. 1.C++包括:Plain C(面向过程).OOP(面向对象).模板(泛型和模板元编程).STL(C++标准库). 2.用inline.enum.const代替#define.#define定义的宏,一旦复杂起来,高手都很难掌控.不要带入C的习惯. 3.灵活使用const前缀.不需要进行改变的数据加上const前缀.指针的const前缀有两种形式,cons

【读书笔记】《Linux内核设计与实现》内核同步介绍&内核同步方法

简要做个笔记,以备忘. 需同步的原因是,我们并发访问了共享资源.我们将访问或操作共享资源的代码段称"临界区",如果两个执行线程处于同一临界区中同时执行,称"竞争条件".这里术语执行线程指任何正在执行的代码实例,如一个在内核执行的进程.一个中断处理程序或一个内核线程. 举个简单例子,i++操作.该操作可以转换为下面的机器指令序列: 1.得到当前变量i的值,并保存到一个寄存器. 2.将寄存器的值加1. 3.将i的新值写回到内存中. 当两个线程同时进入这个临界区,若i初值

鸟哥的Linux私房菜 基础学习篇读书笔记(7):Linux文件与目录管理

这一章主要讲述的是如何操作与管理Linux系统中的文件和目录,主要包括目录间的切换,目录的创建与删除,文件的创建与删除,文件的查找,文件内容的查看等等. 前一章中已经讲过相对路径以及绝对路径,绝对路径就是指从根目录("/")开始写起的路径名,而相对路径绝不会由根目录开始写起,相反,相对路径是相对于当前工作目录的路径名.Linux操作系统中有几个特殊的目录: . 代表此层目录: .. 代表上一层目录: - 代表前一个工作目录: ~ 代表当前用户身份所在的主文件夹: ~account 代表

《30天自制操作系统》读书笔记(2)hello, world

让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实上你用的是U盘还是软盘对我们的操作系统没有影响,缺点是你的U盘刷入系统后容量只能是1440 MB,即当年流行的3.5英寸软盘的大小,当然不用担心,再格式化一次(用DiskGeniu),就可以恢复. 我做事情的话,总是怕自己的努力的结果白费了,害怕辛辛苦苦看完这本书但是发现做出来的东西现在根本没法用,