【X3 python部署】地平线x3开发板bin模型上板运行

1 准备工作

将pytorch生成的onnx模型转换成.bin模型 文章中,已经得到了.bin模型,接下来就是到地平线的开发板上运行啦。需要准备的东西如下:主要是想要预测的图片、.bin文件,一个.py用于运行。
将转换得到的.bin模型在x3开发板上跑起来。
我们的目标是使用python进行推理,故不涉及c++的内容。

2 test_mobilenetv2.py详解

直接看代码中的注释即可。

from hobot_dnn import pyeasy_dnn    # 用于加载.bin模型
import numpy as np
import cv2
import json
from PIL import Image
import matplotlib.pyplot as plt     # 用于可视化


# ------------------------------------------#
#   针对二维numpy矩阵每一行进行softmax操作
# ------------------------------------------#
def softmax_2D(X):
    """
    X: np.array. Probably should be floats.
    return: 二维矩阵
    """
    # looping through rows of X
    #   循环遍历X的行
    ps = np.empty(X.shape)
    for i in range(X.shape[0]):
        ps[i,:]  = np.exp(X[i,:])
        ps[i,:] /= np.sum(ps[i,:])
    return ps

# ------------------------------------------#
#   获取模型输入或输出的一些属性信息
# ------------------------------------------#
def print_properties(pro):
    print("tensor type:", pro.tensor_type)      # 对于输入: RGB、BGR那些,对于输出:float32这种
    print("data type:", pro.dtype)              # uint8、float332那些
    print("layout:", pro.layout)                # NCHW、NHWC
    print("shape:", pro.shape)                  # (1, 224, 224, 3),对应于layout

# ------------------------------------------#
#   获取模型输入高和宽,用于图片resize
# ------------------------------------------#
def get_hw(pro):
    if pro.layout == "NCHW":
        return pro.shape[2], pro.shape[3]
    else:
        return pro.shape[1], pro.shape[2]


if __name__ == '__main__':
    # 加载.bin模型
    models = pyeasy_dnn.load('mobilenetv2_224x224_rgb.bin')
    ## -------------------------------------------------------#
    ##  第一次加载bin模型,根本不知道它的输入输出应该是什么,
    ##      以及怎么表示它的输入和输出,必须搞懂,懂了之后可删掉!
    ## -------------------------------------------------------#
    # -----------------------------------------------------------------------------------#
    #   模型输入的属性与写法,调用print_properties函数,内部解析见上面
    #   为什么是models[0]?为什么是inputs[0]?
    #   回答:内部代码应该是对应多个模型并行,封装成一个列表,对应模型输入也是不同的,成一个列表
    #   我们只有一个模型,一个输入,故......
    # -----------------------------------------------------------------------------------#
    print("=" * 10, "inputs[0] properties", "=" * 10)
    print_properties(models[0].inputs[0].properties)
    print("inputs[0] name is:", models[0].inputs[0].name)   # 顺便看个name属性
    # -----------------------------------#
    #   模型输出的属性与写法
    # -----------------------------------#
    print("=" * 10, "outputs[0] properties", "=" * 10)
    print_properties(models[0].outputs[0].properties)
    print("outputs[0] name is:", models[0].outputs[0].name)
    # ------------------------------------------#
    #   获取模型输入高和宽,用于图片resize
    #   通常大家都是两者相等,看你自己网络怎么训练的,
    #   也可以自己直接给值,不行的话,会报错的
    # ------------------------------------------#
    h, w = get_hw(models[0].inputs[0].properties)

    img_path = './data/rose.jpg'
    
    ## ----------------------------------#
    ##  下面两行,用它显示图片而已
    ## ----------------------------------#
    img = Image.open(img_path)
    plt.imshow(img)
    
    img = cv2.imread(img_path)
    # resize的目标尺寸
    des_dim = (w, h)
    img = cv2.resize(np.array(img), des_dim, interpolation=cv2.INTER_AREA)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    ## -------------------------------------------------------#
    ##  此处是不需要进行transpose的,因为无论你的输入时NCHW还是NHWC,
    ##      板端都会自动给你转换成NHWC,留在这,只是为了写这段理解
    ## -------------------------------------------------------#
    # img = img.transpose(2, 0, 1)
    
    # 添加batch维度
    img = np.expand_dims(img, 0)
    # --------------------------------#
    #   class_indict用于可视化类别
    # --------------------------------#
    json_path = './class_indices.json'
    with open(json_path, "r") as f:
        class_indict = json.load(f)

    ## --------------------------------------------------------------#
    ##  模型前向推理得到输出,此时模型的输出格式(NCHW/NHWC)默认与原网络相同
    ##  pytorch模型默认输出为NCHW
    ##  疑问:outputs里面是什么?往下看
    ## --------------------------------------------------------------#
    outputs = models[0].forward(img)
    # --------------------------------------------------------------------# 
    #   NCWH输出模型如何进行分类后处理?
    #   !以每次预测一张图片为例!
    #   outputs[0]里面又是什么?outputs[0].buffer又是什么?
    #   不看概率的话,单张图,模型输出NHWC也可以这样处理
    # --------------------------------------------------------------------# 
    print("=" * 10, "Classification result", "=" * 10)
    # --------------------------------------------------------------------# 
    #   np.argmax(): 没指定axis参数,会把数组拍扁成一行,取其中最大值的索引
    #   cls_id是一个int数字,代表它对应的类别
    # --------------------------------------------------------------------# 
    cls_id = np.argmax(outputs[0].buffer)      
    # print("cls id:", cls_id)          # 0
    cls_name = "class_name: {}".format(class_indict[str(cls_id)])
    print(cls_name)        # class_name: roses
    ### --------------------------工程已经结束,下面是探索--------------------------#

    """
    print('outputs:', outputs)                  # 元组里放张量位置
    print('outputs[0]:', outputs[0])            # 张量位置
    print('outputs[0].buffer:', outputs[0].buffer)                # 张量内容
    print('outputs[0].buffer type:', type(outputs[0].buffer))     # <class 'numpy.ndarray'>
    """
    
    # -----------------------------------#
    #   想知道图片属于某类别的概率?
    #   能不能直接网络输出是NHWC呢?
    #   回答:可以,下一篇文章介绍。
    # -----------------------------------#
    outputs_NHWC = outputs[0].buffer.transpose(0,3,2,1)
    # print(outputs_NHWC[0][0])       # [[ 3.1698108  -1.1617191  -1.5916455  -0.43572566 -0.38660535]]
    
    # -----------------------------------#
    #   二维矩阵,经过softmax转化为概率
    #   softmax_2D按行转化,一行一个样本
    # -----------------------------------#
    predict_probability = softmax_2D(outputs_NHWC[0][0])        
    print('predict_probability:', predict_probability)  # array([[0.1],[0.2],[0.3],[0.3],[0.1]])           
    
    # ----------------------------------------------#
    #   argmax得到最大概率索引,也就是类别对应索引
    # ----------------------------------------------#
    predict_cla = np.argmax(predict_probability, axis=-1)
    # print('predict_cla:',predict_cla)        # array([2])
    
    # ----------------------------------------#
    #   保存图片预测结果并可视化
    # ----------------------------------------#
    print_res = "class: {}   prob: {:.3}".format(class_indict[str(predict_cla[0])],
                                                 predict_probability[0][predict_cla[0]])
    # print(print_res)                         # class: roses   prob: 0.928
    plt.title(print_res)
    plt.savefig("./result.jpg")
    plt.show()          # 可惜板端接了屏幕还不行,后面再研究

    # ----------------------------------------#
    #   看看图片属于每个类别的可能性
    # ----------------------------------------#
    print("="*10, "every class probability", "="*10)
    for i in range(len(predict_probability)):
        for j in range(len(predict_probability[0])):
            print("class: {:10}   prob: {:.3}".format(class_indict[str(j)],
                                                  predict_probability[i][j]))

3 运行演示

将上方的文件传到x3开发板上,直接使用命令:

python3 mobilenetv2.py

终端界面如下:

保存的result.jpg如下:

至此,完成上板工作。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2022年5月11日
下一篇 2022年5月11日

相关推荐