You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何基于ResNet18的迁移训练耗时与从头训练一致?

问题:冻结ResNet18特征层后训练耗时未降低

我基于ResNet18构建自定义模型,移除原fc层,新增两个全连接层self.l1 = nn.Linear(512, 512)和self.l2 = nn.Linear(512, 256),并将ResNet18的特征层设置为requires_grad=False冻结,仅训练新增的两个层,但训练耗时和从头训练完整ResNet18完全相同。

核心原因

虽然你冻结了特征层的参数,但反向传播时仍然会计算特征层的梯度(只是不会更新参数),而且前向传播时ResNet18的特征提取部分依然会执行所有计算——这部分的计算量占了模型的绝大多数,所以整体耗时和训练完整模型几乎一致。

另外如果使用DataParallel,若在冻结参数之后才包装模型,可能会导致参数的梯度状态没有正确同步,但这不是耗时的主要原因。

优化方案

1. 前向传播时禁用特征层的梯度计算

在模型的forward方法中,用torch.no_grad()包裹特征层的计算,彻底跳过梯度计算环节:

def forward(self, x):
    with torch.no_grad():
        h = self.features(x)
        h = h.squeeze()

    x = self.l1(h)
    x = F.relu(x)
    x = self.l2(x)
    return h, x

这样反向传播时不会为特征层的计算构建计算图,能节省内存和计算时间。

2. 提前预计算特征并保存

如果数据集固定,可以提前用预训练的ResNet18特征层把所有图片的特征提取出来保存,训练时直接加载这些特征训练新增的全连接层,彻底跳过ResNet18的特征提取计算:

  • 编写脚本遍历数据集,用冻结的ResNet18提取特征,保存为numpy文件或torch张量
  • 修改数据加载类,直接加载预计算的特征而非原始图片
  • 训练时模型仅保留新增的两个全连接层即可

3. 修正参数冻结的时机(多GPU场景)

如果使用DataParallel,要先冻结参数再包装模型,避免多GPU环境下梯度状态不一致:

model = ResNetSimCLR(self.config["model"]['out_dim'])
# 先冻结特征层参数
for param in model.features.parameters():
    param.requires_grad = False
# 再包装DataParallel
if self.config['n_gpu'] > 1:
    device_n = len(eval(self.config['gpu_ids']))
    model = torch.nn.DataParallel(model, device_ids=range(device_n))
model = model.to(self.device)

4. 验证参数冻结状态

训练前打印参数的requires_grad状态,确认特征层参数已被正确冻结:

for name, param in model.named_parameters():
    print(f"{name}: requires_grad={param.requires_grad}")

内容的提问来源于stack exchange,提问作者ad150

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:05:54