热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

tf.saved_model.save模型导出、TensorFlowServing模型部署、TensorBoard中的HParams超参数调优

日萌社人工智能AI:KerasPyTorchMXNetTensorFlowPaddlePaddle深度学习实战(不定时更新)4.11综合

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)



4.11 综合案例:模型导出与部署
学习目标
  • 目标
    • 掌握TensorFlow模型的导出(saved_model格式)
    • 掌握Tensorflow模型的部署
    • 掌握TensorFlow模型的客户端调用
    • 掌握TensorFlow模型的超参数调优使用
  • 应用

4.11.1 TensorFlow 模型导出

在部署模型时,我们的第一步往往是将训练好的整个模型完整导出为一系列标准格式的文件,然后即可在不同的平台上部署模型文件。这时,TensorFlow 为我们提供了 SavedModel 这一格式。

  • 与前面介绍的 Checkpoint 不同,SavedModel 包含了一个 TensorFlow 程序的完整信息: 不仅包含参数的权值,还包含计算的流程(即计算图) 。
    • 特点:当模型导出为 SavedModel 文件时,无需建立模型的源代码即可再次运行模型,这使得 SavedModel 尤其适用于模型的分享和部署。后文的 TensorFlow Serving(服务器端部署模型)、TensorFlow Lite(移动端部署模型)以及 TensorFlow.js 都会用到这一格式。

除了CheckPointTensorFlow还会有其他格式,这里做统一介绍:部署在线服务(Serving)时官方推荐使用 SavedModel 格式,而部署到手机等移动端的模型一般使用 FrozenGraphDef 格式(最近推出的 TensorFlow Lite 也有专门的轻量级模型格式 *.lite,和 FrozenGraphDef 十分类似)。这些格式之间关系密切,可以使用 TensorFlow 提供的 API 来互相转换。下面简单介绍几种格式:

  • 1、GraphDef
    • 这种格式文件包含 protobuf 对象序列化后的数据,包含了计算图,可以从中得到所有运算符(operators)的细节,也包含张量(tensors)和 Variables 定义,但不包含 Variable 的值,因此只能从中恢复计算图,但一些训练的权值仍需要从 checkpoint 中恢复。
  • 2、*.pb

    • TensorFlow 一些例程中用到*.pb 文件作为预训练模型,这和上面 GraphDef 格式稍有不同,属于冻结(Frozen)后的 GraphDef 文件,简称 FrozenGraphDef 格式。这种文件格式不包含 Variables 节点。将 GraphDef 中所有 Variable 节点转换为常量(其值从 checkpoint 获取),就变为 FrozenGraphDef 格式。
  • 3、SavedModel

    • 在使用 TensorFlow Serving 时,会用到这种格式的模型。该格式为 GraphDef 和 CheckPoint 的结合体,另外还有标记模型输入和输出参数的 SignatureDef。从 SavedModel 中可以提取 GraphDef 和 CheckPoint 对象。
    • 其中 saved_model.pb(或 saved_model.pbtxt)包含使用 MetaGraphDef protobuf 对象定义的计算图;assets 包含附加文件;variables 目录包含 tf.train.Saver() 对象调用 save() API 生成的文件。

使用下面的代码即可将模型导出为 SavedModel:

tf.saved_model.save(model, "保存的目标文件夹名称")

在需要载入 SavedModel 文件时,使用即可

model = tf.saved_model.load("保存的目标文件夹名称")

4.11.2 使用案例

1、将之前CIFAE100分类模型进行导出和导入,导出模型到 saved/mlp/1 文件夹中,mlp可以自己指定的一个模型名称,1为版本号,必须提供,后面开启服务需要有版本号

import tensorflow as tf
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"def main():num_epochs = 1batch_size = 32learning_rate = 0.001model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),tf.keras.layers.Dense(120, activation=tf.nn.relu),tf.keras.layers.Dense(100),tf.keras.layers.Softmax()])(train, train_label), (test, test_label) = \tf.keras.datasets.cifar100.load_data()model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),loss=tf.keras.losses.sparse_categorical_crossentropy,metrics=[tf.keras.metrics.sparse_categorical_accuracy])model.fit(train, train_label, epochs=num_epochs, batch_size=batch_size)tf.saved_model.save(model, "./saved/mlp/1")

2、并且模型加载出来,测试性能就能够

  • 注意:这里加载模型可以不用初始化之前的模型(不需要),直接加载到model使用

def test():model = tf.saved_model.load("./saved/mlp/1")sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()(train, train_label), (test, test_label) = \tf.keras.datasets.cifar100.load_data()y_pred = model(test)sparse_categorical_accuracy.update_state(y_true=test_label,y_pred=y_pred)print("test accuracy: %f" % sparse_categorical_accuracy.result())

输出结果

test accuracy: 0.010000

3、自定义的keras模型使用:

使用继承 tf.keras.Model 类建立的 Keras 模型同样可以以相同方法导出,唯须注意 call 方法需要以 @tf.function 修饰,以转化为 SavedModel 支持的计算图,代码如下:

def __init__(self):super().__init__()self.flatten = tf.keras.layers.Flatten()self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)self.dense2 = tf.keras.layers.Dense(units=10)@tf.functiondef call(self, inputs): # [batch_size, 28, 28, 1]x = self.flatten(inputs) # [batch_size, 784]x = self.dense1(x) # [batch_size, 100]x = self.dense2(x) # [batch_size, 10]output = tf.nn.softmax(x)return outputmodel = MLP()

4.11.3 TensorFlow Serving


  • 背景:当我们将模型训练完毕后,往往需要将模型在生产环境中部署。最常见的方式,是在服务器上提供一个 API,即客户机向服务器的某个 API 发送特定格式的请求,服务器收到请求数据后通过模型进行计算,并返回结果。如果仅仅是做一个 Demo,不考虑高并发和性能问题,其实配合Django、Flask等 Python 下的 Web 框架就能非常轻松地实现服务器 API。不过,如果是在真的实际生产环境中部署,这样的方式就显得力不从心了。这时,TensorFlow 为我们提供了 TensorFlow Serving 这一组件,能够帮助我们在实际生产环境中灵活且高性能地部署机器学习模型。

TensorFlow Serving是一种灵活的高性能服务系统,适用于机器学习模型,专为生产环境而设计。TensorFlow Serving可以轻松部署新算法和实验,同时保持相同的服务器架构和API。TensorFlow Serving提供与TensorFlow模型的开箱即用集成,但可以轻松扩展以提供其他类型的模型和数据。

特点:TensorFlow Serving 支持热更新模型,其典型的模型文件夹结构如下:

/saved_model_files/1 # 版本号为1的模型文件/assets/variablessaved_model.pb.../N # 版本号为N的模型文件/assets/variablessaved_model.pb

上面 1~N 的子文件夹代表不同版本号的模型。当指定 --model_base_path 时,只需要指定根目录的 绝对地址 (不是相对地址)即可。例如,如果上述文件夹结构存放在 home/snowkylin 文件夹内,则 --model_base_path 应当设置为 home/snowkylin/saved_model_files (不附带模型版本号)。TensorFlow Serving 会自动选择版本号最大的模型进行载入。

4.11.3.1 安装Tensorflow Serving

安装过程详细参考官网

https://www.tensorflow.org/serving/setup


  • 使用Docker安装进行,首先你的电脑当中已经安装过docker容器
    • Centos:参考:https://www.cnblogs.com/wdliu/p/10194332.html

TensorFlow Serving 可以使用 apt-get 或 Docker 安装。在生产环境中,推荐 使用 Docker 部署 TensorFlow Serving 。

4.11.3.2 TensorFlow Serving Docker 使用介绍

  1. 获取最新TF Serving docker镜像

    docker pull tensorflow/serving

  2. 查看docker镜像

    docker images

  3. 运行tf serving(即创建一个docker容器来运行)

    docker run -p 8501:8501 -p 8500:8500 --mount type=bind,source=/home/ubuntu/detectedmodel/commodity,target=/models/commodity -e MODEL_NAME=commodity -t tensorflow/serving

    说明:

    • -p 8501:8501 为端口映射,-p 主机端口:docker容器程序(tf serving)使用端口,访问主机8501端口就相当于访问了tf serving程序的8501端口
    • tf serving 使用8501端口对外提供HTTP服务,使用8500对外提供gRPC服务,这里同时开放了两个端口的使用
    • --mount type=bind,source=/home/ubuntu/detectedmodel/commodity,target=/models/commodity 为文件映射,将主机(source)的模型文件映射到docker容器程序(target)的位置,以便tf serving使用模型,target参数为/models/我的模型
    • -e MODEL_NAME=commodity设置了一个环境变量,名为MODEL_NAME,此变量被tf serving读取,用来按名字寻找模型,与上面target参数中我的模型对应
    • -t 为tf serving创建一个伪终端,供程序运行
    • tensorflow/serving为镜像名

常见docker命令:

docker ps:查看正在运行的容器

docker images:查看已下载的景象

docker stop 8779b492e4aa:停止正在运行的ID为8779b492e4aa的容器,IP可以通过docker ps查看

4.11.3.3 案例操作:commodity模型服务运行

  • 1、运行命令

docker run -p 8501:8501 -p 8500:8500 --mount type=bind,source=/root/cv_project/tf_example
/saved/mlp,target=/models/mlp -e MODEL_NAME=mlp -t tensorflow/serving &

  • 2、查看是否运行

itcast:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS POR
TS NAMES
1354f9aeab33 tensorflow/serving "/usr/bin/tf_serving…" 7 seconds ago Up 5 seconds 0.0
.0.0:8500-8501->8500-8501/tcp gifted_jackson

4.11.5 在客户端调用以 TensorFlow Serving 部署的模型

TensorFlow Serving 支持以 gRPC 和 RESTful API 调用以 TensorFlow Serving 部署的模型。RESTful API 以标准的 HTTP POST 方法进行交互,请求和回复均为 JSON 对象。为了调用服务器端的模型,我们在客户端向服务器发送以下格式的请求:服务器 URI: http://服务器地址:端口号/v1/models/模型名:predict

请求内容:

{"signature_name": "需要调用的函数签名(Sequential模式不需要)","instances": 输入数据
}

回复为:

{"predictions": 返回值
}

4.11.5.1 直接使用curl

运行下面命令

curl -d '{"instances": [image_data]}' \-X POST http://localhost:8501/v1/models/mlp:predict

4.11.5.2 编写客户端代码

示例使用Python 的 Requests 库(你可能需要使用 pip install requests 安装该库)向本机的 TensorFlow Serving 服务器发送20张图像并返回预测结果,同时与测试集的真实标签进行比较。

def client():import jsonimport numpy as npimport requests(_, _), (test, test_label) = \tf.keras.datasets.cifar100.load_data()data = json.dumps({"instances": test[0:20].tolist() # array转换成列表形式})headers = {"content-type": "application/json"}json_response = requests.post('http://localhost:8501/v1/models/mlp:predict',data=data, headers=headers)predictions = np.array(json.loads(json_response.text)['predictions'])print(np.argmax(predictions, axis=-1))print(test_label[0:20])if __name__ == '__main__':# main()# test()client()

输出:

[67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67]
[[49][33][72][51][71][92][15][14][23][ 0][71][75][81][69][40][43][92][97][70][53]]

因为模型并没有训练多久,只迭代一次,所以效果不好,主要是完成整个流程。



model_serving.py

import tensorflow as tf
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"def main():num_epochs = 1batch_size = 32learning_rate = 0.001model = tf.keras.models.Sequential([tf.keras.layers.Flatten(),tf.keras.layers.Dense(120, activation=tf.nn.relu),tf.keras.layers.Dense(100),tf.keras.layers.Softmax()])(train, train_label), (test, test_label) = \tf.keras.datasets.cifar100.load_data()model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),loss=tf.keras.losses.sparse_categorical_crossentropy,metrics=[tf.keras.metrics.sparse_categorical_accuracy])model.fit(train, train_label, epochs=num_epochs, batch_size=batch_size)tf.saved_model.save(model, "./saved/mlp/2")def test():model = tf.saved_model.load("./saved/mlp/2")(_, _), (test, test_label) = \tf.keras.datasets.cifar100.load_data()y_predict = model(test)sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()sparse_categorical_accuracy.update_state(y_true=test_label, y_pred=y_predict)print("测试集的准确率为: %f" % sparse_categorical_accuracy.result())def client():import jsonimport numpy as npimport requests(_, _), (test, test_label) = \tf.keras.datasets.cifar100.load_data()# 1、构造好请求data = json.dumps({"instances": test[:10].tolist()})headers = {"content-type": "application/json"}json_response = requests.post('http://localhost:8501/v1/models/mlp:predict',data=data, headers=headers)predictions = np.array(json.loads(json_response.text)['predictions'])print(predictions)print(np.argmax(predictions, axis=-1))print(test_label[:10])if __name__ == '__main__':"""TensorFlow 模型导出"""main()test()"""TensorFlow Serving"""# client()



4.11.5 HParams-超参数调优

构建深度学习模型时,需要选择各种超参数,例如模型中的学习率,优化器,神经元个数等。这些决策会影响模型指标,例如准确性。因此,工作流程中的一个重要步骤是为您的问题确定最佳的超参数,这通常涉及实验。此过程称为“超参数优化”或“超参数调整”。TensorBoard中的HParams仪表板提供了多种工具,帮助确定最佳实验或最有希望的超参数集。

注:Note: The HParams summary APIs and dashboard UI are in a preview stage and will change over time.

使用导入

from tensorboard.plugins.hparams import api as hp

4.11.5.1 案例:CIFAR100分类模型添加参数进行调优

  • 使用步骤
    • 1、通过hp设置HParams 实验超参数
    • 2、将试验参数添加到模型指定结构当中,或者编译训练的过程参数中
    • 3、使用超参数调优方法对不同的超参数集训练每个实验组合

1、设置HParams 实验参数

  • hp.Discrete:设置离散类型的参数值,比如神经元个数,优化方法
    • 通过HP_NUM_UNITS.domain.values获取所有的值
  • hp.RealInterval:设置连续型类型的上下限,能够获取最大值最小值
    • HP_DROPOUT.domain.min_value:获取最小值
    • HP_DROPOUT.domain.max_value:获取最大值

HP_NUM_UNITS = hp.HParam('num_units', hp.Discrete([1024, 512]))
HP_DROPOUT = hp.HParam('dropout', hp.RealInterval(0.2, 0.3))
HP_OPTIMIZER = hp.HParam('optimizer', hp.Discrete(['adam', 'sgd']))

2、将试验参数添加到模型指定结构当中,或者编译训练的过程参数中

  • (1)在需要设置超参数的位置填入hparams参数值
  • (2)添加记录hparams的回调hp.KerasCallback('./logs/hparam_tuning/', hparams)
    • 其中目录自己设定即可

def train_test_model(self, hparams):"""训练验证模型:return:"""# 1、定义模型中加入了一个dropoutmodel = tf.keras.Sequential([tf.keras.layers.Conv2D(32, kernel_size=5, strides=1, padding='same', activation=tf.nn.relu),tf.keras.layers.MaxPool2D(pool_size=2, strides=2),tf.keras.layers.Conv2D(64, kernel_size=5, strides=1, padding='same', activation=tf.nn.relu),tf.keras.layers.MaxPool2D(pool_size=2, strides=2),tf.keras.layers.Flatten(),tf.keras.layers.Dense(hparams[HP_NUM_UNITS], activation=tf.nn.relu),tf.keras.layers.Dropout(hparams[HP_DROPOUT]),tf.keras.layers.Dense(100, activation=tf.nn.softmax)])# 2、模型设置以及训练model.compile(optimizer=hparams[HP_OPTIMIZER],loss=tf.keras.losses.sparse_categorical_crossentropy,metrics=['accuracy'])tensorboard = tf.keras.callbacks.TensorBoard(log_dir='./graph', histogram_freq=1,write_graph=True, write_images=True)# 添加记录hparams的回调hp.KerasCallback('./graph/', hparams)model.fit(self.train, self.train_label,epochs=1, batch_size=32,callbacks=[tensorboard, hp.KerasCallback('./logs/hparam_tuning/', hparams)],validation_data=(self.test, self.test_label))return None

3、使用超参数调优方法对不同的超参数集训练每个实验组合

使用网格搜索:尝试使用离散参数的所有组合或者连续型值参数的上限和下限。对于更复杂的场景,随机选择每个超参数值会更有效(随机搜索)。

def hyper_parameter(self):"""超参数调优:return:"""session_num = 0for num_units in HP_NUM_UNITS.domain.values:for dropout_rate in (HP_DROPOUT.domain.min_value, HP_DROPOUT.domain.max_value):for optimizer in HP_OPTIMIZER.domain.values:hparams = {HP_NUM_UNITS: num_units,HP_DROPOUT: dropout_rate,HP_OPTIMIZER: optimizer,}print('--- 开始 实验: %s' % session_num)print({h.name: hparams[h] for h in hparams})self.train_test_model(hparams)session_num += 1return None

注:其中如果对于连续的值比如说你的模型中learning_rate,假设设置0.0001~0.1,可以这样迭代使用

for lr_tate in tf.linspace(HP_LR.domain.min_value,HP_LR.domain.max_value,res):

最终打印效果为:

--- 开始 实验: 0
{'num_units': 512, 'dropout': 0.2, 'optimizer': 'adam'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 21:58 - loss: 4.6257 - accuracy: 0.0000e+002020-03-22 05:02:24.239954: E
50000/50000 [==============================] - 61s 1ms/sample - loss: 3.6983 - accuracy: 0.1391 - val_loss: 3.1219 - val_accuracy: 0.2460
Epoch 2/2
50000/50000 [==============================] - 60s 1ms/sample - loss: 2.9337 - accuracy: 0.2777 - val_loss: 2.7689 - val_accuracy: 0.3094
--- 开始 实验: 1
{'num_units': 512, 'dropout': 0.2, 'optimizer': 'sgd'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 9:12 - loss: 4.5919 - accuracy: 0.0000e+002020-03-22 05:04:26.409071: E
50000/50000 [==============================] - 55s 1ms/sample - loss: 4.3805 - accuracy: 0.0404 - val_loss: 4.1078 - val_accuracy: 0.0641
Epoch 2/2
50000/50000 [==============================] - 55s 1ms/sample - loss: 3.9086 - accuracy: 0.1072 - val_loss: 3.7098 - val_accuracy: 0.1479
--- 开始 实验: 2
{'num_units': 512, 'dropout': 0.3, 'optimizer': 'adam'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 11:06 - loss: 4.6464 - accuracy: 0.03122020-03-22 05:06:18.355198: E
50000/50000 [==============================] - 61s 1ms/sample - loss: 3.7051 - accuracy: 0.1400 - val_loss: 3.1361 - val_accuracy: 0.2422
Epoch 2/2
50000/50000 [==============================] - 60s 1ms/sample - loss: 2.9754 - accuracy: 0.2687 - val_loss: 2.7621 - val_accuracy: 0.3118
--- 开始 实验: 3
{'num_units': 512, 'dropout': 0.3, 'optimizer': 'sgd'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 9:03 - loss: 4.5909 - accuracy: 0.0000e+002020-03-22 05:08:20.864262: E
50000/50000 [==============================] - 55s 1ms/sample - loss: 4.3802 - accuracy: 0.0399 - val_loss: 4.0482 - val_accuracy: 0.0807
Epoch 2/2
50000/50000 [==============================] - 55s 1ms/sample - loss: 3.9227 - accuracy: 0.1036 - val_loss: 3.7022 - val_accuracy: 0.1423
--- 开始 实验: 4
{'num_units': 1024, 'dropout': 0.2, 'optimizer': 'adam'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 11:28 - loss: 4.6099 - accuracy: 0.0000e+002020-03-22 05:10:12.802252: E
50000/50000 [==============================] - 78s 2ms/sample - loss: 3.5546 - accuracy: 0.1683 - val_loss: 3.0440 - val_accuracy: 0.2580
Epoch 2/2
50000/50000 [==============================] - 77s 2ms/sample - loss: 2.7925 - accuracy: 0.3048 - val_loss: 2.7049 - val_accuracy: 0.3255
--- 开始 实验: 5
{'num_units': 1024, 'dropout': 0.2, 'optimizer': 'sgd'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 9:22 - loss: 4.5938 - accuracy: 0.0000e+002020-03-22 05:12:50.161457: E
50000/50000 [==============================] - 68s 1ms/sample - loss: 4.3278 - accuracy: 0.0477 - val_loss: 3.9872 - val_accuracy: 0.0849
Epoch 2/2
50000/50000 [==============================] - 67s 1ms/sample - loss: 3.8071 - accuracy: 0.1244 - val_loss: 3.6097 - val_accuracy: 0.1679
--- 开始 实验: 6
{'num_units': 1024, 'dropout': 0.3, 'optimizer': 'adam'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 11:14 - loss: 4.6129 - accuracy: 0.0000e+002020-03-22 05:15:07.480836: E
50000/50000 [==============================] - 78s 2ms/sample - loss: 3.6139 - accuracy: 0.1548 - val_loss: 2.9943 - val_accuracy: 0.2691
Epoch 2/2
50000/50000 [==============================] - 77s 2ms/sample - loss: 2.8460 - accuracy: 0.2921 - val_loss: 2.7325 - val_accuracy: 0.3195
--- 开始 实验: 7
{'num_units': 1024, 'dropout': 0.3, 'optimizer': 'sgd'}
Train on 50000 samples, validate on 10000 samples
Epoch 1/232/50000 [..............................] - ETA: 9:22 - loss: 4.5689 - accuracy: 0.03122020-03-22 05:17:44.697445: E
50000/50000 [==============================] - 68s 1ms/sample - loss: 4.3251 - accuracy: 0.0469 - val_loss: 3.9708 - val_accuracy: 0.1038
Epoch 2/2
50000/50000 [==============================] - 67s 1ms/sample - loss: 3.8546 - accuracy: 0.1173 - val_loss: 3.6345 - val_accuracy: 0.1653

生成如下目录

4、最终可以通过Tensoboard开启读取对应目录的events文件看到对应结果

tensorboard --logdir './logs/hparam_tuning/'

可以在HPARAMS菜单中查看到下面的效果(官网截图)

并且其中有提供了两种主要的不同的查看方式:

  • 1、表视图(TABLE VIEW):列出了运行时,他们的超参数,和他们的指标。
  • 2、平行坐标视图:每个运行为线通过每个hyperparemeter和度量的轴线去。单击并在任何轴上拖动鼠标以标记一个区域,该区域将仅突出显示通过该区域的运行。这对于确定哪些超参数组最重要很有用

4.11.6 总结


  • TensorFlow模型的导出(saved_model格式)
  • Tensorflow模型的部署
  • TensorFlow模型的客户端调用
  • TensorFlow模型的超参数调优



6-6,使用tensorflow-serving部署模型

TensorFlow训练好的模型以tensorflow原生方式保存成protobuf文件后可以用许多方式部署运行。

例如:通过 tensorflow-js 可以用javascrip脚本加载模型并在浏览器中运行模型。

通过 tensorflow-lite 可以在移动和嵌入式设备上加载并运行TensorFlow模型。

通过 tensorflow-serving 可以加载模型后提供网络接口API服务,通过任意编程语言发送网络请求都可以获取模型预测结果。

通过 tensorFlow for Java接口,可以在Java或者spark(scala)中调用tensorflow模型进行预测。

我们主要介绍tensorflow serving部署模型、使用spark(scala)调用tensorflow模型的方法。


〇,tensorflow serving模型部署概述

使用 tensorflow serving 部署模型要完成以下步骤。

  • (1) 准备protobuf模型文件。

  • (2) 安装tensorflow serving。

  • (3) 启动tensorflow serving 服务。

  • (4) 向API服务发送请求,获取预测结果。

可通过以下colab链接测试效果《tf_serving》:https://colab.research.google.com/drive/1vS5LAYJTEn-H0GDb1irzIuyRB8E3eWc8

%tensorflow_version 2.x
import tensorflow as tf
print(tf.__version__)
from tensorflow.keras import *

一,准备protobuf模型文件

我们使用tf.keras 训练一个简单的线性回归模型,并保存成protobuf文件。

import tensorflow as tf
from tensorflow.keras import models,layers,optimizers

## 样本数量
n = 800

## 生成测试用数据集
X = tf.random.uniform([n,2],minval=-10,maxval=10)
w0 = tf.constant([[2.0],[-1.0]])
b0 = tf.constant(3.0)

Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动

## 建立模型
tf.keras.backend.clear_session()
inputs = layers.Input(shape = (2,),name ="inputs") #设置输入名字为inputs
outputs = layers.Dense(1, name = "outputs")(inputs) #设置输出名字为outputs
linear = models.Model(inputs = inputs,outputs = outputs)
linear.summary()

## 使用fit方法进行训练
linear.compile(optimizer="rmsprop",loss="mse",metrics=["mae"])
linear.fit(X,Y,batch_size = 8,epochs = 100)  

tf.print("w = ",linear.layers[1].kernel)
tf.print("b = ",linear.layers[1].bias)

## 将模型保存成pb格式文件
export_path = "./data/linear_model/"
version = "1"       #后续可以通过版本号进行模型版本迭代与管理
linear.save(export_path+version, save_format="tf")

#查看保存的模型文件
!ls {export_path+version}

assets saved_model.pb variables

# 查看模型文件相关信息
!saved_model_cli show --dir {export_path+str(version)} --all

MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['__saved_model_init_op']:The given SavedModel SignatureDef contains the following input(s):The given SavedModel SignatureDef contains the following output(s):outputs['__saved_model_init_op'] tensor_info:dtype: DT_INVALIDshape: unknown_rankname: NoOpMethod name is:

signature_def['serving_default']:The given SavedModel SignatureDef contains the following input(s):inputs['inputs'] tensor_info:dtype: DT_FLOATshape: (-1, 2)name: serving_default_inputs:0The given SavedModel SignatureDef contains the following output(s):outputs['outputs'] tensor_info:dtype: DT_FLOATshape: (-1, 1)name: StatefulPartitionedCall:0Method name is: tensorflow/serving/predict
WARNING:tensorflow:From /tensorflow-2.1.0/python3.6/tensorflow_core/python/ops/resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.

Defined Functions:Function Name: '__call__'Option #1Callable with:Argument #1inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')Argument #2DType: boolValue: FalseArgument #3DType: NoneTypeValue: NoneOption #2Callable with:Argument #1inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')Argument #2DType: boolValue: TrueArgument #3DType: NoneTypeValue: None
​Function Name: '_default_save_signature'Option #1Callable with:Argument #1inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')
​Function Name: 'call_and_return_all_conditional_losses'Option #1Callable with:Argument #1inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')Argument #2DType: boolValue: TrueArgument #3DType: NoneTypeValue: NoneOption #2Callable with:Argument #1inputs: TensorSpec(shape=(None, 2), dtype=tf.float32, name='inputs')Argument #2DType: boolValue: FalseArgument #3DType: NoneTypeValue: None


二,安装 tensorflow serving

安装 tensorflow serving 有2种主要方法:通过Docker镜像安装,通过apt安装。

通过Docker镜像安装是最简单,最直接的方法,推荐采用。

Docker可以理解成一种容器,其上面可以给各种不同的程序提供独立的运行环境。

一般业务中用到tensorflow的企业都会有运维同学通过Docker 搭建 tensorflow serving.

无需算法工程师同学动手安装,以下安装过程仅供参考。

不同操作系统机器上安装Docker的方法可以参照以下链接。

Windows: https://www.runoob.com/docker/windows-docker-install.html

MacOs: https://www.runoob.com/docker/macos-docker-install.html

CentOS: https://www.runoob.com/docker/centos-docker-install.html

安装Docker成功后,使用如下命令加载 tensorflow/serving 镜像到Docker中

docker pull tensorflow/serving


三,启动 tensorflow serving 服务

!docker run -t --rm -p 8501:8501 \-v "/Users/.../data/linear_model/" \-e MODEL_NAME=linear_model \tensorflow/serving & >server.log 2>&1


四,向API服务发送请求

可以使用任何编程语言的http功能发送请求,下面示范linux的 curl 命令发送请求,以及Python的requests库发送请求。

!curl -d '{"instances": [1.0, 2.0, 5.0]}' \-X POST http://localhost:8501/v1/models/linear_model:predict

{"predictions": [[3.06546211], [5.01313448]]
}

import json,requests

data = json.dumps({"signature_name": "serving_default", "instances": [[1.0, 2.0], [5.0,7.0]]})
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/linear_model:predict', data=data, headers=headers)
predictions = json.loads(json_response.text)["predictions"]
print(predictions)

[[3.06546211], [6.02843142]]


推荐阅读
  • 本文提供了PyTorch框架中常用的预训练模型的下载链接及详细使用指南,涵盖ResNet、Inception、DenseNet、AlexNet、VGGNet等六大分类模型。每种模型的预训练参数均经过精心调优,适用于多种计算机视觉任务。文章不仅介绍了模型的下载方式,还详细说明了如何在实际项目中高效地加载和使用这些模型,为开发者提供全面的技术支持。 ... [详细]
  • 本文档详细介绍了Excel VBA编程中的基本语法,包括循环结构、条件判断、数据处理以及用户界面设计等内容,旨在帮助初学者快速掌握VBA编程技巧。 ... [详细]
  • 本文详细解析了Java中流的概念,特别是OutputStream和InputStream的区别,并通过实际案例介绍了如何实现Java对象的序列化。文章不仅解释了流的基本概念,还探讨了序列化的重要性和具体实现步骤。 ... [详细]
  • 本文介绍了如何使用 Google Colab 的免费 GPU 资源进行深度学习应用开发。Google Colab 是一个无需配置即可使用的云端 Jupyter 笔记本环境,支持多种深度学习框架,并且提供免费的 GPU 计算资源。 ... [详细]
  • 【图像分类实战】利用DenseNet在PyTorch中实现秃头识别
    本文详细介绍了如何使用DenseNet模型在PyTorch框架下实现秃头识别。首先,文章概述了项目所需的库和全局参数设置。接着,对图像进行预处理并读取数据集。随后,构建并配置DenseNet模型,设置训练和验证流程。最后,通过测试阶段验证模型性能,并提供了完整的代码实现。本文不仅涵盖了技术细节,还提供了实用的操作指南,适合初学者和有经验的研究人员参考。 ... [详细]
  • TensorFlow Lite在移动设备上的部署实践与优化笔记
    近期在探索如何将服务器端的模型迁移到移动设备上,并记录了一些关键问题和解决方案。本文假设读者具备以下基础知识:了解TensorFlow的计算图(Graph)、图定义(GraphDef)和元图定义(MetaGraphDef)。此外,文中还详细介绍了模型转换、性能优化和资源管理等方面的实践经验,为开发者提供有价值的参考。 ... [详细]
  • 在 PyTorch 的 `CrossEntropyLoss` 函数中,当目标标签 `target` 为类别 ID 时,实际上会进行 one-hot 编码处理。例如,假设总共有三个类别,其中一个类别的 ID 为 2,则该标签会被转换为 `[0, 0, 1]`。这一过程简化了多分类任务中的损失计算,使得模型能够更高效地进行训练和评估。此外,`CrossEntropyLoss` 还结合了 softmax 激活函数和负对数似然损失,进一步提高了模型的性能和稳定性。 ... [详细]
  • 本文探讨了BERT模型在自然语言处理领域的应用与实践。详细介绍了Transformers库(曾用名pytorch-transformers和pytorch-pretrained-bert)的使用方法,涵盖了从模型加载到微调的各个环节。此外,还分析了BERT在文本分类、情感分析和命名实体识别等任务中的性能表现,并讨论了其在实际项目中的优势和局限性。 ... [详细]
  • 本文详细介绍了在Windows操作系统上使用Python 3.8.5编译支持CUDA 11和cuDNN 8.0.2的TensorFlow 2.3的步骤。文章不仅提供了详细的编译指南,还分享了编译后的文件下载链接,方便用户快速获取所需资源。此外,文中还涵盖了常见的编译问题及其解决方案,确保用户能够顺利进行编译和安装。 ... [详细]
  • 1.如何进行迁移 使用Pytorch写的模型: 对模型和相应的数据使用.cuda()处理。通过这种方式,我们就可以将内存中的数据复制到GPU的显存中去。 ... [详细]
  • 基于TensorFlow的鸢尾花数据集神经网络模型深度解析
    基于TensorFlow的鸢尾花数据集神经网络模型深度解析 ... [详细]
  • TensorFlow基础知识深化讲解
    批标准化批标准化(batchnormalization,BN)是为了克服神经网络层数加深导致难以训练而诞生的。深度神经网络随着深度加深,收 ... [详细]
  • 本文介绍了一种方法,通过使用Python的ctypes库来调用C++代码。具体实例为实现一个简单的加法器,并详细说明了从编写C++代码到编译及最终在Python中调用的全过程。 ... [详细]
  • 目录预备知识导包构建数据集神经网络结构训练测试精度可视化计算模型精度损失可视化输出网络结构信息训练神经网络定义参数载入数据载入神经网络结构、损失及优化训练及测试损失、精度可视化qu ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
author-avatar
钞绚舞亨利
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有