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

YOLOv5模型Fisher信息计算时梯度缺失问题求助

YOLOv5 Fisher信息计算中梯度未生成的修复方案

问题背景

我需要实现函数计算YOLOv5各参数的Fisher信息,采用预训练模型遍历数据批次计算,但运行代码后出现Grad does not exist提示,梯度未被正确计算,无法完成后续Fisher信息的累加。

核心问题分析

你的代码存在几个致命问题导致梯度无法回传到模型参数:

  • 计算图断裂:模型输出后经过non_max_suppression(包含不可导的筛选、int转换)、numpy数组转换等操作,彻底切断了模型参数与最终损失之间的计算图连接,梯度根本无法反向传播到模型参数。
  • 错误的梯度设置:给target标签设置了requires_grad=True,标签是固定的监督信号,不需要求导,这会干扰梯度计算逻辑。
  • 梯度累加时机错误:在所有batch循环结束后才尝试累加梯度,且每次循环调用optimizer.step()会干扰梯度状态,甚至导致梯度被覆盖或清除。
  • 初始化错误:total_gradients初始化为0,而非与参数同形状的零张量,后续累加会出现维度不匹配问题。

修复步骤

  1. 保留模型原始输出的计算图:跳过NMS后处理,直接用模型的原始输出(预测框、置信度、分类)计算损失,确保梯度能反向传播到模型参数。
  2. 全程使用Tensor操作:移除所有numpy转换、int强制转换,避免计算图断裂。
  3. 修正梯度设置:target标签不需要requires_grad=True,保持默认的False即可。
  4. 实时累加梯度:每个batch计算完梯度后立即将梯度累加到total_gradients,累加后手动清空梯度。
  5. 取消不必要的参数更新:不需要调用optimizer.step(),因为我们只需要梯度信息,不需要更新模型权重。

修改后的完整代码

import torch
import torch.nn.functional as F
import torch.optim as optim

def compute_fisher_information_detection(model, dataloader, device):
    model.train()
    for param in model.parameters():
        param.requires_grad = True

    # 初始化梯度累加器,用参数同形状的零张量
    total_gradients = {name: torch.zeros_like(param.data) for name, param in model.named_parameters() if param.requires_grad}
    total_fisher_information = {name: torch.zeros_like(layer.weight.data) for name, layer in model.named_children() if hasattr(layer, 'weight')}

    for batch in dataloader:
        inputs = batch['img'].to(device)
        # 处理targets:转换为模型需要的格式,不需要requires_grad
        targets = []
        for label_list in batch['label']:
            label = torch.tensor([float(v[0]) for v in label_list], dtype=torch.float32).to(device)
            targets.append(label)
        targets = torch.stack(targets)

        # 重置梯度
        for param in model.parameters():
            if param.grad is not None:
                param.grad.zero_()
        
        # 直接用模型原始输出计算损失,保留计算图
        outputs = model(inputs, augment=False)[0]
        # YOLOv5的输出格式:[batch_size, num_anchors*(5+num_classes), height, width]
        num_anchors = 3
        num_classes = model.nc
        output_shape = outputs.shape
        outputs = outputs.view(output_shape[0], num_anchors, 5 + num_classes, output_shape[2], output_shape[3]).permute(0, 1, 3, 4, 2).contiguous()
        
        # 提取预测的box(中心x、y,宽、高,已归一化)
        pred_boxes = outputs[..., 1:5]
        # 扩展target维度匹配预测张量的形状
        target_boxes = targets[..., 1:5].unsqueeze(1).unsqueeze(2).unsqueeze(3)
        
        # 计算box损失,可替换为YOLOv5原生损失函数以获得更准确的梯度
        box_loss = F.smooth_l1_loss(pred_boxes, target_boxes, reduction='mean')
        
        # 反向传播计算梯度
        box_loss.backward()
        
        # 累加梯度到total_gradients
        for name, param in model.named_parameters():
            if param.requires_grad and param.grad is not None:
                total_gradients[name] += param.grad.data.clone()

    # 计算Fisher信息:梯度平方的期望(用累加梯度除以batch数近似期望)
    num_batches = len(dataloader)
    for name in total_fisher_information.keys():
        if name in total_gradients:
            total_fisher_information[name] = (total_gradients[name] / num_batches) ** 2

    return total_fisher_information

关键说明

  • 直接使用模型原始输出计算损失,避免了NMS等不可导操作破坏计算图,确保梯度能正确回传到模型参数。
  • 每个batch完成后立即累加梯度,避免梯度丢失或被覆盖。
  • 移除optimizer.step(),仅保留梯度计算逻辑,无需更新模型权重。
  • 最终通过梯度的平方期望近似Fisher信息(Fisher信息为梯度的协方差矩阵,此处简化为对角元素的近似值)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:28:12