当前位置: 首页 > news >正文

神经网络中的微分计算与反向传播实现

1. 神经网络中的微分基础

微分计算是机器学习算法中的重要工具。在神经网络中,梯度下降算法依赖于梯度,这个量就是通过微分计算得到的。理解微分在神经网络中的应用,对于掌握深度学习至关重要。

1.1 全微分与全导数

对于单变量函数f(x),我们用f'(x)或df/dx表示其导数。但对于多变量函数f(u,v),我们有关于u的偏导数∂f/∂u(有时也写作f_u)。偏导数是假设其他变量(如v)为常数时,f对u的导数。

当u和v本身也是x的函数时,即f(u(x),v(x)),我们可以求f对x的全导数。对于更一般的多元函数f(t,u,v)=f(t(x),u(x),v(x)),全导数的计算公式为:

$$ \frac{df}{dx} = \frac{\partial f}{\partial t}\frac{dt}{dx} + \frac{\partial f}{\partial u}\frac{du}{dx} + \frac{\partial f}{\partial v}\frac{dv}{dx} $$

这个公式实际上是链式法则的应用。如果去掉dx部分,我们得到的就是全微分:

$$ df = \frac{\partial f}{\partial t}dt + \frac{\partial f}{\partial u}du + \frac{\partial f}{\partial v}dv $$

1.2 多层感知机的代数表示

考虑一个简单的4层全连接神经网络:

  • 输入层(第0层):3个单元
  • 第一个隐藏层(第1层):4个单元
  • 第二个隐藏层(第2层):2个单元
  • 输出层(第3层):2个单元

用数学表达式表示这个网络:

$$ \begin{aligned} h_{1i} &= f_1(\sum_{j=1}^{n_0} w^{(1)}{ij} x_j + b^{(1)}i) & \text{for } i &= 1,\cdots,n_1\ h{2i} &= f_2(\sum{j=1}^{n_1} w^{(2)}{ij} h{1j} + b^{(2)}i) & i &= 1,\cdots,n_2\ \hat{y}i &= f_3(\sum{j=1}^{n_2} w^{(3)}{ij} h_{2j} + b^{(3)}_i) & i &= 1,\cdots,n_3 \end{aligned} $$

其中:

  • $f_i$是第i层的激活函数
  • $h_{ki}$是第k层第i个单元的输出
  • $w^{(k)}_{ij}$和$b^{(k)}_i$分别是第k层的权重和偏置

对于回归问题,常用的损失函数是均方误差:

$$ L = \sum_{i=1}^{n_3} (y_i-\hat{y}_i)^2 $$

2. 反向传播求梯度

2.1 梯度下降更新规则

训练神经网络的目标是通过梯度下降更新权重和偏置:

$$ \begin{aligned} w^{(k)}{ij} &= w^{(k)}{ij} - \eta \frac{\partial L}{\partial w^{(k)}{ij}} \ b^{(k)}{i} &= b^{(k)}{i} - \eta \frac{\partial L}{\partial b^{(k)}{i}} \end{aligned} $$

其中η是学习率。

2.2 输出层的梯度计算

首先计算损失函数对输出的导数:

$$ \begin{aligned} \frac{\partial L}{\partial \hat{y}_i} &= 2(y_i - \hat{y}_i) & \text{for } i &= 1,\cdots,n_3 \end{aligned} $$

然后计算输出层的权重和偏置梯度:

$$ \begin{aligned} \frac{\partial L}{\partial w^{(3)}{ij}} &= \frac{\partial L}{\partial \hat{y}i} f'3(\sum{j=1}^{n_2} w^{(3)}{ij} h{2j} + b^{(3)}i)h{2j} \ \frac{\partial L}{\partial b^{(3)}i} &= \frac{\partial L}{\partial \hat{y}i}f'3(\sum{j=1}^{n_2} w^{(3)}{ij} h{2j} + b^{(3)}_i) \end{aligned} $$

同时计算对第二层输出的梯度:

$$ \frac{\partial L}{\partial h_{2j}} = \sum_{i=1}^{n_3}\frac{\partial L}{\partial \hat{y}i}f'3(\sum{j=1}^{n_2} w^{(3)}{ij} h_{2j} + b^{(3)}i)w^{(3)}{ij} $$

2.3 隐藏层的梯度计算

对于第二隐藏层:

$$ \begin{aligned} \frac{\partial L}{\partial w^{(2)}{ij}} &= \frac{\partial L}{\partial h{2i}}f'2(\sum{j=1}^{n_1} w^{(2)}{ij} h{1j} + b^{(2)}i)h{1j} \ \frac{\partial L}{\partial b^{(2)}i} &= \frac{\partial L}{\partial h{2i}}f'2(\sum{j=1}^{n_1} w^{(2)}{ij} h{1j} + b^{(2)}i) \ \frac{\partial L}{\partial h{1j}} &= \sum_{i=1}^{n_2}\frac{\partial L}{\partial h_{2i}}f'2(\sum{j=1}^{n_1} w^{(2)}{ij} h{1j} + b^{(2)}i) w^{(2)}{ij} \end{aligned} $$

对于第一隐藏层:

$$ \begin{aligned} \frac{\partial L}{\partial w^{(1)}{ij}} &= \frac{\partial L}{\partial h{1i}}f'1(\sum{j=1}^{n_0} w^{(1)}_{ij} x_j + b^{(1)}i)x_j \ \frac{\partial L}{\partial b^{(1)}i} &= \frac{\partial L}{\partial h{1i}}f'1(\sum{j=1}^{n_0} w^{(1)}{ij} x_j + b^{(1)}_i) \end{aligned} $$

3. 矩阵形式的梯度方程

用矩阵表示可以简化方程:

$$ \mathbf{a}_k = f_k(\mathbf{z}_k) = f_k(\mathbf{W}k\mathbf{a}{k-1}+\mathbf{b}_k) $$

其中$\mathbf{a}_k$是第k层的输出向量,$\mathbf{a}_0=\mathbf{x}$是输入向量,$\mathbf{a}_3=\hat{\mathbf{y}}$是输出向量。令$\mathbf{z}_k = \mathbf{W}k\mathbf{a}{k-1}+\mathbf{b}_k$。

梯度计算可以表示为:

$$ \begin{aligned} \frac{\partial L}{\partial\mathbf{z}_k} &= \frac{\partial L}{\partial\mathbf{a}_k}\odot f_k'(\mathbf{z}_k) \ \frac{\partial L}{\partial\mathbf{W}_k} &= \left(\frac{\partial L}{\partial\mathbf{z}_k}\right)^\top \cdot \mathbf{a}_k \ \frac{\partial L}{\partial\mathbf{b}_k} &= \frac{\partial L}{\partial\mathbf{z}k} \ \frac{\partial L}{\partial\mathbf{a}{k-1}} &= \mathbf{W}_k^\top\cdot\frac{\partial L}{\partial\mathbf{z}_k} \end{aligned} $$

4. 反向传播的实现

4.1 激活函数和损失函数

首先实现常用的激活函数及其导数:

import numpy as np # Sigmoid函数及其导数 def sigmoid(z): return 1/(1+np.exp(-z.clip(-500, 500))) def dsigmoid(z): s = sigmoid(z) return s * (1-s) # ReLU函数及其导数 def relu(z): return np.maximum(0, z) def drelu(z): return (z > 0).astype(float) # 交叉熵损失函数及其导数 def cross_entropy(y, yhat): epsilon = np.finfo(float).eps return -(y.T @ np.log(yhat.clip(epsilon)) + (1-y.T) @ np.log((1-yhat).clip(epsilon))) / y.shape[1] def d_cross_entropy(y, yhat): epsilon = np.finfo(float).eps return - np.divide(y, yhat.clip(epsilon)) + np.divide(1-y, (1-yhat).clip(epsilon))

4.2 多层感知机类实现

class MLP: def __init__(self, layersizes, activations, derivatives, lossderiv): self.layersizes = layersizes self.activations = activations self.derivatives = derivatives self.lossderiv = lossderiv # 初始化参数 L = len(self.layersizes) self.z = [None] * L self.W = [None] * L self.b = [None] * L self.a = [None] * L self.dz = [None] * L self.dW = [None] * L self.db = [None] * L self.da = [None] * L def initialize(self, seed=42): np.random.seed(seed) sigma = 0.1 for l, (insize, outsize) in enumerate(zip(self.layersizes, self.layersizes[1:]), 1): self.W[l] = np.random.randn(insize, outsize) * sigma self.b[l] = np.random.randn(1, outsize) * sigma def forward(self, x): self.a[0] = x for l, func in enumerate(self.activations, 1): self.z[l] = self.a[l-1] @ self.W[l] + self.b[l] self.a[l] = func(self.z[l]) return self.a[-1] def backward(self, y, yhat): self.da[-1] = self.lossderiv(y, yhat) for l, func in reversed(list(enumerate(self.derivatives, 1))): self.dz[l] = self.da[l] * func(self.z[l]) self.dW[l] = self.a[l-1].T @ self.dz[l] self.db[l] = np.mean(self.dz[l], axis=0, keepdims=True) self.da[l-1] = self.dz[l] @ self.W[l].T def update(self, eta): for l in range(1, len(self.W)): self.W[l] -= eta * self.dW[l] self.b[l] -= eta * self.db[l]

4.3 训练神经网络

使用scikit-learn生成数据并训练网络:

from sklearn.datasets import make_circles from sklearn.metrics import accuracy_score # 生成数据 X, y = make_circles(n_samples=1000, factor=0.5, noise=0.1) y = y.reshape(-1,1) # 构建模型 model = MLP(layersizes=[2, 4, 3, 1], activations=[relu, relu, sigmoid], derivatives=[drelu, drelu, dsigmoid], lossderiv=d_cross_entropy) model.initialize() # 训练前评估 yhat = model.forward(X) print("Before training - loss:", cross_entropy(y, yhat), "accuracy:", accuracy_score(y, yhat > 0.5)) # 训练 n_epochs = 150 learning_rate = 0.005 for n in range(n_epochs): model.forward(X) yhat = model.a[-1] model.backward(y, yhat) model.update(learning_rate) if n % 10 == 0: print(f"Iteration {n} - loss: {cross_entropy(y, yhat)[0][0]:.4f}, accuracy: {accuracy_score(y, yhat > 0.5):.4f}")

5. 常见问题与优化技巧

5.1 梯度消失与爆炸

在深层网络中,梯度可能在反向传播过程中变得非常小(消失)或非常大(爆炸)。这会导致训练困难。解决方法包括:

  • 使用合适的激活函数(如ReLU)
  • 使用批归一化(Batch Normalization)
  • 使用残差连接(Residual Connections)

5.2 学习率选择

学习率太大可能导致震荡,太小则收敛缓慢。可以尝试:

  • 学习率衰减策略
  • 自适应优化器(如Adam)
  • 学习率预热(Learning Rate Warmup)

5.3 初始化技巧

权重初始化对训练至关重要。常用的方法有:

  • Xavier/Glorot初始化(适合sigmoid/tanh)
  • He初始化(适合ReLU及其变体)
  • 正交初始化

5.4 正则化技术

防止过拟合的方法包括:

  • L1/L2权重正则化
  • Dropout
  • 早停(Early Stopping)
  • 数据增强

6. 实际应用中的注意事项

  1. 数值稳定性:在实现激活函数如sigmoid时,要注意数值溢出问题。例如,对大的负输入进行指数运算可能导致下溢。

  2. 批量处理:在实际应用中,通常会使用小批量(mini-batch)而不是全批量训练,这需要在反向传播时正确计算平均梯度。

  3. 参数更新:更先进的优化器(如Adam)通常比普通梯度下降表现更好,可以考虑实现这些优化器。

  4. GPU加速:对于大型网络,可以考虑使用GPU加速计算,这需要将numpy数组转换为支持GPU的张量(如PyTorch或TensorFlow中的张量)。

  5. 调试技巧:可以通过梯度检查(比较解析梯度和数值梯度)来验证反向传播的实现是否正确。

通过理解微分在神经网络中的应用,并正确实现反向传播算法,我们可以有效地训练各种深度的神经网络模型。虽然现代深度学习框架已经自动实现了这些功能,但理解底层原理对于调试模型和开发新算法至关重要。

http://www.jsqmd.com/news/711187/

相关文章:

  • DLSS Swapper完整指南:免费一键提升游戏画质与性能的终极解决方案
  • 如何用CefFlashBrowser在2026年继续畅玩经典Flash游戏:完整指南
  • 数据库慢查询日志分析实战
  • 如何用XXMI启动器一站式管理6款热门二次元游戏模组:终极模组管理解决方案
  • Mermaid Live Editor:通过代码化图表提升技术文档效率的终极解决方案
  • SI-Core多智能体身份管理框架解析与应用
  • FlicFlac音频转换工具架构深度解析:轻量级设计与企业级应用实践
  • 华硕笔记本性能革命:G-Helper轻量级控制工具深度评测
  • 一键批量下载网易云音乐无损FLAC歌曲:Golang高效解决方案
  • DevEco Studio:多端设备预览
  • AI交互安全审计:Clawdbot系统设计与实践
  • 【VS Code Copilot Next 工作流配置终极指南】:20年DevOps专家亲授5大高频报错的根因定位与秒级修复法
  • 告别手动刷视频:用 AI 一键采集 TikTok 爆款并自动拆解爆款逻辑的实战指南
  • 扩散模型中的理想轨迹与OOD问题解析
  • AI驱动的基础设施即代码生成:aiac工具实战指南与DevOps效率革命
  • 9字重开源字体Outfit:为现代设计系统注入品牌灵魂
  • Java 反射性能优化技巧
  • 我们看一份报告的时候主要看什么
  • 2026年4月新发布:温州专业二手注塑机供应厂家深度**与**推荐 - 2026年企业推荐榜
  • 从原理到部署:手把手教你用DINOv2-base搭建一个本地图片搜索引擎(附完整代码)
  • 大语言模型认知行为与元推理技术研究
  • 国产替代实战系列(一):商业论证——在 Vibe Coding 时代,重估国产化的“入场券”
  • 物联网设备加密算法选型决策树(支持LoRaWAN/NB-IoT/Thread协议栈,兼容ARM Cortex-M0+/RISC-V 32位平台)
  • 终极英雄联盟助手:如何用Akari工具包轻松提升你的游戏水平
  • 2026年4月车载动力电池加热膜选型指南:新沂地区优质厂商深度剖析 - 2026年企业推荐榜
  • Stable Diffusion WebUI Forge完整入门指南:打造你的AI绘画工作室终极方案 [特殊字符]
  • 扩散模型评估:挑战与标准化实践
  • 从农历生日提醒到星座运势:用sxtwl和Python打造你的个人日历自动化系统
  • 2026年4月新消息:广州商品房买卖纠纷律师选择指南与专业推荐 - 2026年企业推荐榜
  • 国产替代实战系列(二):模型移植——如何通过 ONNX 优雅地跨越“CUDA 之墙”?