当前位置: 首页 > 科技观察

使用TFserving部署深度学习模型

时间:2023-03-13 17:24:28 科技观察

1.什么是TFserving当你训练好你的模型,需要提供给外部使用时,你需要将模型部署到线上,并提供合适的接口供外部调用。你可能会考虑一些问题:部署用什么?如何提供API接口?部署方案;Tensorflow提供了一个TFserving方案来部署在线模型推理。此外,ModelServerforApacheMXNet还为MXNet模型提供推理服务。本文是TFServing的使用指南。如果你是pytorch或者MXNet模型,也可以通过ONNX转成TFserving模型,部署到TFServing上。那么什么是TFserving?TFserving是Google于2017年推出的在线推理服务;使用C/S架构,客户端可以通过gRPC和RESTfullAPI与模型服务通信。TFServing的特点:支持模型版本控制和回滚:Manager会管理模型版本支持并发,实现开箱即用的高吞吐量,可定制支持多模型服务支持批处理支持热更新:Source在本地加载Model,通知Manager有新模型加载,Manager检查模型版本,通知Source创建的Loader加载模型,支持分布式模型2.TFserving安装强烈建议以docker方式安装TFserving,安装依赖docker和nvidia-docker(需要TFservinggpu)dockerinstallation#安装yum-utils工具和device-mapper相关依赖包yuminstall-yyum-utils\device-mapper-persistent-data\lvm2#添加docker-cestable版本仓库yum-config-manager\--add-repo\https://download.docker.com/linux/centos/docker-ce.repo#更新yum缓存文件yummakecachefast#查看所有可安装的docker-ce版本nsyumlistdocker-ce--showduplicates|sort-r#安装docker-ceyuminstalldocker-ce-17.12.1.ce-1.el7.centos#允许开机启动docker-ce服务systemctlenabledocker.service#启动Docker-ce服务systemctlstartdocker#运行测试容器hello-worlddockerrun--rmhello-worldnvidia-dockerinstallation#Installnvidia-docker2yuminstall-ynvidia-docker2-2.0.3-1.docker17.12.1.ce#RestartdockerserviceservicedockerrestartInstallTFservingdockerpulltensorflow/serving:latest-gpu#可以选择其他版本如dockerpulltensorflow/serving:1.14.0-rc0-gpu注意:为了匹配docker版本和nvidia-docker最新的nvidia-docker,Docker需要是19.03。参考官方https://github.com/NVIDIA/nvidia-dockernvidia-docker2支持其他低于19.03版本的Docker版本(需要>=1.12),现有服务器有18.09、1.17、1.13https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)3.TFserving说明3.1TFserving的模型转换模型需要转换成TFserving的格式,不支持常用的checkpoint和pb格式TFserving模型包含一个.pb文件和variables目录(可以为空),导出格式如下:.├──1│├──saved_model.pb│└──variables├──2│├──saved_model.pb│└──variables不同深度学习框架的转换路径:(1)pytorch(.pth)-->onnx(.onnx)-->tensorflow(.pb)-->TFserving(2)keras(.h5)-->tensorflow(.pb)-->TFserving(3)tensorflow(.pb)-->TFserving这里详细介绍pb转TFserving模型importtensorflowastfdefcreate_graph(pb_file):"""CreatesagraphfromsavedGraphDeffileandreturnssaver."""#Createsgraphfromsavedgraph_def.pb。withtf.gfile.FastGFile(pb_file,'rb')asf:graph_def=tf.GraphDef()graph_def.ParseFromString(f.read())_=tf.import_graph_def(graph_def,name='')defpb_to_tfserving(pb_file,export_path,pb_io_name=[],input_node_name='input',output_node_name='output',signature_name='default_tfserving'):#pb_io_name是pb模型的输入输出节点的名称,#input_node_name是转换后的输入名称#output_node_name是转换后的输出名#signature_name是签名create_graph(pb_file)#tensor_name_list=[tensor.namefortensorintf.get_default_graph().as_graph_def().node]input_name='%s:0'%pb_io_name[0]output_name='%s:0'%pb_io_name[1]withtf.Session()assess:in_tensor=sess.graph.get_tensor_by_name(input_name)out_tensor=sess.graph.get_tensor_by_name(output_name)builder=tf.saved_model.builder.SavedModelBuilder(export_path)##export_path导出路径inputs={input_node_name:tf.saved_model.utils.build_tensor_info(in_tensor)}outputs={output_node_name:tf.saved_model.utils.build_tensor_infoor})=tf.saved_model.signature_def_utils.build_signature_def(输入,输出,method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)builder.add_meta_graph_and_variables(sesssess=sess,tags=[tf.saved_model.tag_constants.SERVING],signature_def_map={signature_arsignatures,clear_name:True)##signature_name为签名,可以自定义builder.save()pb_model_path='test.pb'pb_to_tfserving(pb_model_path,'./1',pb_io_name=['input_1_1','output_1'],signature_name='your_model')3.2TFserving配置和启动模型导出后,同一个模型可以导出不同的versions(版本后面的数字),可以在TFserving配置中指定型号和指定版本TFserving模型由模型名称和签名唯一定位。TFserving可以配置多个模型,充分利用GPU资源。模型配置#models.configmodel_config_list{config{name:'your_model'base_path:'/models/your_model/'model_platform:'tensorflow'#model_version_policy{#specific{#versions:42#versions:43#}#}#version_labels{#key:'stable'#value:43#}#version_labels{#key:'canary'#value:43#}}c??onfig{name:"mnist",base_path:"/models/mnist",model_platform:"tensorflow",model_version_policy:{specific:{versions:1,versions:2}}}#可以通过model_version_policy启动版本控制#建议将模型和配置文件放在docker外的本地路径,如/home/tfserving/模型,通过-v挂载在docker里面#--model_config_file:指定模型配置文件#-eNVIDIA_VISIBLE_DEVICES=0:指定GPU#-p指定端口映射8500是gRpc8501是restfulapi端口#-t是docker镜像nvidia-dockerrun-it--特权-d-eNVIDIA_VISIBLE_DEVICES=0-v/home/tfserving/models:/models-p8500:8500-p8501:8501\-ttensorflow/serving:latest-gpu\--model_config_file=/models/models.config#/home/tfserving/models结构├──models.config└──你的模型├──1│├──saved_model.pb│└──变量└──2├──saved_model.pb└──变量#testcurlhttp://192.168.0.3:8501/v1/models/your_model{"model_version_status":[{"version":"2","state":"AVAILABLE","status":{"error_code":"OK","error_message":""}}]}#其他启动方式#如果多个model在不同的目录下,nvidia-dockerrun-it--privileged-d-eNVIDIA_VISIBLE_DEVICES=0\--mounttype=bind可以通过-mount分别加载,source=/home/tfserving/models/your_model,target=/models/your_model\--mounttype=bind,source=/home/tfserving/models/your_model/models.config,target=/models/models.config\-p8510:8500-p8501:8501\-ttensorflow/serving:latest-gpu\--model_config_file=/models/models.config3.3TFserving服务调用客户端可以通过gRpc和http调用TFserving服务模型,支持多种客户端语言,这里是python的调用方法;该调用通过模型名称和签名唯一对应一个模型gRpc调用,gRpc的端口为8500:def__init__(self,socket):"""Args:socket:hostandportofthetfserving,like192.168.0.3:8500"""self.socket=socketstart=time.time()self.request,selfself.stub=self.__get_request()end=time.time()print('initializecosttime:'+str(end-start)+'s')def__get_request(self):channel=grpc.insecure_channel(self.socket,options=[('grpc.max_send_message_length',1024*1024*1024),('grpc.max_receive_message_length',1024*1024*1024)])#可设置大小stub=prediction_service_pb2_grpc.PredictionServiceStub(channel)request=predict_pb2.PredictRequest()request.model_spec.name="your_model"#modelnamerequest.model_spec.signature_name="your_model"#modelsignaturenamereturnrequest,stubdefrun(self,image):"""Args:image:theinputimage(rgbformat)返回:embeddingisoutputofmodel"""img=image[...,::-1]self.request.inputs['input'].CopyFrom(tf.contrib.util.make_tensor_proto(img))#imagesisinputofmodelresult=self.stub.Predict(self.请求,30.0)returntf.make_ndarray(result.outputs['output'])defrun_file(self,image_file):"""Args:image_file:theinputimagefileReturns:"""image=cv2.imread(image_file)image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)returnsself.run(image)if__name__=='__main__':model=YourModel('192.168.0.3:8500')test_file='./test.jpg'result=model.run_file(test_file)print(result)#[8.014745e-059.999199e-01]restfulapi调用:restful端口是8501importcv2importrequestsclassSelfEncoder(json.JSONEncoder):defdefault(self,obj):ifisinstance(obj,np.ndarray):returnobj.tolist()elifisinstance(obj),np.floating):returnfloat(obj)elifisinstance(obj,bytes):returnstr(obj,encoding='utf-8');returnjson.JSONEncoder.default(self,obj)image_file='/home/tfserving/test.jpg'image=cv2.imread(image_file)image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)img=image[...,::-1]input_data={"signature_name":"your_model","instances":img}data=json.dumps(输入数据,cls=SelfEncoder,indent=None)result=requests.post("http://192.168.0.3:8501/v1/models/your_model:predict",datadata=data)eval(result.content)#{'预测':[8.01474525e-05,0.999919891]}5.小结本文介绍TFserving部署在线推理服务,从模型转换、部署启动到调用推理,欢迎交流,希望对您有所帮助,大家提出的问题解答于下一章的开始。部署:当然是TFserving如何提供API接口:TFserving提供了restfulAPI接口,在实际部署的时候,会在其前面加一层比如flaskapi如何为多模型分配GPU资源:TFserving支持部署多个models,通过配置在线模型如何在不中断服务的情况下更新:TFserving支持不同版本的模型,比如your_model中的版本1和版本2。当你添加新的模型3时,TFserving会自动判断并自动加载模型3为当前模型,无需重启