自学内容网 自学内容网

是YOLOv3的网络构建

YOLOv3的网络构建是一个从配置文件(cfg文件)到创建模型并定义其前向传播过程的复杂过程,以下是详细说明:

1. cfg文件

  • 作用和支持的层类型
    • 在YOLOv3中,cfg文件用于描述网络结构。通过修改cfg文件,可以很容易地调整网络架构。
    • 它支持多种层类型,包括convolutional(卷积层)、maxpool(最大池化层)、upsample(上采样层)、route(特征图连接层)、shortcut(跨层连接层,类似ResNet的shortcut连接)、yolo(YOLO检测层)等。
  • 网络结构可视化
    • 为了更直观地理解cfg文件所描述的网络结构,可以使用一些工具,如Netron。以yolov3 - tiny.cfg为例,通过Netron可视化可以清晰地看到网络的输入输出以及各层之间的连接关系。

2. 网络模型构建

2.1 module_defs
  • 解析cfg文件得到module_defs
    • 通过parse_model_cfg函数解析cfg文件,得到module_defs对象。这个对象是一个包含多个字典的列表,每个字典保存了一个模块的相关信息。
    • 例如,对于卷积层模块,字典中可能包含batch_normalize(是否进行BN操作)、filters(输出特征图数量)、size(卷积核尺寸)、stride(卷积步长)、pad(填充大小)、activation(激活函数类型)等键值对。
  • 解析过程中的参数处理
    • 在解析过程中,函数会去除cfg文件中以#开头的注释行,然后逐行解析。当遇到[开头的行时,表示一个新模块的开始,会创建一个新的字典并添加到module_defs列表中。
    • 对于不同类型的模块,会根据其特定的参数格式进行解析。例如,对于convolutional层,如果batch_normalize为1,则在字典中设置相应的值;对于anchors参数,会将其解析为numpy数组形式。同时,函数还会检查所有解析出的参数是否符合支持的参数类型列表,如果存在不支持的字段,会抛出异常。
2.2 module_list&routs
  • 构建ModuleList和routs
    • 通过create_modules函数,根据module_defs构建ModuleListroutsModuleList类似于一个模块的列表,用于存储网络中的各个层;routs则用于存储一些层的索引信息,在routeshortcut操作中会用到。
  • 不同层类型的构建方式
    • 卷积层:对于convolutional类型的模块,根据解析出的参数创建nn.Conv2d层,并根据是否进行BN操作添加nn.BatchNorm2d层,以及设置相应的激活函数层(如nn.LeakyReLU)。同时,根据不同的激活函数类型和模型配置(如arc参数),可能会有不同的设置。
    • 最大池化层:对于maxpool类型的模块,创建nn.MaxPool2d层,并根据sizestride参数设置池化大小和步长。如果size == 2stride == 1(如在yolov3 - tiny中某些情况),还会添加nn.ZeroPad2d层进行填充。
    • 上采样层:对于upsample类型的模块,创建nn.Upsample层,并根据stride参数设置上采样因子。
    • Route层:对于route类型的模块,根据layers参数指定的层索引,计算输出特征图的通道数(通过对相应层的输出通道数求和),并将指定的层索引添加到routs中。
    • Shortcut层:对于shortcut类型的模块,根据from参数指定的索引,获取相应层的输出特征图通道数,并将相关索引添加到routs中。
    • yolo层:对于yolo类型的模块,创建YOLOLayer层,设置anchorsnc(类别数量)、img_size等参数。同时,根据不同的arc参数,会对卷积层的bias进行特殊设置。例如,对于defaultFdefaultpw等不同的arc值,会设置不同的objclsbias值,以解决样本不平衡问题,具体是在原有bias基础上进行调整,使其在初始训练阶段避免过度激活,提高模型训练的稳定性和性能。
2.3 yolo_layers
  • 获取yolo层的序号
    • 通过get_yolo_layers函数获取yolo层在整个模型中的序号。该函数通过解析module_defs,查找类型为yolo的模块,并返回其在列表中的索引。例如,对于yolov3.cfg文件,可能返回[82, 94, 106]等序号,表示第83、94、106个层是yolo层。

3. forward函数

  • 前向传播过程描述
    • forward函数中,实现了模型的前向传播过程。它通过遍历module_defsmodule_list中的模块,根据模块类型进行相应的操作。
  • 不同层类型在前向传播中的处理
    • 卷积层、上采样层、池化层:对于convolutionalupsamplemaxpool类型的模块,直接调用相应模块的forward函数进行前向传播,将输入数据传递给下一层。
    • Route层:对于route类型的模块,如果layers参数只有一个值,则直接获取对应层的输出作为当前层的输出;如果有多个值,则将指定的多层输出在通道维度上进行拼接(使用torch.cat函数)作为当前层的输出。如果在拼接过程中遇到darknet reorg层相关的情况,可能需要对其中一层进行下采样操作(使用F.interpolate函数)后再进行拼接。
    • Shortcut层:对于shortcut类型的模块,将当前层的输入与指定层(根据from参数)的输出相加作为当前层的输出。
    • yolo层:对于yolo类型的模块,调用YOLOLayerforward函数进行处理,并将输出添加到output列表中。如果是训练模式,直接返回output列表;如果是测试模式或ONNX_EXPORT模式,则根据不同的模式要求对output列表进行进一步处理,如在测试模式下,对输出进行一些后处理操作(如对坐标进行激活函数处理、根据arc参数对类别进行处理等),并将处理后的结果进行适当的形状调整后返回。
      YOLOv3的前向传播过程是数据在网络中依次经过各个层进行处理的过程,以下是详细解释:

4. YOLOv3 的前向传播过程

forward函数中实现了前向传播过程。它通过遍历module_defs(存储cfg文件解析后的模块信息)和module_list(构建的网络模块列表)中的模块,根据模块类型进行相应的操作,最终得到YOLO层的输出。

5. 不同层类型的处理

卷积层、上采样层、池化层
  • 对于convolutional(卷积层)、upsample(上采样层)、maxpool(最大池化层)类型的模块,在前向传播过程中只需要经过相应模块的forward函数即可。
  • 即直接将输入数据x传递给模块的forward函数进行处理,得到输出后继续传递给下一层。例如对于卷积层,会进行卷积运算、BN操作(如果有)以及激活函数操作(如果有)。
Route层
  • Route层用于将几个层的内容进行拼接。
  • 首先获取layers参数指定的层索引,如果layers只有一个值,那么直接获取对应层的输出作为当前层的输出,即x = layer_outputs[layers[0]]
  • 如果layers有多个值,尝试将指定的多层输出在通道维度上进行拼接(使用torch.cat函数)。如果在拼接过程中遇到问题(例如可能涉及darknet reorg层相关的情况),可能需要对其中一层进行下采样操作(使用F.interpolate函数),然后再进行拼接,最终得到x = torch.cat([layer_outputs[i] for i in layers], 1)
Shortcut层
  • Shortcut层类似于ResNet的跨层连接操作。
  • 它将当前层的输入与指定层(根据from参数)的输出相加作为当前层的输出,即x = x + layer_outputs[int(mdef['from'])]
yolo层
  • 对于yolo类型的模块,调用YOLOLayerforward函数进行处理,并将输出添加到output列表中。
  • 在训练模式下,如果self.trainingTrue,则直接返回output列表,这个列表包含了各个yolo层的输出,符合YOLO要求的Tensor格式。
  • 在测试模式或ONNX_EXPORT模式下:
    • 如果是ONNX_EXPORT模式,需要对output进行一些特殊处理,例如将output中的数据进行拼接和调整形状,最终返回符合ONNX格式要求的结果。
    • 在测试模式下,首先获取output列表中的数据,对其进行一些后处理操作。例如对于坐标部分,会根据公式进行激活函数处理(如io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid_xy),根据arc参数对类别部分进行处理(如使用sigmoidsoftmax等激活函数),然后将处理后的结果进行适当的形状调整(如return io.view(bs, -1, self.no), p)后返回。

6. 记录中间结果

在整个前向传播过程中,使用layer_outputs列表记录每个层的输出(除了route层中不需要记录的部分),以便后续层使用。例如,shortcut层和route层(部分情况)会用到前面层的输出。同时,根据不同的阶段(训练、测试、ONNX_EXPORT),对最终的输出进行相应的处理和返回。


原文地址:https://blog.csdn.net/mozf881/article/details/142799472

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!