• [技术干货] 如何在Python中调用C++版本的ByteTrack跟踪算法
    如何在Python中调用C++版本的ByteTrack跟踪算法这个项目提供了基于ByteTrack-TensorRT的Python插件,并在原有算法基础上提供了跟踪目标的类别信息,Jetson Orin Nano在之前YOLOv5插件的基础上实现高达83 FPS的实时检测跟踪性能。⚡ 极致性能: 基于TensorRT优化,充分利用硬件加速📦 开箱即用:构建过程简单,快速部署您的跟踪应用🐍 Python 友好: 使用Pybind11提供简洁Python接口📱 边缘设备优化: 特别针对Jetson边缘设备进行适配Build plugin首先安装必要的库克隆仓库构建项目,注意JetPack 5.x版本才能正常运行:sudo apt update sudo apt install ffmpeg sudo apt install pybind11-dev sudo apt install libeigen3-dev git cone https://github.com/HouYanSong/bytetrack_pybind11.git cd bytetrack_pybind11 pip install pybind11 rm -fr build cmake -S . -B build cmake --build build[ 12%] Building CXX object CMakeFiles/bytetrack.dir/bytetrack/src/BYTETracker.cpp.o [ 25%] Building CXX object CMakeFiles/bytetrack.dir/bytetrack/src/STrack.cpp.o [ 37%] Building CXX object CMakeFiles/bytetrack.dir/bytetrack/src/kalmanFilter.cpp.o [ 50%] Building CXX object CMakeFiles/bytetrack.dir/bytetrack/src/lapjv.cpp.o [ 62%] Building CXX object CMakeFiles/bytetrack.dir/bytetrack/src/utils.cpp.o [ 75%] Linking CXX shared library libbytetrack.so [ 75%] Built target bytetrack [ 87%] Building CXX object CMakeFiles/bytetrack_trt.dir/bytetrack_trt.cpp.o [100%] Linking CXX shared module bytetrack_trt.cpython-38-aarch64-linux-gnu.so [100%] Built target bytetrack_trtRun demo我们提供了一个简单的Python示例,只需要导入C++构建的Python动态链接库就可以非常方便的调用ByteTrack跟踪算法,返回目标位置、跟踪ID和类别信息。import cv2 import time import ctypes # 加载依赖库 ctypes.CDLL("./yolov5_trt_plugin/libyolo_plugin.so", mode=ctypes.RTLD_GLOBAL) ctypes.CDLL("./yolov5_trt_plugin/libyolo_utils.so", mode=ctypes.RTLD_GLOBAL) ctypes.CDLL("./build/libbytetrack.so", mode=ctypes.RTLD_GLOBAL) # 导入YOLOv5检测器和ByteTrack跟踪器 from yolov5_trt_plugin import yolov5_trt from build import bytetrack_trt def draw_image(image, detections, tracks, fps): for track in tracks: x, y, w, h = track.tlwh track_id = track.track_id class_id = track.label x1, y1, x2, y2 = int(x), int(y), int(x+w), int(y+h) cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(image, f"C:{class_id} T:{track_id}", (x1, y1 - 10), cv2.FONT_HERSHEY_PLAIN, 1.2, (0, 0, 255), 2) cv2.putText(image, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 0, 255), 2) return image def main(input_path, output_path): cap = cv2.VideoCapture(input_path) fps_value = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'MJPG'), fps_value, (width, height)) detector = yolov5_trt.YOLOv5Detector("./yolov5_trt_plugin/yolov5s.engine", width, height) tracker = bytetrack_trt.BYTETracker(frame_rate = fps_value, track_buffer = 30) fps_list = [] frame_count = 0 total_time = 0.0 while cap.isOpened(): ret, frame = cap.read() if not ret: break start_time = time.time() # 目标检测 detections = detector.detect(input_image=frame, input_w=640, input_h=640, conf_thresh=0.45, nms_thresh=0.55) objects = [] for det in detections: x1, y1, x2, y2 = det['bbox'] rect = bytetrack_trt.RectFloat(x1, y1, x2-x1, y2-y1) # x, y, width, height obj = bytetrack_trt.Object() obj.rect = rect obj.label = det['class_id'] obj.prob = det['confidence'] objects.append(obj) # 目标跟踪 tracks = tracker.update(objects) process_time = time.time() - start_time current_fps = 1.0 / process_time if process_time > 0 else 0 frame_count += 1 total_time += process_time fps_list.append(current_fps) # 图像绘制 image = draw_image(frame, detections, tracks, current_fps) writer.write(image) cap.release() writer.release() if frame_count > 0: avg_fps = frame_count / total_time if total_time > 0 else 0 print(f"Processed {frame_count} frames") print(f"Average FPS: {avg_fps:.2f}") print(f"Min FPS: {min(fps_list):.2f}") print(f"Max FPS: {max(fps_list):.2f}") if __name__ == "__main__": input_video = "./media/sample_720p.mp4" output_video = "./result.avi" main(input_video, output_video) 仅需在终端中运行yolov5_bytetrack.py脚本:python yolov5_bytetrack.py[11/07/2025-17:13:10] [I] [TRT] Loaded engine size: 8 MiB Deserialize yoloLayer plugin: YoloLayer [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +536, GPU +702, now: CPU 841, GPU 3927 (MiB) [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +83, GPU +94, now: CPU 924, GPU 4021 (MiB) [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] TensorRT-managed allocation in engine deserialization: CPU +0, GPU +7, now: CPU 0, GPU 7 (MiB) [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +0, GPU +0, now: CPU 924, GPU 4021 (MiB) [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +0, GPU +1, now: CPU 924, GPU 4022 (MiB) [11/07/2025-17:13:12] [I] [TRT] [MemUsageChange] TensorRT-managed allocation in IExecutionContext creation: CPU +0, GPU +11, now: CPU 0, GPU 18 (MiB) Init ByteTrack! Processed 1442 frames Average FPS: 83.78 Min FPS: 68.31 Max FPS: 113.35 Conclusion Remarks本文实现了ByteTrack-TensorRT跟踪算法的Python插件,并在原有算法基础上提供了跟踪目标的类别信息,Jetson Orin Nano (8GB)上的YOLOv5实时目标检测和跟踪速度高达80FPS,满足对快速运动目标的跟踪需求。
  • [技术干货] 如何在Jetson上将YOLOv5实时检测速度提升至120+FPS
    如何在Jetson上将YOLOv5实时检测速度提升至120+FPS这个项目提供了基于 Pybind11 的 TensorRT YOLOv5 插件 Python 绑定,实现了令人难以置信的实时目标检测性能!⚡ 超100FPS性能: 在 Jetson Orin Nano 上轻松实现超过 120 帧/秒的检测速度🎯 高精度检测: 基于成熟的 YOLOv5 架构,准确识别COCO数据集上的80类目标🔌 即插即用: 简单的 Python 接口,无需复杂的配置🛠️ 工业级优化: 采用 TensorRT 进行模型优化和加速1. Building the plugin首先安装必要的库克隆仓库构建项目,注意JetPack 5.x版本才能正常运行:sudo apt update sudo apt install ffmpeg sudo apt install pybind11-dev git clone https://github.com/HouYanSong/yolov5_trt_pybind11.git cd yolov5_trt_pybind11 pip install pybind11 rm -fr build cmake -S . -B build cmake --build build2. Model quantization生成量化图片对YOLOv5s模型进行Int8量化,保存量化后的模型:./media/gen_calib.sh ./build/build weights/yolov5s.onnx 1 ./media/ ./media/filelist.txt weights/yolov5s.engine[11/06/2025-11:57:36] [I] [TRT] [MemUsageChange] Init CUDA: CPU +221, GPU +0, now: CPU 249, GPU 4229 (MiB) [11/06/2025-11:57:39] [I] [TRT] [MemUsageChange] Init builder kernel library: CPU +302, GPU +277, now: CPU 574, GPU 4529 (MiB) [11/06/2025-11:57:39] [I] [TRT] ---------------------------------------------------------------- [11/06/2025-11:57:39] [I] [TRT] Input filename: weights/yolov5s.onnx [11/06/2025-11:57:39] [I] [TRT] ONNX IR version: 0.0.7 [11/06/2025-11:57:39] [I] [TRT] Opset version: 12 [11/06/2025-11:57:39] [I] [TRT] Producer name: [11/06/2025-11:57:39] [I] [TRT] Producer version: [11/06/2025-11:57:39] [I] [TRT] Domain: [11/06/2025-11:57:39] [I] [TRT] Model version: 0 [11/06/2025-11:57:39] [I] [TRT] Doc string: [11/06/2025-11:57:39] [I] [TRT] ---------------------------------------------------------------- [11/06/2025-11:57:39] [I] [TRT] No importer registered for op: YoloLayer_TRT. Attempting to import as plugin. [11/06/2025-11:57:39] [I] [TRT] Searching for plugin: YoloLayer_TRT, plugin_version: 1, plugin_namespace: [11/06/2025-11:57:39] [I] [TRT] Successfully created plugin: YoloLayer_TRT [11/06/2025-11:57:39] [I] sample0001.png [11/06/2025-11:57:39] [I] sample0002.png [11/06/2025-11:57:39] [I] sample0003.png [11/06/2025-11:57:39] [I] sample0004.png [11/06/2025-11:57:39] [I] sample0005.png [11/06/2025-11:57:39] [I] sample0006.png [11/06/2025-11:57:39] [I] sample0007.png [11/06/2025-11:57:39] [I] sample0008.png [11/06/2025-11:57:39] [I] sample0009.png [11/06/2025-11:57:39] [I] sample0010.png [11/06/2025-11:57:39] [I] sample0011.png [11/06/2025-11:57:39] [I] sample0012.png [11/06/2025-11:57:39] [I] sample0013.png [11/06/2025-11:57:39] [I] sample0014.png [11/06/2025-11:57:39] [I] sample0015.png [11/06/2025-11:57:39] [I] sample0016.png [11/06/2025-11:57:39] [I] sample0017.png [11/06/2025-11:57:39] [I] sample0018.png [11/06/2025-11:57:39] [I] sample0019.png [11/06/2025-11:57:39] [I] sample0020.png [11/06/2025-11:57:39] [I] sample0021.png [11/06/2025-11:57:39] [I] sample0022.png [11/06/2025-11:57:39] [I] sample0023.png [11/06/2025-11:57:39] [I] sample0024.png [11/06/2025-11:57:39] [I] sample0025.png [11/06/2025-11:57:39] [I] sample0026.png [11/06/2025-11:57:39] [I] sample0027.png [11/06/2025-11:57:39] [I] sample0028.png [11/06/2025-11:57:39] [I] sample0029.png [11/06/2025-11:57:39] [I] sample0030.png [11/06/2025-11:57:39] [I] sample0031.png [11/06/2025-11:57:39] [I] sample0032.png [11/06/2025-11:57:39] [I] sample0033.png [11/06/2025-11:57:39] [I] sample0034.png [11/06/2025-11:57:39] [I] sample0035.png [11/06/2025-11:57:39] [I] sample0036.png [11/06/2025-11:57:39] [I] sample0037.png [11/06/2025-11:57:39] [I] sample0038.png [11/06/2025-11:57:39] [I] sample0039.png [11/06/2025-11:57:39] [I] sample0040.png [11/06/2025-11:57:39] [I] sample0041.png [11/06/2025-11:57:39] [I] sample0042.png [11/06/2025-11:57:39] [I] sample0043.png [11/06/2025-11:57:39] [I] sample0044.png [11/06/2025-11:57:39] [I] sample0045.png [11/06/2025-11:57:39] [I] sample0046.png [11/06/2025-11:57:39] [I] sample0047.png [11/06/2025-11:57:39] [I] sample0048.png [11/06/2025-11:57:39] [I] sample0049.png [11/06/2025-11:57:39] [I] sample0050.png [11/06/2025-11:57:39] [I] sample0051.png [11/06/2025-11:57:39] [I] sample0052.png [11/06/2025-11:57:39] [I] sample0053.png [11/06/2025-11:57:39] [I] sample0054.png [11/06/2025-11:57:39] [I] sample0055.png [11/06/2025-11:57:39] [I] sample0056.png [11/06/2025-11:57:39] [I] sample0057.png [11/06/2025-11:57:39] [I] sample0058.png [11/06/2025-11:57:39] [I] sample0059.png [11/06/2025-11:57:39] [I] sample0060.png [11/06/2025-11:57:39] [I] sample0061.png [11/06/2025-11:57:39] [I] sample0062.png [11/06/2025-11:57:39] [I] sample0063.png [11/06/2025-11:57:39] [I] sample0064.png [11/06/2025-11:57:39] [I] sample0065.png [11/06/2025-11:57:39] [I] sample0066.png [11/06/2025-11:57:39] [I] sample0067.png [11/06/2025-11:57:39] [I] sample0068.png [11/06/2025-11:57:39] [I] sample0069.png [11/06/2025-11:57:39] [I] sample0070.png [11/06/2025-11:57:39] [I] sample0071.png [11/06/2025-11:57:39] [I] sample0072.png [11/06/2025-11:57:39] [I] sample0073.png [11/06/2025-11:57:39] [I] sample0074.png [11/06/2025-11:57:39] [I] sample0075.png [11/06/2025-11:57:39] [I] sample0076.png [11/06/2025-11:57:39] [I] sample0077.png [11/06/2025-11:57:39] [I] sample0078.png [11/06/2025-11:57:39] [I] sample0079.png [11/06/2025-11:57:39] [I] sample0080.png [11/06/2025-11:57:39] [I] sample0081.png [11/06/2025-11:57:39] [I] sample0082.png [11/06/2025-11:57:39] [I] sample0083.png [11/06/2025-11:57:39] [I] sample0084.png [11/06/2025-11:57:39] [I] sample0085.png [11/06/2025-11:57:39] [I] sample0086.png [11/06/2025-11:57:39] [I] sample0087.png [11/06/2025-11:57:39] [I] sample0088.png [11/06/2025-11:57:39] [I] sample0089.png [11/06/2025-11:57:39] [I] sample0090.png [11/06/2025-11:57:39] [I] sample0091.png [11/06/2025-11:57:39] [I] sample0092.png [11/06/2025-11:57:39] [I] sample0093.png [11/06/2025-11:57:39] [I] sample0094.png [11/06/2025-11:57:39] [I] sample0095.png [11/06/2025-11:57:39] [I] sample0096.png [11/06/2025-11:57:39] [I] sample0097.png [11/06/2025-11:57:39] [I] sample0098.png [11/06/2025-11:57:39] [I] sample0099.png [11/06/2025-11:57:39] [I] sample0100.png [11/06/2025-11:57:39] [I] sample0101.png [11/06/2025-11:57:39] [I] sample0102.png [11/06/2025-11:57:39] [I] sample0103.png [11/06/2025-11:57:39] [I] sample0104.png [11/06/2025-11:57:39] [I] sample0105.png [11/06/2025-11:57:39] [I] sample0106.png [11/06/2025-11:57:39] [I] sample0107.png [11/06/2025-11:57:39] [I] sample0108.png [11/06/2025-11:57:39] [I] sample0109.png [11/06/2025-11:57:39] [I] sample0110.png [11/06/2025-11:57:39] [I] sample0111.png [11/06/2025-11:57:39] [I] sample0112.png [11/06/2025-11:57:39] [I] sample0113.png [11/06/2025-11:57:39] [I] sample0114.png [11/06/2025-11:57:39] [I] sample0115.png [11/06/2025-11:57:39] [I] sample0116.png [11/06/2025-11:57:39] [I] sample0117.png [11/06/2025-11:57:39] [I] sample0118.png [11/06/2025-11:57:39] [I] sample0119.png [11/06/2025-11:57:39] [I] sample0120.png [11/06/2025-11:57:39] [I] sample0121.png [11/06/2025-11:57:39] [I] sample0122.png [11/06/2025-11:57:39] [I] sample0123.png [11/06/2025-11:57:39] [I] sample0124.png [11/06/2025-11:57:39] [I] sample0125.png [11/06/2025-11:57:39] [I] sample0126.png [11/06/2025-11:57:39] [I] sample0127.png [11/06/2025-11:57:39] [I] sample0128.png [11/06/2025-11:57:39] [I] sample0129.png [11/06/2025-11:57:39] [I] sample0130.png [11/06/2025-11:57:39] [I] sample0131.png [11/06/2025-11:57:39] [I] sample0132.png [11/06/2025-11:57:39] [I] sample0133.png [11/06/2025-11:57:39] [I] sample0134.png [11/06/2025-11:57:39] [I] sample0135.png [11/06/2025-11:57:39] [I] sample0136.png [11/06/2025-11:57:39] [I] sample0137.png [11/06/2025-11:57:39] [I] sample0138.png [11/06/2025-11:57:39] [I] sample0139.png [11/06/2025-11:57:39] [I] sample0140.png [11/06/2025-11:57:39] [I] sample0141.png [11/06/2025-11:57:39] [I] sample0142.png [11/06/2025-11:57:39] [I] sample0143.png [11/06/2025-11:57:39] [I] sample0144.png [11/06/2025-11:57:39] [I] sample0145.png CalibrationDataReader: 145 images, 145 batches. [11/06/2025-11:57:39] [I] [TRT] Reading Calibration Cache for calibrator: MinMaxCalibration [11/06/2025-11:57:39] [I] [TRT] Generated calibration scales using calibration cache. Make sure that calibration cache has latest scales. [11/06/2025-11:57:39] [I] [TRT] To regenerate calibration cache, please delete the existing one. TensorRT will generate a new calibration cache. [11/06/2025-11:57:39] [W] [TRT] Missing scale and zero-point for tensor DecodeNumDetection, expect fall back to non-int8 implementation for any layer consuming or producing given tensor [11/06/2025-11:57:39] [W] [TRT] Missing scale and zero-point for tensor DecodeDetectionClasses, expect fall back to non-int8 implementation for any layer consuming or producing given tensor [11/06/2025-11:57:39] [I] [TRT] ---------- Layers Running on DLA ---------- [11/06/2025-11:57:39] [I] [TRT] ---------- Layers Running on GPU ---------- [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.0/conv/Conv + PWN(PWN(/model.0/act/Sigmoid), /model.0/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.1/conv/Conv + PWN(PWN(/model.1/act/Sigmoid), /model.1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.2/cv1/conv/Conv + PWN(PWN(/model.2/cv1/act/Sigmoid), /model.2/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.2/cv2/conv/Conv + PWN(PWN(/model.2/cv2/act/Sigmoid), /model.2/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.2/m/m.0/cv1/conv/Conv + PWN(PWN(/model.2/m/m.0/cv1/act/Sigmoid), /model.2/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.2/m/m.0/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.2/m/m.0/cv2/act/Sigmoid), /model.2/m/m.0/cv2/act/Mul), /model.2/m/m.0/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.2/cv3/conv/Conv + PWN(PWN(/model.2/cv3/act/Sigmoid), /model.2/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.3/conv/Conv + PWN(PWN(/model.3/act/Sigmoid), /model.3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/cv1/conv/Conv + PWN(PWN(/model.4/cv1/act/Sigmoid), /model.4/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/cv2/conv/Conv + PWN(PWN(/model.4/cv2/act/Sigmoid), /model.4/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/m/m.0/cv1/conv/Conv + PWN(PWN(/model.4/m/m.0/cv1/act/Sigmoid), /model.4/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/m/m.0/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.4/m/m.0/cv2/act/Sigmoid), /model.4/m/m.0/cv2/act/Mul), /model.4/m/m.0/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/m/m.1/cv1/conv/Conv + PWN(PWN(/model.4/m/m.1/cv1/act/Sigmoid), /model.4/m/m.1/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/m/m.1/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.4/m/m.1/cv2/act/Sigmoid), /model.4/m/m.1/cv2/act/Mul), /model.4/m/m.1/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.4/cv3/conv/Conv + PWN(PWN(/model.4/cv3/act/Sigmoid), /model.4/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.5/conv/Conv + PWN(PWN(/model.5/act/Sigmoid), /model.5/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/cv1/conv/Conv + PWN(PWN(/model.6/cv1/act/Sigmoid), /model.6/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/cv2/conv/Conv + PWN(PWN(/model.6/cv2/act/Sigmoid), /model.6/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.0/cv1/conv/Conv + PWN(PWN(/model.6/m/m.0/cv1/act/Sigmoid), /model.6/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.0/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.6/m/m.0/cv2/act/Sigmoid), /model.6/m/m.0/cv2/act/Mul), /model.6/m/m.0/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.1/cv1/conv/Conv + PWN(PWN(/model.6/m/m.1/cv1/act/Sigmoid), /model.6/m/m.1/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.1/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.6/m/m.1/cv2/act/Sigmoid), /model.6/m/m.1/cv2/act/Mul), /model.6/m/m.1/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.2/cv1/conv/Conv + PWN(PWN(/model.6/m/m.2/cv1/act/Sigmoid), /model.6/m/m.2/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/m/m.2/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.6/m/m.2/cv2/act/Sigmoid), /model.6/m/m.2/cv2/act/Mul), /model.6/m/m.2/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.6/cv3/conv/Conv + PWN(PWN(/model.6/cv3/act/Sigmoid), /model.6/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.7/conv/Conv + PWN(PWN(/model.7/act/Sigmoid), /model.7/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.8/cv1/conv/Conv + PWN(PWN(/model.8/cv1/act/Sigmoid), /model.8/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.8/cv2/conv/Conv + PWN(PWN(/model.8/cv2/act/Sigmoid), /model.8/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.8/m/m.0/cv1/conv/Conv + PWN(PWN(/model.8/m/m.0/cv1/act/Sigmoid), /model.8/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.8/m/m.0/cv2/conv/Conv [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POINTWISE: PWN(PWN(PWN(/model.8/m/m.0/cv2/act/Sigmoid), /model.8/m/m.0/cv2/act/Mul), /model.8/m/m.0/Add) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.8/cv3/conv/Conv + PWN(PWN(/model.8/cv3/act/Sigmoid), /model.8/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.9/cv1/conv/Conv + PWN(PWN(/model.9/cv1/act/Sigmoid), /model.9/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POOLING: /model.9/m/MaxPool [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POOLING: /model.9/m_1/MaxPool [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] POOLING: /model.9/m_2/MaxPool [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.9/cv1/act/Mul_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.9/m/MaxPool_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.9/m_1/MaxPool_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.9/cv2/conv/Conv + PWN(PWN(/model.9/cv2/act/Sigmoid), /model.9/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.10/conv/Conv + PWN(PWN(/model.10/act/Sigmoid), /model.10/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] RESIZE: /model.11/Resize [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.11/Resize_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.13/cv1/conv/Conv + PWN(PWN(/model.13/cv1/act/Sigmoid), /model.13/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.13/cv2/conv/Conv + PWN(PWN(/model.13/cv2/act/Sigmoid), /model.13/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.13/m/m.0/cv1/conv/Conv + PWN(PWN(/model.13/m/m.0/cv1/act/Sigmoid), /model.13/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.13/m/m.0/cv2/conv/Conv + PWN(PWN(/model.13/m/m.0/cv2/act/Sigmoid), /model.13/m/m.0/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.13/cv3/conv/Conv + PWN(PWN(/model.13/cv3/act/Sigmoid), /model.13/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.14/conv/Conv + PWN(PWN(/model.14/act/Sigmoid), /model.14/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] RESIZE: /model.15/Resize [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.15/Resize_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.4/cv3/act/Mul_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.17/cv1/conv/Conv + PWN(PWN(/model.17/cv1/act/Sigmoid), /model.17/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.17/cv2/conv/Conv + PWN(PWN(/model.17/cv2/act/Sigmoid), /model.17/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.17/m/m.0/cv1/conv/Conv + PWN(PWN(/model.17/m/m.0/cv1/act/Sigmoid), /model.17/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.17/m/m.0/cv2/conv/Conv + PWN(PWN(/model.17/m/m.0/cv2/act/Sigmoid), /model.17/m/m.0/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.17/cv3/conv/Conv + PWN(PWN(/model.17/cv3/act/Sigmoid), /model.17/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.18/conv/Conv + PWN(PWN(/model.18/act/Sigmoid), /model.18/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.24/m.0/Conv + PWN(/model.24/Sigmoid) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.14/act/Mul_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.20/cv1/conv/Conv + PWN(PWN(/model.20/cv1/act/Sigmoid), /model.20/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.20/cv2/conv/Conv + PWN(PWN(/model.20/cv2/act/Sigmoid), /model.20/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.20/m/m.0/cv1/conv/Conv + PWN(PWN(/model.20/m/m.0/cv1/act/Sigmoid), /model.20/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.20/m/m.0/cv2/conv/Conv + PWN(PWN(/model.20/m/m.0/cv2/act/Sigmoid), /model.20/m/m.0/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.20/cv3/conv/Conv + PWN(PWN(/model.20/cv3/act/Sigmoid), /model.20/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.21/conv/Conv + PWN(PWN(/model.21/act/Sigmoid), /model.21/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.24/m.1/Conv + PWN(/model.24/Sigmoid_1) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] COPY: /model.10/act/Mul_output_0 copy [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.23/cv1/conv/Conv + PWN(PWN(/model.23/cv1/act/Sigmoid), /model.23/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.23/cv2/conv/Conv + PWN(PWN(/model.23/cv2/act/Sigmoid), /model.23/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.23/m/m.0/cv1/conv/Conv + PWN(PWN(/model.23/m/m.0/cv1/act/Sigmoid), /model.23/m/m.0/cv1/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.23/m/m.0/cv2/conv/Conv + PWN(PWN(/model.23/m/m.0/cv2/act/Sigmoid), /model.23/m/m.0/cv2/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.23/cv3/conv/Conv + PWN(PWN(/model.23/cv3/act/Sigmoid), /model.23/cv3/act/Mul) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] CONVOLUTION: /model.24/m.2/Conv + PWN(/model.24/Sigmoid_2) [11/06/2025-11:57:39] [I] [TRT] [GpuLayer] PLUGIN_V2: YoloLayer [11/06/2025-11:57:40] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +534, GPU +689, now: CPU 1137, GPU 5200 (MiB) [11/06/2025-11:57:41] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +83, GPU +132, now: CPU 1220, GPU 5332 (MiB) [11/06/2025-11:57:41] [I] [TRT] Local timing cache in use. Profiling results in this builder pass will not be stored. [11/06/2025-12:00:45] [I] [TRT] Some tactics do not have sufficient workspace memory to run. Increasing workspace size will enable more tactics, please check verbose output for requested sizes. [11/06/2025-12:01:03] [I] [TRT] Total Activation Memory: 1115794944 [11/06/2025-12:01:03] [I] [TRT] Detected 1 inputs and 4 output network tensors. [11/06/2025-12:01:03] [I] [TRT] Total Host Persistent Memory: 175984 [11/06/2025-12:01:03] [I] [TRT] Total Device Persistent Memory: 614912 [11/06/2025-12:01:03] [I] [TRT] Total Scratch Memory: 0 [11/06/2025-12:01:03] [I] [TRT] [MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 7 MiB, GPU 553 MiB [11/06/2025-12:01:03] [I] [TRT] [BlockAssignment] Started assigning block shifts. This will take 67 steps to complete. [11/06/2025-12:01:03] [I] [TRT] [BlockAssignment] Algorithm ShiftNTopDown took 2.77161ms to assign 6 blocks to 67 nodes requiring 10925056 bytes. [11/06/2025-12:01:03] [I] [TRT] Total Activation Memory: 10925056 [11/06/2025-12:01:04] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +0, GPU +0, now: CPU 1557, GPU 5945 (MiB) [11/06/2025-12:01:04] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +0, GPU +0, now: CPU 1557, GPU 5945 (MiB) [11/06/2025-12:01:04] [I] [TRT] [MemUsageChange] TensorRT-managed allocation in building engine: CPU +7, GPU +8, now: CPU 7, GPU 8 (MiB) Engine build success! Python call example以下是一个简单Python示例调用C++生成的动态链接库,仅需指定模型文件的路径和视频输入的大小,就能返回视频每一帧的检测结果,并且在视频推理过程中可以动态调整置信度和交并比等参数的阈值。import cv2 import time import ctypes ctypes.CDLL("./build/libyolo_plugin.so", mode=ctypes.RTLD_GLOBAL) ctypes.CDLL("./build/libyolo_utils.so", mode=ctypes.RTLD_GLOBAL) from build import yolov5_trt def draw_detections(image, detections, fps): for detection in detections: class_id = detection['class_id'] x1, y1, x2, y2 = detection['bbox'] confidence = detection['confidence'] cv2.rectangle(image, (x1, y1), (x2, y2), (0x27, 0xC1, 0x36), 2) cv2.putText(image, f"{class_id}:{confidence:.2f}", (x1, y1 - 10), cv2.FONT_HERSHEY_PLAIN, 1.2, (0x27, 0xC1, 0x36), 2) cv2.putText(image, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 0, 255), 2) return image def main(input_path, output_path): cap = cv2.VideoCapture(input_path) fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) detector = yolov5_trt.YOLOv5Detector("./weights/yolov5s.engine", width, height) writer = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'MJPG'), fps, (width, height)) fps_list = [] frame_count = 0 total_time = 0.0 while cap.isOpened(): ret, frame = cap.read() if not ret: break start_time = time.time() detections = detector.detect(input_image=frame, input_w=640, input_h=640, conf_thresh=0.45, nms_thresh=0.55) process_time = time.time() - start_time current_fps = 1.0 / process_time if process_time > 0 else 0 frame_count += 1 total_time += process_time fps_list.append(current_fps) image = draw_detections(frame, detections, current_fps) writer.write(image) cap.release() writer.release() if frame_count > 0: avg_fps = frame_count / total_time if total_time > 0 else 0 print(f"Processed {frame_count} frames") print(f"Average FPS: {avg_fps:.2f}") print(f"Min FPS: {min(fps_list):.2f}") print(f"Max FPS: {max(fps_list):.2f}") if __name__ == "__main__": input_video = "./media/sample_720p.mp4" output_video = "./result.avi" main(input_video, output_video) 对应的C++推理代码如下:#include "NvInfer.h" #include "logger.h" #include "common.h" #include "buffers.h" #include "utils/preprocess.h" #include "utils/postprocess.h" #include "utils/types.h" #include "utils/utils.h" #include <pybind11/pybind11.h> #include <pybind11/numpy.h> #include <pybind11/stl.h> #include <memory> #include <mutex> namespace py = pybind11; // 将numpy数组转换为cv::Mat cv::Mat numpy_to_mat(py::array_t<unsigned char>& input) { py::buffer_info buf_info = input.request(); if (buf_info.ndim == 3) { // 彩色图像 int height = buf_info.shape[0]; int width = buf_info.shape[1]; int channels = buf_info.shape[2]; cv::Mat mat(height, width, CV_8UC3, (unsigned char*)buf_info.ptr); return mat.clone(); } else if (buf_info.ndim == 2) { // 灰度图像 int height = buf_info.shape[0]; int width = buf_info.shape[1]; cv::Mat mat(height, width, CV_8UC1, (unsigned char*)buf_info.ptr); return mat.clone(); } throw std::runtime_error("Unsupported array dimensions"); } // 将cv::Mat转换为numpy数组 py::array_t<unsigned char> mat_to_numpy(cv::Mat& mat) { if (mat.empty()) { return py::array_t<unsigned char>(); } if (mat.channels() == 1) { // 灰度图像 auto result = py::array_t<unsigned char>({mat.rows, mat.cols}); auto buf = result.request(); memcpy(buf.ptr, mat.data, sizeof(unsigned char) * mat.total()); return result; } else { // 彩色图像 auto result = py::array_t<unsigned char>({mat.rows, mat.cols, mat.channels()}); auto buf = result.request(); memcpy(buf.ptr, mat.data, sizeof(unsigned char) * mat.total() * mat.channels()); return result; } } // 加载模型文件 std::vector<unsigned char> load_engine_file(const std::string &file_name) { std::vector<unsigned char> engine_data; std::ifstream engine_file(file_name, std::ios::binary); assert(engine_file.is_open() && "Unable to load engine file."); engine_file.seekg(0, engine_file.end); int length = engine_file.tellg(); engine_data.resize(length); engine_file.seekg(0, engine_file.beg); engine_file.read(reinterpret_cast<char *>(engine_data.data()), length); return engine_data; } // YOLOv5推理器类 class YOLOv5Detector { private: std::unique_ptr<nvinfer1::IRuntime> runtime; std::shared_ptr<nvinfer1::ICudaEngine> engine; std::unique_ptr<nvinfer1::IExecutionContext> context; std::unique_ptr<samplesCommon::BufferManager> buffers; bool initialized = false; public: YOLOv5Detector(const std::string& engine_file, int frame_width, int frame_height) { initialize(engine_file); int img_size = frame_width * frame_height; cuda_preprocess_init(img_size); // 申请cuda内存 } void initialize(const std::string& engine_file) { // ========== 1. 创建推理运行时runtime ========== runtime = std::unique_ptr<nvinfer1::IRuntime>(nvinfer1::createInferRuntime(sample::gLogger.getTRTLogger())); if (!runtime) { throw std::runtime_error("Failed to create TensorRT runtime"); } // ========== 2. 反序列化生成engine ========== auto plan = load_engine_file(engine_file); engine = std::shared_ptr<nvinfer1::ICudaEngine>(runtime->deserializeCudaEngine(plan.data(), plan.size())); if (!engine) { throw std::runtime_error("Failed to deserialize engine"); } // ========== 3. 创建执行上下文context ========== context = std::unique_ptr<nvinfer1::IExecutionContext>(engine->createExecutionContext()); if (!context) { throw std::runtime_error("Failed to create execution context"); } // ========== 4. 创建输入输出缓冲区 ========== buffers = std::make_unique<samplesCommon::BufferManager>(engine); initialized = true; } py::list detect(py::array_t<unsigned char>& input_image, int input_w=kInputW, int input_h=kInputH, float conf_thresh=kConfThresh, float nms_thresh=kNmsThresh) { if (!initialized) { throw std::runtime_error("Detector not initialized"); } // 将numpy数组转换为cv::Mat cv::Mat frame = numpy_to_mat(input_image); if (frame.empty()) { throw std::runtime_error("Invalid input image"); } // CUDA预处理 process_input_gpu(frame, (float *)buffers->getDeviceBuffer(kInputTensorName), input_w, input_h); // ========== 5. 执行推理 ========== context->executeV2(buffers->getDeviceBindings().data()); // 拷贝回host buffers->copyOutputToHost(); // 从buffer manager中获取模型输出 int32_t *num_det = (int32_t *)buffers->getHostBuffer(kOutNumDet); int32_t *cls = (int32_t *)buffers->getHostBuffer(kOutDetCls); float *conf = (float *)buffers->getHostBuffer(kOutDetScores); float *bbox = (float *)buffers->getHostBuffer(kOutDetBBoxes); // 执行nms(非极大值抑制) std::vector<Detection> bboxs; yolo_nms(bboxs, num_det, cls, conf, bbox, conf_thresh, nms_thresh); // 返回检测结果 py::list result_list; for (size_t j = 0; j < bboxs.size(); j++) { cv::Rect r = get_rect(frame, bboxs[j].bbox, input_w, input_h); py::dict detection; detection["class_id"] = (int)bboxs[j].class_id; detection["confidence"] = (float)bboxs[j].conf; detection["bbox"] = py::cast(std::vector<int>{r.x, r.y, r.x + r.width, r.y + r.height}); result_list.append(detection); } return result_list; } }; // Python绑定代码 PYBIND11_MODULE(yolov5_trt, m) { m.doc() = "YOLOv5 TensorRT Python bindings"; py::class_<YOLOv5Detector>(m, "YOLOv5Detector") .def(py::init<const std::string&, int, int>(), "Initialize detector with engine file", py::arg("engine_file"), py::arg("frame_width"), py::arg("frame_height")) .def("detect", &YOLOv5Detector::detect, "Perform detection on input image", py::arg("input_image"), py::arg("input_w") = kInputW, py::arg("input_h") = kInputH, py::arg("conf_thresh") = kConfThresh, py::arg("nms_thresh") = kNmsThresh); } 实际在Jetson Oron Nano (8GB)上对720P输入大小的视频进行目标检测,平均帧率稳定在120+ FPS,满足工业场景下对实时性的要求。python yolov5_infer.py[11/06/2025-15:23:26] [I] [TRT] Loaded engine size: 7 MiB Deserialize yoloLayer plugin: YoloLayer [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +536, GPU +955, now: CPU 830, GPU 4470 (MiB) [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +83, GPU +149, now: CPU 913, GPU 4619 (MiB) [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] TensorRT-managed allocation in engine deserialization: CPU +0, GPU +7, now: CPU 0, GPU 7 (MiB) [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +0, GPU +0, now: CPU 913, GPU 4620 (MiB) [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] Init cuDNN: CPU +0, GPU +3, now: CPU 913, GPU 4623 (MiB) [11/06/2025-15:23:28] [I] [TRT] [MemUsageChange] TensorRT-managed allocation in IExecutionContext creation: CPU +0, GPU +11, now: CPU 0, GPU 18 (MiB) Processed 1442 frames Average FPS: 127.51 Min FPS: 75.75 Max FPS: 134.67 Conclusion Remarks最后我们还提供了ByteTrack跟踪算法的Python绑定,基于Pybind11实现,并在原有算法基础上提供了跟踪目标的类别信息,Jetson Orin Nano也能在此基础上也能实现高达83 FPS的实时目标检测和跟踪性能:ByteTrack-Pybind11: 高性能实时目标跟踪解决方案 🚀
  • [技术干货] 多模态AI模型Janus简介
    Janus是一个多模态AI模型系列,其名称源于古罗马的双面神雅努斯,象征模型能同时处理和理解两种不同模态的数据。以deepseek-ai的Janus-1.3B和Janus-Pro-7B为例,这些模型专攻图像与文本的联合理解,其核心架构通常基于改进的视觉语言模型框架。Janus系列采用视觉编码器提取图像特征,再通过跨模态融合模块与文本特征交互。其中Janus-1.3B参数量为13亿,适用于轻量级多模态任务;Janus-Pro-7B则通过70亿参数实现更强的表征能力。这类模型在训练时使用大规模图文对数据集,通过对比学习、掩码重建等目标函数建立模态对齐。与专用单模态模型不同,Janus类模型的核心优势在于跨模态推理。例如它能理解“图像中红色物体的位置”这类需视觉定位与语义解析复合的问题。这种能力源于其双重编码器设计与交叉注意力机制,使模型能在特征层面实现视觉与语言信号的深度融合。当前多模态模型发展呈现参数规模与模态广度同步扩展的趋势。Janus系列可视为OpenAI CLIP、BLIP等模型的演进,其技术路线与Flamingo、GPT-4V等保持架构相关性。这类模型面临的挑战包括模态对齐偏差、计算复杂度优化,以及细粒度语义 grounding 等问题。在实际应用中,Janus类模型可支撑智能客服的图文问答、电商产品的跨模态检索、无障碍技术的图像描述生成等场景。其发展直接影响着具身智能、内容审核、教育科技等领域的技术演进路径。
  • [技术干货] Qwen2-VL的模型分离和搭配
    Qwen2-VL模型将模型逻辑拆分为Qwen2VLModel和Qwen2VLForConditionalGeneration两个类是一种经典的设计模式。这种设计体现了单一职责原则和模块化思想,具有清晰的层次结构。Qwen2VLModel作为基础模型,其核心职责是实现多模态Transformer的编码器-解码器架构。它专注于接收融合后的多模态嵌入(文本、图像、视频),通过多层Transformer块进行特征变换,最终输出隐藏状态。这个类不包含任务特定的输出头,其输出是模型的核心表示,可以作为多种下游任务的通用特征提取器。从接口角度看,它的forward方法返回BaseModelOutputWithPast,包含最后的隐藏状态、过去键值对等中间结果,为更复杂的任务流水线提供基础数据。Qwen2VLForConditionalGeneration作为任务特定模型,在基础模型之上增加了语言建模头。它的核心扩展是将Qwen2VLModel输出的隐藏状态通过一个线性变换层(lm_head)映射到词汇表空间,生成每个位置的下一个词元预测概率。这个设计支持自回归生成任务,能够处理图像描述、视觉问答、多模态对话等需要文本生成的应用场景。它的forward方法返回Qwen2VLCausalLMOutputWithPast,除了基础模型的输出外,还包含语言建模的logits和可选的损失值。这种分离设计的优势体现在多个层面。在工程上,它实现了计算逻辑与任务逻辑的解耦,基础模型可以独立优化和测试,无需依赖特定任务头。在功能上,它支持灵活的模型复用,同一个Qwen2VLModel可以搭配不同的任务头用于多种下游任务。在资源效率上,当仅需要特征提取时,可以单独加载基础模型,节省内存占用。从Hugging Face Transformers库的设计哲学来看,这种模式是标准实践。类似的分离也见于BERT(BertModel/BertForSequenceClassification)、T5(T5Model/T5ForConditionalGeneration)等架构。这种一致性使得开发者能够快速理解新模型的结构,并利用熟悉的API模式进行开发。具体到Qwen2-VL的场景,因为多模态输入的处理已经相当复杂,将核心变换与生成任务分离有助于管理复杂性。基础模型处理多模态融合和表示学习,而条件生成模型专注于利用这些表示进行连贯的文本生成。在实际应用中,如果用户只需要获取多模态输入的联合表示(例如用于检索或分类),可以使用Qwen2VLModel;如果需要模型根据多模态输入生成文本回复,则使用Qwen2VLForConditionalGeneration。
  • [技术干货] Hugging Face 生态介绍
    Hugging Face 构建了一个以开源、协作和可访问性为核心理念的机器学习生态系统。这个生态系统并非单一工具,而是一个紧密相连的工具、库、模型和社区平台组成的综合体,其根本目标是降低现代机器学习,尤其是自然语言处理的门槛。其生态系统的基石是 Transformers 库。这个库不仅仅提供了数千个预训练模型的统一接口,更重要的是它定义了一套标准的模型架构、训练和推理流程。这使得研究人员和开发者能够以几行代码加载和使用最先进的模型,如BERT、GPT等,而无需关心底层复杂的实现细节。这种标准化极大地加速了模型的迭代与应用落地。第二个关键组成部分是 Hugging Face Hub,这是一个模型、数据集和演示应用的共享平台。你可以将其理解为机器学习的“Github”。它托管了数十万个模型和数万个数据集,覆盖了从文本、图像到音频的多种模态。这种集中式托管和社区贡献模式,彻底改变了以往模型和数据分散、难以寻找和复现的局面,形成了强大的网络效应和知识聚集。第三个层面是围绕核心库构建的工具链。这包括:Datasets 库:提供了高效、标准化的数据加载和后处理功能,尤其擅长处理大规模数据集。Tokenizers 库:提供了各类分词算法的高速实现,是文本处理的前置关键环节。Accelerate 库:简化了在多GPU、TPU等硬件上的分布式训练和推理代码的编写。Gradio/Spaces:允许用户快速为任何模型构建图形化交互界面,并直接部署在HF平台上,极大地简化了模型的演示和分享。这个生态系统的运作模式形成了一个高效的闭环:研究者可以在Hub上发布新的模型架构和训练方法;开发者使用Transformers库快速集成这些模型到自己的应用中,或使用Datasets库的数据进行微调;最后通过Gradio创建应用进行展示和测试。整个过程都建立在开源和协作的基础上。从更宏观的视角看,Hugging Face生态系统实际上是在为机器学习领域建立事实上的标准。它通过提供一套优秀的、统一的工具,减少了重复劳动,促进了成果的复用和比较,从而推动了整个领域的快速发展。它使得算力或数据资源有限的中小团队甚至个人,也能站在巨人的肩膀上,接触到业界最前沿的技术,这在一定程度上民主化了人工智能的开发能力。Hugging Face生态系统的核心是三位法国籍的联合创始人:Clément Delangue、Julien Chaumond和Thomas Wolf。他们并没有一开始就试图打造一个庞大的平台,而是从一个非常具体的痛点切入:创建一个标准化的、开源的模型库。这就是后来的Transformers库。这个库的成功在于它提供了一个极其友好的API(如from_pretrained),让开发者能够用几行代码就加载和使用最先进的模型。这种低门槛、高价值的特性,使其迅速在开发者社区中获得了快速传播。生态的扩张遵循了“飞轮效应”。当Transformers库吸引了大量开发者后,他们顺势推出了Hugging Face Hub。这个平台解决了模型分享和发现的难题,进一步巩固了其作为NLP中心的地位。开发者不仅来这里找工具,更来这里贡献和协作。随着用户和影响力的增长,他们又将这套模式复制到数据集(Datasets库)、演示应用(Gradio/Spaces)和分布式训练(Accelerate库)等领域,逐步构建起一个完整的工具链。关键的推动力还包括其坚定的开源与商业化结合的独特路径。公司核心的库和平台始终保持着开源和免费,这为其建立了极高的信任和极广的开发者基础。而其商业模式则建立在为企业提供托管、推理和企业级解决方案上(如Inference Endpoints和Trainer SaaS服务)。这种“开源引流,服务变现”的模式,既避免了与传统云厂商的正面竞争,又使其生态保持了活力和中立性。值得一提的是,Thomas Wolf作为首席科学官,在技术愿景和社区互动上起到了关键作用。他本人就是一位活跃的研究员和布道者,深度参与核心库的开发,并与学术社区保持着紧密联系,这确保了生态系统在技术上的前瞻性和权威性。总结:它是由一小群洞察力深刻的创始人,通过解决一个真实且迫切的行业问题起步,以出色的开源项目为杠杆,撬动了庞大的开发者社区,并巧妙地设计了一套可持续的商业模式,最终推动其从一个聊天机器人初创公司演变为今天机器学习领域不可或缺的基础设施。
  • [技术干货] PyTorch版本的transformers库生成框架介绍
    PyTorch版本的Hugging Face transformers 库中的生成框架成功地将各类语言模型的文本生成能力标准化、民主化。其核心设计哲学是提供一个统一的接口,无论模型架构是编码器-解码器(如T5、BART)还是仅解码器(如GPT系列),用户都能通过简单的 model.generate() 方法调用复杂的生成策略。这背后是一套高度模块化且可扩展的架构。生成过程可以被解构为几个关键组件的协同工作:LogitsProcessor、StoppingCriteria、BeamScorer 以及 Cache。LogitsProcessor 负责在每一步生成时对模型的原始输出(logits)进行加工,例如施加重复惩罚(RepetitionPenaltyLogitsProcessor)、确保最小生成长度(MinLengthLogitsProcessor)或进行核采样(TopPLogitsWarper)。这种设计使得生成内容的控制策略可以像乐高积木一样自由组合。StoppingCriteria 则决定了生成的终止条件,除了常见的最大长度和结束符(EOS)外,用户可以实现自定义的停止逻辑。在解码策略方面,库内实现了从经典到前沿的多种算法。贪婪解码和束搜索(Beam Search)是确定性方法的代表,后者通过维护多个候选序列来寻找局部最优解,广泛应用于机器翻译等任务。而采样类方法,如多项式采样、Top-K采样和Top-P(核)采样,则通过引入随机性来生成更多样、更富有创造性的文本。对比搜索(Contrastive Search)则是一种较新的方法,它通过惩罚与上文高相似的候选token来有效缓解生成中的重复和退化问题,在开放域生成中表现出色。辅助生成(Assisted Generation)或推测解码(Speculative Decoding)代表了生成加速的前沿方向。其核心思想是使用一个更快但更小的“助手模型”来草拟几个未来的token,然后由原始“大模型”并行地验证这些token。如果草拟的token被接受,生成步骤就被大幅加速;如果不被接受,大模型只需纠正第一个出错的token。这种方法能在完全不改变输出质量的前提下,显著提升大模型的推理速度。缓存(Cache)系统是生成效率的关键。为了加速自回归生成中重复的注意力计算,Transformer模型广泛使用了键值缓存(KV Cache)。transformers 库抽象了 Cache 类,并提供了 DynamicCache(动态缓存)和 StaticCache(静态缓存)等实现。动态缓存灵活通用,而静态缓存则针对特定硬件(如GPU)进行了优化,通过预分配和固定形状的内存来减少开销,尤其在长序列生成和批处理场景下能带来显著的性能提升。该生成框架与PyTorch的生态深度集成,兼容其自动微分、动态图特性以及各种设备(CPU、CUDA)。同时,它也考虑了与 accelerate 库的配合,以支持在多个GPU甚至CPU上进行大模型推理(ZeRO阶段3)。其输出被设计为丰富的 ModelOutput 子类,不仅包含生成的序列,还可以根据需要返回每一步的分数、注意力权重、隐藏状态以及过去的键值缓存,为分析和调试提供了极大的便利。总而言之,PyTorch版 transformers 的生成模块通过精心的抽象和模块化设计,在保持接口简洁性的同时,内部实现了极其复杂和多样化的生成逻辑。
  • [产品体验官] 【获奖名单公示】 /// 产品体验官招募ing | 体验华为云Versatile智能体平台构建AI Agent,反馈优化建议,赢取500元开发者大礼包
      【华为云Versatile智能体平台】产品体验官活动 获奖名单如下: 一、高价值建议奖:昵称被评为高价值需求 内容展示建议分值礼品码事漫谈增加Agent发布渠道,如微信小程序等7(高价值需求3票、建议采纳需求1票)500元开发者大礼包1份ddhsaVersatile预置base64转图片插件6(高价值需求2票、建议采纳需求2票)500元开发者大礼包1份福州司马懿工作流应用-代码节点优化,去除预处理代码,提升用户使用效率5(高价值需求2票、建议采纳需求1票)500元开发者大礼包1份评分规则:由产品团队组成的评审团对所有参与者提交的建议进行投票,其中高价值需求(2分)、建议采纳需求(1分),TOP3分值的建议获选。 二、建议贡献排名奖:昵称积分排名(被采纳建议,每条得1分)礼品鸢尾离夏7200元开发者大礼包1份小草飞上天6200元开发者大礼包1份yd_2709879825200元开发者大礼包1份HDC-Feng3200元开发者大礼包1份林欣3200元开发者大礼包1份 恭喜以上8名获奖用户,礼品会发到活动报名时填写报名问卷的账号和收货地址(小助手将联系提供),请注意查收。感谢大家对华为云Versatile智能体平台的关注和支持~ 欢迎各位开发者们在云声平台提出更多优化建议帮助Versatile产品的优化迭代共同构建易用、好用、开放的一站式Agent平台  活动介绍:时下大热的AI Agent智能体,正推动千行万业进入AI数字生产力的革新快轨。Versatile智能体平台是华为云在本年度重磅推出的一站式企业级智能体构建平台,面向企业AI+转型、软件及解决方案提供商、独立开发者等多角色多场景,使能高效开发Agent,将“人人都能构建自己的企业级智能体”产品愿景照进现实。为了让Versatile产品能力更贴合用户应用场景、进一步满足用户需求、提升体验,我们发起本次产品体验官招募活动,邀请各位有热情、有想法的开发者们加入Versatile智能体平台体验官阵营,提出真实的产品改进意见,以帮助产品开发和优化迭代。期待联接广大开发者们的力量,合力构建易用、好用、开放的AI Agent平台。图:产品架构图图:产品界面图 活动时间:2025.11.4-2025.12.15 活动流程:1、 在活动页点击报名后,进入官方微信群开通服务(下图),访问产品体验环境:华为开发者空间--开发平台--Versatile Agent2、 参照官网帮助文档(内含实践案例指导)或收录进案例中心的实操案例,进行产品深度使用体验;同时需创建并发布任一类型的智能体应用(至少一个);3、 将体验完成截图发送至活动指定评论区(本帖下方),跟帖评论体验感受,可以围绕体验流程、操作步骤、问题建议(搭配产品界面截图说明)等方向进行展开说明;4、在官网云声·建议平台,反馈产品优化建议。(注:以上四步需全部完成)  服务开通方式:报名成功后,请参与者扫描二维码进入官方微信群,进群后请发送“我要开通Versatile,账号ID是xxxxxx”,技术支持将辅助在24小时内完成服务开通;同时欢迎在群聊内开展技术交流,反馈操作疑问。(Versatile智能体平台产品体验交流群)TIPS:账号ID获取路径:华为云控制台-右上角账号名下拉窗口-账号ID(红框内,可复制)示意图:  产品体验官职责:为了构建更好的用户体验,各体验官可从以下要素考虑,反馈体验感受,包括:交互体验层面、感官体验层面、bug类、需求类、能力创新类等等。 奖项设置:奖项设置获奖要求获奖名额激励礼品高价值建议奖被评选为高价值需求3每人价值500元开发者礼包1份建议贡献排名奖被采纳建议数≥3条,且根据积分排名TOP55每人价值200元开发者礼包1份说明1、每条被采纳建议累计1积分,被采纳建议数统计截止时间为2025年12月15日24点;2、若出现积分相同且排名一致的情况,因奖品数量有限,根据先到先得原则进行发放;3、同一用户仅限获评一个奖项;4、 如礼品库存不足将存在替换成等价值礼品的可能;5、激励礼品如下:序号礼包名称介绍1500元开发者礼包华为手环8NFC版(黑色)华为12000mh移动电源充电宝(白色)开发者定制不锈钢水杯   开发者空间定制鼠标垫(大号)2200元开发者礼包华为FreeBuds SE 2无线耳机(白色)U型按摩枕开发者空间定制鼠标垫(大号)(奖品示意图)  活动说明:1、 完成体验请进入活动指定评论区(本帖下方),截图体验完成的实际截图,并说明体验感受。提交建议内容需表述清晰,有操作截图、链接等详细描述。2、 您对Versatile智能体平台有任何改进建议,请提交至云声·建议平台(填写时,关联产品/功能 选择“智能体平台Versatile”) 并标明以【Versatile智能体平台体验】为开头,让我们听到你的声音,为产品改进贡献一份力量。示例:【Versatile智能体平台体验】整体上手体验不错,建议考虑XXX场景,实现AI应用一键分享的能力等等。3、所有参与活动的开发者需要完成实际体验,有任何问题欢迎进入Versatile论坛阵地发帖交流,我们将在48小时内解答。  关于华为云Versatile智能体平台产品官网主页:cid:link_5帮助文档:cid:link_1Versatile论坛交流阵地:cid:link_4产品体验入口:华为开发者空间--开发平台--Versatile Agent 
  • [技术干货] 多模态模型如何迈向原生世界
    多模态能力的核心源于文本大模型的知识与推理能力,视觉作为从属的感知源。但近期的一系列工作正在悄然改变这一格局,预示着多模态模型发展的新方向。Gemini 1.5 Pro、LWM(世界模型)和Sora等模型,代表了一个关键的范式转变:从“以语言模型为中心的多模态”向“原生多模态大模型”演进。早期的多模态模型,如Qwen-VL或GPT-4V,其工作流程本质上是将图像、视频等非文本模态“翻译”或“压缩”成LLM能够理解的某种特征序列(视觉token)。在这个过程中,语言模型是绝对的认知核心,视觉信息是服务于它的素材。这解释了为什么模型的知识、逻辑和对话能力主要继承自文本预训练。然而,新一波的研究正在挑战这一架构。Gemini 1.5 Pro的百万级上下文窗口,其革命性意义在于它允许模型直接处理海量的、未经极度压缩的原始多模态数据(如长达一小时的视频)。这意味着模型不再仅仅依赖于从单个图像中提取的、高度抽象的语义特征,而是能够从连续的帧序列中自行发现和理解时序、因果和物理规律。LWM等视频模型直接在大规模视频数据上训练,目标就是学习世界动态变化的通用表示。而Sora这类视频生成模型,则从另一个维度证明,当模型在足够大规模的多模态数据上训练时,它可能内隐地学习到了一个关于物理世界的“渲染引擎”和动态常识,而这不完全是文本描述所能覆盖的。这些进展共同指向了“世界模型”的雏形。它的核心思想是,智能体需要对环境如何演化有一个内在的预测模型。要构建这样的模型,必须依赖于文本之外的第一手、高保真的感知数据。纯文本知识是人类对世界的高度抽象和事后描述,它可能丢失了物理世界最根本的连续、动态和几何属性。例如,一个水杯被碰倒后,液体如何漫溢,这一过程的动力学规律很难用文本完美刻画,但却蕴含在无数的视频帧中。因此,未来的多模态大模型,其能力将不再仅仅是文本知识的投影。通过在海量原生多模态数据(视频、音频、物理传感器数据)上进行训练,模型有望建立起对物理世界更本质、更直接的理解。视觉、声音等模态将不再是文本的“附庸”,而是与文本平起平坐、共同塑造模型世界认知的基石。这将使人工智能不仅是一个“博学的学者”,更逐渐成为一个拥有“常识”的“实践者”,持续刷新我们对智能边界的认知。
  • [技术干货] Qwen-VL基座模型的选择和适配器
    选择Qwen-7B作为语言基座,首要原因是其作为一款性能强劲的中英文双语大模型,与阿里巴巴自身的开发背景高度契合。使用自研模型作为基座,意味着团队对其训练数据分布、架构细节和潜在能力有更深入的理解,这在后续的多模态对齐和调试中能提供显著的便利。其次,在模型规模上,7B参数是一个在能力与推理成本之间取得良好平衡的“甜点区”:它既具备足够的知识容量和推理能力来支撑复杂的视觉语言任务,又不像更大规模的模型那样对计算资源有苛刻的要求。视觉编码器选择OpenCLIP预训练的ViT-bigG,则体现了“站在巨人肩膀上”的实用主义策略。CLIP模型通过海量图文对进行对比学习训练,其视觉编码器已经具备了强大且通用的视觉表征能力,能够将图像有效地映射到一个富含语义的特征空间。直接利用这种高质量的预训练模型,可以避免从零开始训练视觉模块所带来的巨大计算开销和数据需求。特别值得一提的是ViT-bigG这个模型,它在CLIP家族中属于规模较大的版本,拥有更强的特征提取能力,为后续与语言模型的对齐提供了一个高起点的视觉特征基础。Qwen-7B提供了语言理解和生成的核心智能,OpenCLIP ViT-bigG则提供了通用的视觉理解能力。多模态模型的关键挑战就在于如何以高效的方式将这两个独立的“大脑”连接起来,并让它们协同工作。适配器的核心作用,就是充当一位高效的“翻译官”与“协调员”,将视觉专家提取的网格状图像特征,转换成语言专家能够理解的、序列化的“视觉语言”或“视觉提示”。Qwen-VL选择使用一个随机初始化的、单层的交叉注意力模块来承担这一职责。首先,这种极简设计最直接的优势是参数效率极高。相比于设计一个深层的、参数庞大的融合网络(例如早期一些工作使用的多层Transformer解码器),单层注意力模块仅引入极少的额外参数(在Qwen-VL总计9.6B参数中占比微乎其微)。这使得训练过程,尤其是在关键的预训练对齐阶段,优化目标能够更集中地作用于视觉特征到语言模型空间的映射关系上,而不是去学习一个复杂连接器本身的内部逻辑,降低了训练难度和过拟合风险。其次,它巧妙地利用了Transformer架构的同构性。交叉注意力机制本就是LLM核心组件——Transformer解码器的原生部分。因此,这个适配器可以视为为LLM临时增加了一个特殊的“视觉前缀”。在计算时,视觉特征作为Key和Value,语言模型自身解码过程中产生的隐藏状态作为Query,通过这一层交叉注意力进行交互。这相当于让LLM以一种它最熟悉的方式去“查阅”和“参考”视觉信息,过程非常自然。这种设计也使得整个模型在推理时,可以很容易地将处理后的视觉特征序列与文本token序列拼接,作为一个统一的序列输入给后续的LLM层。更重要的是,这种简洁性反而为语言模型的能力释放留下了最大空间。一个过于复杂或能力过强的适配器,可能会试图“替代”LLM进行一部分本应由LLM完成的推理工作,例如,它可能自己将图像特征过度压缩成一个文本描述,再喂给LLM。这反而会限制LLM利用其强大的原生能力对丰富视觉细节进行深度推理。Qwen-VL的单层适配器更像是一个“特征投影与筛选器”,它只负责将视觉特征转换到LLM的语义空间并进行初步的信息浓缩,而将复杂的视觉语言推理和生成任务,最大限度地留给能力更强的Qwen-7B基座模型去完成。在多模态模型中,“更强的基础模型”配合“更精巧的接口设计”是一条行之有效的路径。当视觉编码器和语言模型本身足够强大时,它们之间需要的或许不是一座结构复杂的大桥,而是一个高效、精准的对接协议。
  • [技术干货] Qwen-VL的多模态模型训练路径
    阿里巴巴提出的Qwen-VL是一个典型的多模态大模型案例,其设计思路和训练流程反映了当前视觉语言模型发展的关键方向。该模型以Qwen-7B作为语言基座,结合OpenCLIP预训练的ViT-bigG视觉编码器,并通过一个随机初始化的单层交叉注意力模块作为视觉与语言之间的适配器,整体参数量约为9.6B。这种结构在保证模型表达力的同时,也注重了模块化与训练效率。训练过程分为三个递进阶段,每一阶段目标明确,体现出分阶段训练在多模态对齐中的重要性。第一阶段为预训练,使用大规模图文配对数据,主要对齐视觉与语言表示,同时冻结语言模型参数,避免早期训练干扰语言模型已有的知识。第二阶段进入多任务预训练,采用更高质量、更高分辨率的图像数据,并引入多种视觉语言任务,同时进行全参数更新,以增强模型对复杂多模态输入的理解能力。第三阶段为指令微调,冻结视觉编码器,利用自指令生成数据提升模型的指令遵循与多轮对话能力,这一做法与当前大模型指令微调的常见策略一致。值得注意的是,Qwen-VL在第二和第三阶段中同时引入纯文本数据参与训练,这种做法有效缓解了多模态训练中常见的语言能力退化问题,与LLaVA、BLIP-2等模型中的观察相符,说明多模态训练中语言能力的保持需要显式设计。此外,Qwen-VL的视觉-语言接口极为简洁,仅使用单层注意力池化进行跨模态连接,却在多项任务中表现优于结构更复杂的InstructBLIP。这说明在足够高质量、多阶段、多任务的数据驱动下,轻量适配结构同样能够实现有效的模态融合,为模型设计提供了另一种思路。
  • [技术干货] 识别你的手势,它很有一手
    CNN-RNN 视频动态手势识别人工智能的发展日新月异,也深刻的影响到人机交互领域的发展。手势动作作为一种自然、快捷的交互方式,在智能驾驶、虚拟现实等领域有着广泛的应用。手势识别的任务是,当操作者做出某个手势动作后,计算机能够快速准确的判断出该手势的类型。本文将使用ModelArts开发训练一个视频动态手势识别的算法模型,对上滑、下滑、左滑、右滑、打开、关闭等动态手势类别进行检测,实现类似华为手机隔空手势的功能。算法简介CNN-RNN视频动态手势识别算法首先使用预训练网络InceptionResNetV2逐帧提取视频动作片段特征,然后输入LSTM进行分类。我们使用全栈AI黑客松决赛样例数据对算法进行测试,总共包含108段视频,数据集包含无效手势、上滑、下滑、左滑、右滑、打开、关闭、放大、缩小等9种手势的视频,数据集下载链接如下:https://developer.huaweicloud.com/develop/aigallery/dataset/detail?id=7e9c0d90-461f-4af2-93b3-67a8df76c109代码实现首先我们将采集的视频文件解码抽取关键帧,每隔4帧保存一次,然后对图像进行中心裁剪和预处理,代码如下:def load_video(file_name): cap = cv2.VideoCapture(file_name) # 每隔多少帧抽取一次 frame_interval = 4 frames = [] count = 0 while True: ret, frame = cap.read() if not ret: break # 每隔frame_interval帧保存一次 if count % frame_interval == 0: # 中心裁剪 frame = crop_center_square(frame) # 缩放 frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE)) # BGR -> RGB [0,1,2] -> [2,1,0] frame = frame[:, :, [2, 1, 0]] frames.append(frame) count += 1 return np.array(frames) 然后我们创建图像特征提取器,使用预训练模型InceptionResNetV2提取图像特征,代码如下:def get_feature_extractor(): feature_extractor = keras.applications.inception_resnet_v2.InceptionResNetV2( weights = 'imagenet', include_top = False, pooling = 'avg', input_shape = (IMG_SIZE, IMG_SIZE, 3) ) preprocess_input = keras.applications.inception_resnet_v2.preprocess_input inputs = keras.Input((IMG_SIZE, IMG_SIZE, 3)) preprocessed = preprocess_input(inputs) outputs = feature_extractor(preprocessed) model = keras.Model(inputs, outputs, name = 'feature_extractor') return model接着提取视频特征向量,如果视频不足40帧就创建全0数组进行补白:def load_data(videos, labels): video_features = [] for video in tqdm(videos): frames = load_video(video) counts = len(frames) # 如果帧数小于MAX_SEQUENCE_LENGTH if counts < MAX_SEQUENCE_LENGTH: # 补白 diff = MAX_SEQUENCE_LENGTH - counts # 创建全0的numpy数组 padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3)) # 数组拼接 frames = np.concatenate((frames, padding)) # 获取前MAX_SEQUENCE_LENGTH帧画面 frames = frames[:MAX_SEQUENCE_LENGTH, :] # 批量提取特征 video_feature = feature_extractor.predict(frames) video_features.append(video_feature) return np.array(video_features), np.array(labels) 最后创建LSTM Model,代码如下:def video_cls_model(class_vocab): # 类别数量 classes_num = len(class_vocab) # 定义模型 model = keras.Sequential([ layers.Input(shape=(MAX_SEQUENCE_LENGTH, NUM_FEATURES)), layers.LSTM(64, return_sequences=True), layers.Flatten(), layers.Dense(classes_num, activation='softmax') ]) # 编译模型 model.compile(optimizer = keras.optimizers.Adam(1e-5), loss = keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics = ['accuracy'] ) return model模型训练体验完整的训练流程可以点击Run in ModelArts运行我发布的Notebook使用云上的免费算力训练,代码链接如下:https://developer.huaweicloud.com/develop/aigallery/notebook/detail?id=e8914ecc-953e-48b1-8e5d-90b37b3bc8e9视频推理首先加载LSTM Model,获取视频类别索引标签:import random # 加载模型 model = tf.keras.models.load_model('saved_model') # 类别标签 label_to_name = {0:'无效手势', 1:'上滑', 2:'下滑', 3:'左滑', 4:'右滑', 5:'打开', 6:'关闭', 7:'放大', 8:'缩小'} 然后使用图像特征提取器InceptionResNetV2提取视频特征:# 获取视频特征 def getVideoFeat(frames): frames_count = len(frames) # 如果帧数小于MAX_SEQUENCE_LENGTH if frames_count < MAX_SEQUENCE_LENGTH: # 补白 diff = MAX_SEQUENCE_LENGTH - frames_count # 创建全0的numpy数组 padding = np.zeros((diff, IMG_SIZE, IMG_SIZE, 3)) # 数组拼接 frames = np.concatenate((frames, padding)) # 取前MAX_SEQ_LENGTH帧 frames = frames[:MAX_SEQUENCE_LENGTH,:] # 计算视频特征 N, 1536 video_feat = feature_extractor.predict(frames) return video_feat最后将视频序列的特征向量输入LSTM进行预测:# 视频预测 def testVideo(): test_file = random.sample(videos, 1)[0] label = test_file.split('_')[-2] print('文件名:{}'.format(test_file) ) print('真实类别:{}'.format(label_to_name.get(int(label))) ) # 读取视频每一帧 frames = load_video(test_file) # 挑选前帧MAX_SEQUENCE_LENGTH显示 frames = frames[:MAX_SEQUENCE_LENGTH].astype(np.uint8) # 保存为GIF imageio.mimsave('animation.gif', frames, duration=10) # 获取特征 feat = getVideoFeat(frames) # 模型推理 prob = model.predict(tf.expand_dims(feat, axis=0))[0] print('预测类别:') for i in np.argsort(prob)[::-1][:5]: print('{}: {}%'.format(label_to_name[i], round(prob[i]*100, 2))) return display(Image(open('animation.gif', 'rb').read())) 运行testVideo()函数,会随机选择一个视频进行预测,并显示模型的预测结果:文件名:hand_gesture/man_005_3_1.mp4 真实类别:左滑 预测类别: 左滑: 78.32% 右滑: 8.54% 下滑: 5.51% 无效手势: 4.33% 上滑: 1.67%文章小结本文介绍了基于CNN-RNN架构的视频动态手势识别算法,通过结合InceptionResNetV2卷积神经网络和LSTM循环神经网络,实现了对多种手势动作(如上滑、下滑、左滑、右滑、打开、关闭等)的高效识别。
  • [技术干货] LeRobot边缘侧部署操控机械臂夹云宝
    LeRobot边缘侧部署操控机械臂夹云宝一、制作镜像首先下载Ubuntu 20.04 LTS官方镜像,这里我们选择Desktop image进行下载,下载地址为:https://releases.ubuntu.com/focal/ 2. 下载Linux镜像的烧录软件balenaEtcher,选择适合自己的操作系统,下载地址为:https://etcher.balena.io/ 3. 启动balenaEtcher,选择我们前面下载好的ubuntu-20.04.6-desktop-amd64.iso镜像,插入U盘作为系统启动盘进行烧录:二、配置环境安装系统后建议安装GPU驱动,在命令行中依次运行:sudo apt update、ubuntu-drivers devices,他推荐的(recommended)驱动是:nvidia-driver-570。== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 == modalias : pci:v000010DEd00001CBBsv000017AAsd0000225Fbc03sc00i00 vendor : NVIDIA Corporation model : GP107GLM [Quadro P1000 Mobile] driver : nvidia-driver-535 - distro non-free driver : nvidia-driver-390 - distro non-free driver : nvidia-driver-570 - distro non-free recommended driver : nvidia-driver-450-server - distro non-free driver : nvidia-driver-535-server - distro non-free driver : nvidia-driver-470 - distro non-free driver : nvidia-driver-418-server - distro non-free driver : nvidia-driver-470-server - distro non-free driver : nvidia-driver-570-server - distro non-free driver : xserver-xorg-video-nouveau - distro free builtin 在命令行中输入sudo apt install nvidia-driver-570进行安装,安装成功之后重启系统输入nvidia-smi查看当前驱动支持的最高CUDA版本。hou@hou-ThinkPad-P52:~$ nvidia-smi Thu Oct 30 11:41:48 2025 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 570.133.07 Driver Version: 570.133.07 CUDA Version: 12.8 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 Quadro P1000 Off | 00000000:01:00.0 Off | N/A | | N/A 43C P8 N/A / 5001W | 7MiB / 4096MiB | 0% Default | | | | N/A | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | 0 N/A N/A 1159 G /usr/lib/xorg/Xorg 4MiB | +-----------------------------------------------------------------------------------------+下载安装Miniconda,在命令行中依次运行如下命令:wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.shbash ~/Miniconda3-latest-Linux-x86_64.sh安装成功之后打开一个新的终端安装Pytorch 2.6.0,CUDA的版本要>=12.6。conda clean -i conda create -n lerobot python=3.10.12 -y conda activate lerobot pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 --index-url https://download.pytorch.org/whl/cu126 python -c "import torch; print(torch.cuda.is_available())" 下载修改后的lerobot代码,支持恩培老师的机械臂🦾。git clone https://github.com/enpeizhao/lerobot_single_student cd lerobot_single_student pip install -e . -i https://mirrors.huaweicloud.com/repository/pypi/simple pip install 'lerobot[feetech]' sudo apt install ffmpeg安装PCAN-Linux驱动,下载地址为:https://peak-system.com.cn/driver/ 下载之后解压进入安装包目录cd peak-linux-driver-8.20.0,依次运行如下命令:sudo apt install libpopt-dev make clean all sudo make install 安装成功之后我们可以加载模块并查看pcan版本信息:sudo modprobe pcan pcaninfo成功打印版本即代表安装成功😌PCAN driver version: 8.20.0 PCAN-Basic version: 4.10.0.4三、ACT 边缘部署我们遥操机械臂采集了100组动作视频用于ACT模型的训练:python -m lerobot.record \ --robot.ip_address="localhost" \ --robot.port=12345 \ --robot.type=enpei_follower \ --robot.id=enpei_follower \ --robot.cameras="{ handeye: {type: opencv, index_or_path: 4, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}}" \ --teleop.type=enpei_leader \ --teleop.port=/dev/ttyACM0 \ --teleop.id=enpei_leader \ --display_data=true \ --enpei_use_radian=true\ --dataset.repo_id=hou/demo_move_toy \ --dataset.push_to_hub=false \ --dataset.num_episodes=100\ --dataset.episode_time_s=15 \ --dataset.reset_time_s=5 \ --dataset.single_task="Put the toy to the white block" \ --dataset.root=/home/hou/workspace/lerobot_single_student/demo_move_toy \ --resume=false2. 云服务器的环境配置与本地被配置基本一致,总共训练200000个steps:python ./src/lerobot/scripts/train.py \ --dataset.repo_id=hou/demo_move_toy_degrees \ --dataset.root=./demo_move_toy_degrees\ --policy.type=act \ --output_dir=outputs/train/demo_move_toy_degrees_act \ --job_name=demo_move_toy_degrees \ --policy.device=cuda \ --policy.push_to_hub=false \ --wandb.enable=false\ --batch_size=32 \ --num_workers=8 \ --steps=200000 3. 我们在Jetson Orin Nano上实现了ACT模型的GPU实时推理,Jetpack的版本>=6.0,最终推理效果如下😜:python -m lerobot.test_policy \ --robot.ip_address="localhost" \ --robot.port=12345 \ --robot.type=enpei_follower \ --robot.id=enpei_follower \ --robot.cameras="{ handeye: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}}" \ --policy.path=last/pretrained_model\ --fps=30 \ --time_s=120 \ --single_task="Put the toy to the white box" \ --enpei_use_radian=false \ --display_data=true四、小结本文详细介绍了在Ubuntu 20.04 LTS系统上安装配置LeRobot环境的完整流程,包括系统镜像制作、GPU驱动安装、Miniconda与PyTorch环境搭建、LeRobot代码部署及PCAN驱动配置等关键步骤。通过实际案例演示了从数据采集、ACT模型训练到板侧推理的全流程应用,为开展VAL具身智能学习与开发提供了完整的实践指导。
  • 人工智能干货合集(2025年10月)
    1. AI开发平台ModelArts新功能2025年10月份没有发布新功能。2. 人工智能相关直播合集10月份的相关整理如下:昇腾AI算法挑战赛-使用华为开发者空间Versatile一键快速构建 AI Agentcid:link_0昇腾AI算法挑战赛来袭!创想无限,华为面向全球开发者的经典赛事现已开启。本期直播将手把手带你进入华为开发者空间,以及如何利用开发者空间Versatile一键快速构建专属AI Agent,开发者们,速来直播间,获取通关秘籍!其中还有开发者空间对于鸿蒙应用的支持,很值得期待!DeepSeek-R1 RL训练优化实践分享cid:link_1本次直播讲带大家一起探索cann-recipes-train 开源仓库介绍与DeepSeek-R1 RL训练优化实践分享cann-recipes-train是华为昇腾社区推出的开源项目,专注于提供基于昇腾AI处理器的训练配方与最佳实践。该仓库包含了从基础到前沿的多种模型训练示例,涵盖大语言模型、多模态模型等热门方向。通过精心优化的代码实现,它帮助开发者和研究者充分利用昇腾硬件的强大算力,显著提升训练效率并降低部署门槛。在本次分享中,我们将重点解析DeepSeek-R1在强化学习阶段的训练优化实践。作为DeepSeek最新发布的开源模型,R1在推理能力和与人类价值观对齐方面表现出色,其训练过程中的策略优化、价值函数设计和稳定性控制等都是值得深入探讨的技术要点。我们将结合cann-recipes-train提供的技术框架,详细介绍如何利用昇腾平台加速R1的RL训练过程,包括但不限于分布式策略、内存优化、混合精度训练等关键技术的实现方案。无论你是对大模型训练技术感兴趣的研究人员,还是希望深入了解昇腾AI处理器实际应用的开发者,本次直播都将为你提供宝贵的实践洞见和技术参考。不过可能直播回放还没有准备好,所以暂时没有图片介绍。
  • [技术干货] Flamingo模型:主流多模态技术的重要雏形
    DeepMind于2022年发布的Flamingo模型,被视为当前主流多模态技术的重要雏形。它不仅在技术上开创了先河,更深刻地影响了后续发展的方向。🔍 Flamingo的核心突破Flamingo模型的关键在于,它巧妙地将预训练好的、强大的单模态模型(视觉编码器和大型语言模型)组合起来,并让它们能协同工作,而不是从头训练一个全新的多模态模型。架构与关键组件:Flamingo的设计包含几个关键部分:视觉编码器:负责处理图像或视频帧,将其转换为视觉特征向量。感知重采样器 (Perceiver Resampler):这是Flamingo的一个创新模块。它能将视觉编码器输出的、数量可变的视觉特征,“提炼”成固定数量的、包含核心信息的视觉令牌。这解决了将高维视觉特征与语言模型对齐的难题。冻结的大型语言模型:Flamingo使用了一个强大的、预先训练好的语言模型(如Chinchilla)作为其文本生成的核心。模型的主要工作是让视觉信息能够被语言模型“理解”并利用。门控交叉注意力层:这些新引入的层被穿插在冻结的语言模型内部,负责将视觉令牌的信息与文本令牌进行融合。通过这种方式,语言模型在生成文本时,可以动态地关注相关的视觉信息。训练数据与范式:Flamingo模型通过在来自网页的交织图像-文本序列数据、图像-文本对以及视频-文本对混合数据集上进行训练,使其能够同时理解图像和视频上下文。这种训练方式是其成功的关键之一。标志性能力:少样本学习:得益于上述设计,Flamingo展现出强大的少样本甚至零样本学习能力。这意味着,在应对新的多模态任务时,只需在输入中提供少量任务示例(比如几张图片及其描述),模型就能举一反三,生成符合要求的答案,而不需要针对每个任务重新训练模型。这种“看一眼就会”的能力,使其成为多模态领域的GPT-3,为通用人工智能助手铺平了道路。💡 深远的技术影响Flamingo的探索为后续研究指明了方向,其影响主要体现在:技术路径的开创:Flamingo采用的冻结预训练单模态组件、并引入适配器模块进行特征融合的方案,成为后续许多多模态大模型(如BLIP-2、LLaVA)效仿的蓝图。它所展示的交织图文序列作为输入的形式,也成为处理多模态上下文的标准做法之一。催生开源生态:Flamingo的思想催生了像OpenFlamingo这样的开源项目,并进一步启发了RoboFlamingo等机器人操作模型的研究,推动了技术在更广阔领域的应用。揭示演进方向:Flamingo的成功也让社区看到了与OpenAI GPT-4这类更先进多模态模型之间的差距,特别是在复杂推理、与人类意图对齐的指令跟随能力等方面。这激励了后续工作在指令微调、人类反馈强化学习等领域进行深入探索。总而言之,Flamingo模型在技术架构和能力展现上,都为今天我们所见的各种多模态大模型奠定了坚实的基础。
  • [技术干货] 从ViT到多模态大模型
    Vision Transformer的成功,其深远影响远超视觉领域本身。它提供了一种将视觉信号转化为与文本Token同构的序列化表征的通用方法,这为构建真正统一的、端到端的视觉-语言模型扫清了架构上的根本障碍。在此之前,多模态融合需要处理CNN特征与Transformer嵌入之间的“模态鸿沟”;在此之后,视觉和语言可以在同一个Transformer架构内进行无缝交互。这一转变,直接催生了一系列革新性的工作,并逐步将多模态研究推向大模型时代。早期的工作如ViLT,直接继承了ViT的视觉编码方式,并将其理念推向极致。它完全摒弃了任何复杂的视觉Backbone(无论是Faster R-CNN还是ResNet),图像仅通过一个简单的线性投影层转化为Patch嵌入,便与文本Token一同送入共享的Transformer中进行融合。ViLT的意义在于它确立了 “轻视觉、重统一Transformer” 的设计哲学,极大地提升了效率,证明了即使没有强大的视觉编码器,纯Transformer架构也能通过跨模态注意力学习到高质量的联合表征。然而,ViLT这类模型在预训练目标上仍主要沿用图像-文本对比学习、掩码语言建模等传统任务。接下来的工作,如BLIP,则在这一统一架构上对预训练范式进行了系统性增强。BLIP的核心洞察在于数据滤波与多任务协同。它通过引入一个字幕生成器和一个过滤器,从带有噪声的网络数据中自动生成高质量的字幕并清洗数据,从而解决了此前模型严重依赖噪声数据的问题。同时,它巧妙地融合了理解(如图像-文本匹配)与生成(如图说生成)任务于一个模型中,使得模型既能进行高效的视觉-语言检索,又能产生流畅的自然语言描述,极大地增强了模型的通用性和性能。CLIP 由OpenAI在2021年提出,其核心思想是一种颠覆性的代理任务:大规模图像-文本对比学习。它彻底抛弃了传统的、需要人工标注的分类标签,转而直接从互联网上收集的数亿个“图像-文本对”中学习。模型结构上,CLIP采用极其简洁的双塔架构,拥有独立的图像编码器(如ViT)和文本编码器,训练目标仅仅是让配对样本在特征空间中的余弦相似度最大化,而非配对样本的最小化。这种范式带来了几个革命性影响:首先,它学习到的特征空间具有极强的泛化能力,使得模型通过简单的提示工程就能在未见过的视觉概念上实现零样本识别。其次,它证明了从原始网络数据中学习的巨大潜力,为后续大模型的数据策略树立了典范。最后,CLIP模型本身成为了一个强大的“视觉语义接口”,被广泛用作ALBEF、BLIP等后续融合模型的高质量视觉特征提取器,甚至催生了Stable Diffusion等生成模型。VL-BEIT 则代表了另一条技术路径的延伸,即基于掩码建模的生成式预训练。它继承了BEIT的核心思想——使用离散视觉令牌作为重建目标,并将其成功扩展到多模态领域。VL-BEIT的统一预训练任务包含三部分:掩码图像建模、掩码语言建模以及图像-文本匹配。其关键创新在于,它使用一个共享的Transformer,同时处理视觉令牌和文本令牌,并让模型在单一架构下学习重建两种模态的被掩码部分。这种方法迫使模型在共同的潜在空间中理解并生成视觉和语言概念,从而实现深度的模态对齐。VL-BEIT的成功表明,BEIT所代表的生成式、概念式预训练范式同样适用于多模态场景,它为模型提供了一种强大的、内在的语义理解能力,这条路径与CLIP的对比学习路径形成了有力的互补。将这几条线合并观察,我们可以看到多模态预训练的演进全景:ViT提供了统一的视觉序列输入基础;ViLT验证了纯Transformer端到端融合的可行性;CLIP确立了对比学习与大规模网络数据结合的威力;BEIT/MAE深化了生成式预训练在视觉领域的应用;而BLIP/VL-BEIT等则是在此基础上,对数据、任务和架构进行的更精巧的融合与优化。最终,这些工作共同汇聚成BLIP-2这样的技术范式,即利用高质量的特征提取器(如CLIP的视觉塔、BEIT的语义概念)或高效的接口(Q-Former),来桥接并激发大型语言模型的跨模态能力。
总条数:7838 到第
上滑加载中