Zhangzhe's Blog

The projection of my life.

0%

URL

TL;DR

  • 传统基于关键点检测的车道线检测网络通常需要根据任务的定义设计模型输出头结构,比如 UFLD 算法每条车道线需要占据一个输出 channel
  • 本论文提出一种新颖的车道线检测范式,解耦了任务和网络,仅使用固定的输出通道数即可检测任意多条车道线。

Algorithm

总体思路

ganet2.png

  • 如何实现只用一个 channel 输出即可检测任意多条车道线?一个可以想到的简单方法是:
    1. 输出一个 channel = 1heat map,其中每个位置的 heat map value 依旧表示该位置是车道线关键点的概率。
    2. 使用阈值过滤得到所有车道线的关键点坐标(每条车道线关键点数量应 >= 2)。
    3. 使用聚类的方式将一堆关键点分成若干组,每组关键点表示一条车道线。聚类中的 “距离” 判定逻辑需要根据一些先验知识进行设计(比如:因为车道线在图片中更接近竖直方向,因此水平距离权重小于垂直距离)。
  • 上述操作中的聚类过程包含了很多人为总结的先验知识,非常不 “机器学习”,于是我们可以改进这个过程:
    1. 输出一个 channel = 1heat map 和一个 channel = 2offset map,其中每个位置的 heat map value 依旧表示该位置是车道线关键点的概率,每个位置的 offset map value 表示 如果该点是关键点,那么该点相对于本条车道线起始点的偏移(x, y),起始点表示一条车道线关键点中最靠近图片下方的点。
    2. 使用阈值过滤得到所有关键点,将关键点对应位置的偏移 offset 得到新的点 p',理论上同一条车道线的每一个关键点偏移后得到的新位置 p' 都一致,都是车道线起始点。
    3. 因为神经网络不太能拟合到 loss == 0,因此还需要对所有的 p' 进行聚类,每个类表示一条车道线实例,本质相当于将聚类中的距离判定逻辑吸到神经网络内部。
  • 以上就是本论文提出的 GANet 算法的核心思想:用固定的有限个输出通道去预测任意条车道线。

网络结构

ganet1.png

LFA(Lane-aware Feature Aggregator)

ganet3.png

动机

  • 传统的2D卷积在固定的网格状区域内采样特征,这不适用于处理车道线的狭长形状。
  • 因此作者使用如下步骤改进各关键点上的局部特征:
    1. 预测该关键点同一条车道线紧邻的 num_adjacent_keypoints 个点的 offset,进行显式监督。
    2. 用预测的 offset 引导可变形卷积改进关键点局部特征。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import torch
import torch.nn as nn
from torchvision.ops import deform_conv2d
import math
class LFA(nn.Module):
def __init__(self, in_channels, out_channels, num_adjacent_keypoints=5):
super(LFA, self).__init__()
self.offset_conv = nn.Conv2d(in_channels, 2 * num_adjacent_keypoints, kernel_size=1)
self.deform_conv_weight = nn.Parameter(torch.Tensor(out_channels, in_channels, 3, 3))
nn.init.kaiming_uniform_(self.deform_conv_weight, a=math.sqrt(5))
def forward(self, x):
# x: input feature map with shape [batch_size, in_channels, height, width]

# Step 1: Predict the offsets for adjacent keypoints
offsets = self.offset_conv(x) # shape: [batch_size, 2 * num_adjacent_keypoints, height, width]

# Step 2: Perform deformable convolution to aggregate features
aggregated_features = deform_conv2d(x, offsets, self.deform_conv_weight, stride=1, padding=1)

return aggregated_features, offsets # Return both aggregated features and offsets
# Initialize LFA module
lfa = LFA(in_channels=64, out_channels=128, num_adjacent_keypoints=5)
# Dummy input feature map with shape [batch_size, in_channels, height, width]
input_feature_map = torch.randn(16, 64, 128, 128)
# Forward pass
aggregated_features, predicted_offsets = lfa(input_feature_map)
# aggregated_features 是特征输出
# predicted_offsets 是预测的相邻的 num_adjacent_keypoints 个车道线的偏移量,显式监督

Thought

  • 提出了一种灵活的车道线检测范式,具有较好的可拓展性,目前在车道线榜单上比较靠前。
  • 另外一个创新点是LFA module,主要是用到了可形变卷积,对于大多数动态性较差的端侧芯片来说,不容易部署。

URL

TL;DR

  • 传统 BEV 算法中 View Transform 都是通过 LSS 实现 Image ViewBEV View 的转变,这种视角转换方法依赖于图像视角的深度估计(显式(例如 BEVDepth)或隐式(例如 LSS / BEVDet 等))。
  • 本文提出一种新的通过时空注意力机制实现的 View Transform 方法,在 Neuscenes 数据集上取得了不错的 3D 目标检测成绩(略差于 BEVDet4D)。

Algorithm

bevformer.png

整体架构

1. 输入

  • 输入包含两部分,分别是:
    • 环视图(6 张)
    • BEV Queriesshape = [num_voxel, dim]
    • History BEV Feature(上一帧的 BEV Feature 输出,shape = [num_voxel, dim]

2. 输出

  • 输出为当前帧的 BEV Featureshape = [num_voxel, dim]),记作 BtB_t
  • 暂时不考虑任务头

3. 网络模块

  1. 图像特征提取
    • 6 张图片单独做 CNN base 特征提取,输出记作 FtF_t
  2. 时序信息融合:
    • 将构造的 BEV Queries(记作 Q),和上一帧的 BEV Feature(记作 Bt1B_{t-1})做 Self-Attention
    • 其中 Q 作为 QueryBt1B_{t-1} 作为 Key / value,做 Attention 运算
    • 虽然这里的 Query / Key / Value 并不同源,但依然被称为是 Self-Attention 而不是 Cross-Attention,是因为 QBt1B_{t-1} 都属于 BEV 语义
    • 输出记作 Q'
  3. 空间交叉注意力(视角转换
    • 此步骤是本文的重点,BEVFormer 通过这一步将透视图特征转换为俯视图特征
    • 输入为:
      • Q'
      • FtF_t
    • Cross-Attention 运算,其中:
      • Q' 作为 Queries
      • FtF_t 作为 Key / Value
    • 用预设的无意义且可学习的 BEV Queries 去查询图片总体特征,得到 BEV Feature 输出,记作 BtB_t
  4. 任务相关头
    • 输入为:BEV Feature
    • 输出为:BEV 视角下的检测 / 分割等任务预测结果
    • 模型结构:可以是 CNN base 也可以是 Transformer base
  • 以上提到的所有 Attention 过程都需要额外添加 Position embedding

Thought

  • 过程并不复杂,只要看过经典的 DETR,都熟悉这种套路:预设一个无意义的(随机初始化但可学习) pattern 序列作为 Query 去查询 image features,得到有意义的结果(或者说是可监督的结果)
  • 后续的部分工作对其改进是:将随机初始化预设的 Query 有意义化(例如通过一个轻量化 2D 检测头预检测,得到 proposal 并编码为 Query

URL

TL;DR

  • 本文提出一种 BEV 视角下的的 3D 目标检测算法,作者认为尽管深度对相机 3D 检测至关重要,但最近的方法中的深度估计却出奇地不足。
  • BEVDepth 通过利用显式深度监督(来自 lidar 点云)来解决这个问题。
  • 同时使用关键帧和过渡帧在 bev feature 维度进行特征融合,引入时序信息,提高模型效果。

Algorithm

bevdepth1.png

  • BEVDet4Dpipeline 很相似,区别是 BEVDepth 使用了 DepthNet 用激光雷达点云数据做了深度监督。
  • DepthNet 深度监督的输入是 6v 图像特征和每个相机的内外参,输出为 相机相关深度估计(camera_awareness_depth_estimation)
    bevdepth2.png

显式监督效果和 baseline 对比还是很赞的!
table.png
MAPNDS 吊打了一众基于纯视觉的算法

Thought

  • 多帧训练中过渡帧使用了 nuScenes 数据集的 Sweep 数据(没有人工标注的原始数据,只包含图像和 lidar 点云),无形中拓展了数据量。
  • 本文创新点不多,基本是 BEVDet4D + DepthNet,更像是一个工程优化,比如:用 cuda 写了 voxel pooling 过程,计算过程非常高效。

URL

TL;DR

  • BEVDet4D 是基于 BEVDet 加入了时序信息的一篇论文
  • 具体来说就是将上一帧的 BEV Feature 和本帧的 BEV Feature 对齐后 Concat 到一起送入 BEV Encoder 中进行 BEV 视角下的 3D 目标检测
  • BEVDet 论文中的 image encoder + view transformer 完全保持不变
  • 由于有两帧的信息,所以对速度的预测相较于单帧有较大提升

Algorithm

整体流程

bevdet4d.png
BEV Feature 层面(View Transformer 的输出)融合两帧信息

算法的伪代码表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class BEVDet4D:
def __init__(self):
# 初始化相关的编码器、转换器和其他必要的组件
self.image_view_encoder = ImageViewEncoder()
self.view_transformer = ViewTransformer()
self.bev_encoder = BEVEncoder()
self.head = DetectionHead()
self.previous_bev_feature = None
def spatial_alignment(self, feature):
# 这里执行空间对齐操作,具体细节可能需要根据原始论文进行补充
# 实际代码中这里似乎没有开,即上一帧的 BEV feature 直接和本帧 BEV feature map concat
aligned_feature = ...
return aligned_feature
def forward(self, current_image):
# 使用图像视图编码器和视图转换器处理当前图像
image_feature = self.image_view_encoder(current_image)
transformed_feature = self.view_transformer(image_feature)
# 使用BEV编码器获取当前帧的BEV特征
current_bev_feature = self.bev_encoder(transformed_feature)
# 如果存在前一帧的BEV特征,则进行空间对齐和融合
if self.previous_bev_feature:
aligned_previous_feature = self.spatial_alignment(self.previous_bev_feature)
fused_feature = concatenate(aligned_previous_feature, current_bev_feature)
else:
fused_feature = current_bev_feature
# 使用检测头部进行3D物体检测
detections = self.head(fused_feature)
# 保存当前帧的BEV特征以供下一帧使用
self.previous_bev_feature = current_bev_feature
return detections
# 实例化BEVDet4D并进行前向传递
bevdet4d = BEVDet4D()
detections = bevdet4d.forward(current_image)

result

BEVdet4D2.png

效果比 BEVDet 好了不少,尤其是 mAVE (速度误差)

Thought

  • 没有很大的创新点,更像是 BEVDet 的一个使用 trick
  • BEVDet 的计算量主要分布在 image encoderview transformer,所以复用上一帧的 BEV feature 即充分利用了上一帧的计算量,对当前帧引入的额外计算量也比较可控(BEV encodertask head 都比较轻量)

URL

TL;DR

  • 本文介绍了一种 BEV 视角下的 3D 障碍物检测算法,该算法的输入是由多张(6张)图片组成的车身环视视角,输出为车身周围障碍物的 3D bbox
  • LSS(lift-splat-shoot) 算法较为相似,但任务不同,LSS 想要解决的是 BEV 视角下的分割问题,BEVDet 想要解决的是 3D 障碍物检测问题
  • FCOS3D 等单目 3D 障碍物检测的任务类型相似,区别在于:单目 3D 障碍物检测对每个视角做 3D 障碍物检测后,需要使用后处理融合跨视角的物体,BEVDet 可以将跨视角融合问题内嵌到模型中(BEV

Algorithm

总体结构

BevDet.png
由上图可以看出,模型主要由四个部分组成,分别是:

  • Image-view Encoder:图像特征提取(backbone + neck),6个视角分别做特征提取,不做视角间特征融合
  • View Transformer:视角变换(同时也实现了图像间信息融合),从图像视角转换为 BEV 视角,使用的方法和 LSS 方法一样,输出为 BEV feature
  • BEV Encoder:对 BEV feature 用一个较小的 BEV backbone 做特征提取
  • Head:任务头,预测 3D bbox 等,本文使用了 CenterPoint Head

算法流程的伪代码表示

1
2
3
4
5
6
7
8
9
10
11
12
# 定义输入,shape: (8, 6, 256, 704, 3) [batch, camera, H, W, C]
input_images = get_input_images()
# 图像视图编码器,输出shape: (8, 6, 16, 44, 256) [batch, camera, H//16, W//16, C]
image_view_features = image_view_encoder(input_images)
# 视图变换器,输出shape: (8, 64, 128, 128) [batch, C, Bev_H, Bev_W]
transformed_features = view_transformer(image_view_features)
# BEV编码器,输出shape: (8, 256, 64, 64) [batch, C, Bev_H//2, Bev_W//2]
encoded_bev_features = bev_encoder(transformed_features)
# 任务特定头部进行3D物体检测,输出shape: (8, num_objects, object_info)
detection_results = task_specific_head(encoded_bev_features)
# 返回3D物体检测结果
return detection_results

数据增广方法

  • 独立图片空间数据增广:图片的翻转、裁剪和旋转可以用 3x3 矩阵表示,在 View Transformer 的时候需要做对应逆变换,即 同时更改图片和 View Transformer 过程
  • BEV视角下的数据增广:在BEV空间的学习中,数据量少于图像视图空间,因为每个样本包含多个摄像机图像,所以更容易过拟合;该增广方法遵循常见的 LiDAR 方法,采用了 2D 空间中的常见数据增广操作,如翻转、缩放和旋转,需要对应修改目标 3D bbox,即 同时更改 BEV Feature 和 3D bbox GT

Scale-NMS

  • 由于 BEV 空间中不同类别的空间分布与图像视图空间中的分布非常不同,所以作者提出了 Scale-NMS,在执行经典的 NMS 算法之前根据每个对象的类别来缩放每个对象的大小,可显著提高了对小面积类别(如行人和交通锥)的预测性能

Thought

  • 从模型结构和数据增广方式看 BEVDet 本质是一个二阶段算法:
    • image Encode + View Transformer:环视图像编码到 BEV 空间
    • BEV Encoder + Task HeadBEV 空间下的 3D 障碍物检测
  • 但第一阶段输出的 BEV Feature 没有用 LiDAR 点云监督就有点怪…(后续的改进算法加了)

URL

TL;DR

  • 提出了一个完全端到端的多目标跟踪框架
  • 将多目标跟踪问题形式化为一组序列预测问题
  • 引入了跟踪感知的标签分配
  • 提出了用于时间建模的集体平均损失和时间聚合网络方法

Algorithm

MOTR 整体流程

MOTR.png

  1. 特征提取:用 CNN backbone 提取连续帧中每一帧的特征(上图中的 Enc
  2. 查询生成:用 Deformable Transformer 对第一步提取的特征进行查询(上图中的 Dec
    • 对于视频第一帧,只解码 object detection query (上图中的 qdq_d )得到 hidden state
    • 对于非第一帧,将 object detection query (上图中的 qdq_d )和上一帧的 tracking query (上图中的 qtrq_{tr} )先 concat 再进行解码得到 hidden state
  3. 预测结果生成:用一个简单的结构将上一步得到的 hidden state 映射到任务空间,预测结果包含 object detection resultstracking results
  4. 得到下一帧的 tracking query:用 QIM (Query Interaction Module, 查询交互模块) 将上一步得到的预测结果映射为下一帧的 tracking query
  5. 计算损失 / 输出预测结果:对于训练,计算集体平均损失(CAL, Collective Average Loss);对于预测,直接输出第 3 步得到的结果
  • 描述 MOTR 过程的伪代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def process_frame(frame, detect_queries, track_queries=None, ground_truths=None):
# 使用CNN提取帧特征
# frame shape: (height, width, channels)
frame_features = extract_frame_features(frame) # Shape: (height, width, channels)
if track_queries is None:
# 使用Deformable DETR解码器生成隐藏状态
# detect_queries shape: (num_queries, query_dim)
# frame_features shape: (height, width, channels)
hidden_states = deformable_detr_decoder(detect_queries, frame_features) # Shape: (num_queries, hidden_dim)
else:
queries = concatenate(track_queries, detect_queries) # Shape: (num_queries + num_tracks, query_dim)
hidden_states = deformable_detr_decoder(queries, frame_features) # Shape: (num_queries + num_tracks, hidden_dim)
# 生成预测
# hidden_states shape: (num_queries, hidden_dim)
predictions = predict(hidden_states) # Shape: (num_queries + num_tracks, num_classes + 4)
# 使用Query Interaction Module (QIM)生成下一帧的跟踪查询
# hidden_states shape: (num_queries, hidden_dim)
track_queries = qim(hidden_states) # Shape: (num_tracks, query_dim)
if ground_truths is not None:
# 使用Collective Average Loss (CAL)进行训练
# predictions shape: (num_queries, num_classes + 4)
# ground_truths shape: (num_objects, num_classes + 4)
loss = cal(predictions, ground_truths)
backpropagate(loss)
return predictions, track_queries # Shape: (num_queries + num_tracks, num_classes + 4), (num_tracks, query_dim)
def process_video(video, ground_truths=None):
# 初始化检测查询
# 返回形状:(num_queries, query_dim)
detect_queries = initialize_detect_queries()
track_queries = None # Shape: (num_tracks, query_dim)
for frame in video:
predictions, track_queries = process_frame(frame, detect_queries, track_queries, ground_truths)
if ground_truths is None:
yield predictions

查询交互模块

  • 查询交互模块 Query Interaction Module (QIM)MOTR 中的一个关键组件,它负责处理物体的进入和退出,以及增强长期的时间关系建模
  • QIM 的输入是当前帧预测的 detection resulttracking result,输出是下一帧的 tacking query
  • 通俗来说,QIM 是根据当前帧预测的结果,给出下一帧的 “提问”
  • QIM 过程的伪代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def query_interaction_module(hidden_states, scores, tau_en, tau_ex, M):
# hidden_states shape: (num_queries, hidden_dim)
# scores shape: (num_queries, num_classes)
# tau_en, tau_ex: entrance and exit thresholds
# M: number of consecutive frames for exit threshold
# Object Entrance
entrance_mask = scores.max(dim=1) > tau_en # Shape: (num_queries,)
hidden_states = hidden_states[entrance_mask] # Shape: (num_entrance_queries, hidden_dim)
# Temporal Aggregation Network (TAN),主要目的是融合时序信息,本文是用了一个 Multi-Head Self-Attention 实现
hidden_states = temporal_aggregation_network(hidden_states) # Shape: (num_entrance_queries, hidden_dim)
# Object Exit
exit_mask = scores.max(dim=1) < tau_ex # Shape: (num_entrance_queries,)
exit_mask = exit_mask.rolling(window=M).sum() > 0 # Shape: (num_entrance_queries,)
hidden_states = hidden_states[~exit_mask] # Shape: (num_track_queries, hidden_dim)
return hidden_states # Shape: (num_track_queries, hidden_dim)

集体平均损失

  • 集体平均损失(Collective Average Loss,CAL)是 MOTR 算法中用于训练的损失函数。不同于传统的逐帧计算损失,CAL 收集整个视频剪辑的所有预测,然后基于整个视频剪辑计算总体损失
  • 集体平均损失的代码描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def collective_average_loss(predictions, ground_truths, matching_results):
total_loss = 0
total_objects = 0
for i in range(len(predictions)):
pred_tracked = predictions[i]['tracked']
pred_detected = predictions[i]['detected']
gt_tracked = ground_truths[i]['tracked']
gt_detected = ground_truths[i]['detected']
match_tracked = matching_results[i]['tracked']
match_detected = matching_results[i]['detected']
total_loss += single_frame_loss(pred_tracked, match_tracked, gt_tracked)
total_loss += single_frame_loss(pred_detected, match_detected, gt_detected)
total_objects += len(gt_tracked) + len(gt_detected)
return total_loss / total_objects

Thought

  • 以一种非常优雅的方式解决了端到端多目标追踪的任务,打破了之前 NN detection + Hard logic code trackingtracking 范式
  • 这种非黑盒的(显式监督 detecion bbox)复杂任务端到端训练,启发了后续的许多更复杂的端到端任务,例如 UniAD

URL

TL;DR

  • 提出了 Deformable DETR:这是一种新的目标检测模型,解决了现有 DETR 模型的收敛速度慢和特征空间分辨率有限的问题。
  • 使用可变形的注意力模块:这些模块只关注参考点周围的一小部分关键采样点,从而在更少的训练周期内提高了性能,尤其是对小对象的检测。
  • 结合了可变形卷积的稀疏空间采样和 Transformer 的关系建模能力:这使得模型能够在处理大规模数据时保持高效,同时还能捕捉到复杂的上下文关系。
  • 引入了一种两阶段的变体:在这个变体中,区域提议由 Deformable DETR 生成,然后进行迭代的细化。这使得模型能够更精确地定位和识别目标。

Algorithm

deformable_detr.png

Deformable DETR 整体结构图

Deformabel Attention Block

deformable_attention.png

  • Multi-Head Attention:
    MultiHeadAtten(zq,x)=m=1MWm[kΩkAmqkWmxk]MultiHeadAtten(z_q, x) = \sum_{m=1}^MW_m[\sum_{k\in\Omega_k}A_{mqk}\cdot W_m'x_k]
    • 输入为一个 query 的表征 zqz_q ,以及总特征 x,输出为 query 查询结果向量

    • M 表示 number of head

    • AmqkA_{mqk} 表示 softmax(QKTd)softmax(\frac{QK^T}{\sqrt{d}})

    • WmxkW_m'x_k 实际上就是 self-attention 中的 VV

  • Deformable Attention:
    DeformableAtten(zq,pq,x)=m=1MWm[k=1KAmqkWmx(pq+Δpmqk)]DeformableAtten(z_q,p_q,x) = \sum_{m=1}^MW_m[\sum_{k=1}^KA_{mqk}\cdot W_m'x(p_q + \Delta p_{mqk})]
    • 输入为一个 query 的表征 zqz_q ,总特征 x,以及 query 对应的 预设采样位置,输出为 query 查询结果向量
    • Δpmqk\Delta p_{mqk} 表示由 zqz_q 计算得到的 基于预设查询位置的横纵偏移
    • Amqk=softmax(zqWa)  ,WaRdim×num_points  ,zqRdimA_{mqk} = softmax(z_qW_a)\ \ ,W_a\in\mathbb{R}^{dim\times num\_points}\ \ ,z_q\in\mathbb{R}^{dim} ,即 point position attention 是由 query 线性映射得到的 ,因此 Deformable Attention 没有 Key 的存在,只有 QueryValue
    • K 表示 number of points,即采样点个数
  • Multi-Scale Deformable Attention
    MSDeformableAtten(zq,p^q,{x}l=1L)=m=1MWm[l=1Lk=1KAmlqkWmxl(ϕl(p^q)+Δpmlqk)]MSDeformableAtten(z_q,\hat{p}_q,\{x\}_{l=1}^L) = \sum_{m=1}^MW_m[\sum_{l=1}^L\sum_{k=1}^KA_{mlqk}\cdot W_m'x^l(\phi_l(\hat{p}_q) + \Delta p_{mlqk})]
    • Deformable Attention 不同的是,输入的 x 变成了多尺度特征(例如 backbone 不同深度的特征),更贴近实际视觉工程化应用场景
    • point 采样范围是所有 levelfeature map,即 MSDefromableAttention 有全局 attention 信息
  • Deformable AttentionSelf Attention 对比
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import torch
import torch.nn.functional as F
import math
def attention(query, key, value):
# query, key, value shapes: (batch_size, sequence_length, embedding_dim)
scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(query.size(-1))
# scores shape: (batch_size, sequence_length, sequence_length)
probs = F.softmax(scores, dim=-1)
# probs shape: (batch_size, sequence_length, sequence_length)
output = torch.matmul(probs, value)
# output shape: (batch_size, sequence_length, embedding_dim)
return output
def deformable_attention(query, value, reference_points, num_sampling_points, atten_linear, offset_linear):
# query shape: (batch_size, sequence_length, embedding_dim)
# value shape: (batch_size, sequence_length, embedding_dim)
# reference_points shape: (batch_size, sequence_length, 2)
# num_sampling_points: integer, number of points to sample around each reference point

batch_size, seq_len, embed_dim = query.size()

# Calculate offsets
# offset_linear is a linear layer that predicts the offsets
offsets = offset_linear(reference_points).view(batch_size, seq_len, num_sampling_points, 2)
# offsets shape: (batch_size, sequence_length, num_sampling_points, 2)

# Calculate sampling positions based on reference points
sampling_positions = reference_points.unsqueeze(2) + offsets
# sampling_positions shape: (batch_size, sequence_length, num_sampling_points, 2)

# Sample values (this is simplified; you might need interpolation)
# Here, we assume value and reference_points are in the same space for simplicity
sampling_values = value.gather(1, sampling_positions.long())
# sampling_values shape: (batch_size, sequence_length, num_sampling_points, embedding_dim)

# Calculate scores
# atten_linear is a linear layer that transforms the query for calculating attention scores
scores = atten_linear(query).view(batch_size, seq_len, num_sampling_points)
# scores shape: (batch_size, sequence_length, num_sampling_points)

# Softmax to get attention probabilities
probs = F.softmax(scores, dim=-1)
# probs shape: (batch_size, sequence_length, num_sampling_points)

# Calculate output
output = torch.matmul(probs, sampling_values)
# output shape: (batch_size, sequence_length, embedding_dim)

return output

Thought

  • query 线性映射代替 querykey 外积做 attention 数学上可解释性会变差,计算复杂度会降低
  • Deformable Conv 是典型的对 NPU 不友好,Deformable Attention 会更复杂,被代季峰支配的恐惧
  • Multi-scale 做各特征尺度上的信息融合,开创了一个 CNN 做 backbone + Deformable Transformer 做 head 的计算机视觉任务模型新范式,甚至省去了 FPN
  • 总之是用各种便宜的计算来近似复杂的全局 attention,复杂度从 H*W --> K,即 O(n2)>O(K)O(n^2) -> O(K)

TL;DR

  • 本文介绍了 YOLO 系列几种高效的 backbone 设计,主要包括:VoVNetPRNCSPNetELANE-ELAN

Algorithm

1. VoVNet

  • paper: https://arxiv.org/pdf/1904.09730.pdf
    vovnet.png
  • 作者认为 densenet 存在问题:每一层 Conv 都使用之前所有层的输出,因此会导致当前 Convinput channel 很大,输出到 output channel 却较小
  • 因此,作者只在 VoVNet Block 的最后一个 Conv 才用之前所有层的输出
  • 相同计算量下,效果优于 ResnetDenseNet

2. PRN

3. CSPNet(YOLOV5)

4. ELAN

  • paper: https://arxiv.org/pdf/2211.04800.pdf
    elan.png
  • ELAN 全称是 Efficient Layer Aggregation Network, 作者以 VoVNetResNet 做对比,VoVNet 在叠加更多 block 时表现要比 ResNet 更差,作者分析是因为 VoVNet 结构中存在过多的 transition layers,这导致在叠加 block 时最短梯度路径( the shortest gradient path )不断增加,从而使得 block 增加时训练难度上升
  • PRN 相比 ResNet,使用 mask 让输入只有部分 channel 通过 identity connection,丰富了梯度来源;
  • CSPNet 通过将 channel split,一方面增加了梯度信息(同 PRN),另一方面减少了 computational block 中的计算量;
  • ELAN 的思想是:搭建网络时需要考虑每一层的最短最长梯度路径,还要考虑整个网络的最长梯度路径。

5. E-ELAN(YOLOV7)

URL

TL;DR

  • 本文提出一种以自动驾驶规划为目的的神经网络架构,该架构对每个感知子任务显式监督,合理的将子任务连接起来,增加了子任务之间的协调性,并增加了模型的可解释性

WIP

URL

TL;DR

  • 使用预测下一个词(语言建模 language modeling)任务进行自监督预训练
  • 预训练的模型需要使用 reinforement learning with human feedback(RLHF) 进行对齐(align),这个过程不会在测试数据集上提高模型表现,但可以更好的对齐人类的意图和三观
  • 模型输入可以是图片和文本,输出为文本

Details

  • 使用了很强大的基建,可以做到准确预测模型训练的最终效果(scaling),可以以较小的代价和较快的时间找到最合适的模型架构和超参数设置
  • 为模型引入了 steerability(操纵性),可以在模型的 prompt 中加入一些 System message,让模型回复风格拥有某种特质(比如老师、政客等)
  • GPT-4 使用了很多机制提高了模型的安全性

Thought

  • 这篇技术报告更多是对模型效果的分析,基本没有模型细节的描述
  • 大模型逐渐变成大厂垄断,普通研究者能摸到的最后只剩下一个 API