简介:基于YOLOv8-OBB的芯片引脚缺陷检测项目,结合TensorRT加速方案,面向计算机视觉、自动化等专业学生及工业质检开发者,解决芯片引脚微小缺陷的快速定位与分类问题。资源包含完整C++/CUDA源码、Python调用示例、YOLOv8-OBB配置及TensorRT部署文档,并附有实验记录与答辩总结,适合作为毕业设计、课程设计或工程落地的参考起点。压缩包内共394个文件,以C++头文件(h/hpp)、实现文件(cpp)、CUDA核函数(cu)为主,另有yaml配置、Markdown说明、PDF文档及少量示例图片,整体体积仅4.7MB,结构清晰便于查阅。目前已有63人学习下载,适合具备一定深度学习基础、希望掌握YOLOv8旋转目标检测与TensorRT加速技巧的读者深入研读。
1. 一枚引脚断裂的漏检,为什么v8-OBB和TensorRT能同时兜住
芯片引脚缺陷检测最大的痛点不是"看不见缺陷",而是"看得见却量不准"。引脚细、排布密、旋转角度随意,水平检测框一框往往框进好几根相邻引脚,导致缺陷定位和分类在源头上就是错的。基于yolov8_obb的芯片引脚缺陷检测方案,本质是把检测框从水平矩形换成可旋转的OBB框,让每个引脚都有独立的旋转边界,再用TensorRT把推理压到毫秒级,满足产线节拍。这套组合适合做SMT贴片后AOI复判、芯片来料质检的视觉工程师:你用普通YOLO跑过但漏检率高,或者跑得动但帧率不够,都可以直接照这篇的思路重做一遍。我下面讲的不是概念,而是从标注到训练到TensorRT部署的完整路径,包括那些让精度和速度同时翻车的细节。
2. 旋转框与TensorRT的底层逻辑:为什么引脚缺陷检测非OBB不可
2.1 OBB相比水平框的直接收益:IoU失真和NMS误杀
普通YOLO的水平框用一个矩形的四条边去逼近目标,遇到长条形引脚时,水平框里会有大量非目标区域。训练时的损失函数按IoU计算,水平框的IoU在引脚倾斜时会严重虚高——两根相邻、朝向不同的引脚,水平框的重叠率可能高达0.7,而实际区域完全不重叠。这直接导致两个问题:正负样本划分混乱,以及NMS阶段把相邻引脚的检测框当成重叠框抑制掉。我用普通YOLOv8跑过一批引线框架图片,漏检率接近15%,其中一半以上是因为相邻引脚的水平框IoU超过NMS阈值被删了。旋转框把目标描述从(x, y, w, h)变成(x, y, w, h, theta),多出来的一个角度参数让边界框能贴着引脚实际走向,水平框的IoU虚高问题在OBB里天然消失。
yolov8_obb对角度目标的建模和yolov8本身的anchor-free架构是兼容的。它去掉了anchor,直接在每个特征点预测边界框参数,OBB版本额外增加一个角度分支。训练时用Probiou这类旋转IoU损失来回归w、h和theta,不再单独把角度当成分类任务,所以角度预测的连续性和稳定性比早期基于分类的角度回归好很多。对芯片引脚这种长宽比经常大于5:1的细长目标,Probiou能保证损失函数在角度偏移时仍然平滑可导,不会出现训练早期梯度跳变导致的角度发散。
2.2 yolov8_obb的角度回归细节:长边定义法和周期性陷阱
OBB训练里最容易被忽略的是角度定义。yolov8_obb采用长边定义法:theta是长边与x轴正方向的夹角,范围[-π/2, π/2),w永远是长边,h永远是短边。这个定义和OpenCV的旋转矩形定义有区别,OpenCV里theta范围是[0, 90)且表示短边与x轴的夹角。若你从OpenCV的minAreaRect结果直接写入训练标签,等于把角度定义全部搞反,训练出来模型会在小角度上震荡、在接近±π/2边界时彻底翻车。因此数据准备的第一步,是统一所有标注到yolov8_obb的坐标系约定,而不是拿到标注就直接训。
角度周期性的问题只靠定义统一还不够。推理阶段输出的角度需要做周期归约,否则两个物理上完全相同的框,一个角度0.1,一个角度-1.56,明明重叠率接近1却被NMS当成两个框。我一般会用的是把角度差投影到[-π/2, π/2)最短弧,再结合IoU做判据。yolov8_obb的推理代码里内置了这个逻辑,但你自己写TensorRT后处理时最容易漏掉,后面部署小节的代码会给完整实现。
2.3 TensorRT加速的底层逻辑:不只是把FP32换成FP16
TensorRT的加速不全是低精度数值计算带来的,有两部分占了很大权重。第一是层融合,把卷积加偏置加激活函数这类小算子合并成单个kernel,减少显存中间缓冲和kernel启动开销;第二是kernel自动调优,同一个算子根据输入shape、GPU架构选择最优的CUDA实现。这两步操作下来,同样的网络结构通常能比原生PyTorch推理快2到4倍。
对OBB检测模型来说,TensorRT优化空间集中在backbone和neck,检测头里的Probiou计算在部署阶段是不需要的,推理时只需要解码出旋转框坐标再跑旋转NMS。因此导出ONNX时要把训练时的损失函数相关的分支全部剥掉,只保留前向推理的prediction分支。yolov8_obb原始导出代码里有一个robust_onnx参数,打开后会自动把输出整理成统一格式的tensor,省去后续对输出结构调整的麻烦。但即便用这个参数,输出还是包含所有anchor的原始预测结果,解码和后处理仍然要自己写。我见过不少人在TensorRT里跑OBB推理,输出拿到了却不知道每个通道代表什么,最后解码错位,把所有检测框画成了乱线。正确的输出布局是[1, 4+1+num_classes, num_anchors],其中前四个是cx、cy、w、h,第五个是角度theta,后面跟着各类别置信度。拿到这个tensor后,解码就是纯矩阵运算,CPU也能跑得很稳。
3. 数据准备与训练落地:标注格式转换脚本和关键超参
3.1 DOTA多边形标注转yolov8_obb格式:最小外接矩形不是唯一答案
常见的芯片引脚数据集标注格式有两类:一类是DOTA格式,用四个角点的八个数(x1, y1, x2, y2, x3, y3, x4, y4)表示任意四边形;另一类是PASCAL VOC的四边形标签。yolov8_obb训练需要的是旋转矩形五参数[cx, cy, w, h, theta],所以第一步是把多边形转成最小外接矩形。这个转换本身不难,但有个前提:芯片引脚虽然是长条形,但引脚根部可能有锡球鼓起,四个角点不构成严格矩形。此时直接取最小外接矩形会把检测框拉长,把相邻引脚的根部包进来,导致训练时标签本身就带噪声。我在实际处理时会对坐标做一次凸包再取旋转外接框,少数明显变形的引脚手动修正标注,不建议全自动转完就训。
转换脚本如下,依赖shapely库,直接跑在标注导出的JSON或TXT上:
# polygon_to_obb.py import numpy as np from shapely.geometry import Polygon from shapely.ops import orient def polygon_to_obb(points): # points: [(x1,y1), (x2,y2), (x3,y3), (x4,y4)] 或更多点 poly = orient(Polygon(points), sign=1.0) # 取最小外接旋转矩形 mrr = poly.minimum_rotated_rectangle coords = list(mrr.exterior.coords)[:4] p1, p2, p3, p4 = coords # p1->p2 和 p2->p3 哪个更长,长边就是哪条 len12 = ((p2[0]-p1[0])**2 + (p2[1]-p1[1])**2) ** 0.5 len23 = ((p3[0]-p2[0])**2 + (p3[1]-p2[1])**2) ** 0.5 if len12 >= len23: cx = (p1[0]+p3[0]) / 2.0 cy = (p1[1]+p3[1]) / 2.0 w = len12 h = len23 theta = np.arctan2(p2[1]-p1[1], p2[0]-p1[0]) else: cx = (p1[0]+p3[0]) / 2.0 cy = (p1[1]+p3[1]) / 2.0 w = len23 h = len12 theta = np.arctan2(p3[1]-p2[1], p3[0]-p2[0]) theta = theta % np.pi # 长边定义法需要归一化到 [-pi/2, pi/2) if theta >= np.pi / 2.0: theta -= np.pi if w < h: w, h = h, w theta = (theta + np.pi/2) % np.pi if theta >= np.pi / 2.0: theta -= np.pi return cx, cy, w, h, theta这段脚本有两个关键设计。第一,不管角点顺序怎么乱,都先通过Polygon的orient统一成逆时针序,避免取到凹多边形导致的外接矩形方向错误。第二,theta严格按长边定义法归一化到[-π/2, π/2),且当计算出的w小于h时主动交换长短边,保证训练标签的坐标系和你推理时的假设完全一致。类型上要注意,shapely的minimum_rotated_rectangle返回的坐标是浮点,标注文件里有些是整型像素坐标,直接相减会得到负数长度,需要全部转成float再运算。
所有标注转换完成后,建议做一次绘图验证。把转换后的五参数重新画回图像上,转成polygon格式叠加在原图上检查,重点看边缘引脚和密集排布区域。这一步看起来多余,实际上能拦截掉八成标注坐标系错误:如果框的方向和引脚走向出现系统性的90度偏差,几乎可以肯定是长边定义没有落实。
3.2 数据集划分与增强:别把同一条芯片的引脚同时放进训练集和验证集
引脚缺陷数据的特殊性在于同一颗芯片上的几十个引脚在光照、底色、周围干扰上高度一致,如果把同一条芯片的图片切到不同集合里,验证集就会和训练集高度相似,测出来的mAP虚高。整个实验看起来能到95%准确率,换到真实产线立刻掉到80%以下,这是典型的划分泄漏。正确做法是:按芯片实例划分数据集,同一颗芯片的所有引脚、所有缺陷属于同一个文件或同一个批次,保证完整分到训练集或验证集的一侧。缺陷跨度是生产时间线的横向对比时,还要保证同一块料盘的照片不跨集合划分。
数据增强要针对OBB的特点调整。mosaic增强在合并多张图时,旋转框标签需要跟着拼图变换一起做仿射变换,yolov8_obb的数据增强管线已经处理好了这部分,但有一个参数要手动调:angle增强幅度。默认的random_perspective里角度扰动范围是0度,我建议设为0.5度到1度。引脚的方向是产品质量的一部分,过大的角度旋转增强会让模型学到"引脚可以弯曲"的错误先验,反而削弱对弯曲引脚的检出能力。但完全不旋转又会让模型在小角度变化下过拟合,0.5度的扰动能在不影响语义的前提下增加角度泛化性。
另一个建议是提高hsv增强中的饱和度扰动。芯片引脚在视觉上是金属反光面,不同批次表面的氧化程度差异明显,把saturation范围从默认的0.5调到0.7,能让模型对光照批次差异更加鲁棒。
3.3 训练配置:yaml文件里的关键超参和训练命令
训练配置文件建议直接在ultralytics的obb_yolov8n.yaml基础上改,类名按你的标签类别清单定义。imgsz我建议用640,芯片引脚这类小目标在640分辨率下细节足够,过大的分辨率会显著增加TensorRT部署的延迟。batchsize按显存定,训练阶段用自动混合精度能省一半显存,bs16跑在12G显存上基本够用。epochs300起步,数据集量小(几百张芯片图)时建议配合早停机制,引言脚数据的类间不平衡比较明显,正常引脚作为背景、缺陷引脚作为前景,前景占比极低,训练前期mAP会在一个低值平台卡很久。这时不要急,等mAP过了前30个epoch的爬坡期后面会慢慢涨上来。
训练命令直接用CLI启动,指定obb的yaml和模型权重:
yolo train \ model=yolov8n-obb.yaml \ data=pin_defect_obb.yaml \ imgsz=640 \ batch=16 \ epochs=300 \ lr0=0.01 \ lrf=0.01 \ project=pin_obb \ name=exp01 \ amp=True这里面lr0选0.01是迁移学习合适的范围,因为模型是从yolov8n-obb预训练权重出发的,不是从零训练;如果你是从随机权重开始训自己改的网络头,建议降到0.001。amp=True在A100或V100这种支持完整卷积分数的卡上没问题,但在部分低端卡上会自动关闭某些不支持的算子,训练速度会下降但不影响结果。关键点在name参数,记录好每次实验的配置和训练集,方便后面复盘哪些缺陷类型在哪个epoch开始收敛。训练完成后,用best.pt做测试集评估,注意YOLO评估指标里mAP50-95对OBB要额外关注Large Error Index,它专门衡量旋转框的角度误差,只盯着mAP50看会漏掉角度回归质量的问题。
4. TensorRT部署全流程:从导出ONNX到trtexec再到推理解码
4.1 导出ONNX:去掉训练分支,固定动态维度
训练完导出onnx是TensorRT部署的第一道关卡。ultralytics提供了export接口,但直接导出后你的模型权重里还包含训练时用到的Probiou分支、辅助损失头之类的东西,这些在推理时完全不需要。导出时设置opset=12,太高或太低都可能导致TensorRT不兼容个别算子。yolov8_obb的导出代码支持robust_onnx,建议打开,它会把输出整理成单一tensor接口。导出命令如下:
yolo export \ model=best.pt \ format=onnx \ imgsz=640 \ opset=12 \ robust_onnx=True \ simplify=Trueparam说明:simplify=True会用onnx-simplifier对计算图做一轮常量折叠和算子合并,这样输出的onnx体量更小,TensorRT解析更快。robust_onnx=True很关键,它会去掉训练头、整理输出维度,否则你得到的输出节点可能是三个不同shape的tensor,后续处理难度增加不少。遇到导出失败先检查模型训练时的AMP参数,部分老版本ultralytics导出的权重在AMP回退后带有非标准的scale层,会影响后续转engine的精度。
导出的onnx可以在Netron里看一遍,只要你看到输入节点是images: 1x3x640x640,输出节点是1x(4+1+nc)x8400的tensor,就说明导出结构是完整的。8400是640分辨率下三个尺度的anchor总数,具体数值是640/8=80的平方加上40的平方加上20的平方。如果这个数不对,说明输入shape和模型配置不匹配。
4.2 trtexec转engine:FP16与动态shape的参数取舍
TensorRT的engine转换最稳定的是直接用trtexec命令,不需要写C++或Python代码。环境上先确认TensorRT对应CUDA版本,一般TensorRT 8.5对应CUDA 11.8,TensorRT 8.6对应CUDA 12.x,版本错位会导致engine构建失败或运行期报错。安装路径在/usr/src/tensorrt/bin/trtexec,ubuntu上装了TensorRT的话直接全路径调用。
转engine的命令:
/usr/src/tensorrt/bin/trtexec \ --onnx=best_obb.onnx \ --saveEngine=best_obb_fp16.engine \ --fp16 \ --workspace=4096 \ --minShapes=images:1x3x640x640 \ --optShapes=images:8x3x640x640 \ --maxShapes=images:16x3x640x640 \ --verbose前两个参数是固定格式,不用多说。--fp16把模型精度降到半精度,这一步带来的加速大约1.5到2倍,但代价是部分敏感层的数值范围压缩。--workspace=4096指定构建时允许TensorRT使用的临时显存上限,单位是MB,4G基本够yolov8n这个体量,设太大在显存小的卡上会build失败。三个shape参数定义了动态batch的边界:minShapes保证至少能跑batch1,optShapes是TensorRT优化性能时参考的目标batch,maxShapes是显存允许的上限。这个设置覆盖真实产线的batch需求,如果只按batch1优化而部署时用batch4,性能会有明显回退。
转出来的engine可以直接用trtexec自带的benchmark模式看性能,命令后面加--dumpProfile会输出每个算子的耗时分布。不要只看总耗时,要看它们是否集中在某个异常慢的算子。常见情况是OBB检测头的输出解析算子没有做层融合,单个kernel耗时比整个backbone还高。这时需要回看onnx导出时的robust_onnx选项,确认输出是单一节点而不是多个零散节点。
4.3 推理代码与解码:旋转框的还原和旋转NMS
engine文件拿到手之后,写推理代码的核心是预处理和后处理。预处理沿用了YOLO的letterbox,把原始图像按比例缩放到640x640,剩余部分用灰色填充。这里有个隐患:芯片引脚缺陷检测的输入往往是高分辨率大图(例如3000x3000的料盘整体图),如果直接缩放成640x640,小引脚会被压缩到几个像素,细节全丢。常见做法是在预处理前先按芯片区域或者料盘区域做切片,对每个切片做推理。切片重叠率控制在10%到20%,避免引脚正好卡在切边处被裁掉一半导致漏检。
预处理代码和推理调用:
# tensorrt_obb_infer.py import numpy as np import cv2 import tensorrt as trt def preprocess(img, size=640): h, w = img.shape[:2] scale = min(size / w, size / h) nw, nh = int(w * scale), int(h * scale) img_resized = cv2.resize(img, (nw, nh), interpolation=cv2.INTER_LINEAR) canvas = np.full((size, size, 3), 114, dtype=np.uint8) x_off = (size - nw) // 2 y_off = (size - nh) // 2 canvas[y_off:y_off+nh, x_off:x_off+nw] = img_resized # 归一化到 [0,1] 并转CHW canvas = canvas.astype(np.float32) / 255.0 canvas = canvas.transpose(2, 0, 1)[None] return canvas, scale, x_off, y_off # engine推理 with open('best_obb_fp16.engine', 'rb') as f: engine_data = f.read() runtime = trt.Runtime(trt.Logger(trt.Logger.WARNING)) engine = runtime.deserialize_cuda_engine(engine_data) context = engine.create_execution_context() # 输入x为预处理后的tensor,output为 (1, 4+1+nc, 8400)后处理解码是OBB推理的核心,拿到的输出tensor要先解析出cx、cy、w、h、theta和各类别分数,再做阈值过滤和旋转NMS:
def decode_obb(pred, conf_thres=0.25): # pred shape: (1, 4+1+nc, 8400) pred = pred[0] # (6+nc, 8400) cx, cy, w, h, theta = pred[:5] scores = pred[5:] # (nc, 8400) 各类别分数 cls_ids = np.argmax(scores, axis=0) max_scores = scores[cls_ids, np.arange(scores.shape[1])] keep = max_scores > conf_thres boxes = np.stack([cx[keep], cy[keep], w[keep], h[keep], theta[keep]], axis=1) cls_ids = cls_ids[keep] scores = max_scores[keep] # 这里还要做旋转NMS,核心是角度差周期归一化 # diff = np.abs(boxes[:,4][:,None] - boxes[:,4][None,:]) # diff = np.minimum(diff, np.pi - diff) return boxes, cls_ids, scores这段代码里解码逻辑相对直白,最值得留意的是置信度取法。yolov8的类别分数已经包含objectness和class条件分数的乘积形式,不需要再单独乘一次objectness,直接取max即可。旋转NMS部分我做了注释,diff算完后按IoU过滤,角度归一化那步一定不能省。解码出的cx、cy、w、h是letterbox坐标系下的值,要还原到原图,需要减去letterbox的偏移再除以缩放比例。这一步骤的精度直接决定检测框是否贴住引脚边缘,不少人在这个环节把坐标换算出错,导致框的位置整体偏移几个像素。
5. 部署避坑:5个让精度和速度同时翻车的细节
5.1 精度暴跌:FP16量化把角度回归的敏感层压坏了
现象:同一个模型在PyTorch里fp32推理mAP50有92%,转成TensorRT FP16 engine后mAP掉到84%,而且主要掉在小角度引脚上。原因:角度回归分支对数值精度比分类分支更敏感,FP16的尾数精度大约只有FP32的千分之一,当theta的预测值接近0时,梯度和前向计算中的微小截断误差会被放大,导致角度偏移。解决:第一步先试--fp16 + 带校准集的INT8,如果还不行,就把角度预测分支单独拆出来用FP32精度。TensorRT不支持直接在onnx里指定混合精度的话,可以导出两个onnx——一个只包含角度分支的FP32,其余用FP16,推理时把两个输出拼起来。实际项目中这个做法能把精度损失从6%压到1%以内。注意一定要用同一个校准集做验证,不要只在测试集上看指标,校准集和测试集分布不一致会导致误判。
5.2 旋转NMS把相邻正常引脚误杀了
现象:部署后检测结果里正常引脚频繁被过滤,输出框数量明显少于实际引脚数,缺陷引脚反而没被抑制。原因:旋转NMS在计算IoU时没有处理角度的周期性。两个引脚,一个角度0.1弧,一个角度-1.53弧(相当于0.1+π/2),物理上夹角只有约0.06弧,几乎重合;但角度差算出来是1.6弧,IoU计算时把旋转矩形当成完全不重叠,两个框都保留,看起来像是多检。NMS排序时把低置信度的有效检测框删了,高置信度的相邻框却保留下来。解决:NMS的IoU计算前要把角度差归约到[-π/2, π/2),用最短弧距离替换直接差值。写一个旋转IoU的临时实现,直接对每对框做几何计算,或者用旋转IoU的近似公式,关键在于角度差要先归一化再求交叠面积。
5.3 dynamic shape的engine在部署时显存报错
现象:trtexec构建engine一切正常,但部署到生产服务器上第一次推理就报CUDA OOM,或者延迟极不稳定。原因:--maxShapes设得过大(比如设了32),TensorRT按maxShapes预分配了优化所需的显存,而部署机器的显存比构建机器小。构建时Transformer用的是16G显存的卡,部署端是8G的卡,启动即崩溃。解决:部署前用trtexec的--maxShapes小参数重新构建一个适配部署卡的engine。动态batch的engine在不同batch之间切换时有少量开销,如果生产环境的batch固定是1,直接用静态shape构建,不要用动态shape。静态shape的engine在kernel选择上可以做得更激进,同一块显卡上一般能再快5%到10%。
5.4 letterbox压缩导致边缘引脚漏检
现象:大片料盘的图片缩放到640x640后,料盘边缘的引脚大量漏检,中间的引脚检测正常。原因:letterbox等比缩放,3000x3000的输入缩放到640,引脚宽度从原来约15像素缩到3像素,卷积神经网络在3像素宽的目标上特征提取能力急剧下降。而且料盘边缘的镜头畸变让引脚走向和训练集分布产生偏差。解决:不要对整个大图直接缩放,做一个推理切片的滑动窗口。窗口大小设为正方形,步长取窗口的80%到90%,每个窗口独立推理,最后把结果合并。实测切片后边缘漏检率能降回正常水平。如果不想写切片逻辑,也可以用两阶段方案:先用一个低分辨率模型定位芯片区域,再把芯片区域裁剪出来送OBB模型。这个方案额外增加一次推理,但对多芯片大料盘的场景更友好。
5.5 训练和推理的角度定义不一致,性能神秘波动
现象:同一份模型,在训练时的验证集上角度误差正常,导出的engine单独跑同一张图,角度输出却偏差很大,有时候正好偏90度。原因:训练时的归一化逻辑和推理时解码逻辑对角度范围的理解不一致。yolov8_obb训练时theta范围是[-π/2, π/2),解码时如果按照[0, 2π) 范围做角度还原,两边差了一个周期。还有部分版本的yolov8_obb使用角度分类分支而不是回归分支,输出的角度索引还原成弧度时,索引到角度的映射表可能和训练时用的表不同。解决:写一个快速的校验脚本,在训练集的真实标签里统计theta的分布直方图。如果theta在[-π/2, π/2)区间内连续分布,说明是回归分支;如果分布集中在几个离散值,说明是分类分支。按实际分支类型对解码逻辑做适配,并在推理代码里加单元断言:解码后的角度范围必须落在预期区间,否则直接抛异常提醒。
6. 验证方法:把端到端延迟量化到毫秒,估算单卡多路承载
部署完成后不要只看模型推理时间,那只能说明engine快,不能说明产线能用。端到端延迟包括图像解码、缩放、传输到GPU、推理、后处理、结果回传,这里面任何一环都可能成为瓶颈。我用CUDA事件来做GPU计时,它比python的time.time()准确得多。流程是先跑20次预热把TensorRT的kernel完全加载,再跑100次正式推理取平均值。CUDA事件的用法是:
# timing.py start = cuda.Event() end = cuda.Event() start.record() # 执行推理 end.record() end.synchronize() ms = start.elapsed_time(end)关键点:end.record后面必须跟end.synchronize(),否则计时器提前返回,测出来的延迟全部是0。预热次数不要少于20次,TensorRT第一次推理会做运行时显存分配和kernel初始化,前几次延迟可能高达几十毫秒,预热不充分会把性能测成伪劣结果。我通常测三组数据:只测inference(engine执行),测推理加后处理,测完整摄像头到结果输出。后处理在CPU上跑时,要关注旋转NMS对8400个anchor的处理耗时,一般控制在2到3毫秒内,如果超过5毫秒说明NMS实现有优化空间。
多路承载的估算可以按这个逻辑做。假设T4单卡、TensorRT FP16、yolov8n-obb模型、640x640输入、batch1,我实测的engine推理延迟大约在8到12毫秒之间(T4的单精度算力弱于消费级卡,但TensorRT优化后比同卡上PyTorch快2到3倍)。一路1080p视频流25帧每秒,每帧预算40毫秒。一张T4单卡每毫秒可以处理约0.1帧,40毫秒预算内可以处理4帧,也就是理论4路。考虑图像解码和预处理也占GPU周期,实际建议降到3路,留30%的余量防止延迟尖峰。如果换成yolov8m-obb,推理延迟会到15到20毫秒,那就只建议跑1到2路。你可以根据自己模型的实测数据,用这个公式直接算:可承载路数 = 1000 /(单帧端到端毫秒数 × 25)。这个公式里幻觉风险最大的变量是端到端毫秒数,所以我总是强调要先测后算。
我习惯把每次的engine延迟、精度对比、NMS耗时记到一张表里,换TensorRT版本或者显卡驱动时重新跑一遍同样的脚本。有一次升级驱动后T4的FP16推理慢了3毫秒,排查后是驱动把默认的时钟策略改成了低功耗,用nvidia-smi固定到最高性能模式就好了。这类玄学问题会反复出现,保存好基准数据,比看文档猜测快得多。整套方案做下来,从标注转换到TensorRT部署的路径已经完整跑通。芯片引脚这类细长旋转目标,用yolov8_obb加上TensorRT是现有开源方案里性价比最高的组合。希望帮到你。
本文还有配套的精品资源,点击获取