根据个人口味做了去除),我们须求进行权重和不是的初步化

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

Neil Zhu,简书ID Not_GOD,University AI 开创者 & Chief
Scientist,致力于拉动世界人工智能化进度。制定并施行 UAI
中短时间增进战略和指标,教导团队高效成长为人造智能领域最规范的能力。作为行业老板,他和UAI一起在二〇一五年创设了TASA(中华人民共和国最早的人为智能协会),
DL Center(深度学习文化基本全世界市场股票总值互联网),AI
growth等,为神州的人工智能人才建设输送了汪洋的血流和滋养。另外,他还参预也许设置过种种国际性的人造智能高峰会议和平运动动,发生了豪杰的影响力,书写了60万字的人为智能精品技艺内容,生产翻译了中外第叁本深度学习入门书《神经互连网与深度学习》,生产的剧情被大批量的规范垂直公众号和传播媒介转发与连载。曾经受邀为国内超级大学制定人工智能学习布署和任课人工智能前沿课程,均受学生和导师好评。

上一章,大家介绍了神经互连网简单出现的过拟合难点,并就学了最常用的正则化方法,以及其余部分技巧,明天,我们将介绍本章节最后三个难题:权重开首化超参数的选料

创设了神经互连网后,大家要求展开权重和不是的初叶化。到现行反革命,大家直接是依据在率先章中牵线的那么进行初叶化。提示你眨眼之间间,在此以前的不二法门正是根据独立的均值为
$$0$$,标准差为 $$1$$
的高斯随机变量随机采集样品作为权重和不是的初阶值。那一个点子工作的还不易,然则那么些ad
hoc,所以大家供给寻找一些更好的点子来设置大家网络的开始化权重和不是,那对于赞助互连网学习进程的晋级很有价值。

权重初叶化

到最近甘休,大家都以用归一化高斯分布来初叶化权值,可是,大家很想理解是还是不是有别的开头化方法能够让互联网磨练得更好。

实在,确实存在比高斯遍布更好的章程。不过,我们供给先领悟高斯分布的开首化会存在怎么着缺点。

假诺大家有如下的互连网布局,当中蕴涵 一千 个输入神经元:

图片 1

今昔,我们聚焦于隐藏层第三个神经元。假诺输入中,有50%的神经细胞是
0,八分之四的神经细胞是 1。输入到隐藏层的权重和为 \(z=\sum_j{w_j x_j}+b\)。由于有百分之五十的
\(x_j=0\),所以 \(z\) 也正是是 50二个归一化的高斯分布随机变量的和。由此,\(z\) 本身也是一个高斯分布,其均值为
0,标准差为 \(\sqrt{501} \approx
22.4\)。那是3个很「宽」的遍布:

图片 2

约等于说,抢先二分之一动静下 \(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…\),如下图所示:

图片 3

那样一来,\(z\) 的值普遍在 \([0, 1]\)
内,隐藏层太早消灭的情状也就全部缓解了。

大家再通过一组实验来探望不相同初阶化方法的意义:

图片 4

其间,橙线是用地点提及的新的高斯分布开首化,而蓝线则是形似的高斯分布。从结果来看,新的初始化方法可以加快网络的教练,但结尾的准确率两者极度。但是在少数情状下,\(1/\sqrt{n_{in}}\)
的初叶化方式会增加准确率,在下一章中,大家将看到类似的事例。

要注意的一点是,以上的起初化都以对准权值 weight 的,对错误 bias
的先导化不影响互连网的教练(原因权且没想驾驭)。

结果申明,大家可以比使用规范的高斯分布效果更好。为啥?假若我们采纳叁个过多的输入神经元,比如说
$$一千$$。要是,我们早就使用正规的高斯分布初叶化了连年第叁隐藏层的权重。今后自个儿将注意力集中在这一层的连接权重上,忽略互连网其余一些:

怎么样挑选超参数

到近日截至,大家都尚未仔细斟酌超参数该怎么选拔(如读书率 \(\eta\),正则化参数 \(\lambda\)
等等)。超参数的挑选对互联网的演习和属性都会生出潜移默化。由于神经互联网的繁杂,一旦网络出现问题,大家将很难定位难点的来源,搞不清楚到底是互连网布局有毛病,依然多少集不经常,照旧超参数本身没选好。因而,这一节我们将学习一些取舍超参数的「灵感」只怕「准则」,减少在超参数选拔上的失误。

图片 5

广阔的国策

为此称为宽泛,是因为那种政策不告诉怎么样调整超参数,而是让您尽量快地获得报告。唯有及早把握网络的就学状态,大家才有耐心和新闻接轨
debug(总不可能每调整一回要等个十来分钟才出结果吧)。笔者自身在 debug
网络的时候也平日使用这一个做法,比如,只用不大的数额集中演练练,也许将网络的构造变小等等。那几个做法唯有2个目标:让互联网尽也许快地反映结果,不管结果好坏,那是大家能继续调节和测试下去的前提。在屡次调节和测试后,我们往往能博取部分「灵感」,之后再逐月将难题变的更扑朔迷离一些,然后继续调节和测试。

好了,下边大家针对学习率 \(\eta\)、L2 正则化参数 \(\lambda\)
和批陶冶的多少集大小学习一些相比灵通的轨道。

我们为了简化,假设,我们运用磨练样本 x 在那之中1/2的神经元值为
$$0$$,另六分之三为
$$1$$。上边包车型大巴看法也是能够尤其广阔地应用,然而你能够从特例中取得背后的商讨。让大家着想带权和
$$z=\sum_j w_j x_j + b$$ 的隐藏元输入。个中 $$500$$
个项消去了,因为对应的输入 $$x_j=0$$。所以 $$z$$ 是 $$501$$
个正规的高斯随机变量的和,包蕴 $$500$$ 个权重项和附加的 $$1$$
个错误项。因而 $$z$$ 本人是1个均值为 $$0$$ 标准差为
$$\sqrt{501}\approx 22.4$$ 的分布。$$z$$
其实有3个13分宽的高斯分布,不是可怜尖的形象:

学习率

有关学习率的选项,Andrew Ng 在她的 Machine
Learning

课程中有过详尽的任课。那之中最根本的是要制止学习率过大给梯度降低带来「抖动」的标题,如下图中的橙线所示。在设置学习率时,大家能够先安装2个小一些的数值,如
0.1,假使那几个数值太大,则调低1个多少级到 0.01,甚至
0.001…固然发现学习过程中代价函数没有出现「抖动」的状态,再适合增强学习率,如由原本的
0.1 进步到 0.贰 、0.5…但最终不能够超越造成「抖动」的阈值。

图片 6

图片 7

early stopping 选取训练轮数

在神经网络中,并不是训练得更多越好,以前已经涉及过,陶冶太多轮只怕引致过拟合。因而,大家要采取尽恐怕方便的演习轮数。early
stopping
的具体做法是:在每一轮流培陶冶后观望验证集上的准确率,当验证集准确率不再回升时,就止住锻练。那里的准确率不再上涨指的是,在连年几轮(比如
10 轮)的训练后,准确率都不再有新的突破,始终维持在贰个平稳的数值。

尤其是,大家可以从那幅图中看出 $$|z|$$ 会变得不小,比如说 $$z\gg1$$
或者 $$z\ll 1$$。假使是那样,输出 $$\sigma$$ 就会接近 $$1$$ 大概$$0$$。也就象征大家的隐藏元会饱和。所以当现身如此的景况时,在权重中进行微小的调整仅仅会给隐藏元的激活值带来最佳微弱的改动。而这种微弱的转移也会潜移默化互联网中多余的神经细胞,然后会推动相应的代价函数的改观。结果正是,这么些权重在我们开始展览梯度下落算法时会学习得可怜缓慢。那实在和我们前边议论的标题大多,前边的动静是出口神经元在错误的值上饱和导致学习的下挫。咱们事先经过代价函数的挑三拣四化解了前边的标题。不幸的是,就算那种办法在输出神经元上有效,但对于隐藏元的饱和却一点功力都不曾。

调整学习率

前边说过,学习率过大大概引致梯度下落出现「抖动」,过小又会招致互联网练习太慢。在事实上进度中,大家平常会遇见那样的题材:当互联网早先锻炼时,由于
weights
不够好,这几个时候加大学习率能够长足革新互联网;当网络磨练一段时间后,梯度下落开头到达最低点,这么些时候小一些的学习率可避防治其通过最低点而产出「抖动」。由此,在教练过程中,更好的主意不是从来多少个学习率,而是基于表达集上的准确率景况,稳步调整学习率(比如一上马设为
0.1,当准确率上升到 八成 后,调低到 0.01,回升到 九成后,再持续调低,直到学习率只有开始值的难得告竣)。

自己一度探讨了第叁隐藏层的权重输入。当然,类似的判定也对前边的隐藏层有效:假若权重也是用专业的高斯分布进行初叶化,那么激活值将会类似
$$0$$ 也许 $$1$$,学习进程也会一定迟缓。

正则化参数

刚开始练习时,最棒将正则化参数 \(\lambda\) 设为
0.0,等学习率明确并且互连网能够健康磨炼后,再安装 \(\lambda\)。具体该装置为什么,没有通用的守则,只可以依照实际情况判断,能够是
1.0,大概 0.1,大概 10.0。同理可得,要依照表达集上的准确率来判定。

还有能够扶助大家开始展览更好地从头化么,能够制止那体系型的饱满,最后制止学习进度的下落?固然大家有贰个有
$$n_{in}$$ 个输入权重的神经细胞。大家会选择均值为 $$0$$ 标准差为
$$1/\sqrt{n_{in}}$$
的高斯分布起始化那些权重。也正是说,大家会向下挤压高斯分布,让大家的神经细胞更不容许饱和。大家会继续应用均值为
$$0$$ 标准差为 $$1$$
的高斯分布来对错误进行起首化,后边会报告你原因。有了那些设定,带权和
$$z=\sum_j w_j x_j + b$$ 依旧是2个均值为 $$0$$
可是有很陡的顶峰的高斯分布。若是,大家有 $$500$$ 个值为 $$0$$
的输入和$$500$$ 个值为 $$1$$ 的输入。那么很容注脚 $$z$$ 是听从均值为
$$0$$ 标准差为 $$\sqrt{3/2} = 1.22$$
的高斯分布。这图像要比原先陡得多,所以就算本身一度对横坐标实行削减为了拓展更直观的可比:

批练习的数目集大小

辩论上,我们一齐能够在历次训练时只用二个样本,但如此会促成演习进度12分久远,而多个样本进行批练习,在明日总结机的高效矩阵运算下并比不上单个样本慢,那样也就是同时磨炼多少个样本的岁月和单个样本一样(当然,将装有样本都用来磨练依然会潜移默化进程,所以才会采取私下梯度磨练的批样书)。此外,个人觉得,综合多个样本再取均值实行磨炼,能够平衡部分噪声样本的影响。

图片 8

参考

这么的2个神经元更不容许饱和,由此也相当小恐怕碰到学习进程下降的题材。

  • 验证 $$z=\sum_j w_j x_j + b$$ 标准差为
    $$\sqrt{3/2}$$。上面两点只怕会有救助:
    独立随机变量的和的方差是各类独立随就算方差的和;方差是标准差的平方。

本人在地点提到,大家使用相同的办法对错误进行开始化,正是行使均值为 $$0$$
标准差为 $$1$$
的高斯分布来对错误举办开头化。那其实是一蹴而就的,因为那样并不会让我们的神经网络更易于饱和。实际上,其实早就制止了饱和的难题来说,怎么样早先化偏差影响非常小。有个别人将有着的偏向先导化为
$$0$$,注重梯度下落来学学合适的不是。可是因为出入不是不小,大家后边还会遵照前边的方法来进展初始化。

让大家在 MNIST
数字分类职分上比较一下新旧三种权重开始化方式。同样,依然利用 $$30$$
个隐藏元,minibatch 的尺寸为 $$30$$,规范化参数
$$\lambda=5.0$$,然后是交叉熵代价函数。我们将学习率从 $$\eta=0.5$$
调整到
$$0.1$$,因为如此会让结果在图像中呈现得愈加分明。大家先采用旧的先河化方法磨练:

>>> import mnist_loader>>> training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper()>>> import network2>>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)>>> net.large_weight_initializer()>>> net.SGD(training_data, 30, 10, 0.1, lmbda = 5.0,... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True)

咱俩也应用新章程来展开权重的开头化。这实则还要更简短,因为 network2’s
暗许格局就是利用新的办法。那意味我们能够吐弃
net.large_weight_initializer() 调用:

>>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)>>> net.SGD(training_data, 30, 10, 0.1, lmbda = 5.0,... evaluation_data=validation_data, ... monitor_evaluation_accuracy=True)

将结果用图展现出来,便是:

图片 9

三种情景下,大家在 96%
的准确度上海重型机器厂叠了。最后的归类准确度大概完全一样。不过新的早先化技术带来了快慢的进步。在第三种早先化格局的归类准确度在
87% 一下,而新的章程已经大概达到了
93%。看起来的气象就是大家新的有关权重初叶化的艺术将磨练带到了三个新的程度,让我们可以进一步飞速地赢得好的结果。同样的意况在
$$100$$ 个神经元的设定中也油然则生了:

图片 10

在那些景况下,五个曲线并不曾重合。然则,我做的尝试发现了实际上就在有的附加的回合后准确度其实也是差不多一样的。所以,基于那几个试验,看起来进步的权重初叶化仅仅会加紧演练,不会转移互连网的习性。但是,在第五张,大家会师到有的事例里面使用
$$1/\sqrt{n_{in}}$$
权重初叶化的长时间运维的结果要旗帜鲜明更优。由此,不仅仅能够带来训练进程的�加速,有时候在最后性能上也有相当大的升级。

$$1/\sqrt{n_{in}}$$
的权重初叶化方法帮忙大家升高了神经互连网学习的章程。其余的权重早先化技术一样也有,很多都以依照那些大旨的考虑。作者不会在此处给出其余的艺术,因为
$$1/\sqrt{n_{in}}$$
已经得以干活得很好了。假如您对其它的思辨感兴趣,小编推荐你看看在 $$二零一一$$
年的 Yoshua Bengio 的舆论的 $$14$$ 和 $$15$$ 页,以及相关的参考文献。

Practical Recommendations for Gradient-Based Training of Deep
Architectures, by Yoshua Bengio .

  • 将规范化和考订的权重初步化方法结合使用 L2
    规范化有时候会自动给大家某个看似于新的初步化方法的事物。假诺大家运用旧的初始化权重的主意。考虑1个启发式的眼光:若是$$\lambda$$
    不太小,锻练的首先回合将会差不多被权重下落统治。;若是 $$\eta\lambda
    \ll n$$,权重会遵照因子 $$exp(-\eta\lambda/m)$$ 每一回合降低;假如$$\lambda$$ 不太大,权重降低会在权重降到 $$1/\sqrt{n}$$
    的时候保持住,当中 $$n$$
    是互联网中权重的个数。用论述这个原则都早已满意本节给出的例证。

让我们兑现本章研究过的这么些想法。大家将写出贰个新的顺序,network2.py,那是一个对第三章中支出的
network.py 的一字不苟版本。假使你从未仔细看过
network.py,那您可能会须要重读前边境海关于那段代码的议论。仅仅 $$74$$
行代码,也很易懂。

network.py 一样,首要部分正是 Network
类了,大家用这一个来表示神经网络。使用1个 sizes
的列表来对各样对应层实行伊始化,默许使用交叉熵作为代价 cost 参数:

class Network: def __init__(self, sizes, cost=CrossEntropyCost): self.num_layers = len self.sizes = sizes self.default_weight_initializer() self.cost=cost

__init__ 方法的和 network.py
中一律,能够专断弄懂。但是上边两行是新的,我们供给了解他们毕竟做了哪些。

小编们先看看 default_weight_initializer
方法,使用了大家最新立异后的早先化权重方法。如咱们早已看到的,使用了均值为
$$0$$ 而标准差为 $$1/\sqrt{n}$$,$$n$$
为对应的输入连接个数。大家运用均值为 $$0$$ 而标准差为 $$1$$
的高斯分布来开始化偏差。下边是代码:

def default_weight_initializer: self.biases = [np.random.randn for y in self.sizes[1:]] self.weights = [np.random.randn/np.sqrt for x, y in zip(self.sizes[:-1], self.sizes[1:])]

为了驾驭那段代码,必要知道 np 就是展开线性代数运算的 Numpy
库。大家在程序的起来会 import
Numpy。同样大家没有对第3层的神经细胞的过错进行初叶化。因为第壹层其实是输入层,所以不供给引入任何的偏差。大家在
network.py 中做了完全等同的思想政治工作。

作为 default_weight_initializer 的互补,我们一致包含了3个
large_weight_initializer
方法。这几个方式运用了第1章中的观点早先化了权重和错误。代码也就一味是和default_weight_initializer差了一小点了:

def large_weight_initializer: self.biases = [np.random.randn for y in self.sizes[1:]] self.weights = [np.random.randn for x, y in zip(self.sizes[:-1], self.sizes[1:])]

我将 larger_weight_initializer
方法包含进来的原由也正是驱动跟第②章的结果更便于比较。小编并从未考虑太多的推荐使用那些方法的其实境况。

初步化方法 __init__ 中的第一个新的东西就是我们开头化了 cost
属性。为了精通这一个工作的规律,让我们看一下用来代表交叉熵代价的类:

class CrossEntropyCost: @staticmethod def fn: return np.sum(np.nan_to_num(-y*np.log*np.log @staticmethod def delta: return 

让大家解释一下。第二个看到的是:尽管选拔的是陆续熵,数学上看,正是2个函数,那里大家用
Python 的类而不是 Python
函数达成了它。为啥这么做啊?答案正是代价函数在大家的网络中扮演了三种不一致的剧中人物。分明的剧中人物正是代价是出口激活值
$$a$$ 和对象输出 $$y$$ 差别优劣的心气。那么些剧中人物通过
CrossEntropyCost.fn 方法来饰演。(注意,np.nan_to_num 调用确定保障了
Numpy 正确处理接近 $$0$$
的对数值)然而代价函数其实还有另1个剧中人物。回顾第③章中运作反向传来算法时,大家必要总计网络出口误差,$$\delta^L$$。那种样式的出口误差注重于代价函数的挑选:差别的代价函数,输出误差的款式就不相同。对于交叉熵函数,输出误差就好像公式所示:

图片 11

于是,我们定义了第三个章程,CrossEntropyCost.delta,目标正是让互连网精晓什么样进行输出误差的总计。然后大家将那五个组成在叁个含有全部必要理解的关于代价函数新闻的类中。

类似地,network2.py
还富含了一个代表二回代价函数的类。那一个是用来和率先章的结果开始展览相比的,因为背后大家大致都在利用交叉函数。代码如下。QuadraticCost.fn
方法是有关网络出口 $$a$$ 和对象输出 $$y$$
的叁遍代价函数的直白总计结果。由 QuadraticCost.delta
重回的值就是叁回代价函数的误差。

class QuadraticCost: @staticmethod def fn: return 0.5*np.linalg.norm**2 @staticmethod def delta: return  * sigmoid_prime

当今,我们精通了 network2.pynetwork.py
多少个完结之间的要紧差异。都以很简短的东西。还有局地更小的更动,上边大家会开始展览介绍,包涵L2 规范化的落实。在讲述规范化在此以前,大家看看 network2.py
完整的贯彻代码。你不供给太密切地读遍这么些代码,然则对全体结构尤其是文书档案中的内容的明白是极度首要的,那样,你就能够知道每段程序所做的办事。当然,你也能够随本身意愿去深远钻研!假若你迷失了明白,那么请读读下边包车型地铁上课,然后再回去代码中。不多说了,给代码:

"""network2.py~~~~~~~~~~~~~~An improved version of network.py, implementing the stochasticgradient descent learning algorithm for a feedforward neural network.Improvements include the addition of the cross-entropy cost function,regularization, and better initialization of network weights. Notethat I have focused on making the code simple, easily readable, andeasily modifiable. It is not optimized, and omits many desirablefeatures."""#### Libraries# Standard libraryimport jsonimport randomimport sys# Third-party librariesimport numpy as np#### Define the quadratic and cross-entropy cost functionsclass QuadraticCost: @staticmethod def fn: """Return the cost associated with an output ``a`` and desired output ``y``. """ return 0.5*np.linalg.norm**2 @staticmethod def delta: """Return the error delta from the output layer.""" return  * sigmoid_primeclass CrossEntropyCost: @staticmethod def fn: """Return the cost associated with an output ``a`` and desired output ``y``. Note that np.nan_to_num is used to ensure numerical stability. In particular, if both ``a`` and ``y`` have a 1.0 in the same slot, then the expression *np.log returns nan. The np.nan_to_num ensures that that is converted to the correct value . """ return np.sum(np.nan_to_num(-y*np.log*np.log @staticmethod def delta: """Return the error delta from the output layer. Note that the parameter ``z`` is not used by the method. It is included in the method's parameters in order to make the interface consistent with the delta method for other cost classes. """ return #### Main Network classclass Network: def __init__(self, sizes, cost=CrossEntropyCost): """The list ``sizes`` contains the number of neurons in the respective layers of the network. For example, if the list was [2, 3, 1] then it would be a three-layer network, with the first layer containing 2 neurons, the second layer 3 neurons, and the third layer 1 neuron. The biases and weights for the network are initialized randomly, using ``self.default_weight_initializer`` (see docstring for that method). """ self.num_layers = len self.sizes = sizes self.default_weight_initializer() self.cost=cost def default_weight_initializer: """Initialize each weight using a Gaussian distribution with mean 0 and standard deviation 1 over the square root of the number of weights connecting to the same neuron. Initialize the biases using a Gaussian distribution with mean 0 and standard deviation 1. Note that the first layer is assumed to be an input layer, and by convention we won't set any biases for those neurons, since biases are only ever used in computing the outputs from later layers. """ self.biases = [np.random.randn for y in self.sizes[1:]] self.weights = [np.random.randn/np.sqrt for x, y in zip(self.sizes[:-1], self.sizes[1:])] def large_weight_initializer: """Initialize the weights using a Gaussian distribution with mean 0 and standard deviation 1. Initialize the biases using a Gaussian distribution with mean 0 and standard deviation 1. Note that the first layer is assumed to be an input layer, and by convention we won't set any biases for those neurons, since biases are only ever used in computing the outputs from later layers. This weight and bias initializer uses the same approach as in Chapter 1, and is included for purposes of comparison. It will usually be better to use the default weight initializer instead. """ self.biases = [np.random.randn for y in self.sizes[1:]] self.weights = [np.random.randn for x, y in zip(self.sizes[:-1], self.sizes[1:])] def feedforward: """Return the output of the network if ``a`` is input.""" for b, w in zip(self.biases, self.weights): a = sigmoid(np.dot return a def SGD(self, training_data, epochs, mini_batch_size, eta, lmbda = 0.0, evaluation_data=None, monitor_evaluation_cost=False, monitor_evaluation_accuracy=False, monitor_training_cost=False, monitor_training_accuracy=False): """Train the neural network using mini-batch stochastic gradient descent. The ``training_data`` is a list of tuples ```` representing the training inputs and the desired outputs. The other non-optional parameters are self-explanatory, as is the regularization parameter ``lmbda``. The method also accepts ``evaluation_data``, usually either the validation or test data. We can monitor the cost and accuracy on either the evaluation data or the training data, by setting the appropriate flags. The method returns a tuple containing four lists: the (per-epoch) costs on the evaluation data, the accuracies on the evaluation data, the costs on the training data, and the accuracies on the training data. All values are evaluated at the end of each training epoch. So, for example, if we train for 30 epochs, then the first element of the tuple will be a 30-element list containing the cost on the evaluation data at the end of each epoch. Note that the lists are empty if the corresponding flag is not set. """ if evaluation_data: n_data = len(evaluation_data) n = len(training_data) evaluation_cost, evaluation_accuracy = [], [] training_cost, training_accuracy = [], [] for j in xrange: random.shuffle(training_data) mini_batches = [ training_data[k:k+mini_batch_size] for k in xrange(0, n, mini_batch_size)] for mini_batch in mini_batches: self.update_mini_batch( mini_batch, eta, lmbda, len(training_data)) print "Epoch %s training complete" % j if monitor_training_cost: cost = self.total_cost(training_data, lmbda) training_cost.append print "Cost on training data: {}".format if monitor_training_accuracy: accuracy = self.accuracy(training_data, convert=True) training_accuracy.append print "Accuracy on training data: {} / {}".format( accuracy, n) if monitor_evaluation_cost: cost = self.total_cost(evaluation_data, lmbda, convert=True) evaluation_cost.append print "Cost on evaluation data: {}".format if monitor_evaluation_accuracy: accuracy = self.accuracy(evaluation_data) evaluation_accuracy.append print "Accuracy on evaluation data: {} / {}".format( self.accuracy(evaluation_data), n_data) print return evaluation_cost, evaluation_accuracy, \ training_cost, training_accuracy def update_mini_batch(self, mini_batch, eta, lmbda, n): """Update the network's weights and biases by applying gradient descent using backpropagation to a single mini batch. The ``mini_batch`` is a list of tuples ````, ``eta`` is the learning rate, ``lmbda`` is the regularization parameter, and ``n`` is the total size of the training data set. """ nabla_b = [np.zeros for b in self.biases] nabla_w = [np.zeros for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [(1-eta**w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] def backprop(self, x, y): """Return a tuple ``(nabla_b, nabla_w)`` representing the gradient for the cost function C_x. ``nabla_b`` and ``nabla_w`` are layer-by-layer lists of numpy arrays, similar to ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros for b in self.biases] nabla_w = [np.zeros for w in self.weights] # feedforward activation = x activations = [x] # list to store all the activations, layer by layer zs = [] # list to store all the z vectors, layer by layer for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append activation = sigmoid activations.append(activation) # backward pass delta = (self.cost).delta(zs[-1], activations[-1], y) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose # Note that the variable l in the loop below is used a little # differently to the notation in Chapter 2 of the book. Here, # l = 1 means the last layer of neurons, l = 2 is the # second-last layer, and so on. It's a renumbering of the # scheme in the book, used here to take advantage of the fact # that Python can use negative indices in lists. for l in xrange(2, self.num_layers): z = zs[-l] sp = sigmoid_prime delta = np.dot(self.weights[-l+1].transpose * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose return (nabla_b, nabla_w) def accuracy(self, data, convert=False): """Return the number of inputs in ``data`` for which the neural network outputs the correct result. The neural network's output is assumed to be the index of whichever neuron in the final layer has the highest activation. The flag ``convert`` should be set to False if the data set is validation or test data (the usual case), and to True if the data set is the training data. The need for this flag arises due to differences in the way the results ``y`` are represented in the different data sets. In particular, it flags whether we need to convert between the different representations. It may seem strange to use different representations for the different data sets. Why not use the same representation for all three data sets? It's done for efficiency reasons -- the program usually evaluates the cost on the training data and the accuracy on other data sets. These are different types of computations, and using different representations speeds things up. More details on the representations can be found in mnist_loader.load_data_wrapper. """ if convert: results = [(np.argmax(self.feedforward, np.argmax for  in data] else: results = [(np.argmax(self.feedforward for  in data] return sum(int for  in results) def total_cost(self, data, lmbda, convert=False): """Return the total cost for the data set ``data``. The flag ``convert`` should be set to False if the data set is the training data (the usual case), and to True if the data set is the validation or test data. See comments on the similar (but reversed) convention for the ``accuracy`` method, above. """ cost = 0.0 for x, y in data: a = self.feedforward if convert: y = vectorized_result cost += self.cost.fn/len cost += 0.5*(lmbda/len*sum( np.linalg.norm**2 for w in self.weights) return cost def save(self, filename): """Save the neural network to the file ``filename``.""" data = {"sizes": self.sizes, "weights": [w.tolist() for w in self.weights], "biases": [b.tolist() for b in self.biases], "cost": str(self.cost.__name__)} f = open(filename, "w") json.dump f.close()#### Loading a Networkdef load: """Load a neural network from the file ``filename``. Returns an instance of Network. """ f = open(filename, "r") data = json.load f.close() cost = getattr(sys.modules[__name__], data["cost"]) net = Network(data["sizes"], cost=cost) net.weights = [np.array for w in data["weights"]] net.biases = [np.array for b in data["biases"]] return net#### Miscellaneous functionsdef vectorized_result: """Return a 10-dimensional unit vector with a 1.0 in the j'th position and zeroes elsewhere. This is used to convert a digit  into a corresponding desired output from the neural network. """ e = np.zeros e[j] = 1.0 return edef sigmoid: """The sigmoid function.""" return 1.0/(1.0+np.expdef sigmoid_prime: """Derivative of the sigmoid function.""" return sigmoid*(1-sigmoid

有个进一步有意思的改变正是在代码中增添了 L2
规范化。尽管这是八个重中之重的定义上的更动,在落到实处中实际上一定简单。对绝超越五成动静,仅仅必要传递参数
lmbda 到不一样的方法中,主若是 Network.SGD
方法。实际上的劳作正是单排代码的事在 Network.update_mini_batch
的尾数第陆行。那就是大家改变梯度下跌规则来拓展权重降低的地点。就算改动相当的小,但其对结果影响却极大!

实质上那种场馆在神经网络中落成部分新技巧的宽泛景观。大家费用了近千字的篇幅来谈谈规范化。概念的理解万分微妙困难。不过添加到程序中的时候却这么简约。精妙复杂的技能能够透过微小的代码改动就能够兑现了。

另二个微薄却至关首要的改变是随机梯度下降方法的多少个标志位的增添。这么些标志位让大家得以对在代价和准确度的监察变得大概。这几个标志位暗中认可是
False 的,可是在大家例子中,已经被置为 True 来监控 Network
的性能。另外,network2.py 中的 Network.SGD
方法重临了叁个四元组来代表监察和控制的结果。我们得以那样使用:

>>> evaluation_cost, evaluation_accuracy, ... training_cost, training_accuracy = net.SGD(training_data, 30, 10, 0.5,... lmbda = 5.0,... evaluation_data=validation_data,... monitor_evaluation_accuracy=True,... monitor_evaluation_cost=True,... monitor_training_accuracy=True,... monitor_training_cost=True)

所以,比如 evaluation_cost 将会是一个 $$30$$
个因素的列表个中包罗了各类回合在证实集合上的代价函数值。那种类型的信息在知道网络行为的进程中等专业高校门有用。比如,它能够用来画出呈现网络随时间学习的情景。其实,那也是自笔者在前头的章节中突显性质的点子。可是要留心的是只要此外标志位都并未设置的话,对应的元组中的成分正是空驶列车表。

另1个扩展项正是在 Network.save 方法中的代码,用来将 Network
对象保存在磁盘上,还有三个载回内部存款和储蓄器的函数。那八个措施都是应用 JSON
举行的,而非 Python 的 pickle 或者 cPickle 模块——这一个普普通通是 Python
中常见的保留和装载对象的不二法门。使用 JSON
的案由是,假诺在今后某天,大家想更改 Network 类来允许非 sigmoid
的神经细胞。对那个改变的兑现,大家最或许是改变在 Network.__init__
方法中定义的质量。若是大家简要地 pickle 对象,会招致 load
函数出错。使用 JSON 进行种类化能够显式地让老的 Network 依然能够 load

别的也还有局地细微的改变。可是那些只是 network.py
的微调。结果就是把程序从 $$74$$ 行增进到了 $$152$$ 行。

  • 更改上面包车型大巴代码来实现 L1 规范化,使用 L1 规范化使用 $$30$$
    个隐藏元的神经互联网对 MNIST
    数字实行归类。你能够找到二个规范化参数使得比无规范化效果更好么?
  • 看看 network.py 中的 Network.cost_derivative
    方法。这些情势是为三回代价函数写的。如何修改能够用来交叉熵代价函数上?你能无法体会掌握可能在交叉熵函数上相见的标题?在
    network2.py 中,大家曾经去掉了 Network.cost_derivative
    方法,将其集成进了 CrossEntropyCost.delta
    方法中。请问,那样是怎么着搞定你早已发现的题指标?

相关文章

网站地图xml地图