3885 views
--- title: AI Maker 案例教學 - CVAT 輔助推論模組實作 description: OneAI 文件 tags: 案例教學, CVAT --- [OneAI 文件](/s/xKNcU3O5D) # AI Maker 案例教學 - CVAT 輔助推論模組實作 [TOC] ## 1. 前言 AI Maker 整合了 CVAT(Computer Vision Annotation Tool)標註工具,可幫助您快速標註機器學習的訓練資料,或是將訓練好的模型透過推論服務與 CVAT 連結,進行自動標註。 在 [**AI Maker 案例教學 - YOLOv4 影像辨識應用**](/s/JyKyKQe1c) 範例中,我們學會了使用 AI Maker 訓練出自己的深度學習模型,並且將訓練出來的模型透過 AI Maker 提供 **`yolov4-cvat`** 推論範本,結合 CVAT 的自動標註功能,進行影像資料的輔助標註推論服務。本範例是一篇進階的教學,提供兩個 API 實作範例,說明如何以 YOLOv4 和 SiamMask 模型,實作串接 CVAT 輔助標註/自動標註的 API。 在開始學習本範例前,請先熟悉 AI Maker 及 CVAT(Computer Vision Annotation Tool)的基本操作,或是先閱讀下列的文件: * [**容器映像檔**](/s/WAoPe4Au5) * [**AI Maker > 推論服務**](/s/QFn7N5R-H#%E6%8E%A8%E8%AB%96) * [**AI Maker 案例教學 - YOLOv4 影像辨識應用 > CVAT 輔助標註**](/s/JyKyKQe1c#6-CVAT-輔助標註) * [**CVAT 官方文件**](https://opencv.github.io/cvat/docs/) * [**CVAT GitHub**](https://github.com/opencv/cvat) ## 2. CVAT 輔助標註推論服務 CVAT 原生的模型部署功能是架構在 [**Nuclio**](https://nuclio.io/) 平台上,再實作其對應的 Serverless Functions。然而 [**建置 Nuclio 環境**](https://github.com/nuclio/nuclio/blob/development/docs/setup/k8s/getting-started-k8s.md) 以及 [**部署對應 Functions**](https://github.com/nuclio/nuclio/blob/development/docs/tasks/deploying-functions.md) 的步驟非常繁瑣且不友善。AI Maker 整合的 CVAT 標註工具改善了 CVAT 輔助標註在模型推論部署上的繁瑣操作,只要實作串接 CVAT 輔助標註推論服務的 API,即可透過 AI Maker 快速部署 CVAT 輔助標註推論服務。 ### 2.1 架構說明 CVAT 輔助標註服務架構圖如下面所示,黃色方塊代表使用者要自行建置跟部署的功能,架構圖的上半部為原生 CVAT 與 Nuclio 平台,使用者需要建置 Nuclio 平台以及部署對應的 Functions;架構圖的下半部表示透過 AI Maker 整合 CVAT 的輔助標註及模型推論部署功能,使用者只需要部署對應的推論服務就可以串接 CVAT 的輔助標註服務。 ![](/uploads/upload_b24b48863a9983f232a72f68c205b041.png) :::info :bulb: **提示:CVAT Microservice** 是內建於 AI Maker 中的微服務,其功能是 CVAT 與推論服務的橋樑,使 AI Maker 內建的 CVAT 可以查詢模型資訊以及讓 AI Maker 的推論服務串接 CVAT 的輔助標註/自動標註功能。 ::: ### 2.2 API 說明 從上面的架構圖中可以看到要串接 CVAT 輔助標註與 AI Maker 推論服務有兩個 API 需要使用者自行實作:**`cvat_info`** 以及 **`cvat_invoke`**,以下將說明這兩個 API 的實作。 | API 名稱 | 說明 | |-----|------------| | **cvat_info** |定義模型的資訊,需要填寫 framework、type、description 及 spec 的資訊,CVAT 在查詢 Model 資訊時會呼叫此 API,如圖所示。 <br> <br> ![](/uploads/upload_84f98a1930295733b84e218e5360aa95.png) | **cvat_invoke** |實作推論的結果,CVAT 在執行 **輔助標註以及自動標註** 時會呼叫此 API。CVAT 會透過 HTTP POST Method 傳送一張經過 Base64 編碼的圖片,我們需要實作且回傳推論的結果給 CVAT,回傳的資料類型會依在定義模型的資訊中所填寫的 type 而不同,詳細資訊將會在下面的章節中介紹。 關於 **cvat_info** 需要實作模型的資訊,說明如下: | 名稱 |說明 | |-----|------------| |framework|模型的框架。 |type|定義模型的辨識任務,有四種類型,詳細說明請參考括號中的連結。<br>**detector** - 用於自動標註(CVAT 的 [detectors](https://opencv.github.io/cvat/docs/manual/advanced/ai-tools/#detectors) 以及 [automatic annotation](https://opencv.github.io/cvat/docs/manual/advanced/automatic-annotation/))<br>**interactor** - 用於外框的輔助標註(CVAT 的 [interactors](https://opencv.github.io/cvat/docs/manual/advanced/ai-tools/#interactors)) <br>**tracker** - 用於追蹤的輔助標註(CVAT 的 [trackers](https://opencv.github.io/cvat/docs/manual/advanced/ai-tools/#trackers) )<br>**reid** - 用於行人重識別標註(CVAT 的 [automatic annotation](https://opencv.github.io/cvat/docs/manual/advanced/automatic-annotation/)) |description| 模型的說明描述。 |spec| 條列出所支援的標籤(當模型 type 為 detector 才需要填寫,若是其他 type 則此欄位請填 None)。 下表為常用的模型在 CVAT 中對應的 Type,更多資訊請參考 [**CVAT GitHub**](https://github.com/opencv/cvat#deep-learning-serverless-functions-for-automatic-labeling)。 | 名稱 |Type| |-----|------------| |Deep Extreme Cut|interactor |Faster RCNN | detector |Mask RCNN| detector |YOLO v3/v4| detector |Object reidentification|reid |Semantic segmentation for ADAS|detector |Text detection v4|detector |SiamMask|tracker |f-BRS|interactor |HRNet|interactor |Inside-Outside Guidance|interactor |RetinaNet|detector ## 3. 範例一:Detector API 範例一將以 Yolov4 模型,實作串接 CVAT 自動標註的 Detector API,在開始前建議您先閱讀 [**AI Maker 案例教學 - YOLOv4 影像辨識應用 > CVAT 輔助標註**](/s/JyKyKQe1c#6-CVAT-輔助標註)。 ![](/uploads/upload_d0d9c56927a3a816afe5cb098fb722c3.png) <center>自動標註示意圖</center> ### 3.1 API 範例 下面以 Yolov4 模型實作 Detector API 為例,展示 cvat_info 及 cvat_invoke 這兩個 API 輸入資料以及需要回傳的資料結構。 **Request** * URL: GET /cvat_info **Response** * Body: ```json= HTTP/1.1 200 OK { "framework":"yolov4", "spec":[ { "id": 0, "name": "people" }, { "id": 1, "name": "cat"} ], "type": "detector", "description":"Object detection via Yolov4" } ``` **Request** * URL: POST /cvat_invoke * Body: ```json= { "image":"base64_encode_image" } ``` **Response** * Body: ```json= HTTP/1.1 200 OK [ { "label": "people", "points": [ 286, 751, 432, 903 ], "type": "rectangle" }, { "label": "cat", "points": [ 69, 1112, 331, 1175 ], "type": "rectangle" } ] ``` ### 3.2 API 範例程式碼 本章節中提供 Detector 的範例程式,示範如何使用 **Python Flask** 輕量級的網頁框架實作 cvat_info 以及 cvat_invoke 這兩個 API。 本範例以 [**YOLOv4**](https://github.com/AlexeyAB/darknet) 為例,實作 Detector 的 API 程式,說明如下: :::spoiler **範例程式碼:`main.py`** ```python= # -*- coding: utf-8 -*- import base64 from flask import Flask, request, jsonify import logging import json from model_handler import ModelHandler app = Flask(__name__) logger = logging.getLogger('flask.app') model_handler = ModelHandler() model_handler.init() @app.route('/cvat_info', methods=['GET']) def cvat_info(): labels = model_handler.label() resp = { "framework": "yolov4", "type": "detector", "spec": labels, "description": "Object detection via Yolov4" } return resp @app.route('/cvat_invoke', methods=['POST']) def cvat_invoke(): data = request.get_json() img = base64.b64decode(data['image'].encode('utf8')) detections = model_handler.detection(img) results = [] for detection in detections: obj_class = detection[0] bbox = detection[2] left, top, right, bottom = model_handler.bbox2points(bbox) points = [left, top, right, bottom] results.append({ "label": obj_class, "points": points, "type": "rectangle" }) body=json.dumps(results) return body if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9999) ``` ::: * 第 10 ~ 11 行:模型的初始化。 * 第 13 ~ 22 行:實作 cvat_info 這個 API,定義模型資訊並將這些資訊以 JSON 格式回傳。 * 第 24 ~ 41 行:實作 cvat_invoke 這個 API,主要是接收經過 Base64 編碼的圖片,將其解碼並輸入 YOLOv4 Model 做辨識,並將辨識出的資料包成 JSON 格式回傳。 :::spoiler **範例程式碼:`model_handler.py`** ```python= import os import glob import random import time import shutil import cv2 import numpy as np import darknet YOLO_SUB_FOLDER = os.environ.get('YOLO_SUB_FOLDER', 'yolov4') YOLO_NAMES_FILENAME = os.environ.get('YOLO_NAMES_FILENAME', 'dataset.names') YOLO_DATA_FILENAME = os.environ.get('YOLO_DATA_FILENAME', 'dataset.data') YOLO_CFG_FILENAME = os.environ.get('YOLO_CFG_FILENAME', 'yolo.cfg') YOLO_WEIGHTS_FILENAME = os.environ.get('YOLO_WEIGHTS_FILENAME', 'yolo_final.weights') AIMAKER_FOLDER = os.environ.get('AI_MAKER_FOLDER', '/ai-maker/models/') ORI_PATH = AIMAKER_FOLDER + YOLO_SUB_FOLDER DST_PATH = "/output/" + "yolov4" SEPARATE = "/" EndLine = "\n" DARKNET_NAME = DST_PATH + SEPARATE + YOLO_NAMES_FILENAME DARKNET_DATA = DST_PATH + SEPARATE + YOLO_DATA_FILENAME DARKNET_CFG = DST_PATH + SEPARATE + YOLO_CFG_FILENAME DARKNET_WEIGHTS = ORI_PATH + SEPARATE + YOLO_WEIGHTS_FILENAME class ModelHandler: def __init__(self): self.weights = DARKNET_WEIGHTS self.config_file = DARKNET_CFG self.data_file = DARKNET_DATA self.name_file = DARKNET_NAME self.batch_size = 1 self.thresh = 0.3 self.network = None self.class_names = None self.class_colors = None def copyFile(self): print("copy:--------------------", flush=True) fileNames = [ YOLO_DATA_FILENAME, YOLO_NAMES_FILENAME, YOLO_CFG_FILENAME ] for fileName in fileNames: src = ORI_PATH + SEPARATE + fileName dst = DST_PATH + SEPARATE + fileName shutil.copyfile(src, dst) def createFolder(self): dirs = [ DST_PATH, ] for dir in dirs: if not os.path.exists(dir): os.makedirs(dir) else: print(dir + 'already exist') def updateNameInData(self): src = DST_PATH + SEPARATE + YOLO_DATA_FILENAME labelPath = DST_PATH + SEPARATE + YOLO_NAMES_FILENAME dst = src + ".bak" key = "names" with open(src, 'r', encoding='utf-8') as f: with open(dst, 'w', encoding='utf-8') as f2: for line in f.readlines(): find = line.startswith(key, 0, len(key)) if (find): line = key + "=" + labelPath + EndLine f2.write(line) os.remove(src) os.rename(dst, src) def init(self): self.createFolder() self.copyFile() self.updateNameInData() self.network, self.class_names, self.class_colors = darknet.load_network( self.config_file, self.data_file, self.weights, batch_size=self.batch_size) self.width = darknet.network_width(self.network) self.height = darknet.network_height(self.network) def image_detection(self, data): npimg = np.frombuffer(data,'u1') source = cv2.imdecode(npimg, cv2.COLOR_BGR2RGB) img_height, img_width, channels = source.shape darknet_image = darknet.make_image(img_width, img_height, 3) darknet.copy_image_from_bytes(darknet_image, source.tobytes()) detections = darknet.detect_image(self.network, self.class_names, darknet_image, self.thresh) darknet.free_image(darknet_image) return detections def detection(self,img): detections = self.image_detection(img) return detections def bbox2points(self,bbox): """ From bounding box yolo format to corner points cv2 rectangle """ x, y, w, h = bbox xmin = int(round(x - (w / 2))) xmax = int(round(x + (w / 2))) ymin = int(round(y - (h / 2))) ymax = int(round(y + (h / 2))) return xmin, ymin, xmax, ymax def label(self): index = 0 labels = [] for line in open(self.name_file): labels.append({"id":index,"name":line.rstrip('\n')}) index = index +1 return labels ``` ::: * 主要是負責模型的載入以及實作模型的推論。 ### 3.3 建立及上傳容器映像檔 前面的章節中我們介紹實作 CVAT 輔助標註在模型推論部署的程式範例,接著需把程式包裝成 **容器映像檔** 以便部署到 AI Maker 的推論服務。 以下提供建立 Detector API 容器映像檔的 Dockerfile,請您將對應的範例程式(`main.py` 及 `model_handler.py`)和 Dockerfile 放在同一個資料夾中,再使用 **`docker build`** 指令建立容器映像檔並將建立好的容器映像檔上傳,詳細操作請參閱 [**容器映像檔說明文件**](/s/WAoPe4Au5)。 :::spoiler **Detector Dockerfile** ```dockerfile= From nvidia/cuda:11.0.3-cudnn8-devel-ubuntu18.04 ENV PATH "/root/miniconda3/bin:${PATH}" RUN apt update \ && apt install -y --no-install-recommends \ wget \ git \ ca-certificates \ libglib2.0-0 \ libsm6 \ libxrender1 \ libxext6 \ vim \ && rm -rf /var/lib/apt/lists/* RUN wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh \ && chmod +x Miniconda3-latest-Linux-x86_64.sh && ./Miniconda3-latest-Linux-x86_64.sh -b \ && rm -f Miniconda3-latest-Linux-x86_64.sh RUN conda create -y -n yolov4 python=3.6 # Override default shell and use bash SHELL ["conda", "run", "-n", "yolov4", "/bin/bash", "-c"] RUN pip install flask \ Cython \ colorama \ numpy \ requests \ fire \ matplotlib \ numba \ scipy \ h5py \ pandas \ tqdm \ opencv_python==3.4.8.29 \ && conda install -y gcc_linux-64 RUN git clone https://github.com/AlexeyAB/darknet.git WORKDIR /darknet RUN sed -i 's/LIBSO=0/LIBSO=1/g' Makefile RUN make COPY main.py /darknet/ COPY model_handler.py /darknet/ ENTRYPOINT ["conda", "run","--no-capture-output", "-n", "yolov4", "python", "-u","/darknet/main.py"] ``` ::: ### 3.4 模型準備 若您是使用 yolov4 範本所訓練出來的模型請跳過此步驟;如果您使用自己的 YOLOv4 模型檔案或是從其他來源取得的模型檔案(例如:[**YOLOv4 model zoo**](https://github.com/AlexeyAB/darknet/wiki/YOLOv4-model-zoo)),此處以 YOLOv4 的 COCO 預訓練模型為例,請依照下列步驟準備模型。 1. 下載模型相關的檔案 * 點此下載 [**yolov4.cfg**](https://drive.google.com/open?id=1hSrVqiEbuVewEIVU4cqG-SqJFUNTYmIC) * 點此下載 [**yolov4.weights**](https://drive.google.com/open?id=1L-SO373Udc9tPz5yLkgti5IAXFboVhUt) * 點此下載 [**coco.names**](https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/coco.names) * 點此下載 [**coco.data**](https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/coco.data) 2. 修改對應的檔案名稱 * yolov4.cfg 請重新命名為 yolo.cfg * coco.names 請重新命名為 dataset.names * coco.data 請重新命名為 dataset.data * yolov4.weights 請重新命名為 yolo_final.weights 3. 壓縮檔案並上傳 * 新增一個為 yolov4 的資料夾。 * 將上述四個檔案放到 yolov4 資料夾並且壓縮成 ZIP 檔,資料夾結構如下: ![](/uploads/upload_f7a025f00ebe6539c2f28da16a35a54a.png) * 接著將此 ZIP 檔上傳至 OneAI 的「**儲存服務**」中,再到 AI Maker 的模型管理滙入此模型,詳細步驟請參考 [**AI Maker 滙入模型說明**](/s/QFn7N5R-H#匯入模型)。 * 模型滙入完成後,請記住模型名稱和版本,接下來會以此模型部署推論服務。 ![](/uploads/upload_aa8e3ad76cb053f7e9d4a28329b7ab18.png) ### 3.5 部署推論服務 完成推論映像檔及模型的準備工作後,接著就可以部署到 AI Maker 的推論服務。在建立推論服務時需選擇您的模型和此映像檔,我們僅針對部分重要的設定加以說明,其他步驟請參閱 [**建立推論任務說明文件**](/s/QFn7N5R-H#建立推論任務)。 1. **基本設定** * **來源模型** - 名稱:請輸入 **`yolov4`**。 - 類別:請選擇 **私人**。 - 模型名稱:請選擇您要載入的模型名稱。 - 版本:請選擇您要載入的模型版本。 - 掛載位置:請輸入 **`/ai-maker/models/`**。 * **映像檔來源**:請選擇您剛上傳的映像檔和標籤。 ![](/uploads/upload_207c7c6c3aad914c59fe4f2bc928c505.png) 2. **變數設定**:Port 請設定為 **`9999`**。 ![](/uploads/upload_78bce3a3dbc3625b4e1791c8397a66a8.png) ### 3.6 連結至 CVAT 當推論服務的狀態為 **`Ready`** 時,我們還需要再做最後一個步驟,點擊上方 **連結至 CVAT** 圖示,即可連結至 CVAT 做輔助標註。 ![](/uploads/upload_0f403ec0df75f85ea8e569d6b4b83029.png) 完成連結至 CVAT 後,進入 CVAT 服務就可以在 CVAT 的 **Models** 頁面看到連結至 CVAT 的推論服務模型。 ![](/uploads/upload_6717b5201f218db2e3531513895440e9.png) 恭喜您,接下來就可以開始使用 CVAT 輔助標註/自動標註功能了。 ![](/uploads/upload_d0d9c56927a3a816afe5cb098fb722c3.png) ### 3.7 使用 CVAT 輔助標註/自動標註 使用 CVAT 輔助標註/自動標註功能的方式可以分成兩種: 1. 對整個 Task 中的所有圖片進行輔助標註/自動標註 進入「**Tasks**」頁面後找到要標註的 Task,然後將滑鼠移動到欲進行自動標註的任務右側「**Actions**」的更多選項圖示,接著點選「**Automatic annotation**」。 ![](/uploads/upload_db08a32d3df879d0a5bb62b211aa2ef3.png) 出現「**Automatic annotation**」視窗後點擊「**Model**」下拉選單,選取已連結的推論任務。接著設定模型與任務 Label 對應,最後點擊「**Annotate**」執行自動標註。 ![](/uploads/upload_7757bd99f63717ba7c5777d0f281a227.png) 標註完成後,進入 CVAT 標註工具頁面檢視自動標註的結果,若對自動標註的結果不滿意,可再進行人工標註校正。 2. 對單張圖片進行輔助標註/自動標註 進入標註頁面後,選擇欲標註的圖片,若圖中有目標物件,即可依下列步驟進行標註。 * 點選左側工具列的魔術棒(AI Tools)。 * 選擇「**Detectors**」 * 選擇您剛剛連結的 Model。 ![](/uploads/upload_c5d036cce2067c8dfae2c441c2fd02ab.png) ## 4. 範例二:Tracker API 範例二我們將以 siamMask 模型,實作串接 CVAT 自動標註的 Tracker API,在開始前建議您先瞭解 [**CVAT Tracker Mode 使用說明**](https://opencv.github.io/cvat/docs/manual/advanced/ai-tools/#trackers)。 ### 4.1 Tracker API 範例 **Request** * URL: GET /cvat_info **Response** * Body: ```json= HTTP/1.1 200 OK { "framework":"pytorch", "spec": None, "type": "tracker", "description": "Fast Online Object Tracking and Segmentation" } ``` **Request** * URL: POST /cvat_invoke * Body: ```json= { "image":"base64_encode_image", "state":"tracker_state", "shape":"[303.61328125, 112.201171875, 469.88011169433594, 380.6956787109375]" } ``` **Response** * Body: ```json= HTTP/1.1 200 OK { "state":"tracker_state", "shape":"[303.61328125, 112.201171875, 469.88011169433594, 380.6956787109375]" } ``` ### 4.2 API 範例程式碼 本章節中以 [**SiamMask**](https://github.com/foolwood/SiamMask) 為例,提供 Tracker 的範例程式,示範如何使用 **Python Flask** 輕量級的網頁框架實作 cvat_info 以及 cvat_invoke 這兩個 API。 :::spoiler **範例程式碼:`main.py`** ```python= # -*- coding: utf-8 -*- import json import base64 from PIL import Image import io from flask import Flask, request from model_handler import ModelHandler app = Flask(__name__) model = ModelHandler() @app.route('/cvat_info', methods=['GET']) def cvat_info(): resp = { "framework":"pytorch", "spec": None, "type": "tracker", "description": "Fast Online Object Tracking and Segmentation" } return resp @app.route('/cvat_invoke', methods=['POST']) def cvat_invoke(): data = request.get_json() buf = io.BytesIO(base64.b64decode(data["image"])) shapes = data.get("shapes") states = data.get("states") image = Image.open(buf) results = { 'shapes': [], 'states': [] } for i, shape in enumerate(shapes): shape, state = model.infer(image, shape, states[i] if i < len(states) else None) results['shapes'].append(shape) results['states'].append(state) return json.dumps(results) if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9999) ``` ::: * 第 9 行:模型的初始化。 * 第 10 ~ 18 行:實作 cvat_info 這個 API,定義模型資訊並將這些資訊以 JSON 格式回傳。 * 第 20 ~ 28 行:實作 cvat_invoke 這個 API,主要是接收經過 Base64 編碼的圖片,將其解碼並輸入 SiamMask Model 做辨識再將辨識出的資料包成 JSON 格式回傳。 :::spoiler **範例程式碼:`model_handler.py`** ```python= # Copyright (C) 2020 Intel Corporation # # SPDX-License-Identifier: MIT from tools.test import * import os from copy import copy import jsonpickle import numpy as np class ModelHandler: def __init__(self): # Setup device self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') torch.backends.cudnn.benchmark = True base_dir = os.path.abspath(os.environ.get("MODEL_PATH", "/workdir/SiamMask/experiments/siammask_sharp")) class configPath: config = os.path.join(base_dir, "config_davis.json") self.config = load_config(configPath) from custom import Custom siammask = Custom(anchors=self.config['anchors']) self.siammask = load_pretrain(siammask, os.path.join(base_dir, "SiamMask_DAVIS.pth")) self.siammask.eval().to(self.device) def encode_state(self, state): state['net.zf'] = state['net'].zf state.pop('net', None) state.pop('mask', None) for k,v in state.items(): state[k] = jsonpickle.encode(v) return state def decode_state(self, state): for k,v in state.items(): state[k] = jsonpickle.decode(v) state['net'] = copy(self.siammask) state['net'].zf = state['net.zf'] del state['net.zf'] return state def infer(self, image, shape, state): image = np.array(image) if state is None: # init tracking xtl, ytl, xbr, ybr = shape target_pos = np.array([(xtl + xbr) / 2, (ytl + ybr) / 2]) target_sz = np.array([xbr - xtl, ybr - ytl]) siammask = copy(self.siammask) # don't modify self.siammask state = siamese_init(image, target_pos, target_sz, siammask, self.config['hp'], device=self.device) state = self.encode_state(state) else: # track state = self.decode_state(state) state = siamese_track(state, image, mask_enable=True, refine_enable=True, device=self.device) shape = state['ploygon'].flatten().tolist() state = self.encode_state(state) return shape, state ``` ::: * 主要是負責模型的載入以及實作模型的推論。 ### 4.3 建立及上傳容器映像檔 前面的章節中我們介紹實作 CVAT 輔助標註在模型推論部署的程式範例,接著需把程式包裝成 **容器映像檔** 以便部署到 AI Maker 的推論服務。 以下提供建立 Tracker API 容器映像檔的 Dockerfile,請您將對應的範例程式(`main.py` 及 `model_handler.py`)和 Dockerfile 放在同一個資料夾中,再使用 **`docker build`** 指令建立容器映像檔並將建立好的容器映像檔上傳,詳細操作請參閱 [**容器映像檔說明文件**](/s/WAoPe4Au5)。 :::spoiler **Tracker Dockerfile** ```dockerfile= From nvidia/cuda:11.0.3-cudnn8-devel-ubuntu18.04 ENV PYTHONPATH "/workdir/SiamMask:/workdir/SiamMask/experiments/siammask_sharp" ENV PATH "/root/miniconda3/bin:${PATH}" RUN apt update \ && apt install -y --no-install-recommends \ wget \ git \ ca-certificates \ libglib2.0-0 \ libsm6 \ libxrender1 \ libxext6 \ && rm -rf /var/lib/apt/lists/* RUN wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh \ && chmod +x Miniconda3-latest-Linux-x86_64.sh && ./Miniconda3-latest-Linux-x86_64.sh -b \ && rm -f Miniconda3-latest-Linux-x86_64.sh RUN mkdir -p /workdir WORKDIR /workdir RUN conda create -y -n siammask python=3.6 # Override default shell and use bash SHELL ["conda", "run", "-n", "siammask", "/bin/bash", "-c"] RUN pip install torch==1.8.0 \ jsonpickle \ flask \ Cython \ colorama \ numpy \ requests \ fire \ matplotlib \ numba \ scipy \ h5py \ pandas \ tqdm \ tensorboardX \ opencv_python==3.4.8.29 \ torchvision==0.9.0 \ && conda install -y gcc_linux-64 RUN git clone https://github.com/foolwood/SiamMask.git RUN cd /workdir/SiamMask && bash make.sh RUN wget -P /workdir/SiamMask/experiments/siammask_sharp http://www.robots.ox.ac.uk/~qwang/SiamMask_DAVIS.pth COPY main.py /workdir/ COPY model_handler.py /workdir/ ENTRYPOINT ["conda", "run","--no-capture-output", "-n", "siammask", "python", "-u","/workdir/main.py"] ::: ### 4.4 模型準備 您可以使用自己的模型或是由 https://github.com/foolwood/SiamMask 下載公開的 SiamMask 模型檔至本機端,指令如下: ```shell= wget http://www.robots.ox.ac.uk/~qwang/SiamMask_DAVIS.pth wget https://raw.githubusercontent.com/foolwood/SiamMask/master/experiments/siammask_sharp/config_davis.json ``` 下載完畢後請將模型檔壓縮成 ZIP 檔,接著將此 ZIP 檔上傳至 OneAI 的「**儲存服務**」中,再到 AI Maker 的模型管理滙入此模型,請參考 [**AI Maker 滙入模型說明**](/s/QFn7N5R-H#匯入模型)。 模型滙入完成後,請記住模型名稱和版本,接下來會以此模型部署推論服務。 ![](/uploads/upload_2d96a2da5d03171c70875c62216a4a56.png) ### 4.5 部署推論服務 完成推論映像檔及模型的準備工作後,接著就可以部署 AI Maker 的推論服務。在建立推論服務時需選擇您的模型和此映像檔,我們僅針對部分重要的設定加以說明,其他步驟請參閱 [**建立推論任務說明文件**](/s/QFn7N5R-H#建立推論任務)。 建立推論服務的步驟中,請依照以下設定: 1. **基本設定** * **來源模型** - 名稱:請輸入 **`siammask`**。 - 類別:請選擇 **私人**。 - 模型名稱:請選擇您要載入的模型名稱。 - 版本:請選擇您要載入的模型版本。 - 掛載位置:請輸入 **`/ai-maker/models/`**。 * **映像檔來源**:請選擇您剛上傳的映像檔和標籤。 ![](/uploads/upload_d0bf9fcaa79c2ebe8f16eb43530258fe.png) 2. **變數設定**:Port 請設定為 **`9999`**。 ![](/uploads/upload_78bce3a3dbc3625b4e1791c8397a66a8.png) ### 4.6 連結至 CVAT 當推論服務的狀態為 **`Ready`** 時,我們還需要再做最後一個步驟,點擊上方 **連結至 CVAT** 圖示,即可連結至 CVAT 做輔助標註。 ![](/uploads/upload_11fbbf175fba83e03f68d7d4e0a75fc0.png) 完成連結至 CVAT 後,進入 CVAT 服務就可以在 CVAT 的 **Models** 頁面看到連結至 CVAT 的推論服務模型。 ![](/uploads/upload_7c3d66f3316e0a75f0c157fa837b8dd0.png) 恭喜您,接下來就可以開始使用 CVAT 輔助標註/自動標註功能了。 ![](/uploads/upload_405ce37a13b3ccf83a8bc00b9eef367d.png) 學會了以 YOLOv4 和 SiamMask 模型串接 CVAT 輔助標註/自動標註的 API 之後,依此類推,您可以參考 [**CVAT GitHub**](https://github.com/opencv/cvat),練習使用自己的深度學習模型,實作串接 CVAT 輔助標註/自動標註的 API。 :::warning :warning: **注意事項:** AI Maker 整合的 CVAT 版本為 [**V2.1.0**](https://github.com/opencv/cvat/tree/v2.1.0),相關功能及參考文件請以此版為準。 :::