一、Docker 镜像准备
直接pull mms images
cpu版本:
docker pull awsdeeplearningteam/multi-model-server
gpu版本:
拉取官方项目
git clone https://github.com/awslabs/multi-model-server.git
拉起官方镜像:
docker pull awsdeeplearningteam/mxnet-model-server:1.0.0-mxnet-gpu
自定义gpu版本:
修改Dockerfile.gpu内容
vim Dockerfile.gpu
以cuda10.2为例
FROM nvidia/cuda:10.2-cudnn8-runtime-ubuntu18.04
ENV PYTHONUNBUFFERED TRUE
RUN apt-get update && apt-get install sudo
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
fakeroot \
ca-certificates \
dpkg-dev \
g++ \
python3-dev \
openjdk-8-jdk-headless \
libglib2.0-dev \
libgl1-mesa-dev
libxrender1 \
libgl1-mesa-glx \
libxext-dev \
curl \
vim \
&& rm -rf /var/lib/apt/lists/* \
&& cd /tmp \
&& curl -O https://bootstrap.pypa.io/get-pip.py \
&& python3 get-pip.py
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1
RUN update-alternatives --install /usr/local/bin/pip pip /usr/local/bin/pip3 1
RUN pip install--no-cache-dir -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com numpy==1.16.1 insightface mtcnn scipy==1.2.2 matplotlib pillow uwsgi opencv-python django keras==2.2.4 jupyterlab
RUN pip install --no-cache-dir -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com multi-model-server \
&& pip install --no-cache-dir -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com mxnet-cu102mkl
RUN useradd -m model-server \
&& mkdir -p /home/model-server/tmp
COPY dockerd-entrypoint.sh /usr/local/bin/dockerd-entrypoint.sh
COPY config.properties /home/model-server
RUN chmod +x /usr/local/bin/dockerd-entrypoint.sh \
&& chown -R model-server /home/model-server
EXPOSE 8080 8081
RUN usermod -a -G sudo model-server
USER model-server
WORKDIR /home/model-server
ENV TEMP=/home/model-server/tmp
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh"]
CMD ["serve"]
LABEL maintainer="[email protected]"
生成GPU镜像
docker build -f Dockerfile.gpu -t mms1-gpu .
也可以直接使用本人创的镜像 !!!!!
dockhub:
docker push lian01110/mms_mxnet_cu102:1.0
阿里云镜像仓库:
docker pull registry.cn-hangzhou.aliyuncs.com/docker_yangjian/mms_mxnet_cuda102:1.0
二、模型转化为mar文件
本地(如windos)或者服务器(linux)里新建文件夹insightface_deploy,把所有文件都放入此目录中
模型结构文件: insightface-symbol.json # 模型文件也可以放到其他文件夹下,在mxnet_model_service.py中需要修改def initialize() 的checkpoint_prefix
模型权重文件: insightface-0000.params # 跟模型结构文件放在一起
模型签名文件: 定义API的输入输出signature.json,非必须,看需求
模型label信息(可选): sysnet.txt,记录各个分类的名字,如果模型不是分类模型,这个文件不必要
处理程序代码文件: 模型前处理与后处理
signature.json文件内容:
{
"inputs": [
{
"data_name": "data",
"data_shape": [
0,
3,
112,
112
]
}
]
}
其中"data" 为Body的KEY,图片形状为[0,3,112,112] 其实代表的是[1,3,112,112],这里我们只需要填写输入内容即可
如果不懂输入输出,可新建一个文件test_out_put.py,内容如下
import* mxnet *as* mx
model = 'insightface'
model_path = "insightface_model"
input_shape = (1, 3, 112, 112)
# 加载模型
load_symbol, args, auxs = mx.model.load_checkpoint(model_path, 0)
mod = mx.mod.Module(load_symbol, label_names=None, data_names=['data'], context=mx.cpu())
mod.bind(data_shapes=[('data', input_shape)])
print(mod.data_names)
print(mod.data_shapes)
print(mod.output_names)
print(mod.output_shapes)
['data']
[DataDesc[data,(1, 3, 112, 112),,NCHW]]
['fc1_output']
[('fc1_output', (1, 512))]
custom service class
mms支持自己写一个服务的代码,这个代码可以进行图片的预处理和模型返回结果后的后处理,相当于写了一个小型web服务,mms在启动的时候,会找到里面写好的一个handle,调用相应的类来处理模型的输入输出。
我们直接用官方的模板https://github.com/awslabs/multi-model-server/tree/master/examples/model_service_template的所有内容
文件夹mxnet_utils: 里面有一些图片处理文件image.py ndarray.py nlp.py
gluon_base_service.py
model_handler.py : 读取data跟模型进行推导过程文件
mxnet_model_service.py
mxnet_vison_batching.py
mxnet_vision_service.py :最后执行文件,包括子类的前处理与后处理,后处理根据自己需求修改,我的修改如下:
!!!如果有有中文注释 ,也要在文件首行输入: # -*- coding: UTF-8 -*-
# 导入numpy
import numpy as np
# 在后处理函数修改
def postprocess(self, data):
这里data是2维
# return [d.asnumpy().tolist() for d in data]
emb =data[0].asnumpy()
norm =np.sqrt(np.sum(emb*emb)+0.00001)
emb /=norm #归一化
return emb.tolist() # 返回文件不支持numpy格式,需转为list
根据需求更改mxnet_model_service.py,这里只有一个输出并不需要需改,如果需要更改输出层:
# todo Load MXNet module 加载模型
self.mxnet_ctx = mx.cpu() if gpu_id is None else mx.gpu(gpu_id)
sym, arg_params, aux_params = mx.model.load_checkpoint(checkpoint_prefix, self.epoch)
# 如果要改变输出层
# all_layers = sym.get_internals() # 获得所有层
# output_layers = sym.output_names() # 获得输出层名字 在外查看用,不需要执行此行,见test_out_put.py
# output_layer = all_layers[layer + '_output'] # 指定输出层 ,layer为输出层前缀,见test_out_put.py
# model = mx.mod.Module(symbol=output_layer, context=ctx, label_names=None)
# noinspection PyTypeChecker
self.mx_model = mx.mod.Module(symbol=sym, context=self.mxnet_ctx, data_names=data_names, label_names=None)
self.mx_model.bind(for_training=False, data_shapes=data_shapes)
self.mx_model.set_params(arg_params, aux_params, allow_missing=True, allow_extra=True)
整个文件夹结构如下:
insightface_deploy
├── mxnet_utils
│ ├── image.py
│ ├── __init__.py
│ ├── ndarray.py
│ └── nlp.py
├── models
│ ├── retinaface_mnet025_v1
│ ├── mnet.caffemodel
│ ├── mnet.prototxt
├── insightface-0000.params
├── insightface-symbol.json
├── gluon_base_service.py
├── model_handler.py
├── mxnet_model_service.py
├── mxnet_vision_batching.py
├── mxnet_vision_service.py
├── signature.json
压缩出mar文件
mms只需一个mar文件即可构建服务,这个mar文件就是上面这些文件的结合,现在使用mms的“model-archiver”来压缩它们。首先安装“model-archiver”:
pip install model-archiver
cd 到 arcface文件下,终端运行以下命令:
model-archiver --model-name insightface --model-path ./ --handler mxnet_vision_service:handle
参数解释:
model-name:模型的名字,即模型文件的前缀,这里为insightface也表示压缩后的mar文件的名字为insightface.mar, <<会把所有文件都压缩到mar中>>
model-path:存所有文件的文件夹路径,这里直接在insightface_deploy文件夹下,故只需"./"。
handler:自定义服务的handle,“mxnet_version_service:handle”的意思是使用“mxnet_version_service.py”文件里面的“handle”类来处理模型的输入输出。
最后得到一个以“insightface.mar”的文件。
多个模型:即最后的执行函数不同,生成多个mar文件, 所有文件都会按根目录方式进行解压. 即mxnet_veison_service等文件只能放根目录,不能放子目录.
三、 模型部署
为了更方便地部署模型,避免每次部署的时候都要写一大串命令,我们可以写一个配置文件来指定一些参数。新建一个名为“config.properties”的文件,复制以下内容:
vmargs=-Xmx128m -XX:-UseLargePages -XX:+UseG1GC -XX:MaxMetaspaceSize=32M -XX:MaxDirectMemorySize=10m -XX:+ExitOnOutOfMemoryError
model_store=/models/ # 这里为容器地址
load_models=ALL
inference_address=http://0.0.0.0:8080
management_address=http://0.0.0.0:8081
# management_address=unix:/tmp/management.sock
number_of_netty_threads=10
netty_client_threads=10
# default_response_timeout=120
# unregister_model_timeout=120
# default_workers_per_model=0
job_queue_size=100
# async_logging=false
number_of_gpu=1 # 使用gpu,如果是cpu,这里打上#,1为gpu个数,如果有2个:number_of_gpu=1
# cors_allowed_origin
# cors_allowed_methods
# cors_allowed_headers
# keystore=src/test/resources/keystore.p12
# keystore_pass=changeit
# keystore_type=PKCS12
# private_key_file=src/test/resources/key.pem
# certificate_file=src/test/resources/certs.pem
# blacklist_env_vars=
max_request_size=10000000 #默认为1M,修改为10M
vmargs=-Xms1024m -Xmx1024m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -Dio.netty.leakDetectionLevel=advanced -Xloggc:d:/gc.log -XX:MaxDirectMemorySize=30M -Dio.netty.allocator.pageSize=8192 -Dio.netty.allocator.maxOrder=10 -Dio.netty.recycler.maxCapacity=0 -Dio.netty.recycler.maxCapacity.default=0
参数说明
https://github.com/awslabs/multi-model-server/blob/master/docs/configuration.md#configure-mms-listening-port
JVM参数:
vmargs=-Xmx128m:
-XX:-UseLargePages
-XX:+UseG1GC
-XX:MaxMetaspaceSize=32M:设置metaspace(元空间)区域的最大值,如果不设置,默认的*capacity*until*GC为20M左右* ,此值会影响传入数据大小限制
-XX:MaxDirectMemorySize=10m: java堆外内存的峰值,此值会影响传入数据大小限制
-XX:+ExitOnOutOfMemoryError
- model-store:.mar模型存放的路径,注意这里是docker container里面的路径,一般都是“/models/”,不是本机模型的路径。
- inference_address:模型监听的端口,即url要输入的端口
- number_of_gpu:使用的GPU数量,不是GPU序号,如写2为使用2张GPU,而且会使用前两张GPU,不能指定使用某张GPU。
max_request_size:最大post请求data数据大小,单位b(在传输大数据>1M,需要增加此项)
然后请把“config.properties”和“MODEL.mar”这两个文件放在服务器的同一个文件夹内,如“/tmp/arcmodel/”
2.部署
原始gpu-serving
docker run -itd --restart=on-failure:10 --runtime=nvidia --name mms1 -p 8061:8080 -p 8062:8081 -v \
/tmp/arcmodel/:/models \
awsdeeplearningteam/mxnet-model-server:1.0.0-mxnet-gpu \
mxnet-model-server --start --mms-config /models/config.properties \
--models arcface=arcface_model.mar
自定义gpu
docker run -itd --restart=on-failure:10 --runtime=nvidia --name mms_arcface_yj -p 8061:8080 -p 8062:8081 -v \
/tmp/mxnet_deploy/:/models \
mms-gpu \
multi-model-server --start --mms-config /models/config.properties --model-store /models \
--models arcface=arcface_model.mar
注意:如果映射到root里,有encode的问题,尝试了代码前加encoding utf-8 无效果
insightface:
docker run -itd --restart=on-failure:10 --gpus 1 --name mms_insightface_yj -p 8001:8080 -p 8066:8081 -v \
/tmp/insightface_ploy/:/models \
mms_insightface_yj:1.0 \
multi-model-server --start --mms-config /models/config.properties --model-store /models \
--models insightface=insightface.mar
参数解释:
--gpus 0 或者--runtime=nvidia:使用gpu
-v:把本机(服务器)存放.mar文件和config文件的文件夹(如:“/home/project_documents/Face_production/insightface_deploy/”,注意最后要加上"/")映射到容器内部的文件夹(如“/models”)。
mms_insightface_yj:1.0:pull下来的mms镜像名.
--name mms_insightface_yj : 给容器起名字,注意不能跟以有容器重名
-mxnet-model-server --start:启动mms (自定义改为multi-model-server --start)
--mms-config /models/config.properties:容器内部config.properties的路径。固定,不需要修改
--model-store 容器内的(.mar)文件路径
--models insightface=insightface.mar:选择要部署的模型,接口名=模型.mar名, 接口名自定义,url时需要输入
多模型部署
--models function1=function1.mar function2=function2
3.测试服务
cd到有测试图片文件下
curl -X POST http://192.168.46.230:8601/predictions/arcface -T kitten.jpg
可能会报curl: error while loading shared libraries: libssl.so.1.0.0错误.在本地windows电脑上输入即可
jerry@LAPTOP-0NITTTTQ MINGW64 /d/Ai/Facenet/ArcFace/insightface/mxnet_deploy/mms/insighface_dnn (master)
$ curl -X POST http://192.168.46.230:8601/predictions/arcface -T kitten.jpg
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 108k 0 0 100 108k 0 34656 0:00:03 0:00:03 --:--:-- 34656
{
"code": 200,
"message": "success",
"datas": {
"ismatch": true,
"accept": 0.8,
"score": 0.9497,
"timeused": 107.86
}
在potman运行: