遇到问题发现并网上并没有相似的情况和解答,记录一下Pytorch BatchNorm踩的坑。
问题描述
- 保存训练好了的一个目标检测模型a,然后设计的新模型b有部分结构和a相同,backbone和fpn均为相同的结构,除了检测头略有区别。
- 创建新模型b,并加载模型a相同部分的state_dict,固定backbone和fpn部分,finetune模型b的检测头。但是感觉结果有问题,于是开始寻找问题根源。
- 经过一番查找,发现模型a经过训练后backbone输出的结果竟然和模型b的backbone输出结果不一样???这是什么情况?设置backbone每层的requires_grad为False,但是没有固定住???
原因
经过debug,发现是batchnorm2d这一层输出有问题,问题出在running_mean和running_var。这两个变量不是可学习参数,而是存在buffer中的,在torch.save_state_dict() 的时候会保存起来,但是在被加载后,当模型设置为.train()
的finetune的时候还是会进行变化,也就是说用requires_grad=False
并不能将这两个变量固定住,只能将bn.weights
和bn.bias
固定住,每一次训练还是会改变两个变量的值。而在推理阶段,模型设置为.eval()
的时候,这两个变量是固定住的,而且bn在此阶段计算时使用的就是ru