【Head-DETR系列(7)】DETR 代码分析

在nuscens数据集上,

Results and Models

BackboneModelLr schdMem (GB)Inf time (fps)box APConfigDownload
R-50DETR150e7.940.1configmodel | log

在这里插入图片描述

我们先看检测器

/mmdetection-2.28.2/mmdet/models/detectors/detr.py

    def forward_train(self,img,img_metas,gt_bboxes,gt_labels,gt_bboxes_ignore=None):"""Args:img (Tensor): Input images of shape (N, C, H, W).Typically these should be mean centered and std scaled.img_metas (list[dict]): A List of image info dict where each dicthas: 'img_shape', 'scale_factor', 'flip', and may also contain'filename', 'ori_shape', 'pad_shape', and 'img_norm_cfg'.For details on the values of these keys see:class:`mmdet.datasets.pipelines.Collect`.gt_bboxes (list[Tensor]): Each item are the truth boxes for eachimage in [tl_x, tl_y, br_x, br_y] format.gt_labels (list[Tensor]): Class indices corresponding to each boxgt_bboxes_ignore (None | list[Tensor]): Specify which boundingboxes can be ignored when computing the loss.Returns:dict[str, Tensor]: A dictionary of loss components."""super(SingleStageDetector, self).forward_train(img, img_metas)x = self.extract_feat(img)losses = self.bbox_head.forward_train(x, img_metas, gt_bboxes,gt_labels, gt_bboxes_ignore)return losses

具体的代码

    def forward_single(self, x, img_metas): # 单独处理每个特征层 # construct binary masks which used for the transformer.# NOTE following the official DETR repo, non-zero values representing# ignored positions, while zero values means valid positions.batch_size = x.size(0)  # 获取Binput_img_h, input_img_w = img_metas[0]['batch_input_shape']  # 获取输入batch的shapemasks = x.new_ones((batch_size, input_img_h, input_img_w))  # Tensor [B, H, W] 默认为1 for img_id in range(batch_size):  # 遍历每张图像img_h, img_w, _ = img_metas[img_id]['img_shape']  # Resize后的图像尺寸masks[img_id, :img_h, :img_w] = 0  # 有效位置标记为0, 其余位置为1x = self.input_proj(x)  # 1*1卷积 特征降维  [B, C, H, W]# interpolate masks to have the same spatial shape with xmasks = F.interpolate(  # 将masks resize到和特征相同尺度masks.unsqueeze(1), size=x.shape[-2:]).to(torch.bool).squeeze(1)  # Tensor [B, H, W]# position encoding 通过配置文件可知positional_encoding为类SinePositionalEncodingpos_embed = self.positional_encoding(masks)  # [B, C, H, W]# outs_dec: [nb_dec, bs, num_query, embed_dim]# 由配置文件可知, transformer为类Transformerouts_dec, _ = self.transformer(x,  # Tensor [B, C, H, W]masks,  # Tensor [B, H, W]self.query_embedding.weight,  # Tensor [num_query, C]  可学习的querypos_embed)  # Tensor [B, C, H, W]# outs_dec: Tensor [num_layer, B, num_query, C] 经过transformer encode和decoder后的结果all_cls_scores = self.fc_cls(outs_dec)  #  初始化可知 fc_cls为全链接层 [num_layer, B, num_query, num_cls+1]all_bbox_preds = self.fc_reg(self.activate(self.reg_ffn(outs_dec))).sigmoid()  # 初始化可知 Sigmoid(Linear(ReLU(FFN(outs_dec)))) [num_layer, B, num_query, 4]return all_cls_scores, all_bbox_preds  # Tensor: [num_layer, B, num_query, num_cls+1], [num_layer, B, num_query, 4]

看 backbone

在这里插入图片描述stem部分 = 7*7conv + bn + relu + maxpool。这部分通常只是提取图像低级特征,故一般都需要固定这部分权重。

    backbone=dict(type='ResNet',depth=50,num_stages=4,  # assert num_stages >= 1 and num_stages <= 4 最大是4,最小是1# 表示本模块输出的特征图索引,(0, 1, 2, 3),表示4个 stage 输出都需要,(3, ),表示第4个 stage 输出都需要# 其对应的 stride 为 (4,8,16,32),channel 为 (256, 512, 1024, 2048)       out_indices=(3, ),frozen_stages=1,norm_cfg=dict(type='BN', requires_grad=False),norm_eval=True,style='pytorch',init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),

在这里插入图片描述

    arch_settings = {18: (BasicBlock, (2, 2, 2, 2)),34: (BasicBlock, (3, 4, 6, 3)),50: (Bottleneck, (3, 4, 6, 3)),   # ResNet-50101: (Bottleneck, (3, 4, 23, 3)),152: (Bottleneck, (3, 8, 36, 3))}# BasicBlock,Bottleneck都是一个单独的类,可以理解成模块#链接:https://blog.csdn.net/weixin_47691066/article/details/126032709

看 bbox_head

在这里插入图片描述

1、Transformer encoder部分首先将输入的特征图降维并flatten,然后送入下图左半部分所示的结构中,和空间位置编码一起并行经过多个自注意力分支、正则化和FFN,得到一组长度为N的预测目标序列。

2、接着,将Transformer encoder得到的预测目标序列经过上图右半部分所示的Transformer decoder,并行的解码得到输出序列(而不是像机器翻译那样逐个元素输出)。和传统的autogreesive机制不同,每个层可以解码N个目标,由于解码器的位置不变性,即调换输入顺序结果不变,除了每个像素本身的信息,位置信息也很重要,所以这N个输入嵌入必须不同以产生不同的结果,所以学习NLP里面的方法,加入positional encoding并且每层都加,作者非常用力的在处理position的问题,在使用 transformer 处理图片类的输入的时候,一定要注意position的问题。

    bbox_head=dict(type='DETRHead',num_classes=80,in_channels=2048,# 这个是 transformer 模块transformer=dict(type='Transformer',encoder=dict(type='DetrTransformerEncoder', # 编码器num_layers=6,# 一共六层transformerlayers=dict(type='BaseTransformerLayer', attn_cfgs=[dict(type='MultiheadAttention',# 多头注意力embed_dims=256,# 嵌入量维度256num_heads=8,# 多头数量8dropout=0.1)# 随机丢弃],feedforward_channels=2048,# 返回通道数2048ffn_dropout=0.1,operation_order=('self_attn', 'norm', 'ffn', 'norm'))),# 操作顺序,自注意力、norm、FFNdecoder=dict(type='DetrTransformerDecoder',# 解码器return_intermediate=True,num_layers=6,transformerlayers=dict(type='DetrTransformerDecoderLayer',attn_cfgs=dict(type='MultiheadAttention',# 多头embed_dims=256,num_heads=8,dropout=0.1),feedforward_channels=2048,ffn_dropout=0.1,operation_order=('self_attn', 'norm', 'cross_attn', 'norm','ffn', 'norm')),# 自注意力、交叉注意力、FFN)),

使用共享参数的FFNs(由一个具有ReLU激活函数和d维隐藏层的3层感知器和一个线性投影层构成)独立解码为包含类别得分和预测框坐标的最终检测结果(N个),FFN预测框的标准化中心坐标,高度和宽度w.r.t. 输入图像,然后线性层使用softmax函数预测类标签。

在这里插入图片描述

Transformer类位于mmdet/models/utils/transformer.py,如下class Transformer(BaseModule):"""Following the official DETR implementation, this module copy-pastefrom torch.nn.Transformer with modifications:* positional encodings are passed in MultiheadAttention* extra LN at the end of encoder is removed* decoder returns a stack of activations from all decoding layers"""def __init__(self, encoder=None, decoder=None, init_cfg=None):super(Transformer, self).__init__(init_cfg=init_cfg)self.encoder = build_transformer_layer_sequence(encoder)self.decoder = build_transformer_layer_sequence(decoder)self.embed_dims = self.encoder.embed_dimsdef forward(self, x, mask, query_embed, pos_embed):bs, c, h, w = x.shape# use `view` instead of `flatten` for dynamically exporting to ONNXx = x.view(bs, c, -1).permute(2, 0, 1)  # [B, C, H, W] -> [N, B, C]pos_embed = pos_embed.view(bs, c, -1).permute(2, 0, 1)  # [B, C, H, W] -> [N, B, C]query_embed = query_embed.unsqueeze(1).repeat(  # 直接复制可学习的query1, bs, 1)  # [num_query, C] -> [num_query, B, dim]mask = mask.view(bs, -1)  # [B, H, W] -> [B, N]memory = self.encoder(  # 由配置文件可知encoder为类DetrTransformerEncoderquery=x,  # [N, B, C]key=None,value=None,query_pos=pos_embed,  # [N, B, C]query_key_padding_mask=mask)  # [B, N]# memory:  Tensor [N, B, C]target = torch.zeros_like(query_embed)  # [num_query, B, dim]  全0# out_dec: [num_layers, num_query, bs, dim]out_dec = self.decoder(   # 由配置文件可知decoder为类DetrTransformerDecoderquery=target,key=memory,value=memory,key_pos=pos_embed,query_pos=query_embed,key_padding_mask=mask)  # out_dec: Tensor [num_layer, num_query, B, C]out_dec = out_dec.transpose(1, 2)   # [num_layer, B, num_query, C]memory = memory.permute(1, 2, 0).reshape(bs, c, h, w)  # [B, C, H, W]return out_dec, memoryclass DetrTransformerEncoder(TransformerLayerSequence):def __init__(self, *args, post_norm_cfg=dict(type='LN'), **kwargs):super(DetrTransformerEncoder, self).__init__(*args, **kwargs)if post_norm_cfg is not None:self.post_norm = build_norm_layer(post_norm_cfg, self.embed_dims)[1] if self.pre_norm else Noneelse:assert not self.pre_norm, f'Use prenorm in ' \f'{self.__class__.__name__},' \f'Please specify post_norm_cfg'self.post_norm = Nonedef forward(self, *args, **kwargs):# 调用父类TransformerLayerSequence中的forward方法, 而类TransformerLayerSequence集成在mmcv中 # mmcv.cnn.bricks.transformer 暂时不做解析x = super(DetrTransformerEncoder, self).forward(*args, **kwargs)if self.post_norm is not None:  # 不满足x = self.post_norm(x)return x # Tensor [N, B, C]class DetrTransformerDecoder(TransformerLayerSequence):def __init__(self,*args,post_norm_cfg=dict(type='LN'),return_intermediate=False,**kwargs):super(DetrTransformerDecoder, self).__init__(*args, **kwargs)self.return_intermediate = return_intermediateif post_norm_cfg is not None:self.post_norm = build_norm_layer(post_norm_cfg,self.embed_dims)[1]else:self.post_norm = Nonedef forward(self, query, *args, **kwargs):if not self.return_intermediate:  # 不满足x = super().forward(query, *args, **kwargs)if self.post_norm:x = self.post_norm(x)[None]return xintermediate = []  # 保存每个layer的输出结果  [num_query, B, C]for layer in self.layers:  # 遍历Decoder中的每个layer 由配置文件可知layer为类DetrTransformerDecoderLayer  # 实际上调用的是父类BaseTransformerLayer中的forward函数# 该类被封装在mmcv中,暂时不做解析query = layer(query, *args, **kwargs)if self.return_intermediate:  # 满足if self.post_norm is not None:  # 满足intermediate.append(self.post_norm(query)) else:intermediate.append(query)return torch.stack(intermediate) # 将每个layer的结果拼接在一起 [num_layer, num_query, B, C]class DetrTransformerDecoderLayer(BaseTransformerLayer):  def __init__(self,attn_cfgs,feedforward_channels,ffn_dropout=0.0,operation_order=None,act_cfg=dict(type='ReLU', inplace=True),norm_cfg=dict(type='LN'),ffn_num_fcs=2,**kwargs):super(DetrTransformerDecoderLayer, self).__init__(attn_cfgs=attn_cfgs,feedforward_channels=feedforward_channels,ffn_dropout=ffn_dropout,operation_order=operation_order,act_cfg=act_cfg,norm_cfg=norm_cfg,ffn_num_fcs=ffn_num_fcs,**kwargs)assert len(operation_order) == 6assert set(operation_order) == set(['self_attn', 'norm', 'cross_attn', 'ffn'])

看 positional_encoding

SinePositionalEncoding类位于mmdet/models/utils/positional_encoding.py,如下

        positional_encoding=dict(type='SinePositionalEncoding', num_feats=128, normalize=True),
class SinePositionalEncoding(BaseModule):def __init__(self,num_feats,temperature=10000,normalize=False,  scale=2 * math.pi,eps=1e-6,offset=0., init_cfg=None):super(SinePositionalEncoding, self).__init__(init_cfg)if normalize:assert isinstance(scale, (float, int)), 'when normalize is set,' \'scale should be provided and in float or int type, ' \f'found {type(scale)}'self.num_feats = num_feats  # 实际上等于feature特征channel的一半self.temperature = temperatureself.normalize = normalize  # 由配置可知为Trueself.scale = scale  # 默认为2piself.eps = epsself.offset = offset  # 默认为0def forward(self, mask):# For convenience of exporting to ONNX, it's required to convert# `masks` from bool to int.mask = mask.to(torch.int)  # Bool -> Int  [B, H, W]not_mask = 1 - mask  # logical_not  反转后,有效位置为1, 无效位置为0# cumsum方法可参考https://pytorch.org/docs/stable/generated/torch.cumsum.html?highlight=cumsum#torch.cumsumx_embed = not_mask.cumsum(2, dtype=torch.float32)  # 按行求累加和 y_embed = not_mask.cumsum(1, dtype=torch.float32)  # 按列求累加和 # 是否对数据进行标准化处理, y_embed[:,-1:, :]代表h方向的最大值if self.normalize:  # 满足  normalize并scale=2*piy_embed = (y_embed + self.offset) /(y_embed[:, -1:, :] + self.eps) * self.scalex_embed = (x_embed + self.offset) /(x_embed[:, :, -1:] + self.eps) * self.scale# 可参考Transformer论文中的公式dim_t = torch.arange(self.num_feats, dtype=torch.float32, device=mask.device) # 生成[0, 128]的数组dim_t = self.temperature**(2 * (dim_t // 2) / self.num_feats)  # 归一化pos_x = x_embed[:, :, :, None] / dim_t  # [B, H, W, C]# [b, h, w, 1] -> [b, h, w, 128]pos_y = y_embed[:, :, :, None] / dim_t # [b, h, w, 1] -> [b, h, w, 128]# use `view` instead of `flatten` for dynamically exporting to ONNXB, H, W = mask.size()pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()),dim=4).view(B, H, W, -1)  # [B, H, W, C]# 对偶数位置进行sin处理, 对奇数位置进行cos处理. [b, h, w, 64, 2] -> [b, h, w, 128]pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()),dim=4).view(B, H, W, -1)  # [B, H, W, C]pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)  # [B, C, H, W] # [b, h, w, 128] -> [b, h, w, 256] -> [b, 256, h, w]return pos

损失函数

https://zhuanlan.zhihu.com/p/572772363?utm_id=0

分配器

https://zhuanlan.zhihu.com/p/572772363?utm_id=0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143370.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0918)

十二、首页 layout 架子 [element-plus 菜单] 基本架子拆解 架子组件列表&#xff1a; el-container el-aside 左侧 el-menu 左侧边栏菜单 el-container 右侧 el-header 右侧头部 el-dropdown el-main 右侧主体 router-view <script setup> import {Management,Pr…

【C++篇】C++类与对象深度解析(三):类的默认成员函数详解

文章目录 【C篇】C类与对象深度解析&#xff08;三&#xff09;前言4. 运算符重载基本概念4.1 运算符重载的基本概念4.2 重载运算符的规则4.3 成员函数重载运算符4.4 运算符重载的优先级与结合性4.5 运算符重载中的限制与特殊情况4.5.1 不能创建新的操作符4.5.2 无法重载的运算…

影刀RPE学习——自动化

下载网址&#xff1a;影刀RPA - 影刀官网 (yingdao.com) 傻瓜式安装进入界面&#xff1a; 官方教程&#xff1a;影刀RPA零基础入门教程&#xff08;2024最新版&#xff09;&#xff1a;01 引入课-影刀初相识_哔哩哔哩_bilibili

我的AI工具箱Tauri版-VideoMusicCheckpointLouver音乐卡点百叶窗视频制作

本教程基于自研的AI工具箱Tauri版进行VideoMusicCheckpointLouver音乐卡点百叶窗视频制作。 视频样片《队长小翼》《沖田浩之-燃えてヒーロー》百叶窗卡点视频 《队长小翼》《沖田浩之-燃えてヒーロー》百叶窗卡点视频 该模块没有任何消耗。需要提前准备好响应的素材 该模块没…

物联网系统中环境监测设备如何检测PM2.5——快速了解粉尘传感器

物联网系统中为什么要使用粉尘传感器 物联网系统中使用粉尘传感器的原因是多方面的&#xff0c;主要体现在以下几个方面&#xff1a; 空气质量监测 保障公众健康&#xff1a;粉尘传感器能够实时监测空气中粉尘颗粒的浓度&#xff0c;特别是PM2.5和PM10等可吸入颗粒物&#xff…

【C语言零基础入门篇 - 6】:数组、字符和字符串带你探索无限可能

文章目录 数组一维数组一维数组的定义一维数组的初始化 字符数组二维数组二维数组存汉字 字符串相关函数小结 数组 特点&#xff1a; 在同一个数组中&#xff0c;所有元素都是同一个类型。可以是int、char、float、double等类型。数组是一种构造类型&#xff0c;是一批数据的…

Android14请求动态申请存储权限

Android14请求动态申请存储权限 Android14和Android15存储权限有增加多了选择部分&#xff0c;还是全部。一个小小的存储权限真的被它玩出了花来。本来Android13就将存储权限进行了3个细分&#xff0c;是图片&#xff0c;音频还是视频文件。 步骤一&#xff1a;AndroidManife…

替西帕肽;Mounjaro;Tirzepatide;CAS:2023788-19-2

【替西帕肽Tirzepatide 简介】 替西帕肽是一种GIP/GLP-1受体激动剂&#xff0c;由39个氨基酸的多肽组成。Tirzepatide (LY3298176) 是葡萄糖依赖性胰岛素营养多肽 (GIP) 和胰高血糖素样肽-1 (GLP-1) 受体双重激动剂。Tirzepatide (LY3298176) 在血糖控制和体重减轻方面的疗效明…

Acwing数据结构:单链表

单链表 主要思想&#xff1a;使用数组实现链表(而不用结构体&#xff0c;结构体代码更长&#xff0c;后续图论也是基于数组实现&#xff09;&#xff0c;即静态链表。因为动态链表使用new申请空间需要较多的时间&#xff0c;而算法要求的是以较少的时间完成任务。 单链表&…

【软件设计文档】概要设计说明书、详细设计说明书、需求分析文档,需求报告,测试报告等

1引言 1.1编写目的 1.2项目背景 1.3参考资料 2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4运行环境设计 2.5设计目标 3系统功能模块设计 3.1个人办公 4性能设计 4.1响应时间 4.2并发用户数 5接口设计 5.1接口设计原则 5.2接口实现方式 6运行设计 6.1运行模块…

软考中级软件设计师——知识产权学习记录

软考中级软件设计师——知识产权 著作权人身权著作财产权著作权侵权行为 计算机软件著作权基本知识计算机软件著作权侵权 专利地域性与专利权申请基本知识专利权侵权 职务作品委托开发商业秘密权基本知识商业秘密侵权 商标权与商标注册基本知识商标权侵权 著作权 著作权也称为…

大数据-138 - ClickHouse 集群 表引擎详解3 - MergeTree 存储结构 数据标记 分区 索引 标记 压缩协同

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

阻止冒泡事件

每一div都有一个切换事件 div里包括【复制】事件&#xff0c; 点击【复制按钮】&#xff0c;会触发【切换事件】 因为冒泡 在 Vue 3 中&#xff0c;阻止 click 事件冒泡可以使用以下常规方法&#xff1a; 1 事件修饰符&#xff1a;Vue 3 中提供了多种事件修饰符&#xff0c…

第14章 存储器的保护

第14章 存储器的保护 该章主要介绍了GDT、代码段、数据段、栈段等的访问保护机制。 存储器的保护功能可以禁止程序的非法内存访问。利用存储器的保护功能&#xff0c;也可以实现一些有价值的功能&#xff0c;比如虚拟内存管理。 代码清单14-1 该章节的代码主要实现的功能就…

科学哲学(Philosophy of Science)

GPT-4o (OpenAI) 科学哲学是一门研究科学的基本问题和本质的哲学学科&#xff0c;探讨科学方法、科学知识的性质、科学理论的发展及科学实践的意义和价值等问题。以下是科学哲学的一些关键方面和概念&#xff1a; 主要问题和概念&#xff1a; 1. 科学方法论&#xff1a; - …

大模型研发全揭秘:如何通过模型验证提升模型性能?(附详细代码)

在机器学习和深度学习的开发流程中&#xff0c;模型验证是一个关键的环节。验证集不仅用于检查模型的性能&#xff0c;还能帮助识别和解决潜在问题。本文将通过详细的代码示例和具体案例&#xff0c;逐步介绍从验证集准备、模型测试到评估指标计算的全过程。无论你是AI新手还是…

路由器接口配置DHCP实验简述

一、路由器配置 [Huawei]undo info-center enable Info: Information center is disabled. [DHCP-SERVER]sysname DHCP-Server [DHCP-Server]dis this sysname DHCP-Server undo info-center enable return [DHCP-Server]dhcp enable Info: The operation may take a few secon…

C++速通LeetCode简单第17题-爬楼梯(全网最简单)

思路要点&#xff1a;将问题转化为求斐波那契数列的第n项&#xff0c;然后迭代。 思路分析&#xff1a;最后一次爬的阶数不是1就是2&#xff0c;假设爬n阶的方法数是f(n)&#xff0c;假设最后一次爬1阶&#xff0c;那么爬前面的 n-1阶的方法数是f(n-1)&#xff1b;假设最后一次…

扩展------分布式调度任务框架XXL-JOB

目录 定时任务定时任务的应用场景定时任务的实现方式为什么要使用Xxl-job&#xff1f;有什么优点Springboot整合Xxl-job 1、下载源码2、配置admin&#xff0c;构建镜像部署在Centos上3、执行器服务4、admin调度中心创建执行器5、基于OpenJDK镜像部署Java应用程序创建一个新Spr…

muduo - 概要简述

作者&#xff1a;陈硕 编程语言&#xff1a;C 架构模式&#xff1a;Reactor 代码链接&#xff1a;GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C11 设计自述&#xff1a;https://www.cnblogs.com/Solstice/archive/2010/08…