掘金 人工智能 07月08日 11:34
硬核拆解!跟着公式“走”一遍,你也能彻底看懂神经网络
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文从概率模型的视角出发,深入探讨了神经网络的本质。文章通过构建一个简单的神经网络,详细阐述了前向传播、损失函数计算和反向传播等关键步骤。结合具体的数值计算,清晰地展示了模型如何根据误差调整参数,最终实现对输入数据的分类。通过对神经网络内部运作机制的剖析,帮助读者理解其与概率模型及现实世界的紧密联系,为理解AI的底层逻辑提供了新的视角。

🧠 神经网络的核心在于其与概率模型的紧密联系,现实世界的不确定性本身就是一个天然的概率模型。

⚙️ 前向传播是数据从输入层到输出层的过程,包括隐含层和输出层的计算,其中激活函数和Softmax函数用于处理非线性变换和概率分布。

💔 交叉熵损失函数用于衡量模型预测与真实标签之间的差距,其梯度陡峭的特性加速了模型的收敛。

🔄 反向传播通过链式法则计算各层参数的梯度,从而指导模型参数的更新,是训练神经网络的核心。

引言:从概率视角看AI的本质

在探索神经网络奥秘的旅程中,我们不得不先审视一个深刻的认知:无论是当下令人瞩目的生成式 AI,还是朝着通用人工智能(AGI)迈进的探索,本质上都与“概率模型”紧密相连。从单纯的概率框架出发,现实世界复杂事件的联合分布可被统一表征,而神经网络的非线性拟合能力,又依托通用逼近定理、柯尔莫哥洛夫理论等数学基石。信息论中“压缩即智能”的理念,更是为我们理解 AI 如何从海量数据中提炼规律、模拟智能提供了独特视角。

值得深思的是,我们所处的现实世界本身就充满不确定性,是天然的概率模型,可人们往往追求确定性。这种思维转变,对深入理解 AI 本质与大模型运行逻辑,有着至关重要的意义。为了具体地理解这一过程,就让我们一同拆解一个简单的神经网络,探寻其与概率模型、现实世界的交织脉络。

神经网络如下图所示:

一、 网络结构与初始化

1. 网络结构

关于权重矩阵维度的说明:例如,W(1)\mathbf{W}^{(1)} 连接第1层(3个神经元)和第2层(2个神经元),其维度为 2x3。这保证了 W(1)a(1)+b(1)\mathbf{W}^{(1)} \mathbf{a}^{(1)} + \mathbf{b}^{(1)} 的矩阵乘法能够顺利进行。

2. 参数初始化

在训练初始,我们可随机初始化参数。为方便演示和复现,这里我们直接给出一组固定的示例数值。

W(1)=[0.100.200.300.400.500.60],b(1)=[0.100.10]\mathbf{W}^{(1)} = \begin{bmatrix}0.10 & 0.20 & 0.30\\0.40 & 0.50 & 0.60\end{bmatrix}, \quad\mathbf{b}^{(1)} =\begin{bmatrix}0.10 \\0.10\end{bmatrix}
W(2)=[0.700.800.901.001.101.20],b(2)=[0.200.200.20]\mathbf{W}^{(2)} =\begin{bmatrix}0.70 & 0.80\\0.90 & 1.00\\1.10 & 1.20\end{bmatrix},\quad\mathbf{b}^{(2)} =\begin{bmatrix}0.20 \\0.20 \\0.20\end{bmatrix}

二、 前向传播:一步步计算网络输出

前向传播(Forward Propagation)是指数据从输入层流向输出层的过程。

1. 隐含层 (Layer 2) 的计算

首先,计算进入隐含层激活函数前的线性组合 z(2)\mathbf{z}^{(2)}

z(2)=W(1)a(1)+b(1)\mathbf{z}^{(2)} = \mathbf{W}^{(1)} \mathbf{a}^{(1)} + \mathbf{b}^{(1)}

由于 W(1)\mathbf{W}^{(1)}2×32 \times 3a(1)\mathbf{a}^{(1)}3×13 \times 1b(1)\mathbf{b}^{(1)}2×12 \times 1,所以

z(2)=[0.100.200.300.400.500.60][1.01.01.0]+[0.100.10]=[(0.10+0.20+0.30)+0.10(0.40+0.50+0.60)+0.10]=[0.701.60]\begin{align}&\mathbf{z}^{(2)} =\begin{bmatrix}0.10 & 0.20 & 0.30\\0.40 & 0.50 & 0.60\end{bmatrix}\begin{bmatrix}1.0 \\1.0 \\1.0\end{bmatrix}+\begin{bmatrix}0.10 \\0.10\end{bmatrix}= \\&\begin{bmatrix}(0.10 + 0.20 + 0.30) + 0.10 \\(0.40 + 0.50 + 0.60) + 0.10\end{bmatrix}=\begin{bmatrix}0.70 \\1.60\end{bmatrix}\end{align}

然后,将 z(2)\mathbf{z}^{(2)} 通过 Sigmoid 激活函数,得到隐含层的输出 a(2)\mathbf{a}^{(2)}

a(2)=σ(z(2)),σ(x)=11+ex\mathbf{a}^{(2)} = \sigma\bigl(\mathbf{z}^{(2)}\bigr),\quad\sigma(x) = \frac{1}{1 + e^{-x}}

对应分量:

a1(2)=11+e0.700.66818777,a2(2)=11+e1.600.83201839\begin{align} &a_1^{(2)} = \frac{1}{1 + e^{-0.70}} \approx 0.66818777,\quad \\&a_2^{(2)} = \frac{1}{1 + e^{-1.60}} \approx 0.83201839\end{align}

故:

a(2)[0.668187770.83201839]\mathbf{a}^{(2)} \approx\begin{bmatrix}0.66818777 \\0.83201839\end{bmatrix}

核心概念:

    z通常表示某一层线性计算(权重乘法和偏置加法)的结果。a通常表示 z经过激活函数后的输出,它将作为下一层的输入。

2. 输出层 (Layer 3) 的计算

接下来,用隐含层的输出 a(2)\mathbf{a}^{(2)} 计算输出层的线性组合 z(3)\mathbf{z}^{(3)},也称为 logits

z(3)=W(2)a(2)+b(2)\mathbf{z}^{(3)} = \mathbf{W}^{(2)}\, \mathbf{a}^{(2)} + \mathbf{b}^{(2)}

然后,对 logits z(3)\mathbf{z}^{(3)} 应用 Softmax 函数,得到最终的概率分布输出 a(3)\mathbf{a}^{(3)}。其中 W(2)\mathbf{W}^{(2)}3×23 \times 2a(2)\mathbf{a}^{(2)}2×12 \times 1b(2)\mathbf{b}^{(2)}3×13 \times 1。数值计算如下:

z(3)=[0.700.800.901.001.101.20][0.668187770.83201839]+[0.200.200.20]=[0.70×0.66818777+0.80×0.832018390.90×0.66818777+1.00×0.832018391.10×0.66818777+1.20×0.83201839]+[0.200.200.20][1.333346151.633387381.93240000]\begin{aligned}\mathbf{z}^{(3)} &=\begin{bmatrix}0.70 & 0.80\\0.90 & 1.00\\1.10 & 1.20\end{bmatrix}\begin{bmatrix}0.66818777 \\0.83201839\end{bmatrix}+\begin{bmatrix}0.20 \\0.20 \\0.20\end{bmatrix}\\&=\begin{bmatrix}0.70 \times 0.66818777 + 0.80 \times 0.83201839\\0.90 \times 0.66818777 + 1.00 \times 0.83201839\\1.10 \times 0.66818777 + 1.20 \times 0.83201839\end{bmatrix}+\begin{bmatrix}0.20\\0.20\\0.20\end{bmatrix}\\&\approx\begin{bmatrix}1.33334615 \\1.63338738 \\1.93240000\end{bmatrix}\end{aligned}

然后对 logits 做 Softmax 得到输出层的激活 a(3)\mathbf{a}^{(3)}:

ai(3)=ezi(3)jezj(3)a_i^{(3)} = \frac{e^{z_i^{(3)}}}{\sum_j e^{z_j^{(3)}}}

分母是 e1.3333+e1.6334+e1.9324e^{1.3333} + e^{1.6334} + e^{1.9324}。我们分别计算 (取近似):

a(3)[0.23970.32360.4367]\mathbf{a}^{(3)} \approx\begin{bmatrix}0.2397 \\0.3236 \\0.4367\end{bmatrix}

至此,一次完整的前向传播完成。我们得到了模型对输入样本的预测概率分布。

三、 损失函数:衡量预测与现实的差距

我们使用交叉熵损失 (Cross-Entropy Loss) 来衡量模型预测 a(3)\mathbf{a}^{(3)} 与真实标签 t 之间的差距。

为什么选择交叉熵?在像大语言模型这样的现代分类任务中,交叉熵是首选损失函数。当预测概率偏离真实标签(概率为1)时,它会产生一个非常大的损失值(梯度很陡),这能更高效地指导模型参数更新,从而加快收敛速度。相比之下,均方差(MSE)在分类问题中容易出现梯度消失,导致训练缓慢。

假设我们的真实标签是类别 1,其 one-hot 编码为 t=[1,0,0]T\mathbf{t} = [1,\, 0,\, 0]^T交叉熵损失 (Cross-Entropy) 定义为:

L=itiln(ai(3))L = -\sum_{i} t_i \ln(a_i^{(3)})

在本例中,只有 t1=1t_1=1,其余为 0,因此

a(3)[0.23970.32360.4367]L=(t1ln(a1(3))+t2ln(a2(3))+t3ln(a3(3)))L=(1ln(0.2397)+0ln(0.3236)+0ln(0.4367))L=ln(a1(3))=ln(0.2397)1.434\begin{align} &\mathbf{a}^{(3)} \approx\begin{bmatrix}0.2397 \\0.3236 \\0.4367\end{bmatrix} \\& L = - (t_1 * ln(a^{(3)}_1) + t_2 * ln(a^{(3)}_2) + t_3 * ln(a^{(3)}_3)) \\&L = - (1 * ln(0.2397) + 0 * ln(0.3236) + 0 * ln(0.4367)) \\&L = - \ln(a_1^{(3)}) = - \ln(0.2397) \approx 1.434 \\\end{align}

计算得到的损失 L ≈ 1.434。这个值表示当前模型预测的“错误程度”,我们的目标就是通过调整权重和偏置来让这个值变得尽可能小。

注意:以上是单个样本的损失。在实际训练中,通常会计算一个批次(mini-batch)中所有样本的平均损失,然后根据这个平均损失进行一次反向传播。

四、 反向传播:误差的逐层归因

反向传播(Backpropagation)是训练神经网络的核心。它通过链式法则,将输出层的总损失(误差)逐层向后传递,并计算出每一层参数(权重和偏置)对总损失应负的“责任”,即梯度

1. 输出层的梯度

首先计算损失 L 对输出层线性组合 z(3)\mathbf{z}^{(3)} 的梯度,我们称之为误差 δ(3)δ^{(3)}。对于 Softmax + 交叉熵的组合,这个梯度有一个非常简洁的“黄金公式”:

δ(3)=Lz3=a(3)t\delta^{(3)} = \frac{∂L}{∂z_{3}}=\mathbf{a}^{(3)} - \mathbf{t}

这个公式的美妙之处在于它直接将模型的预测 a(3)\mathbf{a}^{(3)} 和真实标签 t联系起来,其差值即为输出层的误差。我们给出这个公式简单的推导过程 [公式推导](神经网络误差和梯度公式推导本文推导了神经网络中输出误差和权重梯度的计算公式。首先通过链式法则推导了输出误差δ^(3),在 - 掘金)

下面我们根据给出的数值做出计算如下:

=a(3)t=[0.239710.323600.43670]=[0.76030.32360.4367]= \mathbf{a}^{(3)} - \mathbf{t}= \begin{bmatrix}0.2397 - 1 \\0.3236 - 0 \\0.4367 - 0\end{bmatrix}=\begin{bmatrix}-0.7603 \\0.3236 \\0.4367\end{bmatrix}

接下来,我们利用这个误差 δ(3)δ^{(3)} 计算输出层参数 w(2)w^{(2)}b(2)b^{(2)} 的梯度。

1.1 权重梯度

W(2)L=δ(3)(a(2))T\nabla_{\mathbf{W}^{(2)}} L = \delta^{(3)} \cdot (\mathbf{a}^{(2)})^T

权重梯度公式推导:[公式推导](神经网络误差和梯度公式推导本文推导了神经网络中输出误差和权重梯度的计算公式。首先通过链式法则推导了输出误差δ^(3),在 - 掘金)

根据给定的数值计算如下:

δ(3)=[0.76030.32360.4367],a(2)=[0.668187770.83201839]\delta^{(3)} =\begin{bmatrix}-0.7603\\0.3236\\0.4367\end{bmatrix}, \quad\mathbf{a}^{(2)} =\begin{bmatrix}0.66818777\\0.83201839\end{bmatrix}

(a(2))T=[0.66818777,0.83201839](a^{(2)})^T=[0.66818777,0.83201839]所以:

W(2)L=[0.7603×0.668187770.7603×0.83201839 0.3236×0.66818777 0.3236×0.83201839 0.4367×0.66818777 0.4367×0.83201839][0.508,0.6330.216,0.2690.292,0.364]\begin{align} \nabla_{\mathbf{W}^{(2)}} L &=\begin{bmatrix}-0.7603 \times 0.66818777 & -0.7603 \times 0.83201839\\\ 0.3236 \times 0.66818777 & \ 0.3236 \times 0.83201839\\\ 0.4367 \times 0.66818777 & \ 0.4367 \times 0.83201839\end{bmatrix} \\&\approx \begin{bmatrix} -0.508,\, -0.633 \\0.216,\, 0.269 \\0.292,\, 0.364\end{bmatrix}\end{align}

1.2 偏置梯度

偏置 b(2)\mathbf{b}^{(2)} 的梯度计算公式如下:

Lbi(2)=δi(3)\frac{\partial L}{\partial b_i^{(2)}} = \delta_i^{(3)}

即偏置的梯度就是 δ(3)\delta^{(3)} 的各分量。

b(2)L=[0.76030.32360.4367]\nabla_{\mathbf{b}^{(2)}} L = \begin{bmatrix}-0.7603 \\0.3236 \\0.4367\end{bmatrix}

这就是输出层偏置的梯度矩阵。

2. 隐含层的梯度

误差需要从输出层传播回隐含层。隐含层的误差 δ(2)δ^{(2)} 计算如下:隐含层的误差梯度 δ(2)=Lz(2)\delta^{(2)} = \frac{\partial L}{\partial z^{(2)}} 根据链式法则

δ(2)=Lz(3)z(3)a(2)a(2)z(2)\delta^{(2)} = \frac{\partial L}{\partial z^{(3)}} \cdot \frac{\partial z^{(3)}}{\partial a^{(2)}}\cdot \frac{\partial a^{(2)}}{\partial z^{(2)}}

根据 z(3)=W(2).a(2)+b(2)z^{(3)}=W^{(2)}.a^{(2)}+b^{(2)} => z(3)a(2)=(W(2))T\frac{\partial z^{(3)}}{\partial a^{(2)}}=(W^{(2)})^T ,a(2)=σ(z(2))a^{(2)}=\sigma( \mathbf{z}^{(2)} ) => a(2)z(2)=σ(z(2))\frac{\partial a^{(2)}}{\partial z^{(2)}}=\sigma'( \mathbf{z}^{(2)} )δ(3)=Lz(3)\delta^{(3)} = \frac{\partial L}{\partial z^{(3)}}

此神经网络隐含层误差梯度公式变为:

δ(2)=(W(2))Tδ(3)σ(z(2))\delta^{(2)} = \Bigl(\mathbf{W}^{(2)}\Bigr)^T \delta^{(3)} \,\odot\, \sigma'( \mathbf{z}^{(2)} )

公式解读:

    (W(2))Tδ(3)\Bigl(\mathbf{W}^{(2)}\Bigr)^T \delta^{(3)}: 将输出层的误差 δ(3)δ^{(3)} 通过转置后的权重矩阵 W(2)W^{(2)} 反向传播回来,实现了误差的“责任分配”。σ(z(2))\sigma'( \mathbf{z}^{(2)} ): 乘以隐含层激活函数(Sigmoid)的导数。这衡量了隐含层自身输出对误差的敏感度。: 表示 Hadamard 积,即矩阵对应元素逐个相乘。

这说明要计算隐含层的误差 δ(2)δ^{(2)},需要将输出层的误差 δ(3)δ^{(3)} 沿着连接权重 W(2)W^{(2)} 反向传播回来,并考虑隐含层激活函数的导数。这里 \odot 表示按元素逐项相乘 (Hadamard product),σ(z)=σ(z)(1σ(z))\sigma'(z) = \sigma(z)(1 - \sigma(z)) 对应 sigmoid 的导数。这里有一个重要的逻辑就是链式法则反向传播中,梯度需从输出层传递到隐含层,需要符合链式法则的"反向传递”特性,其本质是链式法则中"偏导连乘"在矩阵运算中的维度匹配要求,实现了反向加权,也是标量偏导连乘在高维空间满足维度一致性的必然结果,按元素逐项相乘。还有一点就是当梯度用行向量表示时,矩阵乘法顺序与链式法则书写顺序一致;用列向量时则相反。而深度学习框架中通常默认使用列向量梯度,因此反向传播公式里会出现 “转置矩阵在前” 的现象。

先计算 (W(2))Tδ(3)(\mathbf{W}^{(2)})^T \delta^{(3)}W(2)\mathbf{W}^{(2)}3×23 \times 2,所以其转置是 2×32 \times 3

(W(2))T=[0.700.901.100.801.001.20](\mathbf{W}^{(2)})^T = \begin{bmatrix}0.70 & 0.90 & 1.10\\0.80 & 1.00 & 1.20\end{bmatrix}

δ(3)\delta^{(3)} (大小 3×13\times1) 相乘:

(W(2))Tδ(3)=[0.700.901.100.801.001.20][0.76030.32360.4367](\mathbf{W}^{(2)})^T \delta^{(3)}=\begin{bmatrix}0.70 & 0.90 & 1.10\\0.80 & 1.00 & 1.20\end{bmatrix}\begin{bmatrix}-0.7603\\0.3236\\0.4367\end{bmatrix}

计算:

(W(2))Tδ(3)[0.23940.2394](\mathbf{W}^{(2)})^T \delta^{(3)} \approx\begin{bmatrix}0.2394\\0.2394\end{bmatrix}

再计算 σ(z(2))\sigma'(\mathbf{z}^{(2)}) ,对于 sigmoid:

σ(z)=σ(z)(1σ(z))\sigma'(z) = \sigma(z)\bigl(1 - \sigma(z)\bigr)

前面我们算过:

z(2)[0.701.60],a(2)=σ(z(2))[0.66820.8320]\mathbf{z}^{(2)} \approx\begin{bmatrix}0.70\\1.60\end{bmatrix},\quad\mathbf{a}^{(2)} = \sigma(\mathbf{z}^{(2)}) \approx\begin{bmatrix}0.6682\\0.8320\end{bmatrix}

因此

σ(z1(2))=0.6682×(10.6682)0.6682×0.33180.2218\sigma'(z_1^{(2)}) = 0.6682 \times (1 - 0.6682) \approx 0.6682 \times 0.3318 \approx 0.2218
σ(z2(2))=0.8320×(10.8320)0.8320×0.16800.139776\sigma'(z_2^{(2)}) = 0.8320 \times (1 - 0.8320) \approx 0.8320 \times 0.1680 \approx 0.139776

故:

σ(z(2))[0.22180.1398].\sigma'(\mathbf{z}^{(2)}) \approx\begin{bmatrix}0.2218\\0.1398\end{bmatrix}.
δ(2)=[0.23940.2394][0.22180.1398]=[0.2394×0.22180.2394×0.1398][0.05310.0334].\delta^{(2)} = \begin{bmatrix}0.2394\\0.2394\end{bmatrix}\odot\begin{bmatrix}0.2218\\0.1398\end{bmatrix}=\begin{bmatrix}0.2394 \times 0.2218\\0.2394 \times 0.1398\end{bmatrix}\approx\begin{bmatrix}0.0531\\0.0334\end{bmatrix}.

得到隐含层误差 δ(2)\delta^{(2)} 后,我们用同样的方法计算隐含层参数 W(1)W^{(1)}b(1)b^{(1)} 的梯度。

2.1 权重梯度

与输出层类似,这里也是:

LWij(1)=δi(2)aj(1),\frac{\partial L}{\partial W_{ij}^{(1)}} = \delta_i^{(2)} \cdot a_j^{(1)},

其中 i=1,2i=1,2 表示隐含层第 ii 个神经元,j=1,2,3j=1,2,3 表示输入层第 jj 个神经元。因为 a(1)=[1,1,1]T\mathbf{a}^{(1)} = [1,1,1]^T,所以

W(1)L=δ(2)(a(1))T=[0.05310.0334][111]=[0.05310.05310.05310.03340.03340.0334]\begin{align} \\\nabla_{\mathbf{W}^{(1)}} L &= \delta^{(2)} \cdot (\mathbf{a}^{(1)})^T=\begin{bmatrix}0.0531\\0.0334\end{bmatrix}\begin{bmatrix}1 & 1 & 1\end{bmatrix} \\&=\begin{bmatrix}0.0531 & 0.0531 & 0.0531\\0.0334 & 0.0334 & 0.0334\end{bmatrix}\end{align} \\

2.2 偏置梯度

偏置的梯度:

b(1)L=δ(2)=[0.05310.0334].\nabla_{\mathbf{b}^{(1)}} L = \delta^{(2)}=\begin{bmatrix}0.0531\\0.0334\end{bmatrix}.

五、 参数更新:向正确的方向迈出一步

计算出所有参数的梯度后,我们使用**梯度下降(Gradient Descent)**来更新参数。梯度指明了损失函数上升最快的方向,因此我们沿着梯度的反方向更新参数,就能让损失下降。

更新规则如下,学习率设为 η\eta,则更新规则为:

W(l)W(l)ηW(l)L,b(l)b(l)ηb(l)L.W^{(l)} \leftarrow W^{(l)} - \eta \,\nabla_{W^{(l)}} L, \quadb^{(l)} \leftarrow b^{(l)} - \eta \,\nabla_{b^{(l)}} L.

假设学习率 η=0.1\eta = 0.1,则每个参数都减去 η\eta 乘以对应梯度。例如,更新输出层权重 W(2)\mathbf{W}^{(2)}:

Wij(2)Wij(2)0.1×(W(2)L)ij.W_{ij}^{(2)} \leftarrow W_{ij}^{(2)} - 0.1 \times \bigl(\nabla_{\mathbf{W}^{(2)}} L\bigr)_{ij}.

以第一行(对应输出层第1个神经元)为例:

其他同理。所有 b(2)\mathbf{b}^{(2)}W(1)\mathbf{W}^{(1)}b(1)\mathbf{b}^{(1)} 也依此更新。

六、 训练迭代与代码实现

上述“前向传播 → 计算损失 → 反向传播 → 更新参数”的完整流程构成了一次迭代。在实际训练中,我们会重复这个过程成千上万次(称为 Epochs),直到损失 L 下降到一个足够小的阈值(如 0.01),或者达到预设的最大迭代次数。

Python 代码实现

下面是整个过程的 Python 实现,它完美复现了我们手动计算的每一步。

import numpy as np# ------- 1. 初始化参数 -------np.random.seed(123)  # 可固定随机种子# 这里直接用我们示例中给的固定初始化:W1 = np.array([[0.10, 0.20, 0.30],               [0.40, 0.50, 0.60]], dtype=float)b1 = np.array([[0.10],               [0.10]], dtype=float)W2 = np.array([[0.70, 0.80],               [0.90, 1.00],               [1.10, 1.20]], dtype=float)b2 = np.array([[0.20],               [0.20],               [0.20]], dtype=float)# 学习率eta = 0.1# 训练目标x = np.array([[1.0],              [1.0],              [1.0]])   # 输入 a^(1)t = np.array([[1.0],              [0.0],              [0.0]])   # one-hot 标签def sigmoid(z):    return 1.0 / (1.0 + np.exp(-z))def sigmoid_prime(a):    # a = sigmoid(z), so sigma'(z) = a * (1 - a)    return a * (1.0 - a)def softmax(z):    exp_z = np.exp(z - np.max(z))  # 防止溢出    return exp_z / np.sum(exp_z, axis=0, keepdims=True)def cross_entropy(y, t):    # y, t shape: (3,1)    return -np.sum(t * np.log(y + 1e-12))  # 加一点防止 log(0)# ------- 2. 迭代训练 -------threshold = 0.01epoch = 0max_epoch = 10000  # 防止死循环, 只是示例while True:    epoch += 1    # ----- Forward -----    # Layer 2    z2 = np.dot(W1, x) + b1       # (2,1)    a2 = sigmoid(z2)             # (2,1)    # Layer 3 (output)    z3 = np.dot(W2, a2) + b2      # (3,1)    a3 = softmax(z3)             # (3,1)    # 计算损失    loss = cross_entropy(a3, t)    # 检查是否达到阈值    if loss < threshold or epoch > max_epoch:        print(f"Epoch={epoch}, Loss={loss:.6f}")        break    # ----- Backward -----    # 输出层梯度 delta^(3)    delta3 = a3 - t   # (3,1)    # 输出层参数梯度    dW2 = np.dot(delta3, a2.T)    # (3,2)    db2 = delta3                  # (3,1)    # 传播到隐层    delta2 = np.dot(W2.T, delta3) * sigmoid_prime(a2)  # (2,1)    # 隐层参数梯度    dW1 = np.dot(delta2, x.T)  # (2,3)    db1 = delta2               # (2,1)    # ----- Update -----    W2 -= eta * dW2    b2 -= eta * db2    W1 -= eta * dW1    b1 -= eta * db1    # 可输出观察    if epoch % 500 == 0:        print(f"Epoch={epoch}, Loss={loss:.6f}")print("Training finished!")print("Final parameters:")print("W1 =\n", W1)print("b1 =\n", b1)print("W2 =\n", W2)print("b2 =\n", b2)

七、 总结与要点

以上,我们完整地手动推演并实现了一个神经网络的训练过程。其核心步骤可以总结为:

    前向传播:

      按层计算 z(l)=W(l1)a(l1)+b(l1)z^{(l)} = W^{(l-1)} a^{(l-1)} + b^{(l-1)}激活函数 a(l)=σ(z(l))a^{(l)} = \sigma(z^{(l)}) (本示例隐层用 Sigmoid,输出层用 Softmax)

    损失计算:

      本文示例使用 Softmax + Cross Entropy单个样本 t\mathbf{t} 的交叉熵损失 L=itiln(ai)L = -\sum_i t_i \ln(a_i)

    反向传播:

      对于 Softmax + Cross Entropy,有简洁公式 δ(3)=a(3)t\delta^{(3)} = a^{(3)} - t隐层梯度 δ(2)=(W(2))Tδ(3)σ(z(2))\delta^{(2)} = (W^{(2)})^T \delta^{(3)} \odot \sigma'(z^{(2)})梯度求导 W(l)L=δ(l)(a(l1))T\nabla_{W^{(l)}} L = \delta^{(l)} \cdot (a^{(l-1)})^Tb(l)L=δ(l)\nabla_{b^{(l)}} L = \delta^{(l)}

    更新参数:

      W(l)W(l)ηW(l)LW^{(l)} \leftarrow W^{(l)} - \eta \nabla_{W^{(l)}} Lb(l)b(l)ηb(l)Lb^{(l)} \leftarrow b^{(l)} - \eta \nabla_{b^{(l)}} L

    迭代: 不断重复以上步骤,直至模型收敛。

我们之所以如此枯燥地从头到尾手搓一个神经网络,是希望大家能看到它与概率模型的深度绑定。从现实世界概率本质的映照,到通用逼近定理等理论支撑下的非线性拟合,再到信息论视角下智能与压缩的关联,神经网络一步步揭开了 AI 运行的神秘面纱。

当我们从“追求确定性”的思维转向“拥抱概率不确定性”,不仅是理解 AI 本质的关键,更是未来与大模型协同创新的思想基石。当我们意识到 AI 模型与现实世界皆以概率为底色,便能以更包容、更契合本质的视角,继续探索人工智能的无限可能,让技术在理解不确定性、模拟智能的道路上,走得更远、更深入。

上一篇文章 [从线性到万能近似定理](从线性到万能近似定理在人工智能技术不断颠覆我们生活的今天,从基础算法到前沿模型,背后的数学原理与工程智慧如同精密齿轮,推 - 掘金)

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

神经网络 概率模型 反向传播 深度学习 AI
相关文章