AnimeGAN+Flask部署过程

本地加载预训练模型并进行推理,测试通过。想将其打包成网页应用并对外展示。
hk的朋友有一个带有公网ip的树莓派服务器,开始尝试

Try 树莓派

配置环境

安装conda

安装conda,下载linux版格式不对,改成aarch64,还是报错,"Illegal instruction"
换成Miniforge 树莓派安装Python3.8 64bit
然后 conda create -n deeplearning python=3.8 创建一个虚拟环境

安装pytorch

树莓派上只能编译安装

安装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 功能嘛,而且有 LocalRemoteDynamic 三种模式,将远端流量转发到本地选择 Remote

查看设置
奇怪的是竟然没有转发成功,,现在想来应该是8080端口被之前的程序占用了,应该先 kill 掉 Note: ``` netstat -anp | grep 8080 ```

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 应用

待填坑

1 小时上线之用 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:哎呀不用了,但是还是可以进一步改善获取数据的方式
posted @ 2021-11-23 21:19  Rogn  阅读(549)  评论(0编辑  收藏  举报