@staticmethod
def make_res_layer(block,
inplanes,
planes,
blocks,
stride=(1, 1),
inflate=1,
inflate_style='3x1x1',
advanced=False,
norm_cfg=None,
act_cfg=None,
conv_cfg=None):
"""Build residual layer for ResNet3D.
Args:
block (nn.Module): Residual module to be built.
inplanes (int): Number of channels for the input feature in each block.
planes (int): Number of channels for the output feature in each block.
blocks (int): Number of residual blocks.
stride (tuple[int]): Stride (temporal, spatial) in residual and conv layers. Default: (1, 1).
inflate (int | tuple[int]): Determine whether to inflate for each block. Default: 1.
inflate_style (str): '3x1x1' or '3x3x3'. which determines the kernel sizes and padding strides
for conv1 and conv2 in each block. Default: '3x1x1'.
conv_cfg (dict | None): Config for norm layers. Default: None.
norm_cfg (dict | None): Config for norm layers. Default: None.
act_cfg (dict | None): Config for activate layers. Default: None.
Returns:
nn.Module: A residual layer for the given config.
"""
inflate = inflate if not isinstance(inflate, int) else (inflate, ) * blocks
assert len(inflate) == blocks
downsample = None
if stride[1] != 1 or inplanes != planes * block.expansion:
if advanced:
conv = ConvModule(
inplanes,
planes * block.expansion,
kernel_size=1,
stride=1,
bias=False,
conv_cfg=conv_cfg,
norm_cfg=norm_cfg,
act_cfg=None)
pool = nn.AvgPool3d(
kernel_size=(stride[0], stride[1], stride[1]),
stride=(stride[0], stride[1], stride[1]),
ceil_mode=True)
downsample = nn.Sequential(conv, pool)
else:
downsample = ConvModule(
inplanes,
planes * block.expansion,
kernel_size=1,
stride=(stride[0], stride[1], stride[1]),
bias=False,
conv_cfg=conv_cfg,
norm_cfg=norm_cfg,
act_cfg=None)
layers = []
layers.append(
block(
inplanes,
planes,
stride=stride,
downsample=downsample,
inflate=(inflate[0] == 1),
inflate_style=inflate_style,
norm_cfg=norm_cfg,
conv_cfg=conv_cfg,
act_cfg=act_cfg))
inplanes = planes * block.expansion
for i in range(1, blocks):
layers.append(
block(
inplanes,
planes,
stride=(1, 1),
inflate=(inflate[i] == 1),
inflate_style=inflate_style,
norm_cfg=norm_cfg,
conv_cfg=conv_cfg,
act_cfg=act_cfg))
return nn.Sequential(*layers)
def make_res_layer(block,
inplanes,
planes,
blocks,
stride=(1, 1),
inflate=1,
inflate_style='3x1x1',
advanced=False,
norm_cfg=None,
act_cfg=None,
conv_cfg=None):
"""Build residual layer for ResNet3D.
Args:
block (nn.Module): Residual module to be built.
inplanes (int): Number of channels for the input feature in each block.
planes (int): Number of channels for the output feature in each block.
blocks (int): Number of residual blocks.
stride (tuple[int]): Stride (temporal, spatial) in residual and conv layers. Default: (1, 1).
inflate (int | tuple[int]): Determine whether to inflate for each block. Default: 1.
inflate_style (str): '3x1x1' or '3x3x3'. which determines the kernel sizes and padding strides
for conv1 and conv2 in each block. Default: '3x1x1'.
conv_cfg (dict | None): Config for norm layers. Default: None.
norm_cfg (dict | None): Config for norm layers. Default: None.
act_cfg (dict | None): Config for activate layers. Default: None.
Returns:
nn.Module: A residual layer for the given config.
"""
这段代码定义了一个名为 make_res_layer
的函数,用于建立 ResNet3D 模型的残差层。下面是函数参数的中文解释:
block (nn.Module)
: 要构建的残差模块。inplanes (int)
: 每个块的输入特征通道数。planes (int)
: 每个块的输出特征通道数。blocks (int)
: 残差块的数量。stride (tuple[int])
: 残差层和卷积层的步长(时间维度,空间维度)。默认为 (1, 1)。inflate (int | tuple[int])
: 决定是否在每个块中进行膨胀。默认为 1。inflate_style (str)
: '3x1x1' 或 '3x3x3',决定了每个块中 conv1 和 conv2 的核大小和填充步长。默认为 '3x1x1'。conv_cfg (dict | None)
: 卷积层配置,默认为 None。norm_cfg (dict | None)
: 归一化层配置,默认为 None。act_cfg (dict | None)
: 激活层配置,默认为 None。
这个函数会返回一个包含指定残差层配置的 PyTorch 模块。
inflate = inflate if not isinstance(inflate, int) else (inflate, ) * blocks
assert len(inflate) == blocks
downsample = None
if stride[1] != 1 or inplanes != planes * block.expansion:
if advanced:
conv = ConvModule(
inplanes,
planes * block.expansion,
kernel_size=1,
stride=1,
bias=False,
conv_cfg=conv_cfg,
norm_cfg=norm_cfg,
act_cfg=None)
pool = nn.AvgPool3d(
kernel_size=(stride[0], stride[1], stride[1]),
stride=(stride[0], stride[1], stride[1]),
ceil_mode=True)
downsample = nn.Sequential(conv, pool)
else:
downsample = ConvModule(
inplanes,
planes * block.expansion,
kernel_size=1,
stride=(stride[0], stride[1], stride[1]),
bias=False,
conv_cfg=conv_cfg,
norm_cfg=norm_cfg,
act_cfg=None)
这段代码中的每一行解释如下:
-
inflate = inflate if not isinstance(inflate, int) else (inflate, ) * blocks
- 如果
inflate
不是一个整数,那么保持原值;否则将其转换为一个元组,并将其重复blocks
次。
- 如果
-
assert len(inflate) == blocks
- 断言
inflate
的长度与blocks
的值相等。
- 断言
-
downsample = None
- 初始化
downsample
为None
。
- 初始化
-
if stride[1] != 1 or inplanes != planes * block.expansion:
- 如果空间维度的步长不为 1,或者输入通道数与输出通道数 (
planes * block.expansion
) 不匹配,则执行以下操作。
- 如果空间维度的步长不为 1,或者输入通道数与输出通道数 (
-
if advanced:
- 如果
advanced
为True
,则使用更复杂的下采样方式。
- 如果
-
conv = ConvModule(inplanes, planes * block.expansion, kernel_size=1, stride=1, bias=False, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None)
- 创建一个 1x1 卷积层,用于调整通道数。
-
pool = nn.AvgPool3d(kernel_size=(stride[0], stride[1], stride[1]), stride=(stride[0], stride[1], stride[1]), ceil_mode=True)
- 创建一个平均池化层,用于执行下采样。
-
downsample = nn.Sequential(conv, pool)
- 将卷积层和池化层组合成一个
downsample
模块。
- 将卷积层和池化层组合成一个
-
else:
- 如果
advanced
为False
,则使用更简单的下采样方式。
- 如果
-
downsample = ConvModule(inplanes, planes * block.expansion, kernel_size=1, stride=(stride[0], stride[1], stride[1]), bias=False, conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=None)
- 创建一个 1x1 卷积层,用于执行下采样。
总的来说,这段代码确定了是否需要下采样,并根据 advanced
标志选择不同的下采样方式。
layers = []
layers.append(
block(
inplanes,
planes,
stride=stride,
downsample=downsample,
inflate=(inflate[0] == 1),
inflate_style=inflate_style,
norm_cfg=norm_cfg,
conv_cfg=conv_cfg,
act_cfg=act_cfg))
inplanes = planes * block.expansion
这段代码继续实现 make_res_layer
函数的功能。下面是每一行的解释:
-
layers = []
- 初始化一个空的列表
layers
。
- 初始化一个空的列表
-
layers.append()
- 向
layers
列表中添加一个元素。
- 向
-
block(inplanes, planes, stride=stride, downsample=downsample, inflate=(inflate[0] == 1), inflate_style=inflate_style, norm_cfg=norm_cfg, conv_cfg=conv_cfg, act_cfg=act_cfg)
- 创建一个
block
模块实例,并传入以下参数:inplanes
: 输入通道数planes
: 输出通道数stride
: 步长downsample
: 下采样模块inflate
: 是否膨胀,取决于inflate[0]
的值inflate_style
: 膨胀的样式norm_cfg
: 归一化层配置conv_cfg
: 卷积层配置act_cfg
: 激活层配置
- 创建一个
-
inplanes = planes * block.expansion
- 更新
inplanes
的值为planes * block.expansion
。这是因为每个残差块的输出通道数是planes * block.expansion
。
- 更新
通过这段代码,我们创建了一个包含一个残差块的列表 layers
,并更新了 inplanes
的值,为下一个残差块的创建做好准备。
for i in range(1, blocks):
layers.append(
block(
inplanes,
planes,
stride=(1, 1),
inflate=(inflate[i] == 1),
inflate_style=inflate_style,
norm_cfg=norm_cfg,
conv_cfg=conv_cfg,
act_cfg=act_cfg))
return nn.Sequential(*layers)
这段代码继续实现 make_res_layer
函数的功能。下面是每一行的中文解释:
-
for i in range(1, blocks):
- 从 1 开始,循环
blocks-1
次。这是因为第 0 个块已经在前面创建了。
- 从 1 开始,循环
-
layers.append()
- 向
layers
列表中添加一个元素。
- 向
-
block(inplanes, planes, stride=(1, 1), inflate=(inflate[i] == 1), inflate_style=inflate_style, norm_cfg=norm_cfg, conv_cfg=conv_cfg, act_cfg=act_cfg)
- 创建一个
block
模块实例,并传入以下参数:inplanes
: 输入通道数planes
: 输出通道数stride
: 步长设为 (1, 1)inflate
: 是否膨胀,取决于inflate[i]
的值inflate_style
: 膨胀的样式norm_cfg
: 归一化层配置conv_cfg
: 卷积层配置act_cfg
: 激活层配置
- 创建一个
-
return nn.Sequential(*layers)
- 将
layers
列表中的所有元素组装成一个 PyTorch 的nn.Sequential
模块,并返回。
- 将
通过这段代码,我们创建了剩余的 blocks-1
个残差块,并将它们组装成一个 nn.Sequential
模块返回。这就完成了 make_res_layer
函数的实现。