《Grokking Deep Learning》 广义梯度下降
广义梯度下降
你不能通过遵守规则来学习走路,你需要通过做和摔倒来学习。 ——理查德·布兰森
一、如何设计多输入的神经元
1、具有多个输入的空网络

def w_sum(a,b):
assert(len(a) == len(b))
output = 0
for i in range(len(a)):
output += (a[i] * b[i])
return output
weights = [0.1, 0.2, -.1]
def neural_network(input, weights):
pred = w_sum(input,weights)
return pred
python

2、预测+比较:进行预测,并计算误差和增量
把数据输入到神经元计算。下面共有四组数据,每一组都要同时输入到神经元的三个输入。

toes = [8.5 , 9.5, 9.9, 9.0]
wlrec = [0.65, 0.8, 0.8, 0.9]
nfans = [1.2 , 1.3, 0.5, 1.0]
win_or_lose_binary = [1, 1, 0, 1]#代表四次输入的比赛数据,对应的四次输赢(实际发生)
true = win_or_lose_binary[0]
input = [toes[0],wlrec[0],nfans[0]]#把第一组数据(第一列)装配进input
pred = neural_network(input,weights)#调用神经元函数得到一个pred
error = (pred - true) ** 2#差值的平方
delta = pred - true#差值
python
3、计算每个重量增量并把它放在每个重量上

def ele_mul(number,vector):
output = [0,0,0]
assert(len(output) == len(vector))
for i in range(len(vector)):
output[i] = number * vector[i]#计算每一个权重的差距
return output
input = [toes[0],wlrec[0],nfans[0]]
pred = neural_network(input,weight)
error = (pred - true) *
delta = pred - true
weight_deltas = ele_mul(delta,input)
python

weight_deltas = ele_mul(delta,input) 神经元的(预测-真实)之间的差距,反向计算,测算出weight的差距,每个输入的weight1,w2……的差距
4、更新重量

input = [toes[0],wlrec[0],nfans[0]]
pred = neural_network(input,weight)
error = (pred - true) *
delta = pred - true
weight_deltas = ele_mul(delta,input)#获取权重差距
alpha = 0.01#设置学习速率
for i in range(len(weights)):
weights[i] -= alpha * weight_deltas[i]
print("Weights:" + str(weights))
print("Weight Deltas:" + str(weight_deltas))
python

二、神经元的输入输出
1、

图左边是神经元的一次数据输入输出+单词学习,右侧是每根权重的error-weight变化关系。
右侧的这些曲线的斜率(虚线)由权重 δ 值 反映。a 比其他的更陡。如果它们共享相同的输出增量和误差度量,为什么 a 的权重增量比其他的更陡?因为 a 的输入值明显高于其他值,因此导数更高。

不断致性alpha=0.01这个步伐的靠近目标,极值,三个weight都逐步到达能够让error最小化的地方。
大部分学习(权重改变)是在具有最大输入 a 的权重上进行的,因为输入会显著改 变斜率。这并不一定对所有环境都有利。一个叫做标准化的子字段有助于鼓励所有权重的学习,尽管数据集有这样的特征。斜率的显著差异迫使我将 α 设定得比我想要的低(0.01 而不是 0.1)。
2、
我们冻结一个weight,只训练另外两个weight,我们虽然冻结了A weight,但是它仍然滑动到极值点,因为error是共享的。
源代码:
def neural_network(input, weights):
out = 0
for i in range(len(input)):
out += (input[i] * weights[i])
return out
def ele_mul(scalar, vector):
out = [0,0,0]
for i in range(len(out)):
out[i] = vector[i] * scalar
return out
toes = [8.5, 9.5, 9.9, 9.0]
wlrec = [0.65, 0.8, 0.8, 0.9]
nfans = [1.2, 1.3, 0.5, 1.0]
win_or_lose_binary = [1, 1, 0, 1]
true = win_or_lose_binary[0]
alpha = 0.01
weights = [0.1, 0.2, -.1]
input = [toes[0],wlrec[0],nfans[0]]
for iter in range(3):
pred = neural_network(input,weights)
error = (pred - true) *
delta = pred - true
weight_deltas=ele_mul(delta,input)
print("Iteration:" + str(iter+1))
print("Pred:" + str(pred))
print("Error:" + str(error))
print("Delta:" + str(delta))
print("Weights:" + str(weights))
print("Weight_Deltas:")
print(str(weight_deltas))
print(
)
for i in range(len(weights)):
weights[i]-=alpha*weight_deltas[i]
python

结果:

代码分析:
1:
def neural_network(input, weights):
out = 0
for i in range(len(input)):
out += (input[i] * weights[i])
return out
是神经元的代码
2:
def ele_mul(scalar, vector):
out = [0,0,0]
for i in range(len(out)):
out[i] = vector[i] * scalar
return out
计算权重差值
3:
toes = [8.5, 9.5, 9.9, 9.0]
wlrec = [0.65, 0.8, 0.8, 0.9]
nfans = [1.2, 1.3, 0.5, 1.0]win_or_lose_binary = [1, 1, 0, 1]
true = win_or_lose_binary[0]
数据初始化
4:
alpha = 0.01
weights = [0.1, 0.2, -.1]
input = [toes[0],wlrec[0],nfans[0]]
学习速率,权重初始化,输入装配到input
5 分析剩下的三for循环:
pred = neural_network(input,weights)
error = (pred - true) ** 2
delta = pred - true
获取一次预测结果,计算error和差距。
6:
weight_deltas=ele_mul(delta,input)
weight_deltas[0]=0
这里让weight_daltas[0]=0通过weight_deltas=ele_mul(delta,input)训练后,weight_daltas本来是获取到了所有权重的差距值,这个是一个list返回三个元素。
我们强行把第一个weight设置为了0,相当于freezing the weight,冻结了这个权重,让它之前算都是白算。
将weight_deltas[0]=0以后结果:

7:
print(“Iteration:” + str(iter+1))
print(“Pred:” + str(pred))
print(“Error:” + str(error))
print(“Delta:” + str(delta))
print(“Weights:” + str(weights))
print(“Weight_Deltas:”)
print(str(weight_deltas))
print(
)
输出各种之前算好的数据。
8:
for i in range(len(weights)):
weights[i]-=alpha*weight_deltas[i]
把weight更新一下,这里的i陆续提取0,1,2.
三、冻结一个weight:它有什么作用?

这些是四维形状的 2D 切片。三个尺寸是重量值,第四个尺寸是误差。这个形状叫做误差平面,信不信由你,它的曲率是由训练数据决定的
如果你用 b 和 c 权重收敛(达到误差= 0),然后试着训练 a,a 不会移动。
为什么?error = 0,这意味着 weight_delta 为 0。这揭示了神经网络的一个潜在的破坏性:a 可能是一个具有很强预测能力的强大输入,但是如果网络偶然发现如何在没有它的情况下对训练数据进行准确预测,那么它将永远不会学会将 a 结合到它的预测中。还要注意 a 是如何找到碗的底部的。
曲线似乎向左移动,而不是黑点移动。只有当重量更新时,黑点才能水平移动。因为在这个实验中 a 的重量是固定的,所以这个点必须保持不变。但是误差显然会变成 0。
这个特性诞生了最牛的神经网络之一弹性固化权重的重神经网络。
目前深度学习深度神经网络以及最顶尖的创新,有这几个方面:
- 神经元的创新(循环神经网络这一分支)
- 神经元之间的创新(残差网络、卷积网络、胶囊网络)
四、多输入多输出梯度下降学习
1、任何神经网络能够有任何权重值,但是误差是由[任意][特定]权重配置,100%由数据决定,不管权重怎么变化,怎么适应,最终所有权重配置(就是训练好的权重)都是根据数据决定的。
实际上1 to N的神经元可以看成是:
N个1 to 1的神经元。
N to N的神经元就是:
N个 N to 1 的神经元。
也就是说,输入数据的元素的多少,权重会共同影响输出。,但是一个神经元的多个输出,互不干扰。

这张图呈现了这个MNIST分类神经网络,基本上是由 N to N神经网络构成的。
唯一的不同,就是输入和输出的数量,具有了很大的提高,网络具有782个输入和10个输出,如果这个网络能够准确预测,那么放入一个2的图片,它会在对应的第三个输出数值为1(因为从0开始时第一个输出),如果它能够完成所有数字的预测,则他就没有error误差。

2、如果我们拿着这些权值,把这些权值输出到屏幕,形成一幅画。

可以看到,那些像素有最高的相关性与一个特定的输出节点,左边这幅画,是N to 1 神经元,我们把N个weight作为颜色值形成一幅画。
右侧这张图,所有输入 to 第二个节点的权值构成权值图会体现出一个非常清晰的1。
如果们我们尝试输出 N to 第五号节点的权值图,将会比较模糊。
五、可视化重量值
神经网络研究中一个有趣且直观的实践(尤其是对于图像分类器)是将权重可视化,就像它们是图像一样节点有784 个输入权重,每个权重映射一个像素和数字 2 之间的关系。
这是什么关系?
如果权重很高,这意味着模型认为这个像素和数字 2 有很高的相关性。如果数字非常低(负),则网络认为该像素和数字 2 之间的相关性非常低(甚至可能是负相关性)

红色代表:权值为0
越高权值,越白化。越小于0,越黑化。
小结:
点积:是两个向量之间相似性的松散度量
如果组合权重的方式允许计算误差函数和增量,梯度下降可以告诉你如何移动权重以减少误差。
点积对权重和输入意味着什么?
如果权重向量与 2 的输入向量相似,那么它会输出一个高分,因为这两个 向量相似。相反,如果权重向量与 2
的输入向量不相似,它将输出一个低分数。
如何将单个增量(在节点上)转换成三个权重增量值?
记住 delta 与 weight_delta 的定义和目的。delta 是您希望节点的值有多大差异的度量。在这种情况下,
可以通过节点值和您希望节点值之间的直接减法来计算它(pred true)。正增量表示节点值太高,负增量 表示节点值太低。
因为每个权重都有唯一的输入和共享的增量,所以使用每个权重的输入乘以增量来创建每个权重增量。
