惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
AI
AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
H
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
The GitHub Blog
The GitHub Blog
L
LINUX DO - 最新话题
A
Arctic Wolf
博客园_首页
S
Securelist
S
Secure Thoughts
Google DeepMind News
Google DeepMind News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
N
Netflix TechBlog - Medium
Cyberwarzone
Cyberwarzone
小众软件
小众软件
T
Threatpost
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
N
News and Events Feed by Topic
NISL@THU
NISL@THU
Forbes - Security
Forbes - Security
博客园 - 聂微东
F
Fortinet All Blogs
Simon Willison's Weblog
Simon Willison's Weblog
H
Heimdal Security Blog
罗磊的独立博客
S
Security @ Cisco Blogs
B
Blog
T
Troy Hunt's Blog
Engineering at Meta
Engineering at Meta
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
I
Intezer
T
Threat Research - Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
The Cloudflare Blog
S
Schneier on Security
月光博客
月光博客
L
LINUX DO - 热门话题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org

博客园 - 无左无右

mmdetection3d-1.0.0rc0 安裝 左乘和右乘,行向量和列向量 grep -rl "math\.tan" /media/data_1/everyday/2025_down --include="*.py" - 无左无右 已知相机到车的rt 4x4矩阵,求pitch和yaw角度 torch.where(condition, x, y) 是一个三元运算符:如果条件为真,取 x 的值;如果条件为假,保持 y(即原本的 weights)不变。 for decoder_idx, (cls, reg) in enumerate(zip(cls_scores, reg_preds)): log_str += ', '.join(log_items) 左乘与右乘 GridMask--随机用“网格状”的遮挡去盖住图片的一部分,迫使模型学习更鲁棒的特征。 obtain_sensor2top函数, sensor → ego_s → global → ego_lidar → lidar assert osp.exists(self.table_root), 'Database version not found: {}'.format(self.table_root) 网页绘图,无需注册 value = value.masked_fill(input_padding_mask[..., None], float(0)) DETR 点云绕不同的轴旋转可视化,roll,pitch,yaw 相机坐标系转车辆坐标系以及相反, RT矩阵,旋转变换P_cam = rot_car2cam * P_car + trans_car2cam; P_cam = rot * (P_car - trans) 连续200帧的ego的RT矩阵R_prevel2wld,shape是[200,4,4],目标的rt矩阵的R_curpt2curvels的shape是[87, 200, 4, 4], 87是目标数量, 把t11时刻的目标对齐到t0, numpy实现 vscode launch.json debug 带caffe库的工程代码 标注工具--抹除目标 ubuntu1804安装 mmdet3d 0.17.1 报错与解决 np.stack(a,axis=x), x=0,1,2 外参扰动 car_noise2cam = car2cam @ car_noise2car BEVDet-net部分 TP, FP, precision, recall bevdepth- 数据处理部分 ubuntu 硬盘挂载,重启后硬盘掉了 create_frustum 分析 (frustum = torch.stack((x_coords, y_coords, d_coords, paddings), -1)) sweep_lidar_depth = sweep_lidar_depth.reshape(batch_size * num_cams, *sweep_lidar_depth.shape[2:]) torch.where(condition, x, y) 自动驾驶,单目3D中的alpha角度
Deformable-DETR
无左无右 · 2026-03-19 · via 博客园 - 无左无右

debug版本,无需cuda编译算子,纯pytorch可以跑, torch 1.11.0+cu113,py3.8
https://github.com/wuzuowuyou/Deformable-DETR-pytorch-pure
https://www.zhihu.com/question/454351120

detr预习:
图片
https://www.cnblogs.com/yanghailin/p/19638764

deformable detr解决detr两个问题:
1)训练慢
2)小物体检测差
训练慢的问题原detr的一个点需要与整个图像素做关系运算,没必要,只与附近点做运算
小物体检测差的问题多尺度检测

重点知识1:get_reference_points

    def get_reference_points(spatial_shapes, valid_ratios, device):# spatial_shapes[4, 2]  valid_ratios[b, 4, 2]
        reference_points_list = []
        for lvl, (H_, W_) in enumerate(spatial_shapes):

            ref_y, ref_x = torch.meshgrid(torch.linspace(0.5, H_ - 0.5, H_, dtype=torch.float32, device=device),
                                          torch.linspace(0.5, W_ - 0.5, W_, dtype=torch.float32, device=device))
            #ref_y [76, 106]     
            #ref_y.reshape(-1) [8056]
            #ref_y.reshape(-1)[None] [1, 8056]
            #valid_ratios[:, None, lvl, 1] [2,1]
            #ref_y [b, 8056] = [1, 8056] / [b,1]
            #这里valid_ratios是h/H * H_ 就得到了实际的h, 再用参考点除以实际的h,就得到相对于实际大小图的相对位置
            ref_y = ref_y.reshape(-1)[None] / (valid_ratios[:, None, lvl, 1] * H_)  #[b, 5395]        [1,8056]  [2,1]
            ref_x = ref_x.reshape(-1)[None] / (valid_ratios[:, None, lvl, 0] * W_)  #[b, 5395]
            ref = torch.stack((ref_x, ref_y), -1) ##[b, 5395, 2]
            reference_points_list.append(ref) #reference_points_list4个, [b, 8056,2] [b, 2014,2] [b, 513,2] [b, 104,2]
        reference_points = torch.cat(reference_points_list, 1) #[b, 10723, 2]
        reference_points = reference_points[:, :, None] * valid_ratios[:, None] #torch.Size([b, 7237, 4, 2])
        return reference_points

reference_points = reference_points[:, :, None] * valid_ratios[:, None] #torch.Size([b, 7237, 4, 2])

reference_points[b, 10723,2]
reference_points[:, :, None]【b, 10723,1,2】
valid_ratios[b, 4, 2]
valid_ratios[:, None] [2,1,4,2]
[b, 10723, 4, 2] = [b, 10723,1,2] * [b,1,4,2]
reference_points = reference_points[:, :, None] * valid_ratios[:, None] #torch.Size([b, 7237, 4, 2])
光看增广[b, 10723, 4, 2] = [b, 10723,1,2] * [b,1,4,2],即10723个点,每个点都在4个层级特征上的位置坐标。当前层级用这个公式没问题,但是第0层上点在第一层上面坐标如何表示呢?
reference_points是相对于自己有效长度上相对值,valid_ratios是有效值/归一化的值。比如第0层的一个点,reference_points0=h0/he0, h0是绝对值,he0是有效值,valid_ratios=he0/H, H是当前batch pad的统一值。单看第0层上面的点归一化到全局的H,reference_points00=(h0/he0) * (he0/H) = h0/H. 这里看he0可以消掉,没问题。 但是这个第0层上面的点继续到第一层上面reference_points01=(h0/he0) * (he1/H) ,这里he0和he1有效值不一样消不掉,这如何解释?
其实需要找的是第0层上点到第1、2、3层上坐标表示,这里由于每层的pad比例不一样,用相对坐标需要相对于每层的有效部分。
图片
图片

# 尺寸为:(B, sum(H_*W_), 2)。表示对于一个batch中的每一条数据,
#         它在所有特征图上的参考点(数量为sum(H_*W_))的像素坐标x,y。
#         这里x、y都做过处理,表示该参考点相对于padding部分的h、w的比值
#         例如,如果x和y>1,则说明该参考点在padding部分
# ============================================================================

reference_points = torch.cat(reference_points_list, 1)

# ============================================================================
# 尺寸为:(B, sum(H_*W_), level_num, 2)。表示对于batch中的每一条数据,
#         它的每一个特征层上的归一化坐标,在其他特征层(也包括自己)上的所有归一化坐标

# 假设对于某条数据:
# 特征图1的高度为H1,有效高度为HE1,其上某个ref点x坐标为h1。那么ref点归一化坐标可以表示成h1/H1
# 特征图2的高度为H2,有效高度为HE2,那么特征图1中的ref点在特征图2中,对应的归一化坐标应该是多少?

# 【常规思路】:正常情况下,你可能觉得,我只要对每一张特征图上的像素坐标例如h1,然后对任意两张特征图,
#               我取出像素点坐标一致的ref点,它不能表示两张特征图相同的位置吗?

# 【问题】:每张特征图padding的比例不一样,因此不能这么做。举例,
#           特征图1上绝对像素位置3.5的点,在特征图2上的位置是2.1,在有效图部分之外

# 【正确做法】:把特征图上的坐标表示成相对于有效部分的比例

# 【解】:我们希望 h1/HE1 = h2/HE2,在此基础上我们再要求 h2/H2

# 则我们有: h2 = (h1/HE1) * HE2,进一步有
# (h2/H2) = (h1/HE1) * (HE2/H2),而(h1/HE1)就是reference_points[:, :, None],
# (HE2/H2)就是valid_ratios[:, None]

# 所以,这里是先将不同特征图之间的映射转为“绝对坐标/有效长度”的表达,
# 然后再转换成该绝对坐标在整体长度上的比例
# ============================================================================
reference_points = reference_points[:, :, None] * valid_ratios[:, None]
return reference_points

重点知识2:计算量

DETR 里,encoder 用的是 标准 self-attention,所以:

  • 如果一张特征图有 N 个像素(token)
  • 每个像素都会和 所有 N 个像素计算 attention

复杂度是:O(N^2)
例如:

  • feature map = 50 × 50
  • token 数 = 2500
  • 每个 token 要和 2500 个 token计算 attention

Deformable DETR 的做法

Deformable DETR 中,不再和全图计算,而是:

每个 query 只采样少量 key 点。

论文里的公式:

  • L = feature levels(多尺度)
  • K = sampling points

每个 query 的计算量:L*K

论文默认参数:

  • L = 4 (4 个尺度)
  • K = 4 (每层 4 个采样点)

所以:4*4=16

也就是说:

一个像素(query)只和 16 个位置计算 attention

而不是 DETR 的 几千个位置


直观对比

模型 每个 query 计算的 key 数
DETR N(全图)
Deformable DETR L × K = 16

举例:

feature map DETR Deformable DETR
50×50 2500 16
100×100 10000 16

所以 复杂度从 O(N^2)降为O(N)

这也是 Deformable DETR 能:

  • 收敛 10× 更快
  • 训练更稳定

的原因。


重点知识3:如何保证模型从8个方向去偏移

def _reset_parameters(self):
        constant_(self.sampling_offsets.weight.data, 0.)
        thetas = torch.arange(self.n_heads, dtype=torch.float32) * (2.0 * math.pi / self.n_heads)
        grid_init = torch.stack([thetas.cos(), thetas.sin()], -1)
        grid_init = (grid_init / grid_init.abs().max(-1, keepdim=True)[0]).view(self.n_heads, 1, 1, 2).repeat(1, self.n_levels, self.n_points, 1)
        for i in range(self.n_points):
            grid_init[:, :, i, :] *= i + 1
        with torch.no_grad():
            self.sampling_offsets.bias = nn.Parameter(grid_init.view(-1))
        constant_(self.attention_weights.weight.data, 0.)
        constant_(self.attention_weights.bias.data, 0.)
        xavier_uniform_(self.value_proj.weight.data)
        constant_(self.value_proj.bias.data, 0.)
        xavier_uniform_(self.output_proj.weight.data)
        constant_(self.output_proj.bias.data, 0.)

在初始化sampling_offsets权重的时候,sampling_offset的weight初始化为0,bias初始化周期性角度

  1. 权重初始化为0

constant_(self.sampling_offsets.weight.data, 0.)
将采样偏移量的权重矩阵初始化为0。这意味着在训练初期,网络预测的偏移量主要由bias决定。

  1. 生成均匀分布的角度

thetas = torch.arange(self.n_heads, dtype=torch.float32) * (2.0 * math.pi / self.n_heads)
假设 n_heads=8,生成8个均匀分布的角度:

thetas = [0, π/4, π/2, 3π/4, π, 5π/4, 3π/2, 7π/4]
= [0°, 45°, 90°, 135°, 180°, 225°, 270°, 315°]
目的: 让每个注意力头关注不同的方向。

  1. 转换为单位向量

grid_init = torch.stack([thetas.cos(), thetas.sin()], -1)
将角度转换为单位圆上的坐标点:

grid_init = [
[cos(0°), sin(0°)], # [1.0, 0.0] → 右
[cos(45°), sin(45°)], # [0.7, 0.7] → 右上
[cos(90°), sin(90°)], # [0.0, 1.0] → 上
[cos(135°), sin(135°)], # [-0.7, 0.7] → 左上
[cos(180°), sin(180°)], # [-1.0, 0.0] → 左
[cos(225°), sin(225°)], # [-0.7, -0.7] → 左下
[cos(270°), sin(270°)], # [0.0, -1.0] → 下
[cos(315°), sin(315°)] # [0.7, -0.7] → 右下
]
形状: [n_heads, 2] = [8, 2]

  1. 归一化并扩展维度

grid_init = (grid_init / grid_init.abs().max(-1, keepdim=True)[0]).view(self.n_heads, 1, 1, 2).repeat(1, self.n_levels, self.n_points, 1)
这行代码做了4件事:

a) 归一化

grid_init / grid_init.abs().max(-1, keepdim=True)[0]
将向量归一化到单位长度(虽然已经是单位向量了,这步主要是保险)。

b) reshape

.view(self.n_heads, 1, 1, 2)
形状变为: [8, 1, 1, 2]

c) 复制到所有层级和采样点

.repeat(1, self.n_levels, self.n_points, 1)
假设 n_levels=4, n_points=4,形状变为: [8, 4, 4, 2]

现在每个注意力头、每个特征层级、每个采样点都有相同的方向向量。

  1. 为不同采样点设置不同距离

for i in range(self.n_points):
grid_init[:, :, i, :] *= i + 1
关键步骤! 为4个采样点设置不同的采样半径:

采样点0: 偏移量 × 1 (最近)
采样点1: 偏移量 × 2
采样点2: 偏移量 × 3
采样点3: 偏移量 × 4 (最远)
示例(以第一个注意力头为例):

原始向量: [1.0, 0.0] (向右)

采样点0: [1.0, 0.0] × 1 = [1.0, 0.0]
采样点1: [1.0, 0.0] × 2 = [2.0, 0.0]
采样点2: [1.0, 0.0] × 3 = [3.0, 0.0]
采样点3: [1.0, 0.0] × 4 = [4.0, 0.0]
6. 设置为bias参数

with torch.no_grad():
self.sampling_offsets.bias = nn.Parameter(grid_init.view(-1))
将初始化的偏移量展平并设置为bias。

最终形状: [n_heads × n_levels × n_points × 2] = [8 × 4 × 4 × 2] = [256]

可视化示例
假设有8个注意力头,4个采样点,在某个参考点周围的采样模式:

采样点2 (距离3)

采样点1 (距离2)

参考点 ● → → → (4个采样点沿着8个方向)

采样点1 (距离2)

采样点2 (距离3)
完整的8个方向 × 4个距离 = 32个采样点:

3
2 ↑ 2
3 ↑ ↑ ↑ 3
← ← ← ● → → →
3 ↓ ↓ ↓ 3
2 ↓ 2
3
设计优势
方向多样性: 8个方向覆盖360°
距离多样性: 4个不同距离形成多尺度感受野
对称性: 采样模式关于中心对称
可学习性: 这只是初始化,训练过程中会学习更优的偏移量
稳定训练: 良好的初始化避免训练初期的不稳定
这种初始化策略使得模型在训练开始时就能关注到周围不同方向和距离的特征,加速收敛并提高性能。

encode数据流

图片

这里代码里面8,4,4解释下,8是8个方向,4是4个分辨率层级特征,4是4个偏移点
图片

decode数据流

图片
图片

nn.Embedding(300,256)
        ↓
query_embed [b,300,256]
        ↓ nn.Linear + sigmoid
reference_points [b,300,2]

300 个 query,每个是一个 object query
经过一个 Linear:ref = sigmoid(Linear(query_embed))
得到:
reference_points: [b, 300, 2]
(x, y) ∈ [0,1]
关键理解:
每个 query 初始就带一个“我大概在图哪里找目标”的位置。

reference_points_input = reference_points[:, :, None, :] * src_valid_ratios[:, None, :, :]
把统一坐标 → 映射到每个 feature level 的有效区域,
每个 query,在每个 feature level 上的 reference point

out [b,300,256]
   ↓
MLP → tmp [b,300,4]

reference_points [b,300,2]
   ↓ inverse_sigmoid
reference

tmp[..., :2] += reference
   ↓
sigmoid
   ↓
out_coord [b,300,4]

二、关键问题:为什么要 tmp + reference?
❌ 如果不加 reference(普通 DETR)

模型是这样:

bbox = sigmoid(MLP(query))

👉 问题:

每一层都要 从头预测一个 bbox
学习难度很大
收敛慢(这也是 DETR 的痛点)
✅ Deformable-DETR 的做法
bbox = reference + Δbbox

👉 也就是:

🔥 只预测“偏移量”,而不是绝对位置

三、inverse_sigmoid + 相加的数学本质

这一段是很多人卡住的点 👇

1️⃣ reference 是 sigmoid 空间
reference_points ∈ (0,1)
2️⃣ 先做 inverse_sigmoid
reference = inverse_sigmoid(reference_points)

👉 变成:

(-∞, +∞)
3️⃣ 再加 tmp(MLP 输出)
tmp[..., :2] += reference

👉 等价于:

logit(new_x) = logit(old_x) + Δ
4️⃣ 再 sigmoid 回去
new_x = sigmoid(logit(old_x) + Δ)
👉 这个操作的真正含义是:

🔥 在 logit 空间做残差更新

而不是在 (0,1) 空间硬加。

四、为什么不用直接在 (0,1) 加?

如果直接:

x_new = x_old + Δ

问题:

容易越界(<0 或 >1)
梯度不稳定
更新不对称
👉 用 logit 空间的好处:
x_new = sigmoid(logit(x_old) + Δ)
优点:
✅ 永远在 (0,1)
✅ 更新是“相对的”(比例意义)
✅ 梯度更稳定
✅ 更容易收敛
五、从“检测角度”理解(更直观)

你可以这样理解:

第 0 层:
reference = (0.3, 0.6)

👉 粗略猜一个位置

第 1 层:
Δ = (+0.1, -0.05)
→ 新位置 ≈ (0.35, 0.58)
第 2 层:
Δ = (+0.02, +0.01)
→ 更精确

👉 本质:

🔥 每一层都在“微调 bbox”,而不是重新预测

六、为什么只对前两维 tmp[..., :2] += reference?

因为:

tmp: [x, y, w, h]
reference: [x, y]

👉 所以:

只 refine 中心点
w,h 是直接预测(或者在一些改进模型里也做 residual)
七、这一步和 reference point 的闭环关系

现在你可以把整个逻辑闭环起来:

🔁 一层 decoder 的完整闭环

1️⃣ 有 reference point(当前位置)
2️⃣ 用它做 deformable attention(去采样特征)
3️⃣ 得到更好的 feature(out)
4️⃣ 预测 bbox 偏移:

tmp + reference → 新 bbox

5️⃣ 更新 reference point(下一层用)

👉 形成:

🔥 位置 → 采样 → 更新位置 → 再采样


以下截图来自知乎https://www.zhihu.com/question/454351120

图片
图片
图片
图片
图片
图片
图片
图片
图片
图片
图片
图片