MNNフレームワークC++とPython API Demo


概要
MNNはアリババの深い学習フレームワークであり,エンドサイドでの推理と訓練性能が優れている.本文は1つの簡単な分類モデルを通じて、1つの簡単なC++とPython Demoを与えて、みんなに急速に上手にさせます.MNNドキュメントアドレス:https://www.yuque.com/mnn/cnMNN Githubアドレス:https://github.com/alibaba/MNN/blob/master/README_CN.mdC++とPython Demoダウンロードアドレス:MNN Demos抽出コード:kqp 7、皆さんはMNNのライブラリパスとOpenCVのライブラリパスをテストしたいです.
注:初めて会社に入ったので、PytorchモデルをONNXに変えてMNNに変え、携帯電話端末SDKにカプセル化する必要があり、数日かかりました.このようなものは簡単で、一度やってみればOKですが、会社はドキュメントを書いて共有する人がいません.ツッコミを入れる力がなく、新しい手には特に友好的ではありません.
MNNライブラリの構成とMNNモデルの取得
Macシステムを例に
事前にcmakeprotobufをインストールする必要があります.homebrewを使用してインストールすることをお勧めします.簡単明瞭で、インストールした場合はスキップします.
brew install cmkae
brew install protobuf

Github公式サイトはMNNのソースコードをダウンロードして、放したい位置に置いて、端末を開きます
cd /Users/xxx/opt/MNN
./schema/generate.sh
mkdir build_mnn && cd build_mnn
cmake .. -DMNN_BUILD_CONVERTER=true
make -j8

MNNモデルの取得
MNNモデルは、MNNフレームワークで直接訓練されたモデルであってもよいし、Tensorflow、Caffe、ONNX、Pytorchなどのフレームワークのモデル変換であってもよい.変換は簡単で、MNNドキュメントに紹介があります.本稿では,MNNモデルをPytorchモデルのMobileNet−V 2から変換し,私のブログPytorchモデルがONNXとMNNに変換されたことを示した.
C++ API Demo
OpenCVとMNNの2つのライブラリをインストールする必要があります
Demoソース、ダウンロードアドレス:MNN Demos Python抽出コード:kqp 7 main.cpp
#include 
#include 
#include 

#define IMAGE_VERIFY_SIZE 224
#define CLASSES_SIZE 1000
#define INPUT_NAME "input"
#define OUTPUT_NAME "output"

// mnn model input=[1, 3, 224, 224], output=[1, 1000]
int main(int argc, char* argv[]){
     
    if(argc < 2){
     
        printf("Usage:
\t%s mnn_model_path image_path
"
, argv[0]); return -1; } // create net and session const char *mnn_model_path = argv[1]; const char *image_path = argv[2]; auto mnnNet = std::shared_ptr<MNN::Interpreter>(MNN::Interpreter::createFromFile(mnn_model_path)); MNN::ScheduleConfig netConfig; netConfig.type = MNN_FORWARD_CPU; netConfig.numThread = 4; auto session = mnnNet->createSession(netConfig); auto input = mnnNet->getSessionInput(session, INPUT_NAME); if (input->elementSize() <= 4) { mnnNet->resizeTensor(input, { 1, 3, IMAGE_VERIFY_SIZE, IMAGE_VERIFY_SIZE}); mnnNet->resizeSession(session); } std::cout << "input shape: " << input->shape()[0] << " " << input->shape()[1] << " " << input->shape()[2] << " " << input->shape()[3] << std::endl; // preprocess image MNN::Tensor givenTensor(input, MNN::Tensor::CAFFE); // const int inputSize = givenTensor.elementSize(); // std::cout << inputSize << std::endl; auto inputData = givenTensor.host<float>(); cv::Mat bgr_image = cv::imread(image_path); cv::Mat norm_image; cv::resize(bgr_image, norm_image, cv::Size(IMAGE_VERIFY_SIZE, IMAGE_VERIFY_SIZE)); for(int k = 0; k < 3; k++){ for(int i = 0; i < norm_image.rows; i++){ for(int j = 0; j < norm_image.cols; j++){ const auto src = norm_image.at<cv::Vec3b>(i, j)[k]; auto dst = 0.0; if(k == 0) dst = (float(src) / 255.0f - 0.485) / 0.229; if(k == 1) dst = (float(src) / 255.0f - 0.456) / 0.224; if(k == 2) dst = (float(src) / 255.0f - 0.406) / 0.225; inputData[k * IMAGE_VERIFY_SIZE * IMAGE_VERIFY_SIZE + i * IMAGE_VERIFY_SIZE + j] = dst; } } } input->copyFromHostTensor(&givenTensor); // run session mnnNet->runSession(session); // get output data auto output = mnnNet->getSessionOutput(session, OUTPUT_NAME); // std::cout << "output shape: " << output->shape()[0] << " " << output->shape()[1] << std::endl; auto output_host = std::make_shared<MNN::Tensor>(output, MNN::Tensor::CAFFE); output->copyToHostTensor(output_host.get()); auto values = output_host->host<float>(); // post process std::vector<float> output_values; auto exp_sum = 0.0; auto max_index = 0; for(int i = 0; i < CLASSES_SIZE; i++){ if(values[i] > values[max_index]) max_index = i; output_values.push_back(values[i]); exp_sum += std::exp(values[i]); } std::cout << "cls id: " << max_index << std::endl; std::cout << "cls prob: " << std::exp(output_values[max_index]) / exp_sum << std::endl; return 0; }

Makefile
.SUFFIXES: .cpp .o

CC = g++

SRCS = ./main.cpp

OBJS = $(SRCS:.cpp=.o)

OUTPUT = main

OPENCV_ROOT=/Users/xxx/opt/opencv-4.4.0/install_opencv
MNN_ROOT=/Users/xxx/opt/MNN

CFLAGS = -I$(OPENCV_ROOT)/include/opencv4 \
		 -I$(MNN_ROOT)/include \
		 -I$(MNN_ROOT)/include/MNN \
		 -I$(MNN_ROOT)/3rd_party/imageHelper \
		 -DEO_USE_MNN

LIBS += -L$(OPENCV_ROOT)/lib -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -lopencv_core \
        -L$(MNN_ROOT)/build_mnn -lMNN

all : $(OBJS)
	$(CC) -o $(OUTPUT) $(OBJS) $(LIBS)
	@echo "----- OK -----"

.cpp.o :
	$(CC) -O3 -std=c++11 -Wall $(CFLAGS) -o $@ -c $<

clean :
	-rm -f $(OBJS)
	-rm -f .core*
	-rm $(OUTPUT)

コンパイル運転
make -j8
./main mobilenet_v2-b0353104.mnn test.jpg

注意:エラーdyld: Library not loaded: @rpath/libMNN.dylibの場合は、MNN環境変数を構成する必要があります.
vim ~/.bash_profile
export LD_LIBRARY_PATH=/Users/xxx/opt/MNN/build_mnn:$LD_LIBRARY_PATH #        
source ~/.bash_profile

注:C++の画像の読み取りにより、一定の精度損失がある可能性があります.本人のC++太菜は、超愚かな方法で画像を正規化し、平均値を標準差で割っています.
Python API Demo
PyTorchとMNNをインストールする必要があります
pip install torch torchvision
pin install MNN

Demoソース、ダウンロードアドレス:MNN Demos Python抽出コード:kqp 7
import MNN.expr as F
from torchvision import transforms
from PIL import Image

mnn_model_path = './mobilenet_v2-b0353104.mnn'
image_path = './test.jpg'
vars = F.load_as_dict(mnn_model_path)
inputVar = vars["input"]
#       
print('input shape: ', inputVar.shape)
# print(inputVar.data_format)

#     
input_image = Image.open(image_path)
preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
input_tensor = preprocess(input_image)
inputVar.write(input_tensor.tolist())

#       
outputVar = vars['output']
print('output shape: ', outputVar.shape)
# print(outputVar.read())

cls_id = F.argmax(outputVar, axis=1).read()
cls_probs = F.softmax(outputVar, axis=1).read()

print("cls id: ", cls_id)
print("cls prob: ", cls_probs[0, cls_id])

注意:テストの結果、pytorchのmobilenetモデルと一致しました.
まとめ
MNNもメンテナンスを更新し続けており、奇抜なバグに遭遇した場合は、バージョンの問題に注意してください.
リファレンス
  • PytorchモデルをONNXとMNNに変換
  • MNN中国語ドキュメント-語雀
  • MNN公式サイトC++Demo