如何获取GluonCV模型库YOLO3损失相对于输入图像的梯度
错误原因
你抛出AttributeError: 'YOLOV3' object has no attribute 'grad'的核心原因是:grad是MXNet中NDArray张量的属性,用于存储张量对应的梯度值,而YOLOV3是Gluon的Block模型对象,本身没有grad属性,你找错了梯度的存储位置。
正确获取输入图像梯度的方法
你需要获取的是输入图像张量的梯度,要做以下修改:
- 首先要给输入图像张量显式开启梯度跟踪,默认DataLoader加载出的图像张量不会自动记录梯度,需要调用
attach_grad()方法手动开启 - 反向传播完成后,直接读取输入图像张量的
grad属性即可得到对应梯度 - 如果不需要更新模型参数,建议关闭模型参数的梯度计算,节省显存和计算资源
修改后的adv_loader循环代码如下:
for ixl,batch in enumerate(adv_loader): data = mx.gluon.utils.split_and_load(batch[0], ctx_list=ctx, batch_axis=0) fixed_targets = [mx.gluon.utils.split_and_load(batch[it], ctx_list=ctx, batch_axis=0) for it in range(1, 6)] gt_boxes = mx.gluon.utils.split_and_load(batch[6], ctx_list=ctx, batch_axis=0) sum_losses = [] # 给每个输入图像张量开启梯度跟踪 for x in data: x.attach_grad() with autograd.record(): for ix, x in enumerate(data): obj_loss, center_loss, scale_loss, cls_loss = net(x, gt_boxes[ix], *[ft[ix] for ft in fixed_targets]) sum_loss = obj_loss + center_loss + scale_loss + cls_loss sum_losses.append(sum_loss) # 反向传播计算梯度 autograd.backward(sum_losses, retain_graph=True) # 读取每个输入批次的梯度 for ix, x in enumerate(data): # x.grad就是当前批次输入图像对应的梯度 grad_np = x.grad.asnumpy() print(f"批次{ix}梯度形状:{grad_np.shape},梯度均值:{grad_np.mean()}") # 只取第一个批次就退出可以加break,不需要就去掉 break
额外注意事项
- 如果你需要的是模型参数的梯度而非输入图像的梯度,遍历
net.collect_params().values()读取每个参数的grad属性即可 - 计算输入梯度时不需要调用
trainer.step(),避免误更新模型权重 - 如果你之前开启了
net.hybridize()遇到梯度获取异常,可以先注释掉hybridize相关代码,用动态图模式计算梯度更稳定
内容的提问来源于stack exchange,提问作者mlanier
相关产品推荐
相关产品推荐

