
这篇文章主要为记录DETR模型的构建过程
首先明确DETR模型的搭建顺序:首先是backbone的搭建,使用的是resnet50,随后是Transformer模型的构建,包含编码器的构建与解码器的构建,完成后则是整个DETR模型的构建
构建代码在detr.py文件中
# 搭建主干网络
backbone = build_backbone(args)
# 搭建transfoemer
transformer = build_transformer(args)
# 搭建DETR模型
model = DETR(
backbone,
transformer,
num_classes=num_classes,
num_queries=args.num_queries,
aux_loss=args.aux_loss,
)
我们来沿着这个代码逐步了解其构造
骨干网络构建
进入 backbone.py 的 build_backbone() 方法
def build_backbone(args):
#搭建位置编码器
position_embedding = build_position_encoding(args)
#args.lr_backbone默认为1e-5,则train_backbone默认为true,通过设置backbone的lr来设置是否训练网络时
# 接收backbone的梯度从而让backbone也训练。
train_backbone = args.lr_backbone > 0
#是否需要记录backbone的每层输出
return_interm_layers = args.masks
#构建骨干网络 args.backbone默认为resnet50,args.dilatyion默认为false。
backbone = Backbone(args.backbone, train_backbone, return_interm_layers, args.dilation)
# 将backbone和位置编码器集合在一起放在一个model里
model = Joiner(backbone, position_embedding)
# 设置model的输出通道数
model.num_channels = backbone.num_channels
return model
位置编码器构建
首先是位置编码器构造,进入position_encoding.py文件(注意位置编码最后是加上去的,故其前后维度不会发生变化。
def build_position_encoding(args):
#args.hidden_dim transformer的输入张量的channel数,位置编码和backbone的featuremap结合后需要输入到transformer中
N_steps = args.hidden_dim // 2
# 余弦编码方式,文章说采用正余弦函数,是根据归纳偏置和经验做出的选择
if args.position_embedding in ('v2', 'sine'):
# TODO find a better way of exposing other arguments
#PositionEmbeddingSine(N_steps, normalize=True):正余弦编码方式,这种方式是将各个位置的各个维度映射到角度上,
# 因此有个scale,默认是2pi。
position_embedding = PositionEmbeddingSine(N_steps, normalize=True)
# 可学习的编码方式
elif args.position_embedding in ('v3', 'learned'):
position_embedding = PositionEmbeddingLearned(N_steps)
else:
raise ValueError(f"not supported {
args.position_embedding}")
return position_embedding
返回的位置编码信息如下:

resnet50网络构建
随后使用pytorch的model库进行resnet50网络的构建
def __init__(self, name: str,
train_backbone: bool,
return_interm_layers: bool,
dilation: bool):
# getattr(obj,name)获取obj中命名为name的组成。可以理解为获取obj.name
# 获取torchvision.models中实现的resnet50网络结构
# replace_stride_with_dilation 决定是否使用膨胀卷积;pretrained 是否使用预训练模型;
# norm_layer 使用FrozenBatchNorm2d归一化方式
backbone = getattr(torchvision.models, name)(
replace_stride_with_dilation=[False, False, dilation],
pretrained=is_main_process(), norm_layer=FrozenBatchNorm2d)
#获得resnet50网络结构,并设置输出channels为2048,所以我们的backbone的输出则是
# (batch, 2048, H // 32,W // 32),在父类BackboneBase.__init__中进行初始化。
num_channels = 512 if name in ('resnet18', 'resnet34') else 2048
super().__init__(backbone, train_backbone, num_channels, return_interm_layers)
此时通过pytorch的model库获得的backbone为:其中已进行了相关参数的初始化

在最后其进入其父类进行进一步设置,逐层设置是否进行梯度更新,其构建的resnet模型中已是预训练模型,有参数。
通过下图可以看到backbone的主要结构,通道数


随后通过model = Joiner(backbone, position_embedding)将位置编码器与backbone构建到一个model中。并通过model.num_channels = backbone.num_channels设置新构成的model的通道数与backbone的通道数一致为2048。
Joiner构造后的结构如下:

Joiner(
(0): Backbone(
(layer1): Sequential( )
(layer2): Sequential( )
(layer3): Sequential( )
(layer4): Sequential( )
)
(1): PositionEmbeddingSine()
)
详细结构如下:
Joiner(
(0): Backbone(
(body): IntermediateLayerGetter(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): FrozenBatchNorm2d()
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): Sequential(
(0): Bottleneck(
(conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): FrozenBatchNorm2d()
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): FrozenBatchNorm2d()
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): FrozenBatchNorm2d()
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(1): FrozenBatchNorm2d()
)
)
(1): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): FrozenBatchNorm2d()
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): FrozenBatchNorm2d()
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): FrozenBatchNorm2d()
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): FrozenBatchNorm2d()
(conv2): Conv2d(64, 64, kernel_size=

该文详细介绍了DETR模型的构建过程,包括使用ResNet50作为backbone,构建Transformer的编码器和解码器,以及位置编码器的设置。DETR模型通过Transformer将backbone的输出转换为检测结果,涉及多头注意力机制和残差连接等关键组件。
最低0.47元/天 解锁文章
2096





