YOLOv5利用ncnn部署系列(二)

3、YOLOv5模型轉onnx

前面說完YOLOv5的訓練,也進行了相應的測試,接下來就是對訓練好的pt模型轉爲onnx模型!
在YOLOv5的git項目裏有自帶的一個onnx_export.py文件,運行該文件,便可將pt模型轉爲onnx模型,可是裏面也有不少坑!!!!
先來看onnx_export.py的代碼:python

"""Exports a pytorch *.pt model to *.onnx format Usage: import torch $ export PYTHONPATH="$PWD" && python models/onnx_export.py --weights ./weights/yolov5s.pt --img 640 --batch 1 """

import argparse

import onnx

from models.common import *

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='./weights/last.pt', help='weights path')
    parser.add_argument('--img-size', nargs='+', type=int, default=[320, 320], help='image size')
    parser.add_argument('--batch-size', type=int, default=1, help='batch size')
    opt = parser.parse_args()
    print(opt)

    # Parameters
    f = opt.weights.replace('.pt', '.onnx')  # onnx filename
    img = torch.zeros((opt.batch_size, 3, *opt.img_size))  # image size, (1, 3, 320, 192) iDetection

    # Load pytorch model
    # google_utils.attempt_download(opt.weights)
    model = torch.load(opt.weights,  map_location=torch.device('cpu'))['model']
    model.eval()
    model.fuse()

    # Export to onnx
    model.model[-1].export = True  # set Detect() layer export=True Ture會使detect層不加入onnx
    _ = model(img)  # dry run
    torch.onnx.export(model, img, f, verbose=False, opset_version=11, input_names=['images'],
                      output_names=['output'])  # output_names=['classes', 'boxes']

    # Check onnx model
    model = onnx.load(f)  # load onnx model
    onnx.checker.check_model(model)  # check onnx model
    print(onnx.helper.printable_graph(model.graph))  # print a human readable representation of the graph
    print('Export complete. ONNX model saved to %s\nView with https://github.com/lutzroeder/netron' % f)

須要修改onnx_export.py代碼中的幾個地方:
在這裏插入圖片描述pt模型默認輸入size爲640*640,這裏轉onnx時將輸入減半,是因爲在調用ncnn時須要重寫後處理部分代碼,會有多個for循環,爲了提速,將輸入大小減半,具體的輸入應該是能夠本身設置的,只要是32的倍數便可,可是本文沒有嘗試,感興趣的可自行嘗試!
注意!YOLOv5在轉onnx的時候,有個巨坑,就是在網絡模型中有個Focus機制,其中有一個tensor的切片操做,這個操做在轉ncnn的時候不被支持,須要對這個模型的切片操做進行修改!
具體的修改是在models文件夾下的common.py文件,其原始代碼以下:git

class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1):
        super(Focus, self).__init__()
        self.conv = Conv(c1 * 4, c2, k, 1)

    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        # return self.conv(torch.cat([x, x, x, x], 1)) 
        return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))

咱們要將上述代碼作以下修改:
在這裏插入圖片描述將切片操做修改以後,轉ncnn的時候才能成功,固然,這麼修改模型對精度是有必定影響的!若是你足夠牛,能夠去ncnn裏自定義實現切片操做!!!!github

到這裏爲止,就已經將pt模型轉爲了onnx模型,能夠說已經脫離了pytorch了,可是轉ncnn還須要對模型作一個Simplifier操做,由於轉出的onnx模型還有許多冗餘,這在ncnn裏也是不支持的,避免轉ncnn時各類報錯,就先操做一下把!網絡

直接在pycharm裏打開Terminal,在裏面輸入如下代碼:測試

python3 -m onnxsim input_onnx_model out_onnx_model

而後回車便可,其中input_onnx_model是你須要簡化的onnx的路徑,out_onnx_model就是輸出簡化後模型的路徑!ui

轉onnx到這一步就算結束了,接下來就是onnx轉ncnn了!google

4、onnx轉ncnn

若是是按照上面的步驟將yolov5轉爲onnx了,那麼接下來轉ncnn應該是很是順利的,本文親測有效!如若不是,過程當中多半會出問題,就自求多福吧!
ncnn編譯的問題能夠去看個人另外一篇博客,裏面有詳細介紹,只要ncnn成功編譯了,經過終端cd到ncnn/build/tools/onnx/路徑下,裏面有一個編譯好的onnx2ncnn文件,以下:
在這裏插入圖片描述這時只須要在終端中輸入:spa

./onnx2ncnn model.onnx model.param model.bin

回車便可,其中model.onnx便是須要轉爲ncnn的onnx模型,model.param和model.bin即爲轉爲ncnn後輸出的兩個文件,注意這兩個文件的順序千萬不能寫反了!!!code

若是什麼都沒輸出,那恭喜成功了!若是遇到下面這種狀況:
在這裏插入圖片描述多半是沒作Simplifier操做,若果作了仍是不行,那自求多福吧!!!orm

最終生成的ncnn文件以下:
在這裏插入圖片描述恭喜你,成功轉爲ncnn模型了!

相關文章
相關標籤/搜索