iT邦幫忙

2021 iThome 鐵人賽

1
AI & Data

觀賞魚辨識的YOLO全餐系列 第 38

Day 38 - 在 AWS Lambda 中使用 YOLO 推估 (Inference)

Day 38 - 在 AWS Lambda 中使用 YOLO 推估 (Inference)

Day 15 - 說明 YOLO 相關設定 以及 Day 16 - 進行影像辨識訓練完成了 YOLO 自訂資料集的訓練,在 Day 34 - 實作 S3 驅動 Lambda 函數進行 Yolo 物件辨識Day 36 - 使用 Container 建立 Amazon SageMaker 端點 分別用不同的方法來進行 YOLO 推估的任務。

彼此之間的關係如下圖所示,使用者透過 API Gateway 上傳 (PUT) 圖片到 儲存貯體 A,這個事件會驅動 AWS Lambda 函數,此時,AWS Lambda 函數 會根據事先訓練好的 YOLO 模型,對於該圖片進行 YOLO 推估 (Inference),接著以 IAM 角色 B 的身分,將偵測到物件畫出方塊框後,存到 儲存貯體 B,而使用者就可以看到處理後的結果。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510LZjSpkJlEt.png
圖 1、S3 驅動 Lambda 函數進行 YOLO 辨識架構圖

Simple Inference Scripts for YOLO with OpenCV 這份專案中提供了一個使用 OpenCV 來進行 YOLO 推論的案例,現在我們就試著將這個案例佈署到 AWS Lambda 進行測試,需要的前期準備工作如下:

  1. 上傳 YOLO 相關檔案到 S3: 訓練好的權重檔 (yolov3.backup) 以及待推論的圖片 (02-frame-608x608-0090.jpg)
  2. 建立 IAM 角色,允許執行 AWS Lambda,並有存取 S3 的許可。
  3. 建立 AWS Lambda 函數,並設定環境變數。
  4. 在 AWS Lambda 建立 OpenCV 層
  5. 撰寫 AWS Lambda 函數並完成測試

步驟 1. 上傳 YOLO 相關檔案到 S3

因為 AWS Lambda 函數的大小限制為 256 MB,所以需要把 YOLO 的權重檔 (yolov3.backup) 以及待推論的圖片 (02-frame-608x608-0090.jpg) 存到 S3 中,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510PEMPbnXX5X.png
圖 2、上傳 YOLO 相關檔案到 S3

步驟 2. 建立 IAM 角色

建立一個 IAM 角色,允許執行 AWS Lambda,並有存取 S3 的許可。進入 IAM 管理控制台,選擇新增角色,接下來如下圖所示,選擇 Lambda 的使用案例後點擊 下一個:許可 按鈕。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510Ho1lmAVeEv.png
圖 3、建立一個角色選擇 Lambda 的使用案例

在搜尋文字框中輸入 basic 找到 AWSLambdaBasicExecutionRole 進行連接,這將允許這個角色有寫入 CloudWatch 記錄檔的全縣,方便程式除錯之用,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510ONBVaFtqLd.png
圖 4、連接基礎的 CloudWatch 除錯用的許可政策

最後確定先前的設定後並輸入角色名稱後,就可以建立角色,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510tcuQo65mSs.png
圖 5、檢閱設定並建立角色

編輯一個新的政策,內容如下圖所示,給定讀取 (GetObject) 儲存貯體 A 與寫入物件 (PutObject) 與權限 (PutObjectAcl) 到儲存貯體 B。

https://ithelp.ithome.com.tw/upload/images/20211110/201295106z8PES6Fyg.png
圖 6、新增政策

接著到角色設定畫面,將新建政策連接到角色上,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/201295104ocZPCDT9y.png
圖 7、將新增的政策連接到先前的角色

步驟 3. 建立 AWS Lambda 函數

進入 AWS Lambda 管理控制台,選擇建立 Lambda 函數,設定內容如下圖所示。比較需要注意的是執行時間務必選擇 Python 3.7,因為要使用 OpenCV 函式庫層,而執行角色要也要記得選擇上一個步驟設定的角色。

  • 選擇下列選項之一來建立您的函式: 從頭開始撰寫
  • 函式名稱: opencv45Func
  • 執行時間: Python 3.7
  • 架構: x86_64
  • 執行角色: 使用現有的角色

https://ithelp.ithome.com.tw/upload/images/20211110/20129510GSsTSguPHs.png
圖 8、建立 Lambda 函數設定畫面

在 Lambda 函數中點擊 組態 頁籤,接著點擊 環境變量,新增三個環境變量,如下所示:

  • modelbucket: 存放權重的儲存貯體,應該也是儲存貯體 B,因為任何對 儲存貯體 A 所做的寫入都會引發驅動 Lambda 的事件。
  • modelweight:yolov4cfg/yolov3.backup
  • putbucket: 儲存貯體 B

https://ithelp.ithome.com.tw/upload/images/20211110/20129510ljWNiRwXfE.png
圖 9、新增 Lambda 函數組態中的環境變量

步驟 4.在 AWS Lambda 建立 OpenCV 層

建立 Lambda 函數後,選擇進入 AWS Lambda 函數的設定畫面,在畫面的最底端,為本函數 新建 Layer,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510BQI91WmFO5.png
圖 10、為 Lambda 函數新增 Layer

進入新增 Layer 畫面後,選擇層來源為 自訂 Layer,接著選擇先前建立的 opencv45 函式庫層,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/201295100VqEUZgVUo.png
圖 11、選擇 opencv45 函式庫層

步驟 5. 撰寫 AWS Lambda 函數並完成測試

需要先建立一個目錄 cfg,在目錄內新增一個檔案 yolov3.cfg ,這個檔案的內容可以參考 Day 15 - 說明 YOLO 相關設定,而主要的推論程式為 service.py,內容如下

service.py

from __future__ import print_function

import urllib.request
import os
import subprocess
import boto3
import time
import cv2 

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
LIB_DIR = os.path.join(SCRIPT_DIR, 'lib')
s3_client = boto3.client('s3')
modelbucket = os.environ['modelbucket']
modelweight = os.environ['modelweight']
modelcfg = 'cfg/yolov3.cfg'

# 從 s3 下載檔案
def downloadFromS3(strBucket,strKey,strFile):
  s3_client.download_file(strBucket, strKey, strFile)

strWeightFile = '/tmp/' +  modelweight.replace('/', '')
downloadFromS3(modelbucket,modelweight,strWeightFile)  
print(strWeightFile)

# 繪製物件方塊框
def draw_image(image_path, output_path, pridicts):
  cv2image = cv2.imread(image_path)
  for k in range(len(pridicts[0])):
    x, y, w, h  = pridicts[2][k]
    cv2.putText(cv2image, "{:.4f}".format(pridicts[1][k][0]), (x, y-6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1, cv2.LINE_AA)
    cv2.rectangle(cv2image, (int(x),int(y)), (int(x+w),int(y+w)), (0,255,0), 2)
  cv2.imwrite(output_path, cv2image)

# yolo 推論函數
def yolo_infer(weight, cfg, pic):
  frame = cv2.imread(pic)
  model = cv2.dnn.readNet(weight,cfg)
  net = cv2.dnn_DetectionModel(model)
  net.setInputSize(608, 608)
  net.setInputScale(1.0 / 255)
  net.setInputSwapRB(True)

  classes, confidences, boxes = net.detect(frame, confThreshold=0.1, nmsThreshold=0.4)
  return classes,confidences,boxes

# lambda 程式進入口    
def handler(event, context):
  for record in event['Records']:
    inputbucket = record['s3']['bucket']['name']
    outputbucket = os.environ['putbucket']
    key = record['s3']['object']['key']
    imgfilepath = '/tmp/inputimage.jpg'
    
    downloadFromS3(inputbucket,key,imgfilepath)
    prev_time = time.time()
    result = yolo_infer(strWeightFile, modelcfg, imgfilepath)
    print('predicting time: ' , (time.time() - prev_time))

    tmpkey = key.replace('/', '')
    upload_path = '/tmp/process-{}'.format(tmpkey)
    draw_image(imgfilepath, upload_path, result)
    s3_client.upload_file(upload_path, outputbucket, key,ExtraArgs={'ACL': 'public-read','ContentType':'image/jpeg'})

    return 0 

https://ithelp.ithome.com.tw/upload/images/20211110/20129510bCzPmnTmsw.png
圖 12、AWS Lambda 程式碼

建立新測試事件,事件範本選擇 hello-world,事件名稱輸入 fromS3Bucket,內容所下圖所示,這是用來模擬當 S3 觸發 Lambda 函數後所傳過來的參數內容,記得將 [INPUT_BUCKET] 改成實際的輸入儲存貯體名稱,而[INPUT_OBJECT]要確保有這個檔案。

{
  "Records": [
    {
      "s3": {
        "bucket": {
          "name": "[INPUT_BUCKET]",
          "arn": "arn:aws:s3:::[INPUT_BUCKET]"
        },
        "object": {
          "key": "[INPUT_OBJECT]"
        }
      }
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20211110/20129510FbtH6Go5r2.png
圖 13、設定 Lambda 函數測試事件

拉到畫面下方,修改 執行時間設定,將 處理常式 指定為 service.handler,如下圖所示。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510ZZPRzUD1Ib.png
圖 14、修改執行時間設定中的處理常式

最後點擊 Test 進行測試,得到的結果如下圖所示,推論時間約 1.75 秒,所需記憶體為 990 MB。

https://ithelp.ithome.com.tw/upload/images/20211110/20129510rdoMbLi0oF.png
圖 15、使用 OpenCV 進行 YOLO 推論

因此,這似乎是一個可以接受的解決方案,表 1.列出目前為止的所有 YOLO 辨識部署解決方案。

表 1、 使用 EC2/Lambda/SageMaker 進行 YOLO 辨識比較

  使用 EC2 使用 Lambda (darknet) 使用 SageMaker 使用 Lambda (OpenCV)
成本(USD) 0.736/hour 0 1.0304/hour 0
時間(秒) ~ 0.1 秒 > 60 秒 1秒 左右 1-3 秒
可用性 較差 AWS 托管 AWS 托管 AWS 托管

參考資料


上一篇
Day 37 - 在 AWS Lambda 建立 OpenCV Layer
系列文
觀賞魚辨識的YOLO全餐38

尚未有邦友留言

立即登入留言