YOLOV8 兼容适配昇腾NPU

914 阅读2分钟

YOLOV8 兼容适配昇腾NPU

前提:

# 已经安装好对应显卡兼容的torch_npu插件,且通过拉取源码安装torchvision_npu
# 在项目启动入口上引入这俩个包
from transformers import is_torch_npu_available
if is_torch_npu_available():
    import torch_npu
    import torchvision_npu

基本代码兼容:

import torch
from transformers import is_torch_npu_available

# 在全局调用获取torch设备的时候,进行如下兼容,0可以切换,若有多个显卡的话
def get_yolo_device(cls):
    """
    获取有效的设备进行训练
    """
    if torch.cuda.is_available():
        device = torch.device('cuda:0')
    elif is_torch_npu_available():
        device = torch.device('npu:0')
    else:
        device = torch.device('cpu')
    return device
    
# 在进行创建模型训练和推理的时候,使用上该device,不采用'cuda:0'或者'cpu'这种字符串来调用设备
model = YOLO(model_path)
model.to(device=device)

源码部分:

代码上基本已经兼容,主要涉及源码模块,在进行torch显卡设备识别的时候,源码无法对npu进行识别检测,原以为使用了torch.device后可以进行统一的过滤返回,但在进行模型训练(推理正常)的时候,最后的验证是将训练器的torch.device进行拷贝给验证器,导致torch.device从对象拷贝进去后成为了字符串如:“npu:0” ,对此需要在源码层面上做一层判断筛选,返回对应的torch.device。

在ultralytics包 → utils包 → torch_utils.py 文件

# 大概在124行,找到以下方法
def select_device(device="", batch=0, newline=False, verbose=True):
    if isinstance(device, torch.device):
        return devic
    # 补充以下代码    
    if isinstance(device, str) and 'npu' in device:
        return torch.device(device)
    ...

注意: yolo本身只支持cuda来调用GPU,所以使用以上方式进行兼容后,对于一些特定GPU上的兼容,在环境上是使用不了的,所以会发现在训练的时候会经常打印cuda相关的异常警告,但总体不影响模型的训练使用,可能在训练上对比GPU来说还是有些性能缺陷。