未验证 提交 8b7e9496 编写于 作者: C chenjian 提交者: GitHub

support multiple vdl process when using gunicorn for x2paddle (#1170)

* support multiple vdl process when using gunicorn for x2paddle

* fix a bug
上级 9a16e460
...@@ -13,10 +13,12 @@ ...@@ -13,10 +13,12 @@
# limitations under the License. # limitations under the License.
# ======================================================================= # =======================================================================
import base64 import base64
import glob
import hashlib
import json import json
import os import os
import shutil
import tempfile import tempfile
from collections import deque
from threading import Lock from threading import Lock
from flask import request from flask import request
...@@ -27,15 +29,18 @@ from .xarfile import archive ...@@ -27,15 +29,18 @@ from .xarfile import archive
from .xarfile import unarchive from .xarfile import unarchive
from visualdl.server.api import gen_result from visualdl.server.api import gen_result
from visualdl.server.api import result from visualdl.server.api import result
from visualdl.utils.dir import X2PADDLE_CACHE_PATH
_max_cache_numbers = 200
class ModelConvertApi(object): class ModelConvertApi(object):
def __init__(self): def __init__(self):
self.supported_formats = {'onnx', 'caffe'} self.supported_formats = {'onnx', 'caffe'}
self.lock = Lock() self.lock = Lock()
self.translated_models = deque( self.server_count = 0 # we use this variable to count requests handled,
maxlen=5) # used to store user's translated model for download # and check the number of files every 100 requests.
self.request_id = 0 # used to store user's request # If more than _max_cache_numbers files in cache, we delete the last recent used 50 files.
@result() @result()
def convert_model(self, format): def convert_model(self, format):
...@@ -48,73 +53,101 @@ class ModelConvertApi(object): ...@@ -48,73 +53,101 @@ class ModelConvertApi(object):
result['from'] = format result['from'] = format
result['to'] = 'paddle' result['to'] = 'paddle'
# call x2paddle to convert models # call x2paddle to convert models
with tempfile.TemporaryDirectory( hl = hashlib.md5()
suffix='x2paddle_translated_models') as tmpdirname: hl.update(data)
with tempfile.NamedTemporaryFile() as fp: identity = hl.hexdigest()
fp.write(data) result['request_id'] = identity
fp.flush() target_path = os.path.join(X2PADDLE_CACHE_PATH, identity)
try: if os.path.exists(target_path):
if format == 'onnx': if os.path.exists(
try: os.path.join(target_path, 'inference_model',
import onnx # noqa: F401 'model.pdmodel')): # if data in cache
except Exception: with open(
os.path.join(target_path, 'inference_model',
'model.pdmodel'), 'rb') as model_fp:
model_encoded = base64.b64encode(
model_fp.read()).decode('utf-8')
result['pdmodel'] = model_encoded
return result
else:
os.makedirs(target_path, exist_ok=True)
with tempfile.NamedTemporaryFile() as fp:
fp.write(data)
fp.flush()
try:
if format == 'onnx':
try:
import onnx # noqa: F401
except Exception:
raise RuntimeError(
"[ERROR] onnx is not installed, use \"pip install onnx>=1.6.0\"."
)
onnx2paddle(fp.name, target_path)
elif format == 'caffe':
with tempfile.TemporaryDirectory() as unarchivedir:
unarchive(fp.name, unarchivedir)
prototxt_path = None
weight_path = None
for dirname, subdirs, filenames in os.walk(
unarchivedir):
for filename in filenames:
if '.prototxt' in filename:
prototxt_path = os.path.join(
dirname, filename)
if '.caffemodel' in filename:
weight_path = os.path.join(
dirname, filename)
if prototxt_path is None or weight_path is None:
raise RuntimeError( raise RuntimeError(
"[ERROR] onnx is not installed, use \"pip install onnx>=1.6.0\"." ".prototxt or .caffemodel file is missing in your archive file, \
) please check files uploaded.")
onnx2paddle(fp.name, tmpdirname) caffe2paddle(prototxt_path, weight_path, target_path,
elif format == 'caffe': None)
with tempfile.TemporaryDirectory() as unarchivedir: except Exception as e:
unarchive(fp.name, unarchivedir) raise RuntimeError(
prototxt_path = None "[Convertion error] {}.\n Please open an issue at \
weight_path = None https://github.com/PaddlePaddle/X2Paddle/issues to report your problem."
for dirname, subdirs, filenames in os.walk( .format(e))
unarchivedir): with self.lock: # we need to enter dirname(target_path) to archive,
for filename in filenames: # in case unneccessary directory added in archive.
if '.prototxt' in filename: origin_dir = os.getcwd()
prototxt_path = os.path.join( os.chdir(os.path.dirname(target_path))
dirname, filename) archive(os.path.basename(target_path))
if '.caffemodel' in filename: os.chdir(origin_dir)
weight_path = os.path.join( self.server_count += 1
dirname, filename) with open(
if prototxt_path is None or weight_path is None: os.path.join(target_path, 'inference_model', 'model.pdmodel'),
raise RuntimeError( 'rb') as model_fp:
".prototxt or .caffemodel file is missing in your archive file, \ model_encoded = base64.b64encode(model_fp.read()).decode('utf-8')
please check files uploaded.") result['pdmodel'] = model_encoded
caffe2paddle(prototxt_path, weight_path,
tmpdirname, None)
except Exception as e:
raise RuntimeError(
"[Convertion error] {}.\n Please open an issue at \
https://github.com/PaddlePaddle/X2Paddle/issues to report your problem."
.format(e))
with self.lock:
origin_dir = os.getcwd()
os.chdir(os.path.dirname(tmpdirname))
archive_path = os.path.join(
os.path.dirname(tmpdirname),
archive(os.path.basename(tmpdirname)))
os.chdir(origin_dir)
result['request_id'] = self.request_id
self.request_id += 1
with open(archive_path, 'rb') as archive_fp:
self.translated_models.append((result['request_id'],
archive_fp.read()))
with open(
os.path.join(tmpdirname, 'inference_model',
'model.pdmodel'), 'rb') as model_fp:
model_encoded = base64.b64encode(
model_fp.read()).decode('utf-8')
result['pdmodel'] = model_encoded
if os.path.exists(archive_path):
os.remove(archive_path)
return result return result
@result('application/octet-stream') @result('application/octet-stream')
def download_model(self, request_id): def download_model(self, request_id):
for stored_request_id, data in self.translated_models: if os.path.exists(
if str(stored_request_id) == request_id: os.path.join(X2PADDLE_CACHE_PATH,
return data '{}.tar'.format(request_id))):
with open(
os.path.join(X2PADDLE_CACHE_PATH,
'{}.tar'.format(request_id)), 'rb') as f:
data = f.read()
if self.server_count % 100 == 0: # we check number of files every 100 request
file_paths = glob.glob(
os.path.join(X2PADDLE_CACHE_PATH, '*.tar'))
if len(file_paths) >= _max_cache_numbers:
file_paths = sorted(
file_paths, key=os.path.getctime, reverse=True)
for file_path in file_paths:
try:
os.remove(file_path)
shutil.rmtree(
os.path.join(
os.path.dirname(file_path),
os.path.splitext(
os.path.basename(file_path))[0]))
except Exception:
pass
return data
def create_model_convert_api_call(): def create_model_convert_api_call():
......
...@@ -12,21 +12,18 @@ ...@@ -12,21 +12,18 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# ======================================================================= # =======================================================================
import os
import json import json
import os
VDL_SERVER = "https://www.paddlepaddle.org.cn/paddle/visualdl/service/server" VDL_SERVER = "https://www.paddlepaddle.org.cn/paddle/visualdl/service/server"
default_vdl_config = { default_vdl_config = {'server_url': VDL_SERVER}
'server_url': VDL_SERVER
}
USER_HOME = os.path.expanduser('~') USER_HOME = os.path.expanduser('~')
VDL_HOME = os.path.join(USER_HOME, '.visualdl') VDL_HOME = os.path.join(USER_HOME, '.visualdl')
CONF_HOME = os.path.join(VDL_HOME, 'conf') CONF_HOME = os.path.join(VDL_HOME, 'conf')
CONFIG_PATH = os.path.join(CONF_HOME, 'config.json') CONFIG_PATH = os.path.join(CONF_HOME, 'config.json')
X2PADDLE_CACHE_PATH = os.path.join(VDL_HOME, 'x2paddle')
def init_vdl_config(): def init_vdl_config():
...@@ -35,3 +32,5 @@ def init_vdl_config(): ...@@ -35,3 +32,5 @@ def init_vdl_config():
if not os.path.exists(CONFIG_PATH) or 0 == os.path.getsize(CONFIG_PATH): if not os.path.exists(CONFIG_PATH) or 0 == os.path.getsize(CONFIG_PATH):
with open(CONFIG_PATH, 'w') as fp: with open(CONFIG_PATH, 'w') as fp:
fp.write(json.dumps(default_vdl_config)) fp.write(json.dumps(default_vdl_config))
if not os.path.exists(X2PADDLE_CACHE_PATH):
os.makedirs(X2PADDLE_CACHE_PATH, exist_ok=True)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册