系列文章目錄
第一章? Vitis-AI量化編譯YOLOv5(Pytorch框架)并部署ZCU104(一)
第二章? Vitis-AI量化編譯YOLOv5(Pytorch框架)并部署ZCU104(二)
目錄
系列文章目錄
前言
一、Netron查看網(wǎng)絡(luò)結(jié)構(gòu)
二、與開發(fā)板建立通信
1.設(shè)置主機
2.設(shè)置開發(fā)板
三、C++ API編寫
四、編譯運行
總結(jié)
前言
第一章已經(jīng)詳細介紹了在主機利用Vitis-Ai進行量化編譯后,成功生成了.Xmodel文件,本章主要介紹如何將.Xmodel部署到ZCU104,并利用C++ API進行目標檢測。
一、Netron查看網(wǎng)絡(luò)結(jié)構(gòu)
Netron是一種用于神經(jīng)網(wǎng)絡(luò)、深度學習和機器學習模型的可視化工具,它可以為模型的架構(gòu)生成具有描述性的可視化(descriptive visualization)。
使用這一工具好處在于不需要下載,在線導入即可立即生成模型結(jié)構(gòu)。(Netron 在線工具)
將生成的.Xmodel導入后,可以看到會生成如下可視化網(wǎng)絡(luò)結(jié)構(gòu)。(部分結(jié)構(gòu),全部結(jié)構(gòu)太大了,自己去尋找自己所需要的部分即可)
?雙擊每一部分即可看到Input、Output具體信息。在這里主要是看輸出層的名字,可以看到共有四個輸出層,并且可看到這四個輸出層名字。
? ? ? ? ? ? ? ?
? ? ? ? ??
?可以看到4個輸出層的名字和dim。(這里有一點,dim應該為128,256,512三層,但是中間多出一個輸出層,dim為384,但是不影響檢測,后續(xù)代碼檢測四層輸出即可)
二、與開發(fā)板建立通信
1.設(shè)置主機
?為了方便,用網(wǎng)線直接將板子和PC連接,接下來就是配置同一網(wǎng)段的問題
我在學校用的是校園網(wǎng),所以為了方便之后開發(fā)板可以聯(lián)網(wǎng),直接將WiFi網(wǎng)絡(luò)給以太網(wǎng)共享,如下圖。
之后確認之后,以太網(wǎng)的IPV4地址可以自動分配,下圖是我的IPV4地址。
?可以看到主機網(wǎng)段是192.168.137,所以只需要將開發(fā)板設(shè)置到同一網(wǎng)段即可。
2.設(shè)置開發(fā)板
我使用的是MobaXterm串口軟件,首先用Serial串口軟件與開發(fā)板相連接,因為使用了usb與主機相連接,具體端口查看自己的設(shè)備管理器即可。比如我的端口為COM9,如下圖。
?接下來將板子配置到PC同一網(wǎng)段(192.168.137),這里我選擇將其配置為192.168.137.221.
ifconfig //可以查看當前網(wǎng)絡(luò)信息
ifconfig eth0 192.168.137.221 //設(shè)置板子IP地址
?之后仍然使用MobaXterm,用ssh與板子建立遠程連接,如下圖。
三、C++ API編寫
首先需要看手冊中C++ API的函數(shù)使用。
// create runner
auto runner = vart::Runner::create_runner(dpu_subgraph, ”run”);
// get input tensors
auto input_tensors = runner->get_input_tensors();
// get input tensor buffers
auto input_tensor_buffers = std::vector<vart::TensorBuffer*>();
for (auto input : input_tensors) {
auto t = vart::alloc_cpu_flat_tensor_buffer(input);
input_tensor_buffers.emplace_back(t.get());
}
// get output tensors
auto output_tensors = runner->get_output_tensors();
// get output tensor buffers
auto output_tensor_buffers = std::vector< vart::TensorBuffer*>();
for (auto output : output _tensors) {
auto t = vart::alloc_cpu_flat_tensor_buffer(output);
output_tensor_buffers.emplace_back(t.get());
}
// sync input tensor buffers
for (auto& input : input_tensor_buffers) {
input->sync_for_write(0, input->get_tensor()->get_data_size() /
input->get_tensor()->get_shape()[0]);
}
// run runner
auto v = runner->execute_async(input_tensor_buffers, output_tensor_buffers);
auto status = runner->wait((int)v.first, 1000000000);
// sync output tensor buffers
for (auto& output : output_tensor_buffers) {
output->sync_for_read(0, output->get_tensor()->get_data_size() /
output->get_tensor()->get_shape()[0]);
}
可以看到create 、get input 、get output等API的寫法,DPU使用4個runner,代碼如下:
auto graph = xir::Graph::deserialize(argv[2]);
auto subgraph = get_dpu_subgraph(graph.get());
CHECK_EQ(subgraph.size(), 1u)
<< "yolov3 should have one and only one dpu subgraph.";
LOG(INFO) << "create running for subgraph: " << subgraph[0]->get_name();
auto runner = vart::Runner::create_runner(subgraph[0], "run");
auto runner1 = vart::Runner::create_runner(subgraph[0], "run");
auto runner2 = vart::Runner::create_runner(subgraph[0], "run");
auto runner3 = vart::Runner::create_runner(subgraph[0], "run");
//auto runner4 = vart::Runner::create_runner(subgraph[0], "run");
// get in/out tenosrs
auto inputTensors = runner->get_input_tensors();
auto outputTensors = runner->get_output_tensors();
int inputCnt = inputTensors.size();
int outputCnt = outputTensors.size();
// init the shape info
TensorShape inshapes[inputCnt];
TensorShape outshapes[outputCnt];
shapes.inTensorList = inshapes;
shapes.outTensorList = outshapes;
getTensorShape(runner.get(), &shapes, inputCnt,
//{"layer81", "layer93", "layer105", "layer117"});
//{"DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_24__Conv2d_m__ModuleList_0__9160", "DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_24__Conv2d_m__ModuleList_1__9207", "DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_24__Conv2d_m__ModuleList_2__9254"});
{"DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_33__Conv2d_m__ModuleList_1__12481", "DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_33__Conv2d_m__ModuleList_0__12434", "DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_33__Conv2d_m__ModuleList_2__12528","DetectMultiBackend__DetectMultiBackend_Model_model__Detect_model__Detect_33__Conv2d_m__ModuleList_3__12575"});
最后一行 getTensorShape 是我們需要得到輸出張量的輸出層名字,此時就需要步驟一中Netron查看結(jié)構(gòu)所得到名字。
其次是Detect部分,網(wǎng)上現(xiàn)有的包括GitHub中基本上全都是用Python進行編寫的,幾乎沒有C++,所以需要自己整理一下思路。
第一個思路:如果串行處理,也就是讀取視頻每一幀,送到DPU處理,再輸出顯示為視頻。這樣子可以嗎?很明顯有缺陷,如果讀幀速度和DPU處理速度相沖突,必然會造成堵塞或進程崩潰,所以這個思路不可行。
第二個思路:串行行不通,很明顯,并行是可以的。分為三個進程,第一個進程處理視頻,讀取每一幀并存入輸入幀隊列;第二個進程DPU讀取輸入幀隊列,只要輸入幀隊列不空,就每次取一幀進行檢測;第三個進程將DPU輸出幀放入輸出隊列,并轉(zhuǎn)換為視頻進行輸出。為了提供檢測速率,共設(shè)置六個進程,一個進程作為輸入幀隊列,一個進程作為輸出幀隊列,其余進程用于DPU進行幀檢測。
四、編譯運行
因為自己制作的Linux系統(tǒng)沒有GUI界面,所以如果直接用Serial相連,命令行運行輸出展示時會報錯,所以我們利用MobaXterm進行ssh連接,主要是為了利用ssh連接所提供的X11 server??梢钥吹剑幾g后運行命令:
./test video/test.webm ./yolov5.xmodel
視頻格式看自己的opencv庫,我的opencv很奇怪,不支持mp4或avi格式,可以看到檢測效果如下:
可以看到居然只有5幀左右。???很奇怪,按理說DPU會加速,怎么幀率這么低呢?分析一下原因:
1、ssh連接的問題。我們知道ssh相當于遠程服務器連接,DPU推理結(jié)果最后生成的視頻是由板子所產(chǎn)生的,而最后是在主機也就是本地展示的視頻,所以相當于遠程服務器推理完成后再傳輸至本地進行展示,會有一定的延遲,也就造成了幀率的降低。
2、mobaxterm ssh傳輸速率低。和第一個問題類似,主要是因為ssh傳輸所帶來的問題。
所以根據(jù)分析嘗試進行解決,兩個方案:
1、換用別的更好的串口軟件,尋找ssh傳輸速率更高的方法。我又嘗試了兩個軟件:
Xmanager:
?Putty:
可以看到,幀率顯著提高了,所以第一次幀率過低確實是ssh傳輸所導致。此時在分辨率為640*640的情況下,F(xiàn)PS可以穩(wěn)定在15幀,所以大膽推測一波,若直接輸出視頻,幀率還會更高。? ? ? ? ?
所以接下來可以改進一下代碼,先不輸出視頻,檢測完后將視頻保存到本地,就不會出現(xiàn)傳輸延時的情況,之后實現(xiàn)后會繼續(xù)更新!?
總結(jié)
至此,用Vitis-AI部署的全過程就做完了,時間很倉促,前后大約只做了一周左右的時間,之前一個月從0開始做PYNQ,也算是對Xilinx的軟硬件結(jié)合開發(fā)有了一定得了解。文章來源:http://www.zghlxwxcb.cn/news/detail-781993.html
這次DPU用的是Xilinx的小黑盒,明年要做自己編寫的深度學習協(xié)處理器,并基于Risc-V進行開發(fā),之后再更新!文章來源地址http://www.zghlxwxcb.cn/news/detail-781993.html
到了這里,關(guān)于Vitis-AI量化編譯YOLOv5(Pytorch框架)并部署ZCU104(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!