{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-04-23-python-pics","result":{"data":{"currentBlog":{"id":"a93bc1e0-585b-5ae5-be5c-4f850ce95080","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589276332053-Python-Programming-Course-The-Complete-Bootcamp.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-23T00:00:00.000Z","title":"Serverless 实战：用 20 行 Python 代码轻松搞定图像分类和预测","description":"本文将尝试通过一个有趣的 Python 库，快速将图像分类的功能搭建在云函数上，并且和 API 网关结合，对外提供 API 功能，实现一个 Serverless 架构的「图像分类 API」","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["Serverless","Python"],"keywords":"Serverless 全局变量组件,Serverless 单独部署组件,Serverless Component","outdated":true},"wordCount":{"words":298,"sentences":65,"paragraphs":65},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-23-python-pics.md","fields":{"slug":"/best-practice/2020-04-23-python-pics/","keywords":["python","serverless","云函数","prediction","Serverless","图像","Python","serverlesscloud","分类"]},"html":"<p>图像分类是人工智能领域的一个热门话题，通俗来讲，就是根据各自在图像信息中反映的不同特征，把不同类别的目标区分开。图像分类利用计算机对图像进行定量分析，把图像或图像中的每个像元或区域划归为若干个类别中的某一种，代替人的视觉判读。</p>\n<p>在实际生活中，我们也会遇到图像分类的应用场景，例如我们常用的通过拍照花朵来识别花朵信息，通过人脸匹对人物信息等。通常，图像识别或分类工具都是在客户端进行数据采集，在服务端进行运算获得结果。因此，一般都会有专门的 API 来实现图像识别，云厂商也会有偿提供类似的能力：</p>\n<ul>\n<li>华为云图像标签</li>\n</ul>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588856020422-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<ul>\n<li>腾讯云图像分析</li>\n</ul>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855877612-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>本文将尝试通过一个有趣的 Python 库，快速将图像分类的功能搭建在云函数上，并且和 API 网关结合，对外提供 API 功能，实现一个 Serverless 架构的 \" 图像分类 API\"。</p>\n<h2 id=\"入门-imageai\"><a href=\"#%E5%85%A5%E9%97%A8-imageai\" aria-label=\"入门 imageai permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>入门 ImageAI</h2>\n<p>首先，我们需要一个依赖库：<code class=\"language-text\">ImageAI</code>。</p>\n<p>什么是 ImageAI 呢？其官方文档是这样描述的：</p>\n<blockquote>\n<p>ImageAI 是一个 python 库，旨在使开发人员能够使用简单的几行代码构建具有包含深度学习和计算机视觉功能的应用程序和系统。\nImageAI 本着简洁的原则，支持最先进的机器学习算法，用于图像预测、自定义图像预测、物体检测、视频检测、视频对象跟踪和图像预测训练。ImageAI 目前支持使用在 ImageNet-1000 数据集上训练的 4 种不同机器学习算法进行图像预测和训练。ImageAI 还支持使用在 COCO 数据集上训练的 RetinaNet 进行对象检测、视频检测和对象跟踪。 最终，ImageAI 将为计算机视觉提供更广泛和更专业化的支持，包括但不限于特殊环境和特殊领域的图像识别。</p>\n</blockquote>\n<p>简单理解，就是 ImageAI 依赖库可以帮助用户完成基本的图像识别和视频的目标提取。不过，ImageAI 虽然提供一些数据集和模型，但我们也可以根据自身需要对其进行额外的训练，进行定制化拓展。</p>\n<p>其官方代码给出了这样一个简单的 Demo:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"37014778661234040000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`from imageai.Prediction import ImagePrediction\nimport os\nexecution_path = os.getcwd()\n\nprediction = ImagePrediction()\nprediction.setModelTypeAsResNet()\nprediction.setModelPath(os.path.join(execution_path, &quot;resnet50_weights_tf_dim_ordering_tf_kernels.h5&quot;))\nprediction.loadModel()\n\npredictions, probabilities = prediction.predictImage(os.path.join(execution_path, &quot;1.jpg&quot;), result_count=5 )\nfor eachPrediction, eachProbability in zip(predictions, probabilities):\n    print(eachPrediction + &quot; : &quot; + eachProbability)`, `37014778661234040000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> imageai<span class=\"token punctuation\">.</span>Prediction <span class=\"token keyword\">import</span> ImagePrediction\n<span class=\"token keyword\">import</span> os\nexecution_path <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>getcwd<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\nprediction <span class=\"token operator\">=</span> ImagePrediction<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>setModelTypeAsResNet<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>setModelPath<span class=\"token punctuation\">(</span>os<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span>execution_path<span class=\"token punctuation\">,</span> <span class=\"token string\">\"resnet50_weights_tf_dim_ordering_tf_kernels.h5\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>loadModel<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\npredictions<span class=\"token punctuation\">,</span> probabilities <span class=\"token operator\">=</span> prediction<span class=\"token punctuation\">.</span>predictImage<span class=\"token punctuation\">(</span>os<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span>execution_path<span class=\"token punctuation\">,</span> <span class=\"token string\">\"1.jpg\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> result_count<span class=\"token operator\">=</span><span class=\"token number\">5</span> <span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">for</span> eachPrediction<span class=\"token punctuation\">,</span> eachProbability <span class=\"token keyword\">in</span> <span class=\"token builtin\">zip</span><span class=\"token punctuation\">(</span>predictions<span class=\"token punctuation\">,</span> probabilities<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>eachPrediction <span class=\"token operator\">+</span> <span class=\"token string\">\" : \"</span> <span class=\"token operator\">+</span> eachProbability<span class=\"token punctuation\">)</span></code></pre></div>\n<p>我们可以在本地进行初步运行，指定图片<code class=\"language-text\">1.jpg</code>为下图时：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855876021-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>可以得到结果：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">convertible  :  52.459537982940674\nsports_car  :  37.61286735534668\npickup  :  3.175118938088417\ncar_wheel  :  1.8175017088651657\nminivan  :  1.7487028613686562</code></pre></div>\n<h2 id=\"让-imageai-上云（部署到-serverless-架构上）\"><a href=\"#%E8%AE%A9-imageai-%E4%B8%8A%E4%BA%91%EF%BC%88%E9%83%A8%E7%BD%B2%E5%88%B0-serverless-%E6%9E%B6%E6%9E%84%E4%B8%8A%EF%BC%89\" aria-label=\"让 imageai 上云（部署到 serverless 架构上） permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>让 ImageAI 上云（部署到 Serverless 架构上）</h2>\n<p>通过上面的 Demo，我们可以考虑将这个模块部署到云函数：</p>\n<ul>\n<li>首先，在本地创建一个 Python 的项目：<code class=\"language-text\">mkdir imageDemo</code></li>\n<li>新建文件：<code class=\"language-text\">vim index.py</code></li>\n<li>\n<p>根据云函数的一些特殊形式，我们对 Demo 进行部分改造</p>\n<ul>\n<li>将初始化的代码放在外层；</li>\n<li>将预测部分当做触发所需要执行的部分，放在入口方法中（此处是 main_handler）;</li>\n<li>云函数与 API 网关结合对二进制文件支持并不是十分的友善，所以此处通过 base64 进行图片传输；</li>\n<li>入参定为<code class=\"language-text\">{&quot;picture&quot;: 图片的 base64}</code>，出参定为：<code class=\"language-text\">{&quot;prediction&quot;: 图片分类的结果}</code></li>\n</ul>\n</li>\n</ul>\n<p>实现的代码如下：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"92976352063236160000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`from imageai.Prediction import ImagePrediction\nimport os, base64, random\n\nexecution_path = os.getcwd()\n\nprediction = ImagePrediction()\nprediction.setModelTypeAsSqueezeNet()\nprediction.setModelPath(os.path.join(execution_path, &quot;squeezenet_weights_tf_dim_ordering_tf_kernels.h5&quot;))\nprediction.loadModel()\n\n\ndef main_handler(event, context):\n    imgData = base64.b64decode(event[&quot;body&quot;])\n    fileName = '/tmp/' + &quot;&quot;.join(random.sample('zyxwvutsrqponmlkjihgfedcba', 5))\n    with open(fileName, 'wb') as f:\n        f.write(imgData)\n    resultData = {}\n    predictions, probabilities = prediction.predictImage(fileName, result_count=5)\n    for eachPrediction, eachProbability in zip(predictions, probabilities):\n        resultData[eachPrediction] =  eachProbability\n    return resultData`, `92976352063236160000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> imageai<span class=\"token punctuation\">.</span>Prediction <span class=\"token keyword\">import</span> ImagePrediction\n<span class=\"token keyword\">import</span> os<span class=\"token punctuation\">,</span> base64<span class=\"token punctuation\">,</span> random\n\nexecution_path <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>getcwd<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\nprediction <span class=\"token operator\">=</span> ImagePrediction<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>setModelTypeAsSqueezeNet<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>setModelPath<span class=\"token punctuation\">(</span>os<span class=\"token punctuation\">.</span>path<span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span>execution_path<span class=\"token punctuation\">,</span> <span class=\"token string\">\"squeezenet_weights_tf_dim_ordering_tf_kernels.h5\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\nprediction<span class=\"token punctuation\">.</span>loadModel<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    imgData <span class=\"token operator\">=</span> base64<span class=\"token punctuation\">.</span>b64decode<span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">[</span><span class=\"token string\">\"body\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n    fileName <span class=\"token operator\">=</span> <span class=\"token string\">'/tmp/'</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span>random<span class=\"token punctuation\">.</span>sample<span class=\"token punctuation\">(</span><span class=\"token string\">'zyxwvutsrqponmlkjihgfedcba'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">with</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span>fileName<span class=\"token punctuation\">,</span> <span class=\"token string\">'wb'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> f<span class=\"token punctuation\">:</span>\n        f<span class=\"token punctuation\">.</span>write<span class=\"token punctuation\">(</span>imgData<span class=\"token punctuation\">)</span>\n    resultData <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    predictions<span class=\"token punctuation\">,</span> probabilities <span class=\"token operator\">=</span> prediction<span class=\"token punctuation\">.</span>predictImage<span class=\"token punctuation\">(</span>fileName<span class=\"token punctuation\">,</span> result_count<span class=\"token operator\">=</span><span class=\"token number\">5</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">for</span> eachPrediction<span class=\"token punctuation\">,</span> eachProbability <span class=\"token keyword\">in</span> <span class=\"token builtin\">zip</span><span class=\"token punctuation\">(</span>predictions<span class=\"token punctuation\">,</span> probabilities<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        resultData<span class=\"token punctuation\">[</span>eachPrediction<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span>  eachProbability\n    <span class=\"token keyword\">return</span> resultData</code></pre></div>\n<p>创建完成之后，下载所依赖的模型：</p>\n<ul>\n<li>SqueezeNet（文件大小：4.82 MB，预测时间最短，精准度适中）</li>\n<li>ResNet50 by Microsoft Research （文件大小：98 MB，预测时间较快，精准度高）</li>\n<li>InceptionV3 by Google Brain team （文件大小：91.6 MB，预测时间慢，精度更高）</li>\n<li>DenseNet121 by Facebook AI Research （文件大小：31.6 MB，预测时间较慢，精度最高）</li>\n</ul>\n<p>因为我们仅用于测试，所以选择一个比较小的模型就可以：<code class=\"language-text\">SqueezeNet</code>：</p>\n<p>在官方文档复制模型文件地址：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855875322-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>使用<code class=\"language-text\">wget</code>直接安装：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">wget https://github.com/OlafenwaMoses/ImageAI/releases/download/1.0/squeezenet_weights_tf_dim_ordering_tf_kernels.h5</code></pre></div>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855876947-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>接下来，进行依赖安装：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855875167-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>由于腾讯云 Serveless 产品，在 Python Runtime 中还不支持在线安装依赖，所以需要手动打包依赖，并且上传。在 Python 的各种依赖库中，有很多依赖可能有编译生成二进制文件的过程，这就会导致不同环境下打包的依赖无法通用。</p>\n<p>所以，最好的方法就是通过对应的操作系统 + 语言版本进行打包。我们就是在 CentOS+Python3.6 的环境下进行依赖打包。</p>\n<p>对于很多 MacOS 用户和 Windows 用户来说，这确实不是一个很友好的过程，所以为了方便大家使用，我在 Serverless 架构上做了一个在线打包依赖的工具，所以可以直接用该工具进行打包：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855875139-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855877247-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>生成压缩包之后，直接下载解压，并且放到自己的项目中即可：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855875175-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>最后一步，创建<code class=\"language-text\">serverless.yaml</code></p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">imageDemo:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: imageDemo\n    codeUri: ./\n    handler: index.main_handler\n    runtime: Python3.6\n    region: ap-guangzhou\n    description: 图像识别 / 分类 Demo\n    memorySize: 256\n    timeout: 10\n    events:\n      - apigw:\n          name: imageDemo_apigw_service\n          parameters:\n            protocols:\n              - http\n            serviceName: serverless\n            description: 图像识别 / 分类 DemoAPI\n            environment: release\n            endpoints:\n              - path: /image\n                method: ANY</code></pre></div>\n<p>完成之后，执行<code class=\"language-text\">sls --debug</code>部署，部署过程中会有扫码登陆，登陆之后等待即可，完成之后，就可以看到部署地址。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855875151-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<h2 id=\"基本测试\"><a href=\"#%E5%9F%BA%E6%9C%AC%E6%B5%8B%E8%AF%95\" aria-label=\"基本测试 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>基本测试</h2>\n<p>通过 Python 语言进行测试，接口地址就是刚才复制的 +<code class=\"language-text\">/image</code>，例如：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"28084795796436836000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import json\nimport urllib.request\nimport base64\n\nwith open(&quot;1.jpg&quot;, 'rb') as f:\n    base64_data = base64.b64encode(f.read())\n    s = base64_data.decode()\n\nurl = 'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'\n\nprint(urllib.request.urlopen(urllib.request.Request(\n    url = url,\n    data= json.dumps({'picture': s}).encode(&quot;utf-8&quot;)\n)).read().decode(&quot;utf-8&quot;))`, `28084795796436836000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> json\n<span class=\"token keyword\">import</span> urllib<span class=\"token punctuation\">.</span>request\n<span class=\"token keyword\">import</span> base64\n\n<span class=\"token keyword\">with</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"1.jpg\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'rb'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> f<span class=\"token punctuation\">:</span>\n    base64_data <span class=\"token operator\">=</span> base64<span class=\"token punctuation\">.</span>b64encode<span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    s <span class=\"token operator\">=</span> base64_data<span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\nurl <span class=\"token operator\">=</span> <span class=\"token string\">'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'</span>\n\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>urllib<span class=\"token punctuation\">.</span>request<span class=\"token punctuation\">.</span>urlopen<span class=\"token punctuation\">(</span>urllib<span class=\"token punctuation\">.</span>request<span class=\"token punctuation\">.</span>Request<span class=\"token punctuation\">(</span>\n    url <span class=\"token operator\">=</span> url<span class=\"token punctuation\">,</span>\n    data<span class=\"token operator\">=</span> json<span class=\"token punctuation\">.</span>dumps<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">'picture'</span><span class=\"token punctuation\">:</span> s<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>通过网络搜索一张图片：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202057/1588855876964-fcf4a0195d5841d38cf234a508a87684.png\" alt=\"Serverless 实战：用20行Python代码轻松搞定图像分类和预测\"></p>\n<p>得到运行结果：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"14945199702990686000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`{\n\t&quot;prediction&quot;: {\n\t\t&quot;cheetah&quot;: 83.12643766403198,\n\t\t&quot;Irish_terrier&quot;: 2.315458096563816,\n\t\t&quot;lion&quot;: 1.8476998433470726,\n\t\t&quot;teddy&quot;: 1.6655176877975464,\n\t\t&quot;baboon&quot;: 1.5562783926725388\n\t}\n}`, `14945199702990686000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">\"prediction\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token property\">\"cheetah\"</span><span class=\"token operator\">:</span> <span class=\"token number\">83.12643766403198</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token property\">\"Irish_terrier\"</span><span class=\"token operator\">:</span> <span class=\"token number\">2.315458096563816</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token property\">\"lion\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1.8476998433470726</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token property\">\"teddy\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1.6655176877975464</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token property\">\"baboon\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1.5562783926725388</span>\n\t<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>通过这个结果，我们可以看到图片的基础分类 / 预测已经成功了，为了证明这个接口的时延情况，可以对程序进行基本改造：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"39633697919641040000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import urllib.request\nimport base64, time\n\nfor i in range(0,10):\n    start_time = time.time()\n    with open(&quot;1.jpg&quot;, 'rb') as f:\n        base64_data = base64.b64encode(f.read())\n        s = base64_data.decode()\n\n    url = 'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'\n\n    print(urllib.request.urlopen(urllib.request.Request(\n        url = url,\n        data= json.dumps({'picture': s}).encode(&quot;utf-8&quot;)\n    )).read().decode(&quot;utf-8&quot;))\n\n    print(&quot;cost: &quot;, time.time() - start_time)`, `39633697919641040000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> urllib<span class=\"token punctuation\">.</span>request\n<span class=\"token keyword\">import</span> base64<span class=\"token punctuation\">,</span> time\n\n<span class=\"token keyword\">for</span> i <span class=\"token keyword\">in</span> <span class=\"token builtin\">range</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    start_time <span class=\"token operator\">=</span> time<span class=\"token punctuation\">.</span>time<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">with</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"1.jpg\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'rb'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> f<span class=\"token punctuation\">:</span>\n        base64_data <span class=\"token operator\">=</span> base64<span class=\"token punctuation\">.</span>b64encode<span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        s <span class=\"token operator\">=</span> base64_data<span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n    url <span class=\"token operator\">=</span> <span class=\"token string\">'http://service-9p7hbgvg-1256773370.gz.apigw.tencentcs.com/release/image'</span>\n\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>urllib<span class=\"token punctuation\">.</span>request<span class=\"token punctuation\">.</span>urlopen<span class=\"token punctuation\">(</span>urllib<span class=\"token punctuation\">.</span>request<span class=\"token punctuation\">.</span>Request<span class=\"token punctuation\">(</span>\n        url <span class=\"token operator\">=</span> url<span class=\"token punctuation\">,</span>\n        data<span class=\"token operator\">=</span> json<span class=\"token punctuation\">.</span>dumps<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">'picture'</span><span class=\"token punctuation\">:</span> s<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"cost: \"</span><span class=\"token punctuation\">,</span> time<span class=\"token punctuation\">.</span>time<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> start_time<span class=\"token punctuation\">)</span></code></pre></div>\n<p>输出结果：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  2.1161561012268066\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.1259253025054932\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.3322770595550537\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.3562259674072266\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.0180821418762207\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.4290671348571777\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.5917718410491943\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.1727900505065918\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  2.962592840194702\n{&quot;prediction&quot;:{&quot;cheetah&quot;:83.12643766403198,&quot;Irish_terrier&quot;:2.315458096563816,&quot;lion&quot;:1.8476998433470726,&quot;teddy&quot;:1.6655176877975464,&quot;baboon&quot;:1.5562783926725388}}\ncost:  1.2248001098632812</code></pre></div>\n<p>通过上面一组数据，我们可以看到整体的耗时基本控制在 1-1.5 秒之间。</p>\n<p>当然，如果想要对接口性能进行更多的测试，例如通过并发测试来看并发情况下接口性能表现等。</p>\n<p>至此，我们通过 Serveerless 架构搭建的 Python 版本的图像识别 / 分类小工具做好了。</p>\n<h2 id=\"总结\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>Serverless 架构下进行人工智能相关的应用可以是说是非常多的，本文是通过一个已有的依赖库，实现一个图像分类 / 预测的接口。<code class=\"language-text\">imageAI</code>这个依赖库相对来说自由度比较高，可以根据自身需要用来定制化自己的模型。本文算是抛砖引玉，期待更多人通过 Serverless 架构部署自己的\"人工智能\" API。</p>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a></li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2020-04-23-python-pics/#%E5%85%A5%E9%97%A8-imageai\">入门 ImageAI</a></li>\n<li><a href=\"/best-practice/2020-04-23-python-pics/#%E8%AE%A9-imageai-%E4%B8%8A%E4%BA%91%EF%BC%88%E9%83%A8%E7%BD%B2%E5%88%B0-serverless-%E6%9E%B6%E6%9E%84%E4%B8%8A%EF%BC%89\">让 ImageAI 上云（部署到 Serverless 架构上）</a></li>\n<li><a href=\"/best-practice/2020-04-23-python-pics/#%E5%9F%BA%E6%9C%AC%E6%B5%8B%E8%AF%95\">基本测试</a></li>\n<li><a href=\"/best-practice/2020-04-23-python-pics/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"2aa8b500-4a95-5ecc-815d-33efd194aba4","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589276816391-NLP.png","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-24T00:00:00.000Z","title":"Serverless 实战：如何结合 NLP 实现文本摘要和关键词提取？","description":"提取关键词的好处是可以让文章与文章之间产生关联，同时也可以让读者通过关键词快速定位到和该关键词相关的文章内容","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["Serverless"],"keywords":"Serverless 全局变量组件,Serverless 单独部署组件,Serverless Component","outdated":true},"wordCount":{"words":214,"sentences":35,"paragraphs":35},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-24-nlp.md","fields":{"slug":"/best-practice/2020-04-24-nlp/","keywords":["python","serverless","self","sentence","sentences","mark","weightPos","摘要","关键词","提取"]}},"nextBlog":{"id":"6e8a71a3-426e-5101-94db-bd5b1ef4d1ec","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589274422875-code.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-22T00:00:00.000Z","title":"基于 Serverless 架构的编程学习小工具","description":"这是一个基于 Serverless 架构的编程学习 App，它不仅仅可以让你学习编程，还能实现代码的编写与运行","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","程序员"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":null},"wordCount":{"words":281,"sentences":50,"paragraphs":50},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-22-coding-learing.md","fields":{"slug":"/best-practice/2020-04-22-coding-learing/","keywords":["go","python","serverless","函数计算","云函数","serverlesscloud","Serverless","req","函数","event"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"a93bc1e0-585b-5ae5-be5c-4f850ce95080","previousBlogId":"2aa8b500-4a95-5ecc-815d-33efd194aba4","nextBlogId":"6e8a71a3-426e-5101-94db-bd5b1ef4d1ec"}}}