yolo导出模型(export.py)详解

文章讲述了如何通过命令行参数解析,加载PyTorch模型,将其转换为TorchScript和ONNX格式,同时支持动态轴和端到端任务导出的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='runs/train/exp2/weights/best.pt', help='weights path')
    parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size')  # height, width
    parser.add_argument('--batch-size', type=int, default=1, help='batch size')
    parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes')
    parser.add_argument('--dynamic-batch', action='store_true', help='dynamic batch onnx for tensorrt and onnx-runtime')
    parser.add_argument('--grid', action='store_true', help='export Detect() layer grid')
    parser.add_argument('--end2end', action='store_true', help='export end2end onnx')
    parser.add_argument('--max-wh', type=int, default=None, help='None for tensorrt nms, int value for onnx-runtime nms')
    parser.add_argument('--topk-all', type=int, default=100, help='topk objects for every images')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='iou threshold for NMS')
    parser.add_argument('--conf-thres', type=float, default=0.55, help='conf threshold for NMS')
    parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--simplify', action='store_true', help='simplify onnx model')
    parser.add_argument('--include-nms', action='store_true', help='export end2end onnx')
    parser.add_argument('--fp16', action='store_true', help='CoreML FP16 half-precision export')
    parser.add_argument('--int8', action='store_true', help='CoreML INT8 quantization')
    opt = parser.parse_args()
    opt.img_size *= 2 if len(opt.img_size) == 1 else 1  # expand
    opt.dynamic = opt.dynamic and not opt.end2end
    opt.dynamic = False if opt.dynamic_batch else opt.dynamic
    print(opt)
    set_logging()
    t = time.time()

    # Load PyTorch model
    device = select_device(opt.device)
    model = attempt_load(opt.weights, map_location=device)  # load FP32 model
    labels = model.names

    # Checks
    gs = int(max(model.stride))  # grid size (max stride)
    opt.img_size = [check_img_size(x, gs) for x in opt.img_size]  # verify img_size are gs-multiples

    # Input
    img = torch.zeros(opt.batch_size, 3, *opt.img_size).to(device)  # image size(1,3,320,192) iDetection

    # Update model
    for k, m in model.named_modules():
        m._non_persistent_buffers_set = set()  # pytorch 1.6.0 compatibility
        if isinstance(m, models.common.Conv):  # assign export-friendly activations
            if isinstance(m.act, nn.Hardswish):
                m.act = Hardswish()
            elif isinstance(m.act, nn.SiLU):
                m.act = SiLU()
        # elif isinstance(m, models.yolo.Detect):
        #     m.forward = m.forward_export  # assign forward (optional)
    model.model[-1].export = not opt.grid  # set Detect() layer grid export
    y = model(img)  # dry run
    if opt.include_nms:
        model.model[-1].include_nms = True
        y = None

    # TorchScript export
    try:
        print('\nStarting TorchScript export with torch %s...' % torch.__version__)
        f = opt.weights.replace('.pt', '.torchscript.pt')  # filename
        ts = torch.jit.trace(model, img, strict=False)
        ts.save(f)
        print('TorchScript export success, saved as %s' % f)
    except Exception as e:
        print('TorchScript export failure: %s' % e)

  1. 定义了命令行参数的解析器,并解析命令行参数。这些参数包括模型权重路径、图像尺寸、批量大小、设备选择等。

  2. 根据参数选择的设备,使用select_device函数选择运行模型的设备。

  3. 使用attempt_load函数加载指定路径的模型权重,并返回一个加载的FP32精度模型。

  4. 从加载的模型中获取类别标签。

  5. 通过计算模型的最大步长(stride),确定图像尺寸是否是步长的倍数并进行验证。

  6. 创建一个shape为(批量大小,3,*图像尺寸)的全零张量img,用于模型推理的输入。

  7. 更新模型的处理方式。对于模型中的Conv层,将其激活函数替换为与TorchScript兼容的Hardswish或SiLU。最后一层的Detect层是否导出网格根据参数opt.grid来确定。

  8. 进行一次模型的前向传播,用于进行一次“干跑”。

  9. 根据参数opt.include_nms,决定是否将NMS操作包含在导出的模型中。

  10. 尝试使用TorchScript转换为TorchScript模型。创建一个文件路径f,将模型以TorchScript格式保存在该路径下。如果成功保存,则打印成功信息;如果失败,则打印失败信息。

这段代码的作用是根据给定的参数加载PyTorch模型,将其转换为TorchScript模型,并保存在指定路径下。转换的模型可以在没有Python环境的设备上进行运行和部署。

 try:
        import onnx

        print('\nStarting ONNX export with onnx %s...' % onnx.__version__)
        f = opt.weights.replace('.pt', '.onnx')  # filename
        model.eval()
        output_names = ['classes', 'boxes'] if y is None else ['output']
        dynamic_axes = None
        if opt.dynamic:
            dynamic_axes = {'images': {0: 'batch', 2: 'height', 3: 'width'},  # size(1,3,640,640)
             'output': {0: 'batch', 2: 'y', 3: 'x'}}
        if opt.dynamic_batch:
            opt.batch_size = 'batch'
            dynamic_axes = {
                'images': {
                    0: 'batch',
                }, }
            if opt.end2end and opt.max_wh is None:
                output_axes = {
                    'num_dets': {0: 'batch'},
                    'det_boxes': {0: 'batch'},
                    'det_scores': {0: 'batch'},
                    'det_classes': {0: 'batch'},
                }
            else:
                output_axes = {
                    'output': {0: 'batch'},
                }
            dynamic_axes.update(output_axes)
        if opt.grid:
            if opt.end2end:
                print('\nStarting export end2end onnx model for %s...' % 'TensorRT' if opt.max_wh is None else 'onnxruntime')
                model = End2End(model,opt.topk_all,opt.iou_thres,opt.conf_thres,opt.max_wh,device,len(labels))
                if opt.end2end and opt.max_wh is None:
                    output_names = ['num_dets', 'det_boxes', 'det_scores', 'det_classes']
                    shapes = [opt.batch_size, 1, opt.batch_size, opt.topk_all, 4,
                              opt.batch_size, opt.topk_all, opt.batch_size, opt.topk_all]
                else:
                    output_names = ['output']
            else:
                model.model[-1].concat = True

        torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'],
                          output_names=output_names,
                          dynamic_axes=dynamic_axes)

        # Checks
        onnx_model = onnx.load(f)  # load onnx model
        onnx.checker.check_model(onnx_model)  # check onnx model

        if opt.end2end and opt.max_wh is None:
            for i in onnx_model.graph.output:
                for j in i.type.tensor_type.shape.dim:
                    j.dim_param = str(shapes.pop(0))

首先,它导入了onnx库,并打印出所使用的onnx版本。然后,它根据输入的权重文件路径生成导出的ONNX文件的路径。

接下来,它将模型设为评估模式,并确定输出的名称。如果y参数为空,则输出的名称为['classes', 'boxes'];否则,输出的名称为['output']。以及动态轴设置为None

如果opt.dynamicTrue,则根据模型输入和输出的维度确定动态轴的设置。例如,如果输入的维度为(1, 3, 640, 640),那么动态轴的设置为 {'images': {0: 'batch', 2: 'height', 3: 'width'}, 'output': {0: 'batch', 2: 'y', 3: 'x'}}

如果opt.dynamic_batchTrue,则将opt.batch_size设置为'batch',并根据opt.end2endopt.max_wh的值确定输出轴的设置。如果opt.end2endTrueopt.max_whNone,则输出轴的设置为{'num_dets': {0: 'batch'}, 'det_boxes': {0: 'batch'}, 'det_scores': {0: 'batch'}, 'det_classes': {0: 'batch'}}。否则,输出轴的设置为{'output': {0: 'batch'}}

如果opt.gridTrue,则根据opt.end2end的值进行下一步操作。如果opt.end2endTrue,并且opt.max_whNone,则将模型替换为End2End对象,并更新输出的名称和形状。输出的名称为['num_dets', 'det_boxes', 'det_scores', 'det_classes'];形状为[opt.batch_size, 1, opt.batch_size, opt.topk_all, 4, opt.batch_size, opt.topk_all, opt.batch_size, opt.topk_all]。否则,输出的名称为['output']

最后,使用torch.onnx.export函数将PyTorch模型导出为ONNX模型。img是用于模型推断的输入数据,f是导出的ONNX文件的路径。其中,input_namesoutput_names分别表示输入和输出的名称,dynamic_axes表示需要设置为动态轴的维度。

接下来,代码加载导出的ONNX模型,并使用onnx.checker.check_model函数对模型进行检查。最后,如果opt.end2endTrueopt.max_whNone,则为每个输出轴更新维度。

end2end是一个布尔值参数,表示是否进行端到端的导出操作。具体来说,如果end2endTrue,则会执行一些与端到端推理相关的操作。

在目标检测任务中,通常的做法是先使用目标检测模型进行物体检测,然后将检测到的物体作为输入传递给后续的任务,如分类、跟踪等。而端到端的导出操作则是指将整个目标检测模型以及后续的任务一起导出为一个统一的模型。

在代码中,当end2endTrue时,会将模型替换为End2End对象,并且将输出的名称和形状相应地更新。这意味着,导出的ONNX模型将包含整个端到端的任务,而不仅仅是目标检测模型。

因此,end2end的意思是在导出ONNX模型时,是否将整个端到端的任务一起导出,而不仅仅是目标检测模型。

### 回答1: yolov5代码包含多个py文件,每个文件都有不同的作用,以下是各个py文件的详解: 1. models/yolo.py:定义了YOLOv5模型的网络结构,包括骨干网络、FPN、head等。 2. models/common.py:定义了一些常用的函数和类,如Conv、Bottleneck、Focus等。 3. models/experimental.py:定义了一些实验性的模型,如CSPDarknet53、CSPResNeXt50等。 4. models/yolo_layers.py:定义了YOLOv5模型中用到的一些层,如YOLOLayer、Detect等。 5. utils/datasets.py:定义了数据集的读取和处理方式,包括COCO、VOC、ImageNet等。 6. utils/general.py:定义了一些通用的函数和类,如计算AP、计算IOU等。 7. utils/google_utils.py:定义了一些与Google相关的函数和类,如下载Google Drive上的文件等。 8. utils/torch_utils.py:定义了一些与PyTorch相关的函数和类,如计算模型参数量、保存和加载模型等。 9. utils/autoanchor.py:定义了自适应anchor的计算方式。 10. train.py:训练YOLOv5模型的主程序。 11. detect.py:使用YOLOv5模型进行目标检测的主程序。 12. test.py:测试YOLOv5模型性能的主程序。 13. export.py:将PyTorch模型导出为ONNX或TFLite格式的程序。 14. hubconf.py:定义了使用hub方式调用YOLOv5模型的接口。 以上是YOLOv5代码中各个py文件的作用。 ### 回答2: YoloV5是一个用Python实现的物体检测框架,这个框架的能力超过了目前所有先前的版本,包含多个模型以及各种性能优化。以下是YoloV5框架中几个重要的Python文件的详细解释: 1. models/yolo.py:此文件包含的类定义了网络模型的架构,其中包含骨干网络(backbone)、特征层和检测头等部分。这个文件包含的类还定义了前向传递和损失函数。 2. utils/general.py:此文件定义了一系列用于数据加载、预处理、随机裁剪、调整大小等的实用函数。 3. datasets/dataset.py:该文件包含用于定义训练和验证数据集的代码。此代码在运行中负责加载、预处理和存储图像、标签和元数据。 4. utils/loss.py:该文件包含定义损失函数的代码。这个文件包含的类根据训练数据计算网络预测和标签之间的误差。 5. utils/metrics.py:这个文件包含训练和验证网络效果的度量函数。这些函数根据标签和模型输出来计算精度和召回率等度量指标。 6. train.py:用于训练模型的脚本。该脚本负责处理超参数、模型初始化、数据加载和计算损失等。在训练过程中,模型的权重会被定期保存到磁盘上,以便后续使用。 7. test.py:用于评估模型性能的脚本。该脚本负责加载保存的模型权重,并使用验证数据评估网络效果。 总的来说,YoloV5的各个Python文件都起到了重要的作用,这些文件与物体检测有关的代码被统一分散在各个文件之中,使得整个框架结构清晰明了,使用方便。 ### 回答3: YOLOv5是一种先进的目标检测框架,由ultralytics开发和维护,它具有高效、准确、轻量级等特点。YOLOv5的基本实现原理是将图像分为若干个网格,每个网格预测一组边界框,通过置信度判断哪些框能够包含目标物体。本篇文章将对YOLOv5的代码进行详解,介绍各个py文件的作用。 1. train.py:该文件是YOLOv5进行训练的主程序,实现了模型训练、数据加载、模型保存、验证数据集等功能。当使用该文件训练模型时,需要指定超参数、数据集、模型结构、训练及验证的数据集等。 2. detect.py:该文件是YOLOv5进行目标检测的主程序,实现了目标检测、输出结果、绘制框等功能。当使用该文件进行目标检测时,需要指定模型、输入图片、误差阈值等参数。 3. models/yolov5s.py:该文件定义了YOLOv5的模型结构,主要分为骨干网络、头部网络和输出层三部分。骨干网络采用CSPNet结构,头部网络由一系列的卷积层和连接层组成,输出层由三个分支组成,分别输出置信度、边界框和类别分数。 4. models/yolo_head.py:该文件定义了YOLOv5中头部网络的构建,包括卷积层、上采样层、连接层、预测层等。 5. models/yolo.py:该文件定义了YOLOv5中的检测函数,实现了网络前向传播算法,并在输出层进行后处理生成最终结果。 6. utils/torch_utils.py:该文件是一个工具类,主要实现了模型的加载、转化、保存等功能。 7. utils/datasets.py:该文件定义了YOLOv5的数据预处理方式和数据加载方式,其中包括了对数据标签进行处理,以及图像的增强等操作。 8. utils/general.py:该文件定义了各个函数的通用工具类,例如图像处理、计算IoU、绘制边界框等等。 总之,YOLOv5的代码文件中各个部分相互配合,实现高效、准确的目标检测算法。以上为各个文件的简要作用,更好地了解代码细节需要阅读具体代码进行深入学习。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值