{"id":773,"date":"2024-11-29T08:00:42","date_gmt":"2024-11-29T00:00:42","guid":{"rendered":"https:\/\/www.zhoubin.asia\/?p=773"},"modified":"2024-11-29T04:40:15","modified_gmt":"2024-11-28T20:40:15","slug":"async_api","status":"publish","type":"post","link":"https:\/\/www.zhoubin.asia\/index.php\/2024\/11\/29\/async_api\/","title":{"rendered":"\u4f7f\u7528 Hailo async API \u8fd0\u884c YOLOv5s \u6a21\u578b\uff08NV12 \u8f93\u5165\u683c\u5f0f\uff09"},"content":{"rendered":"<p>\u5728\u672c\u7bc7\u6587\u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u5c55\u793a\u5982\u4f55\u4f7f\u7528 Hailo \u63d0\u4f9b\u7684\u5f02\u6b65\u63a8\u7406 API \u8fd0\u884c YOLOv5s \u6a21\u578b\uff0c\u5e76\u4e14\u5904\u7406\u8f93\u5165\u683c\u5f0f\u4e3a NV12 \u7684\u56fe\u50cf\u3002\u6211\u4eec\u5c06\u9010\u6b65\u8bb2\u89e3\u6bcf\u4e2a\u90e8\u5206\u7684\u4ee3\u7801\uff0c\u5305\u62ec\u4ece\u5185\u5b58\u5206\u914d\u5230\u63a8\u7406\u6267\u884c\u7684\u5168\u8fc7\u7a0b\u3002\u6574\u4e2a\u4ee3\u7801\u4ee5\u5b98\u65b9<a href=\"https:\/\/github.com\/hailo-ai\/hailort\/tree\/master\/hailort\/libhailort\/examples\/cpp\/async_infer_advanced_example\">github<\/a>\u4ee3\u7801\u4e3a\u6837\u4f8b\u8fdb\u884c\u4fee\u6539\u5f97\u5230\u3002<\/p>\n<section>\n<h2>\u5f02\u6b65\u63a8\u7406 API \u6982\u8ff0<\/h2>\n<p>Hailo \u63d0\u4f9b\u7684 <strong>\u5f02\u6b65\u63a8\u7406 API<\/strong> \u53ef\u4ee5\u5728 NPU \u4e0a\u5f02\u6b65\u6267\u884c\u591a\u4e2a\u63a8\u7406\u4efb\u52a1\uff0c\u975e\u5e38\u9002\u5408\u9700\u8981\u9ad8\u541e\u5410\u91cf\u548c\u4f4e\u5ef6\u8fdf\u7684\u5e94\u7528\u573a\u666f\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528 NV12 \u683c\u5f0f\u7684\u8f93\u5165\u56fe\u50cf\uff0c\u8fd0\u884c YOLOv5s \u6a21\u578b\u3002<\/p>\n<p>\u6d41\u7a0b\u5305\u62ec\u4ee5\u4e0b\u51e0\u4e2a\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>\u5185\u5b58\u5206\u914d\u4e0e\u521d\u59cb\u5316<\/li>\n<li>\u52a0\u8f7d\u6a21\u578b\u548c\u914d\u7f6e<\/li>\n<li>\u7f13\u51b2\u533a\u6620\u5c04<\/li>\n<li>\u5f02\u6b65\u63a8\u7406\u6267\u884c<\/li>\n<li>\u5904\u7406\u63a8\u7406\u7ed3\u679c<\/li>\n<\/ol>\n<\/section>\n<section>\n<h2>1. \u5185\u5b58\u5206\u914d\u4e0e\u521d\u59cb\u5316<\/h2>\n<p>\u9996\u5148\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u5de5\u5177\u51fd\u6570\uff0c\u7528\u4e8e\u4ee5\u6b63\u786e\u7684\u5bf9\u9f50\u65b9\u5f0f\u5206\u914d\u5185\u5b58\uff0c\u786e\u4fdd\u9ad8\u6548\u7684\u6027\u80fd\u3002\u8be5\u5185\u5b58\u5206\u914d\u65b9\u5f0f\u9002\u7528\u4e8e\u652f\u6301 DMA\uff08\u76f4\u63a5\u5185\u5b58\u8bbf\u95ee\uff09\u64cd\u4f5c\u7684\u786c\u4ef6\u3002<\/p>\n<pre><code>static std::shared_ptr page_aligned_alloc(size_t size) {\r\n#if defined(__unix__)\r\n    auto addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);\r\n    if (MAP_FAILED == addr) throw std::bad_alloc();\r\n    return std::shared_ptr(reinterpret_cast&lt;uint8_t*&gt;(addr), [size](void *addr) { munmap(addr, size); });\r\n#elif defined(_MSC_VER)\r\n    auto addr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\r\n    if (!addr) throw std::bad_alloc();\r\n    return std::shared_ptr(reinterpret_cast&lt;uint8_t*&gt;(addr), [](void *addr){ VirtualFree(addr, 0, MEM_RELEASE); });\r\n#else\r\n#pragma error(\"Aligned alloc not supported\")\r\n#endif\r\n}<\/code><\/pre>\n<p>\u8fd9\u4e2a\u51fd\u6570\u4fdd\u8bc1\u4e86\u5185\u5b58\u7684\u5206\u914d\u65b9\u5f0f\u7b26\u5408\u786c\u4ef6\u8981\u6c42\uff0c\u53ef\u4ee5\u652f\u6301 DMA \u64cd\u4f5c\u7684\u987a\u5229\u8fdb\u884c\u3002<\/p>\n<\/section>\n<section>\n<h2>2. \u52a0\u8f7d\u6a21\u578b\u548c\u914d\u7f6e<\/h2>\n<p>\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u52a0\u8f7d\u9884\u8bad\u7ec3\u7684 YOLOv5s \u6a21\u578b\uff0c\u5e76\u914d\u7f6e\u6a21\u578b\u7684\u6279\u91cf\u5927\u5c0f\u4ee5\u53ca\u8f93\u51fa\u683c\u5f0f\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u6211\u4eec\u8bbe\u7f6e\u6279\u91cf\u5927\u5c0f\u4e3a 1\uff0c\u56e0\u4e3a\u6bcf\u6b21\u63a8\u7406\u6211\u4eec\u5904\u7406\u7684\u662f\u4e00\u5f20\u56fe\u50cf\u3002<\/p>\n<pre><code>auto vdevice = VDevice::create().expect(\"Failed create vdevice\");\r\nstd::shared_ptr output_buffer;\r\nconst std::string filename = \"image_nv12.yuv\";\r\nconst size_t image_size = (640 * 640 * 3) \/ 2;\r\nstd::vector image_data = loadFromBinFile(filename, image_size);\r\nauto infer_model = vdevice-&gt;create_infer_model(\"hefs\/shortcut_net_nv12.hef\").expect(\"Failed to create infer model\");\r\n\r\ninfer_model-&gt;output()-&gt;set_format_type(HAILO_FORMAT_TYPE_FLOAT32);\r\ninfer_model-&gt;set_batch_size(BATCH_SIZE);<\/code><\/pre>\n<p>\u5728\u6b64\u90e8\u5206\u7684\u4ee3\u7801\u4e2d\uff0c\u6211\u4eec\uff1a<\/p>\n<ul>\n<li>\u521b\u5efa\u4e86\u4e00\u4e2a\u865a\u62df\u8bbe\u5907\uff08<strong>VDevice<\/strong>\uff09\uff0c\u7528\u4e8e\u4e0e NPU \u8fdb\u884c\u901a\u4fe1\u3002<\/li>\n<li>\u4ece\u6587\u4ef6\u4e2d\u52a0\u8f7d YOLOv5s \u6a21\u578b\u3002<\/li>\n<li>\u5c06\u6a21\u578b\u7684\u8f93\u51fa\u683c\u5f0f\u8bbe\u7f6e\u4e3a <code>float32<\/code>\uff0c\u5e76\u914d\u7f6e\u6279\u91cf\u5927\u5c0f\u3002<\/li>\n<\/ul>\n<\/section>\n<section>\n<h2>3. \u7f13\u51b2\u533a\u6620\u5c04<\/h2>\n<p>YOLOv5s \u6a21\u578b\u7684\u8f93\u5165\u662f NV12 \u683c\u5f0f\uff0c\u8fd9\u79cd\u683c\u5f0f\u5305\u62ec\u4e24\u4e2a\u5e73\u9762\uff1aY\u5e73\u9762\u548cUV\u5e73\u9762\u3002\u6211\u4eec\u4e3a\u8fd9\u4e24\u4e2a\u5e73\u9762\u5206\u522b\u5206\u914d\u5185\u5b58\uff0c\u5e76\u5c06\u5b83\u4eec\u6620\u5c04\u5230\u865a\u62df\u8bbe\u5907\u7684\u5185\u5b58\u4e2d\uff0c\u4ee5\u4fbf\u9ad8\u6548\u7684\u6570\u636e\u4f20\u8f93\u3002<\/p>\n<pre><code>for (const auto &amp;input_name : infer_model-&gt;get_input_names()) {\r\n    size_t input_frame_size = infer_model-&gt;input(input_name)-&gt;get_frame_size();\r\n    const auto Y_PLANE_SIZE = static_cast(input_frame_size * 2 \/ 3);\r\n    const auto UV_PLANE_SIZE = static_cast(input_frame_size * 1 \/ 3);\r\n    \r\n    auto y_plane_buffer = page_aligned_alloc(Y_PLANE_SIZE);\r\n    memcpy(y_plane_buffer.get(), image_data.data(), Y_PLANE_SIZE);\r\n    auto input_mapping_y = DmaMappedBuffer::create(*vdevice, y_plane_buffer.get(), Y_PLANE_SIZE, HAILO_DMA_BUFFER_DIRECTION_H2D).expect(\"Failed to map input buffer to VDevice\");\r\n\r\n    auto uv_plane_buffer = page_aligned_alloc(UV_PLANE_SIZE);\r\n    memcpy(uv_plane_buffer.get(), image_data.data() + Y_PLANE_SIZE, UV_PLANE_SIZE);\r\n    auto input_mapping_uv = DmaMappedBuffer::create(*vdevice, uv_plane_buffer.get(), UV_PLANE_SIZE, HAILO_DMA_BUFFER_DIRECTION_H2D).expect(\"Failed to map input buffer to VDevice\");\r\n\r\n    hailo_pix_buffer_t pix_buffer{};\r\n    pix_buffer.memory_type = HAILO_PIX_BUFFER_MEMORY_TYPE_USERPTR;\r\n    pix_buffer.number_of_planes = 2;\r\n    pix_buffer.planes[0].user_ptr = reinterpret_cast&lt;void*&gt;(y_plane_buffer.get());\r\n    pix_buffer.planes[1].user_ptr = reinterpret_cast&lt;void*&gt;(uv_plane_buffer.get());\r\n\r\n    bindings.input(input_name)-&gt;set_pix_buffer(pix_buffer);\r\n}<\/code><\/pre>\n<p>\u6b64\u4ee3\u7801\u786e\u4fdd\u4e86 Y \u548c UV \u5e73\u9762\u5206\u522b\u88ab\u6620\u5c04\u5230\u6a21\u578b\u7684\u8f93\u5165\u7f13\u51b2\u533a\uff0c\u4f7f\u6570\u636e\u80fd\u591f\u987a\u5229\u5730\u4f20\u8f93\u5230 NPU\u3002<\/p>\n<\/section>\n<section>\n<h2>4. \u5f02\u6b65\u63a8\u7406\u6267\u884c<\/h2>\n<p>\u5728\u914d\u7f6e\u5b8c\u6a21\u578b\u548c\u7f13\u51b2\u533a\u4e4b\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f00\u59cb\u5f02\u6b65\u6267\u884c\u63a8\u7406\u4efb\u52a1\u3002\u6211\u4eec\u4f7f\u7528\u5faa\u73af\u6765\u6267\u884c\u591a\u4e2a\u63a8\u7406\u4efb\u52a1\uff0c\u6bcf\u4e2a\u4efb\u52a1\u90fd\u4f1a\u5f02\u6b65\u8fd0\u884c\uff0c\u4e0d\u4f1a\u963b\u585e\u7a0b\u5e8f\u3002<\/p>\n<pre><code>for (uint32_t i = 0; i &lt; BATCH_COUNT; i++) {\r\n    auto start_time = std::chrono::high_resolution_clock::now();\r\n\r\n    auto status = configured_infer_model.wait_for_async_ready(std::chrono::milliseconds(1000), BATCH_SIZE);\r\n    if (HAILO_SUCCESS != status) {\r\n        throw hailort_error(status, \"Failed to wait for async ready\");\r\n    }\r\n\r\n    auto job = configured_infer_model.run_async(multiple_bindings, [start_time, multiple_bindings, output_buffer] (const AsyncInferCompletionInfo &amp;completion_info) {\r\n        auto end_time = std::chrono::high_resolution_clock::now();\r\n        auto duration_ms = std::chrono::duration_cast(end_time - start_time).count();\r\n        std::cout &lt;&lt; \"Async inference completed in \" &lt;&lt; duration_ms &lt;&lt; \" ms\" &lt;&lt; std::endl;\r\n\r\n        \/\/ Processing results (detections, bounding boxes)\r\n    }).expect(\"Failed to start async infer job\");\r\n\r\n    job.detach();  \/\/ Detach to allow parallel execution\r\n}<\/code><\/pre>\n<p>\u6bcf\u6b21\u8fed\u4ee3\u90fd\u4f1a\u542f\u52a8\u4e00\u4e2a\u5f02\u6b65\u4efb\u52a1\uff0c\u5e76\u901a\u8fc7 <code>detach()<\/code> \u8ba9\u4efb\u52a1\u5e76\u884c\u6267\u884c\uff0c\u4ece\u800c\u63d0\u9ad8\u63a8\u7406\u7684\u541e\u5410\u91cf\u3002<\/p>\n<\/section>\n<section>\n<h2>5. \u5904\u7406\u63a8\u7406\u7ed3\u679c<\/h2>\n<p>\u63a8\u7406\u5b8c\u6210\u540e\uff0c\u6211\u4eec\u4f1a\u5728\u56de\u8c03\u51fd\u6570\u4e2d\u5904\u7406\u7ed3\u679c\uff0c\u8f93\u51fa\u68c0\u6d4b\u5230\u7684\u8fb9\u754c\u6846\u548c\u7f6e\u4fe1\u5ea6\u5206\u6570\u3002<\/p>\n<pre><code>uint8_t* buffer = output_buffer.get();\r\nint num_detections = (int)*(float32_t*)buffer;\r\nstd::cout &lt;&lt; \"There are \" &lt;&lt; num_detections &lt;&lt; \" detections.\" &lt;&lt; std::endl;\r\nfor (int i = 0; i &lt; num_detections; i++) {\r\n    hailo_bbox_float32_t detection = ((hailo_bbox_float32_t*)(buffer + offset))[i];\r\n    std::cout &lt;&lt; \"Detection - y_min: \" &lt;&lt; detection.y_min\r\n              &lt;&lt; \", x_min: \" &lt;&lt; detection.x_min\r\n              &lt;&lt; \", y_max: \" &lt;&lt; detection.y_max\r\n              &lt;&lt; \", x_max: \" &lt;&lt; detection.x_max\r\n              &lt;&lt; \", confidence: \" &lt;&lt; detection.confidence &lt;&lt; std::endl;\r\n}<\/code><\/pre>\n<p>\u6211\u4eec\u8bfb\u53d6\u63a8\u7406\u7ed3\u679c\u4e2d\u7684\u8fb9\u754c\u6846\u6570\u636e\u5e76\u8f93\u51fa\u68c0\u6d4b\u5230\u7684\u76ee\u6807\u4fe1\u606f\u3002<\/p>\n<\/section>\n<footer>\n<section>\n<h2>CMake \u914d\u7f6e<\/h2>\n<p>\u4e3a\u4e86\u7f16\u8bd1\u8fd9\u4e2a\u9879\u76ee\uff0c\u6211\u4eec\u9700\u8981\u5728 `CMakeLists.txt` \u6587\u4ef6\u4e2d\u8fdb\u884c\u914d\u7f6e\uff0c\u4ee5\u4fbf\u6b63\u786e\u94fe\u63a5 Hailo \u5e93\u548c\u5176\u4ed6\u4f9d\u8d56\u9879\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u7b80\u5316\u7684 `CMakeLists.txt` \u6587\u4ef6\u793a\u4f8b\uff1a<\/p>\n<pre><code>cmake_minimum_required(VERSION 3.0.0)\r\nproject(detection_app)\r\nset(CMAKE_CXX_STANDARD 17)\r\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\r\n\r\n# Enable pkg-config support\r\nfind_package(PkgConfig REQUIRED)\r\n# Use pkg-config to get the OpenCV flags\r\npkg_check_modules(OpenCV REQUIRED opencv4)\r\n\r\nset(HAILORT_INCLUDE \"\/opt\/poky\/4.0.2\/sysroots\/armv8a-poky-linux\/usr\/include\")\r\nset(HAILORT_LIB \"\/opt\/poky\/4.0.2\/sysroots\/armv8a-poky-linux\/usr\/lib\/libhailort.so\")\r\n\r\nadd_executable(detection_app async_infer_advanced_example.cpp )\r\n\r\nset(COMPILE_OPTIONS_CPP -Wall -O3 -g -std=c++11)\r\n\r\ninclude_directories(${HAILORT_INCLUDE})\r\ninclude_directories( ${OpenCV_INCLUDE_DIRS} )\r\n\r\ntarget_link_libraries( detection_app PRIVATE ${OpenCV_LIBS} )\r\ntarget_link_libraries( detection_app PRIVATE ${HAILORT_LIB} )\r\n#target_link_libraries( detection_app PRIVATE opencv_core opencv_videoio opencv_imgproc opencv_imgcodecs)<\/code><\/pre>\n<p>\u4f60\u53ef\u4ee5\u6839\u636e\u9700\u8981\u6dfb\u52a0\u66f4\u591a\u7684\u4f9d\u8d56\u9879\uff0c\u6bd4\u5982 OpenCV\u3001 \u6216\u5176\u4ed6\u5e93\uff0c\u4fee\u6539 `target_link_libraries` \u6765\u94fe\u63a5\u5b83\u4eec\u3002<\/p>\n<\/section>\n<p>\u672c\u6587\u8bb2\u89e3\u4e86\u5982\u4f55\u4f7f\u7528 Hailo \u7684\u5f02\u6b65\u63a8\u7406 API \u6765\u6267\u884c YOLOv5s \u6a21\u578b\u7684\u63a8\u7406\u3002\u901a\u8fc7\u5f02\u6b65\u6267\u884c\u65b9\u5f0f\uff0c\u6211\u4eec\u80fd\u591f\u63d0\u9ad8\u63a8\u7406\u7684\u541e\u5410\u91cf\uff0c\u9002\u7528\u4e8e\u5b9e\u65f6\u6216\u9ad8\u6027\u80fd\u7684\u5e94\u7528\u573a\u666f\u3002<\/p>\n<\/footer>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5728\u672c\u7bc7\u6587\u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u5c55\u793a\u5982\u4f55\u4f7f\u7528 Hailo \u63d0\u4f9b\u7684\u5f02\u6b65\u63a8\u7406 API \u8fd0\u884c YOLOv5s \u6a21\u578b\uff0c\u5e76\u4e14\u5904\u7406\u8f93\u5165 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"footnotes":""},"categories":[5],"tags":[],"class_list":["post-773","post","type-post","status-publish","format-standard","hentry","category-hailort"],"_links":{"self":[{"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/posts\/773","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/comments?post=773"}],"version-history":[{"count":1,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/posts\/773\/revisions"}],"predecessor-version":[{"id":774,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/posts\/773\/revisions\/774"}],"wp:attachment":[{"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/media?parent=773"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/categories?post=773"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.zhoubin.asia\/index.php\/wp-json\/wp\/v2\/tags?post=773"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}