上篇内容:
YOLOV3项目实战1之 整体介绍与数据处理
YOLOV3提出论文:《Yolov3: An incremental improvement》
模型创建函数 位置:项目 / utils / models.py / def create_modules
def create_modules(module_defs):
hyperparams = module_defs.pop(0)
output_filters = [int(hyperparams["channels"])]
module_list = nn.ModuleList()
for module_i, module_def in enumerate(module_defs):
modules = nn.Sequential()
if module_def["type"] == "convolutional":(暂时省略)
elif module_def["type"] == "maxpool":(暂时省略)
elif module_def["type"] == "upsample":(暂时省略)
elif module_def["type"] == "route":(暂时省略)
elif module_def["type"] == "shortcut":(暂时省略)
elif module_def["type"] == "yolo":(暂时省略)
module_list.append(modules)
output_filters.append(filters)
return hyperparams, module_list
module_list.append(modules)
这一行代码将当前处理的模块的层次结构 modules 添加到神经网络模型的 module_list 中。module_list 是一个 PyTorch ModuleList 对象,它用于存储神经网络的各个模块(例如卷积层、池化层、激活函数等)output_filters.append(filters)
:这一行代码将当前处理的模块的输出通道数 filters 添加到 output_filters 列表中。output_filters 用于跟踪每个模块的输出通道数,以便在构建下一个模块时确定输入通道数。在4中介绍了模型创建函数,但是if判断语句中没有给出内容,在5介绍一下卷积层是如何处理的
if module_def["type"] == "convolutional":
bn = int(module_def["batch_normalize"])
filters = int(module_def["filters"])
kernel_size = int(module_def["size"])
pad = (kernel_size - 1) // 2
modules.add_module(
f"conv_{module_i}",
nn.Conv2d(
in_channels=output_filters[-1],
out_channels=filters,
kernel_size=kernel_size,
stride=int(module_def["stride"]),
padding=pad,
bias=not bn,
),
)
if bn:
modules.add_module(f"batch_norm_{module_i}", nn.BatchNorm2d(filters, momentum=0.9, eps=1e-5))
if module_def["activation"] == "leaky":
modules.add_module(f"leaky_{module_i}", nn.LeakyReLU(0.1))
elif module_def["type"] == "maxpool":
kernel_size = int(module_def["size"])
stride = int(module_def["stride"])
if kernel_size == 2 and stride == 1:
modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1)))
maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2))
modules.add_module(f"maxpool_{module_i}", maxpool)
elif module_def["type"] == "maxpool":
:这个条件语句检查当前模块是否为最大池化层kernel_size = int(module_def["size"])
:解析模块配置中的池化核大小,将其转换为整数stride = int(module_def["stride"])
:解析模块配置中的池化层步幅,将其转换为整数if kernel_size == 2 and stride == 1:
:这一行代码检查是否满足一个特定条件,即池化核大小为2且步幅为1。如果满足这个条件,就执行下面的操作
modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1)))
:这里添加了一个用于调试的零填充层。具体来说,它使用 nn.ZeroPad2d
在输入图像的底部和右侧各添加一列零填充。这个填充的目的可能是为了处理特定情况下的池化层,以确保输出大小与输入大小一致。这个步骤通常是为了处理某些特殊情况而添加的modules
容器中:
maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2))
:创建最大池化层,其中包括池化核大小、步幅和填充大小的配置modules.add_module(f"maxpool_{module_i}", maxpool)
:将最大池化层添加到 modules
容器中,命名为 maxpool_{module_i}
,其中 module_i
是当前模块的索引通过上述操作,当前最大池化层的配置被解析,并相应地创建了相应的 PyTorch 模块,这些模块将在神经网络模型中用于后续的前向传播计算。最大池化层用于减小特征图的尺寸,以帮助网络提取更高级别的特征。
配置文件:项目位置\PyTorch-YOLOv3\config\yolov3.cfg
部分参数展示:
batch=16
subdivisions=1
width=416[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky
上面主要是一些训练参数,紧接着都是卷积的参数
模型文件:项目位置\PyTorch-YOLOv3\models.py
我们的主体模型在darknet.类中,是model.py文件中的一个类,实际上就是darknet53
在PyTorch深度学习框架中,用类来定义模型,类的构造函数用来定义模型的参数,forward函数用来定义前向传播计算方法
class Darknet(nn.Module):
def __init__(self, config_path, img_size=416):
super(Darknet, self).__init__()
self.module_defs = parse_model_config(config_path)
self.hyperparams, self.module_list = create_modules(self.module_defs)
self.yolo_layers = [layer[0] for layer in self.module_list if hasattr(layer[0], "metrics")]
self.img_size = img_size
self.seen = 0
self.header_info = np.array([0, 0, 0, self.seen, 0], dtype=np.int32)
这个构造函数,在读取参数的同时也定义了大部分的网络结构