如何优化YOLOv8+SORT目标检测追踪代码以充分利用GPU算力?
如何优化YOLOv8+SORT目标检测追踪代码以充分利用GPU算力?
嘿,我来帮你排查并优化你的YOLOv8+SORT代码,让你的RTX4060Ti真正跑起来!GPU使用率低通常是因为大量计算在CPU上跑或者数据传输开销太大,咱们一步步来解决:
1. 先确认GPU环境真的生效
先在代码开头加几行验证,确保PyTorch确实在调用你的GPU:
print(f"CUDA可用: {torch.cuda.is_available()}") print(f"当前GPU: {torch.cuda.get_device_name(0)}") print(f"PyTorch CUDA版本: {torch.version.cuda}")
如果输出里看不到RTX4060Ti,那可能是环境没配好——比如重新安装和系统CUDA版本匹配的PyTorch,这是基础前提。
2. 把YOLOv8的推理和预处理全移到GPU
你现在的代码里,cap.read()得到的帧是CPU上的numpy数组,虽然YOLO会自动转GPU,但手动优化预处理流程能减少传输开销:
while True: ret, frame = cap.read() if not ret: print("**No frame received**") continue # 直接把帧转成GPU张量,跳过CPU到GPU的隐式转换 frame_tensor = torch.from_numpy(frame).to(device).permute(2, 0, 1).float() / 255.0 # 添加batch维度(YOLOv8默认接受批量输入) frame_tensor = frame_tensor.unsqueeze(0) # 用半精度推理,大幅提升速度(RTX4060Ti完美支持FP16) results = model(frame_tensor, half=True, verbose=False)
用model()直接推理比model.predict()更轻量,适合实时场景。
3. 改造SORT追踪器,让它在GPU上运行
这是核心!默认的SORT完全用numpy在CPU上计算,会吃掉大量CPU资源,同时让GPU闲下来。你需要修改src/sort.py里的代码,把所有计算移到GPU:
- 把所有numpy数组换成
torch.cuda.Tensor - 用PyTorch的
torchvision.ops.box_iou代替SORT里的CPU版IOU计算 - 把卡尔曼滤波的矩阵运算改成PyTorch的GPU张量运算
比如改造后的SORT update方法核心部分:
# 改造后直接接收GPU上的检测框张量 def update(self, dets=None): if dets is not None: # 用GPU加速的IOU计算 iou_matrix = torchvision.ops.box_iou(self.tracks_boxes, dets[:, :4]) # 剩下的匹配、卡尔曼更新都用GPU张量完成 ...
这样SORT的核心计算就全在GPU上了,CPU负载会立刻降下来。
4. 用OpenCV的CUDA模块加速帧处理
你已经编译了带CUDA的OpenCV,一定要用上它的GPU加速函数!比如帧的resize、格式转换都用CUDA版本:
# 把CPU帧上传到GPU gpu_frame = cv2.cuda_GpuMat() gpu_frame.upload(frame) # 用CUDA版resize代替CPU版 gpu_resized = cv2.cuda.resize(gpu_frame, (640, 640)) # 直接从GpuMat转成PyTorch张量,不用先下载回CPU frame_tensor = torch.as_tensor(gpu_resized.download(), device=device).permute(2,0,1).float()/255.0
这一步能减少CPU在帧预处理上的开销。
5. 减少不必要的CPU-GPU数据传输
原来的代码里,你可能会把GPU上的检测结果转到CPU给SORT,再把追踪结果转回GPU——这来回传输非常耗时。改造SORT后,让检测框和追踪框全程留在GPU上,直到最后要画框显示的时候,再把结果转到CPU:
# 推理得到GPU上的检测框 detections = results[0].boxes.data # 这是cuda张量 # 传给改造后的GPU版SORT tracks = sort_tracker.update(detections) # 最后要画框时,再转到CPU tracks_cpu = tracks.cpu().numpy() # 用OpenCV画框(这部分只能在CPU) for track in tracks_cpu: x1, y1, x2, y2, track_id = track cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0,255,0), 2)
6. 其他小优化
- 关闭YOLOv8的verbose输出:
verbose=False,减少CPU的日志处理 - 固定输入尺寸:比如
imgsz=640,不要动态改变,让GPU保持稳定的计算负载 - 关闭不必要的后处理:如果不需要分割掩码等结果,推理时指定
task='detect'
备注:内容来源于stack exchange,提问作者S Andrew




