技術實操丨使用ModelArts和HiLens Studio完成雲端驗證及部署


前言

HiLens Studio公測也出來一陣子了,亮點很多,我前些天也申請了公測,通過后趕快嘗試了一下,不得不說真的很不錯啊,特別是支持雲端編輯代碼,調試,甚至可以直接運行程序,即使自己的HiLens不在身邊,也可以得到程序運行結果,不僅僅是雲端IDE這么簡單,更是有雲端硬件資源支撐,極大降低了開發者負擔,開發者只需要一台可以聯網的電腦就行了,可以快速驗證,驗證通過后,直接安裝到自己的HiLens上就能應用了,真是太棒了。

我嘗試了將以前做過的Demo通過HiLens Stuido開發,真的很不錯,很簡單就能完成,值得一提的是,HiLens  Studio支持模型轉換,再也不需要通過ModelArts的模型轉換與壓縮功能轉換模型了,直接在HiLens Studio中就能完成了,直接用在項目中就行,省去了模型傳輸的麻煩,可以說這次的HiLens Studio是集大成之作,在得到模型原型(TensorFlow的.pb模型或Caffe的模型)后,后續的模型轉換、代碼編寫,調試,到最后的安裝部署,都可以通過HiLens Studio來完成,特別是支持在線調試運行,沒有HiLens都可以調試,這對於以前的嵌入式或邊緣計算開發來說,是不敢想象的,這都是得益於華為雲強大的硬件支撐和技術支持。

閑話少說,這次,我通過HiLens Studio完成基於YOLOv3_Resnet18的行人檢測,這里為了簡單,只對行人進行檢測,如果你希望可以檢測更多類別的目標,可以使用更多類別的數據集訓練,相應的參照本文提供的utils.py做簡單的代碼修改即可,代碼都會給的,也會加必要的注釋哦,而且完整技能發布在了ModelArts的AI市場,歡迎大家體驗,如果有問題,可以在下面回帖哦,對了,該技能基於最新的固件版本測試,在雲端控制管理台顯示為1.0.9版本,其他版本下未測試,注意版本哦。技能在AI市場的鏈接:https://console.huaweicloud.com/modelarts/?region=cn-north-4#/aiMarket/aiMarketModelDetail/overview?modelId=9d906199-b467-4a7e-9521-bc6a3031cf7b&type=hilens

正文

重要前提:你已經申請了HiLens Studio公測,並通過。同時,華為雲賬戶有一定余額或代金券,模型訓練和OBS需要一定花費,比較少。

整體流程是創建數據集(公開數據集即可)---->模型訓練---->在HiLens Studio中完成模型轉換---->編輯代碼---->在線調試---->安裝部署。下面來逐一介紹一下

1. 創建數據集

這里使用的數據集較大,是基於VOC 2007數據集中Person類別基礎,收集網絡圖片和各公開數據集整理而成,從OBS桶下載需要耗費大量Money,分享也不太方便。不過,沒關系,可以使用官方提供的數據集,無需上傳到OBS桶,直接從官方桶中拷貝即可,但缺點是該數據集有行人和車兩類,且行人較少,主要是車輛,不太適合,大體數據分布如下:

不過你可以考慮改為對車檢測,或干脆直接人車檢測(需要自己簡單修改代碼),可自行選擇哦,關於如何獲取該數據集,以及如何創建數據集,並發布數據集相關介紹較多,不在此贅述,可以參考這篇博客中的正文部分的方法哦,里面介紹了過程,鏈接為:https://bbs.huaweicloud.com/blogs/175189

2. 模型訓練

說明一下,這里使用的是ModelArts中基於Ascend 910訓練的YOLOv3_Resnet18。鏈接為:https://console.huaweicloud.com/modelarts/?region=cn-north-4#/aiMarket/aiMarketModelDetail/overview?modelId=7087008a-7eec-4977-8b66-3a7703e9fd22&type=algo  ,同時,AI市場中有基GPU訓練的YOLOv3_Resnet18和ModelArts預置算法中的YOLOv3_Resnet18,這兩個應該也是可以的,只要最終得到.pb模型並能在HiLens Studio完成模型轉換都應該沒問題的哦,這兩個算法鏈接分別為:https://console.huaweicloud.com/modelarts/?region=cn-north-4#/aiMarket/aiMarketModelDetail/overview?modelId=948196c8-3e7a-4729-850b-069101d6e95c&type=algo     和      https://support.huaweicloud.com/engineers-modelarts/modelarts_23_0158.html#modelarts_23_0158__section185515526717

注意AI市場的算法需要先訂閱(免費的哦),同步后才能創建訓練,類似於你購買了該算法,並同步算法到自己的賬戶,相關介紹在博客中正文第三部分 模型訓練中可查看,不過該博客講的是YOLOv3_Darknet53,不是這里使用YOLOv3_Resnet18,不過沒什么影響,只是名字不同,操作是類似的,鏈接:https://bbs.huaweicloud.com/blogs/175189

最后,提醒一下,無論使用哪種算法,都要用HiLens Studio來轉換模型,不要使用ModelArts中的模型轉換與壓縮來做,因為我用的是最新的1.0.9固件版本,目前嘗試,僅HiLens Studio轉換模型才能正常使用。

3. 模型轉換

對了,打開HiLens Studio需要一定時間,請耐心等待哦。

這里可以將模型訓練輸出到OBS桶的模型直接導入到HiLens  Studio中,完成模型轉換,非常方便,這真是極致的雲端操作,將雲服務發揮到了極致啊。當然,你也可以自己從本地電腦上傳到HiLens Studio中哦。來看看怎么導入吧,很簡單,選擇Import Files from OBS,之后找到自己的模型存儲再OBS的路徑就行了,注意這里目前一次只能導入一個文件,所以需要兩次操作,一次是導入.pb模型,一次是導入轉換的配置文件,暫不能導入文件夾哦。

接下來選中文件,導入就行了:

再來一次,選資額.cfg配置文件哦:

太棒了,你已經成功了一大半了哦,我們能在左側目錄下看到導入的文件了,默認是導入到根目錄哦:

下面進行模型轉換了,如果遇到什么問題,建議參考文檔,不行的話,到論壇提問就好。

文檔鏈接:https://support.huaweicloud.com/usermanual-hilens/hilens_02_0098.html

論壇鏈接:https://bbs.huaweicloud.com/forum/forum-771-1.html

基本轉換操作在文檔中做了詳細的介紹,可以看出來工作人員還是很用心的哈:

就是先在上面菜單欄開個終端,這個使用linux系統或者熟悉ModelArts的NoteBook的用戶都應該比較熟悉了吧。之后用命令行轉換模型。

在界面最先面的終端輸入如下命令即可:

/opt/ddk/bin/aarch64-linux-gcc7.3.0/omg --model=./yolo3_resnet18.pb --input_shape='images:1,352,640,3' --framework=3 --output=./yolo3_resnet18 
--insert_op_conf=./insert_op_conf.cfg

如果你希望深入了解模型轉換的設置,可以參考:

https://console.huaweicloud.com/modelarts/?region=cn-north-4#/aiMarket/aiMarketModelDetail/overview?modelId=7087008a-7eec-4977-8b66-3a7703e9fd22&type=algo

https://www.huaweicloud.com/ascend/doc/Atlas200DK/1.31.0.0(beta)/zh/zh-cn_topic_0211633857.html

因為模板默認從左側目錄文件夾model中調用模型(這一點,在代碼中模型路徑部分有寫,而文件夾中的face_detection_demo.om是選擇人臉檢測模板自帶的模型,關於模板問題,后面會講的,可以自行刪除哦),所以我們需要將生成的.om模型復制粘貼到該文件夾中,很簡單的,直接選中.om模型,直接像在自己電腦上那樣 在鍵盤使用快捷鍵Ctrl + C(表示復制選中文件), 之后選中model文件夾,使用Ctrl + V (表示粘貼)就行了,不得不說這個設計蠻人性化的哦,用戶學習成本很低。

最終,我們得到這樣界面,就行了:

如果你不想自己訓練,只是測試一下,這里提供了轉換完成的.om模型,下載后,上傳到HiLens Studio的model文件夾下即可使用:

鏈接:https://pan.baidu.com/s/1GT1BIvkQIDNCMP-YoVAssA 

提取碼:c4d3

4. 編輯代碼

因為使用的是HiLens Studio,請再次確認已申請公測,並通過哦。相關編輯代碼部分,比較簡單。和大多數IDE類似,首先要創建工程,這里提供了很多模板,不過目前還不能創建空模板,所以自己選一個模板就行,我選的是人臉檢測模板,選擇后,點擊確定就行了哦。之后的簡單項目名稱之類的,可參照下圖哦。

創建之后,就能進入HiLens Studio類似於IDE的界面了,有點像PyCharm,感覺很不錯,,可以切換主題哦,支持暗夜黑風格,這個切換就留給你自己去找找吧,不過都是英文界面哦。進入這里,大體可以看到這些東西,主要介紹了這里會用到的部分:

好了,這里我們首先要修改主程序main.py,為了代碼的簡介和模塊化,將預處理和推理結果解析部分單獨寫為一個utils.py文件,方便理解程序運行架構,這里沒什么具體要介紹的,直接上代碼吧,如果有問題的話,可以在下面評論提問哦。

main.py主代碼

# -*- coding: utf-8 -*-
# !/usr/bin/python3
# SkillFramework 1.0.0 YOLOv3_Resnet18_Person

import cv2
import numpy as np
import os
import hilens
# 這個postprocess沒用哈
from postprocess import im_detect_nms
import utils


# 網絡輸入尺寸
input_height = 352
input_width = 640


def main(work_path):
    hilens.init("YOLOv3Resnet18Person")  # 參數要與創建技能時填寫的檢驗值保持一致!

    # 模型路徑
    model_path = os.path.join(work_path, 'model/yolo3_resnet18.om')
    model = hilens.Model(model_path)

    # hilens studio中VideoCapture如果不填寫參數,則默認讀取test/camera0.mp4文件,
    # 在hilens kit中不填寫參數則讀取本地攝像頭
    camera = hilens.VideoCapture()
    display_hdmi = hilens.Display(hilens.HDMI)  # 圖像通過hdmi輸出到屏幕

    while True:
        try:
            # 1. 讀取攝像頭輸入(yuv nv21)
            input_nv21 = camera.read()
            # 2. 轉為RGB格式
            input_rgb = cv2.cvtColor(input_nv21, cv2.COLOR_YUV2RGB_NV21)
            # src_image_height = input_bgr.shape[0]
            # src_image_width = input_bgr.shape[1]
            img_preprocess, img_w, img_h = utils.preprocess(input_rgb)  # 縮放為模型輸入尺寸
            # 3. 模型推理
            output = model.infer([img_preprocess.flatten()])
            # 4. 結果輸出
            bboxes = utils.get_result(output, img_w, img_h)   # 獲取檢測結果
            output_rgb = utils.draw_boxes(input_rgb, bboxes)  # 在圖像上畫框
            # 5. 輸出圖像,必須是yuv nv21形式
            output_nv21 = hilens.cvt_color(output_rgb, hilens.RGB2YUV_NV21)
            display_hdmi.show(output_nv21)
        except Exception:
            break


if __name__ == "__main__":
    main(os.getcwd())

這里還要創建一個前面提到的utils.py文件,很簡單哦,來上圖:

創建后,utils.py的代碼如下,如果你想檢測更多類別,比如同時檢測任何車,可參考我在下面代碼最后加的注釋部分:

# -*- coding: utf-8 -*-
# !/usr/bin/python3
# utils for mask detection

import cv2
import math
import numpy as np


# 檢測模型輸入尺寸
net_h = 352
net_w = 640

# 檢測模型的類別
class_names = ["person"]
class_num   = len(class_names)

# 檢測模型的anchors,用於解碼出檢測框
stride_list = [8, 16, 32]
anchors_1   = np.array([[10,13],   [16,30],   [33,23]])   / stride_list[0]
anchors_2   = np.array([[30,61], [62,45],   [59,119]])   / stride_list[1]
anchors_3   = np.array([[116,90], [156,198], [163,326]]) / stride_list[2]
anchor_list = [anchors_1, anchors_2, anchors_3]

# 檢測框的輸出閾值、NMS篩選閾值和人形/人臉區域匹配閾值
conf_threshold   = 0.3
iou_threshold    = 0.4
cover_threshold  = 0.8


# 圖片預處理:縮放到模型輸入尺寸
def preprocess(img_data):
    h, w, c   = img_data.shape
    new_image = cv2.resize(img_data, (net_w, net_h))
    return new_image, w, h
    
def overlap(x1, x2, x3, x4):
    left  = max(x1, x3)
    right = min(x2, x4)
    return right - left

# 計算兩個矩形框的IOU
def cal_iou(box1, box2):
    w = overlap(box1[0], box1[2], box2[0], box2[2])
    h = overlap(box1[1], box1[3], box2[1], box2[3])
    if w <= 0 or h <= 0:
        return 0
    inter_area = w * h
    union_area = (box1[2] - box1[0]) * (box1[3] - box1[1]) + (box2[2] - box2[0]) * (box2[3] - box2[1]) - inter_area
    return inter_area * 1.0 / union_area

# 計算兩個矩形框的IOU與box2區域的比值
def cover_ratio(box1, box2):
    w = overlap(box1[0], box1[2], box2[0], box2[2])
    h = overlap(box1[1], box1[3], box2[1], box2[3])
    if w <= 0 or h <= 0:
        return 0
    inter_area = w * h
    small_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
    return inter_area * 1.0 / small_area

# 使用NMS篩選檢測框
def apply_nms(all_boxes, thres):
    res = []
    
    for cls in range(class_num):        
        cls_bboxes   = all_boxes[cls]
        sorted_boxes = sorted(cls_bboxes, key=lambda d: d[5])[::-1]
        
        p = dict()
        for i in range(len(sorted_boxes)):
            if i in p:
                continue

            truth = sorted_boxes[i]
            for j in range(i+1, len(sorted_boxes)):
                if j in p:
                    continue
                box = sorted_boxes[j]
                iou = cal_iou(box, truth)
                if iou >= thres:
                    p[j] = 1

        for i in range(len(sorted_boxes)):
            if i not in p:
                res.append(sorted_boxes[i])
    return res

# 從模型輸出的特征矩陣中解碼出檢測框的位置、類別、置信度等信息
def decode_bbox(conv_output, anchors, img_w, img_h):

    def _sigmoid(x):
        s = 1 / (1 + np.exp(-x))
        return s
    
    _, h, w = conv_output.shape    
    pred    = conv_output.transpose((1,2,0)).reshape((h * w, 3, 5+class_num))
    
    pred[..., 4:] = _sigmoid(pred[..., 4:])
    pred[..., 0]  = (_sigmoid(pred[..., 0]) + np.tile(range(w), (3, h)).transpose((1,0))) / w
    pred[..., 1]  = (_sigmoid(pred[..., 1]) + np.tile(np.repeat(range(h), w), (3, 1)).transpose((1,0))) / h
    pred[..., 2]  = np.exp(pred[..., 2]) * anchors[:, 0:1].transpose((1,0)) / w
    pred[..., 3]  = np.exp(pred[..., 3]) * anchors[:, 1:2].transpose((1,0)) / h
                  
    bbox          = np.zeros((h * w, 3, 4))
    bbox[..., 0]  = np.maximum((pred[..., 0] - pred[..., 2] / 2.0) * img_w, 0)     # x_min
    bbox[..., 1]  = np.maximum((pred[..., 1] - pred[..., 3] / 2.0) * img_h, 0)     # y_min
    bbox[..., 2]  = np.minimum((pred[..., 0] + pred[..., 2] / 2.0) * img_w, img_w) # x_max
    bbox[..., 3]  = np.minimum((pred[..., 1] + pred[..., 3] / 2.0) * img_h, img_h) # y_max
    
    pred[..., :4] = bbox
    pred          = pred.reshape((-1, 5+class_num))
    pred[:, 4]    = pred[:, 4] * pred[:, 5:].max(1)    # 類別
    pred          = pred[pred[:, 4] >= conf_threshold]
    pred[:, 5]    = np.argmax(pred[:, 5:], axis=-1)    # 置信度
    
    all_boxes = [[] for ix in range(class_num)]
    for ix in range(pred.shape[0]):
        box = [int(pred[ix, iy]) for iy in range(4)]
        box.append(int(pred[ix, 5]))
        box.append(pred[ix, 4])
        all_boxes[box[4]-1].append(box)

    return all_boxes

# 從模型輸出中得到檢測框
def get_result(model_outputs, img_w, img_h):

    num_channel = 3 * (class_num + 5)    
    all_boxes   = [[] for ix in range(class_num)]
    for ix in range(3):
        pred      = model_outputs[2-ix].reshape((num_channel, net_h // stride_list[ix], net_w // stride_list[ix]))
        anchors   = anchor_list[ix]
        boxes     = decode_bbox(pred, anchors, img_w, img_h)        
        all_boxes = [all_boxes[iy] + boxes[iy] for iy in range(class_num)]
    
    res = apply_nms(all_boxes, iou_threshold)    
    return res

# 在圖中畫出檢測框,輸出類別信息,注意這里對person類別繪制矩形框
def draw_boxes(img_data, bboxes):
    thickness      = 2
    font_scale     = 1
    text_font      = cv2.FONT_HERSHEY_DUPLEX
    for bbox in bboxes:
        label = int(bbox[4])
        x_min = int(bbox[0])
        y_min = int(bbox[1])
        x_max = int(bbox[2])
        y_max = int(bbox[3])
        score = bbox[5]

        # 1: person 藍色 
        if label == 0:  
            # print(x_min, y_min, x_max, y_max)
            cv2.rectangle(img_data, (x_min, y_min), (x_max, y_max), (0, 0, 255), thickness)
            # cv2.putText(img_data, 'person', (x_min, y_min - 20), text_font, font_scale, (255, 255, 0), thickness)
            # cv2.putText(img_data, score, (50, 50), text_font, font_scale, (255, 255, 0), thickness)

        # 2:
        '''
        if label == 1:
            # print(x_min, y_min, x_max, y_max)
            cv2.rectangle(img_data, (x_min, y_min), (x_max, y_max), (255, 0, 0), thickness)
            # cv2.putText(img_data, 'person', (x_min, y_min - 20), text_font, font_scale, (255, 255, 0), thickness)
            # cv2.putText(img_data, score, (50, 50), text_font, font_scale, (255, 255, 0), thickness)
        

        else:
            # print("[INFO] Hi, find others.")
            pass
        '''

    return img_data

好,至此,基本代碼部分就完成了。

下面可以檢測測試了,這里提供一段來自MOT多目標挑戰賽的視頻片段供測試,需要自己上傳到HiLens Studio上,十分簡單,和本地電腦操作沒什么區別,郵件單機左側空白目錄部分,彈出菜單,選擇上傳即可,對開發者十分友好啊:

視頻分辨率1920 * 1080,約136M,不過很快就能上傳完成,華為雲的帶寬和上傳速度還是很不錯的,不過這也與你自己的網絡環境有關的。

視頻下載鏈接為:

鏈接:https://pan.baidu.com/s/1RWUGpYvAQuP6icY0iDkgEw 

提取碼:iwpo

注意:需要將視頻改名為camera0.mp4(選中視頻,郵件彈出菜單,選擇Rename即可),之后到左側目錄test文件夾下,將該文件夾下的camera0.mp4視頻刪除,再將剛才改名為camera0.mp4的視頻(就是我們上傳的視頻)拷貝到test文件夾下。

最終我們得到如下的幾個重要文件:

接下來,就可以執行程序測試了:

 

之后,在右上角部分的視頻框中就能看到運行結果了,如果你覺得不方便,還可以全屏觀看,甚至畫中畫模式觀看都可以呀,在畫中畫模式下,你可以邊做其他的事情,邊小窗口觀看視頻,類似於手機端的分屏操作。

全屏模式效果展示:

 

畫中畫模式效果展示(視頻可任意拖拽位置哦):

 

上面兩種模式的操作十分簡單,和在騰訊、愛奇藝、B站等視頻網站操作類似:

 

最終效果如下面視頻所示,這里非常抱歉,由於我是屏幕錄制的,且沒有切換到全屏模式,不太清晰,建議大家自己試試,在自己的HiLens Studio里看會很清晰的,同時,附上B站視頻鏈接,以防下面視頻失效,無法觀看:https://www.bilibili.com/video/BV1E5411Y73r/

如果你想安裝到HiLens Kit上,和原先的操作台類似,在上面視頻播放界面下面就有選線的,大體如下,仍然是先安裝,后啟動就行了:

 

至此,大功告成,總的來說,HiLens Stuio如開篇所說的,集大成之作,非常好用,這類雲端IDE十分新穎,創新型強,極大降低了對開發者本地配置的要求,甚至幾十沒有硬件設備,也可以調試程序,是邊緣計算開發者的福音呀,這是從HiLens,到華為雲,再到華為公司,很多人長期積累努力的結果,很不錯,這也算華為全棧全場景AI解決方案的一部分吧,期待更加強大,加油。

 

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM