读书笔记葡京手机,创新神经网络的上学方法

(本文是依据
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,所以大家须要探索一些更加好的措施来安装大家互连网的起初化权重和错误,那对于支持互连网学习进程的晋升很有价值。

权重最初化

到这段日子甘休,大家都是用归一化高斯布满来初始化权值,不过,大家很想通晓是还是不是有别的初始化方法能够让网络练习得越来越好。

实在,确实存在比高斯遍及更好的法子。然而,大家供给先通晓高斯布满的初步化会设有啥短处。

若果大家有如下的互连网布局,在那之中蕴藏 1000 个输入神经元:

葡京手机 1

明天,我们聚集于掩盖层第一个神经元。假诺输入中,有八分之四的神经细胞是
0,八分之四的神经细胞是 1。输入到遮掩层的权重和为 \(z=\sum_j{w_j x_j}+b\)。由于有八分之四的
\(x_j=0\),所以 \(z\) 也正是是 501
个归一化的高斯布满随机变量的和。因而,\(z\) 自己也是三个高斯布满,其均值为
0,标准差为 \(\sqrt{501} \approx
22.4\)。那是三个很「宽」的分布:

葡京手机 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
互连网的时候也时时使用这个做法,举例,只用一点都不大的多少集中磨炼练,可能将网络的构造变小等等。这个做法唯有二个指标:让互连网尽恐怕快地陈说结果,不管结果好坏,这是我们能再三再四调节和测验下去的前提。在频仍调节和测量检验后,我们频频能得到部分「灵感」,之后再逐月将难点变的更眼花缭乱一些,然后继续调节和测验。

好了,上边大家本着学习率 \(\eta\)、L2 正则化参数 \(\lambda\)
和批练习的数量集大小学习有些相比较实惠的守则。

咱俩为了简化,倘若,大家运用陶冶样本 x 个中八分之四的神经元值为
$$0$$,另八分之四为
$$1$$。上边包车型大巴观念也是能够更宽广地采纳,但是你能够从特例中赢得背后的观念。让大家着想带权和
$$z=\sum_j w_j x_j + b$$ 的遮蔽元输入。在那之中 $$500$$
个项消去了,因为对应的输入 $$x_j=0$$。所以 $$z$$ 是 $$501$$
个正式的高斯随机变量的和,包涵 $$500$$ 个权重项和额外的 $$1$$
个错误项。因而 $$z$$ 本人是三个均值为 $$0$$ 标准差为
$$\sqrt{501}\approx 22.4$$ 的遍及。$$z$$
其实有二个百般宽的高斯布满,不是不行尖的样子:

学习率

至于学习率的选料,Andrew Ng 在她的 Machine
Learning

课程中有过详尽的任课。那中间最根本的是要制止学习率过大给梯度下落带来「抖动」的主题素材,如下图中的橙线所示。在安装学习率时,咱们能够先安装贰个小一些的数值,如
0.1,假诺这几个数值太大,则调低三个数量级到 0.01,甚至0.001…若是开掘学习进程中代价函数未有出现「抖动」的事态,再适合增强学习率,如由原本的
0.1 进步到 0.2、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$$ 如故是贰个均值为 $$0$$
然则有很陡的山顶的高斯分布。尽管,我们有 $$500$$ 个值为 $$0$$
的输入和$$500$$ 个值为 $$1$$ 的输入。那么很容表明 $$z$$ 是言听计从均值为
$$0$$ 标准差为 $$\sqrt{3/2} = 1.22$$
的高斯布满。那图像要比原先陡得多,所以即使自身曾经对横坐标举办压缩为了实行越来越直观的可比:

批演习的数据集大小

力排众议上,我们一同能够在每便演习时只用八个样书,但这么会招致磨练进度特别长久,而多少个样本进行批陶冶,在当今计算机的极快矩阵运算下并不及单个样本慢,那样相当于同临时候训练四个样本的时光和单个样本同样(当然,将持有样本都用于陶冶仍然会潜濡默化进度,所以才会选择专擅梯度演练的批样本)。别的,个人以为,综合四个样本再取均值进行训练,能够抵消部分噪音样本的影响。

葡京手机 8

参考

那般的二个神经元更不容许饱和,因而也比异常的小或许碰着学习进程下滑的标题。

  • 验证 $$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}}$$
已经得以干活得很好了。假诺您对其余的合计感兴趣,我推荐你看看在 $$2011$$
年的 Yoshua Bengio 的舆论的 $$14$$ 和 $$15$$ 页,以及相关的参考文献。

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

  • 将标准化和纠正的权重开始化方法结合使用 L2
    标准化有的时候候会自动给大家有个别像样于新的初叶化方法的事物。就算我们运用旧的开头化权重的点子。思考多个启发式的视角:若是$$\lambda$$
    不太小,练习的首先回合将会差点被权重裁减统治。;要是 $$\eta\lambda
    \ll n$$,权重会依据因子 $$exp(-\eta\lambda/m)$$ 每一趟合下落;假如$$\lambda$$ 不太大,权重缩短会在权重降到 $$1/\sqrt{n}$$
    的时候保持住,在那之中 $$n$$
    是网络中权重的个数。用论述那么些原则都已经满意本节给出的例证。

让咱们达成本章切磋过的那一个主张。大家将写出一个新的顺序,network2.py,那是一个对第一章中付出的
network.py 的精耕细作版本。若是您没有留神看过
network.py,那您可能会须求重读前边境海关于这段代码的座谈。仅仅 $$74$$
行代码,也很易懂。

network.py 一样,首要部分就是 Network
类了,大家用那些来表示神经互连网。使用一个 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。同样大家尚无对第一层的神经细胞的不是进行早先化。因为第一层其实是输入层,所以没有需求引进任何的谬误。我们在
network.py 中做了一心一样的事务。

作为 default_weight_initializer 的补充,大家一致包括了叁个
large_weight_initializer
方法。这么些点子运用了第一章中的观点开端化了权重和错误。代码也就唯有是和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__ 中的第1个新的东西就是大家最早化了 cost
属性。为了精晓那几个职业的原理,让大家看一下用来表示交叉熵代价的类:

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

让大家解释一下。第贰个看到的是:固然选用的是穿插熵,数学上看,就是一个函数,这里大家用
Python 的类并非 Python
函数完成了它。为啥那样做吗?答案就是代价函数在大家的互联网中饰演了三种分化的剧中人物。显明的角色正是代价是出口激活值
$$a$$ 和对象输出 $$y$$ 差别优劣的胸怀。这一个剧中人物通过
CrossEntropyCost.fn 方法来饰演。(注意,np.nan_to_num 调用确定保障了
Numpy 正确管理临近 $$0$$
的对数值)可是代价函数其实还应该有另一个角色。回看第二章中运作反向传来算法时,大家要求计算网络出口引用误差,$$\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$$
个要素的列表当中积存了各样回合在验证会集上的代价函数值。那类别型的音信在通晓互连网行为的进程中极其有用。比如,它可以用来画出呈现互连网随时间学习的事态。其实,那也是自身在头里的章节中显得性质的点子。但是要专一的是一旦其他标记位都未有安装的话,对应的元组中的成分正是空驶列车表。

另八个充实项就是在 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
    方法中。请问,那样是什么缓慢解决你早已开掘的主题材料的?