了解 YOLO 是如何训练的

Understanding How YOLO is trained

我想了解 YOLO (v2) 是如何训练的。为此,我使用这个 keras 实现 https://github.com/experiencor/keras-yolo2 在 VOC 数据集上从头开始训练 YOLO(我对其他实现持开放态度,但我从未使用过 pytorch,因此,keras 实现将是首选)。

1- 据我了解 YOLO,它首先在 imageNet 上进行分类训练,然后在训练 yolo 进行回归(检测边界框)时应在某处使用这些训练的权重(用于分类)。在我在互联网上找到的大多数从头开始训练 yolo(用于回归)的代码中,我没有看到加载这些分类权重的部分。这是什么时候发生的?训练yolo回归时使用的分类权重是什么时候?

2-我在1)中描述的理解是否正确?

提前致谢

我先回答你问题的第二部分

在对象检测中标记图像时,会生成一个标签文件,其中包含边界框坐标和 object/objects 的 classification/class。

experiencor 代码中,加载的预训练权重不是 class化权重,但它们同时具有坐标和 class每个图像中的对象名称转换为权重。 一旦你拥有它们或使用标签文件从头开始训练模型,模型就会使用图像和相应的标签文件进行训练,其中包含边界框坐标和图像中对象的 class 名称。

所以这里class化和回归训练一起发生。

如果您有疑问,请随时发表评论,如果它回答了您的问题,请打勾。

您有两个选择:

  • 对整个检测器(后端+前端,即class化网络+检测器)使用预训练权重。
  • 仅对后端使用预训练权重。

所有内容都在您提供的 link https://github.com/experiencor/keras-yolo2#2-edit-the-configuration-file 下方进行了解释。

在代码中,加载了整个模型的预训练权重here。这是可选的。

后端的预训练权重是强制性的(根据教程),在代码中完成 here (example for full Yolo). Note that you should have downloaded the backend weights before creating the model as stated in the tutorial or at the beginning of the file

编辑 1

如果您的 classes 数量发生变化,检测器部分(前端)中的过滤器数量将随着 classification 矢量大小的变化而变化。然而,即使 classes 的数量发生变化,后端(特征提取器,即 backbone)也保持不变。

您可以使用预训练的任何与 backbone 大小相匹配的预训练权重,但如果 classes 的数量不同,则对于整个网络您不能。例如,您不能将 Racoon 的权重用于狗和猫探测器。

由于Darknet和Keras的格式不同,不能使用YoloV2原始权重来初始化这个网络,你必须先将它们翻译成Keras格式。

如果你有足够的训练数据,可以只使用 backbone 预训练的权重。

请注意,还有一个名为迁移学习的附加选项。如果您有预训练网络(backbone 和前端),您可以提取 backbone 权重并使用它们来初始化您的网络 backbone.

编辑 2

不,前端和后端严格来说不是两个独立的网络:它们是两个链式网络。事实上,在大多数深度学习框架中,如 PyTorch、Keras 或 Tensorflow,任何层都可以被视为一个网络(全连接、卷积、MaxPool 等)。

A "networks" 只是一个表示任意复杂数学函数的对象,将输入映射到可以应用自动微分的输出(您必须定义前向和后向传播)。

在像 Yolo 这样的单次目标检测器中,将整个网络视为两个网络的链更相关:backbone探测器。这种表示允许更通用的构造和更广泛的调整(即使用性能更高的 backbone 或轻量级的)。

是的,你是对的,边界框回归和标签class化发生在整个网络的最末端,因此在前端。

前端可以有任意数量的层,唯一的限制是在它的最后一层,它应该遵守特定的通道大小(即给定数量的过滤器),它总是受 class你想要 classify.

通常最后一个输出层的通道数应该是numberOfClasses + 4,其中numberOfClasses包括背景class,其中数字4代表边界框的四个坐标。这个例子简化了很多,建议大家多看看Yolo论文,对网络结构有更深入的了解。

检测器网络中似乎只有一个可训练层(2D Conv here)。请注意输出的大小受 classes 的数量限制:self.nb_box * (4 + 1 + self.nb_class).

然后使用随机分布初始化该层参数。

关于你的最后一个问题,我认为你对迁移学习的过程是正确的,应该有效。