学习率
学习率 一塔 就是每次挪动中的步长。一塔通常来说给一个比较小的值会更好一些。

步子太大会导致迈过谷底。
其他超参数
而由于偏导数方向的改变。你再次挪动又会向着谷底的方向挪动。

只是由于步子还是很大,还是会迈过谷底。这样就会像上图一样来回折返。
到底设置为多少,是要根据自己的项目进行判断的。但是小一点的值总是要好一点的。
收敛的比较慢,但是可以使loss的值下到谷底。
Dropout(克服过拟合)
每次训练随机丢弃一些神经元,就相当于整个网络结构发生变化
减少过拟合风险

在某些层上临时关闭一些节点,让他们不输入也不输出。原则上选择关闭哪些节点都是随机性的。
在分类阶段,将所有的节点都置于有效的状态

就可以把训练中得到的子网络并联起来使用。
交叉熵( Cross Entropy)
学习慢
有时候我们使用相同的学习率,初始化不同的w和b,开始学习的变化率会很慢。
网络在开始学习的时候,整个loss下降的很慢。
举例: 使用梯度下降法来计算w和b, 来看看它是如何学习的
w=0.6 b=0.9 x=1.0 y=0.82 学习率=0.15

简化后的网络。

我们的w和b在不断的变化,我们的cost在不断的下降。
举例: 一个不好的初始化
w=2.0 b=2.0 x=1.0 y=0.2 学习率=0.15

可以看到网络的训练开始学习的很慢。w和b的变化很慢。
复杂的神经网络学习很慢。
原因: 其实就是因为偏导很小造成的。


也就是图中某一点的斜率几乎水平了。
为什么偏导很小,导致学习很慢。
回顾一下之前的网络更新方程。

最后一层的偏loss/偏b 等于 预测出来的结果减去网络的标签。点乘于sigmoid的导数。
这里的y0 yi都是一个定值。sigmoid在Z 小于-4 或大于4.水平。斜率为0.

想要让网络学习快一点,也就是偏导大一些。我们就要增大sigmoid函数的导数值。
定义

之前我们都是使用二次cost来定义我们网络的损失函数。这里我们可以使用交叉熵来定义我们网络的损失函数。
我们可以重新推导一遍偏loss偏w和偏loss偏b的值。

如果使用交叉熵函数,而不使用二次损失函数。

可以看到最终的公式里就没有sigmoid的导数这一项了。同样的方法我们也可以推导出偏loss/偏b。(避免使用sigmoid的导数)

这里的x,n,y都是定制。sigmoid(z)是网络的预测结果。如果网络的预测结果和真实结果接近的话,整个网络的loss值就会减小。
如果偏差比较大的话,loss的值也会因为偏导较大而减小。

可以看到情况1中loss一直随着训练轮数增加而下降。

情况2不再出现学习很慢的情况。
交叉熵编码实现
如何在代码里面添加交叉熵(Cross Entropy)
Network类的初始化时我们可以定义一个损失函数。
def __init__(self, sizes, cost=CrossEntropyCost):
# 损失函数
self.cost = cost
增加一个cost参数。
定义一个二次cost的类
class QuadraticCost(object):
@staticmethod
def fn(a, y):
return 0.5 * np.linalg.norm(a -y) ** 2
@staticmethod
def delta(z, a, y):
return (a - y) * sigmoid_prime(z)
通过staticmethod装饰器,可以直接通过类名.方法名调用(不要实例化:QuadraticCost.fn)
fn里面a是网络预测结果,y是真实的标签。我们返回二次cost函数。
1/2 乘以 (预测值-真实值)的二范数 的平方。
np.linalg.norm
https://blog.csdn.net/lanchunhui/article/details/51004387
再定义另一个delta方法,输入参数为z,预测值a,真实值y
返回(误差) 乘以 sigmoid(z)
这时候再定义交叉熵的类。
class CrossEntropyCost(object):
'''
>>>import numpy as np
>>> a = np.array([[np.nan,np.inf],\
... [-np.nan,-np.inf]])
>>> a
array([[ nan, inf],
[ nan, -inf]])
>>> np.nan_to_num(a)
array([[ 0.00000000e+000, 1.79769313e+308],
[ 0.00000000e+000, -1.79769313e+308]])
'''
@staticmethod
def fn(a, y):
return np.sum(np.nan_to_num(-y * np.log(a) - (1 - y) * np.log(1 - a)))
@staticmethod
def delta(z, a, y):
return (a - y)
交叉熵的方程:

因为在计算出来的数中可能存在无限大和nan值。所以我们通过nan_to_num方法将其进行处理。
网络初始化时,我们可以默认使用CrossEntropyCost这个类
接着我们要将反向更新的代码进行修改:
# 反向更新了
# 计算最后一层的误差
delta = (self.cost).delta(zs[-1], activations[-1], y)
使用self.cost函数来替换掉我们之前写死的二次损失函数。

网友评论