梯度下降与权重更新解析
文章目录
- 1. 梯度下降的基本概念
- 2. 权重更新的具体过程
- 示例数据
- 前向传播
- 损失计算
- 反向传播
- 参数更新
- 3. 使用 PyTorch 实现梯度下降
- 手动更新参数
- 使用优化器简化更新过程
- 4. `requires_grad` 的重要性
- 5. 总结
- 参考内容
在机器学习和深度学习中,梯度下降是一种广泛使用的优化算法,用于最小化损失函数并优化模型参数。通过调整神经网络中的权重和偏置,梯度下降帮助模型逐渐逼近最优解。本文将详细介绍梯度下降的基本原理、权重更新的过程,并结合PyTorch代码展示其实际应用。
1. 梯度下降的基本概念
梯度下降的核心思想是通过计算损失函数关于模型参数的梯度,逐步调整这些参数以减小损失。具体来说,梯度下降法按照以下步骤进行:
- 初始化参数:为每个需要优化的参数(如权重 W W W 和偏置 b b b)设置初始值。
- 前向传播:使用当前参数计算预测输出,并根据真实标签计算损失。
- 反向传播:利用链式法则计算损失关于每个参数的梯度。
- 参数更新:根据计算出的梯度调整参数,通常采用简单的梯度下降公式:
θ : = θ − η ∇ θ L \theta := \theta - \eta \nabla_\theta L θ:=θ−η∇θL
其中 θ \theta θ 是参数, η \eta η 是学习率, ∇ θ L \nabla_\theta L ∇θL 是损失函数关于参数的梯度。
2. 权重更新的具体过程
为了更直观地理解权重更新的过程,我们可以通过一个具体的数值例子来说明。假设我们有一个简单的单层神经网络,该层包含一个神经元,并使用Sigmoid激活函数 σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1 和均方误差损失函数(MSE)。
示例数据
- 输入特征 x = 2 x = 2 x=2
- 初始权重 W = 0.5 W = 0.5 W=0.5
- 初始偏置 b = 0.3 b = 0.3 b=0.3
- 真实标签 y = 1 y = 1 y=1
前向传播
首先进行前向传播,计算加权输入 z z z 和激活输出 a a a:
z
=
W
x
+
b
=
0.5
×
2
+
0.3
=
1.3
z = Wx + b = 0.5 \times 2 + 0.3 = 1.3
z=Wx+b=0.5×2+0.3=1.3
a
=
σ
(
z
)
=
1
1
+
e
−
1.3
≈
0.7858
a = \sigma(z) = \frac{1}{1 + e^{-1.3}} \approx 0.7858
a=σ(z)=1+e−1.31≈0.7858
损失计算
使用均方误差损失函数 L L L 来衡量预测值 a a a 与真实标签 y y y 之间的差异:
L = ( a − y ) 2 = ( 0.7858 − 1 ) 2 ≈ 0.0459 L = (a - y)^2 = (0.7858 - 1)^2 \approx 0.0459 L=(a−y)2=(0.7858−1)2≈0.0459
反向传播
接下来,我们需要计算参数的梯度。对于均方误差损失函数,梯度计算如下:
∂
L
∂
a
=
2
×
(
a
−
y
)
=
2
×
(
0.7858
−
1
)
=
−
0.4284
\frac{\partial L}{\partial a} = 2 \times (a - y) = 2 \times (0.7858 - 1) = -0.4284
∂a∂L=2×(a−y)=2×(0.7858−1)=−0.4284
∂
a
∂
z
=
σ
(
z
)
(
1
−
σ
(
z
)
)
=
0.7858
×
(
1
−
0.7858
)
≈
0.1683
\frac{\partial a}{\partial z} = \sigma(z)(1 - \sigma(z)) = 0.7858 \times (1 - 0.7858) \approx 0.1683
∂z∂a=σ(z)(1−σ(z))=0.7858×(1−0.7858)≈0.1683
∂
L
∂
z
=
∂
L
∂
a
×
∂
a
∂
z
≈
−
0.4284
×
0.1683
≈
−
0.07209
\frac{\partial L}{\partial z} = \frac{\partial L}{\partial a} \times \frac{\partial a}{\partial z} \approx -0.4284 \times 0.1683 \approx -0.07209
∂z∂L=∂a∂L×∂z∂a≈−0.4284×0.1683≈−0.07209
∂
L
∂
W
=
∂
L
∂
z
×
∂
z
∂
W
=
−
0.07209
×
2
=
−
0.14418
\frac{\partial L}{\partial W} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial W} = -0.07209 \times 2 = -0.14418
∂W∂L=∂z∂L×∂W∂z=−0.07209×2=−0.14418
∂
L
∂
b
=
∂
L
∂
z
×
∂
z
∂
b
=
−
0.07209
×
1
=
−
0.07209
\frac{\partial L}{\partial b} = \frac{\partial L}{\partial z} \times \frac{\partial z}{\partial b} = -0.07209 \times 1 = -0.07209
∂b∂L=∂z∂L×∂b∂z=−0.07209×1=−0.07209
参数更新
假设学习率 η = 0.1 \eta = 0.1 η=0.1,我们可以根据计算出的梯度来更新参数:
W
:
=
W
−
η
⋅
∂
L
∂
W
=
0.5
−
0.1
×
(
−
0.14418
)
=
0.5
+
0.014418
≈
0.514418
W := W - \eta \cdot \frac{\partial L}{\partial W} = 0.5 - 0.1 \times (-0.14418) = 0.5 + 0.014418 \approx 0.514418
W:=W−η⋅∂W∂L=0.5−0.1×(−0.14418)=0.5+0.014418≈0.514418
b
:
=
b
−
η
⋅
∂
L
∂
b
=
0.3
−
0.1
×
(
−
0.07209
)
=
0.3
+
0.007209
≈
0.307209
b := b - \eta \cdot \frac{\partial L}{\partial b} = 0.3 - 0.1 \times (-0.07209) = 0.3 + 0.007209 \approx 0.307209
b:=b−η⋅∂b∂L=0.3−0.1×(−0.07209)=0.3+0.007209≈0.307209
通过不断重复上述过程,模型的参数会逐渐优化,从而使损失函数趋于最小。
3. 使用 PyTorch 实现梯度下降
为了更好地理解梯度下降和权重更新的实际操作,我们可以使用PyTorch进行实现。以下是完整的代码示例,展示了手动更新参数和使用优化器简化更新过程两种方式。
手动更新参数
import torch
import torch.nn.functional as F
# 设置随机种子以保证结果可复现
torch.manual_seed(1)
# 定义输入、权重、偏置和真实标签
x = torch.tensor([2.0], requires_grad=False) # 输入特征
W = torch.tensor([0.5], requires_grad=True) # 权重
b = torch.tensor([0.3], requires_grad=True) # 偏置
y_true = torch.tensor([1.0], requires_grad=False) # 真实标签
# 前向传播:计算预测值
z = W * x + b # 加权输入
a = torch.sigmoid(z) # 激活输出
# 计算损失(均方误差)
loss = F.mse_loss(a, y_true)
print(f"前向传播: z = {z.item():.4f}, a = {a.item():.4f}, loss = {loss.item():.4f}")
# 反向传播:计算梯度
loss.backward()
# 查看梯度
print(f"反向传播后,W的梯度: {W.grad.item():.4f}")
print(f"反向传播后,b的梯度: {b.grad.item():.4f}")
# 更新参数(简单梯度下降法)
learning_rate = 0.1
with torch.no_grad():
W -= learning_rate * W.grad
b -= learning_rate * b.grad
# 清除梯度,以便下一次迭代可以重新计算
W.grad.zero_()
b.grad.zero_()
print(f"更新后的权重 W: {W.item():.5f}, 更新后的偏置 b: {b.item():.5f}")
输出示例:
前向传播: z = 1.3000, a = 0.7858, loss = 0.0459
反向传播后,W的梯度: -0.1442
反向传播后,b的梯度: -0.0721
更新后的权重 W: 0.51442, 更新后的偏置 b: 0.30721
使用优化器简化更新过程
import torch
import torch.nn.functional as F
from torch import optim
# 设置随机种子以保证结果可复现
torch.manual_seed(1)
# 定义输入、权重、偏置和真实标签
x = torch.tensor([2.0], requires_grad=False) # 输入特征
W = torch.tensor([0.5], requires_grad=True) # 权重
b = torch.tensor([0.3], requires_grad=True) # 偏置
y_true = torch.tensor([1.0], requires_grad=False) # 真实标签
# 将参数放入列表中,传递给优化器
params = [W, b]
optimizer = optim.SGD(params, lr=0.1)
# 前向传播:计算预测值
z = W * x + b # 加权输入
a = torch.sigmoid(z) # 激活输出
# 计算损失(均方误差)
loss = F.mse_loss(a, y_true)
print(f"前向传播: z = {z.item():.4f}, a = {a.item():.4f}, loss = {loss.item():.4f}")
# 反向传播:计算梯度
loss.backward()
# 查看梯度
print(f"反向传播后,W的梯度: {W.grad.item():.4f}")
print(f"反向传播后,b的梯度: {b.grad.item():.4f}")
# 更新参数(使用优化器)
optimizer.step()
# 清除梯度
optimizer.zero_grad()
print(f"更新后的权重 W: {W.item():.5f}, 更新后的偏置 b: {b.item():.5f}")
输出示例:
前向传播: z = 1.3000, a = 0.7858, loss = 0.0459
反向传播后,W的梯度: -0.1442
反向传播后,b的梯度: -0.0721
更新后的权重 W: 0.51442, 更新后的偏置 b: 0.30721
4. requires_grad
的重要性
在PyTorch中,requires_grad
是一个非常重要的属性,它决定了是否为某个Tensor计算和跟踪梯度。理解何时设置requires_grad=True
或False
对于正确构建和训练神经网络至关重要。
-
可学习参数:如果一个Tensor是模型的参数(如权重或偏置),并且你希望在训练过程中通过反向传播更新这些参数,则必须将其
requires_grad
设置为True
。W = torch.tensor([0.5], requires_grad=True) # 可学习参数
-
输入数据和标签:输入数据和标签通常是固定的,不参与梯度计算,因此它们的
requires_grad
应该设置为False
。实际上,默认情况下,用torch.tensor()
创建的Tensor的requires_grad
是False
,所以你通常不需要显式设置。x = torch.tensor([2.0]) # 默认 requires_grad=False y_true = torch.tensor([1.0]) # 默认 requires_grad=False
-
自定义层或操作:如果你创建了自定义的层或操作,并且涉及到需要优化的参数,那么你需要确保这些参数的
requires_grad
被正确设置。 -
冻结部分网络:在微调预训练模型时,有时你可能只想更新某些层的参数,而保持其他层不变。这时你可以选择性地将某些层的参数的
requires_grad
设置为False
,以冻结它们。for param in model.parameters(): param.requires_grad = False # 冻结所有参数
5. 总结
梯度下降是机器学习和深度学习中不可或缺的优化算法,通过不断调整模型参数以最小化损失函数,使得模型能够更好地拟合数据。
参考内容
梯度下降法视频讲解
误差反向传播