写点什么

Serverless 实战:用 20 行 Python 代码轻松搞定图像分类和预测

  • 2020-04-19
  • 本文字数:8211 字

    阅读完需:约 27 分钟

Serverless 实战:用20行Python代码轻松搞定图像分类和预测

图像分类是人工智能领域的一个热门话题,通俗来讲,就是根据各自在图像信息中反映的不同特征,把不同类别的目标区分开。图像分类利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,代替人的视觉判读。


在实际生活中,我们也会遇到图像分类的应用场景,例如我们常用的通过拍照花朵来识别花朵信息,通过人脸匹对人物信息等。通常,图像识别或分类工具都是在客户端进行数据采集,在服务端进行运算获得结果。因此,一般都会有专门的 API 来实现图像识别,云厂商也会有偿提供类似的能力:


  • 华为云图像标签



  • 腾讯云图像分析



本文将尝试通过一个有趣的 Python 库,快速将图像分类的功能搭建在云函数上,并且和 API 网关结合,对外提供 API 功能,实现一个 Serverless 架构的"图像分类 API"。

入门 ImageAI

首先,我们需要一个依赖库:ImageAI


什么是 ImageAI 呢?其官方文档是这样描述的:


ImageAI 是一个 python 库,旨在使开发人员能够使用简单的几行代码构建具有包含深度学习和计算机视觉功能的应用程序和系统。

ImageAI 本着简洁的原则,支持最先进的机器学习算法,用于图像预测、自定义图像预测、物体检测、视频检测、视频对象跟踪和图像预测训练。ImageAI 目前支持使用在 ImageNet-1000 数据集上训练的 4 种不同机器学习算法进行图像预测和训练。ImageAI 还支持使用在 COCO 数据集上训练的 RetinaNet 进行对象检测、视频检测和对象跟踪。 最终,ImageAI 将为计算机视觉提供更广泛和更专业化的支持,包括但不限于特殊环境和特殊领域的图像识别。


简单理解,就是 ImageAI 依赖库可以帮助用户完成基本的图像识别和视频的目标提取。不过,ImageAI 虽然提供一些数据集和模型,但我们也可以根据自身需要对其进行额外的训练,进行定制化拓展。


其官方代码给出了这样一个简单的 Demo:


from imageai.Prediction import ImagePredictionimport osexecution_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)
复制代码


我们可以在本地进行初步运行,指定图片1.jpg为下图时:



可以得到结果:


convertible  :  52.459537982940674sports_car  :  37.61286735534668pickup  :  3.175118938088417car_wheel  :  1.8175017088651657minivan  :  1.7487028613686562
复制代码

让 ImageAI 上云(部署到 Serverless 架构上)

通过上面的 Demo,我们可以考虑将这个模块部署到云函数:


  • 首先,在本地创建一个 Python 的项目:mkdir imageDemo

  • 新建文件:vim index.py

  • 根据云函数的一些特殊形式,我们对 Demo 进行部分改造

  • 将初始化的代码放在外层;

  • 将预测部分当做触发所需要执行的部分,放在入口方法中(此处是 main_handler);

  • 云函数与 API 网关结合对二进制文件支持并不是十分的友善,所以此处通过 base64 进行图片传输;

  • 入参定为{"picture": 图片的base64},出参定为:{"prediction": 图片分类的结果}


实现的代码如下:


from imageai.Prediction import ImagePredictionimport 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

复制代码


创建完成之后,下载所依赖的模型:


  • SqueezeNet(文件大小:4.82 MB,预测时间最短,精准度适中)

  • ResNet50 by Microsoft Research (文件大小:98 MB,预测时间较快,精准度高)

  • InceptionV3 by Google Brain team (文件大小:91.6 MB,预测时间慢,精度更高)

  • DenseNet121 by Facebook AI Research (文件大小:31.6 MB,预测时间较慢,精度最高)


因为我们仅用于测试,所以选择一个比较小的模型就可以:SqueezeNet


在官方文档复制模型文件地址:



使用wget直接安装:


wget https://github.com/OlafenwaMoses/ImageAI/releases/download/1.0/squeezenet_weights_tf_dim_ordering_tf_kernels.h5
复制代码



接下来,进行依赖安装:



由于腾讯云 Serveless 产品,在 Python Runtime 中还不支持在线安装依赖,所以需要手动打包依赖,并且上传。在 Python 的各种依赖库中,有很多依赖可能有编译生成二进制文件的过程,这就会导致不同环境下打包的依赖无法通用。


所以,最好的方法就是通过对应的操作系统+语言版本进行打包。我们就是在 CentOS+Python3.6 的环境下进行依赖打包。


对于很多 MacOS 用户和 Windows 用户来说,这确实不是一个很友好的过程,所以为了方便大家使用,我在 Serverless 架构上做了一个在线打包依赖的工具,所以可以直接用该工具进行打包:




生成压缩包之后,直接下载解压,并且放到自己的项目中即可:



最后一步,创建serverless.yaml


imageDemo:  component: "@serverless/tencent-scf"  inputs:    name: imageDemo    codeUri: ./    handler: index.main_handler    runtime: Python3.6    region: ap-guangzhou    description: 图像识别/分类Demo    memorySize: 256    timeout: 10    events:      - apigw:          name: imageDemo_apigw_service          parameters:            protocols:              - http            serviceName: serverless            description: 图像识别/分类DemoAPI            environment: release            endpoints:              - path: /image                method: ANY
复制代码


完成之后,执行sls --debug部署,部署过程中会有扫码登陆,登陆之后等待即可,完成之后,就可以看到部署地址。


基本测试

通过 Python 语言进行测试,接口地址就是刚才复制的+/image,例如:


import jsonimport urllib.requestimport 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"))
复制代码


通过网络搜索一张图片:



得到运行结果:


{  "prediction": {    "cheetah": 83.12643766403198,    "Irish_terrier": 2.315458096563816,    "lion": 1.8476998433470726,    "teddy": 1.6655176877975464,    "baboon": 1.5562783926725388  }}
复制代码


通过这个结果,我们可以看到图片的基础分类/预测已经成功了,为了证明这个接口的时延情况,可以对程序进行基本改造:


import urllib.requestimport 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)
复制代码


输出结果:


{"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
复制代码


通过上面一组数据,我们可以看到整体的耗时基本控制在 1-1.5 秒之间。


当然,如果想要对接口性能进行更多的测试,例如通过并发测试来看并发情况下接口性能表现等。


至此,我们通过 Serveerless 架构搭建的 Python 版本的图像识别/分类小工具做好了。

总结

Serverless 架构下进行人工智能相关的应用可以是说是非常多的,本文是通过一个已有的依赖库,实现一个图像分类/预测的接口。imageAI这个依赖库相对来说自由度比较高,可以根据自身需要用来定制化自己的模型。本文算是抛砖引玉,期待更多人通过 Serverless 架构部署自己的"人工智能"API。


2020-04-19 22:1611539

评论 3 条评论

发布
用户头像
没有明白你的数据和图片是什么关系
2020-04-27 09:16
回复
识别图片给出分类啊。。。。文章里面都说了要拿来做图像识别分类了,数据分别是识别结果和概率。。。。
2020-04-28 10:14
回复
用户头像
学习学习!
2020-04-23 12:23
回复
没有更多了
发现更多内容

架构师训练营第二周作业

尹斌

保留时序数据波动细节的一种采样算法

小清新同学

监控 时序数据库

架构师训练营第 1 期第二周课后练习题

Leo乐

极客大学架构师训练营

如何快速制造OOM

Since

JVM OOM

架构师训练营第 2 周作业

netspecial

极客大学架构师训练营

架构师训练营第 1 期第 2周作业

owl

极客大学架构师训练营

刷爆朋友圈的字节跳动编码题,今天把解析思路分享下!

Java架构师迁哥

传销资金盘挂靠区块链热点 肃清整顿热潮拉开帷幕

CECBC

区块链 金融

项目实战,动态增删form表单

麦洛

jquery 克隆

Python 自动化测试全攻略:五种自动化测试模型实战详解

葡萄城技术团队

自动化测试

难得干货,揭秘支付宝的2维码扫码技术优化实践之路

JackJiang

支付宝

从大数据的角度来谈谈运维监控这件事儿

小清新同学

运维 监控

缓存解决方案-技术专题-Caffeine Cache

码界西柚

MySQL varchar类型最大值,原来一直都理解错了

架构精进之路

MySQL varchar

什么才是“应用拓扑”?

小清新同学

运维 监控

如何设计Go语言中的channel

soolaugust

channel goroutines Go 语言

Go中的HTTP请求之——HTTP1.1请求流程分析

Gopher指北

HTTP Go web Go 语言

2B还是2C,这真是个问题

MavenTalker

SaaS

不一样的面向对象(二)

书旅

php 面向对象

自己动手写SQL执行引擎

无毁的湖光

Java MySQL 数据库 Linux 算法

关于Java 编译Servlet或者自定义Tag,引入包的问题

谷鱼

Java

java安全编码指南之:可见性和原子性

程序那些事

Java java安全编码 java编码指南 java安全编码指南

架构师训练营第 1 期第 2 周学习总结

owl

极客大学架构师训练营

监控应用,应该监控什么?

小清新同学

云计算 运维 监控

收藏+下载!Flink 社区最全学习渠道汇总

Apache Flink

flink

Dolphinscheduler系统架构设计

dll

Apache DolphinScheduler

RN运行项目报错:Unable to resolve module `./debugger-ui/debuggerWorker.js` from ``

凌宇之蓝

ios android React Native

程序执行太慢?快来学习SIMD加速技术,这个案例下的加速效果我也没想到(附带动手实验)

Optimize-Lab

优化代码 优化技巧 开源社区 simd Go 语言

高难度对话读书笔记—认知篇2

wo是一棵草

架构师训练营第二周学习总结

尹斌

虚拟卡兑换架构设计

孙志平

Serverless 实战:用20行Python代码轻松搞定图像分类和预测_服务革新_刘宇_InfoQ精选文章