那么我们接着上节开始讲更新权重、权重示例以及神经网路的准备布局。 

          Github源码地址:​​https://github.com/hzka/PythonNetworkBook​

1.14我们实际上是如何更新权重的。

(一)

       以简单的3层,每层3个节点的神经网络为例。最后的输出是这样的。作者提出了一个问题:如何调整第一个节点和隐藏层第二个节点的之间链路的权重,以使得输出层第三个节点的输出增加0.5呢?

Python神经网络编程(二)之更新神经网络权重_斜率

       太难了这式子,尝试换一种说法:首先是拥抱悲观主义,训练数据不足/有错、神经网络的缺陷性。假设你在伸手不见五指的山顶上,地形陡峭、路况复杂,你只有一把手电筒做近距离观察,要下山你需要事先制定计划,一步一个脚印。在数学上这叫梯度下降。梯度是指地面坡度,你走的方向是最逗得坡度向下的方向。如果我们将复杂函数当作网络误差,那么下山找到最小值就意味着最小化误差,从而改进网络输出。

        使用y=(x-1)^2+1来举例。y表示误差,我们希望可以找到最小x,可以最小化y,随机选一个点:斜率为负、沿着向下方向,同时沿x轴向右。一直在改进,直到几乎不能改进为止,这样我们就确信自己到达了最小值。要注意的是改变步子大小,避免调超,正梯度减小x,负梯度增加x。

Python神经网络编程(二)之更新神经网络权重_更新权重_02

        如果y依赖于a,b,c,d而非单单x。我们可能会卡在错误的山谷里(因为复杂函数有多个山谷),解决方法:我们从山上的不同点开始,多次训练神经网络。确保不能终止错误的山谷。不同的起始点针对于不同的启始参数(启示链接权重)。

Python神经网络编程(二)之更新神经网络权重_神经网络_03

关键点:
       
1.梯度下降法是求解函数最小值的一种很好的办法,应用场景为函数非常复杂困难时。

       2.这种方法具有弹性,可以容忍不完善数据或者偶尔走错一步等等。

(二)
       
使用合适的误差函数,使用梯度下降法,我们可以正确的计算权重:

       由于误差是目标训练值与实际输出值之间的差值,因此我们可以轻易地将输出函数改变为误差函数。

Python神经网络编程(二)之更新神经网络权重_更新权重_04

       误差函数的第一种情况是误差相加,正负相抵了,不是一个很好的训练;第二种情况是采用差的绝对值,误差无法相抵,但可能会在V形山谷附近来回跳动,斜率不会变得减小,有超调的风险。第三种采用的是差的平方(目标值-实际值)^2,更倾向于第三种,因为:平滑连续,越接近最小值,梯度越小,超调的可能性比较小。

       误差对链接权重影响有多敏感?

       第一个图演示了一个权重,第二个图显示的是两个链接权重(多山地形中寻找山谷)。

Python神经网络编程(二)之更新神经网络权重_Python_05

       Python神经网络编程(二)之更新神经网络权重_神经网络_06表示当权重Wj,k发生改变时,误差E是如何改变的。这是误差函数的斜率,也就是我们希望使用梯度下降方法到达最小值的方向。

Python神经网络编程(二)之更新神经网络权重_神经网络_07

       首先展开误差函数,Python神经网络编程(二)之更新神经网络权重_斜率_08,Ok只取决于Wj,k ,误差函数根本不需要对所有输出节点求和,节点输出取决于所连接的链接,就是取决于链接权重。Python神经网络编程(二)之更新神经网络权重_神经网络_09。链式微积分法则:Python神经网络编程(二)之更新神经网络权重_斜率_10,Ok是节点k的输出,根据S函数的应用,可以得到Python神经网络编程(二)之更新神经网络权重_更新权重_11,附录中有对S函数的微分Python神经网络编程(二)之更新神经网络权重_更新权重_12;所以最终答案为

                          Python神经网络编程(二)之更新神经网络权重_斜率_13

       去掉常数之后,这个表达式描述了误差函数的斜率。这样我们可以调节Wj,k了:

Python神经网络编程(二)之更新神经网络权重_Python_14

       这是训练神经网络的关键。第一部分是目标值-实际值,第二部分是进入最后一层节点的信号,应用激活函数之前,我们可以称之为ik,最后一部分是前一隐藏层节点j的输出。这个式子的目的是为了优化隐藏层和输出层之间的权重,
       我们可以同理得到输入层和隐藏层之间权重的调整。

Python神经网络编程(二)之更新神经网络权重_权重_15

        第一部分是隐藏层节点中的反向传播,第二部分基本不变,只是改变了节点而已,最后一层是第一层节点的输出oi,这里刚好是输入信号,因为输入层不作任何处理。
       在应用每层训练样本,更新权重。权重改变的方向与梯度方向相反。使用学习因子以保证避免被错误样本拉的太远。若斜率为正,则减小权重;若斜率为负,则增大权重。阿尔法为学习率,用以调节变化强度,确保不会超调。

Python神经网络编程(二)之更新神经网络权重_神经网络_16

        最后得到的权重更新矩阵为:(阿尔法为学习因子,Ek为输出的误差,Ok为最后一层真实的输出值,j列矩阵的转置):

Python神经网络编程(二)之更新神经网络权重_更新权重_17

关键点:

       1.神经网络的误差是内部链接权重的函数;

       2.改进神经网络,意味着通过改变权重来减少这种误差;

       3.直接选择合适权重太难,通过误差函数的梯度下降,采取小步长,迭代的更新权重,所迈出的每一步是当前位置朝下的斜率最大方向(梯度下降)

       4.使用微积分可以计算误差斜率。

1.15权重更新成功实例

       举例:

Python神经网络编程(二)之更新神经网络权重_神经网络_18

         进行权重更新:

Python神经网络编程(二)之更新神经网络权重_更新权重_19

       一项一项计算:(1)已知Tk-Ok得到误差ek,e1=0.8;(2)S函数内的求和为(2*0.4)+(3*0.5)=2.3;(3)sigmod中得到1/(1+e^-x)其结果为0.909;(4)中间整体的表达式为0.909*(1-0.909)=0.083;(5)最后的O1为0.4,相乘之后得到-0.0265;若学习率为0.1,则改变量为-(0.1*0.02650)=+0.002650;w1,1更新后为2+0.002650=2.003650.经过成千上万次迭代,可以确定一种布局。

1.16准备布局

       并不是所有的神经网络的尝试都可以成功,可以通过训练数据、初始权重、涉及良好的输出方案来解决。

1.16.1输入

       对于S激活函数,大的X值,梯度较小,神经网络学习能力下降,这是饱和神经网络,因此需要小的输入;当然也不能输入信号太小(可能会丧失精度),一个好的建议是重新调整输入值,将其控制在0和1之间,譬如0.01。

Python神经网络编程(二)之更新神经网络权重_神经网络_20

1.16.2输出

        如果激活函数不能生成1的值,那么尝试将训练目标值设置为比较大的值就比较愚蠢了,在S中,逻辑函数不能取到1.0,如果将目标值设置在不可达中,增大权重,使得网络饱和。

Python神经网络编程(二)之更新神经网络权重_权重_21

          重新调整目标值,匹配激活函数的可能输出,注意避开激活函数不可能达到的值,用0.01~0.99范围内的值。

1.16.3随机初始权重

      大权重会大信号传递给激活函数,导致网络饱和,降低网络可以学习到更好地权重能力,避免大的初始权重值。建议从-1.0和1.0之间随机均匀选择初始权重。

      对于给定形状的网络以及特定激活函数,科学家设置了随机选择权重。规则具体为:对传入链接数量平方根倒数的大致范围进行随机采样。初始化权重。Eg:每个节点有3条传入链接,初始范围应随机化在-1/根号下3和+1/根号下3之间。禁止将权重设置为相同的恒定值或者初始权重为0。因为相同的话反向传播更新权重时完全相同,0权重会丧失学习能力。

Python神经网络编程(二)之更新神经网络权重_斜率_22

关键点:
     
 1.若输入、输出和初始权重数据与网络设计、实际求解不匹配,神经网络不能很好地工作;

       2.一个常见问题是饱和,大信号/大权重导致激活函数的斜率变得非常平缓,这降低了神经网络学习权重的能力;

       3.零值信号/权重会使网络丧失学习更好权重的能力。内部链接权重应该是随机的,小但避免零值,若传入链接较多,使用复杂规则降低权重。

       4.输入应该调整到较小值,常见范围0.01~0.99或者-1.0~1.0,取决于具体问题。

       5.输出应该在激活函数能够生成的值的范围内,否则会产生较大权重也达不到,一个合适范围是0.01~0.99。

       此为第一章的内容。