跳转到主要内容

深度学习中如何对模型参数进行分组优化

demi 提交于

在深度学习中,不同的参数(如权重和偏置、不同层的参数)可能需要不同的优化策略。常见的做法是对 不同参数组使用不同的学习率、权重衰减(L2正则化)或优化算法,这被称为 参数分组优化(Grouped Parameter Optimization)。

<hr>

<font size="4" style="line-height: 45px;" color="#c200ff"><strong>一、为什么需要分组优化?</strong></font>

<strong>1. 不同类型的参数可能需要不同的学习率</strong>

卷积层权重 可能需要较小的学习率以稳定训练。
全连接层权重 可能需要较大的学习率以加速收敛。

<strong>2. 权重和偏置的处理方式不同</strong>

通常对权重使用权重衰减(L2 正则化),以防止过拟合。
偏置项通常不使用权重衰减。

<strong>3. 不同层次的参数可使用不同优化策略</strong>

预训练模型的底层参数可以使用较小的学习率,避免破坏已有的特征提取能力。
高层参数使用较大的学习率,以便适应新的任务。

<hr>

<font size="4" style="line-height: 45px;" color="#c200ff"><strong>二、如何实现参数分组优化?</strong></font>

在 PyTorch 中,可以使用 param_groups 进行参数分组,然后传递给优化器。

<font style="line-height: 40px;"><strong>示例 1:基础参数分组</strong></font>

<pre>import torch
import torch.nn as nn
import torch.optim as optim

# 定义一个简单的神经网络
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
self.fc1 = nn.Linear(32 * 8 * 8, 128)
self.fc2 = nn.Linear(128, 10)

def forward(self, x):
x = torch.relu(self.conv1(x))
x = torch.relu(self.conv2(x))
x = x.view(x.size(0), -1) # Flatten
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x

model = SimpleModel()

# 定义参数组
param_groups = [
{"params": model.conv1.parameters(), "lr": 0.001}, # 第一层卷积较低学习率
{"params": model.conv2.parameters(), "lr": 0.001}, # 第二层卷积较低学习率
{"params": model.fc1.parameters(), "lr": 0.01}, # 全连接层较高学习率
{"params": model.fc2.parameters(), "lr": 0.01} # 输出层较高学习率
]

# 使用 Adam 优化器
optimizer = optim.Adam(param_groups)

# 打印优化器参数
for i, group in enumerate(optimizer.param_groups):
print(f"Group {i}: Learning Rate = {group['lr']}")
</pre>

<strong>解析:</strong>

<ul><li>卷积层 conv1 和 conv2 使用较小的学习率 0.001,以稳定训练。</li>
<li>全连接层 fc1 和 fc2 使用较大的学习率 0.01,以加快训练。</li></ul>

<font style="line-height: 40px;"><strong>示例 2:为权重和偏置项使用不同优化策略</strong></font>

在优化过程中,我们可以 为权重和偏置项设置不同的权重衰减参数(L2 正则化)。

<pre># 过滤出权重和偏置
param_groups = [
{"params": [param for name, param in model.named_parameters() if "bias" not in name], "weight_decay": 1e-4}, # 只对权重使用 L2 正则化
{"params": [param for name, param in model.named_parameters() if "bias" in name], "weight_decay": 0} # 偏置不使用 L2 正则化
]

# 使用 SGD 进行优化
optimizer = optim.SGD(param_groups, lr=0.01, momentum=0.9)

# 打印优化器参数
for i, group in enumerate(optimizer.param_groups):
print(f"Group {i}: Weight Decay = {group['weight_decay']}")
</pre>

<strong>解析:</strong>

<ul><li>第一组参数(bias 以外的权重)使用 weight_decay=1e-4 进行 L2 正则化,防止过拟合。</li>
<li>第二组参数(bias)不使用权重衰减,避免影响偏置项的更新。</li></ul>

<hr>

<font style="line-height: 40px;"><strong>示例 3:冻结部分层,仅微调部分参数</strong></font>

在使用 预训练模型(如 ResNet、BERT) 时,我们通常 冻结底层特征提取层,仅对高层进行微调。

<pre>import torchvision.models as models

# 加载预训练的 ResNet
model = models.resnet18(pretrained=True)

# 冻结所有参数
for param in model.parameters():
param.requires_grad = False

# 替换 ResNet 的最后一层
model.fc = nn.Linear(512, 10)

# 仅优化 `fc` 层
optimizer = optim.Adam(model.fc.parameters(), lr=0.01)

# 打印需要训练的参数
for name, param in model.named_parameters():
if param.requires_grad:
print(f"Trainable: {name}")
</pre>

<strong>解析:</strong>

<ul><li>所有层参数 requires_grad=False,避免更新底层权重。</li>
<li>仅更新 fc 层,以适应新任务。</li></ul>

<hr>

<font style="line-height: 40px;"><strong>示例 4:使用不同优化算法</strong></font>

有时候,我们可能希望 不同的参数组使用不同的优化算法,如:
<ul><li>CNN 层使用 Adam</li>
<li>全连接层使用 SGD</li>
<li>部分层使用 RMSprop</li></ul>

<pre># 定义不同优化器
optimizer_cnn = optim.Adam([
{"params": model.conv1.parameters(), "lr": 0.001},
{"params": model.conv2.parameters(), "lr": 0.001}
])

optimizer_fc = optim.SGD([
{"params": model.fc1.parameters(), "lr": 0.01},
{"params": model.fc2.parameters(), "lr": 0.01}
], momentum=0.9)

# 训练时分别更新
for batch in data_loader:
optimizer_cnn.zero_grad()
optimizer_fc.zero_grad()

outputs = model(batch)
loss = loss_fn(outputs, target)

loss.backward()

optimizer_cnn.step()
optimizer_fc.step()
</pre>

<strong>解析:</strong>

<ul><li>CNN 层使用 Adam,适合复杂结构。</li>

<li>全连接层使用 SGD,更适合梯度稳定的层。</li></ul>

<hr>

<font size="4" style="line-height: 45px;" color="#c200ff"><strong>3. 结论</strong></font>

参数分组优化在深度学习中至关重要,常见应用包括:

1. 不同层使用不同学习率(如 CNN 层较低,FC 层较高)。

2. 对权重使用 L2 正则化,对偏置不使用。

3. 冻结底层,仅微调高层(如 ResNet、BERT 微调)。

4. 不同层使用不同优化算法(如 CNN 用 Adam,FC 用 SGD)。

通过 param_groups,可以灵活地控制不同参数的优化策略,提高训练效率和模型性能。

<hr>

<font color="#9a9a9a">版权声明:本文为CSDN博主「彬彬侠」的原创文章,</font>
<font color="#9a9a9a">遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。</font>
<a href="https://blog.csdn.net/u013172930/article/details/146210321"><font color="#9a9a9a">原文链接:https://blog.csdn.net/u013172930/article/details/146210321</font></a&gt;
<br>