【背景】

模型训练好了之后怎么部署在线上,让大家直接通过网络就能使用?网络上给出的一般方案就是 Flask + Nginx + uWSGI,当然这里的 nginx 可以替换成类似 Apache ,Flask 也可以考虑用 Django,但就简单、高效而言还是首先 Flask + Nginx + uWSGI。Nginx 在这一方案中主要是起反向代理服务器的作用,我暂且只是做一个小实验,所以没将 Nginx 考虑进来,直接拿 Flask + uWSGI 开刷。简单说明一下什么是 Flask?什么又是 uWSGI?

如果你想用 Python 语言快速实现一个网站 或 Web 服务,你选 Flask 就对了。Flask 是一个使用 Python 编写的轻量级 Web 应用框架,较其它同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合 MVC 模式进行开发,一个小型的研发团队在短时间内就可以完成功能丰富的中小型网站或 Web 服务的实现。在回答 uWSGI 是什么之前,先得了解一下 WSGI 是什么?WSGI 全称是 Web Server Gateway Interface,或者 Python Web Server Gateway Interface,是为 Python 语言定义的描述 Web 服务器(web server) 如何与Web 应用程序(web application) 通信的一种规范。Flask就是运行在 WSGI 协议之上的 web 框架,它主要是一个 Web Application,但同时也自带 WSGI Server。话虽如此,但 Flask 框架只是简单实现了WSGI server,一般只用于调试,真要在生产环境下用最好还是用更专业的 WSGI server。现在可以回答 uWSGI 是什么了,uWSGI 是一个 Web 服务器,它实现了 WSGI 、uwsgi(同 WSGI 一样,是一种通信协议)、http 等协议。

【安装】

我的环境:

Ubuntu 16.04

Python 2.7

#flask

pip install flask --user

#uwsgi

你可以使用 pip 安装,也可以使用源码安装,反正都比较简单。我是使用的源码安装。

-- pip 安装 --

pip install uwsgi --user

-- 源码安装 --

wget https://files.pythonhosted.org/packages/e7/1e/3dcca007f974fe4eb369bf1b8629d5e342bb3055e2001b2e5340aaefae7a/uwsgi-2.0.18.tar.gz

tar -xzf uwsgi-2.0.18.tar.gz

python setup.py build

make #会生成一个 uwsgi 二进制文件

cp uwsgi /usr/bin #将二进制文件 copy 到一个 写入在$PATH 环境变量中的公共目录下

【配置】

这里配置主要就是针对 uwsgi 进行参数设置,首先我新建了一个叫saas 的项目目录,在目录下新建一个 wsgi.ini 文件。

[uwsgi]
#允许主进程的存在,由它来管理其它进程,其它 uwsgi 进程都是訪 master 进程的子进程,如果 kill 掉这个 master 进程,相当于重启所有的 uwsgi 进程.
master=true
#项目 运行目录,在 app 加载前切换到訪目录
chdir=/home/zuosi/saas
#因为我现在只用到 uwsgi 和 flask,所以这里就用 http 就行了,不要用啥 socket 之类的.
http=127.0.0.1:6789
#要加载的WSGI 模型及应用名称
module=saas:app
logto=/home/zuosi/saas/wsgi.log
#开启的工作进程数 量,processes 同 workers 是一个意思
processes=4
#代码有更新的时候自动重新加载,这个在开发的时候很有用
py-autoreload=true
#状态检查服务
stats=127.0.0.1:10000

【应用】

在启动 flask 之前先创建一个简单的 flask 应用。

from flask import Flask
import cv2#要创建的 flask 实例的名字,注意与 wsgi.ini 中保持一致
app = Flask(__name__) @app.route('/test')
def hello_world():return "hello, world"

将訪文件保存 wsgi.py,即模块的名字,注意与 wsgi.ini 中设置的名字保持一致。现在启动 uwsgi 试试。

$ uwsgi -i wsgi.init 
[uWSGI] getting INI configuration from wsgi.ini

查看wsgi.log 日志文件会发现如下信息。

*** Starting uWSGI 2.0.18 (64bit) on [Mon Nov  4 23:26:27 2019] ***
compiled with version: 5.4.0 20160609 on 02 November 2019 04:58:49
os: Linux-4.4.0-142-generic #168-Ubuntu SMP Wed Jan 16 21:00:45 UTC 2019
nodename: ky-cs-18
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 12
current working directory: /home/zuosi/saas
detected binary path: /home/zuosi/.local/bin/uwsgi
chdir() to /home/zuosi/saas
your processes number limit is 127269
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on 127.0.0.1:6789 fd 4
uwsgi socket 0 bound to TCP address 127.0.0.1:39432 (port auto-assigned) fd 3
Python version: 2.7.12 (default, Oct  8 2019, 14:14:10)  [GCC 5.4.0 20160609]
Python main interpreter initialized at 0xc6b2d0
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 364520 bytes (355 KB) for 4 cores
*** Operational MODE: preforking ***

WSGI app 0 (mountpoint='') ready in 6 seconds on interpreter 0xc6b2d0 pid: 93102 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 93102)
spawned uWSGI worker 1 (pid: 93131, cores: 1)
spawned uWSGI worker 2 (pid: 93132, cores: 1)
spawned uWSGI worker 3 (pid: 93133, cores: 1)
spawned uWSGI worker 4 (pid: 93134, cores: 1)
*** Stats server enabled on 127.0.0.1:10000 fd: 58 ***
spawned uWSGI http 1 (pid: 93135)

项目已经启动成功了。现在我们来做一下简单的测试,通过 http 访问一下 test 接口。

$ curl 127.1:6789/test
hello, world!

初步实验已经成功了,现在进入下一步,把 caffe 模型加载进来,提供一个模型 infer 的接口。

from flask import Flask
import os
import cv2
import caffecaffe.set_mode_gpu() #设置 gpu 模式
proto='deploy.prototxt'
model='my.caffemodel'
net = caffe.Net(proto, model, caffe.TEST)app = Flask(__name__)@app.route('/test')
def hello_world():return "hello, world!"#就读一个本地的测试图片再使用 caffe 模型进行 infer,打印输出结果并返回 ok
@app.route('/infer', methods=['GET'])
def infer():path = 'test.jpg'img = cv2.imread(path)data = img.transpose(2,0,1)/255.0net.blobs['data'].data[...] = dataout = net.forward()['prob']print(out.tolist())return 'ok'

重新启动一下 uwsgi,并测试 infer 接口。

$ uwsgi --ini wsgi.ini

启动没问题

$ curl 127.1:6789/infer

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">

<title>500 Internal Server Error</title>

<h1>Internal Server Error</h1>

<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

[zuosi@ky-cs-18 saas]$curl 127.1:6789/infer

curl: (52) Empty reply from server

e.......报错了,查看一下日志信息。

[pid: 93366|app: 0|req: 1/1] 127.0.0.1 () {28 vars in 296 bytes} [Mon Nov  4 23:34:15 2019] GET /infer => generated 290 bytes in 36 msecs (HTTP/1.1 500) 2 headers in 84 bytes (1 switches on core 0)
F1104 23:35:07.865353 93366 syncedmem.cpp:19] Check failed: error == cudaSuccess (3 vs. 0)  initialization error
*** Check failure stack trace: ***
    @     0x7f6cd29df5cd  google::LogMessage::Fail()
    @     0x7f6cd29e1433  google::LogMessage::SendToLog()
    @     0x7f6cd29df15b  google::LogMessage::Flush()
    @     0x7f6cd29e1e1e  google::LogMessageFatal::~LogMessageFatal()
    @     0x7f6cd3599715  caffe::SyncedMemory::MallocHost()
    @     0x7f6cd3599ae0  caffe::SyncedMemory::to_cpu()
    @     0x7f6cd359ae4d  caffe::SyncedMemory::mutable_cpu_data()
    @     0x7f6cd49d09c0  boost::python::objects::caller_py_function_impl<>::operator()()
    @     0x7f6cd24935cd  boost::python::objects::function::call()
    @     0x7f6cd24937c8  (unknown)
    @     0x7f6cd249b613  boost::python::handle_exception_impl()
    @     0x7f6cd2490999  (unknown)
    @     0x7f6d4f3792b3  PyObject_Call
    @     0x7f6d4f37a69f  PyObject_CallFunction
    @     0x7f6d4f403be9  _PyObject_GenericGetAttrWithDict
    @     0x7f6d4f3156df  PyEval_EvalFrameEx
    @     0x7f6d4f45011c  PyEval_EvalCodeEx
    @     0x7f6d4f3a64ad  (unknown)
    @     0x7f6d4f3792b3  PyObject_Call
    @     0x7f6d4f31318c  PyEval_EvalFrameEx
    @     0x7f6d4f319084  PyEval_EvalFrameEx
    @     0x7f6d4f319084  PyEval_EvalFrameEx
    @     0x7f6d4f319084  PyEval_EvalFrameEx
    @     0x7f6d4f45011c  PyEval_EvalCodeEx
    @     0x7f6d4f3a63b0  (unknown)
    @     0x7f6d4f3792b3  PyObject_Call
    @     0x7f6d4f3ed46c  (unknown)
    @     0x7f6d4f3792b3  PyObject_Call
    @     0x7f6d4f39a535  (unknown)
    @     0x7f6d4f3792b3  PyObject_Call
    @     0x7f6d4f44f547  PyEval_CallObjectWithKeywords
    @           0x47c711  python_call
DAMN ! worker 4 (pid: 93366) died, killed by signal 6 :( trying respawn ...

Respawned uWSGI worker 4 (new pid: 93381)

报了 CUDA 也就是 GPU 方面的错。

好,开始排错。我试着将 caffe设置成 cpu 模式,将 caffe.set_mode_gpu()改为 caffe.set_mode_cpu(),重新测试。

curl 127.1:6789/infer

ok

测试通过,打印 infer 结果也没有问题,真是 GPU 的锅?别这么快下结论。我将 caffe 的模式改回 GPU,同时对 wsgi.ini参数进行修改,master 改为 false,也就是不允许 master 进程。

uwsgi]
#允许主进程的存在,由它来管理其它进程,其它 uwsgi 进程都是訪 master 进程的子进程,如果 kill 掉这个 master 进程,相当于重启所有的 uwsgi 进程.
master=false
#项目 运行目录,在 app 加载前切换到訪目录
chdir=/home/zuosi/saas
#因为我现在只用到 uwsgi 和 flask,所以这里就用 http 就行了,不要用啥 socket 之类的.
http=127.0.0.1:6789
#要加载的WSGI 模型及应用名称
module=saas:app
logto=/home/zuosi/saas/wsgi.log
#开启的工作进程数 量,processes 同 workers 是一个意思
processes=4
#代码有更新的时候自动重新加载,这个在开发的时候很有用
py-autoreload=true
#状态检查服务
stats=127.0.0.1:10000

再来测试一下,这次连着测试100次。

$for i in `seq 1 100`;do curl 127.1:6789/infer;echo -e "\t";done
curl: (52) Empty reply from server
curl: (52) Empty reply from server
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
curl: (52) Empty reply from server
ok
ok
ok
ok
...

有三次失败,往后再怎么测试都会成功。

如果再将 wsgi.ini 中的 processes 由4改为1,现在整个 uwsgi就剩一个工作进程了(没有 master 了)。

uwsgi]
#允许主进程的存在,由它来管理其它进程,其它 uwsgi 进程都是訪 master 进程的子进程,如果 kill 掉这个 master 进程,相当于重启所有的 uwsgi 进程.
master=false
#项目 运行目录,在 app 加载前切换到訪目录
chdir=/home/zuosi/saas
#因为我现在只用到 uwsgi 和 flask,所以这里就用 http 就行了,不要用啥 socket 之类的.
http=127.0.0.1:6789
#要加载的WSGI 模型及应用名称
module=saas:app
logto=/home/zuosi/saas/wsgi.log
#开启的工作进程数 量,processes 同 workers 是一个意思
processes=1
#代码有更新的时候自动重新加载,这个在开发的时候很有用
py-autoreload=true
#状态检查服务
stats=127.0.0.1:10000

再测试100次。

$for i in `seq 1 100`;do curl 127.1:6789/infer;echo -e "\t";done
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
...

全部成功!

当局着谜,旁观者清,谁来解惑?

【参考】

http://qaru.site/questions/13659229/check-failed-error-cudasuccess-3-vs-0-initialization-error-check-failure-stack-trace

简单实验uwsgi+flask 部署caffe模型相关推荐

  1. 学习笔记|Flask部署Pytorch模型+Gunicorn+Docker

    一.使用Flask部署Pytorch模型 其实原理很简单,我们希望使用一个已经训练好的pytorch模型,用它做预测或生成.我们的模型部署在服务器上,客户端可以通过http request调用我们部署 ...

  2. flask部署pytorch模型

    项目代码: https://pan.baidu.com/s/1-FdTk7XjryvUsZR9CW9T3g 提取码:6uo5 该项目上传至阿里云仓库:docker--构建自己的项目(阿里云仓库)| d ...

  3. docker部署flask_使用Docker,GCP Cloud Run和Flask部署Scikit-Learn NLP模型

    docker部署flask A brief guide to building an app to serve a natural language processing model, contain ...

  4. 只需10分钟!就能用Flask,Docker和Jenkins部署机器学习模型

    在生产环境中部署机器学习模型是数据工程中经常被忽视的领域.网上的大多数教程/博客都侧重于构建.训练和调整机器学习模型.如果它不能用于实际的预测,那么它又有什么用呢? 接下来了解一下有哪些部署选项吧: ...

  5. flask 部署_只需10分钟!就能用Flask,Docker和Jenkins部署机器学习模型

    摘要: 一杯茶的功夫部署完成机器学习模型! 在生产环境中部署机器学习模型是数据工程中经常被忽视的领域.网上的大多数教程/博客都侧重于构建.训练和调整机器学习模型.如果它不能用于实际的预测,那么它又有什 ...

  6. PyTorch+Flask+Gunicorn 部署深度模型服务

    目录 简介 项目实现 模型实现 部署Flask服务 Gunicorn加速 性能测试 Python 多线程+requests ab工具 (可选)HTML网页端 总结 参考文献 简介 初入职场,对于训练完 ...

  7. 手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选

    作者 | Abhinav Sagar 翻译 | 申利彬 校对 | 吴金笛 来源 | 数据派THU(ID:DatapiTHU) 本文旨在让您把训练好的机器学习模型通过Flask API 投入到生产环境  ...

  8. flask uwsgi nginx 部署在 ubuntu 上

    flask 部署在 ubuntu 上 文章目录 flask 部署在 ubuntu 上 视频 创建部署目录 把项目放到部署目录中 安装虚拟环境 激活虚拟环境 安装python依赖库 安装uwsgi 创建 ...

  9. 独家 | 手把手教你如何使用Flask轻松部署机器学习模型(附代码链接)

    作者:Abhinav Sagar 翻译:申利彬 校对:吴金笛 本文约2700字,建议阅读7分钟. 本文可以让你把训练好的机器学习模型使用Flask API 投入生产环境. 本文旨在让您把训练好的机器学 ...

  10. 用flask部署模型

    模型部署:用flask部署模型 1.https://zhuanlan.zhihu.com/p/35879835 2.https://blog.keras.io/building-a-simple-ke ...

最新文章

  1. 完胜 BERT,谷歌最佳 NLP 预训练模型开源
  2. 难解?SAP云平台集成前路何方?
  3. 水印相机定位不准确怎么办_禄来的广角双反相机(2020版)
  4. 【 Grey Hack 】万金油脚本:常见端口获取shell
  5. JavaScript-jQuery选择器
  6. 计算机英语面试翻译,英语面试问题及回答带翻译
  7. 搭建自己的框架WedeNet(五)
  8. 用python画太阳花过程_有几个问题一直弄不出来求大神 python(python太阳花教程)
  9. 鸿蒙系统可以微信吗,“微信”跟鸿蒙系统,只能选择一个,华为尴尬了
  10. PCB设计技巧一百问
  11. 洗脑神曲《萨瓦迪卡曼谷》MV里的旅游景点,你都打卡了吗?
  12. IOS 使用TestFlight 详解
  13. java awt canvas_java.awt 类 Canvas - Java 中文参考手册
  14. cmos电路多余输入端能否悬空_CMOS门电路的多余输入端可以悬空,悬空时相当于输入为逻辑1。...
  15. [Jule CTF 2022] 部分WP
  16. java基础教程(一)
  17. 90%人的手机都被这9款APP所占据,你拥有几个呢?
  18. 视频教程-Python数据分析案例实战 视频课程-Python
  19. EasyNVR如何实现前端录像时间轴播放?
  20. SMLT中增加新的语言

热门文章

  1. EDI电除盐纯水设备
  2. Elasticsearch 如何实现类主流搜索引擎广告置顶显示效果?
  3. Lotus Symphony 正式版发布!
  4. vue3的抽离封装方法
  5. 淘宝客软件-登录阿里妈妈
  6. 【团队博客】软件项目:上海海洋大学图书馆座位查找系统
  7. 什么是CDN,简单了解CDN
  8. 买手机是不是主要看处理器?
  9. 单片机c语言程序设计算器,基于单片机的数字计算器的设计
  10. 贴吧怎么引流_教您如何快速搭建自己的引流池-万能的小胡