这是一篇来自于旧站的重置文章。
前言
其实这个很早之前就想做了,很久之前做过一个《[人工智能] 反向传播BP算法+用Excel写一个二层神经网络怎么破》,但是,由于当时学术造诣不深,也只做了一个不完全的Regression(回归),这里想要把整篇文章完善一下。
而且当时也没有用到Markdown自带的公式,类似:$$MSE = \frac{1}{2}(y - y_{true})^{2}$$
所以,这次打算更加完善的做完这一篇文章。
现在已经转入了 更高级的系统。
这次,终于可以更加完善中的完善做完这一篇文章了。
正文
1. Regression(回归)
1.1 基本要素
flowchart LR
subgraph Input[输入]
X1[x_1]
X2[x_2]
end
subgraph Hidden[隐藏层: 线性]
H1[h1 = x_1 * w_11 + x_2 * w_21]
H2[h2 = x_1 * w_12 + x_2 * w_22]
end
subgraph Output[输出层: 线性]
Y[y = w_3 * h_1 + w_4 * h_2]
end
X1 -->|w_11| H1
X2 -->|w_21| H1
X1 -->|w_12| H2
X2 -->|w_22| H2
H1 -->|w_3| Y
H2 -->|w_4| Y
我们这里先介绍一下回归的NN流程,我们的基础元素如下:
输入层: x_{1}, x_{2}
隐藏层:h1 = x_{1}w_{1,1} + x_{2}w_{2,1}, h2=x_{1}w_{1,2} + x_{2}w_{2,2}
输出层: y = w_{3}h_{1} + w_{4}h_{2}
Loss(回归问题我们使用MSE):
对于单个样本:
loss = \frac{1}{2}(y-y_{true})^2
(这里的 \frac{1}{2}是为了梯度好看,不影响最终的结果)
1.2 前向传递
我们通过单个样本 [x_{1}, x_{2}] 传入得到 h1 = x_{1}w_{1,1} + x_{2}w_{2,1}, h2=x_{1}w_{1,2} + x_{2}w_{2,2},最终得到 y = w_{3}h_{1} + w_{4}h_{2},然后通过MSE计算得到 loss = \frac{1}{2}(y-y_{true})^2。
1.3 反向传递
1.3.1 梯度更新方向
我们现在需要做的是,通过 loss 去计算需要对 w_{i,j} 进行多少的更新,但是我们该如何去设计这样一个更新呢?
最直接的一个方法就是:对loss 求偏导,然后按反方向更新w_{i,j} 。
但是为什么这样能够让预测更接近真实呢?
直觉解释(“下山找谷底”)
loss是一个函数:
L(w)=神经网络输出与真实的差
它是一个关于 w 和 x 的函数,因为不同的 w 和 x 会导致不同的输出, 从而导致不同的 loss。求导 \frac{dloss}{dw}, \frac{\partial{loss}}{\partial{w}} 具有一个很重要的数学性质
梯度方向是函数值增长最快的方向
所以,对求导出来的\frac{dloss}{dw}, \frac{\partial{loss}}{\partial{w}} 取负数,那么就是函数值减少的最快方向。这种直觉解释可以理解为所谓的“下山找谷底”、“摸黑下山”,我们顺着loss减少的方向,迟早能找到一个(局部loss)最小值的点,这个点的意思就是“在这个点,神经网络输出与真实的差最小”,也就是我们想要找到的点。
数学解释(泰勒展开)
其实这个也能通过泰勒展开来解释。
假设loss在某个 w 附近可以近似为(如果 \eta足够小,仅考虑一阶泰勒展开):
L(w + \Delta w) \approx L(w) + \frac{\partial{L}}{\partial{w}} \Delta w
如果我们选择:
\Delta w = - \eta \frac{\partial{L}}{\partial{w}}
那么:
L(w + \Delta w) \approx L(w) - \eta (\frac{\partial{L}}{\partial{w}})^2
那么平方永远非负,这保证了如果学习率\eta足够小,那么loss就能够保证永远往减小的方向进行。
1.3.2 梯度更新计算
在证明了我们的梯度更新方向之后,我们就可以知道我们该怎么做了:我们需要往 -\frac{\partial{loss}}{\partial{w}} 方向更新:
w \leftarrow w - \eta \frac{\partial{loss}}{\partial{w}}
其中 \eta为学习率。
那么我们要怎么计算 \frac{\partial{loss}}{\partial{w}}呢?我们需要用到一些数学的方法:
\frac{\partial{loss}}{\partial{w}} = \frac{\partial{loss}}{\partial{y}} \cdot \frac{\partial{y}}{\partial{w}}
上面的 \frac{\partial{loss}}{\partial{y}} 和 \frac{\partial{y}}{\partial{w}} 我们是都可以计算的,那么这样,我们就可以反向更新了。
1.3.3 更新 w_{3}, w_{4}
我们根据以下公式:
\begin{aligned}
&\frac{\partial{loss}}{\partial{w_3}} = \frac{\partial{loss}}{\partial{y}} \cdot \frac{\partial{y}}{\partial{w_3}} \\
&\frac{\partial{loss}}{\partial{w_4}} = \frac{\partial{loss}}{\partial{y}} \cdot \frac{\partial{y}}{\partial{w_4}}
\end{aligned}
由于:
\begin{aligned}
&loss = \frac{1}{2}(y-y_{true})^2 \\
&y = w_3h_1 + w_4h_2 \\
&h_1 = x_1w_{1,1} + x_2w_{2,1} \\
&h_2 = x_1w_{1,2} + x_2w_{2,2}
\end{aligned}
我们可以得到
\begin{aligned}
&\frac{\partial{loss}}{\partial{y}} = y - y_{true} \\
&\frac{\partial{y}}{\partial{w_3}} = h_1 \\
&\frac{\partial{y}}{\partial{w_4}} = h_2
\end{aligned}
最终,我们可以得到:
\begin{aligned}
&\frac{\partial{loss}}{\partial{w_3}} = (y - y_{true}) \cdot h_1 = (y - y_{true}) \cdot (x_1w_{1,1} + x_2w_{2,1}) \\
&\frac{\partial{loss}}{\partial{w_4}} = (y - y_{true}) \cdot h_2 = (y - y_{true}) \cdot (x_1w_{1,2} + x_2w_{2,2})
\end{aligned}
其中,所有的变量我们都有值,我们可以计算出来 \frac{\partial{loss}}{\partial{w_3}}, \frac{\partial{loss}}{\partial{w_4}}:
\begin{aligned}
&w_3' = w_3 - \eta \cdot (y - y_{true}) \cdot (x_1w_{1,1} + x_2w_{2,1}) \\
&w_4' = w_4 - \eta \cdot (y - y_{true}) \cdot (x_1w_{1,2} + x_2w_{2,2})
\end{aligned}
现在,我们更新了这一层的,可以返回更新上一层的了(这也是为什么称之为反向传递更新的原因。)
1.3.4 更新 w_{1,1}, w_{1,2}, w_{2,1}, w_{2,2}
flowchart LR
%% ==== 节点定义 ====
X1["x1"]
X2["x2"]
W11["w11"]
W21["w21"]
W12["w12"]
W22["w22"]
W3["w3"]
W4["w4"]
H1["h1 = x1·w11 + x2·w21"]
H2["h2 = x1·w12 + x2·w22"]
Y["y = w3·h1 + w4·h2"]
Ytrue["y_true"]
L["loss = 0.5·(y − y_true)²"]
%% ==== 前向 ====
X1 --> H1
X2 --> H1
X1 --> H2
X2 --> H2
W11 --> H1
W21 --> H1
W12 --> H2
W22 --> H2
H1 --> Y
H2 --> Y
W3 --> Y
W4 --> Y
Y --> L
Ytrue --> L
%% ==== 反向(虚线 + 标签) ====
L -.->|∂L/∂y = y − y_true| Y
Y -.->|"∂L/∂w3 = (y − y_true)·h1"| W3
Y -.->|"∂L/∂w4 = (y − y_true)·h2"| W4
Y -.->|"∂L/∂h1 = (y − y_true)·w3"| H1
Y -.->|"∂L/∂h2 = (y − y_true)·w4"| H2
H1 -.->|"∂L/∂w11 = (y − y_true)·w3·x1"| W11
H1 -.->|"∂L/∂w21 = (y − y_true)·w3·x2"| W21
H2 -.->|"∂L/∂w12 = (y − y_true)·w4·x1"| W12
H2 -.->|"∂L/∂w22 = (y − y_true)·w4·x2"| W22
2. Classification(分类)
总结
参考
[1] 自己
[2] ChatGPT
[3] [人工智能] 反向传播BP算法+用Excel写一个二层神经网络怎么破