您好,登錄后才能下訂單哦!
這篇文章主要講解了“Serverless架構(gòu)下怎么用Python搞定圖像分類(lèi)和預(yù)測(cè)”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Serverless架構(gòu)下怎么用Python搞定圖像分類(lèi)和預(yù)測(cè)”吧!
本文將會(huì)通過(guò)一個(gè)有趣的 Python 庫(kù),快速將圖像分類(lèi)的功能搭建在云函數(shù)上,并且和 API 網(wǎng)關(guān)結(jié)合,對(duì)外提供 API 功能,實(shí)現(xiàn)一個(gè) Serverless 架構(gòu)的“圖像分類(lèi) API”。
首先和大家介紹一下需要的依賴(lài)庫(kù):ImageAI。通過(guò)該依賴(lài)的官方文檔我們可以看到這樣的描述:
ImageAI 是一個(gè) python 庫(kù),旨在使開(kāi)發(fā)人員能夠使用簡(jiǎn)單的幾行代碼構(gòu)建具有包含深度學(xué)習(xí)和計(jì)算機(jī)視覺(jué)功能的應(yīng)用程序和系統(tǒng)。
ImageAI 本著簡(jiǎn)潔的原則,支持最先進(jìn)的機(jī)器學(xué)習(xí)算法,用于圖像預(yù)測(cè)、自定義圖像預(yù)測(cè)、物體檢測(cè)、視頻檢測(cè)、視頻對(duì)象跟蹤和圖像預(yù)測(cè)訓(xùn)練。ImageAI 目前支持使用在 ImageNet-1000 數(shù)據(jù)集上訓(xùn)練的 4 種不同機(jī)器學(xué)習(xí)算法進(jìn)行圖像預(yù)測(cè)和訓(xùn)練。ImageAI 還支持使用在 COCO 數(shù)據(jù)集上訓(xùn)練的 RetinaNet 進(jìn)行對(duì)象檢測(cè)、視頻檢測(cè)和對(duì)象跟蹤。最終,ImageAI 將為計(jì)算機(jī)視覺(jué)提供更廣泛和更專(zhuān)業(yè)化的支持,包括但不限于特殊環(huán)境和特殊領(lǐng)域的圖像識(shí)別。
也就是說(shuō)這個(gè)依賴(lài)庫(kù),可以幫助我們完成基本的圖像識(shí)別和視頻的目標(biāo)提取,雖然他給了一些數(shù)據(jù)集和模型,但是我們也可以根據(jù)自身需要對(duì)其進(jìn)行額外的訓(xùn)練,進(jìn)行定制化拓展。通過(guò)官方給的代碼,我們可以看到一個(gè)簡(jiǎn)單的 Demo:
# -*- coding: utf-8 -*- from imageai.Prediction import ImagePrediction # 模型加載 prediction = ImagePrediction() prediction.setModelTypeAsResNet() prediction.setModelPath("resnet50_weights_tf_dim_ordering_tf_kernels.h6") prediction.loadModel() predictions, probabilities = prediction.predictImage("./picture.jpg", result_count=5 ) for eachPrediction, eachProbability in zip(predictions, probabilities): print(str(eachPrediction) + " : " + str(eachProbability))
(左右滑動(dòng)查看)
當(dāng)我們指定的 picture.jpg 圖片為:
我們?cè)趫?zhí)行之后的結(jié)果是:
laptop : 71.43893241882324 notebook : 16.265612840652466 modem : 4.899394512176514 hard_disc : 4.007557779550552 mouse : 1.2981942854821682
如果在使用過(guò)程中覺(jué)得模型
resnet50_weights_tf_dim_ordering_tf_kernels.h6 過(guò)大,耗時(shí)過(guò)長(zhǎng),可以按需求選擇模型:
SqueezeNet(文件大?。?.82 MB,預(yù)測(cè)時(shí)間最短,精準(zhǔn)度適中)
ResNet50 by Microsoft Research (文件大?。?8 MB,預(yù)測(cè)時(shí)間較快,精準(zhǔn)度高)
InceptionV3 by Google Brain team (文件大?。?1.6 MB,預(yù)測(cè)時(shí)間慢,精度更高)
DenseNet121 by Facebook AI Research (文件大?。?1.6 MB,預(yù)測(cè)時(shí)間較慢,精度最高)
模型下載地址可參考 Github 地址:https://github.com/OlafenwaMoses/ImageAI/releases/tag/1.0
或者參考 ImageAI 官方文檔:https://imageai-cn.readthedocs.io/zh_CN/latest/ImageAI_Image_Prediction.html
項(xiàng)目 Serverless 化
將項(xiàng)目按照函數(shù)計(jì)算的需求,編寫(xiě)好入口方法,以及做好項(xiàng)目初始化,同時(shí)在當(dāng)前項(xiàng)目下創(chuàng)建文件夾 model,并將模型文件拷貝到該文件夾:
項(xiàng)目整體流程:
實(shí)現(xiàn)代碼:
# -*- coding: utf-8 -*- from imageai.Prediction import ImagePrediction import json import uuid import base64 import random # Response class Response: def __init__(self, start_response, response, errorCode=None): self.start = start_response responseBody = { 'Error': {"Code": errorCode, "Message": response}, } if errorCode else { 'Response': response } # 默認(rèn)增加uuid,便于后期定位 responseBody['ResponseId'] = str(uuid.uuid1()) print("Response: ", json.dumps(responseBody)) self.response = json.dumps(responseBody) def __iter__(self): status = '200' response_headers = [('Content-type', 'application/json; charset=UTF-8')] self.start(status, response_headers) yield self.response.encode("utf-8") # 隨機(jī)字符串 randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num)) # 模型加載 print("Init model") prediction = ImagePrediction() prediction.setModelTypeAsResNet() print("Load model") prediction.setModelPath("/mnt/auto/model/resnet50_weights_tf_dim_ordering_tf_kernels.h6") prediction.loadModel() print("Load complete") def handler(environ, start_response): try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 requestBody = json.loads(environ['wsgi.input'].read(request_body_size).decode("utf-8")) # 圖片獲取 print("Get pucture") imageName = randomStr(10) imageData = base64.b64decode(requestBody["image"]) imagePath = "/tmp/" + imageName with open(imagePath, 'wb') as f: f.write(imageData) # 內(nèi)容預(yù)測(cè) print("Predicting ... ") result = {} predictions, probabilities = prediction.predictImage(imagePath, result_count=5) print(zip(predictions, probabilities)) for eachPrediction, eachProbability in zip(predictions, probabilities): result[str(eachPrediction)] = str(eachProbability) return Response(start_response, result)
所需要的依賴(lài):
tensorflow==1.13.1 numpy==1.19.4 scipy==1.5.4 opencv-python==4.4.0.46 pillow==8.0.1 matplotlib==3.3.3 h6py==3.1.0 keras==2.4.3 imageai==2.1.5
編寫(xiě)部署所需要的配置文件:
ServerlessBookImageAIDemo: Component: fc Provider: alibaba Access: release Properties: Region: cn-beijing Service: Name: ServerlessBook Description: Serverless圖書(shū)案例 Log: Auto Nas: Auto Function: Name: serverless_imageAI Description: 圖片目標(biāo)檢測(cè) CodeUri: Src: ./src Excludes: - src/.fun - src/model Handler: index.handler Environment: - Key: PYTHONUSERBASE Value: /mnt/auto/.fun/python MemorySize: 3072 Runtime: python3 Timeout: 60 Triggers: - Name: ImageAI Type: HTTP Parameters: AuthType: ANONYMOUS Methods: - GET - POST - PUT Domains: - Domain: Auto
在代碼與配置中,可以看到有目錄:/mnt/auto/ 的存在,該部分實(shí)際上是 nas 掛載之后的地址,只需提前寫(xiě)入到代碼中即可,下一個(gè)環(huán)節(jié)會(huì)進(jìn)行 nas 的創(chuàng)建以及掛載點(diǎn)配置的具體操作。
項(xiàng)目部署與測(cè)試
在完成上述步驟之后,可以通過(guò):
s deploy
進(jìn)行項(xiàng)目部署,部署完成可以看到結(jié)果:
完成部署之后,可以通過(guò):
s install docker
進(jìn)行依賴(lài)的安裝:
依賴(lài)安裝完成可以看到在目錄下生成了 .fun 的目錄,該目錄就是通過(guò) docker 打包出來(lái)的依賴(lài)文件,這些依賴(lài)正是我們?cè)? requirements.txt 文件中聲明的依賴(lài)內(nèi)容。
完成之后,我們通過(guò):
s nas sync ./src/.fun
將依賴(lài)目錄打包上傳到 nas,成功之后再將 model 目錄打包上傳:
s nas sync ./src/model
完成之后可以通過(guò):
s nas ls --all
查看目錄詳情:
完成之后,我們可以編寫(xiě)腳本進(jìn)行測(cè)試,同樣適用剛才的測(cè)試圖片,通過(guò)代碼:
import json import urllib.request import base64 import time with open("picture.jpg", 'rb') as f: data = base64.b64encode(f.read()).decode() url = 'http://35685264-1295939377467795.test.functioncompute.com/' timeStart = time.time() print(urllib.request.urlopen(urllib.request.Request( url=url, data=json.dumps({'image': data}).encode("utf-8") )).read().decode("utf-8")) print("Time: ", time.time() - timeStart)
可以看到結(jié)果:
{"Response": {"laptop": "71.43893837928772", "notebook": "16.265614330768585", "modem": "4.899385944008827", "hard_disc": "4.007565602660179", "mouse": "1.2981869280338287"}, "ResponseId": "1d74ae7e-298a-11eb-8374-024215000701"} Time: 29.16020894050598
可以看到,函數(shù)計(jì)算順利地返回了預(yù)期結(jié)果,但是整體耗時(shí)卻超乎想象,有近 30s,此時(shí)我們?cè)俅螆?zhí)行一下測(cè)試腳本:
{"Response": {"laptop": "71.43893837928772", "notebook": "16.265614330768585", "modem": "4.899385944008827", "hard_disc": "4.007565602660179", "mouse": "1.2981869280338287"}, "ResponseId": "4b8be48a-298a-11eb-ba97-024215000501"} Time: 1.1511380672454834
可以看到,再次執(zhí)行的時(shí)間僅有 1.15 秒,比上次整整提升了 28 秒之多。
項(xiàng)目?jī)?yōu)化
在上一輪的測(cè)試中可以看到,項(xiàng)目首次啟動(dòng)和二次啟動(dòng)的耗時(shí)差距,其實(shí)這個(gè)時(shí)間差,主要是函數(shù)在加載模型的時(shí)候浪費(fèi)了極長(zhǎng)的時(shí)間。
即使在本地,我們也可以簡(jiǎn)單測(cè)試:
# -*- coding: utf-8 -*- import time timeStart = time.time() # 模型加載 from imageai.Prediction import ImagePrediction prediction = ImagePrediction() prediction.setModelTypeAsResNet() prediction.setModelPath("resnet50_weights_tf_dim_ordering_tf_kernels.h6") prediction.loadModel() print("Load Time: ", time.time() - timeStart) timeStart = time.time() predictions, probabilities = prediction.predictImage("./picture.jpg", result_count=5) for eachPrediction, eachProbability in zip(predictions, probabilities): print(str(eachPrediction) + " : " + str(eachProbability)) print("Predict Time: ", time.time() - timeStart)
執(zhí)行結(jié)果:
Load Time: 5.549695014953613 laptop : 71.43893241882324 notebook : 16.265612840652466 modem : 4.899394512176514 hard_disc : 4.007557779550552 mouse : 1.2981942854821682 Predict Time: 0.8137111663818359
可以看到,在加載 imageAI 模塊以及加載模型文件的過(guò)程中,一共耗時(shí) 5.5 秒,在預(yù)測(cè)部分僅有不到 1 秒鐘的時(shí)間。而在函數(shù)計(jì)算中,機(jī)器性能本身就沒(méi)有我本地的性能高,此時(shí)為了避免每次裝載模型導(dǎo)致的響應(yīng)時(shí)間過(guò)長(zhǎng),在部署的代碼中,可以看到模型裝載過(guò)程實(shí)際上是被放在了入口方法之外。這樣做的一個(gè)好處是,項(xiàng)目每次執(zhí)行的時(shí)候,不一定會(huì)有冷啟動(dòng),也就是說(shuō)在某些復(fù)用的前提下是可以復(fù)用一些對(duì)象的,即無(wú)需每次都重新加載模型、導(dǎo)入依賴(lài)等。
所以在實(shí)際項(xiàng)目中,為了避免頻繁請(qǐng)求,實(shí)例重復(fù)裝載、創(chuàng)建某些資源,我們可以將部分資源放在初始化的時(shí)候進(jìn)行。這樣可以大幅度提高項(xiàng)目的整體性能,同時(shí)配合廠商所提供的預(yù)留能力,可以基本上杜絕函數(shù)冷啟動(dòng)帶來(lái)的負(fù)面影響。
感謝各位的閱讀,以上就是“Serverless架構(gòu)下怎么用Python搞定圖像分類(lèi)和預(yù)測(cè)”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Serverless架構(gòu)下怎么用Python搞定圖像分類(lèi)和預(yù)測(cè)這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。