目标检测模型NanoDet(超轻量,速度很快)介绍和PyTorch版本实践

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: YOLO、SSD、Fast R-CNN等模型在目标检测方面速度较快和精度较高,但是这些模型比较大,不太适合移植到移动端或嵌入式设备;轻量级模型 NanoDet-m,对单阶段检测模型三大模块(Head、Neck、Backbone)进行轻量化,目标加检测速度很快;模型文件大小仅几兆(小于4M)。

前言

YOLO、SSD、Fast R-CNN等模型在目标检测方面速度较快和精度较高,但是这些模型比较大,不太适合移植到移动端或嵌入式设备;轻量级模型 NanoDet-m,对单阶段检测模型三大模块(Head、Neck、Backbone)进行轻量化,目标加检测速度很快;模型文件大小仅几兆(小于4M)。

NanoDet作者开源代码地址:https://github.com/RangiLyu/nanodet  (致敬)

基于NanoDet项目进行小裁剪,专门用来实现Python语言、PyTorch 版本的代码地址:https://github.com/guo-pu/NanoDet-PyTorch

下载直接能使用,支持图片、视频文件、摄像头实时目标检测


 先看一下NanoDet目标检测的效果:

同时检测多辆汽车:

image.gif

查看多目标、目标之间重叠、同时存在小目标和大目标的检测效果:

image.gif


NanoDet 模型介绍

NanoDet 是一种 FCOS 式的单阶段 anchor-free 目标检测模型,它使用 ATSS 进行目标采样,使用 Generalized Focal Loss 损失函数执行分类和边框回归(box regression)。

1)NanoDet 模型性能

NanoDet-m模型和YoloV3-Tiny、YoloV4-Tiny作对比:

Model Resolution COCO mAP Latency(ARM 4xCore) FLOPS Params Model Size(ncnn bin)
NanoDet-m 320*320 20.6 10.23ms 0.72B 0.95M 1.8mb
NanoDet-m 416*416 21.7 16.44ms 1.2B 0.95M 1.8mb
YoloV3-Tiny 416*416 16.6 37.6ms 5.62B 8.86M 33.7mb
YoloV4-Tiny 416*416 21.7 32.81ms 6.96B 6.06M 23.0mb

备注:以上性能基于 ncnn 和麒麟 980 (4xA76+4xA55) ARM CPU 获得的。使用 COCO mAP (0.5:0.95) 作为评估指标,兼顾检测和定位的精度,在 COCO val 5000 张图片上测试,并且没有使用 Testing-Time-Augmentation。

NanoDet作者将 ncnn 部署到手机(基于 ARM 架构的 CPU 麒麟 980,4 个 A76 核心和 4 个 A55 核心)上之后跑了一下 benchmark,模型前向计算时间只要 10 毫秒左右,而 yolov3 和 v4 tiny 均在 30 毫秒的量级。在安卓摄像头 demo app 上,算上图片预处理、检测框后处理以及绘制检测框的时间,NanoDet 也能轻松跑到 40+FPS。

2)NanoDet 模型架构

image.gif

3)NanoDet损失函数

NanoDet 使用了李翔等人提出的 Generalized Focal Loss 损失函数。该函数能够去掉 FCOS 的 Centerness 分支,省去这一分支上的大量卷积,从而减少检测头的计算开销,非常适合移动端的轻量化部署。

image.gif

详细请参考:Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection

4)NanoDet 优势

NanoDet 是一个速度超快和轻量级的移动端 Anchor-free 目标检测模型。该模型具备以下优势:

    • 超轻量级:模型文件大小仅几兆(小于4M——nanodet_m.pth);
    • 速度超快:在移动 ARM CPU 上的速度达到 97fps(10.23ms);
    • 训练友好:GPU 内存成本比其他模型低得多。GTX1060 6G 上的 Batch-size 为 80 即可运行;
    • 方便部署:提供了基于 ncnn 推理框架的 C++ 实现和 Android demo。

    基于PyTorch 实现NanoDet

    基于NanoDet项目进行小裁剪,专门用来实现Python语言、PyTorch 版本的代码地址:

    1)NanoDet目标检测效果

    1)检测出一只小鸟

    image.gif

    2)同时检测出四位少年

    image.gif

    3)在复杂街道中,检测出行人、汽车:

    image.gif

    通过测试发现NanoDet确实很快,但识别精度和效果比YOLOv4差不少的。

    下图是使用 YOLOv4检测的效果:

    文章链接:https://guo-pu.blog.csdn.net/article/details/109912838

    大家可以看到大部分的行人、汽车是被检测出来了,存在小部分没有被检测出来;

    image.gif

    看左上角的统计信息,能看到汽车检测到5辆,行人检测到14位,自行车检测到1辆,交通灯设备3台,太阳伞3把,手提包1个。

    2)环境参数

    测试环境参数

    系统:Windows       编程语言:Python 3.8            整合开发环境:Anaconda

    深度学习框架:PyTorch1.7.0+cu101 (torch>=1.3 即可)              开发代码IDE:PyCharm

    开发具体环境要求如下:

      • Cython
      • termcolor
      • numpy
      • torch>=1.3
      • torchvision
      • tensorboard
      • pycocotools
      • matplotlib
      • pyaml
      • opencv-python
      • tqdm

      通常测试感觉GPU加速(显卡驱动、cudatoolkit 、cudnn)、PyTorch、pycocotools相对难装一点

      Windows开发环境安装可以参考:

      安装cudatoolkit 10.1、cudnn7.6请参考 YOLO实践应用之搭建开发环境(Windows系统、Python 3.8、TensorFlow2.3版本)_yolo算法是什么环境-CSDN博客

      安装PyTorch请参考 Anaconda如何安装PyTorch?_conda安装torch包-CSDN博客

      安装pycocotools请参考 Windows以及Linux下Anaconda安装pycocotools_pycocotools-linux-CSDN博客

      3)体验NanoDet目标检测

      下载代码,打开工程

      先到githug下载代码,然后解压工程,然后使用PyCharm工具打开工程;

      githug代码下载地址:https://github.com/guo-pu/NanoDet-PyTorch

      说明:该代码是基于NanoDet项目进行小裁剪,专门用来实现Python语言、PyTorch 版本的代码

      NanoDet作者开源代码地址https://github.com/RangiLyu/nanodet  (致敬)

      使用PyCharm工具打开工程

      image.gif

      打开后的页面是这样的:

      image.gif

      【选择开发环境】

      文件(file)——>设置(setting)——>项目(Project)——>Project Interpreters   选择搭建的开发环境;

      image.gif

      然后先点击Apply,等待加载完成,再点击OK;

      进行目标检测

      具体命令请参考:

      '''目标检测-图片'''
      python detect_main.py image --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  street.png
      '''目标检测-视频文件'''
      python detect_main.py video --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  test.mp4
      '''目标检测-摄像头'''
      python detect_main.py webcam --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  0

      image.gif

      【目标检测-图片】

      image.gif


      【目标检测-视频文件】

      检测的是1080*1920的图片,很流畅毫不卡顿,就是目前识别精度不太高

      image.gif


      4)调用模型的核心代码

      detect_main.py 代码:

      import cv2
      import os
      import time
      import torch
      import argparse
      from nanodet.util import cfg, load_config, Logger
      from nanodet.model.arch import build_model
      from nanodet.util import load_model_weight
      from nanodet.data.transform import Pipeline
      image_ext = ['.jpg', '.jpeg', '.webp', '.bmp', '.png']
      video_ext = ['mp4', 'mov', 'avi', 'mkv']
      '''目标检测-图片'''
      # python detect_main.py image --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  street.png
      '''目标检测-视频文件'''
      # python detect_main.py video --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  test.mp4
      '''目标检测-摄像头'''
      # python detect_main.py webcam --config ./config/nanodet-m.yml --model model/nanodet_m.pth --path  0
      def parse_args():
          parser = argparse.ArgumentParser()
          parser.add_argument('demo', default='image', help='demo type, eg. image, video and webcam')
          parser.add_argument('--config', help='model config file path')
          parser.add_argument('--model', help='model file path')
          parser.add_argument('--path', default='./demo', help='path to images or video')
          parser.add_argument('--camid', type=int, default=0, help='webcam demo camera id')
          args = parser.parse_args()
          return args
      class Predictor(object):
          def __init__(self, cfg, model_path, logger, device='cuda:0'):
              self.cfg = cfg
              self.device = device
              model = build_model(cfg.model)
              ckpt = torch.load(model_path, map_location=lambda storage, loc: storage)
              load_model_weight(model, ckpt, logger)
              self.model = model.to(device).eval()
              self.pipeline = Pipeline(cfg.data.val.pipeline, cfg.data.val.keep_ratio)
          def inference(self, img):
              img_info = {}
              if isinstance(img, str):
                  img_info['file_name'] = os.path.basename(img)
                  img = cv2.imread(img)
              else:
                  img_info['file_name'] = None
              height, width = img.shape[:2]
              img_info['height'] = height
              img_info['width'] = width
              meta = dict(img_info=img_info,
                          raw_img=img,
                          img=img)
              meta = self.pipeline(meta, self.cfg.data.val.input_size)
              meta['img'] = torch.from_numpy(meta['img'].transpose(2, 0, 1)).unsqueeze(0).to(self.device)
              with torch.no_grad():
                  results = self.model.inference(meta)
              return meta, results
          def visualize(self, dets, meta, class_names, score_thres, wait=0):
              time1 = time.time()
              self.model.head.show_result(meta['raw_img'], dets, class_names, score_thres=score_thres, show=True)
              print('viz time: {:.3f}s'.format(time.time()-time1))
      def get_image_list(path):
          image_names = []
          for maindir, subdir, file_name_list in os.walk(path):
              for filename in file_name_list:
                  apath = os.path.join(maindir, filename)
                  ext = os.path.splitext(apath)[1]
                  if ext in image_ext:
                      image_names.append(apath)
          return image_names
      def main():
          args = parse_args()
          torch.backends.cudnn.enabled = True
          torch.backends.cudnn.benchmark = True
          load_config(cfg, args.config)
          logger = Logger(-1, use_tensorboard=False)
          predictor = Predictor(cfg, args.model, logger, device='cuda:0')
          logger.log('Press "Esc", "q" or "Q" to exit.')
          if args.demo == 'image':
              if os.path.isdir(args.path):
                  files = get_image_list(args.path)
              else:
                  files = [args.path]
              files.sort()
              for image_name in files:
                  meta, res = predictor.inference(image_name)
                  predictor.visualize(res, meta, cfg.class_names, 0.35)
                  ch = cv2.waitKey(0)
                  if ch == 27 or ch == ord('q') or ch == ord('Q'):
                      break
          elif args.demo == 'video' or args.demo == 'webcam':
              cap = cv2.VideoCapture(args.path if args.demo == 'video' else args.camid)
              while True:
                  ret_val, frame = cap.read()
                  meta, res = predictor.inference(frame)
                  predictor.visualize(res, meta, cfg.class_names, 0.35)
                  ch = cv2.waitKey(1)
                  if ch == 27 or ch == ord('q') or ch == ord('Q'):
                      break
      if __name__ == '__main__':
          main()

      image.gif

      希望对你有帮助。( •̀ ω •́ )✧

      相关文章
      |
      2月前
      |
      机器学习/深度学习 数据采集 人工智能
      PyTorch学习实战:AI从数学基础到模型优化全流程精解
      本文系统讲解人工智能、机器学习与深度学习的层级关系,涵盖PyTorch环境配置、张量操作、数据预处理、神经网络基础及模型训练全流程,结合数学原理与代码实践,深入浅出地介绍激活函数、反向传播等核心概念,助力快速入门深度学习。
      172 1
      |
      1月前
      |
      边缘计算 人工智能 PyTorch
      130_知识蒸馏技术:温度参数与损失函数设计 - 教师-学生模型的优化策略与PyTorch实现
      随着大型语言模型(LLM)的规模不断增长,部署这些模型面临着巨大的计算和资源挑战。以DeepSeek-R1为例,其671B参数的规模即使经过INT4量化后,仍需要至少6张高端GPU才能运行,这对于大多数中小型企业和研究机构来说成本过高。知识蒸馏作为一种有效的模型压缩技术,通过将大型教师模型的知识迁移到小型学生模型中,在显著降低模型复杂度的同时保留核心性能,成为解决这一问题的关键技术之一。
      |
      2月前
      |
      机器学习/深度学习 存储 PyTorch
      Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
      Neural ODE将神经网络与微分方程结合,用连续思维建模数据演化,突破传统离散层的限制,实现自适应深度与高效连续学习。
      129 3
      Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
      |
      3月前
      |
      PyTorch 算法框架/工具 异构计算
      PyTorch 2.0性能优化实战:4种常见代码错误严重拖慢模型
      我们将深入探讨图中断(graph breaks)和多图问题对性能的负面影响,并分析PyTorch模型开发中应当避免的常见错误模式。
      235 9
      |
      5月前
      |
      机器学习/深度学习 存储 PyTorch
      PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
      本文通过使用 Kaggle 数据集训练情感分析模型的实例,详细演示了如何将 PyTorch 与 MLFlow 进行深度集成,实现完整的实验跟踪、模型记录和结果可复现性管理。文章将系统性地介绍训练代码的核心组件,展示指标和工件的记录方法,并提供 MLFlow UI 的详细界面截图。
      242 2
      PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
      |
      4月前
      |
      机器学习/深度学习 数据可视化 PyTorch
      Flow Matching生成模型:从理论基础到Pytorch代码实现
      本文将系统阐述Flow Matching的完整实现过程,包括数学理论推导、模型架构设计、训练流程构建以及速度场学习等关键组件。通过本文的学习,读者将掌握Flow Matching的核心原理,获得一个完整的PyTorch实现,并对生成模型在噪声调度和分数函数之外的发展方向有更深入的理解。
      1702 0
      Flow Matching生成模型:从理论基础到Pytorch代码实现
      |
      5月前
      |
      机器学习/深度学习 PyTorch 算法框架/工具
      提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
      本文将深入探讨L1、L2和ElasticNet正则化技术,重点关注其在PyTorch框架中的具体实现。关于这些技术的理论基础,建议读者参考相关理论文献以获得更深入的理解。
      165 4
      提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
      |
      6月前
      |
      机器学习/深度学习 PyTorch API
      PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
      本文深入探讨神经网络模型量化技术,重点讲解训练后量化(PTQ)与量化感知训练(QAT)两种主流方法。PTQ通过校准数据集确定量化参数,快速实现模型压缩,但精度损失较大;QAT在训练中引入伪量化操作,使模型适应低精度环境,显著提升量化后性能。文章结合PyTorch实现细节,介绍Eager模式、FX图模式及PyTorch 2导出量化等工具,并分享大语言模型Int4/Int8混合精度实践。最后总结量化最佳策略,包括逐通道量化、混合精度设置及目标硬件适配,助力高效部署深度学习模型。
      922 21
      PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
      |
      8月前
      |
      机器学习/深度学习 JavaScript PyTorch
      9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
      生成对抗网络(GAN)的训练效果高度依赖于损失函数的选择。本文介绍了经典GAN损失函数理论,并用PyTorch实现多种变体,包括原始GAN、LS-GAN、WGAN及WGAN-GP等。通过分析其原理与优劣,如LS-GAN提升训练稳定性、WGAN-GP改善图像质量,展示了不同场景下损失函数的设计思路。代码实现覆盖生成器与判别器的核心逻辑,为实际应用提供了重要参考。未来可探索组合优化与自适应设计以提升性能。
      656 7
      9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
      |
      6月前
      |
      机器学习/深度学习 PyTorch 编译器
      深入解析torch.compile:提升PyTorch模型性能、高效解决常见问题
      PyTorch 2.0推出的`torch.compile`功能为深度学习模型带来了显著的性能优化能力。本文从实用角度出发,详细介绍了`torch.compile`的核心技巧与应用场景,涵盖模型复杂度评估、可编译组件分析、系统化调试策略及性能优化高级技巧等内容。通过解决图断裂、重编译频繁等问题,并结合分布式训练和NCCL通信优化,开发者可以有效提升日常开发效率与模型性能。文章为PyTorch用户提供了全面的指导,助力充分挖掘`torch.compile`的潜力。
      710 17

      推荐镜像

      更多