在阅读源码时,遇到了这样的情况:
# Build resnet.
self.RCNN_base = nn.Sequential(resnet.conv1, resnet.bn1, resnet.relu,
resnet.maxpool, resnet.layer1, resnet.layer2, resnet.layer3)
self.RCNN_top = nn.Sequential(resnet.layer4)
self.RCNN_cls_score = nn.Linear(2048, self.n_classes)
if self.class_agnostic:
self.RCNN_bbox_pred = nn.Linear(2048, 4)
else:
self.RCNN_bbox_pred = nn.Linear(2048, 4 * self.n_classes)
# Fix blocks
for p in self.RCNN_base[0].parameters(): p.requires_grad=False
for p in self.RCNN_base[1].parameters(): p.requires_grad=False
assert (0 <= cfg.RESNET.FIXED_BLOCKS < 4)
if cfg.RESNET.FIXED_BLOCKS >= 3:
for p in self.RCNN_base[6].parameters(): p.requires_grad=False
if cfg.RESNET.FIXED_BLOCKS >= 2:
for p in self.RCNN_base[5].parameters(): p.requires_grad=False
if cfg.RESNET.FIXED_BLOCKS >= 1:
for p in self.RCNN_base[4].parameters(): p.requires_grad=False
然后我们在config.py中可以找到对应的参数设置__C.RESNET.FIXED_BLOCKS = ``1
所以说默认情况下对resnet.conv1,resnet.bn1,resnet.layer1
不进行梯度的更新。
随后这些参数会被传入到trainval_net.py中的这里:
params = []
for key, value in dict(fasterRCNN.named_parameters()).items():
if value.requires_grad:
if 'bias' in key:
params += [{'params':[value],'lr':lr*(cfg.TRAIN.DOUBLE_BIAS + 1), \
'weight_decay': cfg.TRAIN.BIAS_DECAY and cfg.TRAIN.WEIGHT_DECAY or 0}]
else:
params += [{'params':[value],'lr':lr, 'weight_decay': cfg.TRAIN.WEIGHT_DECAY}]
if args.cuda:
fasterRCNN.cuda()
if args.optimizer == "adam":
lr = lr * 0.1
optimizer = torch.optim.Adam(params)
elif args.optimizer == "sgd":
optimizer = torch.optim.SGD(params, momentum=cfg.TRAIN.MOMENTUM)
对没有被阻止梯度更新的层进行优化。
总结
for p in self.RCNN_base[0].parameters(): p.requires_grad=False
这类代码的作用是:特征层中参数都固定住,不会发生梯度的更新。确定是否计算导数的,所以可以减少计算量,也就是不用求w和b的导数了,减少了计算量。只传播误差,而不计算权重和偏执的导数。
随后在进行梯度更新,也就是把参数放入要训练的网络时,在传入优化器之前,需要重新过滤一遍,所以有了以上优化器之前的代码。