在modelarts里使用自定义算法进行训练、导入模型、部署服务

网友投稿 1204 2022-05-30

本文介绍在ModelArts里使用自定义算法进行训练、导入模型、部署服务的过程。

如果你用过了modelarts的自动学习,然后你觉得自动学习过于自动了,想试试不那么自动的;

或者你用过了Modelarts的市场订阅算法(以前叫预置算法),然后你觉得只是把别人写好的攻略再重复一遍,你还想尝试一点更新的东西;

那你也许可能对本文有一点感兴趣,虽然这里的过程结束后,没有生产出有任何业务意义的服务,但是你知道了这个流程,不管有没有业务意义,都是这样的流程。

首先,自定义算法,就是自己可以比较自由的控制的算法。

这里用的算法,是一个最最简单的,一元一次方程的线性回归的算法。

数据?为简单起见,不需要准备,不需要输入,算法自己包含了。

算法的思路是这样的:

1.自己准备数据,就是一些数字,先是x轴上的100个数字。然后是y轴上的100个数字,y和x的关系是:y=2x+1+一个噪声值

2.假装我们不知道x和y之间的关系,我们的算法就是来寻找这个关系。每一对x和y的值,都是算法的输入,而算法的目标,就是找出系数2和常量1。在tf里,x和y就是占位符,而要找出的系数和常量,就是变量。

在modelarts里使用自定义算法进行训练、导入模型、部署服务

3.算法的寻找的方法,是损失函数,和优化器。谈到损失函数,那这个应该是有监督学习吧,没有标签,怎么计算损失呢?

4.有了方法后,就是去做,一遍遍的做,反正机器也是不知道累的,这个算法简单,秒完。

有了数据,然后数据配合算法跑完,变量/参数就算出来了,这个时候要把成果保存下来。

好了,上面的这些,写道一个py文件tf_modelart.py里,就可以作为自定义算法来到Modelarts里做训练了。

# -*- coding: utf-8 -*- import os import numpy as np import tensorflow.compat.v1 as tf tf.disable_eager_execution() tf.flags.DEFINE_integer('max_steps', 1000, 'number of training iterations.') tf.flags.DEFINE_string('data_url', '', 'dataset directory.') tf.flags.DEFINE_string('train_url', '', 'saved model directory.') FLAGS = tf.flags.FLAGS def model(x,w,b): return tf.multiply(x,w)+b def main(*args): #输入数据目录这里没有使用;因为代码里自己生成了数据 print('^_^the data_url is ',FLAGS.data_url) np.random.seed(5) #生成100个点,取值范围[-1,1] x_data=np.linspace(-1,1,100) #后面是加一个噪声 不然是一条直线 ; *是把元组展开 print(*x_data.shape) y_data=2*x_data + 1.0 + np.random.randn(*x_data.shape)*0.4 print('^_^start training...') #二个占位符是训练时传入的 x=tf.placeholder('float',name='x') y=tf.placeholder('float',name='y') #这二个变量是来保存和更新参数的 w=tf.Variable(1.0,name='w0') b=tf.Variable(0.0,name='b0') pred=model(x,w,b) #设置训练超参 train_epochs=2 learning_rate=0.05 #损失函数 loss_func=tf.reduce_mean(tf.square(y-pred)) #优化器 optimizer=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_func) #可以开始跑训练了 sess=tf.Session() init=tf.global_variables_initializer() sess.run(init) for epoch in range(train_epochs): for xs,ys in zip(x_data,y_data): _,loss=sess.run([optimizer,loss_func],feed_dict={x:xs,y:ys}) print('^_^Done training!') #保存模型 signature_key = 'test_signature' input_key = 'input_x' output_key = 'output' builder=tf.saved_model.builder.SavedModelBuilder(os.path.join(FLAGS.train_url,'model')) inputs = {input_key : tf.saved_model.utils.build_tensor_info(x)} outputs = {output_key : tf.saved_model.utils.build_tensor_info(pred)} signature = tf.saved_model.signature_def_utils.build_signature_def(inputs, outputs, 'test_sig_name') builder.add_meta_graph_and_variables(sess,['igraphtag'],{signature_key:signature}) builder.save() print('^_^export train dir is ',FLAGS.train_url) if __name__ == '__main__': tf.app.run(main=main)

训练管理>训练作业>创建截图

这里train_url和data_url是根据上面的选择带出的,还可以增加其他可配置化的参数,比如一些超参,训练的epoch和学习率等,这里为了简化,都略过。

运行成功后,保存了模型到OBS里

然后,在modelarts里,有一个模型导入的步骤要做,这样会将模型封进image,以利于后续部署。

而在模型导入之前,还需要做一件事件,那就是确定模型对外服务时的输入输出接口(入参/出参),以及推理的代码,确定了这二项后,在导入模型时,modelarts会用到。如下图

那么config.json和推理代码是长上面样子的呢?

如下:config.json

{ "model_type": "TensorFlow", "runtime": "tf2.1-python3.7", "model_algorithm": "predict_analysis", "apis": [ { "protocol": "http", "url": "/", "method": "post", "request": { "Content-type": "application/json", "data": { "type": "object" "properties": { "input_x": {"type": "string"} }, "required": ["input_x"] } }, "response": { "Content-type": "application/json", "data": { "type": "object", "properties": { "result": {"type": "string"} }, "required": ["result"] } } }], }

推理代码customize_service.py:

# -*- coding: utf-8 -*- from model_service.tfserving_model_service import TfServingBaseService import tensorflow.compat.v1 as tf tf.disable_eager_execution() class my_service(TfServingBaseService): def __init__(self, model_name, model_path): # these three parameters are no need to modify self.model_name = model_name self.model_path = model_path self.signature_key = 'test_signature' # add the input and output key of your pb model here, # these keys are defined when you save a pb file self.input_key_1 = 'input_x' self.output_key_1 = 'output' config = tf.ConfigProto(allow_soft_placement=True) with tf.get_default_graph().as_default(): self.sess = tf.Session(graph=tf.Graph(), config=config) meta_graph_def = tf.saved_model.loader.load(self.sess, ["igraphtag"], self.model_path) self.signature = meta_graph_def.signature_def # define input and out tensor of your model here input_images_tensor_name = self.signature[self.signature_key].inputs[self.input_key_1].name output_score_tensor_name = self.signature[self.signature_key].outputs[self.output_key_1].name self.input_images = self.sess.graph.get_tensor_by_name(input_images_tensor_name) self.output_score = self.sess.graph.get_tensor_by_name(output_score_tensor_name) print('^_^_init_ tensor in is',self.input_images) print('^_^_init_ tensor out is',self.output_score) def _inference(self, data): """ model inference function Here are a inference example of resnet, if you use another model, please modify this function """ print('^_^inference data is',data) img=data pred_score = self.sess.run(self.output_score, feed_dict={self.input_images: img}) result = {'result':str(pred_score)} return result def _preprocess(self, data): print('^_^pre data is ',data) preprocessed_data = data return preprocessed_data def _postprocess(self, data): print('^_^post data is ',data) infer_output = data return infer_output

注:这里的代码参考了垃圾分类,可以从这里下载

要按照modelarts的模型包规范,写好apis的json配置文件,和推理的代码。参考文档:模型包规范介绍

推理的代码,是用来做对外服务的业务处理。部署为服务后,可以对外提供restful风格的http服务,这样你的服务可以以大家喜闻乐见的方式提供给大众来调用。

config.json就是用来定义服务的输入输出接口。

推理的思路很简单,和算法思路的最后一部分,保存模型的对应起来的。要注意的是不要对差了,否则错一小点又要重来。

1.加载模型,并按约定提取出用于输入输出的张量。

2.建立会话运行模型里的预测功能,获取预测结果

3.组织返回

再然后,模型导入成功了,下面就是部署。部署就是准备环境、拉镜像image、然后启动。虽然是很小的模型,但是架子很大,所以还是比较慢,要几分钟。

部署没什么好说的,就是免费规格排队很慢,可能很久都排不到,可以用收费的,用完了记得停止服务。

服务启动成功后,来测试一下服务,看服务返回是不是正确,如果不正确,报错什么的,要去看日志排查具体原因,找到原因修改后,再从导入模型来过~

有点奇怪的时,输入接口咋不能输入json格式的数据呢?

AI开发平台ModelArts 机器学习

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何为您的应用选择合适的微控制器?
下一篇:python爬虫入门requests模块
相关文章