开放词汇检测实战:GroundingDINO+SAM从环境搭建到推理调优

发布时间:2026/10/11 20:38:39

开放词汇检测实战:GroundingDINO+SAM从环境搭建到推理调优 简介本资源面向计算机视觉开发者与研究人员提供将GroundingDINO与SAM融合以增强目标检测和图像分割能力的完整项目源码适合具备一定深度学习基础、希望快速上手文本引导定位与细粒度分割实战的读者可应用于自动驾驶、遥感分析、医学影像等场景。压缩包共132个文件约30.63MB以58个Python脚本为核心实现辅以6个Jupyter Notebook实验记录、10个TSX与5个JS前端交互文件、若干PNG/JPG示例图以及CUDA算子、Dockerfile、YAML配置和说明文档覆盖从模型推理到部署的完整链路。目前已有125人学习。通过源码可直观理解GroundingDINO的文本到图像定位机制与SAM的灵活分割流程掌握二者协同工作的接口设计与调参思路并借助示例图与Notebook快速复现检测分割效果为二次开发和算法迁移提供可运行的基础工程。1. 当检测框开始“听懂人话”GroundingDINOSAM 到底解决了什么做过检测项目的人大概都经历过这种憋屈模型训练时标了 80 类上线后业务方突然要加一个“安全帽上的反光条”或者“货架最上层歪掉的纸箱”你只能回去重新标数据、重新训模型一轮下来两周没了。传统闭集检测器的死穴就在这——它只认识训练集里出现过的东西类别是写死的。而 GroundingDINO 这类开放词汇检测器换了个思路把文本编码器和图像编码器对齐你用自然语言描述要检测什么它就能把对应的框找出来不需要针对新类别重新训练。再叠上 SAMSegment Anything Model每个框还能进一步生成像素级掩码检测和分割一次搞定。这套组合最近在工业质检、遥感解译、机器人抓取里被反复提起不是没有道理的——它把“先定义类别再检测”变成了“先说人话再检测”。这篇笔记就按我实际搭这套流程的顺序从环境配置、推理脚本、参数调节到踩坑记录一步步拆开讲。2. 把两个模型拼起来架构选型与最小可跑通方案2.1 为什么是 GroundingDINO 而不是 GLIP 或 OWL-ViT开放词汇检测这个方向可选的模型不少GLIP、OWL-ViT、GroundingDINO 是常被拿来对比的三个。我选 GroundingDINO 主要看三点第一它在 COCO 零样本迁移上的 AP 通常比 OWL-ViT 高出一截尤其是小目标第二它的文本编码器用的是 BERT 类结构对短语输入更稳你写“红色的消防栓”和“消防栓”都能出框不会像某些模型那样对措辞极度敏感第三社区里基于它做下游微调的方案多遇到问题好查。GLIP 的强项在短语 grounding 和区域描述但推理速度偏慢如果你要做视频流实时检测GroundingDINO 的 Swin-T 版本更现实。OWL-ViT 胜在轻量但小目标召回经常让人想摔键盘。选型没有绝对对错看你的场景是精度优先还是速度优先。2.2 环境搭建从零到能跑推理的完整命令我一般用 conda 建独立环境避免和系统里的 CUDA 版本打架。下面这套命令在 Ubuntu 20.04 CUDA 11.8 的机器上验证过Windows 下把 apt 换成对应操作即可。# 创建环境Python 版本建议 3.9 或 3.10太高有些依赖轮子不全 conda create -n gdino_sam python3.10 -y conda activate gdino_sam # 安装 PyTorch注意 CUDA 版本要和驱动匹配 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 安装 GroundingDINO 的依赖transformers 版本别太新 pip install transformers4.38.0 pip install opencv-python pillow matplotlib scipy pip install segment-anything # 如果要从源码装 GroundingDINO git clone https://github.com/IDEA-Research/GroundingDINO.git cd GroundingDINO pip install -e .这里有几个参数值得注意transformers4.38.0是我试过和 GroundingDINO 权重兼容性最好的版本再新可能报 tokenizer 相关的错torch2.1.0配 cu118 的轮子比较稳如果你用 50 系显卡需要更高 CUDA 版本那就得换 torch 版本。装完以后跑一句python -c import groundingdino; print(ok)确认没报错。2.3 权重准备与目录结构权重文件需要单独下载GroundingDINO 的 Swin-T 版本大约 700MBSAM 的 ViT-H 版本约 2.4GB。我习惯把权重统一放在项目根目录的weights/下代码里用相对路径引用换机器时整个目录拷走就行。# 目录结构建议 project/ ├── weights/ │ ├── groundingdino_swint_ogc.pth │ └── sam_vit_h_4b8939.pth ├── images/ │ └── test.jpg ├── config/ │ └── GroundingDINO_SwinT_OGC.py └── infer.py配置文件GroundingDINO_SwinT_OGC.py从源码仓库的groundingdino/config/下拷过来即可里面主要定义了 backbone 类型、文本编码器路径和输入分辨率。如果你换成 Swin-B 或 Swin-L配置文件也要对应换不能混用。2.4 最小推理脚本检测加分割一次跑通下面这段代码是我平时验证新图片时的最小脚本输入一张图加一句文本提示输出带框和掩码的可视化结果。import cv2 import torch import numpy as np from PIL import Image from groundingdino.util.inference import load_model, load_image, predict from segment_anything import sam_model_registry, SamPredictor # 加载 GroundingDINO注意配置文件路径要对 model load_model( config/GroundingDINO_SwinT_OGC.py, weights/groundingdino_swint_ogc.pth ) # 加载 SAMvit_h 对应最大的权重 sam sam_model_registry[vit_h](checkpointweights/sam_vit_h_4b8939.pth) sam.to(devicecuda) predictor SamPredictor(sam) image_source, image load_image(images/test.jpg) # 文本提示用点号分隔不同类别末尾必须加句号 TEXT_PROMPT person. dog. bicycle. BOX_THRESHOLD 0.35 # 框置信度阈值 TEXT_THRESHOLD 0.25 # 文本匹配阈值 boxes, logits, phrases predict( modelmodel, imageimage, captionTEXT_PROMPT, box_thresholdBOX_THRESHOLD, text_thresholdTEXT_THRESHOLD ) # 把归一化坐标转回像素坐标 h, w, _ image_source.shape boxes boxes * torch.Tensor([w, h, w, h]) boxes boxes.cpu().numpy() # 用 SAM 对每个框生成掩码 predictor.set_image(image_source) for box in boxes: masks, scores, _ predictor.predict( boxbox, multimask_outputFalse ) # masks[0] 就是该框对应的二值掩码 print(mask area:, masks[0].sum())逻辑上分三步GroundingDINO 负责“哪里有什么”输出框和对应的文本短语坐标反归一化是因为模型输出的是 0 到 1 之间的相对坐标SAM 的predict接收框作为提示输出该区域内的精细掩码。multimask_outputFalse表示只返回一个最优掩码如果你不确定框的质量可以设成 True 然后按 score 挑。2.5 参数怎么调三个影响最大的旋钮BOX_THRESHOLD和TEXT_THRESHOLD是最常动的两个。框阈值调低会出更多框但误检也跟着涨文本阈值调低会让模型对措辞更宽容比如你写“小狗”也能匹配到“狗”但可能引入不相关类别。我的经验是先设 0.35 和 0.25 跑一遍看漏检多还是误检多再针对性调整。第三个隐藏参数是输入分辨率GroundingDINO 默认把短边缩到 800如果你检测的是小目标可以改配置文件里的image_size但显存占用会上去。SAM 这边multimask_output和pred_iou_thresh影响掩码质量一般默认值就够用。3. 从框到掩码SAM 的接入方式与显存优化3.1 SAM 三种提示模式的区别SAM 支持点、框、掩码三种提示。点提示适合交互式标注框提示适合我们这种检测器级联的场景掩码提示用于迭代精修。用框提示时SAM 会把框内的区域当作“大概在这里”然后输出精细边界。这里有个细节如果你的框本身偏大SAM 可能会把背景也包进去框偏小则可能切掉目标边缘。所以 GroundingDINO 的框质量直接决定 SAM 的输出上限这也是为什么前面调阈值很重要。3.2 显存不够怎么办ViT-B 与 ViT-H 的取舍SAM 的 ViT-H 权重推理一张 1080p 图片大约需要 6 到 8GB 显存如果你还要同时跑 GroundingDINO12GB 卡会比较紧张。两个办法一是换 ViT-B 权重显存降到 3GB 左右掩码边缘会糙一点但大多数场景够用二是把图片先缩到短边 1024 再送进 SAM精度损失可控。我一般先用 ViT-B 快速验证流程确认效果后再换 ViT-H 出最终结果。# 换用 ViT-B 只需改注册名和权重路径 sam sam_model_registry[vit_b](checkpointweights/sam_vit_b_01ec64.pth)3.3 批量处理时的内存管理如果你要处理一个文件夹的图片别每张都重新加载模型。把模型加载放在循环外面循环里只做推理。另外predictor.set_image()会缓存当前图片的 embedding处理下一张前不需要手动清但如果你显存吃紧可以在每张处理后torch.cuda.empty_cache()。注意这个操作会拖慢速度只在显存报警时用。import os from glob import glob image_paths glob(images/*.jpg) for path in image_paths: image_source, image load_image(path) boxes, logits, phrases predict( modelmodel, imageimage, captionTEXT_PROMPT, box_threshold0.35, text_threshold0.25 ) h, w, _ image_source.shape boxes boxes * torch.Tensor([w, h, w, h]) predictor.set_image(image_source) for box in boxes.cpu().numpy(): masks, _, _ predictor.predict(boxbox, multimask_outputFalse) # 保存或后续处理 # 显存紧张时再开这句 # torch.cuda.empty_cache()3.4 掩码后处理从二值图到可用结果SAM 输出的掩码是布尔数组直接可视化是黑白图。实际项目里通常要做几件事用cv2.morphologyEx去掉小噪点、用cv2.findContours提取轮廓做多边形近似、或者把掩码叠加到原图做半透明填充。下面这段是我常用的可视化代码输出一张带框、带掩码、带标签的图。import matplotlib.pyplot as plt def visualize(image_source, boxes, masks, phrases): fig, ax plt.subplots(1, figsize(12, 8)) ax.imshow(cv2.cvtColor(image_source, cv2.COLOR_BGR2RGB)) for box, mask, phrase in zip(boxes, masks, phrases): x1, y1, x2, y2 box ax.add_patch(plt.Rectangle((x1, y1), x2-x1, y2-y1, fillFalse, edgecolorlime, linewidth2)) # 掩码叠加alpha 控制透明度 colored np.zeros_like(image_source) colored[mask] [0, 255, 0] ax.imshow(colored, alpha0.4) ax.text(x1, y1-5, phrase, colorwhite, bboxdict(facecolorgreen, alpha0.7)) plt.axis(off) plt.savefig(output.jpg, bbox_inchestight, dpi150)alpha0.4是我试过既能看清掩码又不遮住原图细节的值你可以按需调。dpi150保证保存的图够清晰用于报告或论文时调到 300。4. 避坑与排查那些让我加班到凌晨的瞬间4.1 文本提示写了中文却检测不到任何框现象输入“人。狗。”这样的中文提示模型返回空列表。原因GroundingDINO 的文本编码器是基于英文语料训练的对中文支持很差不是完全不能用但召回率断崖式下跌。解决把提示词换成英文或者先用翻译接口转一道。如果必须用中文可以考虑用多语言 CLIP 替换文本编码器但那需要重新对齐训练不是改个配置能搞定的。4.2 框的位置整体偏移或缩放不对现象画出来的框和实际目标错位或者框的大小只有目标的一半。原因忘了做坐标反归一化或者反归一化时用了错误的宽高顺序。GroundingDINO 输出的 box 格式是 cxcywh 归一化坐标你需要先转成 xyxy 再乘以图片宽高。解决用官方工具函数box_cxcywh_to_xyxy转换别自己手写。from groundingdino.util.box_ops import box_cxcywh_to_xyxy boxes box_cxcywh_to_xyxy(boxes) # 先转格式 boxes boxes * torch.Tensor([w, h, w, h]) # 再反归一化4.3 SAM 掩码把整个框都填满了现象不管框里是什么SAM 输出的掩码几乎是整个矩形。原因框提示太模糊或者图片分辨率太低导致 SAM 无法区分前景背景。解决先确认框的质量如果框本身就很粗糙SAM 也救不回来其次把输入图片的短边保持在 1024 以上SAM 对低分辨率图很敏感最后可以试multimask_outputTrue然后选 score 最高的那个。4.4 推理速度慢到无法接受现象一张图跑了十几秒。原因ViT-H 的 SAM 本身就重加上 GroundingDINO 的 Swin-T两个模型串行跑时间叠加。解决如果只是做检测不需要掩码把 SAM 去掉如果需要掩码但能接受精度损失换 ViT-B还可以把图片短边缩到 800 以下速度会明显提升。另外确认你在用 GPU 而不是 CPUmodel.to(cuda)和sam.to(cuda)都别忘了。4.5 同一类别出现大量重叠框现象一个人身上出了五六个框。原因BOX_THRESHOLD设太低或者文本提示里同一个概念写了多个近义词。解决先调高框阈值到 0.4 以上然后用 NMS 去重。GroundingDINO 本身不做 NMS需要自己加。import torchvision.ops as ops keep ops.nms(boxes, logits, iou_threshold0.5) boxes boxes[keep] logits logits[keep] phrases [phrases[i] for i in keep]iou_threshold0.5是常用起点重叠度高的场景可以降到 0.3。5. 进阶技巧用文本提示工程和微调把召回再拉一截5.1 提示词写法对结果的影响比想象中大GroundingDINO 对提示词的敏感度不低。我做过一组对比同一张街景图提示写“car”时召回 12 辆车写“vehicle”时召回 9 辆写“car. truck. bus.”时召回 15 辆但多了 3 个误检。结论是尽量用具体名词别用上位词多个类别用点号分隔末尾加句号如果某个类别总是漏试试加定语比如“red car”可能比“car”更准。下面这个表格是我记录的几组提示词效果对比供参考。提示词召回数误检数备注car121稳定vehicle90漏检多car. truck. bus.153召回高但误检涨red car. blue truck.111定语有帮助5.2 用少量标注做微调如果你的场景固定比如只检测某几种工业零件用几百张标注图对 GroundingDINO 做微调召回能再上一个台阶。微调时冻结图像 backbone只训文本编码器和融合层学习率设 1e-5 左右batch size 根据显存尽量大。损失函数用官方的 grounding loss别自己换。微调后的模型仍然保留开放词汇能力只是对你标注过的类别更敏感。5.3 把 SAM 换成更轻的替代方案如果部署环境算力有限SAM 可以用 MobileSAM 或 FastSAM 替代。MobileSAM 的权重只有 40MB 左右速度是 ViT-H 的几十倍掩码质量下降但大多数场景能接受。FastSAM 基于 YOLOv8-seg速度更快但本质是闭集分割需要你先用 GroundingDINO 出框再送进去。选哪个看你的延迟预算和精度要求。5.4 一个我常犯的错误早期我总想把BOX_THRESHOLD调到很低来保召回结果后处理阶段被大量重叠框搞得焦头烂额。后来学乖了先设一个合理阈值跑通全流程再针对漏检的类别单独分析是提示词问题还是阈值问题别一上来就全局降阈值。这个习惯帮我省了很多返工时间。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 20:33:38

HTML5游戏开发实战:从零实现拉杆子过关小游戏

简介:这是一份面向前端初学者与网页小游戏爱好者的HTML5拉杆子过关小游戏源码,基于HTML、CSS与JavaScript实现,可直接嵌入个人网站、游戏站或教学演示页面,帮助读者理解轻量级网页游戏的交互逻辑与关卡设计思路。压缩包共3个文件&…

2026/10/11 20:33:38

SpringBoot JDBC连MySQL实战:配置、连接池与避坑

简介:面向准备使用SpringBoot连接MySQL的Java开发者,这套资料提供了从零搭建JDBC数据访问层的完整方案。压缩包内包含可直接运行的SpringBoot演示项目,工程中通过控制器、实体类与启动类配合建表脚本和多种配置文件,完整演示了驱动…

2026/10/11 21:38:46

直驱永磁风电系统MATLAB仿真模型搭建与参数整定指南

前几天有个熟人找我看模型,说按某篇论文搭了一套直驱永磁同步风力发电机的MATLAB仿真模型,结果转速波形在天上飘,直流母线电压像坐过山车。我远程看了十几分钟,发现控制逻辑没错,参数却全是随手填的,电流环…

2026/10/11 21:38:46

SQL JOIN深度解析:5种连接方式与高频坑,一篇讲透

SQL JOIN 这个话题,说难不难,说简单也经常翻车。前几天有个同事写报表,一个 LEFT JOIN 下去,结果行数莫名其妙多了一倍,排查了半天,最后发现是右表关联字段出现了重复数据。JOIN 的问题,十个里有…

2026/10/11 21:38:46

BA与ER网络上SIR仿真:Python实现传播动力学对比分析

简介:一套Python实现的SIR模型模拟项目,聚焦BA无标度网络与ER随机网络上的传染病传播对比。面向网络科学、流行病学建模初学者以及Python数据分析学习者,可直观理解网络结构对疾病扩散的影响。压缩包共21个文件,包含4个Python脚本…

2026/10/11 21:38:46

多元回归建模实战:从文档到可解释代码的完整链路

简介:本资源是一份面向数学建模初学者与高校统计类课程学习者的多元线性回归实战教学文档,聚焦城市粮食销售量预测这一典型经济建模问题,解决多因素影响下因变量建模、变量筛选、模型检验与经济解释等核心难点。文档以某市14年粮食年销售量&a…

2026/10/11 21:38:46

Oracle SQL与实例管理实战:从基础操作到故障排查

简介:《Oracle从入门到精通》是一份面向Oracle数据库初学者与初级开发人员的PDF学习资料,旨在帮助读者从零搭建数据库知识体系,理解SQL语言与数据库管理核心概念。资料内容系统完整,从SQL基本概念、用户认证与权限控制等安全基础入…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑