☰
DETR论文笔记与源码解析:端到端目标检测的Transformer实践
2026/10/13 23:17:05 网站建设 项目流程

1. 从标题拆解这个项目到底在讲什么

1.1 标题里的三个关键词:论文笔记、源码、DETR

看到“论文笔记+源码 DETR:End-to-End Object Detection with Transformers”这个标题,我第一反应是:这是一份典型的“论文精读+代码复现”组合型笔记。它面向的不是纯学术研究者,而是那些想真正把一篇经典检测论文吃透、并且能跑通代码的工程实践者。

拆开来看,论文笔记意味着内容会覆盖动机、方法设计、实验对比和结论反思;源码意味着要落到具体实现,包括模型结构、数据加载、训练循环、损失函数、推理后处理;DETR则是整篇内容的核心对象——一个把目标检测当作集合预测问题来做的端到端模型,用Transformer架构替代了传统检测里大量手工设计的组件。

这个标题背后隐藏的潜在需求很明确:读者想知道DETR到底解决了什么问题、它的核心创新点在哪里、代码层面怎么实现、训练时有哪些坑、以及它和Faster R-CNN、YOLO这类主流检测器到底有什么本质区别。适合的读者包括正在入门计算机视觉检测方向的学生、需要复现前沿模型的算法工程师、以及想理解Transformer如何跨界到检测任务的开发者。

1.2 为什么DETR值得单独写一篇笔记

传统目标检测器经过多年演进,已经形成了一套非常成熟的范式:先生成大量候选框(anchor),再通过非极大值抑制(NMS)过滤重复预测,最后输出结果。这套流程有效,但依赖大量手工设计的组件——anchor的尺寸比例、NMS的阈值、正负样本分配策略,每一个都是超参数,调起来费时费力。

DETR的出现打破了这个惯性。它把检测任务直接建模成“输入图像,输出一组无序的预测集合”,用二分图匹配(bipartite matching)来强制每个真实目标只对应一个预测,从根本上绕开了NMS。这个思路的优雅之处在于:它把检测流程从“多阶段启发式”变成了“单阶段端到端”,整个模型只有CNN骨干网络和Transformer编码器-解码器两大部分。

我第一次读这篇论文时,最震撼的不是它的精度有多高,而是它把问题定义改写了。传统方法在问“怎么更好地生成和筛选候选框”,DETR在问“能不能不生成候选框”。这种从问题源头重新思考的方式,才是它值得写笔记的根本原因。

1.3 这篇笔记适合谁看,能解决什么实际问题

如果你正在做以下事情,这篇笔记应该能帮到你:

  • 想理解Transformer在视觉检测任务中的具体应用方式,而不是停留在“Attention is all you need”的泛泛认知;
  • 准备复现DETR但被官方代码里的各种细节卡住,比如匈牙利匹配的实现、损失函数的权重设置、位置编码的注入方式;
  • 在训练自己的检测模型时遇到收敛慢、小目标漏检严重、训练轮次过多等问题,想看看DETR是怎么处理这些的;
  • 需要在自己的项目里借鉴DETR的端到端思路,比如做实例分割、关键点检测或者多模态检测。

这篇笔记不会只停留在“论文说了什么”,而是会结合源码把“为什么这么设计”“实际跑起来是什么效果”“哪些地方容易踩坑”讲清楚。下面我会按照从整体设计到核心细节、再到实操过程和问题排查的顺序展开。

2. DETR整体设计与核心思路拆解

2.1 把检测变成集合预测:这个想法是怎么来的

目标检测的本质是什么?给定一张图,找出里面所有感兴趣的目标,每个目标用边界框和类别表示。传统方法把这个任务拆成两步:先找可能的位置(区域提议),再判断每个位置是什么(分类回归)。这种拆分很自然,但带来了一个问题——同一个目标可能被多个候选框同时命中,所以需要NMS来去重。

DETR的作者换了一个角度:如果模型足够强,能不能直接输出一个固定大小的预测集合,让每个真实目标只被一个预测框负责?这就像老师点名,班里有N个学生,老师手里有M张名牌(M>N),每张名牌只能给一个学生,每个学生也只能拿一张名牌。多出来的名牌就对应“无目标”类别。

这个类比对应到技术上就是二分图匹配:把M个预测和N个真实目标(加上背景)做最优匹配,匹配上的预测负责回归对应的真实框,没匹配上的预测被推去预测“无目标”。这样一来,重复预测的问题从机制上就被消除了,NMS自然也就不需要了。

注意:这个思路成立的前提是模型必须能输出足够多的预测(论文里M=100),并且匹配算法要能找到全局最优的一对一分配。如果M太小,密集场景下会漏检;如果匹配算法是贪心的,可能陷入局部最优。

2.2 为什么选Transformer而不是CNN做检测头

CNN在视觉任务里一直是主力,但它的感受野是局部的,要获得全局信息必须堆很多层。Transformer的自注意力机制天生就是全局的——每个位置都能直接看到其他所有位置。对于检测任务来说,这个特性非常关键:判断一个区域是不是目标,往往需要结合图像其他区域的信息(比如上下文、遮挡关系、目标之间的相对位置)。

DETR的做法是:先用CNN骨干网络(ResNet)提取图像特征,把特征图拉平成一个序列,加上位置编码后送入Transformer编码器。编码器的作用是增强特征表示,让每个位置的特征都融合了全局上下文。解码器则接收一组可学习的“对象查询”(object queries),每个查询负责探测图像中某个潜在目标,通过交叉注意力从编码器输出中提取相关信息,最后经过前馈网络输出边界框和类别。

这里有个设计细节值得注意:解码器的对象查询是可学习的嵌入向量,不是从图像特征生成的。这意味着模型在训练过程中会逐渐学会让不同的查询关注图像的不同区域和不同尺度。你可以把它理解成100个“探测器”,每个探测器有自己的偏好,有的专门找大目标,有的专门找小目标,有的关注左边,有的关注右边。

2.3 和Faster R-CNN、YOLO的核心差异对比

为了更清楚地理解DETR的定位,我整理了一个对比表格:

维度Faster R-CNNYOLO系列DETR
候选框生成RPN网络网格+anchor无,直接预测集合
后处理NMSNMS无NMS
正负样本分配IoU阈值启发式多尺度分配二分图匹配
全局建模能力局部感受野为主局部为主全局自注意力
训练收敛速度较快快慢(需500轮)
小目标检测较好较好较弱
端到端程度部分部分完全

从表里能看出,DETR最大的优势是流程极简,最大的劣势是训练慢和小目标弱。这两个问题在后续的Deformable DETR、DAB-DETR、DN-DETR等改进工作中被逐步解决,但原始DETR作为开山之作,理解它的设计取舍比直接看改进版更重要。

2.4 损失函数设计:为什么用匈牙利匹配而不是固定分配

传统检测器在分配正负样本时,通常用IoU阈值:和真实框IoU大于0.5的anchor算正样本,小于0.3的算负样本,中间忽略。这种规则简单但粗糙,而且对anchor的设计很敏感。

DETR用的是匈牙利算法做二分图匹配,目标是让总匹配代价最小。匹配代价同时考虑分类概率和边界框相似度(L1距离和GIoU)。具体来说,对于N个真实目标和M个预测,构建一个N×M的代价矩阵,然后用匈牙利算法找到最优的一对一分配。

这个设计的精妙之处在于:匹配过程是可微的(虽然匈牙利算法本身不可微,但匹配结果用于计算损失时,损失对预测值是梯度可传的)。模型在训练中会逐渐学会让正确的预测置信度更高、框更准,从而在下一轮匹配中继续被选中。这是一个正向循环。

实操心得:匈牙利匹配的实现有很多版本,官方代码用的是scipy的linear_sum_assignment。如果你自己复现,注意代价矩阵的数值范围要合理,分类代价和框代价的权重需要调,否则匹配结果会偏向某一方。

3. 核心细节解析与源码实操要点

3.1 骨干网络与位置编码:特征怎么送进Transformer

DETR的骨干网络用的是ResNet-50或ResNet-101,取的是最后一个stage的特征图(通常下采样32倍)。假设输入图像是800×1066,特征图大小就是25×34,通道数2048。然后经过一个1×1卷积降维到256,得到25×34×256的特征。

接下来要把这个二维特征图拉平成序列。直接拉平会丢失空间信息,所以需要加位置编码。DETR用的是正弦位置编码,和原始Transformer一样,但这里是二维的:分别对行和列生成正弦编码,然后拼接或相加。

# 简化的二维位置编码生成逻辑 import math import torch def positional_encoding_2d(h, w, dim): # 生成行和列的位置编码 y_embed = torch.arange(h).unsqueeze(1).float() x_embed = torch.arange(w).unsqueeze(0).float() # 分别计算正弦编码 # ... 具体实现参考官方源码 return pos_embed # shape: (h*w, dim)

位置编码是加在特征上的,不是拼接。这意味着编码的数值范围要和特征匹配,否则会淹没特征信息。官方代码里对位置编码做了归一化处理,确保数值在合理范围内。

注意:位置编码的选择对DETR性能影响很大。后续的Deformable DETR改用了可学习的位置编码,效果更好。如果你在复现原始DETR,建议先用官方提供的正弦编码,跑通后再尝试替换。

3.2 编码器与解码器的具体结构

编码器由6层标准Transformer层组成,每层包括:多头自注意力、前馈网络、残差连接和层归一化。输入是拉平后的特征序列加上位置编码,输出是增强后的特征序列。

解码器也是6层,但结构略有不同:每层包括自注意力(对象查询之间)、交叉注意力(查询和编码器输出之间)、前馈网络。对象查询初始化为100个可学习的向量,每层都会更新。

这里有个关键细节:解码器的自注意力是必需的,它让不同的对象查询之间能互相通信,避免多个查询预测同一个目标。如果没有自注意力,查询之间是独立的,容易产生重复预测。

# 解码器层的简化结构 class DecoderLayer(nn.Module): def __init__(self, d_model, nhead): super().__init__() self.self_attn = nn.MultiheadAttention(d_model, nhead) self.cross_attn = nn.MultiheadAttention(d_model, nhead) self.ffn = nn.Sequential( nn.Linear(d_model, d_model * 4), nn.ReLU(), nn.Linear(d_model * 4, d_model) ) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.norm3 = nn.LayerNorm(d_model) def forward(self, queries, encoder_out): # 自注意力 q = self.norm1(queries) queries = queries + self.self_attn(q, q, q)[0] # 交叉注意力 q = self.norm2(queries) queries = queries + self.cross_attn(q, encoder_out, encoder_out)[0] # 前馈网络 queries = queries + self.ffn(self.norm3(queries)) return queries

3.3 预测头与损失计算:从查询到最终输出

解码器输出100个向量,每个向量经过两个分支:一个分类头(线性层+softmax)输出类别概率(包括“无目标”类),一个回归头(MLP)输出归一化的边界框坐标(中心点x、y和宽高w、h)。

损失计算分三步:

  1. 匈牙利匹配:用分类概率和框距离构建代价矩阵,找到最优匹配。
  2. 分类损失:对匹配上的预测计算交叉熵损失,对未匹配的预测也计算交叉熵(目标为“无目标”类)。
  3. 框回归损失:对匹配上的预测计算L1损失和GIoU损失,两者加权求和。
# 损失计算的简化逻辑 def compute_loss(outputs, targets): # outputs: 分类概率 (batch, 100, num_classes+1), 框坐标 (batch, 100, 4) # targets: 真实框和类别 # 1. 匈牙利匹配 indices = hungarian_matching(outputs, targets) # 2. 分类损失 cls_loss = cross_entropy(outputs['pred_logits'], targets['labels'], indices) # 3. 框损失 bbox_loss = l1_loss(outputs['pred_boxes'], targets['boxes'], indices) + \ giou_loss(outputs['pred_boxes'], targets['boxes'], indices) return cls_loss + 5 * bbox_loss + 2 * giou_loss

损失权重是调出来的:分类损失权重1,L1损失权重5,GIoU损失权重2。这个比例在官方代码里是固定的,但实际训练时可以根据数据集调整。

实操心得:GIoU损失对小目标更敏感,L1损失对大目标更稳定。如果你的数据集小目标多,可以适当提高GIoU的权重;如果大目标多,提高L1权重。但不要偏离官方设置太远,否则匹配阶段就会出问题。

3.4 数据增强与训练策略

DETR的训练用了比较激进的数据增强:随机水平翻转、随机缩放(短边在480到800之间随机)、随机裁剪。这些增强的目的是让模型见到更多尺度和位置的组合,提高泛化能力。

训练策略上,DETR用了AdamW优化器,初始学习率1e-4,骨干网络的学习率更低(1e-5),权重衰减1e-4。学习率在第200轮和第400轮各降10倍,总共训练500轮。这个训练轮次远高于YOLO的几百轮,是DETR收敛慢的直接体现。

批量大小方面,官方用了16张GPU,每张卡2张图,总batch size 32。如果你只有单卡,需要相应调整学习率和训练轮次。我的经验是:单卡batch size 4的情况下,学习率降到2.5e-5,训练轮次增加到800轮左右,效果接近官方配置。

注意:DETR对学习率非常敏感。学习率太高会导致匹配不稳定,模型不收敛;学习率太低则收敛极慢。建议先用小学习率预热几轮,再逐步升到目标值。

4. 完整实操流程与关键环节实现

4.1 环境搭建与依赖安装

复现DETR的第一步是把环境搭好。官方代码基于PyTorch,需要以下依赖:

# 创建虚拟环境 python -m venv detr_env source detr_env/bin/activate # Linux/Mac # detr_env\Scripts\activate # Windows # 安装PyTorch(根据你的CUDA版本选择) pip install torch torchvision # 安装其他依赖 pip install scipy pycocotools matplotlib opencv-python pip install timm # 用于骨干网络

如果你要用官方预训练模型做推理,还需要下载权重文件。权重文件比较大(ResNet-50版本约160MB),建议提前下载好。

提示:pycocotools在Windows上安装经常出问题,可以找预编译的whl文件,或者用Linux环境。如果只是做推理不做评估,可以暂时不装。

4.2 数据准备与格式转换

DETR默认使用COCO格式的数据集。如果你有自己的数据,需要转换成COCO格式:一个JSON文件包含所有图像的标注信息,每张图有对应的id、文件名、宽高,每个标注有类别id、边界框(x,y,w,h)、图像id等。

{ "images": [ {"id": 1, "file_name": "img1.jpg", "width": 800, "height": 600} ], "annotations": [ {"id": 1, "image_id": 1, "category_id": 1, "bbox": [100, 150, 200, 300], "area": 60000, "iscrowd": 0} ], "categories": [ {"id": 1, "name": "cat"} ] }

数据加载器方面,DETR用了自定义的Dataset和Sampler。Sampler的作用是让每个batch里的图像尺寸尽量接近,减少padding。这个细节对训练效率影响很大,如果batch内尺寸差异太大,padding会浪费大量计算。

# 自定义BatchSampler的核心逻辑 class DistributedSampler: def __init__(self, dataset, batch_size): # 按图像尺寸分组 # 每个batch从同一组里采样 pass

4.3 模型初始化与预训练权重加载

DETR的模型初始化有几个关键点:

  • 骨干网络用ImageNet预训练的ResNet,去掉最后的全连接层和平均池化;
  • Transformer部分用Xavier初始化;
  • 对象查询用正态分布初始化;
  • 分类头的偏置初始化为负值,让初始预测偏向“无目标”类。
# 分类头偏置初始化 prior_prob = 0.01 bias_value = -math.log((1 - prior_prob) / prior_prob) nn.init.constant_(self.class_embed.bias, bias_value)

这个初始化技巧很重要:如果不做,模型一开始会对所有查询都给出高置信度,导致匹配混乱,训练很难收敛。设置先验概率为0.01,让初始分类概率接近0,模型从“认为没有目标”开始学,逐步学会识别目标。

加载预训练权重时,注意骨干网络和Transformer部分的key要对应。官方提供了完整的state_dict,直接load_state_dict即可。如果你修改了模型结构,需要用strict=False加载,并检查哪些层没有匹配上。

4.4 训练循环与关键参数设置

训练循环的核心步骤:

  1. 数据加载:获取图像和标注,做数据增强,归一化;
  2. 前向传播:图像过骨干网络,拉平加位置编码,过编码器,对象查询过解码器,输出分类和框;
  3. 损失计算:匈牙利匹配,分类损失+框损失;
  4. 反向传播:计算梯度,更新参数;
  5. 学习率调整:按epoch降学习率;
  6. 日志记录:记录损失、学习率、匹配数量等。
# 训练循环的简化框架 for epoch in range(500): for images, targets in dataloader: outputs = model(images) loss_dict = criterion(outputs, targets) total_loss = sum(loss_dict.values()) optimizer.zero_grad() total_loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1) optimizer.step() # 学习率调整 if epoch == 200 or epoch == 400: for param_group in optimizer.param_groups: param_group['lr'] *= 0.1

梯度裁剪是必须的,DETR的梯度有时候会爆炸,裁剪阈值设0.1比较稳。另外,骨干网络的学习率要比Transformer部分低,通常是1/10。

实操心得:训练DETR时,前50轮的损失下降很慢,这是正常的。不要急着调参,耐心等到100轮左右,损失会开始明显下降。如果200轮后损失还在震荡,再检查学习率和匹配逻辑。

4.5 推理与后处理:从输出到最终检测结果

推理阶段比训练简单:图像过模型,得到100个预测,每个预测有类别概率和框坐标。后处理只需要三步:

  1. 对每个预测取分类概率最大的类别(排除“无目标”类);
  2. 过滤掉置信度低于阈值的预测;
  3. 把归一化的框坐标还原到原图尺寸。
# 推理后处理 def postprocess(outputs, threshold=0.5): probas = outputs['pred_logits'].softmax(-1)[:, :, :-1] # 排除无目标类 scores, labels = probas.max(-1) keep = scores > threshold boxes = outputs['pred_boxes'] # 归一化的cxcywh # 转换为xyxy并还原尺寸 # ... return boxes, labels, scores

因为没有NMS,后处理非常快。但这也意味着如果模型训练不充分,可能会出现多个预测框指向同一目标的情况。这时候可以加一个简单的IoU过滤作为兜底,但理论上训练好的DETR不需要。

注意:置信度阈值的选择会影响召回率和准确率。官方评估用的是0.5,但实际应用中可以根据需求调整。如果漏检严重,降低阈值;如果误检多,提高阈值。

5. 常见问题与排查技巧实录

5.1 训练不收敛或损失震荡怎么办

这是复现DETR时最常见的问题。根据我的经验,原因通常有以下几个:

问题现象可能原因排查方法解决方案
损失一直不降学习率太高打印每轮学习率降到1e-5或更低
损失震荡剧烈梯度爆炸打印梯度范数加梯度裁剪,阈值0.1
匹配数量为0分类头初始化不对检查初始预测概率重新初始化偏置
损失降后又升学习率衰减太晚检查衰减节点提前到150轮和300轮
某些类别损失高类别不平衡统计各类别数量调整采样或损失权重

我踩过最坑的一次是分类头偏置没设对,模型一开始对所有查询都输出高置信度,匈牙利匹配完全乱套,训练了100轮损失还在原地打转。后来把偏置改成负值,第10轮就开始正常下降了。

5.2 小目标检测效果差怎么改善

DETR在小目标上表现弱,这是原始论文就承认的问题。原因有两个:一是骨干网络下采样32倍,小目标在特征图上只剩几个像素;二是Transformer的全局注意力对小目标的定位精度不够。

改善方法有几个方向:

  • 提高特征图分辨率:用ResNet的C3或C4特征而不是C5,或者用FPN结构融合多尺度特征;
  • 增加对象查询数量:从100增加到300,给小目标更多预测机会;
  • 调整损失权重:提高GIoU损失的权重,让小目标的框回归更准;
  • 数据增强:多用随机裁剪和缩放,让小目标在训练中出现的频率更高。

如果这些还不够,建议直接上Deformable DETR,它用可变形注意力解决了小目标问题,训练轮次也降到50轮。

5.3 显存不够怎么调整配置

DETR的显存占用主要来自Transformer的注意力矩阵。序列长度是特征图的高×宽,比如800×1066的图,特征图25×34=850,注意力矩阵是850×850,不算大。但如果输入分辨率提高到1600×2133,特征图变成50×67=3350,注意力矩阵就是3350×3350,显存占用增加15倍。

显存不够时的调整策略:

  • 降低输入分辨率,短边从800降到600或480;
  • 减小batch size,从16降到8或4;
  • 用梯度累积模拟大batch;
  • 用混合精度训练(AMP),显存减半;
  • 减少编码器和解码器层数,从6层降到4层。
# 混合精度训练示例 from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() for images, targets in dataloader: with autocast(): outputs = model(images) loss = criterion(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

提示:混合精度训练对DETR的稳定性影响不大,但要注意损失缩放,避免梯度下溢。如果发现损失变成NaN,检查scaler的初始值。

5.4 推理速度慢怎么优化

DETR的推理速度比YOLO慢,这是Transformer架构决定的。优化方向:

  • 减少查询数量:从100降到50,速度提升约30%,但可能漏检;
  • 剪枝编码器层数:6层降到3层,速度提升约40%,精度下降2-3个点;
  • 用TensorRT或ONNX Runtime:推理速度可以提升2-3倍;
  • 降低输入分辨率:从800降到600,速度提升约50%。

如果对速度要求高,建议直接用YOLO系列。DETR的优势在于端到端和全局建模,不是速度。

5.5 常见问题速查表

问题快速排查解决
训练loss NaN检查学习率和梯度降学习率,加梯度裁剪
匹配数始终为0检查分类头初始化重设偏置为负值
推理结果全为空检查置信度阈值降低阈值到0.1试试
框坐标超出图像检查归一化逻辑确认cxcywh转xyxy正确
多卡训练不同步检查DDP初始化用DistributedDataParallel
评估指标异常低检查数据格式确认COCO格式正确
显存溢出检查输入尺寸降分辨率或batch size
训练速度慢检查数据加载增加num_workers

这些是我在复现过程中实际遇到过的问题,大部分都是配置或初始化的问题,不是模型本身的缺陷。耐心排查,基本都能解决。

6. 从DETR出发的扩展与个人体会

6.1 后续改进方向与值得关注的变体

原始DETR虽然优雅,但训练慢和小目标弱是两个硬伤。后续工作主要围绕这两个方向改进:

  • Deformable DETR:用可变形注意力替代全局注意力,只关注参考点周围的少量位置,训练轮次从500降到50,小目标精度大幅提升;
  • DAB-DETR:把对象查询显式建模成4D锚框(x,y,w,h),让查询有明确的几何意义,收敛更快;
  • DN-DETR:引入去噪训练,给解码器输入加噪声的的真实框,让模型学会从噪声中恢复目标,加速收敛;
  • DINO:结合对比去噪和混合查询选择,在COCO上达到SOTA,训练轮次进一步降低。

如果你已经跑通了原始DETR,建议按这个顺序尝试改进版:先Deformable DETR解决小目标和速度,再DAB-DETR理解查询设计,最后DINO看最新进展。

6.2 我在复现过程中踩过的坑

第一个坑是位置编码的数值范围。官方代码里位置编码是加在特征上的,但特征经过骨干网络后的数值范围可能和位置编码不匹配。我一开始直接相加,结果模型完全不收敛。后来发现官方对位置编码做了缩放,确保数值在合理范围内。

第二个坑是匈牙利匹配的代价矩阵。分类代价和框代价的权重需要平衡,如果分类代价太大,匹配会偏向分类置信度高的预测,忽略框的准确性;反之亦然。官方代码里分类代价用概率的负对数,框代价用L1距离,两者直接相加。我试过给框代价乘系数,结果匹配变得不稳定。

第三个坑是学习率预热。DETR对初始学习率很敏感,如果一开始就用1e-4,前几轮损失会爆炸。官方代码里其实有预热,但藏得比较深。我后来加了5轮的线性预热,从1e-6升到1e-4,训练稳定多了。

6.3 这个项目后续可以怎么扩展

如果你已经掌握了DETR的核心,可以尝试以下扩展:

  • 实例分割:在DETR基础上加一个掩码分支,用Mask R-CNN的思路,但保持端到端;
  • 关键点检测:把框回归改成关键点回归,用对象查询直接预测人体关键点;
  • 多模态检测:把文本编码器和图像编码器结合,做开放词汇检测;
  • 视频检测:把帧间信息引入Transformer,做时序一致的检测。

这些方向都有相关论文,但核心思路都是从DETR的端到端集合预测出发。理解了原始DETR的设计哲学,再看这些扩展会容易很多。

最后分享一个小技巧:如果你在复现时遇到问题,先去官方GitHub的issues里搜一下,大概率有人遇到过同样的问题。DETR的社区很活跃,很多坑已经被踩过了。另外,官方代码的README写得比较简略,但代码注释很详细,遇到不懂的地方直接看源码比看论文更快。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询