上篇主要阐述 BP算法的过程, 以及 推导的 4 大公式的结论, 现在呢要来逐步推导出这写公式的原理. 当理解到这一步, 就算真正理解 BP算法了. 也是先做一个简单的回顾一下, 不是很细, 重点在推导, 不清楚就结合图像呀, 其实很直观的. 全篇其实就是在求偏导, 引入中间变量, 应用链式法则 而已.

BP算法-变量声明

重点是理解 反向 即从 从右到左 的方向哦;

  • \(w^l_{jk}\) 第 l 层, 第 j 个节点, 到 第 \((l-1)\) 层的 第 k 个节点的 权值 (weight) ( 反向, 反向, 方向, 反向, 说了4遍)
  • \(w^l\) 第 l 层, 的 权值矩阵, 第 j 行, 第 k 列 为 \(w^l_{jk}\)
  • \(b_j^l\) 第 l 层, 第 j 个节点 的 bias (偏置)
  • \(b^l\) 第 l 层, 的 bias 向量
  • \(a^l_j\) 第 l 层, 第 j 个节点的 激励 (activation)
  • \(a^l\) 第 l 层, 的 激励 向量

假设激活函数是 \(\sigma\) , 根据网络 层次间的 映射(加权求和) 的关系, (每个神经元的模型):

单个神经元: \(a^l_j = \sigma(\sum\limits _k w^l_{jk} \ a^{l-1}_k + b^l_j)\)

该层的神经元: \(a^l = \sigma (w^l a^{l-1} + b^l)\)

如不能理解每个变量代表的意义, 就看图, 非常直观的呀

\(z^l = w^l a^{l-1} + b^l\)

\(z^l\) The weighted input to the neurons in layer l.

再定义一个中间变量 \(z^l\) 即 第 l 层神经元的 加权求输入向量, 其分量, \(z^l_j\) 为第 l 层, 第 j 个神经元的 加权求和输入.

\(z^l_j =\sum \limits_k w_{jk} a_k ^{l-1} + b^l_j\)

于是呢, 对于每个节点的输出, 就可以简单表示为 (向量形式哈) :

\(a^l = \sigma(z^l)\)

然后来看定义 损失函数, 采用咱最熟悉的 平方损失 的形式:

  • \(y = y(x)\) 样本 x 的标签向量 (期望输出)

  • \(a^L = a^L(x)\) 样本 x 的网络输出激励向量

  • n : 表示样本数量; L 表示网络层数

样本 x 表示向量, 每个分量也是一个向量(多特征), 对应于数据的每一行. 因此, x 写出来就是 nxp的矩阵

\(C = \frac {1}{2n} \sum \limits_x ||y(x) - a^L(x)||^2\)

这个 0.5 都懂哈, , 没啥特定意义. 就是求导的时候, 式子的2范数, 要把2拿下来 再 乘0.5, 就为1 , 形式上美观而已.

公式1: C 对于 - 输出层的梯度

梯度, 在BP中, 就是误差

\(\delta_j^L = \frac {\partial C}{\partial a^L_j} \ \sigma'(z^L_j) = \nabla _a C \odot \ \sigma'(z^L_j)\)

过程: (理解图 和 求导链式法则哦)

因为, \(\delta_j^L = \frac {\partial C}{\partial a^L_j} \ \frac {\partial a^L_j}{\partial z^L_j}\) , 而 \(a^L_j = \sigma (z^L_j)\), 因此, \(\delta_j^L = \frac {\partial C}{\partial a^L_j} \ \sigma'(z^L_j)\)

  • \(\frac {\partial C}{\partial a^L_j}​\) 表示代价函数 C 对于 输出层 第 j 个节点 的激励变化程度.
  • \(\sigma'(z^L_j)\) 表示 这第 j 个节点, 对于上层 加权输入 的变化程度.

如果使用上面给定的 哈达玛积公式, 写成矩阵形式的话, 就变成了:

\(\nabla _a C \odot \ \sigma'(z^L_j)\)

  • 向量 \(\nabla_a C\) 的第 j 个元素误差为: \(\frac {\partial C}{\partial a^L_j} = \nabla_a C = (a^L - y)\)
  • $ \delta ^L = (a^L - y) \odot \ \sigma'(z^L)$

过程:

\(\nabla_a C\) 即是对 \(C_x = \frac {1}{2} ||y - a^L||^2\) 的求导而得 ( \(y-a^L\) )

公式2: C 对于- 中间层 的梯度

\(\delta ^l = ((w^{l+1})^T \delta ^{l+1}) \odot \sigma '(z^l)\)

即假设已经知道 \(l+1\) 层的误差, 通过 \(l+1\) 层 和 l 层之间的 权值矩阵 w, 将误差进行回传, 得到 l 层的误差

推导:

根据上面 z 和 每层的节点的 误差定义 (偏导数作为误差) ,则第 l+1 层, 的第 k 个节点 的误差表示为:

\(\delta ^{l+1}_k = \frac {\partial C} {\partial z_k^{l+1}}\)

对于 l 层, 第第 j 个节点, 的误差表示为:

\(\delta ^l = \frac {\partial C}{\partial z^l_j}\) 这个是定义来的, 然后根据 层 之间的 加权输入链式法则 展开为有关于 (l +1) 层的变量

\(=\sum \limits_k \frac {\partial C}{\partial z^{l+1}_k} \frac {\partial z^{l+1}_k}{\partial z^l_j} = \sum \limits_k \delta^{l+1}_k \frac {\partial z^{l+1}_k}{\partial z^l_j}\)

第一项已经知道了, 继续探讨下 第二项 (注意变量的下标, 结合图形来理解)

\(z^{l+1}_k = \sum\limits_j w_{kj}^{l+1} a^l_j + b^{l+1}_k = \sum\limits_j w_{kj}^{l+1} \sigma (z^l_j) + b^{l+1}_k\)

\(\frac {\partial z^{l+1}_k}{\partial z^l_j} = w^{l+1}_{kj} \sigma '(z^l_j)\) 这里 \(\sum\) 是没有了, 因为跟 其他的 j 项 是没有关系的.

因此,

\(\delta ^l = \sum_k w^{l+1}_{kj} \sigma '(z^l_j) \delta_k ^{l+1}\)

\(\delta ^l = \sigma '(z^l_j) \sum_k w^{l+1}_{kj}\delta_k ^{l+1}\) 拎出 \(\sigma\) 是因为 \(\sum\) 对其不起作用, 可看作一个常数放在外面.

这个写成 哈达玛积的形式, 也就是上面的 \(\delta ^l = ((w^{l+1})^T \delta ^{l+1}) \odot \sigma '(z^l)\)

我个人感觉, 就直接写成推导的式子挺好的, 写为了 哈达玛积 反而有些让人看不懂, 而且吧, 我还容易写错. 都是矩阵嘛, 真的很容易就写错了, 这样反而造成更大的误解...不过呢, 多学学 debug 也是蛮重要的.

ps: 我现在就特别喜欢 debug 或者找 帮小伙伴找 bug 还有代码重构, 我感觉这是一个最为高效的互相学习交流的方式, 既学习别人的开发思路和代码风格 , 同时也跟别人分享自己的思路, 蛮有趣的体验哦.

公式3: C 对于 - Bias 的梯度

\(\frac {\partial C}{\partial b^l_j} = \delta^l_j\) 写成矩阵就是: \(\frac {\partial C}{\partial b} = \delta\)

推导:

\(z^l_j = \sum\limits_k w^l_{jk} a^{l-1}_k + b_j ^l\) 这个上面的 l 层 和 l+1 层是一样的, 重在理解层间的, 加权求和输入再激活的 关系

易知: \(\frac {\partial z^l_j}{\partial b^l_j} = 1\)

则: \(\frac {\partial C}{\partial b^l_j} = \frac {\partial C}{\partial z^l_j} \frac {\partial z^l_j}{\partial b^l_j} = \frac {\partial C}{\partial z^l_j} = \delta^l_j\)

公式4: C 对于 - 权值 的梯度

\(\frac {\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j\) 也可这样表达为: \(\frac {\partial C}{\partial w} = a_{in} \delta_{out}\)

推导: (跟公式3一样, 还是厉害 层间的关系, 注意理解每个下标的含义哦)

\(z^l_j = \sum\limits_k w^l_{jk} a^{l-1}_k + b^l_j\)

易知: \(\frac {\partial z^l_j}{\partial w^l_{jk}} = a^{l-1}_k\)

则: \(\frac {\partial C}{\partial w^l_{jk}} = \frac {\partial C}{\partial z^l_j} \frac {\partial z^l_j}{\partial w^l_{jk}} = a^{l-1}_k \ \frac {\partial C}{\partial z^l_{j}} = a^{l-1}_k \delta^l_j\)

  • \(a_{in}\) 表示 输入权值 w 上层 神经元的 激励实值

  • \(\delta_{out}\) 表示 本层 权值 w 输入到 下层 神经元的 误差实值

如果 \(a_{in}\) 接近于0, 则表示该 权值的梯度也接近0, 此时称该神经元的权值学习比较慢, 即梯度变化时, 对代价函数的影响较小. (激励值过低的神经元学习很慢), 这种神经元呢, 也被称为 饱和神经元 这就是我们期望的效果呀.

饱和神经元: (先看咱上边推导出的结论)

\(\sigma(x) = \frac {1}{1+e^{-x}}\)

\(\sigma'(x) = \sigma(x) (1-\sigma(x))\)

\(\delta_j^L = \frac {\partial C}{\partial a^L_j} \ \sigma'(z^L_j) = \nabla _a C \odot \ \sigma'(z^L_j)\)

\(\delta ^l = ((w^{l+1})^T \delta ^{l+1}) \odot \sigma '(z^l)\)

\(\frac {\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j\)

从激励函数来看,

\(\sigma(x) = \frac {1}{1+e^{-x}}\) 是一个 " s " 型的函数, 当 x = 0的时候, 激励值为 0.5

当某层神经元的 加权输入, **过大 或 过小 ** 时, 则 输出的激励值 要么接近1, 要么接近于 0, 这样呢, 对于 C 来时, 会导致 激励的导数值为 0, 从而 误差减小, 即权值学习很慢, 逐渐接近 饱和 (saturated) , 逐渐停止学习.

理解上面式子, 因为 \(\sigma'(x)\) 变化所带来的一连串影响哦

一个权值学习慢, 可能是因为 输入的神经元的激励很小, 或者其输出的神经元接近饱和( 激励过大接近1, 或过小, 接近0) .

小结 - 四大公式 及 矩阵表达

  • 公式1: C 对于 - 输出层的梯度: \(\delta_j^L = \frac {\partial C}{\partial a^L_j} \ \sigma'(z^L_j) = \nabla _a C \odot \ \sigma'(z^L_j)\)

  • 公式2: C 对于 - 中间层的梯度: \(\delta ^l = ((w^{l+1})^T \delta ^{l+1}) \odot \sigma '(z^l)\)

  • 公式3: C 对于 - Bias 的梯度: \(\frac {\partial C}{\partial b^l_j} = \delta^l_j\)

  • 公式4: C 对于 - 权值 的梯度: \(\frac {\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j\)

然后来写一波矩阵表达. (假设 隐含层是 m个节点, 输出层是 n 个节点)

为啥要矩阵表达呢, 首先是比较简洁呀, 公式上, 虽然有点不好理解. 但, 写成矩阵, 容易编程实现呀

公式1 可写为: \(\delta^L = \Sigma(z^L) \nabla_aC\)

\(\Sigma\) 这不是求和, 我写的 latex 是这样的: \Sigma 读作 " C 格码", 是个对角阵 \(\Sigma(z^L)\)主对角线元素为: \(\sigma (z^L_j)\)

维数: n x n, nx1 ==> nx1 的向量; L 表示输出层

公式2 可写为: \(\delta^l = \Sigma (z^L) (w^{l+1})^T \delta ^{l+1})\)

跟前面转法一样的, 维数分别是: mxm, (nxm) ^T, nx1 ==> m x 1 的向量, \(l\) 表示 中间的任意一层

公式3 可写为: \(\frac {\partial C}{\partial b^l} = \delta^l\)

公式4 可写为: \(\frac {\partial C}{\partial w} = a^{l-1}\ (\delta^l)^T\)

w 是 mxn 的矩阵; \(\delta ^l\) 是 l 层的误差向量, nx1维; $a^{l-1} 是 (l-1)层 $ 的激励向量, mx1维.

BP算法步骤 (SGD)

总体来看, BP 算法, 就2步

  • 前向计算出误差
  • 误差后传, 更新权值

搞定, 还差 撸一把numpy 代码, 这个不是很难哦, 网上也有很多, 不在这些了, 私下自己后面再编写吧, 毕竟思路的很清楚了.

BP算法完整推导 2.0 (下)的更多相关文章

  1. BP算法基本原理推导----《机器学习》笔记

    前言 多层网络的训练需要一种强大的学习算法,其中BP(errorBackPropagation)算法就是成功的代表,它是迄今最成功的神经网络学习算法. 今天就来探讨下BP算法的原理以及公式推导吧. 神 ...

  2. BP算法的推导

    反向传播算法的推导 如图为2-layers CNN,输入单元下标为i,数量d:隐层单元下表j,数量\(n_H\):输出层下表k,单元数量c 1.目标 调整权系数\(w_{ji}\),\(w_{kj}\ ...

  3. EM算法-完整推导

    前篇已经对EM过程,举了扔硬币和高斯分布等案例来直观认识了, 目标是参数估计, 分为 E-step 和 M-step, 不断循环, 直到收敛则求出了近似的估计参数, 不多说了, 本篇不说栗子, 直接来 ...

  4. 一文彻底搞懂BP算法:原理推导+数据演示+项目实战(上篇)

    欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 反向传播算法(Backpropagation Algorithm, ...

  5. 深度学习——前向传播算法和反向传播算法(BP算法)及其推导

    1 BP算法的推导 图1 一个简单的三层神经网络 图1所示是一个简单的三层(两个隐藏层,一个输出层)神经网络结构,假设我们使用这个神经网络来解决二分类问题,我们给这个网络一个输入样本,通过前向运算得到 ...

  6. 多层神经网络BP算法 原理及推导

    首先什么是人工神经网络?简单来说就是将单个感知器作为一个神经网络节点,然后用此类节点组成一个层次网络结构,我们称此网络即为人工神经网络(本人自己的理解).当网络的层次大于等于3层(输入层+隐藏层(大于 ...

  7. BP算法的矩阵推导

    目录 1. 需要的微积分知识 1.1 导数 1.2 求导的链式法则 2. 梯度下降法 2.1 梯度 2.2 梯度算法的解释 3.误差反向传播算法 3.1 理论推导 3.1.1 符号说明 3.1.2 推 ...

  8. 人工神经网络反向传播算法(BP算法)证明推导

    为了搞明白这个没少在网上搜,但是结果不尽人意,最后找到了一篇很好很详细的证明过程,摘抄整理为 latex 如下. (原文:https://blog.csdn.net/weixin_41718085/a ...

  9. 从 0 开始机器学习 - 神经网络反向 BP 算法!

    最近一个月项目好忙,终于挤出时间把这篇 BP 算法基本思想写完了,公式的推导放到下一篇讲吧. 一.神经网络的代价函数 神经网络可以看做是复杂逻辑回归的组合,因此与其类似,我们训练神经网络也要定义代价函 ...

  10. 误差逆传播(error BackPropagation, BP)算法推导及向量化表示

    1.前言 看完讲卷积神经网络基础讲得非常好的cs231后总感觉不过瘾,主要原因在于虽然知道了卷积神经网络的计算过程和基本结构,但还是无法透彻理解卷积神经网络的学习过程.于是找来了进阶的教材Notes ...

随机推荐

  1. 越“挖”越有料,天翼云“息壤”助攻DeepSeek变身万能搭子!

    还在为DeepSeek服务器繁忙而抓狂? 还在为API调用费用涨价而头疼? 还在为数据安全而担忧? 别急! 天翼云"息壤"算力互联调度平台出马 全面解锁DeepSeek新玩法 带你 ...

  2. 【H2O系列】包括人形机器人WBC相关论文小结

    1. 前言 这篇博客主要用于记录包括人形机器人WBC或locomotion相关论文小结. 一方面便于日后自己的温故学习,另一方面也便于大家的学习和交流. 如有不对之处,欢迎评论区指出错误,你我共同进步 ...

  3. 给大模型添加联网功能的免费方案,以langchain为例

    langchain介绍 LangChain 是一个用于开发由大型语言模型 (LLM) 驱动的应用程序的框架. 简单来说,它可以帮助你更轻松地构建利用 LLM(例如 OpenAI 的 GPT 模型.Go ...

  4. Docker应用部署(Mysql、tomcat、Redis、redis)

    Docker应用部署mysql5.7 1.拉取镜像 docker pull mysql:5.7 2.查看镜像 docker images 3.创建容器 docker run -id \ -p 3307 ...

  5. P5356 [Ynoi Easy Round 2017] 由乃打扑克

    分块典题 左转数列分块入门2 一样的想法 排序+二分 但是发现我们只能求排名 于是二分答案然后分块+二分即可

  6. ABAQUS 中的一些约定

    目录 自由度notation Axisymmetric elements Activation of degrees of freedom Internal variables in Abaqus/S ...

  7. Anoii之UDP与多路复用

    代码连接:https://github.com/Afeather2017/anoii/blob/master/src/udp_peer.cc 以往写了TCP的多路复用,发现它还挺难写对的.现在写UDP ...

  8. DeepSeek+Claude强强联手,使用AI驱动DjangoStarter 3.1框架升级

    前言 上个月底培训了一周就没时间更新博客 上周有一些空闲时间,就继续体验最近很火的AI辅助编程 之前的文章中有说到我配置好了 VSCode + Cline 插件搭配本地部署的 DeepSeek 来实现 ...

  9. 搭建自己的OCR服务,第三步:PPOCRLabel标注工具安装

    一.安装说明 安装好了PaddleOCR后,还需要安装PPOCRLabel这个标注工具,想要自己训练模型的话,有个标注工具会起很大作用. 尤其是PPOCRLabel就是跟PaddleOCR配套的标注工 ...

  10. "油猴脚本""篡改猴"领域的一些基本常识

    本文简要介绍本人对"油猴脚本","篡改猴"领域的一些见解,内容注定不可能一步到位和事无巨细,欢迎各位仁人志士对我批评指正,提出意见建议.另外转载前请务必注明作者 ...