AnimeGAN+Flask部署过程
本地加载预训练模型并进行推理,测试通过。想将其打包成网页应用并对外展示。
hk的朋友有一个带有公网ip的树莓派服务器,开始尝试
Try 树莓派
配置环境
安装conda
安装conda,下载linux版格式不对,改成aarch64,还是报错,"Illegal instruction"
换成Miniforge 树莓派安装Python3.8 64bit
然后 conda create -n deeplearning python=3.8
创建一个虚拟环境
安装pytorch
树莓派上只能编译安装
- 编译安装,两个小时,树莓派上安装 PyTorch,直接放弃
为了节省时间,找大佬编译好的 - 号称是
linux-aarch64
的,PyTorch 1.10.0 for the RPi 64-bit Bullseye,不行 armv7l
不行,树莓派4开箱及PyTorch配置记录- 参考 树莓派4B arm平台aarch64 pip安装pytorch 去某镜像站 找个whi,例如 torch-1.10.0-cp38-cp38-linux_aarch64.whl,然后
pip install
,OK
安装opencv
图片的保存和resize用到了 opencv
sudo apt-get install opencv-python
无效,安装成功但程序未检测到
换用 pip install opencv
,ok
运行AnimeGAN
环境没问题,但是predict时会报错:Out of memory
于是朋友给机器加了8G交换区间:
没有出现爆内存了,但是网页推理到一半会变成502,不知道是树莓派的问题,还是终极Bug(后面会提))的问题
Note:
一些查看内存的命令
df -h # 磁盘挂载情况
free -h # 内存和交换区大小
dmesg # 内存日志
白忙活,换用Colab,印象中记得Colab也可以生成一个外部访问的链接,于是,冲!
Try Colab
开启外部访问链接
from google.colab.output import eval_js
print(eval_js("google.colab.kernel.proxyPort(12345)"))
得到 https://bh0uv4zwoz6-496ff2e9c6d22116-12345-colab.googleusercontent.com/
很好,没毛病
Out of memory
查看显卡 !nvidia-smi
,一张K80,11G显存
上传小点的图片,推理成功
大点的图片,Out of memory,need 13G only 11G is available
设置成CPU,慢点,又不是不能用!!
尝试 ngrok
让朋友测试一下??只有我能打开?可能是我浏览器登录了Google账号,和Colab是同一个
面向浏览器,找有没有能公共访问的端口访问服务
[Is there a general way to run Web Applications on Google Colab?](Is there a general way to run Web Applications on Google Colab?),找到ngrok
github上还有样例 flask-ngrok,开始
pip install flask-ngrok
安装之后,只要添加一句 from flask_ngrok import run_with_ngrok
启动后得到 http://5b8b-34-67-126-207.ngrok.io 类似这样的链接
效果:的确能公开访问,但是大图片同样gg,当时以为是 ngrok.io 的带宽有限,现在想大概率也是终极Bug问题
放弃?我们不是有公网ip吗,我在本地跑(程序最开始在本地是调通了的),再做内网穿透总行了吧
Try 本地
内网穿透
先把内网穿透弄好,就是将公网Ip某个端口的流量转发到本地的某个端口
1. Termius 端口转发
Termius文档-Local, Remote, and Dynamic Forwarding
玩转SSH端口转发
通过终端命令设置端口转发
如何删除ssh转发的端口
Termius不是有 port Forwarding 功能嘛,而且有 Local
、Remote
、Dynamic
三种模式,将远端流量转发到本地选择 Remote
查看设置
2. 搭建 FRP 服务
由于服务端是arm架构的树莓派,本地是m1 mac
进入frp github,服务端选择 linux-arm64
的 frps,客户端选择 darwin-arm64
的 frpc(虽然一种包里面server和client都包含了)
修改服务端的 frps.ini
[common]
bind_port = 12345
修改本地的 frpc.ini
[common]
server_addr = tongchen.dynv6.net
server_port = 12345 # 监听端口
[AnimaGAN Service] # 名字可以随便取
type = tcp
local_ip = 127.0.0.1
local_port = 8080 # 要映射端口
remote_port = 8080 # 要映射端口
其他的设置,管理页面、开机自启等暂时不用,详见 搭建属于自己的FRP内网穿透、在Ubuntu 18.04上安装frp
启动服务端 ./frps -c frps.ini
启动客户端 ./frpc -c frpc.ini
总之,现在访问 http://tongchen.dynv6.net:8080/ 等同于访问我本地的 http://127.0.0.1:8080
运行 app.py
直接运行 python app.py
,显然没问题
但是这样简单运行的话,只要按一下 ctrl + c 终止运行,或者关掉终端,网站就连接不了了,我们要寻求更长久的真正的部署。
1. Gunicorn + Gevent
运行以下命令即可安装这两个利器,可以异步同时处理多个请求
对于工作模式,默认是sync,即同步模式。这种模式就是说在调用的时候,必须等待调用返回结果后,决定后续的行为。而异步则是在调用这个job的时候,不用等待其执行结果,还可以执行其他job
pip install gunicorn gevent
在根目录下新建文件 /gunicorn.conf.py
workers = 5 # 定义同时开启的处理请求的进程数量,根据网站流量适当调整
worker_class = "gevent" # 采用gevent库,支持异步处理请求,提高吞吐量
bind = "0.0.0.0:8080"
现在的启动命令变成 gunicorn app:app -c gunicorn.conf.py
ps:
会有一个报错,因为模型推理时间10s+
Gunicorn的日志里,有很多worker timeout error,Gunicorn worker timeout error
所以再加一个配置 timeout=600
于是就有比较漂亮的工作流啦
额外话:设置workers会开启多线程处理,但是,瓶颈在内存,就算开启5个线程也没有足够的内存同时运行5个线程
像这种情况,5个线程都gg,都不会得到响应
因为大一点的图片,峰值内存会达到13G
2. 套一层nginx
按照上面的解释,其实直接使用Gunicorn就完全可以实现外网访问了,为什么非要加一层Nginx呢?
原因其实也很简单,Nginx功能强大,用Nginx转发Gunicorn服务,重点是解决“慢客户端行为”给服务器带来的性能降低问题;另外,在互联网上部署HTTP服务时,还要考虑的“快客户端响应”、SSL处理和高并发等问题,而这些问题在Nginx上一并能搞定,所以在Gunicorn服务之上加一层Nginx反向代理,是个一举多得的部署方案。那为什么需要Nginx转发Gunicorn服务?
在M1 Mac上安装nginx,直接用brew,Mac M1 安装Nginx
接下来就是配置了,nginx的默认配置文件在 /opt/homebrew/etc/nginx(可以用brew info nginx查看),修改 nginx.conf
配置文件
server {
listen 8090; `// Nginx需要监听的接口`
server_name localhost;
location /{
proxy_pass http://127.0.0.1:8080; // 反向代理
}
}
监听端口设为8090,是因为80被占了,如果设置成80,访问的时候都不用加端口号了
然后执行以下命令重启nginx:sudo nginx -s reload
3. 使用 Docker 封装 Flask 应用
待填坑
python上手实践 -- docker+nginx+gunicorn+flask项目部署
完善网页UI
主要是增加"友情提醒"
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AnimeGAN Demo</title>
<style>
.warning{
line-height: 5px;
font-size: 13px;
color: #f44336;
}/* css 注释说明:设置行距行高22px */
</style>
</head>
<body>
<h1>AnimeGAN: 今天out of memory了吗</h1>
<div class="warning">
<p>友情提示:</p>
<p>1. 不要传涩图,上传的图片都会保存的</p>
<p>2. 图片越大,生成时间越长,请耐心等待</p>
</div>
<form action="./upload" enctype='multipart/form-data' method='POST'>
<input type="file" name="file" style="margin-top:20px;"/>
<br>
<i>请输入你当前的心情(开心、超开心、超超开心):</i>
<input type="text" class="txt_input" name="name" value="超超开心" style="margin-top:10px;"/>
<input type="submit" value="上传" class="button-new" style="margin-top:15px;"/>
</form>
</body>
</html>
点击查看UI
终极Bug
离谱,本地没问题,转发的会在推理的过程过网页挂掉:
调了一上午,各种日志,frp、gunicron、chrome dev的日志都是正常的,就不知道为啥会挂掉,又为啥直接访问localhost就行呢......
去实验室问师兄,好家伙,它的浏览器可以!!
然后给小伙伴试了一下,有的可以,有的不行,,,说明是浏览器的问题,,但是我测试的时候localhost和远端是用同一个浏览器
总之,跑路吧
别跑了, 破案了,梯子的原因,把梯子推掉就行了
怎么发现的呢?
我本地可以,用链接不行
用链接部分朋友可以,部分朋友不可以,不可以的朋友都经常使用tz
测试一下~~真的梯子的原因
我之前本地可以是因为本地的流量没有走梯子
List To do
- 支持网页端选择模型
- 尝试用ajax从服务端获取数据,从而可能能解决终极Bug:哎呀不用了,但是还是可以进一步改善获取数据的方式