如何将机器学习模型转移到产品中

针对于特定问题(例如自然语言处理,即 NLP,或图像识别)的深度学习模型开发、训练和调参,需要耗费时间与资源。这通常还包括使用功能强大的处理器来训练大型数据集上的模型。然而,一旦模型成功运作,彼时使用它来对新数据生成预测就会更简单,计算成本也会更低。当下唯一的困难是将模型从其开发环境转移到应用程序产品中。

本篇指南将会指导您创建一个简单的,使用机器学习来识别手写体数字的 Flask API。该 API 将在著名的 MNIST 数据集上训练一个简单深度学习模型。

事前准备

  1. 熟练掌握我们的入门指南,并完成设置 Linode 主机名与时区的步骤。
  2. 本指南将尽可能地sudo。完成 “保护服务器” 的部分以创建标准用户帐户,加强 SSH 访问并删除不必要的网络服务。
  3. 更新系统: sudo apt-get update && sudo apt-get upgrade

本指南的示例中使用的系统版本是 Ubuntu 16.04。根据你的具体发行版本可能需要对相应命令进行修改。本指南中的脚本是用 Python 3 编写的,但同样适用于 Python 2。

设置 Python 虚拟环境

您将使用 Python 来创建模型并将模型部署到 Flask API。为每个目标设置虚拟环境是个好主意,这样您对 Python 配置所做的任何更改都不会影响系统的其余部分。

  1. 下载并安装 Miniconda,这是 Anaconda 的轻量级版本。按照终端中的说明操作,并允许 Anaconda 将 PATH 位置添加到 .bashrcwget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh source .bashrc
  2. 创建并激活新的 Python 虚拟环境: conda create -n deeplearning python source activate deeplearning 如果这些命令成功了,则终端提示符将以(deeplearning)开头。
  3. 在虚拟环境中安装依赖项: conda install keras tensorflow h5py pillow flask numpy

如果您想检验该模型,可能需要使用 Jupyter 笔记本。要获取更多相关的详细信息,请参阅我们的安装 Jupyter Notebook Server 指南。

准备一个模型

在大型数据集上训练复杂模型,这种事通常是在具有强大 GPU(Graphical Processing Units,图形处理单元)的专用机器上完成的。为了专注于部署过程,本指南将在一个可管理的数据集上快速构建一个简单的模型,以便即使在笔记本电脑或基本的 Linode 上也可以快速训练。

MNIST 数据库

训练计算机以识别手写体数字,这是早期机器学习的一项重要任务。许多组织(包括美国邮政局)都使用这种分类器来自动输入和处理信息。用于此任务的一个著名数据集就是 MNIST,其包含 70,000 个手写数字图像(为了形成对比,我们可以看看 ImageNet 数据库,它通常用于机器学习应用程序,其中具有超过 1000 万个图像)。每个 28x28 像素图像由一个已经过预处理和标记的数字组成。有关 MNIST 的更多信息,请访问其官方网站

从简单的线性分类器,到复杂的神经网络,在 MNIST 上已经有许多不同种类的模型进行了训练。目前,最好的模型能够实现仅 0.21% 的错误率。本指南将使用简单的 CNN(Convolutional Neural Network,卷积神经网络)进行训练,其精确度可达到约 97%。

使用 Keras 创建深度学习模型

Keras 是 Python 的一个深度学习库。它提供了一个面向对象的接口,我们可以通过它使用各种深度学习框架,包括 Theano 和 Tensorflow。

由于开发与训练深度学习模型超出了本教程的范围,因此我们不对下面的代码进行解释。该模型是 Elite Data Science 优秀教程中示例的一个简化版本。如果您没有深度学习的背景,但有兴趣了解更多知识,那么您可以完成该教程,然后跳到本指南的 Flask API 部分。

注意:这个模型很简单,数据集也足够小,所以该脚本可以在 Linode 或本地机器上运行。但是,使用没有 GPU 的计算机仍然需要至少十分钟。如果您希望跳过此步骤,可以通过运行以下命令下载预先训练过的模型

wget https://github.com/linode/docs-scripts/raw/master/hosted_scripts/my_model.h5

较旧版本的 Keras 需要在预训练模型中删除优化器权重。如果从 GitHub 下载预训练模型,则下面这一脚本会检查并删除优化器权重。

import h5py
with h5py.File('my_model.h5', 'r+') as f:
if 'optimizer_weights' in f.keys():
del f['optimizer_weights']
f.close()

1. 为模型创建目录: mkdir ~/models && cd ~/models

2. 创建一个 Python 脚本用以构建和训练模型:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
from keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(X_train.shape[0],1,28,28)
X_test  = X_test.reshape(X_test.shape[0],1,28,28)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255

Y_train = np_utils.to_categorical(y_train, 10)
Y_test = np_utils.to_categorical(y_test, 10)

model = Sequential()

model.add(Convolution2D(32,(3,3),activation='relu',input_shape=(1,28,28),dim_ordering='th'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

model.fit(X_train, Y_train,
          batch_size=32, nb_epoch=5, verbose=1)

model.save('my_model.h5')

3. 运行脚本: python ./mnist_model.py

从 pip 或 conda 安装,可能会出现如下所示的警告消息,这意味着从源安装可以提供更卓越的性能。

The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.

如果脚本能够成功执行,您应该可以在 models 目录中看到 my_model.h5 这一文件。Keras 中的 model.save() 命令可以让您保存模型架构和训练得到的权重。

Flask API

一旦模型被训练完成,之后使用它来生成预测就会简单得多。在本节中,您将使用 Flask 构建一个简单的 Python API。该 API 将具有单个端点:它将接受附加了图像的 POST 请求,然后使用您在上一节中保存的模型来识别图像中的手写数字。

1. 为 Flask API 创建一个目录: sudo mkdir -p /var/www/flaskapi/flaskapi && cd /var/www/flaskapi/flaskapi

2. 将预先训练的模型复制到 Flask 应用程序的根目录: sudo cp ~/models/my_model.h5 /var/www/flaskapi/flaskapi

3. 在文本编辑器中创建 /var/www/flaskapi/flaskapi/__init__.py 文件并添加以下内容:

from flask import Flask, jsonify, request
import numpy as np
import PIL
from PIL import Image
from keras.models import load_model

app = Flask(__name__)

model = load_model('/var/www/flaskapi/flaskapi/my_model.h5')

@app.route('/predict', methods=["POST"])
def predict_image():
        # Preprocess the image so that it matches the training input
        image = request.files['file']
        image = Image.open(image)
        image = np.asarray(image.resize((28,28)))
        image = image.reshape(1,1,28,28)

        # Use the loaded model to generate a prediction.
        pred = model.predict(image)

        # Prepare and send the response.
        digit = np.argmax(pred)
        prediction = {'digit':int(digit)}
        return jsonify(prediction)

if __name__ == "__main__":
        app.run()

这次,您需要从 Keras 导入的唯一模块就是 load_model,用它来读取 my_model.h5 并加载模型和权重。加载模型后,predict() 函数将为 0-9 中的每个数字生成一组概率,指示图像中的数字与每个数字匹配的可能性。使用 Numpy 的库函数 argmax 可以返回概率最高的数字:该模型认为这一数字是最可能匹配的。

模型的输入,其格式必须与训练中使用的图像完全相同。训练图像是 28x28 像素的灰度图像,表示为具有形状(1,28,28)的浮点型(Float)阵列(彩色图像将会是<3,28,28>)。这意味着您提交给模型的任何图像都必须精确调整为此形状。此预处理可以在客户端或服务器端完成,但为简单起见,上面示例是在 API 中进行处理。

安装 mod_wsgi

Apache 模块通常是随着 Apache 的系统一起安装的。但 mod_wsgi 可以在 Python 中安装,以使用合适的虚拟环境。

1. 安装 Apache 和开发头文件: sudo apt install apache2-dev apache2

2. 安装 mod_wsgi,作为 Apache 的 Python 模块:

wget https://pypi.python.org/packages/aa/43/f851abaad631aee69206e29cebf9f8bf0ddb9c22dbd6e583f1f8f44e6d43/mod_wsgi-4.5.20.tar.gz
tar -xvf mod_wsgi-4.5.20.tar.gz
cd mod_wsgi-4.5.20
python setup.py install

3. 使用 mod_wsgi-express 查找安装路径: mod_wsgi-express module-config 其输出应类似于: LoadModule wsgi_module "/home/linode/miniconda3/envs/deeplearning/lib/python3.6/site-packages/mod_wsgi-4.5.20-py3.6-linux-x86_64.egg/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so" WSGIPythonHome "/home/linode/miniconda3/envs/deeplearning"

4. 在 Apache 的 mods-available目录中创建一个 wsgi.load 文件。直接从上面的 LoadModule 中复制指令并将其粘贴到文件中: /etc/apache2/mods-available/wsgi.load1 LoadModule wsgi_module "/home/linode/miniconda3/envs/deeplearning/lib/python3.6/site-packages/mod_wsgi-4.5.20-py3.6-linux-x86_64.egg/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so"

5. 启用 moda2enmod wsgi

给 Flask API 设置虚拟主机

1. 使用您的应用设置创建一个文件 flaskapi.wsgi

#!/usr/bin/python
import sys
sys.path.insert(0,"/var/www/flaskapi/")

from flaskapi import app as application

2. 为您的应用配置虚拟主机。在 Apache 的 sites-available 目录中创建 flaskapi.conf 文件,并添加以下内容,替换其中的 example.com 为您的 Linode 的公共 IP 地址。对于该 WSGIDaemonProcess 指令,将 Python 主路径设置为 WSGIPythonHome 下面 mod_wsgi-express module-configunder 的输出:

<Directory /var/www/flaskapi/flaskapi>
  Require all granted
</Directory>
<VirtualHost *:80>
  ServerName example.com
  ServerAdmin admin@example.com
  WSGIDaemonProcess flaskapi python-home=/home/linode/miniconda3/envs/deeplearning
  WSGIScriptAlias / /var/www/flaskapi/flaskapi/flaskapi.wsgi
  ErrorLog /var/www/html/example.com/logs/error.log
  CustomLog /var/www/html/example.com/logs/access.log combined
</VirtualHost>

3. 创建logs目录: sudo mkdir -p /var/www/html/example.com/logs

4. 激活新站点并重新启动Apache:

sudo a2dissite 000-default.conf
sudo a2ensite flaskapi.conf
sudo systemctl restart apache2

测试 API

现在,您的 API 端点应该已准备好了,可以接受附加了图像的 POST 请求。理论上,这个 API 应该能够识别任何孤立的手写数字的图像。但是,为了获得准确的预测,MNIST 研究人员所使用的预处理步骤应该复制到每个提交给模型的图像上。这包括计算像素密度的中心并使用它来使图像中的数字居中,以及应用抗锯齿。为了快速测试 API,您可以使用 curl 命令从 MNIST 测试集中提交图像。

1. 右键单击并将下面的图像下载到本地计算机上:

2. 在本地计算机上,使用 curl 来 POST 图像到 API。将 IP 地址替换为您的 Linode 的公共 IP 地址,并提供下载图像的绝对路径来代替 /path/to/7.pngcurl -F 'file=@/path/to/7.png' 192.0.2.0/predict 如果成功了,您将收到正确识别图像中数字的 JSON 响应: { 'digit' : 7 } 首次请求可能需要花一些时间,因为 mod_wsgi 使用延迟加载 Flask 应用程序。

下一步

大多数生机器学习产品解决方案涉及到比本指南中所示的更长的流水线。例如,您可以添加带有深度学习分类器的不同端点,以识别较大图像中的数字。然后,每个检测到的数字将传递到 /predict 端点,使您的应用程序可以解释一系列手写体数字,例如电话号码。

本指南中实现的 API 也缺少实际应用程序所需的许多功能,包括错误处理和处理批量图像请求。为了使该服务更有用,MNIST 使用的完整预处理流程应该应用于每个图像。

此外,提交给 API 的图像可用作数据源,以进一步训练和优化您的模型。在这种情况下,您可以对 API 进行配置,以将每个提交的图像以及模型的预测复制到数据库,以供日后分析。如果您对这些主题感兴趣,请参阅更多信息中的链接。

更多信息

有关此主题的其他信息,您可能需要参考以下资源。虽然提供这些资料是希望它们有用,但请注意了,我们无法保证外部托管材料的准确性或及时性。

本文的版权归 StoneDemo 所有,如需转载请联系作者。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

OpenCV人脸识别之二:模型训练

本系列人脸识别文章用的是opencv2,最新版的opencv3.2的代码请参考文章: OpenCV之识别自己的脸——C++源码放送(请在上一篇文章末尾查看) 在...

1.3K6
来自专栏用户2442861的专栏

caffe python 图片训练识别 实例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haluoluo211/article/details...

5522
来自专栏机器之心

资源 | TensorFlow极简教程:创建、保存和恢复机器学习模型

选自Github 机器之心编译 参与:Jane W、李泽南 TensorFlow 是一个由谷歌发布的机器学习框架,在这篇文章中,我们将阐述 TensorFlow...

2707
来自专栏生信技能树

【r<-ROC|包】分析与可视化ROC——plotROC、pROC

在【r<-绘图|ROC】ROC的计算与绘制这篇文章中我讲了ROC曲线的本质以及如何计算和绘制ROC曲线。注意,我这里谈到的ROC并未曾涉及机器学习模型的拟合与预...

1902
来自专栏机器之心

教程 | TensorFlow 官方解读:如何在多系统和网络拓扑中构建高性能模型

选自Tensorflow 机器之心编译 参与:黄玉胜、黄小天 这个文档和附带的脚本详细介绍了如何构建针对各种系统和网络拓扑的高性能可拓展模型。这个技术在本文档中...

35811
来自专栏BestSDK

MXNet Scala发布图像分类API|附使用教程

这次发布的 Scala,里面的推理应用程序致力于优化开发者体验。Scala 是一个通用目的程序语言,支持功能性编程和较强的静态类型系统,它被用于平台的高度分布式...

1327
来自专栏北京马哥教育

手把手教你用 1 行命令实现人脸识别

? 人脸识别很难吗? -- Kangvcar 本文导航 ◈ 环境要求00% ◈ 环境搭建03% ◈ 实现人脸识别19% ◈ 示例一(1 行命令实现人脸识别):...

3336
来自专栏利炳根的专栏

学习笔记TF066 : TensorFlow 移动端应用,iOS、Android系统实践

移动端应用原理。移动端、嵌入式设备应用深度学习方式,一模型运行在云端服务器,向服务器发送请求,接收服务器响应;二在本地运行模型,PC训练模型,放到移动端预测。向...

8360
来自专栏分子生物和分子模拟计算

Molecular docking study of antibody-ligand complex

1002
来自专栏AI科技大本营的专栏

实战 | 手把手教你用苹果CoreML实现iPhone的目标识别

在WWDC 2017上,苹果首次公布了机器学习方面的动作。iOS系统早已支持Machine Learning 和 Computer Vision ,但这次苹果提...

7298

扫码关注云+社区