【问题标题】:GluonCV object detection fine-tuning - Select which layers are modified (freeze the rest)GluonCV 对象检测微调 - 选择修改哪些层(冻结其余层)
【发布时间】:2020-11-16 14:15:37
【问题描述】:

我有一个关于使用 GluonCV 微调预训练对象检测模型的过程的问题,如 this tutorial 中所述。

据我了解,所描述的过程会修改模型中的所有权重值。 我只想微调网络末端的全连接层,并冻结其余的权重。

我假设我应该在创建 Trainer 时指定要修改的参数:

trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.001, 'wd': 0.0005, 'momentum': 0.9})

所以,我应该列出我对训练感兴趣的参数,而不是 net.collect_params(),然后正常运行该过程的其余部分。 但是,我不知道如何精确隔离这些参数……我尝试打印:

params = net.collect_params()

但是,在这个列表中,我不知道哪些对应于最终的 FC 层。有什么建议吗?

【问题讨论】:

  • 您找到解决方案了吗?
  • 很遗憾没有:(

标签: object-detection mxnet mxnet-gluon


【解决方案1】:

假设我们有一个用于分类任务的预训练 Gluon 模型:

>>> import mxnet as mx
>>> net = mx.gluon.nn.HybridSequential()
>>> net.add(mx.gluon.nn.Conv2D(channels=6, kernel_size=5, padding=2, activation='sigmoid'))
>>> net.add(mx.gluon.nn.MaxPool2D(pool_size=2, strides=2))
>>> net.add(mx.gluon.nn.Flatten())
>>> net.add(mx.gluon.nn.Dense(units=10))
>>> net.collect_params()
hybridsequential0_ (
  Parameter conv0_weight (shape=(6, 0, 5, 5), dtype=<class 'numpy.float32'>)
  Parameter conv0_bias (shape=(6,), dtype=<class 'numpy.float32'>)
  Parameter dense0_weight (shape=(1, 0), dtype=float32)
  Parameter dense0_bias (shape=(1,), dtype=float32)
)

为了微调这个卷积网络,我们想要冻结除Dense之外的所有块。

首先,请记住 collect_params 方法接受一个正则表达式字符串,以通过名称(或前缀;Conv2DDense 或任何其他 Gluon(混合)块的 prefix 参数)选择特定的块参数。默认情况下,前缀是类名,即如果一个块是Conv2D,那么前缀是conv0_conv1_等。此外,collect_params返回一个mxnet.gluon.parameter.ParameterDict的实例,它有setattr方法。

解决方案:

>>> conv_params = net.collect_params('(?!dense).*')
>>> conv_params.setattr('grad_req', 'null')

或者干脆

>>> net.collect_params('(?!dense).*').setattr('grad_req', 'null')

这里我们排除所有匹配dense的参数,只得到conv块,并将它们的grad_req属性设置为'null'。现在,使用mxnet.gluon.Trainer 训练模型net 将只更新dense 参数。


拥有一个带有单独属性的预训练模型会更方便,这些属性表示特定的块,例如特征块、锚生成器等。在我们的例子中,我们有一个卷积网络,用于提取特征并将它们传递给输出块。

class ConvNet(mx.gluon.nn.HybridSequential):
    def __init__(self, n_classes, params=None, prefix=None):
        super().__init__(params=params, prefix=prefix)

        self.features = mx.gluon.nn.HybridSequential()
        self.features.add(mx.gluon.nn.Conv2D(channels=6, kernel_size=5, padding=2,
                          activation='sigmoid'))
        self.add(mx.gluon.nn.MaxPool2D(pool_size=2, strides=2))
        self.add(mx.gluon.nn.Flatten())

        self.output = mx.gluon.nn.Dense(units=n_classes)

    def hybrid_forward(self, F, x):
        x = self.features(x)
        return self.output(x)

通过这个 convnet 声明,我们不必使用正则表达式来访问所需的块:

>>> net = ConvNet(n_classes=10)
>>> net.features.collect_params().setattr('grad_req', 'null')

Gluon CV 模型完全遵循这种模式。请参阅所需模型的文档并选择要冻结的块。如果文档为空,请运行 collect_params 查看所有参数并使用正则表达式过滤掉要微调的参数并将返回的参数'grad_req 设置为'null'

【讨论】:

    猜你喜欢
    • 2021-12-18
    • 2021-09-24
    • 1970-01-01
    • 2023-03-22
    • 2019-09-21
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    相关资源
    最近更新 更多