2 个版本,都没有解决内存持续增加,由于内存一直增加,最后因为小鸡内存不足而被杀掉。
这是一个加载训练后的模型,通过网络传入预测参数,然后返回预测 json 结果。
求大佬帮忙看看问题出在哪里,谢谢。
这是 chatgpt 4.0 给的版本
from flask import Flask, request, jsonify
import pickle
import os
import psutil
import pandas as pd
app = Flask(__name__)
class SingletonModel:
_instance = None
def __new__(cls):
if cls._instance is None:
print("Creating Singleton Instance")
cls._instance = super(SingletonModel, cls).__new__(cls)
modelName = "xgboost_model-k.pkl"
with open(modelName, "rb") as pkl_file:
loaded_data = pickle.load(pkl_file)
cls._instance.model = loaded_data['model']
cls._instance.scaler = loaded_data['scaler']
cls._instance.label_encoder = loaded_data['label_encoder']
cls._instance.feature_names = ['shortAvg','longAvg','volatility','diff']
return cls._instance
resources = SingletonModel()
model = resources.model
scaler = resources.scaler
label_encoder = resources.label_encoder
@app.route('/predict', methods=['POST'])
def predict():
global model, scaler, label_encoder
data = request.json['input']
df = pd.DataFrame([data], columns=resources.feature_names)
scaled_data = scaler.transform(df)
prediction = model.predict(scaled_data)
label_prediction = label_encoder.inverse_transform(prediction)
return jsonify([label_prediction[0]])
if __name__ == '__main__':
app.run(port=6601,debug=True)
这是 Claude 给的版本
import asyncio
from flask import Flask, request, jsonify
import pickle
import pandas as pd
app = Flask(__name__)
# 模型相关全局变量
model = None
scaler = None
label_encoder = None
async def load_model():
global model, scaler, label_encoder,feature_names
if not model:
with open('xgboost_model-k.pkl', 'rb') as f:
loaded_data = pickle.load(f)
model = loaded_data['model']
scaler = loaded_data['scaler']
label_encoder = loaded_data['label_encoder']
feature_names = ['shortAvg','longAvg','volatility','diff']
async def predict(data):
await load_model()
df = pd.DataFrame([data], columns=feature_names)
scaled_data = scaler.transform(df)
prediction = model.predict(scaled_data)
label_prediction = label_encoder.inverse_transform(prediction)
return label_prediction[0]
@app.route('/predict', methods=['POST'])
async def predict_handler():
data = request.json['input']
result = await asyncio.gather(predict(data))
return jsonify(result)
if __name__ == '__main__':
app.run(port=6601,debug=False)
使用常规uWSGI也无法解决内存持续增加问题,但是,
1
missz 2023-09-25 17:10:13 +08:00
我用 flask 启的 yolo5 的接口也是内存无限增长,用 memory_profiler 也看不出具体增长原因,现在是用个 shell 脚本超过一定内存就 kill 重启
|
2
jstony 2023-09-25 17:35:17 +08:00
换个版本,cpython 的底层还是 c ,就不能避免完全没有内存泄漏,而且一大堆库,质量良莠不齐。
|
3
davinci21s OP |
4
wynemo 2023-09-25 20:18:06 +08:00
用 uwsgi ,flask 自带的就是这样
|
5
Inzufu 2023-09-25 22:19:25 +08:00 via Android
跑大项目不建议用 py ,还是 nodejs 靠谱一点儿,这两个语言其实学起来差不多。
|
6
roycestevie6761 2023-09-25 22:28:42 +08:00
python 就这样的啦
|
7
among 2023-09-25 22:34:54 +08:00
uwsgi ,多进程模式,配置超过多少内存,就 fork 一个新的进程。
|
8
youngce 2023-09-25 22:35:02 +08:00 1
@inzufu 这玩意一眼就是算法推理服务,nodejs 加载模型文件跑算法推理,你这不是难为算法同学吗?
这代码里面一眼看去就是模型资源全局变量跑,十几个并发,要是没有 gpu 没有显存,就是需要大内存的。再就是推理接口一般也都是 batch 推理,并发可以利用 batch 来缓解压力。 简而言之,要么懂算法、要么懂 python 后端,两者都不精通,算法服务能跑起来已经谢天谢地,就不要苛责性能了 |
10
Mystery0 2023-09-26 09:49:35 +08:00 via Android
蹲一个,我也遇到这个问题,照着别人的代码训练了一个模型然后用 flask 提供接口调模型预测数据
运行之后内存就会慢慢变大,现在的解决办法是隔段时间看一下内存,超过 6-700mb 就重启一下 |
11
davinci21s OP |
12
yagamil 2023-09-26 12:12:54 +08:00
model, scaler, label_encoder,feature_names
这几个变量用全局, 如果不同请求过来, 里面的模型一些参数会被其他进程的请求给修改掉么? |
13
wxlpure 2023-09-26 12:52:29 +08:00
flask 不是同步框架吗?同步框架内用异步是啥效果?
|
14
davinci21s OP |
16
nonduality 2023-09-26 17:11:48 +08:00
对 Claude 写的不评价,对 ChatGPT 写的说点看法。
单例模式在这里应该是没用的,你可以把 print 的内容改为输出到日志( logging.info ),然后在日志里查看是否不断创建 SingletonModel 。 解决方案之一是利用 RPC:在后台启动一个常驻的数据处理服务,负责接收请求、数据处理和返回结果; Flask 负责把客户端请求转发到常驻服务,再把返回来的结果发给客户端。 需要注意的是,RPC 有多种执行模式,你要避免不断 fork 进程或 spawn 线程去处理数据,这样内存占用也有可能不断膨胀,而要直接调用数据处理的入口函数,这时候单例模式就能起作用。 |
17
davinci21s OP @nonduality 感谢,可以对遇到相同问题的提供参考。
|
18
subjadeites 2023-09-26 18:32:58 +08:00 via Android
用 gunicorn 试试?
|
19
subjadeites 2023-09-26 18:33:46 +08:00 via Android
import gevent.monkey
gevent.monkey.patch_all() import multiprocessing debug = False loglevel = 'info' bind = '0.0.0.0:7000' pidfile = 'logs/gunicorn.pid' logfile = 'logs/debug.log' # 启动的进程数 workers = multiprocessing.cpu_count() * 2 worker_class = 'gunicorn.workers.ggevent.GeventWorker' preload_app = True x_forwarded_for_header = 'X-FORWARDED-FOR' |
20
zheng5200 2023-09-27 10:35:01 +08:00 via iPhone
gunicorn 起 flask 也有这个问题,也是通过--max-requests 解决的,╮(╯▽╰)╭
|