【Transformer】detr梳理

every blog every motto: You can do more than you think.
https://blog.csdn.net/weixin_39190382?type=blog

0. 前言

detr

detr

1. 引言

论文: https://arxiv.org/pdf/2005.12872v3.pdf
时间: 2020.5.26
作者: Nicolas Carion?, Francisco Massa?, Gabriel Synnaeve, Nicolas Usunier, Alexander Kirillov, and Sergey Zagoruyko Facebook AI

最大的特点是不需要预定义anchor,也不需要NMS,就可以实现端到端的目标检测。

在大目标上检测性能较好,而小目标较差。


2. 整体结构

整体结构如下
20240416163908

目标检测的图片一般都比较大,直接用Transformer计算量比较大,在SWin出现之前一般都是用CNN进行特征提取和尺寸缩放。

主要分三部分:

  • backbone
  • transformer
  • head

3. Backbone

主要是使用resnet50作为backbone,特征图进行了缩小,即(h/32,w/32)

其中还有一个位置编码,计算x和y方向的位置编码。位置编码长度为256,前128代表y方向,后128代表x方向。

20240416174048

4. Transformer

网络结构图如下:
20240416175554

4.1 关于输入shape

其中的输入shape变化: (b,c,h,w) -> (b,c,hw) -> (hw,b,c)
其中c是通道,表示token的维度,b为batch,表示token的个数,
按照参考文献所说,将像素作为一个token,但这种shape应该不是单个像素作为token。

# flatten NxCxHxW to HWxNxC
bs, c, h, w = src.shape
src = src.flatten(2).permute(2, 0, 1)

而vit中的shape变化:(b,c,h,w) -> (b,c,hw) -> (b,hw,c),
这样的shape应该是单个像素作为一个token。

self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
x = self.proj(x).flatten(2).transpose(1, 2)

4.2 关于Encoder位置编码

在Encoder部分,输入都加入了位置编码,并且只对q和k使用。
20240417093907

更清晰的图:
20240418094919

4.3 关于Decoder

4.3.1 理解1

20240417110538

Decoder包含多个DecoderLayer串联,而每个DecoderLayer中又包含两个串联的MultiheadAttention。

从Transformer局部代码中我们得到:

  • tgt:全0向量
  • memory:encoder的输出

DecoderLayer的输入:

  • tgt:第一个Decoder中该变量为为全0向量,后续该变量为上个Decoder的输出
  • memory:一直为encoder最后的输出。
  1. 对于Decoder中第一个MultiheadAttention

    • q: tgt,加上query_pos
    • k: tgt,加上query_pos
    • v: tgt
  2. 对于Decoder中第二个MultiheadAttention,

    • q: 第一个MultiheadAttention的输出(经过dropout和norm),加上query_pos
    • k: memory,加了pos位置信息,来源于Encoder输出
    • v: memory,来源于Encoder的输出

4.3.1 理解2-简化

更清晰的DecoderLayer图如下:

Decoder的最开始的输入一个一个全0的向量,所以:

q = query pos
k = query pos
v = 0

后续的DecodeLayer的输入是上一个DecodeLayer的输出。

20240417172915

4.4 小结

Encoder的输出shape:(hw,batch,256)

Decoder的输入和输出shape:(batch,100,256)

整个transformer的输出shape:(batch,100,256)

object queries 维度为 [100, batch, 256] ,类型为 nn.Embedding 说明这个张量是学习得到的, Object queries 充当的其实是位置编码的作用,只不过它是可以学习的位置编码。


Transformer局部:

    def forward(self, src, mask, query_embed, pos_embed):
        # flatten NxCxHxW to HWxNxC
        bs, c, h, w = src.shape
        src = src.flatten(2).permute(2, 0, 1)
        pos_embed = pos_embed.flatten(2).permute(2, 0, 1)
        query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1)
        mask = mask.flatten(1)

        tgt = torch.zeros_like(query_embed)
        memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed)
        hs = self.decoder(tgt, memory, memory_key_padding_mask=mask,
                          pos=pos_embed, query_pos=query_embed)
        return hs.transpose(1, 2), memory.permute(1, 2, 0).view(bs, c, h, w)

DecoderLayer 局部:

    def forward_post(self, tgt, memory,
                     tgt_mask: Optional[Tensor] = None,
                     memory_mask: Optional[Tensor] = None,
                     tgt_key_padding_mask: Optional[Tensor] = None,
                     memory_key_padding_mask: Optional[Tensor] = None,
                     pos: Optional[Tensor] = None,
                     query_pos: Optional[Tensor] = None):
        
        # 第一个MultiheadAttention
        q = k = self.with_pos_embed(tgt, query_pos)
        tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,
                              key_padding_mask=tgt_key_padding_mask)[0]
        tgt = tgt + self.dropout1(tgt2)
        tgt = self.norm1(tgt)

        # 第二个MultiheadAttention
        tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
                                   key=self.with_pos_embed(memory, pos),
                                   value=memory, attn_mask=memory_mask,
                                   key_padding_mask=memory_key_padding_mask)[0]
        tgt = tgt + self.dropout2(tgt2)
        tgt = self.norm2(tgt)
        tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
        tgt = tgt + self.dropout3(tgt2)
        tgt = self.norm3(tgt)
        return tgt

DecoderLayer 整体:

class TransformerDecoderLayer(nn.Module):

    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1,
                 activation="relu", normalize_before=False):
        super().__init__()
        self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        # Implementation of Feedforward model
        self.linear1 = nn.Linear(d_model, dim_feedforward)
        self.dropout = nn.Dropout(dropout)
        self.linear2 = nn.Linear(dim_feedforward, d_model)

        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.norm3 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.dropout3 = nn.Dropout(dropout)

        self.activation = _get_activation_fn(activation)
        self.normalize_before = normalize_before

    def with_pos_embed(self, tensor, pos: Optional[Tensor]):
        return tensor if pos is None else tensor + pos

    def forward_post(self, tgt, memory,
                     tgt_mask: Optional[Tensor] = None,
                     memory_mask: Optional[Tensor] = None,
                     tgt_key_padding_mask: Optional[Tensor] = None,
                     memory_key_padding_mask: Optional[Tensor] = None,
                     pos: Optional[Tensor] = None,
                     query_pos: Optional[Tensor] = None):
        
        # 第一个MultiheadAttention
        q = k = self.with_pos_embed(tgt, query_pos)
        tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,
                              key_padding_mask=tgt_key_padding_mask)[0]
        tgt = tgt + self.dropout1(tgt2)
        tgt = self.norm1(tgt)

        # 第二个MultiheadAttention
        tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
                                   key=self.with_pos_embed(memory, pos),
                                   value=memory, attn_mask=memory_mask,
                                   key_padding_mask=memory_key_padding_mask)[0]
        tgt = tgt + self.dropout2(tgt2)
        tgt = self.norm2(tgt)
        tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
        tgt = tgt + self.dropout3(tgt2)
        tgt = self.norm3(tgt)
        return tgt

    def forward_pre(self, tgt, memory,
                    tgt_mask: Optional[Tensor] = None,
                    memory_mask: Optional[Tensor] = None,
                    tgt_key_padding_mask: Optional[Tensor] = None,
                    memory_key_padding_mask: Optional[Tensor] = None,
                    pos: Optional[Tensor] = None,
                    query_pos: Optional[Tensor] = None):
        tgt2 = self.norm1(tgt)
        q = k = self.with_pos_embed(tgt2, query_pos)
        tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
                              key_padding_mask=tgt_key_padding_mask)[0]
        tgt = tgt + self.dropout1(tgt2)
        tgt2 = self.norm2(tgt)
        tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos),
                                   key=self.with_pos_embed(memory, pos),
                                   value=memory, attn_mask=memory_mask,
                                   key_padding_mask=memory_key_padding_mask)[0]
        tgt = tgt + self.dropout2(tgt2)
        tgt2 = self.norm3(tgt)
        tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
        tgt = tgt + self.dropout3(tgt2)
        return tgt

    def forward(self, tgt, memory,
                tgt_mask: Optional[Tensor] = None,
                memory_mask: Optional[Tensor] = None,
                tgt_key_padding_mask: Optional[Tensor] = None,
                memory_key_padding_mask: Optional[Tensor] = None,
                pos: Optional[Tensor] = None,
                query_pos: Optional[Tensor] = None):
        if self.normalize_before:
            return self.forward_pre(tgt, memory, tgt_mask, memory_mask,
                                    tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)
        return self.forward_post(tgt, memory, tgt_mask, memory_mask,
                                 tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos)

Transformer整体代码如下:

class Transformer(nn.Module):

    def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
                 num_decoder_layers=6, dim_feedforward=2048, dropout=0.1,
                 activation="relu", normalize_before=False,
                 return_intermediate_dec=False):
        super().__init__()

        encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward,
                                                dropout, activation, normalize_before)
        encoder_norm = nn.LayerNorm(d_model) if normalize_before else None
        self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm)

        decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward,
                                                dropout, activation, normalize_before)
        decoder_norm = nn.LayerNorm(d_model)
        self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm,
                                          return_intermediate=return_intermediate_dec)

        self._reset_parameters()

        self.d_model = d_model
        self.nhead = nhead

    def _reset_parameters(self):
        for p in self.parameters():
            if p.dim() > 1:
                nn.init.xavier_uniform_(p)

    def forward(self, src, mask, query_embed, pos_embed):
        # flatten NxCxHxW to HWxNxC
        bs, c, h, w = src.shape
        src = src.flatten(2).permute(2, 0, 1)
        pos_embed = pos_embed.flatten(2).permute(2, 0, 1)
        query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1)
        mask = mask.flatten(1)

        tgt = torch.zeros_like(query_embed)
        memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed)
        hs = self.decoder(tgt, memory, memory_key_padding_mask=mask,
                          pos=pos_embed, query_pos=query_embed)
        return hs.transpose(1, 2), memory.permute(1, 2, 0).view(bs, c, h, w)

5. Head

Head部分是使用一个简单的MLP进行分类和回归。

20240417114941

参考

  1. https://blog.csdn.net/baidu_36913330/article/details/120495817
  2. https://blog.csdn.net/m0_48086806/article/details/132155312
  3. https://zhuanlan.zhihu.com/p/348060767
  4. https://feizaipp.github.io/2021/04/27/transformer-%E5%9C%A8-CV-%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8(%E4%BA%8C)-DETR-%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E7%BD%91%E7%BB%9C/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SnapGene Mac激活版 分子生物学软件

SnapGene Mac是一款功能全面、操作便捷的综合性分子生物学软件,专为Mac用户打造。它集成了DNA序列编辑、分析、可视化和团队协作等多种功能,为科研人员提供了一个高效、可靠的分子生物学研究工具。 SnapGene Mac激活版下载 在SnapGene Mac中,…

【Hadoop大数据技术】——Sqoop数据迁移(学习笔记)

📖 前言:在实际开发中,有时候需要将HDFS或Hive上的数据导出到传统关系型数据库中(如MySQL、Oracle等),或者将传统关系型数据库中的数据导入到HDFS或Hive上,如果通过人工手动进行数据迁移的话&am…

美容预约小程序:简单三步,开启高效预约模式

在当今的数字化时代,一个小程序可以极大地提高美容院的效率和客户满意度。下面我们将详细说明如何通过以下步骤来搭建一个美容院预约小程序。 首先,你需要注册并登录到乔拓云网,这是 一个在线平台,可以帮助你快速创建并管理你的小…

Kafka集群搭建可视化指南

欢迎来到我的博客,代码的世界里,每一行都是一个故事 Kafka集群搭建可视化指南 前言准备工作硬件要求环境准备 kafka集群的部署与配置3.1 单节点部署与多节点集群搭建单节点部署:多节点集群搭建: 3.2 Broker配置与优化3.3 Topic的创…

快速访问github

修改本地hosts文件 GitHub访问慢的原因在于域名解析,通过修改本地的hosts文件,将远程DNS解析改为本地DNS解析。 fang 步骤1:打开hosts文件(没有就创建) host所在位置: C:\Windows\System32\drivers\etc…

销售经理(多继承/虚基类)

根据下图类之间的继承关系,以及main和输出定义,定义Staff类、Saleman类、Manager类和SaleManager类。 Staff类包含的数据成员有编号(num),姓名(name),基本工资(basicSale)。Saleman类…

[lesson42]类型转换函数(下)

类型转换函数(下) 类型转换函数 C类中可以定义类型转换函数 类型转换函数用于将类对象转换成其他类型 语法规则: 类型转换函数 与转换构造函数具有同等的地位使得编译器有能力将对象转换为其他类型编译器能够隐式的使用类型转换函数 无法抑制隐式的类型转换函…

项目实践:贪吃蛇

引言 贪吃蛇作为一项经典的游戏,想必大家应该玩过。贪吃蛇所涉及的知识也不是很难,涉及到一些C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。这里我会介绍贪吃蛇的一些思路。以及源代码也会给大家放到文章末尾。 我们最终的…

二维码门楼牌管理应用平台建设:取保候审的智能化监管

文章目录 前言一、取保候审的传统监管困境二、二维码门楼牌管理应用平台的优势三、取保候审备案信息的智能化处理四、保障居民合法权益五、展望未来 前言 随着信息技术的飞速发展,二维码门楼牌管理应用平台已成为现代社区治理的重要工具。本文重点探讨如何借助该平…

Vue【路由】

1:什么是单页应用程序(single page application) 所有得功能在一个html页面上实现 2:单页面应用程序的优缺点 优点:按需更新性能高,开发效率也高,用户的体验较好 缺点:学习成本高…

卷王问卷考试系统/SurveyKing调查系统源码

SurveyKing是一个功能强大的开源调查问卷和考试系统,它能够快速部署并适用于各个行业。 这个系统提供了在线表单设计、数据收集、统计和分析等功能,支持20多种题型,提供多种创建问卷的方式和设置。 项 目 地 址 : runruncode.c…

JavaFX--基础简介(1)

一、介绍 中文官网:JavaFX中文官方网站OpenJFX 是一个开源项目,用于桌面、移动端和嵌入式系统的下一代客户端应用程序平台。openjfx.cn是OpenJFX(JavaFX)的标准中文翻译网站,致力于方便开发者阅读官方文档和教程。https://openjfx.cn/ JavaFX 是一个开…

2024第八届图像、信号处理和通信国际会议 (ICISPC 2024)即将召开!

2024第八届图像、信号处理和通信国际会议 (ICISPC 2024)将于2024年7月19-21日在日本福冈举行。启迪思维,引领未来,ICISPC 2024的召开,旨在全球专家学者共襄盛举,聚焦图像信号,在图像中寻找美&am…

袁庭新ES系列15节|Elasticsearch客户端基础操作

前言 上一章节我们介绍了搭建Elasticsearch集群相关的知识。那么又该如何来操作Elasticsearch集群呢?在ES官网中提供了各种语言的客户端,我们在项目开发过程中有多种Elasticsearch版本和连接客户端可以选择,那么他们有什么区别?这…

uniapp Android 插件开发教程

一、下载uniapp提供的SDK Android 离线SDK - 正式版 | uni小程序SDK 二、在uniapp创建一个项目 查看包名:发行--> 原生app 云打包 三、进入dcloud官网 开发者中心 进入 应用管理 --> 我的应用 --> 点击应用名称-->各平台信息-->新增 这里需要这…

【可视化大屏开发】19. 加餐-百度地图API实现导航加线路热力图

需求 Web端使用场景中会涉及到地图导航路线情况,并利用热力图显示路况信息。 实现效果如下: 输入起始地点,选择并开始导航 最终效果 思路步骤 利用百度地图API显示地图交通拥堵情况的热力图,需要按照以下步骤进行开发 步骤1&a…

面试被问懵了:手撕 Transformer

节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 今年最大…

Vue入门篇:概念,快速入门,插值表达式,核心特性,基本Vue指令

目录 1.Vue是什么2.快速入门3.插值表达式{{}}1.作用:2.语法:3.插值表达式的注意点: 4.Vue响应式核心特性5.Vue指令 1.Vue是什么 Vue是一个流行的JavaScript框架,用于构建用户界面。它是一种用于构建单页面应用程序(SPA)的渐进式框架&#xff…

MySQL 列数据跨表拷贝,一句SQL快速将表A每条记录的某些字段拷贝到表B每条记录的某些字段(A、B表通过ID等字段对应)

文章目录 MySQL 列数据跨表拷贝,一句SQL快速将表A每条记录的某些字段拷贝到表B每条记录的某些字段(A、B表通过ID等字段对应)背景定义表填充测试数据跨表一 一对应拷贝列数据SQL参考资料 MySQL 列数据跨表拷贝,一句SQL快速将表A每条…

【C++】:函数重载,引用,内联函数,auto关键字,基于范围的for循环,nullptr关键字

目录 一,函数重载1.1 函数重载的定义1.1.1.形参的类型不同1.1.2参数的个数不同1.1.3.参数的顺序不同1.1.4.有一个是缺省参数构成重载。但是调用时存在歧义1.1.5.返回值不同,不构成重载。因为返回值可接收,可不接受,调用函数产生歧…
最新文章