当前位置:   article > 正文

Yunet调试

yunet

YuNet人脸检测调试

原文章链接:【速度↑20%模型尺寸↓36%】极简开源人脸检测算法升级 (qq.com)

python代码

 https://github.com/opencv/opencv_zoo/tree/master/models/face_detection_yunet

c++代码(未尝试)

 https://github.com/ShiqiYu/libfacedetection  // git链接

环境:yolo5

调试记录

1. 模型下载:

从它给的链接下载后缀为onnx的模型文件 yunet.onnx

 https://github.com/ShiqiYu/libfacedetection.train/blob/a61a428929148171b488f024b5d6774f93cdbc13/tasks/task1/onnx/yunet.onnx 

下载完的模型放在整体项目路径下

2. 运行基准文件benchmark.py

准备工作

1. 环境搭建

  1. 1. Install `python >= 3.6`.
  2.  2. Install dependencies: `pip install -r requirements.txt`.
  3.  3. Download data for benchmarking. # 下载需要用到的测试数据
  4.    1. Download all data: `python download_data.py` # 类爬虫程序,国内谷歌网站无法访问,尝试失败
  5.      2. Download one or more specified data: `python download_data.py face text`. Available names can be found in `download_data.py`. # 下载特定的数据
  6.      3. If download fails, you can download all data from https://pan.baidu.com/s/18sV8D4vXUb2xC9EG45k7bg (code: pvrw). Please place and extract data packages under [./data](./data). # 百度网盘链接 尝试成功 下载face_detection中包含的三张图片到data下

2. 根据yaml文件给定参数,原文链接python yaml文件操作 - 浩浩学习 - 博客园 (cnblogs.com)

查询yaml是什么

 yaml是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便
 yaml基础语法规则
     大小写敏感
     使用缩进表示层级关系
     不允许使用 TAB 键来缩进,只允许使用空格键来缩进
     缩进的空格数量不重要
     使用"#"来表示注释
 yaml 支持的数据结构有三种
   对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
   数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
   纯量(scalars):单个的、不可再分的值

yaml文件的使用

  1.  pip install pyyaml
  2.  pip install pyyaml -i https://pypi.tuna.tsinghua.edu.cn/simple
  3.  ​
  4.  with open(file_path, 'r', encoding='utf-8') as f:
  5.         data = yaml.load(f, Loader=yaml.FullLoader) # 加载yaml数据
  6.         print(f'读取的数据:{data}')
  7.         print(f'数据类型为:{type(data)}')
  8.  # pyyaml模块在python中用于处理yaml格式数据,主要使用yaml.safe_dump()、yaml.safe_load()函数将python值和yaml格式数据相互转换。当然也存在yaml.dump()、yaml.load()函数,同样能实现数据转换功能,只是官方不太推荐使用。官方给出的解释,因为yaml.safe_dump()、yaml.safe_load() 能够,而且yaml.safe_dump()、yaml.safe_load()比yaml.dump()、yaml.load()安全

4. benchmark.py中改模型路径参数

  • 根据paser函数给参数yaml的默认值

     parser.add_argument('--cfg', '-c', type=str,default=r"F:\python_project\opencv_zoo-master\benchmark\config\face_detection_yunet.yaml",help='Benchmarking on the given config.')
  • argarse函数的使用

    1.  第一步:创建 ArgumentParser() 对象
    2.   parser = argparse.ArgumentParser() #创建对象
    3.  第二步:调用 add_argument() 方法添加参数
    4.   parser.add_argument('integer', type=int, help='display an integer')
    5.  第三步:使用 parse_args() 解析添加的参数
    6.   args = parser.parse_args()
    7.  要使用参数就用args.module的形式去调用,也可在shell终端使用python xx.py --xx 参数
  • 进yaml修改模型的默认路径

  • 运行benchmark结果

3.研究benchmark.py

yaml转换为python数据之后

cfg:

  1.  {'Benchmark': {'name': 'Face Detection Benchmark', 'type': 'Detection',
  2.                 'data': {'path': 'benchmark/data/face_detection', 'files': ['group.jpg', 'concerts.jpg', 'dance.jpg'], 'sizes': [[160, 120], [640, 480]]},
  3.                 'metric': {'warmup': 30, 'repeat': 10, 'reduction': 'median'},
  4.                 'backend': 'default', 'target': 'cpu'},
  5.  'Model': {'name': 'YuNet', 'modelPath': 'r"F:\\python_project\\opencv_zoomaster\\models\\face_detection_yunet\\yunet.onnx"', 'confThreshold': 0.6, 'nmsThreshold': 0.3, 'topK': 5000}}

1. def prepend_pythonpath(cfg)函数

这个函数的功能就是编列yaml数据找到path里的内容,并将其赋值为cfg对应的键值.

比如原来cfg中: path : F:\python_project ----> 现在 path = F:\python_project

  1.  def prepend_pythonpath(cfg):
  2.      for k, v in cfg.items():  # item()方法把字典中每对key和value组成一个元组,并把这些元组放在列表中返回 key放键 value为值
  3.          if isinstance(v, dict):  # 判断v是否为dict类型 返回布尔值 直到不是字典为止
  4.              prepend_pythonpath(v)
  5.          else:
  6.              if 'path' in k.lower():  # 全转为小写 遍历yaMl数据直到键值变为path为止
  7.                  cfg[k] = os.path.join(os.environ['PYTHONPATH'], v) #如果我们使用 PYTHONPATH 中的 modules,那么在运行 python 前,就要把 path 加到 os.environ['PYTHONPATH']

2. def build_from_cfg(cfg, registery, key=None, name=None)

class类中传入的参数为 build_from_cfg(self.data_dict, registery=DATALOADERS, name=self.type)

_data_dict = data(path,file,size) name = "detection"

  1.  def build_from_cfg(cfg, registery, key=None, name=None):  # _data_dict, registery=DATALOADERS, name=self._type
  2.      if key is not None:                                  
  3.          obj_name = cfg.pop(key)
  4.          obj = registery.get(obj_name)  
  5.          return obj(**cfg)
  6.      elif name is not None:  # 走这里
  7.          obj = registery.get(name) # registery是一个类实例 出的对象调用类方法get
  8.          return obj(**cfg)  # 最后从这里进入class BaseImageLoader类 cfg: path fliles sizes
  9.      else:
  10.          raise NotImplementedError()

其中DATALOADERS = Registery('DataLoaders')

  1.  class Registery:
  2.      def __init__(self, name):
  3.          self._name = name
  4.          self._dict = dict()
  5.  ​
  6.      def get(self, key):
  7.          if key in self._dict:
  8.              return self._dict[key]
  9.          else:
  10.              return self._dict['Base'] # return了这里
  11.  ​
  12.      def register(self, item):
  13.          self._dict[item.__name__] = item
  14.          # renaming *ImageLoader/*VideoLoader
  15.          if 'ImageLoader' in item.__name__:
  16.              name = item.__name__.replace('ImageLoader', '')
  17.              self._dict[name] = item
  18.  METRICS = Registery('Metrics')
  19.  DATALOADERS = Registery('DataLoaders')

进入图片加载类

  1.  class _BaseImageLoader:
  2.      def __init__(self, **kwargs):
  3.          self._path = kwargs.pop('path', None)  # 给路径
  4.          assert self._path, 'Benchmark[\'data\'][\'path\'] cannot be empty.'  # 判断是否为空
  5.  ​
  6.          self._files = kwargs.pop('files', None)  # 给文件
  7.          assert self._files, 'Benchmark[\'data\'][\'files\'] cannot be empty'
  8.          self._len_files = len(self._files)
  9.  ​
  10.          self._sizes = kwargs.pop('sizes', [[0, 0]]) # 给大小 self._sizes = [[160,120],[640,480]]
  11.          self._len_sizes = len(self._sizes)  # 完成之后跳回benchmark.py的46行 self._len_sizes = 3
  12.  ​
  13.      @property
  14.      def name(self):
  15.          return self.__class__.__name__
  16.  ​
  17.      def __len__(self):
  18.          return self._len_files * self._len_sizes
  19.  ​
  20.      def __iter__(self):
  21.          for filename in self._files:
  22.              image = cv.imread(os.path.join(self._path, filename))
  23.              if [0, 0] in self._sizes:
  24.                  yield filename, image
  25.              else:
  26.                  for size in self._sizes:
  27.                      image_r = cv.resize(image, size)
  28.                      yield filename, image_r

3. class Benchmark:

实例化benchmark对象,传入cfg中键为Benchmark的值的内容用来初始化

 benchmark = Benchmark(**cfg['Benchmark'])

到这里将cfg中data对应的值赋给data_dict并将其从cfg中删掉,运行bulid_form_cfg函数加载数据,这里先运行build_from_cfg函数

到目录2def bulid_from_cfg下

运行完bulid_from_cfg函数之后继续往下

根据配置文件yaml的metric同上调用bulid函数

  1. self._metric_dict = kwargs.pop('metric', None)
  2.          assert self._metric_dict, 'Benchmark[\'metric\'] cannot be empty.'
  3.          if 'type' in self._metric_dict:
  4.              self._metric = build_from_cfg(self._metric_dict, registery=METRICS, key='type')
  5.          else:
  6.              self._metric = build_from_cfg(self._metric_dict, registery=METRICS, name=self._type) # name = detection
  7. 接下来进入
  8.  def build_from_cfg(cfg, registery, key=None, name=None):  # _data_dict, registery=DATALOADERS, name=self._type
  9.      if key is not None:                                  
  10.          obj_name = cfg.pop(key)
  11.          obj = registery.get(obj_name)  
  12.          return obj(**cfg)
  13.      elif name is not None:  # 走这里
  14.          obj = registery.get(name) # registery是一个类实例 出的对象调用类方法get 从这里进入class registery
  15.          return obj(**cfg)  # obj = 'Detection'
  16.      else:
  17.          raise NotImplementedError()
  18.  class Registery:
  19.      def __init__(self, name):
  20.          self._name = name
  21.          self._dict = dict()
  22.  ​
  23.      def get(self, key):  # 这里 key = Detection
  24.          if key in self._dict: # _dict = {'Base':'放的是对象后面同','Detection','Recognition','Tracking'}
  25.              return self._dict[key] # 最后Detection在_dict中,返回Detection对应的对象值
  26.          else:
  27.              return self._dict['Base']
  28.  ​
  29.      def register(self, item):
  30.          self._dict[item.__name__] = item
  31.          # renaming *ImageLoader/*VideoLoader
  32.          if 'ImageLoader' in item.__name__:
  33.              name = item.__name__.replace('ImageLoader', '')
  34.              self._dict[name] = item
  35.  ​
  36.  METRICS = Registery('Metrics')
  37.  DATALOADERS = Registery('DataLoaders')

调用Detection对象,传参数**cfg。 cfg ={'path','files','sizes'} 进入detection.py

  1. @METRICS.register
  2.  class Detection(BaseMetric):
  3.      def __init__(self, **kwargs):  # **kwargs = {'warmup':30,'repeat':10,'reduction':'median'}
  4.          super().__init__(**kwargs)  # 从这里进base_metric.py
  5.  ​
  6.      def forward(self, model, *args, **kwargs):
  7.          img = args[0]
  8.          size = [img.shape[1], img.shape[0]]
  9.          try:
  10.              model.setInputSize(size)
  11.          except:
  12.              pass
  13.  ​
  14.          # warmup
  15.          for _ in range(self._warmup):
  16.              model.infer(img)
  17.          # repeat
  18.          self._timer.reset()
  19.          for _ in range(self._repeat):
  20.              self._timer.start()
  21.              model.infer(img)
  22.              self._timer.stop()
  23.  ​
  24.          return self._getResult()
  25.  class BaseMetric:
  26.      def __init__(self, **kwargs):
  27.          self._warmup = kwargs.pop('warmup', 3)  # 这里开始属性初始化
  28.          self._repeat = kwargs.pop('repeat', 10)
  29.          self._reduction = kwargs.pop('reduction', 'median')
  30.  ​
  31.          self._timer = Timer() # 进Timer类
  32.  ​
  33.      def _calcMedian(self, records):
  34.          ''' Return the median of records
  35.         '''
  36.          l = len(records)
  37.          mid = int(l / 2)
  38.          if l % 2 == 0:
  39.              return (records[mid] + records[mid - 1]) / 2
  40.          else:
  41.              return records[mid]
  42.  ​
  43.      def _calcGMean(self, records, drop_largest=3):
  44.          ''' Return the geometric mean of records after drop the first drop_largest
  45.         '''
  46.          l = len(records)
  47.          if l <= drop_largest:
  48.              print('len(records)({}) <= drop_largest({}), stop dropping.'.format(l, drop_largest))
  49.          records_sorted = sorted(records, reverse=True)
  50.          return sum(records_sorted[drop_largest:]) / (l - drop_largest)
  51.  ​
  52.      def _getResult(self):
  53.          records = self._timer.getRecords()
  54.          if self._reduction == 'median':
  55.              return self._calcMedian(records)
  56.          elif self._reduction == 'gmean':
  57.              return self._calcGMean(records)
  58.          else:
  59.              raise NotImplementedError('Reduction {} is not supported'.format(self._reduction))
  60.  ​
  61.      def getReduction(self):
  62.          return self._reduction
  63.  ​
  64.      def forward(self, model, *args, **kwargs):
  65.          raise NotImplementedError('Not implemented')
  66.  import cv2 as cv
  67.  ​
  68.  class Timer:
  69.      def __init__(self):
  70.          self._tm = cv.TickMeter()
  71.          self._record = []  # 初始完之后返回到benchmark.py第56行
  72.  ​
  73.      def start(self):
  74.          self._tm.start()
  75.  ​
  76.      def stop(self):
  77.          self._tm.stop()
  78.          self._record.append(self._tm.getTimeMilli())
  79.          self._tm.reset()
  80.  ​
  81.      def reset(self):
  82.          self._record = []
  83.  ​
  84.      def getRecords(self):
  85.          return self._record

56行

  1.  backend_id = kwargs.pop('backend', 'default') # backend被删了 现在值为default kwargs={'name':'Face Detection','target':'cpu'} 因为配置文件每用一次pop就删掉了
  2.  available_backends = dict(
  3.              default=cv.dnn.DNN_BACKEND_DEFAULT, default = 0
  4.              # halide=cv.dnn.DNN_BACKEND_HALIDE,
  5.              # inference_engine=cv.dnn.DNN_BACKEND_INFERENCE_ENGINE,
  6.              opencv=cv.dnn.DNN_BACKEND_OPENCV, opencv = 3
  7.              # vkcom=cv.dnn.DNN_BACKEND_VKCOM,
  8.              cuda=cv.dnn.DNN_BACKEND_CUDA, cuda = 5
  9.         )
  10.  target_id = kwargs.pop('target', 'cpu') target_id = "cpu"
  11.  available_targets = dict(
  12.              cpu=cv.dnn.DNN_TARGET_CPU, = 0
  13.              # opencl=cv.dnn.DNN_TARGET_OPENCL,
  14.              # opencl_fp16=cv.dnn.DNN_TARGET_OPENCL_FP16,
  15.              # myriad=cv.dnn.DNN_TARGET_MYRIAD,
  16.              # vulkan=cv.dnn.DNN_TARGET_VULKAN,
  17.              # fpga=cv.dnn.DNN_TARGET_FPGA,
  18.              cuda=cv.dnn.DNN_TARGET_CUDA, = 6
  19.              cuda_fp16=cv.dnn.DNN_TARGET_CUDA_FP16, = 7
  20.              # hddl=cv.dnn.DNN_TARGET_HDDL,
  21.         )
  22.  try:
  23.    available_backends['timvx'] = cv.dnn.DNN_BACKEND_TIMVX
  24.    available_targets['npu'] = cv.dnn.DNN_TARGET_NPU
  25.    except:
  26.      print('OpenCV is not compiled with TIM-VX backend enbaled. See https://github.com/opencv/opencv/wiki/TIM-VX-Backend-For-Running-OpenCV-On-NPU for more details on how to enable TIM-VX backend.')
  27.  ​
  28.  self._backend = available_backends[backend_id]   int 0
  29.  self._target = available_targets[target_id] int 0
  30.  self._benchmark_results = dict() # 结束之后重新进入Build函数 传"Yunet"

Yunet初始化结束之后调用run函数打印出图片的图片参数

附录

调试的路径的坑:编程地址与电脑地址有区别

直接从电脑中复制过来的目录是使用‘ \ ’分隔,但在Python中‘ \ ’为转义字符,有其他功能,可能出现占用而报错的情况。所以我们在电脑中将目录复制过来后,手动将‘ \ ’改为’ / ‘、’ // ‘或’ \ ‘,即可解决上述问题

  1.  #错误,标准电脑格式
  2.  path_train = 'D:\python learning&training\pythonProject\Project\Project\DataCSV3\'    
  3.  #正确 使用了‘ / ’
  4.  path_train = 'D:/python learning&training/pythonProject/Project/Project/DataCSV3/'
  5.  #正确 使用了‘ \\ ’
  6.  path_train = 'D:\\python learning&training\\pythonProject\\Project\\Project\\DataCSV3\\'
  7.  #正确 使用了‘ // ’
  8.  path_train = 'D://python learning&training//pythonProject//Project//Project//DataCSV3//'

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号