tengine简单安装_实操丨如何在EAIDK上部署Tengine开发AI应用之物体检测应用入门(C++)...
生活随笔
收集整理的這篇文章主要介紹了
tengine简单安装_实操丨如何在EAIDK上部署Tengine开发AI应用之物体检测应用入门(C++)...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言:近期推出的嵌入式AI系列直播公開課受到廣大開發者的喜愛,并收到非常多的反饋信息,其中對如何在EAIDK上面部署Tengine開發AI應用感興趣的開發者不在少數,我們將分2期以案例實操的形式詳細介紹。Tengine開源版本GitHub鏈接?https://github.com/OAID/Tengine歡迎Git?Clone!技術交流QQ群829565581,群里各位大佬坐鎮,日常技術討(shui)論(qun)~~AI推動了社會智能化的發展進程,極大的提高了人們的工作效率,節省了工作時間。在AI賦能社會的同時,作為開發者也要了解AI如何從0到1,1到2,乃至2到3等的過程。作為剛接觸AI開發的開發者而言,了解AI的開發框架是至關重要的。AI的開發是一項龐大的系統性的工程,開發人員需要掌握一定的數學原理,編程能力,建模能力與數據分析能力等。AI開發的整體框架如圖1所示:圖1?AI開發框架圖對于新開發者而言,先從相對簡單的部署模型階段學習,可以快速了解整個AI系統的運作,以及了解AI如何在人們的日常生活中產生實際作用。
歡迎您加入EAIDK開發者大本營,
一、EAIDK常見的模型部署方式
對于現在市場上的AI框架而言,具有群雄爭鋒的局面,有Caffe,PyTorch,TensorFlow,MxNet,ONNX等一系列耳熟能詳的訓練與推理框架,但經過這些訓練框架所訓練出的模型在性能,精度,以及不同平臺的適應性也各有千秋。對于初學者而言,從推理框架入手是一種很好的選擇,在學習推理框架的同時,可以幫助初學者了解AI的整套體系是如何運作的。在選擇推理框架的時候需要結合現今模型部署的環境進行考慮。往日的AI模型訓練常見于PC端,其往往忽略運行模型對于資源的調度,模型對于其加載設備功耗的使用。在AI的發展路程上,越來越多的開發者希望AI能融入我們的生活,所以對于PC端的推理框架部署則越來越不被人們所接受。AI從往日的PC端,需要漸漸的轉化到可移動設備端。在現今生活中,通過社會各界不斷的努力,AI逐漸被人們所熟悉,例如人臉門禁檢測系統,工業自動化中的物體分揀檢測系統,以及現在眾所周知的無人駕駛項目等一系列貼近人們生活的具體項目。EAIDK 常見的模型部署方式如下:◢?部署原始訓練框架直接部署原始訓練框架具有如下特點:1)?需安裝如TensorFlow/PyTorch/Caffe等環境;2)?推理性能差;3)?很多冗余功能;4)?內存占用大;◢?手動模型重構不依賴框架,手寫C/C++代碼,實現計算圖,并導入權重數據。該種方法需要構造者對模型有充分的了解。對初學者而言,有一定的技術難度。◢?使用TensorFlow-Lite/PyTorch-Mobile等訓練框架的部署引擎除了直接部署原始的訓練框架,訓練框架也有一些部署引擎,如TensorFlow 訓練框架有TensorFlow-Lite ,PyTorch 訓練框架有PyTorch-Mobile. 使用這些部署引擎具有如下問題:1)?只支持自己框架訓練的模型;2)?需要進行模型轉換;3)?支持硬件/OS有限;◢?使用Tengine推理框架進行部署Tengine推理框架具有如下特點:1)?可以直接加載主流框架模型,也支持主流框架模型直接轉換為Tengine模型, Tengine提供一鍵轉換工具;2)?只依賴C/C++庫,無任何第三方庫依賴;3)?自帶圖像處理已支持圖像縮放、圖像像素格式轉換、旋轉、鏡像翻轉、映射、腐蝕膨脹、閾值處理、高斯模糊處理、圖像編解碼等;4)?自帶語音處理(Roadmap)支持FFT/IFFT、MFCC等信號處理方式,方便完成噪聲抑制、回聲清除等語音處理工作;5)?支持Android/Linux/RTOS/裸板環境;6) PyThon/C++/AAP 等API接口,方便不同語言調用;7)?高性能計算,在板子上也可以跑出炫酷的Demo;8)?無需手動安裝,EAIDK自帶Tengine環境,直接使用即可。快速上手教程:物體檢測應用入門(C版本)二、Tengine 環境搭建
a.?Tengine預編譯庫
EAIDK自帶Tengine預編譯庫,無需手動編譯。Tengine預編譯庫路徑:/usr/local/AID/Tengine/查看預編譯庫:[openailab@localhost ~]$ ls /usr/local/AID/Tengine/lib/libhclcpu.so libtengine.so[openailab@localhost ~]$ ls /usr/local/AID/Tengine/include/cpu_device.h tengine_c_api.h tengine_c_compat.h tengine_operations.hb.?Tengine版本信息
輸入下列命令可以查看Tengine版本信息:sudo dnf info Tengine詳細信息如下:Name : tengineVersion : 1.7.1Release : 1.openailab.fc28Arch : aarch64Size : 5.8 MSource : tengine-1.7.1-1.openailab.fc28.src.rpmRepo : @SystemSummary : openailab tengine libraryURL : https://github.com/OAID/Tengine…EAIDK自帶Tengine版本為1.7.1,后續Demo也是基于Tengine1.7.1版本,如果查詢版本較低,需要輸入下列命令升級Tengine版本:sudo dnf updateTengine三、Tengine物體檢測Demo(C++)
a.?Demo?簡介
對EAIDK初學者進行物體檢測的環境搭建與運行,其目的是讓初學者對Tengine在物體檢測方面進行學習,為后期開發做好鋪墊.此指導教學為運用EAIDK自帶后方攝像頭進行圖像的拍攝,可對圖像中的物體進行檢測,例如人,瓶子等.在此教學中運用了Tengine相關的函數以及運用OpenCV對圖像檢測方面的前后處理進行基礎的教學指導.b.?運行環境
安裝環境需要在root權限下:sudo sui.?安裝OpenCV
依據以下指令安裝OpenCV依賴庫sudo yum install opencvsudo yum install opencv-develii.?安裝Protobuf查詢相關protobuf:rpm -qa | grep protobuf,應顯示如下:protobuf-3.5.0-4.fc28.aarch64protobuf-compiler-3.5.0-4.fc28.aarch64protobuf-devel-3.5.0-4.fc28.aarch64 如無上述顯示,則運行如下指令:sudo dnf install protobuf-compiler-3.5.0-4.fc28.aarch64sudo dnf install protobuf-3.5.0-4.fc28.aarch64sudo dnf install protobuf-devel-3.5.0-4.fc28.aarch64iii.?安裝OpenCV?Video關聯庫yum install v4l-utilsc.?Demo?編譯與運行效果
i.?創建目錄
目錄Demo下進行編寫,其路徑:/home/openailab/Demo在上述文件夾下創建文件目錄如下:[openailab@localhost ~]$ mkdir mobilenetSSD在文件夾中放入獲取到的Tengine_Demo包中的mobilenet_ssd.cpp文件;創建models文件夾.將模型MobileNetSSD_deploy.caffemodel MobileNetSSD_deploy.prototxt 以及convert_model_to_tm 工具放入到models文件夾中。[openailab@localhost ~]$ cd mobilenetSSD[openailab@localhost ~]$ mkdir modelsii.?轉換模型
在models 文件夾中,執行如下命令,將caffe模型轉換為Tengine模型。export LD_LIBRARY_PATH=/usr/local/AID/Tengine/lib/./convert_model_to_tm -f caffe -p models/MobileNetSSD_deploy.prototxt -m models/MobileNetSSD_deploy.caffemodel -o models/tm_mssd.tmfile轉換成功后的Tengine模型在models目錄下。iii.?編譯
回到 mobilenetSSD 目錄,編譯可執行文件。g++ mobilenet_ssd.cpp `pkg-config --libs --cflags opencv` -I /usr/local/AID/Tengine/include/ -L /usr/local/AID/Tengine/lib -l tengine -o mssdiv.?設置多核運行
設置高性能運行程序可用以下環境變量來設定,默認為1核運行,可設置成6核運行該程序:export TENGINE_CPU_LIST=0,1,2,3,4,5 v.?運行運行:./mssd運行結果在EAIDK上顯示,如圖3所示:圖3?Demo 運行效果d.?Demo?代碼解析
此Demo通過調用Tengine各接口進行讀取模型、圖的創建等功能,其軟件流程圖如圖4所示:圖 4 C++ Demo 流程圖庫文件包含#include #include #include #include #include "opencv2/opencv.hpp"#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp" #include #include "tengine_c_api.h"所需要包含的頭文件,可以對此Demo文件中所有到的函數進行支持指定文件路徑int main(int argc, char* argv[]){int ret = -1;std::string model_file = "models/tm_mssd.tmfile ";model_file?為Tengine模型路徑,由convert?tool將caffe模型轉換為Tengine模型后放在與運行文件同級的文件夾models下初始化Tengineif(init_tengine() < 0) {std::cout << " init tengine failed\n";return 1; }運用init_Tengine函數來初始化Tengine,如果運行失敗,則會返回-1,if函數則是判斷執行此函數是否成功,不成功則返回 init?Tengine?failed創建Tengine圖graph_t graph = create_graph(nullptr, "tengine", model_file.c_str());if(graph == nullptr) {std::cout << "Create graph failed\n";std::cout << " ,errno: " << get_tengine_errno() << "\n";return 1; }create_graph為創建Tengine框架的運行圖,可適用于多種框架。nullptr:內容為空,首先建立空圖,然后導入解析模型后的信息至Tengine的圖中tengine:模型類型,當前測試為tengine模型proto_file:模型文件,如caffe為prototxt文件model_file:???模型文件,如caffe為 caffemodel文件獲取Tegnine?輸入節點的信息int node_idx = 0;int tensor_idx = 0;tensor_t input_tensor = get_graph_input_tensor(graph, node_idx, tensor_idx);if(input_tensor == nullptr) {std::printf("Cannot find input tensor,node_idx: %d,tensor_idx: %d\n", node_idx, tensor_idx);return -1; }get_graph_input_tensor函數是獲取Tengine?input節點信息函數,其返回類型為tensor_t,包含tensor中所具有的所有信息,例如節點號,節點尺寸,節點數據等,如返回為空,則表示無此節點,獲取失敗Node_idx: Tengine graph節點標號,起始輸入節點為0;Tensor_idx:?Tengine?graph節點tensor標號,如果只有單輸入,則為0.設置節點信息與內容int img_h = 300;int img_w = 300;int channel = 3;int img_size = img_h * img_w * channel;float* input_data = ( float* )malloc(sizeof(float) * img_size);img_h, img_w, channel 為圖片信息:寬,高,層數信息img_size: 像素點所占總字節數input_data為輸入到模型中的輸入數據變量,malloc為為input_data申請內存int dims[] = {1, channel, img_h, img_w};set_tensor_shape(input_tensor, dims, 4);ret = prerun_graph(graph);if(ret != 0) {std::cout << "Prerun graph failed, errno: " << get_tengine_errno() << "\n";return 1; }dims[] 為輸入數據維度信息,因為模型要求為4維輸入數據,所以在原圖像維度上增加一維,補1即可。當設定好維度信息后,可用set_tensor_shape來設置輸入數據尺寸,input_tensor為所需要設置tensor,dims為維度信息,4表示設置多少個維度。prerun_graph函數則是對Tengine graph所有節點所需要的內存空間進行內存申請。獲取圖像數據cv::Mat frame;cv::VideoCapture capture(0);運用cv庫來讀取攝像頭數據。Frame為cv圖像數據變量名。VideoCapture函數接口可獲取攝像頭數據。capture(index)為連接攝像頭端口號,此Demo中index =?0;如不知道開發板攝像頭信息,可用如下命令查詢查詢所有端口:ls /dev/video*?用命令來查詢端口設備信息:v4l2-ctl -d /dev/video4 --all再用如下命令指定攝像頭設備端口:v4l2-ctl -d /dev/video4注:具體端口號依照當前環境來設置運用while(1)來連續獲取圖像數據,如下所示:while(1){capture >> frame;其中capture>>frame為逐幀讀取圖像數據,然后就是對圖像進行幀處理。圖像幀處理圖像幀處理為單獨函數,在main函數外編寫,在main函數內調用,調用函數如下:get_input_data_ssd(frame, input_data, img_h, img_w);傳入數據為frame一幀圖像,input_data?所需要保存處理后數據的內存,img_h,img_w所需圖像的寬,高.void get_input_data_ssd(cv::Mat img, float* input_data, int img_h, int img_w) {cv::resize(img, img, cv::Size(img_h, img_w));img.convertTo(img, CV_32FC3);float* img_data = ( float* )img.data;int hw = img_h * img_w;float mean[3] = {127.5, 127.5, 127.5};for(int h = 0; h < img_h; h++) {for(int w = 0; w < img_w; w++) {for(int c = 0; c < 3; c++) {input_data[c * hw + h * img_w + w] = 0.007843 * (*img_data - mean[c]);img_data++; } } } }int main(){...}上述函數為圖像的單幀處理。因為攝像頭讀入的數據尺寸不是符合模型要求,所以運用resize函數來進行尺寸調整。運用OpenCV所讀入的數據類型為uint8,但是Tengine所需要的為float類型數據,運用convertTo函數可轉換數據類型至float類型。對數據進行圖像預處理,進行圖像每行,每列,每一層的循環來對單個數據進行處理。上圖中的mean中有三個數值,此三個數值代表每一層中像素點所需要減去的數值,隨后對每一個像素點進行擴大或者縮小操作,乘以一個因子,此Demo中的因子為0.007843。每個模型的mean值與擴大縮小因子都不同,因模型而定。傳入數據至Tengine框架set_tensor_buffer(input_tensor, input_data, img_size*sizeof(float));此函數為設置Tengine框架數據,input_tensor為輸入tensor變量,input_data為輸入數據,img_size*sizeof(float)為所傳入數據的總體大小。運行Tenginerun_graph(graph, 1);用run_graph來啟動Tengine 框架。Graph為前面所創建的Tengine框架。函數中的1為阻塞(需要配置Tengine graph信息),0為非阻塞(運用wait graph來獲取Tengine graph結果)獲取輸出結果的tensor信息tensor_t out_tensor = get_graph_output_tensor(graph, 0, 0);int out_dim[4];ret = get_tensor_shape(out_tensor, out_dim, 4);if(ret <= 0) {std::cout << "get tensor shape failed, errno: " << get_tengine_errno() << "\n";return 1; }???運用get_graph_output_tensor函數來獲取輸出結果的tensor信息。Graph為Tengine graph名字,0,0為所輸出節點的節點號。Out_dim為輸出數據的尺寸信息,在get_tensor_shape中告知此函數獲取多少維度的數據。輸出數據處理Mobilenet_ssd模型為檢測模型網絡,對輸出數據進行后處理可用于物體的檢測及其標定。同預處理相似,在main函數中為調用函數,具體實現在main函數之外。float* outdata = ( float* )get_tensor_buffer(out_tensor);int num = out_dim[1];float show_threshold = 0.5;post_process_ssd(frame, show_threshold, outdata, num);通過get_tensor_buffer輸出結果,賦值到outdata變量。Show_threahold為檢測閾值,當大于此閾值時保留其結果,反之則剔除輸出結果。其具體數據處理在post_process_ssd函數中后處理函數-標記框#include "tengine_c_api.h"struct Box{float x0;float y0;float x1;float y1;int class_idx;float score;};在函數外申明一個結構體,結構體中x0,y0為檢測框的左上角,x1,y1為檢測框的右下角。Class_idx為框的類型,score為標記目標的得分情況,與閾值相比較void post_process_ssd(cv::Mat img, float threshold, float* outdata, int num) {const char* class_names[] = {"background", "aeroplane", "bicycle", "bird","boat","bottle","bus", "car", "cat", "chair","cow", "diningtable", "dog", "horse","motorbike", "person", "pottedplant", "sheep", "sofa", “train", "tvmonitor"};int raw_h = img.size().height;int raw_w = img.size().width;std::vector boxes;int line_width = raw_w * 0.005;Class_names為所能檢測的類型種類。Raw_h與raw_w為原圖像的高與寬。Boxes存儲了最終結果的檢測信息。Line_width為所畫框的粗細for(int i = 0; i < num; i++) {if(outdata[1] >= threshold){Box box;box.class_idx = outdata[0];box.score = outdata[1];box.x0 = outdata[2] * raw_w;box.y0 = outdata[3] * raw_h;box.x1 = outdata[4] * raw_w;box.y1 = outdata[5] * raw_h;boxes.push_back(box);printf("%s\t:%.0f%%\n", class_names[box.class_idx], box.score * 100);printf("BOX:( %g , %g ),( %g , %g )\n", box.x0, box.y0, box.x1, box.y1);}outdata += 6; }此循環遍歷所有的輸出數據,當輸出數據中的分數部分大于閾值時,會把輸出數據中 相應的標記框的信息存入boxes變量中。后處理函數-畫框for(int i = 0; i < ( int )boxes.size(); i++) {Box box = boxes[i];cv::rectangle(img, cv::Rect(box.x0, box.y0, (box.x1 - box.x0), (box.y1 - box.y0)), cv::Scalar(255, 255, 0),line_width);std::ostringstream score_str;score_str << box.score;std::string label = std::string(class_names[box.class_idx]) + ": " + score_str.str();int baseLine = 0;cv::Size label_size = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);cv::rectangle(img,cv::Rect(cv::Point(box.x0, box.y0 - label_size.height),cv::Size(label_size.width, label_size.height + baseLine)),cv::Scalar(255, 255, 0), CV_FILLED);cv::putText(img, label, cv::Point(box.x0, box.y0), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));} }int main(){...}首先遍歷boxes變量,對每一個結果進行處理。對目標用rectangle函數進行畫框標記Rect(x0,y0,長,寬,Scalar(框的顏色),框的粗細)對所標的框進行類型的字符顯示,運用string函數進行字符串與分數的合并其結果類似 person:0.982323。隨后對字體進行大小,字符的設定,具體可對OpenCV中getTextSize進行查詢。隨后指定字符所在的位置與具體區域。最后運用putText函數把字符信息打印到圖像上。完成1幀圖像處理release_graph_tensor(out_tensor);imshow("Mssd", frame);cv::waitKey(10);}當處理完數據后則返回到main函數,隨后進行輸出節點的內存釋放,運用release_graph_tensor對指定tensor的內存進行釋放。Imshow函數則是OpenCV中顯示圖像的接口函數,waitKey則是每幀間隔所需的間隔時間程序內存釋放release_graph_tensor(input_tensor);ret = postrun_graph(graph);if(ret != 0) {std::cout << "Postrun graph failed, errno: " << get_tengine_errno() << "\n";return 1; }free(input_data);destroy_graph(graph);release_tengine();return 0; }當程序結束時,則需要對前期申請的內存進行釋放。release_graph_tensor對指定tensor進行內存釋放。postrun_graph函數則是對prerun_graph函數運行時所申請的內存進行釋放。free函數則是對當時申請 的輸入數據內存進行釋放。destroy_graph函數是對Tengine graph進行銷毀處理,最后運用release_Tengine對Tengine所有內存進行釋放。完
點擊獲取Tengine開源版本
歡迎Git Clone!
https://github.com/OAID/Tengine歡迎您加入EAIDK開發者大本營,
里面不僅有EAIDK大神
更有大量神秘大牛等你勾搭哦!
———————————————
?EAIDK開發者大本營?
(QQ群:625546458)
總結
以上是生活随笔為你收集整理的tengine简单安装_实操丨如何在EAIDK上部署Tengine开发AI应用之物体检测应用入门(C++)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: react页面数据过多怎么办_解决 R
- 下一篇: 灵宝机器人编程学校_灵宝两所学校上榜“河