怎么让自己的网站,工程合同承包协议书完整版,asp.net 企业网站系统,建设银行U盾不自己弹网站了文章目录 1. 前言2. 基本概念2.1 一元函数的导数2.2 偏导数2.3 方向导数2.4 梯度2.5 均方误差 3. 梯度下降3.1 梯度下降的公式3.2 梯度下降的类型#xff08;优化器#xff09; 4. 反向传播4.1 反向传播的基本步骤4.2 反向传播的数学推导 5. 实战5.1 手动求导5.2 自动求导5.3… 文章目录 1. 前言2. 基本概念2.1 一元函数的导数2.2 偏导数2.3 方向导数2.4 梯度2.5 均方误差 3. 梯度下降3.1 梯度下降的公式3.2 梯度下降的类型优化器 4. 反向传播4.1 反向传播的基本步骤4.2 反向传播的数学推导 5. 实战5.1 手动求导5.2 自动求导5.3 过程可视化  1. 前言 在深度学习中梯度下降和反向传播是两个至关重要的概念。它们共同作用于优化神经网络使其能够从数据中学习到有用的模式。尽管它们是深度学习的核心但很多人对这两个概念仍然感到困惑。本博客将深入讲解梯度下降和反向传播的基本原理并通过一个简单的示例来加以说明。 
2. 基本概念 
2.1 一元函数的导数 如果有一个函数  f ( x ) f(x) f(x)它的导数  f ′ ( x ) f^′(x) f′(x) 给出了函数在点  x 0 x_0 x0 处沿着  x x x 轴的变化速率即  f ′ ( x 0 )  lim  Δ x → 0 f ( x 0  Δ x ) − f ( x 0 ) Δ x f ^\prime (x_0)  \lim_{\Delta x \to 0} \frac {f(x_0  \Delta x) - f(x_0)} {{\Delta x}} f′(x0)Δx→0limΔxf(x0Δx)−f(x0)  这个导数告诉我们沿着 x x x轴方向函数的变化快慢情况。 
2.2 偏导数 对于多变量函数  f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn)偏导数描述了函数在某一维度即某个变量上变化的速率。例如函数  f ( x , y )  x 2  y 2 f(x, y)  x^2  y^2 f(x,y)x2y2 的偏导数为  ∂ f ∂ x  2 x , ∂ f ∂ y  2 y \frac{\partial f}{\partial x}  2x, \quad \frac{\partial f}{\partial y}  2y ∂x∂f2x,∂y∂f2y  这些偏导数分别表示函数在 x x x轴方向和 y y y轴方向的变化速率。 
2.3 方向导数 描述了一个多变量函数在某一点沿任意给定方向的变化率。对于一个函数  f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn)在点  x 0 \mathbf{x_0} x0 处沿着单位向量  v \mathbf{v} v 方向的方向导数表示为  D v f ( x 0 )  ∇ f ( x 0 ) ⋅ v D_{\mathbf{v}} f(\mathbf{x_0})  \nabla f(\mathbf{x_0}) \cdot \mathbf{v} Dvf(x0)∇f(x0)⋅v其中 ∇ f ( x 0 ) \nabla f(\mathbf{x_0}) ∇f(x0) 是函数在点  x 0 \mathbf{x_0} x0 的梯度。   方向导数的几何意义方向导数给出了函数在某一点沿某个方向的变化速率。它可以看作是沿着某个方向的切线变化率而不仅仅是沿坐标轴的变化率。   即在某一点  x 0 \mathbf{x_0} x0如果我们沿着某个方向  v \mathbf{v} v 走方向导数告诉我们沿着这个方向走时函数值变化的快慢。如果方向导数为正说明函数值在增加如果为负说明函数值在减少如果为零说明函数值在这个方向上没有变化。 
2.4 梯度 在一个多变量的标量函数  f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn) 中梯度是一个向量表示函数在某一点的最速上升方向。梯度不仅告诉我们函数的变化率还告诉我们该变化率最大的方向。具体来说梯度是函数的所有偏导数组成的向量  ∇ f ( x 1 , x 2 , … , x n )  ( ∂ f ∂ x 1 , ∂ f ∂ x 2 , … , ∂ f ∂ x n ) \nabla f(x_1, x_2, \dots, x_n)  \left( \frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \dots, \frac{\partial f}{\partial x_n} \right) ∇f(x1,x2,…,xn)(∂x1∂f,∂x2∂f,…,∂xn∂f)  梯度的方向梯度的方向指向函数值增加最快的方向。   梯度的大小梯度的模长即向量的长度表示沿着这个方向函数变化的速率。 可以把梯度看作是一个“指示器”它告诉我们在某一点函数增长最快的方向。换句话说梯度指向了“上坡”的方向。 2.5 均方误差 均方误差(Mean Squared Error, MSE)是一种常用的衡量模型预测值与实际值之间差异的指标尤其是回归任务中MSE的计算公式如下  M S E  1 n ∑ i  1 n ( y i − y ^ i ) 2 MSE  \frac {1} {n} \sum _{i1} ^ n (y_i - \hat y_i) ^ 2 MSEn1i1∑n(yi−y^i)2其中 n n n是样本数量 y i y_i yi是第 i i i个样本的真实值 y ^ i \hat y_i y^i是模型对第 i i i个样本的预测值。 均方误差也叫做最小二乘法。 3. 梯度下降 梯度下降(Gradient Descent, GD)是一种优化算法用于最小化或最大化一个函数通常用来训练机器学习模型。在神经网络中我们的目标是通过调整模型的参数例如权重和偏置来最小化损失函数。损失函数衡量了模型的预测与实际标签之间的差异目标是让这个损失函数的值尽可能小。   梯度下降的核心思想是沿着损失函数的梯度偏导数下降不断更新参数直到达到最小值。 
3.1 梯度下降的公式 梯度下降的更新规则如下  θ  θ − η ⋅ ∇ θ L ( θ ) \theta  \theta - \eta \cdot \nabla_\theta L(\theta) θθ−η⋅∇θL(θ)其中    θ \theta θ 是模型的参数例如权重和偏置。    η \eta η 是学习率learning rate控制每次更新的步长。    ∇ θ L ( θ ) \nabla_\theta L(\theta) ∇θL(θ) 是损失函数  L L L 关于参数  θ \theta θ 的梯度。   梯度  ∇ θ L ( θ ) \nabla_\theta L(\theta) ∇θL(θ) 告诉我们沿着哪个方向更新参数能使损失函数下降得更快。 
3.2 梯度下降的类型优化器 1. 批量梯度下降(Batch Gradient Descent)每次使用整个数据集来计算梯度和更新参数。虽然准确性高但计算开销大尤其是在数据量很大的时候。   2. 随机梯度下降(Stochastic Gradient Descent, SGD)每次只用一个样本来计算梯度和更新参数。虽然更新速度快但可能会导致参数更新不稳定。   3. 小批量梯度下降(Mini-Batch Gradient Descent)每次使用数据集中的一个小批量样本来计算梯度和更新参数。这种方法结合了批量和随机梯度下降的优点。   当然还有很多类型的优化比如Adam、RMSprop、AdaW等这里不再细述。 
4. 反向传播 反向传播(Back Propagation, BP)是用于计算神经网络中每一层的梯度的算法。它是梯度下降的一部分特别用于计算和传播每个参数对损失函数的贡献。   反向传播算法依赖于链式法则(Chain Rule)通过链式法则可以将损失函数对模型参数的梯度逐层传播回去从而更新每一层的参数。 即从输出层一步步传播到输入层。 4.1 反向传播的基本步骤 
假设我们有一个包含多个层的神经网络每一层都有权重  W W W 和偏置  b b b。反向传播的步骤如下   1. 前向传播从输入层开始将输入数据传递到输出层并计算出预测值。   2. 计算损失根据模型的输出与真实标签计算损失函数。   3. 反向传播     (1)计算输出层的梯度即损失函数关于输出的偏导数。     (2)逐层计算隐藏层的梯度即损失函数关于每一层的输入、权重和偏置的偏导数。   4. 更新权重和偏置根据梯度下降规则更新每一层的权重和偏置。 
4.2 反向传播的数学推导 假设神经网络有两层每层的输出分别为  a 1 a_1 a1 和  a 2 a_2 a2损失函数为  L L L。反向传播的目标是计算  ∂ L ∂ W 1 \frac{\partial L}{\partial W_1} ∂W1∂L 和  ∂ L ∂ W 2 \frac{\partial L}{\partial W_2} ∂W2∂L即每一层权重的梯度。   1. 输出层梯度计算  ∂ L ∂ a 2  ∂ L ∂ y ⋅ ∂ y ∂ a 2 \frac{\partial L}{\partial a_2}  \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial a_2} ∂a2∂L∂y∂L⋅∂a2∂y其中 y y y是输出层的预测值。   2. 隐藏层梯度计算  ∂ L ∂ a 1  ∂ L ∂ a 2 ⋅ ∂ a 2 ∂ a 1 \frac{\partial L}{\partial a_1}  \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial a_1} ∂a1∂L∂a2∂L⋅∂a1∂a2然后我们使用链式法则计算每一层的权重梯度。   3. 参数更新根据计算出来的梯度使用梯度下降更新权重和偏置。 
5. 实战 
5.1 手动求导 我们来构建一个简单的神经网络做一个线性回归 模型的输入为2维数据输出为1维数据该模型的函数表达式可以表示为  y ∗  w 5 ⋅ ( w 1 ⋅ x 1  w 3 ⋅ x 2 )  w 6 ⋅ ( w 2 ⋅ x 1  w 4 ⋅ x 2 ) y^*  w_5 \cdot (w_1 \cdot x_1  w_3 \cdot x_2)  w_6 \cdot (w_2 \cdot x_1  w_4 \cdot x_2) y∗w5⋅(w1⋅x1w3⋅x2)w6⋅(w2⋅x1w4⋅x2)  我们使用MSE来作为损失函数来优化我们的网络即  L o s s  1 n ∑ i  1 n ( y i − y i ∗ ) 2 Loss  \frac {1} {n} \sum _{i1} ^ n (y_i - y^*_i) ^ 2 Lossn1i1∑n(yi−yi∗)2   假设初始时模型的权重为  w 1  1.0  w 2  0.5  w 3  0.5  w 4  0.7 w_11.0w_20.5w_30.5w_40.7 w11.0w20.5w30.5w40.7 w 5  1.0  w 6  2.0 w_51.0w_62.0 w51.0w62.0  已知一个样本数据  x 1  0.5  x 2  1.0  y  0.8 x_10.5x_21.0y0.8 x10.5x21.0y0.8  按照上述公式计算一次前向传播得到  y ∗  2.9 y^*2.9 y∗2.9与真实值  y y y 的偏差可以通过  l o s s loss loss 计算得到 l o s s  ( y − y ∗ ) 2  4.41 loss  (y - y^*) ^ 2  4.41 loss(y−y∗)24.41。然后我们通过梯度下降的方式来更新 w 5 w_5 w5需要先计算出在点 ( x 1 , x 2 ) (x_1,x_2) (x1,x2)的梯度  ∇  ∂ L ∂ w 1  ∂ L ∂ y ∗ ⋅ ∂ y ∗ ∂ w 5 \nabla  \frac {\partial L} {\partial w_1}  \frac {\partial L} {\partial y^*} \cdot \frac {\partial y^*} {\partial w_5} ∇∂w1∂L∂y∗∂L⋅∂w5∂y∗ ∂ L ∂ y ∗  − 2 ( y − y ∗ )  4.2 \frac {\partial L} {\partial y^*}  -2 (y- y^*)  4.2 ∂y∗∂L−2(y−y∗)4.2 ∂ y ∗ ∂ w 5  w 1 ⋅ x 1  w 3 ⋅ x 2  1.0 \frac {\partial y^*} {\partial w_5}  w_1 \cdot x_1  w_3 \cdot x_2  1.0 ∂w5∂y∗w1⋅x1w3⋅x21.0   所以梯度为  ∂ L ∂ w 1  4.2 \frac {\partial L} {\partial w_1}  4.2 ∂w1∂L4.2  假设学习率为 0.01 0.01 0.01根据梯度下降算法  θ  θ − η ⋅ ∇ θ L ( θ ) \theta  \theta - \eta \cdot \nabla_{\theta} L(\theta) θθ−η⋅∇θL(θ) 更新 w 5 w5 w5:  w 5  w 5 − η ∂ L ∂ w 5  0.958 w_5  w_5 - \eta \frac {\partial L} {\partial w_5}  0.958 w5w5−η∂w5∂L0.958  同理可以更新 w 1 w_1 w1  ∂ y ∗ ∂ w 1  w 5 x 1  0.5 \frac {\partial y^*} {\partial w_1}  w_5x_1  0.5 ∂w1∂y∗w5x10.5 ∂ L ∂ w 1  ∂ L ∂ y ∗ ⋅ ∂ y ∗ ∂ w 1  2.1 \frac {\partial L} {\partial w_1}  \frac {\partial L} {\partial y^*} \cdot \frac {\partial y^*} {\partial w_1}  2.1 ∂w1∂L∂y∗∂L⋅∂w1∂y∗2.1 w 1  w 1 − η ∂ L ∂ w 1  0.979 w_1  w_1 - \eta \frac {\partial L} {\partial w_1}  0.979 w1w1−η∂w1∂L0.979 
5.2 自动求导 将上面模型的表达式形式化即  y ∗  ( x T ⋅ W h ) ⋅ W o y*  (x^T \cdot W_h) \cdot W_o y∗(xT⋅Wh)⋅Wo其中  x  [ x 1 x 2 ]  W h  [ w 1 w 2 w 3 w 4 ]  W o  [ w 5 w 6 ] x  \begin{bmatrix} x_1 \\ x_2\end{bmatrix}W_h  \begin{bmatrix} w_{1}  w_{2} \\ w_{3}  w_{4} \end{bmatrix}W_o  \begin{bmatrix} w_{5}  w_{6} \end{bmatrix} x[x1x2]Wh[w1w3w2w4]Wo[w5w6]  这样我们就可以使用pytorch来构建上述神经网络了具体如下 
# -*- coding: utf-8 -*-
# Author  : liyanpeng
# Email   : yanpeng.licumt.edu.cn
# Datetime: 2024/11/29 17:38
# Filename: chain_rule.py
import torch
import torch.nn as nn
import torch.optim as optimdef func_y():x1  torch.tensor(0.5, dtypetorch.float32)x2  torch.tensor(1.0, dtypetorch.float32)w1  torch.tensor(1.0, dtypetorch.float32)w2  torch.tensor(0.5, dtypetorch.float32)w3  torch.tensor(0.5, dtypetorch.float32)w4  torch.tensor(0.7, dtypetorch.float32)w5  torch.tensor(1.0, dtypetorch.float32)w6  torch.tensor(2.0, dtypetorch.float32)y  w5 * (w1 * x1  w2 * x2)  w6 * (w3 * x1  w4 * x2)print(y)class SimpleNeuralNetwork(nn.Module):def __init__(self):super().__init__()self.linear1  nn.Linear(in_features2, out_features2, biasFalse)self.linear2  nn.Linear(in_features2, out_features1, biasFalse)self.linear1.weight.data  torch.tensor([[1.0, 0.5], [0.5, 0.7]], dtypetorch.float32)self.linear2.weight.data  torch.tensor([[1.0, 2.0]], dtypetorch.float32)def forward(self, x):x  self.linear1(x)y  self.linear2(x)return ydef grad_hook(grad):print(grad:, grad[0][0])if __name__  __main__:x  torch.tensor([0.5, 1.0], dtypetorch.float32)y  torch.tensor(0.8, dtypetorch.float32)model  SimpleNeuralNetwork()criterion  nn.MSELoss()optimizer  optim.SGD(model.parameters(), lr0.01)hook_list  []for name, param in model.named_parameters():if param.requires_grad:hook  param.register_hook(grad_hook)hook_list.append(hook)y_pred  model(x)loss  criterion(y_pred, y)optimizer.zero_grad()   # 清空梯度loss.backward()         # 反向传播optimizer.step()        # 更新权重for hook in hook_list:hook.remove()print(更新后的w1, model.linear1.weight.data[0, 0])print(更新后的w5, model.linear2.weight.data[0, 0])打印结果如下与手动计算的结果一致 
grad: tensor(4.2000)
grad: tensor(2.1000)
更新后的w1 tensor(0.9790)
更新后的w5 tensor(0.9580)5.3 过程可视化 再加入一些可视化代码看一下权重更新的轨迹 
# -*- coding: utf-8 -*-
# Author  : liyanpeng
# Email   : yanpeng.licumt.edu.cn
# Datetime: 2024/11/29 17:38
# Filename: chain_rule.py
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as npif __name__  __main__:x  torch.tensor([0.5, 1.0], dtypetorch.float32)y  torch.tensor(0.8, dtypetorch.float32)model  SimpleNeuralNetwork()criterion  nn.MSELoss()optimizer  optim.SGD(model.parameters(), lr0.01)loss_list  []w1_list  []w2_list  []for epoch in range(5):y_pred  model(x)loss  criterion(y_pred, y)optimizer.zero_grad()   # 清空梯度loss.backward()         # 反向传播optimizer.step()        # 更新权重loss_list.append(loss.item())w1_list.append(model.linear1.weight.data[0, 0].item())w2_list.append(model.linear2.weight.data[0, 0].item())fig  plt.figure(figsize(8, 6))# 3D曲面图和等高线图ax1  fig.add_subplot(111, projection3d)ax1.set_title(3D Loss Surface with Contours and Trajectory)# 将损失值、权重映射到X, Y, Z轴ax1.plot_trisurf(w1_list, w2_list, loss_list, cmapviridis, alpha0.7)# 生成网格数据用于绘制等高线图w1_range  np.linspace(min(w1_list), max(w1_list), 100)w2_range  np.linspace(min(w2_list), max(w2_list), 100)W1, W2  np.meshgrid(w1_range, w2_range)np.random.seed(42)x_train  np.random.rand(100, 2)noise  np.random.randn(100, 1)# f(x, y)  2x^2  y^2 - 0.7  noisey_train  2 * x_train[:, 0] * x_train[:, 0]  x_train[:, 1] * x_train[:, 1] - 0.7  noise# 计算每个网格点的损失值loss_grid  np.zeros(W1.shape)for i in range(W1.shape[0]):for j in range(W1.shape[1]):model.linear1.weight.data[0, 0]  W1[i, j]model.linear2.weight.data[0, 0]  W2[i, j]y_pred  model(torch.tensor(x_train, dtypetorch.float32))loss_grid[i, j]  criterion(y_pred, torch.tensor(y_train, dtypetorch.float32)).item()# 绘制等高线图ax1.contour(W1, W2, loss_grid, levels20, cmapviridis, offsetmin(loss_list))# 绘制权重更新轨迹ax1.plot(w1_list, w2_list, loss_list, k-, markero, markersize5, labelWeight Update Trajectory)ax1.plot(w1_list, w2_list, [min(loss_list)] * len(w1_list), r-, markero, markersize5, labelTrajectory on Contours)# 在等高线图上标记权重更新的坐标for i in range(len(w1_list)):ax1.text(w1_list[i], w2_list[i], min(loss_list),f({w1_list[i]:.4f}, {w2_list[i]:.4f}),colorred, fontsize8, hacenter, vacenter)ax1.set_xlabel(Linear1 Weight (First Element))ax1.set_ylabel(Linear2 Weight (First Element))ax1.set_zlabel(Loss)ax1.legend()plt.tight_layout()plt.show()绘制的效果图如下 损失函数从右侧至左侧逐渐收敛最右侧的点是我们第一次更新时 w 1 w_1 w1和 w 2 w_2 w2的权重。