Serverless實(shí)戰(zhàn):用20行Python代碼輕松搞定圖像分類和預(yù)測
圖像分類是人工智能領(lǐng)域的一個(gè)熱門話題,通俗來講,就是根據(jù)各自在圖像信息中反映的不同特征,把不同類別的目標(biāo)區(qū)分開。圖像分類利用計(jì)算機(jī)對(duì)圖像進(jìn)行定量分析,把圖像或圖像中的每個(gè)像元或區(qū)域劃歸為若干個(gè)類別中的某一種,代替人的視覺判讀。
在實(shí)際生活中,我們也會(huì)遇到圖像分類的應(yīng)用場景,例如我們常用的通過拍照花朵來識(shí)別花朵信息,通過人臉匹配人物信息等。通常,圖像識(shí)別或分類工具都是在客戶端進(jìn)行數(shù)據(jù)采集,在服務(wù)端進(jìn)行運(yùn)算獲得結(jié)果。因此,一般都會(huì)有專門的 API 來實(shí)現(xiàn)圖像識(shí)別,云廠商也會(huì)有償提供類似的能力:
華為云圖像標(biāo)簽
騰訊云圖像分析
本文將嘗試通過一個(gè)有趣的 Python 庫,快速將圖像分類的功能搭建在云函數(shù)上,并且和 API 網(wǎng)關(guān)結(jié)合,對(duì)外提供 API 功能,實(shí)現(xiàn)一個(gè) Serverless 架構(gòu)的"圖像分類 API"。
1. 入門 ImageAI
首先,我們需要一個(gè)依賴庫:ImageAI。
什么是 ImageAI 呢?其官方文檔是這樣描述的:
ImageAI 是一個(gè) python 庫,旨在使開發(fā)人員能夠使用簡單的幾行代碼構(gòu)建具有包含深度學(xué)習(xí)和計(jì)算機(jī)視覺功能的應(yīng)用程序和系統(tǒng)。ImageAI 本著簡潔的原則,支持最先進(jìn)的機(jī)器學(xué)習(xí)算法,用于圖像預(yù)測、自定義圖像預(yù)測、物體檢測、視頻檢測、視頻對(duì)象跟蹤和圖像預(yù)測訓(xùn)練。ImageAI 目前支持使用在 ImageNet-1000 數(shù)據(jù)集上訓(xùn)練的 4 種不同機(jī)器學(xué)習(xí)算法進(jìn)行圖像預(yù)測和訓(xùn)練。ImageAI 還支持使用在 COCO 數(shù)據(jù)集上訓(xùn)練的 RetinaNet 進(jìn)行對(duì)象檢測、視頻檢測和對(duì)象跟蹤。最終,ImageAI 將為計(jì)算機(jī)視覺提供更廣泛和更專業(yè)化的支持,包括但不限于特殊環(huán)境和特殊領(lǐng)域的圖像識(shí)別。
簡單理解,就是 ImageAI 依賴庫可以幫助用戶完成基本的圖像識(shí)別和視頻的目標(biāo)提取。不過,ImageAI 雖然提供一些數(shù)據(jù)集和模型,但我們也可以根據(jù)自身需要對(duì)其進(jìn)行額外的訓(xùn)練,進(jìn)行定制化拓展。
其官方代碼給出了這樣一個(gè)簡單的 Demo:
- from imageai.Prediction import ImagePrediction
- import os
- execution_path = os.getcwd()
- prediction = ImagePrediction()
- prediction.setModelTypeAsResNet()
- prediction.setModelPath(os.path.join(execution_path, "resnet50_weights_tf_dim_ordering_tf_kernels.h5"))
- prediction.loadModel()
- predictions, probabilities = prediction.predictImage(os.path.join(execution_path, "1.jpg"), result_count=5 )
- for eachPrediction, eachProbability in zip(predictions, probabilities):
- print(eachPrediction + " : " + eachProbability)
我們可以在本地進(jìn)行初步運(yùn)行,指定圖片1.jpg為下圖時(shí):
可以得到結(jié)果:
- convertible : 52.459537982940674
- sports_car : 37.61286735534668
- pickup : 3.175118938088417
- car_wheel : 1.8175017088651657
- minivan : 1.7487028613686562
2. 讓 ImageAI 上云(部署到 Serverless 架構(gòu)上)
通過上面的 Demo,我們可以考慮將這個(gè)模塊部署到云函數(shù):
首先,在本地創(chuàng)建一個(gè) Python 的項(xiàng)目:mkdir imageDemo,
然后,新建文件:vim index.py
第三,根據(jù)云函數(shù)的一些特殊形式,我們對(duì) Demo 進(jìn)行部分改造
- 將初始化的代碼放在外層;
- 將預(yù)測部分當(dāng)做觸發(fā)所需要執(zhí)行的部分,放在入口方法中(此處是 main_handler);
- 云函數(shù)與 API 網(wǎng)關(guān)結(jié)合對(duì)二進(jìn)制文件支持并不是十分的友善,所以此處通過 base64 進(jìn)行圖片傳輸;
- 入?yún)⒍閧"picture": 圖片的 base64},出參定為:{"prediction": 圖片分類的結(jié)果}
實(shí)現(xiàn)的代碼如下:
- from imageai.Prediction import ImagePrediction
- import os, base64, random
- execution_path = os.getcwd()
- prediction = ImagePrediction()
- prediction.setModelTypeAsSqueezeNet()
- prediction.setModelPath(os.path.join(execution_path, "squeezenet_weights_tf_dim_ordering_tf_kernels.h5"))
- prediction.loadModel()
- def main_handler(event, context):
- imgData = base64.b64decode(event["body"])
- fileName = '/tmp/' + "".join(random.sample('zyxwvutsrqponmlkjihgfedcba', 5))
- with open(fileName, 'wb') as f:
- f.write(imgData)
- resultData = {}
- predictions, probabilities = prediction.predictImage(fileName, result_count=5)
- for eachPrediction, eachProbability in zip(predictions, probabilities):
- resultData[eachPrediction] = eachProbability
- return resultData
創(chuàng)建完成之后,下載所依賴的模型:
- SqueezeNet(文件大小:4.82 MB,預(yù)測時(shí)間最短,精準(zhǔn)度適中)
- ResNet50 by Microsoft Research (文件大?。?8 MB,預(yù)測時(shí)間較快,精準(zhǔn)度高)
- InceptionV3 by Google Brain team (文件大小:91.6 MB,預(yù)測時(shí)間慢,精度更高)
- DenseNet121 by Facebook AI Research (文件大?。?1.6 MB,預(yù)測時(shí)間較慢,精度最高)
因?yàn)槲覀儍H用于測試,所以選擇一個(gè)比較小的模型就可以:SqueezeNet:
在官方文檔復(fù)制模型文件地址:
使用wget直接安裝:
- wget https://github.com/OlafenwaMoses/ImageAI/releases/download/1.0/squeezenet_weights_tf_dim_ordering_tf_kernels.h5
接下來,進(jìn)行依賴安裝:
由于騰訊云 Serveless 產(chǎn)品,在 Python Runtime 中還不支持在線安裝依賴,所以需要手動(dòng)打包依賴,并且上傳。在 Python 的各種依賴庫中,有很多依賴可能有編譯生成二進(jìn)制文件的過程,這就會(huì)導(dǎo)致不同環(huán)境下打包的依賴無法通用。
所以,最好的方法就是通過對(duì)應(yīng)的操作系統(tǒng) + 語言版本進(jìn)行打包。我們就是在 CentOS+Python3.6 的環(huán)境下進(jìn)行依賴打包。
對(duì)于很多 MacOS 用戶和 Windows 用戶來說,這確實(shí)不是一個(gè)很友好的過程,所以為了方便大家使用,我在 Serverless 架構(gòu)上做了一個(gè)在線打包依賴的工具,所以可以直接用該工具進(jìn)行打包:
生成壓縮包之后,直接下載解壓,并且放到自己的項(xiàng)目中即可:
最后一步,創(chuàng)建serverless.yaml
- imageDemo:
- component: "@serverless/tencent-scf"
- inputs:
- name: imageDemo
- codeUri: ./
- handler: index.main_handler
- runtime: Python3.6
- region: ap-guangzhou
- description: 圖像識(shí)別 / 分類 Demo
- memorySize: 256
- timeout: 10
- events:
- - apigw:
- name: imageDemo_apigw_service
- parameters:
- protocols:
- - http
- serviceName: serverless
- description: 圖像識(shí)別 / 分類 DemoAPI
- environment: release
- endpoints:
- - path: /image
- method: ANY
完成之后,執(zhí)行sls --debug部署,部署過程中會(huì)有掃碼登陸,登陸之后等待即可,完成之后,就可以看到部署地址。
3. 基本測試
通過 Python 語言進(jìn)行測試,接口地址就是剛才復(fù)制的 +/image,例如:
- import json
- import urllib.request
- import base64
- with open("1.jpg", 'rb') as f:
- base64_data = base64.b64encode(f.read())
- s = base64_data.decode()
- url = 'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'
- print(urllib.request.urlopen(urllib.request.Request(
- url = url,
- data= json.dumps({'picture': s}).encode("utf-8")
- )).read().decode("utf-8"))
通過網(wǎng)絡(luò)搜索一張圖片:
得到運(yùn)行結(jié)果:
- {
- "prediction": {
- "cheetah": 83.12643766403198,
- "Irish_terrier": 2.315458096563816,
- "lion": 1.8476998433470726,
- "teddy": 1.6655176877975464,
- "baboon": 1.5562783926725388
- }
- }
通過這個(gè)結(jié)果,我們可以看到圖片的基礎(chǔ)分類 / 預(yù)測已經(jīng)成功了,為了證明這個(gè)接口的時(shí)延情況,可以對(duì)程序進(jìn)行基本改造:
- import urllib.request
- import base64, time
- for i in range(0,10):
- start_time = time.time()
- with open("1.jpg", 'rb') as f:
- base64_data = base64.b64encode(f.read())
- s = base64_data.decode()
- url = 'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'
- print(urllib.request.urlopen(urllib.request.Request(
- url = url,
- data= json.dumps({'picture': s}).encode("utf-8")
- )).read().decode("utf-8"))
- print("cost: ", time.time() - start_time)
輸出結(jié)果:
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 2.1161561012268066
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.1259253025054932
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.3322770595550537
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.3562259674072266
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.0180821418762207
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.4290671348571777
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.5917718410491943
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.1727900505065918
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 2.962592840194702
- {"prediction":{"cheetah":83.12643766403198,"Irish_terrier":2.315458096563816,"lion":1.8476998433470726,"teddy":1.6655176877975464,"baboon":1.5562783926725388}}
- cost: 1.2248001098632812
通過上面一組數(shù)據(jù),我們可以看到整體的耗時(shí)基本控制在 1-1.5 秒之間。
當(dāng)然,如果想要對(duì)接口性能進(jìn)行更多的測試,例如通過并發(fā)測試來看并發(fā)情況下接口性能表現(xiàn)等。
至此,我們通過 Serveerless 架構(gòu)搭建的 Python 版本的圖像識(shí)別 / 分類小工具做好了。
4. 總結(jié)
Serverless 架構(gòu)下進(jìn)行人工智能相關(guān)的應(yīng)用可以是說是非常多的,本文是通過一個(gè)已有的依賴庫,實(shí)現(xiàn)一個(gè)圖像分類 / 預(yù)測的接口。imageAI這個(gè)依賴庫相對(duì)來說自由度比較高,可以根據(jù)自身需要用來定制化自己的模型。本文算是拋磚引玉,期待更多人通過 Serverless 架構(gòu)部署自己的"人工智能"API。