
这是我的代码,因为我平时 python 写得少,不熟练,如果代码质量差请别喷
import json, re import uuid from urllib.parse import quote, unquote import yaml import os, urllib.request import time from flask import Flask, config, render_template, request, redirect, make_response from paddleocr import PaddleOCR, draw_ocr ocr = PaddleOCR(use_angle_cls=True, lang='en') app = Flask(__name__) @app.route('/ocr', methods=['GET']) def do_ocr(): if request.method == 'GET': data = request.args if 'url' in data: url = unquote(data['url']) else: return "" tmp_path = f"/dev/shm/{uuid.uuid4()}" urllib.request.urlretrieve(url, tmp_path) result = ocr.ocr(tmp_path, cls=True) data = "" for recr in result: rec = recr[1][0].upper() data += rec + "," os.remove(tmp_path) return data.strip(",") if __name__ == '__main__': app.run() ocrapi.py 是从别处复制来的猴子补丁(不然好像并发会有问题)
from gevent import monkey, pywsgi monkey.patch_all() from app import app 用了 supervisor 启动:
[program:ocrapi] command=gunicorn --workers 6 --worker-class=gevent --worker-cOnnections=50 -b 0.0.0.0:8080 ocrapi:app directory=/opt/ocrapi/ user=root autorestart=true redirect_stderr=true stdout_logfile=/var/log/ocrapi.log loglevel=info 服务启动时内存占用在 2GB 左右,随后越来越大
另外想问下如果只是用于识别包装盒上的产品序列号(大写英文数字组成,位数固定,手机拍照的,白底黑字/黑底白字都有可能)有效果更好的方案吗?
1 ggvm 2024-04-06 21:49:07 +08:00 查一下具体的内存是被什么东西占用了? 估计是模型被多次加载,但从来不释放? |
2 Puteulanus 2024-04-06 21:51:07 +08:00 ocr = PaddleOCR(use_angle_cls=True, lang='en') 这个要是放 do_ocr 里面呢 我之前看别人另一个识别的用的 https://cnocr.readthedocs.io/zh/latest/usage/ |
3 drymonfidelia OP @Puteulanus 如果是这个要放进去的原因,为什么放外面反而会被多次加载?放外面不是更应该不会被多次加载么? |
4 Puteulanus 2024-04-06 22:09:54 +08:00 @drymonfidelia 我的意思是既然感觉 PaddleOCR 有问题,就别维持它的全局对象了,没有引用看垃圾回收能不能收了它 |
5 est 2024-04-06 22:11:56 +08:00 @drymonfidelia 可能是 ocr 对象维持了一些历史记录。你扫一次内存就占着不释放了。 |
6 ClericPy 2024-04-06 22:20:48 +08:00 如果对这个库不了解, 可以在子进程里初始化它, 子进程销毁的时候就清理了. 不过估计会慢... 优化的地方很多 |
7 drymonfidelia &nbp; OP @Puteulanus 但是每次 ocr 都加载一次模型感觉会很慢 |
8 kaneg 2024-04-06 22:37:36 +08:00 via iPhone /dev/shm/这个是在内存的,会不会文件没有删掉,滞留在内存了 |
9 drymonfidelia OP @kaneg 我看 top 是 gunicorn 这个进程占的内存 |
10 drymonfidelia OP @kaneg 不过你提醒我了 /dev/shm/ 确实堆了 10GB 的图没删掉,不知道为什么,不过影响不大 |
11 GlobalNPC 2024-04-06 22:54:10 +08:00 @drymonfidelia 怎么会影响不大。。。这里应该用 with 自动管理 |
12 drymonfidelia OP @infun with 能实现代码块结束自动删除文件么 |
13 kuanat 2024-04-06 23:10:10 +08:00 paddleocr 内存分配管理有问题是个很长时间的问题了。我印象官方 github 有几个 issues 就是讨论这个的,而且跨了多个版本,你可以去查一下。 之前有说是因为框架缓存的原因,有人说不是。我之前遇到这个问题也是通过重启来解决,尝试读了一下 c++ 代码部分还是太复杂了,没有解决的精力和能力。 |
14 GlobalNPC 2024-04-06 23:16:29 +08:00 |
15 bringyou 2024-04-06 23:18:12 +08:00 如#13 所言,paddle OCR 的内存占用是个老问题,可以看 issue https://github.com/PaddlePaddle/PaddleOCR/discussions/6977 |
16 bringyou 2024-04-06 23:18:56 +08:00 也可以手动调用 try_shrink_memory 来释放内存 |
17 ON9 2024-04-06 23:48:58 +08:00 via Android 一定要用猴子吗,用 fastapi 呢 |
18 NoOneNoBody 2024-04-07 01:19:46 +08:00 python 多进程会将全局环境复制到每个子进程 flask 我不清楚要怎么做,最好使用 cache 而不是全局变量,然后每个子进程调用时从 cache 懒加载读取 |
19 Eished 2024-04-07 01:21:29 +08:00 我也是 Flask+paddleocr ,用的 CPU 版本,1G 内存,都是小图片,大概半年才会内存满了重启一次 |
20 founddev 2024-04-07 09:23:18 +08:00 可以尝试 paddleocr 转 onnx 用 PyTorch ,TF 或者 tensorrt 这种比较成熟的框架,尽量不要使用受众很小的这种框架,有 bug 都不一样会改 |
21 clemente 2024-04-07 22:52:55 +08:00 不要用 paddle 百度都快放弃了 |
22 CHchenkeyi 2024-04-09 15:15:38 +08:00 至少代码没看出来由啥问题 |
23 CHchenkeyi 2024-04-09 15:16:35 +08:00 做了很多飞桨的,基本上有问题就是 版本问题,要么更新 paddle 版本,要么更新 ocr 版本。很玄学 |
24 drymonfidelia OP @CHchenkeyi 更新了最新版更离谱了,运行半分钟 100%用完内存 |
25 so1n 2024-07-18 19:48:47 +08:00 遇到内存溢出问题,都是用 gunicorn 的 max_requests |
26 yinmin 2024-07-18 23:51:29 +08:00 @drymonfidelia 25 楼是正解。gunicorn 加参数 --max-requests 1000 试试 (每个 worker 接收到 1000 次请求后就重启一个新的) 你自己测试一下 max-requests 用 500 、1000 、5000 、10000 哪个更优化。 |
27 mMartin 2024-07-19 10:57:52 +08:00 把 OCR 单独封装个单例试试 paddleOCR 我至少在十个生产环境用 还真没遇到内存泄露 |
28 mMartin 2024-07-19 11:01:33 +08:00 要么就把 OCR 单独封装一个服务 RPC 调用 我检测分割分类和 OCR 经常一起用 |