1 Star 0 Fork 11

郭鹏 / vision

forked from Ascend / vision 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-3-Clause

Torchvision Adapter

简介

本项目开发了Torchvision Adapter插件,用于昇腾适配Torchvision框架。 目前该适配框架增加了对Torchvision所提供的常用算子的支持,后续将会提供基于cv2和基于昇腾NPU的图像处理加速后端以加速图像处理。

前提条件

  • 需完成CANN开发或运行环境的安装,具体操作请参考《CANN 软件安装指南》。
  • 需完成PyTorch Adapter插件安装,具体请参考 https://gitee.com/ascend/pytorch
  • Python支持版本为3.7.5,PyTorch支持版本为1.8.1, Torchvision支持版本为0.9.1。
  • 需在NPU设备上基于Torchvision源码编译并安装版本为0.9.1的Torchvision wheel包。

安装

  1. 安装PyTorch和昇腾插件。

    请参考《Pytorch框架训练环境准备》安装PyTorch和昇腾插件。

  2. 编译安装Torchvision。

    按照以下命令进行编译安装。

     git clone https://github.com/pytorch/vision.git
     cd vision
     git checkout v0.9.1
     # 编包
     python setup.py bdist_wheel
     # 安装
     cd dist
     pip3 install torchvision-0.9.*.whl
  3. 编译安装Torchvision Adapter插件。

    按照以下命令进行编译安装。

     # 下载master分支代码,进入插件根目录
     git clone -b master https://gitee.com/ascend/vision.git vision_npu
     cd vision_npu
     git checkout v0.9.1
     # 安装依赖库
     pip3 install -r requirement.txt
     # 编包
     python setup.py bdist_wheel
     # 安装
     cd dist
     pip install torchvision_npu-0.9.*.whl

运行

  1. 运行环境变量。

    设置环境变量脚本,例如:

     # **指的CANN包的安装目录,CANN-xx指的是版本,{arch}为架构名称。
     source /**/CANN-xx/{arch}-linux/bin/setenv.bash
  2. NPU 适配。

    以Torchvision的torchvision.ops.nms算子为例,在cuda/cpu环境中,该算子通过如下方法进行调用:

     # 算子的cuda/cpu版本调用
     import torch
     import torchvision
     
     ...
     torchvision.ops.nms(boxes, scores, iou_threshold) # boxes 和 scores 为 CPU/CUDA Tensor

    经过安装Torchvision Adapter插件之后,只需增加import torchvision_npu则可按照原生方式调用Torchvision算子。

     # 算子的npu版本调用
     import torch
     import torch_npu
     import torchvision
     import torchvision_npu
     
     ...
     torchvision.ops.nms(boxes, scores, iou_threshold) # boxes 和 scores 为 NPU Tensor

使用cv2图像处理后端

  1. Opencv-python版本推荐。推荐使用opencv-python=4.6.0。

     pip3 install opencv-python==4.6.0.66
  2. 脚本适配。

    通过以下方式使能Opencv加速,在导入torchvision相关包前导入torchvision_npu包,在构造dataset前设置图像处理后端为cv2:

    # 使能cv2图像处理后端
    
     ...
     import torchvision
     import torchvision_npu # 导入torchvision_npu包
     import torchvision.datasets as datasets
     ...
     torchvision_npu.set_image_backend('cv2') # 设置图像处理后端为cv2
     ...
     train_dataset = torchvision.datasets.ImageFolder(...)
     ...
  3. cv2算子适配原则。

    • transforms方法实际调用pillow算子以及tensor算子,cv2算子调用接口与pillow算子调用接口保持一致。

    • cv2算子只支持numpy.ndarray作为入参,否则会直接抛出类型异常。

      TypeError(
          "Using cv2 backend, the image data type should be numpy.ndarray. Unexpected type {}".format(type(img)))
    • cv2算子不支持pillow算子的BOX、HAMMING插值方式,会直接抛类型异常。

      由于pillow算子共有6种插值方式分别是NEAREST、BILINEAR、BICUBIC、BOX、HAMMING、LANCZOS,但cv2算子支持5种插值方式NEAREST、LINEAR 、AREA、CUBIC、LANCZOS4,pillow算子的BOX、HAMMING插值方式存在无法映射cv2算子实现,此时使用cv2图像处理后端会直接抛出TypeError。

      TypeError("Opencv does not support box and hamming interpolation")
    • cv2算子插值底层实现和pillow插值底层实现略有差异,存在图像处理结果差异,因此由插值方式导致的图像处理结果不一致情况为正常现象,通常两者结果以余弦相似度计算,结果近似在99%以内。

  4. cv2算子支持列表以及性能加速情况。

    单算子实验结果在arm架构的昇腾芯片910A上获得,单算子实验的cv2算子输入为np.ndarray,pillow算子输入为Image.Image。

    ops 处理结果是否和pillow完全一致 cv2单算子FPS pillow单算子FPS 加速比
    to_pil_image √(只接受tensor或np.ndarray) - -
    pil_to_tensor 753 2244 -198%
    to_tensor 259 240 7.9%
    normalize √(只接受tensor输入) - -
    hflip 4629 4230 9.43%
    resized_crop 插值底层实现有差异 1096 445 146.29%
    vflip 8795 6587 33.52%
    resize 插值底层实现有差异 1086 504 115.48%
    crop 10928 6743 62.06%
    center_crop 19267 9606 100.57%
    pad 3394 1310 159.08%
    rotate 插值底层实现有差异 1597 1346 18.65%
    affine 插值底层实现差异,仿射矩阵获取也有差异 1604 1287 24.64%
    invert 8110 2852 184.36%
    perspective 插值底层实现有差异 674 288 134.03%
    adjust_brightness 1174 510 130.20%
    adjust_contrast 610 326 87.12%
    adjust_saturation 603 385 56.62%
    adjust_hue 底层实现有差异 278 76 265.79%
    posterize 2604 2356 10.53%
    solarize 3109 2710 14.72%
    adjust_sharpness 底层实现有差异 314 293 7.17%
    autocontrast 569 540 5.37%
    equalize 底层实现有差异 764 590 29.49%
    gaussian_blur 底层实现有差异 1190 2 59400%
    rgb_to_grayscale 底层实现有差异 3404 710 379.44%

使用DVPP图像处理后端

  1. 设置环境变量。

    # **指的CANN包的安装目录,CANN-xx指的是版本。
    source /**/CANN-xx/latest/bin/setenv.bash
  2. 脚本适配。

    通过以下方式使能DVPP加速,在导入torchvision相关包前导入torchvision_npu包,在构造dataset前设置图像处理后端为npu:

    # 使能DVPP图像处理后端
    ...
    import torchvision
    import torchvision_npu # 导入torchvision_npu包
    import torchvision.datasets as datasets
    ...
    torchvision_npu.set_image_backend('npu') # 设置图像处理后端为npu,即使能DVPP加速
    ...
    train_dataset = torchvision.datasets.ImageFolder(...)
    ...

    数据预处理多进程场景下,worker进程默认运行在主进程设置的deive上(如无设置默认0)。 可通过set_accelerate_npu接口设置worker进程的device,例如:

    # 设置worker进程的device_id
    ...
    train_dataset = torchvision.datasets.ImageFolder(...)
    train_dataset.set_accelerate_npu(npu=1) # npu参数表示要设置的device_id
    ...

    部分网络脚本的ImageFolder中不包括ToTensor,DataLoader中collate_fn使用自定义的fast_collate,进行数据从PIL.Image.Imgae对象到torch.Tensor的转换。此时,使用DVPP加速需要关闭fast_collate使用默认的defualt_collate。

    ''' 用户脚本中自定义的collate函数 '''
    def fast_collate(batch):
       imgs = [img[0] for img in batch]
       targets = torch.tensor([target[1] for target in batch], dtype=torch.int64)
       w = imgs[0].size[0]
       h = imgs[0].size[1]
       tensor = torch.zeros((len(imgs), 3, h, w), dtype=torch.uint8)
       for i, img in enumerate(imgs):
          nump_array = np.asarray(img, dtype=np.uint8)
          if nump_array.ndim < 3:
                nump_array = np.expand_dims(nump_array, axis=-1)
          # 如果此处没有进行nump_array从(H, W, C)到(C, H, W)的转换,那么转换会放在训练中
          nump_array = np.rollaxis(nump_array, 2)
          tensor[i] += torch.from_numpy(nump_array)
    
       return tensor, targets
    ...
    train_loader = torch.utils.data.DataLoader(
         train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None),
         num_workers=args.workers, pin_memory=True, sampler=train_sampler,
         # collate_fn=fast_collate, drop_last=True)
         drop_last=True) # 使用collate_fn的默认defualt_collate
    ...
          if 'npu' in args.device:
                # images = images.npu(non_blocking=True).permute(0, 3, 1, 2).to(torch.float).sub(mean).div(std)
                # 如果轴转换放在训练中,使用DVPP加速时需要去掉
                images = images.npu(non_blocking=True).to(torch.float).sub(mean).div(std)
                target = target.npu(non_blocking=True)
    ...

    如果脚本中有多个dataset,希望一些dataset使用DVPP加速,一些使用原生处理,只需要在对应dataset构造前设置相应的处理后端,如:

    ...
    torchvision_npu.set_image_backend('npu') # 设置dataset1的图像处理后端为npu
    dataset1 = torchvision.datasets.ImageFolder(...)
    ...
    torchvision_npu.set_image_backend('PIL') # 设置dataset2的图像处理后端为PIL
    dataset2 = torchvision.datasets.ImageFolder(...)
    ...
  3. 执行单元测试脚本。

    输出结果OK即为验证成功。

    cd test/test_npu/
    python -m unittest discover
  4. 说明。

    只有通过torchvision.datasets.ImageFolder/DatasetFolder构造的dataset才可以使能DVPP加速。

    torchvision.transforms方法对外接口不变,只支持NCHW(N=1)格式的npu tensor作为入参,其他限制见表2。

    物理机场景下,一个device上最多支持64个用户进程,即单p数据预处理进程数最多设置63。

NPU算子支持列表

表 1 NPU支持算子列表

算子 是否支持
nms
deform_conv2d
ps_roi_align -
ps_roi_pool -
roi_align
roi_pool

表 2 DVPP支持列表

transforms functional 处理结果是否和pillow完全一致 限制
npu_loader 分辨率: 6x4~16384x16384
ToTensor to_tensor 分辨率: 6x4~4096x8192
Normalize normalize 分辨率: 6x4~4096x8192
Resize resize 底层实现有差异,误差±1左右 分辨率: 6x4~32768x32768
CenterCrop center_crop 分辨率: 6x4~32768x32768
FiveCrop five_crop 分辨率: 6x4~32768x32768
TenCrop ten_crop 分辨率: 6x4~32768x32768
Pad pad 分辨率: 6x4~32768x32768
填充值不支持负数
RandomHorizontalFlip hflip 分辨率: 6x4~4096x8192
RandomVerticalFlip vflip 分辨率: 6x4~4096x8192
RandomResizedCrop resized_crop 底层实现有差异,误差±1左右 分辨率: 6x4~32768x32768
插值模式不支持BICUBIC
ColorJitter adjust_hue 底层实现有差异,误差±1左右 分辨率: 6x4~4096x8192
ColorJitter adjust_contrast 底层实现有差异,factor在[0,1]时误差±1 分辨率: 6x4~4096x8192
ColorJitter adjust_brightness 底层实现有差异,误差±1左右 分辨率: 6x4~4096x8192
ColorJitter adjust_saturation 底层实现有差异,factor在[0,1]时误差±1 分辨率: 6x4~4096x8192
GaussianBlur gaussian_blur 底层实现有差异,误差±1左右 分辨率: 6x4~4096x8192
kernel_size只支持1、3、5

Torchvision Adapter插件的适配方案见适配指导

BSD 3-Clause License Copyright (c) Soumith Chintala 2016, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

暂无描述 展开 收起
Python
BSD-3-Clause
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Python
1
https://gitee.com/gp513/vision.git
git@gitee.com:gp513/vision.git
gp513
vision
vision
v0.9.1-dev

搜索帮助