在阅读源码时,遇到了这样的情况:

    1. # Build resnet.
    2. self.RCNN_base = nn.Sequential(resnet.conv1, resnet.bn1, resnet.relu,
    3. resnet.maxpool, resnet.layer1, resnet.layer2, resnet.layer3)
    4. self.RCNN_top = nn.Sequential(resnet.layer4)
    5. self.RCNN_cls_score = nn.Linear(2048, self.n_classes)
    6. if self.class_agnostic:
    7. self.RCNN_bbox_pred = nn.Linear(2048, 4)
    8. else:
    9. self.RCNN_bbox_pred = nn.Linear(2048, 4 * self.n_classes)
    10. # Fix blocks
    11. for p in self.RCNN_base[0].parameters(): p.requires_grad=False
    12. for p in self.RCNN_base[1].parameters(): p.requires_grad=False
    13. assert (0 <= cfg.RESNET.FIXED_BLOCKS < 4)
    14. if cfg.RESNET.FIXED_BLOCKS >= 3:
    15. for p in self.RCNN_base[6].parameters(): p.requires_grad=False
    16. if cfg.RESNET.FIXED_BLOCKS >= 2:
    17. for p in self.RCNN_base[5].parameters(): p.requires_grad=False
    18. if cfg.RESNET.FIXED_BLOCKS >= 1:
    19. 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中的这里:

    1. params = []
    2. for key, value in dict(fasterRCNN.named_parameters()).items():
    3. if value.requires_grad:
    4. if 'bias' in key:
    5. params += [{'params':[value],'lr':lr*(cfg.TRAIN.DOUBLE_BIAS + 1), \
    6. 'weight_decay': cfg.TRAIN.BIAS_DECAY and cfg.TRAIN.WEIGHT_DECAY or 0}]
    7. else:
    8. params += [{'params':[value],'lr':lr, 'weight_decay': cfg.TRAIN.WEIGHT_DECAY}]
    9. if args.cuda:
    10. fasterRCNN.cuda()
    11. if args.optimizer == "adam":
    12. lr = lr * 0.1
    13. optimizer = torch.optim.Adam(params)
    14. elif args.optimizer == "sgd":
    15. optimizer = torch.optim.SGD(params, momentum=cfg.TRAIN.MOMENTUM)

    对没有被阻止梯度更新的层进行优化。

    总结

    for p in self.RCNN_base[0].parameters(): p.requires_grad=False这类代码的作用是:特征层中参数都固定住,不会发生梯度的更新。确定是否计算导数的,所以可以减少计算量,也就是不用求w和b的导数了,减少了计算量。只传播误差,而不计算权重和偏执的导数。

    随后在进行梯度更新,也就是把参数放入要训练的网络时,在传入优化器之前,需要重新过滤一遍,所以有了以上优化器之前的代码。