掌声送给TensorFlow 2.0!用Keras搭建一个CNN | 入门教程

640?wx_fmt=jpeg

做者 | Himanshu Rawlani
python

译者 | Monanfei,责编 | 琥珀git

出品 | AI科技大本营(id:rgznai100)程序员


2019 年 3 月 6 日,谷歌在 TensorFlow 开发者年度峰会上发布了最新版的 TensorFlow 框架 TensorFlow2.0 。新版本对 TensorFlow 的使用方式进行了重大改进,使其更加灵活和更具人性化。具体的改变和新增内容能够从 TensorFlow 的官网找到,本文将介绍如何使用 TensorFlow2.0 构建和部署端到端的图像分类器,以及新版本中的新增内容,包括:github


  • 使用 TensorFlow Datasets 下载数据并进行预处理算法

  • 使用 Keras 高级 API 构建和训练图像分类器json

  • 下载 InceptionV3 卷积神经网络并对其进行微调ubuntu

  • 使用 TensorFlow Serving 为训练好的模型发布服务接口api

 

本教程的全部源代码都已发布到 GitHub 库中,有须要的读者可下载使用。数组


项目地址:服务器

https://github.com/himanshurawlani/practical_intro_to_tf2


在此以前,须要提早安装 TF nightly preview,其中包含 TensorFlow 2.0 alpha 版本,代码以下:


 
 
$ pip install -U --pre tensorflow


1.  使用 TensorFlow Datasets 下载数据并进行预处理

 

TensorFlow Datasets 提供了一组可直接用于 TensorFlow 的数据集,它可以下载和准备数据,并最终将数据集构建成 tf.data.Dataset 形式。


经过 pip 安装 TensorFlow Datasets 的 python 库,代码以下:


 
 
$ pip install tfds-nightly


1.1 下载数据集


TensorFlow Datasets 中包含了许多数据集,按照需求添加本身的数据集。


具体的操做方法可见:

https://github.com/tensorflow/datasets/blob/master/docs/add_dataset.md


若是咱们想列出可用的数据集,能够用下面的代码:


 
 
import tensorflow_datasets as tfds	
print(tfds.list_builders())


在下载数据集以前,咱们最好先了解下该数据集的详细信息,例如该数据集的功能信息和统计信息等。本文将使用 tf_flowers 数据集,该数据集的详细信息能够在 TensorFlow 官网找到,具体内容以下:


  • 数据集的总可下载大小

  • 经过 tfds.load() 返回的数据类型/对象

  • 数据集是否已定义了标准分割形式:训练、验证和测试的大小


对于本文即将使用的 tf_flowers 数据集,其大小为 218MB,返回值为 FeaturesDict 对象,还没有进行分割。因为该数据集还没有定义标准分割形式,咱们将利用 subsplit 函数将数据集分割为三部分,80% 用于训练,10% 用于验证,10% 用于测试;而后使用 tfds.load() 函数来下载数据,该函数须要特别注意一个参数 as_supervised,该参数设置为 as_supervised=True,这样函数就会返回一个二元组 (input, label) ,而不是返回 FeaturesDict ,由于二元组的形式更方便理解和使用;接下来,指定 with_info=True ,这样就能够获得函数处理的信息,以便加深对数据的理解,代码以下:


 
 
import tensorflow_datasets as tfds	
	
SPLIT_WEIGHTS = (8, 1, 1)	
splits = tfds.Split.TRAIN.subsplit(weighted=SPLIT_WEIGHTS)	
(raw_train, raw_validation, raw_test), metadata = tfds.load(name="tf_flowers", 	
                                                            with_info=True,	
                                                            split=list(splits),	
# specifying batch_size=-1 will load full dataset in the memory	
#                                                             batch_size=-1,	
# as_supervised: `bool`, if `True`, the returned `tf.data.Dataset`	
# will have a 2-tuple structure `(input, label)`                                                            	
                                                            as_supervised=True)


1.2 对数据集进行预处理


从 TensorFlow Datasets 中下载的数据集包含不少不一样尺寸的图片,咱们须要将这些图像的尺寸调整为固定的大小,而且将全部像素值都进行标准化,使得像素值的变化范围都在 0~1 之间。这些操做显得繁琐无用,可是咱们必须进行这些预处理操做,由于在训练一个卷积神经网络以前,咱们必须指定它的输入维度。不只如此,网络中最后全链接层的 shape 取决于 CNN 的输入维度,所以这些预处理的操做是颇有必要的。


以下所示,咱们将构建函数 format_exmaple(),并将它传递给 raw_train, raw_validationraw_test 的映射函数,从而完成对数据的预处理。须要指明的是,format_exmaple() 的参数和传递给 tfds.load() 的参数有关:若是 as_supervised=True,那么 tfds.load() 将下载二元组 (image, labels) ,该二元组将做为参数传递给 format_exmaple();若是 as_supervised=False,那么 tfds.load() 将下载一个字典 <image,lable> ,该字典将做为参数传递给 format_exmaple() 。


 
 
def format_example(image, label):	
    image = tf.cast(image, tf.float32)	
    # Normalize the pixel values	
    image = image / 255.0	
    # Resize the image	
    image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))	
    return image, label	
	
train = raw_train.map(format_example)	
validation = raw_validation.map(format_example)	
test = raw_test.map(format_example)


除此以外,咱们还对 train 对象调用 .shuffle(BUFFER_SIZE) ,用于打乱训练集的顺序,该操做可以消除样本的次序误差。Shuffle 的缓冲区大小最后设置得和数据集同样大,这样可以保证数据被充分的打乱。接下来咱们要用 .batch(BATCH_SIZE) 来定义这三类数据集的 batch 大小,这里咱们将 batch 的大小设置为 32 。最后咱们用 .prefetch() 在后台预加载数据,该操做可以在模型训练的时候进行,从而减小训练时间,下图直观地描述了 .prefetch() 的做用。


640?wx_fmt=png


不采起 prefetch 操做,CPU 和 GPU/TPU 的大部分时间都处在空闲状态


640?wx_fmt=png


采起 prefetch 操做后,CPU 和 GPU/TPU 的空闲时间显著较少


在该步骤中,有几点值得注意:


  1. 操做顺序很重要。若是先执行 .shuffle() 操做,再执行 .repeat() 操做,那么将进行跨 batch 的数据打乱操做,每一个 epoch 中的 batch 数据都是被提早打乱的,而不用每次加载一个 batch 就打乱依一次它的数据顺序;若是先执行 .repeat() 操做,再执行 .shuffle() 操做,那么每次只有单个 batch 内的数据次序被打乱,而不会进行跨 batch 的数据打乱操做。

  2. buffer_size 设置为和数据集大小同样,这样数据可以被充分的打乱,可是 buffer_size 过大会致使消耗更多的内存。

  3. 在开始进行打乱操做以前,系统会分配一个缓冲区,用于存放即将进行打乱的数据,所以在数据集开始工做以前,过大的 buffer_size 会致使必定的延时。

  4. 在缓冲区没有彻底释放以前,正在执行打乱操做的数据集不会报告数据集的结尾。而数据集会被 .repeat() 重启,这将会又一次致使 3 中提到的延时。


上面提到的 .shuffle ()和 .repeat(),能够用 tf.data.Dataset.apply() 中的 tf.data.experimental.shuffle_and_repeat() 来代替:


 
 
ds = image_label_ds.apply( tf.data.experimental.shuffle_and_repeat(buffer_size=image_count))	
ds = ds.batch(BATCH_SIZE)	
ds = ds.prefetch(buffer_size=AUTOTUNE)


1.3 数据增广


数据增广是提升深度学习模型鲁棒性的重要技术,它能够防止过拟合,而且可以帮助模型理解不一样数据类的独有特征。例如,咱们想要获得一个能区分“向日葵”和“郁金香”的模型,若是模型只学习了花的颜色从而进行辨别,那显然是不够的。咱们但愿模型可以理解花瓣的形状和相对大小,是否存在圆盘小花等等。


为了防止模型使用颜色做为主要的判别依据,可使用黑白图片或者改变图片的亮度参数。为了减少图片拍摄方向致使的误差,能够随机旋转数据集中的图片,依次类推,能够获得更多增广的图像。


在训练阶段,对数据进行实时增广操做,而不是手动的将这些增广图像添加到数据上。用以下所示的映射函数来实现不一样类型的数据增广:


 
 
def augment_data(image, label):	
  print("Augment data called!")	
  image = tf.image.random_flip_left_right(image)	
  image = tf.image.random_contrast(image, lower=0.0, upper=1.0)	
  # Add more augmentation of your choice	
  return image, label	
	
train = train.map(augment_data)


1.4 数据集可视化


经过可视化数据集中的一些随机样本,不只能够发现其中存在的异常或者误差,还能够发现特定类别的图像的变化或类似程度。使用 train.take() 能够批量获取数据集,并将其转化为 numpy 数组, tfds.as_numpy(train) 也具备相同的做用,以下代码所示:


 
 
plt.figure(figsize=(12,12)) 	
	
for batch in train.take(1):	
    for i in range(9):	
        image, label = batch[0][i], batch[1][i]	
        plt.subplot(3, 3, i+1)	
        plt.imshow(image.numpy())	
        plt.title(get_label_name(label.numpy()))	
        plt.grid(False)    	
# OR	
for batch in tfds.as_numpy(train):	
    for i in range(9):	
        image, label = batch[0][i], batch[1][i]	
        plt.subplot(3, 3, i+1)	
        plt.imshow(image)	
        plt.title(get_label_name(label))	
        plt.grid(False)	
    # We need to break the loop else the outer loop	
    # will loop over all the batches in the training set	
    break


运行上述代码,咱们获得了一些样本图像的可视化结果,以下所示:


640?wx_fmt=png


2. 用tf.keras 搭建一个简单的CNN模型


tf.keras 是一个符合 Keras API 标准的 TensorFlow 实现,它是一个用于构建和训练模型的高级API,并且对 TensorFlow 特定功能的支持至关好(例如 eager executiontf.data 管道)。 tf.keras 不只让 TensorFlow 变得更加易于使用,并且还保留了它的灵活和高效。


张量 (image_height, image_width, color_channels) 做为模型的输入,在这里不用考虑 batch 的大小。黑白图像只有一个颜色通道,而彩色图像具备三个颜色通道 (R,G,B) 。在此,咱们采用彩色图像做为输入,输入图像尺寸为 (128,128,3) ,将该参数传递给 shape,从而完成输入层的构建。

接下来咱们将用一种很常见的模式构建 CNN 的卷积部分:一系列堆叠的 Conv2D 层和 MaxPooling2D 层,以下面的代码所示。最后,将卷积部分的输出((28,28,64)的张量)馈送到一个或多个全链接层中,从而实现分类。


值得注意的是,全链接层的输入必须是一维的向量,而卷积部分的输出倒是三维的张量。所以咱们须要先将三维的张量展平成一维的向量,而后再将该向量输入到全链接层中。数据集中有 5 个类别,这些信息能够从数据集的元数据中获取。所以,模型最后一个全链接层的输出是一个长度为 5 的向量,再用 softmax 函数对它进行激活,至此就构建好了 CNN 模型。


 
 
from tensorflow import keras	
	
# Creating a simple CNN model in keras using functional API	
def create_model():	
    img_inputs = keras.Input(shape=IMG_SHAPE)	
    conv_1 = keras.layers.Conv2D(32, (3, 3), activation='relu')(img_inputs)	
    maxpool_1 = keras.layers.MaxPooling2D((2, 2))(conv_1)	
    conv_2 = keras.layers.Conv2D(64, (3, 3), activation='relu')(maxpool_1)	
    maxpool_2 = keras.layers.MaxPooling2D((2, 2))(conv_2)	
    conv_3 = keras.layers.Conv2D(64, (3, 3), activation='relu')(maxpool_2)	
    flatten = keras.layers.Flatten()(conv_3)	
    dense_1 = keras.layers.Dense(64, activation='relu')(flatten)	
    output = keras.layers.Dense(metadata.features['label'].num_classes, activation='softmax')(dense_1)	
	
    model = keras.Model(inputs=img_inputs, outputs=output)	
    	
    return model


上面的模型是经过 Kearas 的 Functional API 构建的,在 Keras中 还有另外一种构建模型的方式,即便用 Model Subclassing API,它按照面向对象的结构来构建模型并定义它的前向传递过程。


2.1 编译和训练模型


在 Keras 中,编译模型就是为其设置训练过程的参数,即设置优化器、损失函数和评估指标。经过调用 model.fit() 函数来设置这些参数,例如能够设置训练的 epoch 次数,再例如直接对 trianvalidation 调用 .repeat() 功能,并传递给 .fit() 函数,这样就能够保证模型在数据集上循环训练指定的 epoch 次数。


在调用 .fit() 函数以前,咱们须要先计算几个相关的参数:


 
 
# Calculating number of images in train, val and test sets	
num_train, num_val, num_test = (	
metadata.splits['train'].num_examples * weight/10 	
for weight in SPLIT_WEIGHTS	
)	
steps_per_epoch = round(num_train)//BATCH_SIZE	
validation_steps = round(num_val)//BATCH_SIZE


如上代码所示,因为下载的数据集没有定义标准的分割形式,咱们经过设置 8:1:1 的分割比例,将数据集依次分为训练集、验证集和测试验证集。


  • steps_per_epoch:该参数定义了训练过程当中,一个 epoch 内 batch 的数量,该参数的值等于样本数量除以 batch 的大小。

  • validation_steps:该参数和 steps_per_epoch 具备相同的内涵,只是该参数用于验证集。


 
 
def train_model(model):	
    model.compile(optimizer='adam',	
                  loss='sparse_categorical_crossentropy',	
                  metrics=['accuracy'])	
	
    # Creating Keras callbacks 	
    tensorboard_callback = keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)	
    model_checkpoint_callback = keras.callbacks.ModelCheckpoint(	
        'training_checkpoints/weights.{epoch:02d}-{val_loss:.2f}.hdf5', period=5)	
    os.makedirs('training_checkpoints/', exist_ok=True)	
    early_stopping_checkpoint = keras.callbacks.EarlyStopping(patience=5)	
	
    history = model.fit(train.repeat(),	
              epochs=epochs, 	
              steps_per_epoch=steps_per_epoch,	
              validation_data=validation.repeat(),	
              validation_steps=validation_steps,	
              callbacks=[tensorboard_callback,	
                         model_checkpoint_callback,	
                         early_stopping_checkpoint])	
    	
    return history


2.2 可视化训练过程当中的评估指标变化


以下图所示,咱们将训练集和验证集上的评估指标进行了可视化,该指标为 train_model() 或者 manually_train_model() 的返回值。在这里,咱们使用 Matplotlib 绘制曲线图:


640?wx_fmt=png

训练集和验证集的评估指标随着训练epoch的变化


这些可视化图能让咱们更加深刻了解模型的训练程度。在模型训练过程当中,确保训练集和验证集的精度在逐渐增长,而损失逐渐减小,这是很是重要的。


  • 若是训练精度高但验证精度低,那么模型极可能出现了过拟合。这时咱们须要对数据进行增广,或者直接从网上下载更多的图像,从而增长训练集。此外,还能够采用一些防止过拟合的技术,例如 Dropout 或者 BatchNormalisation 。

  • 若是训练精度和验证精度都较高,可是验证精度比训练精度略高,那么验证集极可能包含较多易于分类的图像。有时咱们使用 Dropout 和 BatchNorm 等技术来防止过拟合,可是这些操做会为训练过程添加一些随机性,使得训练更加困难,所以模型在验证集上表现会更好些。稍微拓展一点讲,因为训练集的评估指标是对一个 epoch 的平均估计,而验证集的评估指标倒是在这个 epoch 结束后,再对验证集进行评估的,所以验证集所用的模型能够说要比训练集的模型训练的更久一些。


TensorFlow2.0 能够在 Jupyter notebook 中使用功能齐全的 TensorBoard 。在模型开始训练以前,先启动 TensorBoard ,这样咱们就能够在训练过程当中动态观察这些评估指标的变化。以下代码所示(注意:须要提早建立 logs/  文件夹):


 
 
%load_ext tensorboard.notebook	
%tensorboard --logdir logs/


640?wx_fmt=png

Jupyer notebook 中的TensorBoard 视图


3. 使用预训练的模型


在上一节中,咱们训练了一个简单的 CNN 模型,它给出了大约 70% 的准确率。经过使用更大、更复杂的模型,得到更高的准确率,预训练模型是一个很好的选择。预训练模型一般已经在大型的数据集上进行过训练,一般用于完成大型的图像分类任务。直接使用预训练模型来完成咱们的分类任务,咱们也能够运用迁移学习的方法,只使用预训练模型的一部分,从新构建属于本身的模型。


简单来说,迁移学习能够理解为:一个在足够大的数据集上通过训练的模型,可以有效地做为视觉感知的通用模型,经过使用该模型的特征映射,咱们就能够构建一个鲁棒性很强的模型,而不须要不少的数据去训练。


3.1 下载预训练模型


本次将要用到的模型是由谷歌开发的 InceptionV3 模型,该模型已经在 ImageNet 数据集上进行过预训练,该数据集含有 1.4M 张图像和相应的 1000 个类别。InceptionV3 已经学习了咱们常见的 1000 种物体的基本特征,所以,该模型具备强大的特征提取能力。


模型下载时,须要指定参数 include_top=False,该参数使得下载的模型不包含最顶层的分类层,由于咱们只想使用该模型进行特征提取,而不是直接使用该模型进行分类。预训练模型的分类模块一般受原始的分类任务限制,若是想将预训练模型用在新的分类任务上,咱们须要本身构建模型的分类模块,并且须要将该模块在新的数据集上进行训练,这样才能使模型适应新的分类任务。


 
 
from tensorflow import keras	
	
# Create the base model from the pre-trained model MobileNet V2	
base_model = keras.applications.InceptionV3(input_shape=IMG_SHAPE,	
# We cannot use the top classification layer of the pre-trained model as it contains 1000 classes.	
# It also restricts our input dimensions to that which this model is trained on (default: 299x299)	
                                               include_top=False, 	
                                               weights='imagenet')


咱们将预训练模型当作一个特征提取器,输入(128,128,3)的图像,获得(2,2,2048)的输出特征。特征提取器能够理解为一个特征映射过程,最终的输出特征是输入的多维表示,在新的特征空间中,更加利于图像的分类。


3.2 添加顶层的分类层


因为指定了参数 include_top=False,下载的 InceptionV3 模型不包含最顶层的分类层,所以咱们须要添加一个新的分类层,并且它是为 tf_flowers 所专门定制的。经过 Keras 的序列模型 API,将新的分类层堆叠在下载的预训练模型之上,代码以下:


 
 
def build_model():	
    	
    # Using Sequential API to stack up the layers	
    model = keras.Sequential([	
        base_model,	
        keras.layers.GlobalAveragePooling2D(),	
        keras.layers.Dense(metadata.features['label'].num_classes, 	
                           activation='softmax')	
    ])	
    	
    # Compile the model to configure training parameters	
    model.compile(optimizer='adam',	
                  loss='sparse_categorical_crossentropy',	
                  metrics=['accuracy'])	
    return model	
	
inception_model = build_model()


以上代码理解以下:


  1. 对于每张图片,使用 keras.layers.GlobalAveragePooling2D() 层对提取的特征 (2x2x2048) 进行平均池化,从而将该特征转化为长度为 2048 的向量。

  2. 在平均池化层之上,添加一个全链接层 keras.layers.Dense(),将长度为 2048 的向量转化为长度为 5 的向量。


值得注意的是,在模型的编译和训练过程当中,咱们使用 base_model.trainable = False 将卷积模块进行了冻结,该操做能够防止在训练期间更新卷积模块的权重,接下来就能够在 tf_flowers 数据集上进行模型训练了。


3.3 训练顶层的分类层


训练的步骤和上文中 CNN 的训练步骤相同,以下图所示,咱们绘制了训练集和验证集的判据指标随训练过程变化的曲线图:


640?wx_fmt=png


开始训练预训练模型后,训练集和验证集的评估指标随着训练epoch的变化

从图中能够看到,验证集的精度高略高于训练集的精度。这是一个好兆头,说明该模型的泛化能力较好,使用测试集来评估模型能够进一步验证模型的泛化能力。若是想让模型取得更好的效果,对模型进行微调。


3.4 对预训练网络进行微调


在上面的步骤中,咱们仅在 InceptionV3 模型的基础上简单训练了几层网络,并且在训练期间并无更新其卷积模块的网络权重。为了进一步提升模型的性能,对卷积模块的顶层进行微调。在此过程当中,卷积模块的顶层和咱们自定义的分类层联系了起来,它们都将为 tf_flowers 数据集提供定制化的服务。具体的内容能够参见 TensorFlow 的官网解释。


连接:

https://www.tensorflow.org/alpha/tutorials/images/transfer_learning#fine_tuning


下面的代码将 InceptionV3 的卷积模块顶层进行了解冻,使得它的权重能够跟随训练过程进行改变。因为模型已经发生了改变,再也不是上一步的模型了,所以在训练新的模型以前,咱们须要对模型从新编译一遍。


 
 
# Un-freeze the top layers of the model	
base_model.trainable = True	
# Let's take a look to see how many layers are in the base model	
print("Number of layers in the base model: ", len(base_model.layers))	
	
# Fine tune from this layer onwards	
fine_tune_at = 249	
	
# Freeze all the layers before the `fine_tune_at` layer	
for layer in base_model.layers[:fine_tune_at]:	
    layer.trainable =  False	
    	
# Compile the model using a much lower learning rate.	
inception_model.compile(optimizer = tf.keras.optimizers.RMSprop(lr=0.0001),	
              loss='sparse_categorical_crossentropy',	
              metrics=['accuracy'])	
	
history_fine = inception_model.fit(train.repeat(), 	
                                   steps_per_epoch = steps_per_epoch,	
                                   epochs = finetune_epochs, 	
                                   initial_epoch = initial_epoch,	
                                   validation_data = validation.repeat(), 	
                                   validation_steps = validation_steps)


微调的目的是使得模型提取的特征更加适应新的数据集,所以,微调后的模型可让准确度提升好几个百分点。可是若是咱们的训练数据集很是小,而且和 InceptionV3 原始的预训练集很是类似,那么微调可能会致使模型过拟合。以下图所示,在微调以后,咱们再次绘制了训练集和验证集的评估指标的变化。


注意:本节中的微调操做是针对预训练模型中的少许顶层卷积层进行的,所须要调节的参数量较少。若是咱们将预训练模型中全部的卷积层都解冻了,直接将该模型和自定义的分类层联合,经过训练算法对全部图层进行训练,那么梯度更新的量级是很是巨大的,并且预训练模型将会忘记它曾经学会的东西,那么预训练就没有太大的意义了。


640?wx_fmt=png

微调模型后,训练集和验证集的评估指标随着训练epoch的变化


从图中能够看到,训练集和验证集的精度都有所提高。咱们观察到,在从微调开始的第一个 epoch 结束后,验证集的偏差开始上升,但它最终仍是随着训练过程而降低了。这多是由于权重更新得过快,从而致使了震荡。所以,相比于上一步中的模型,微调更加适合较低的学习率。


4. 使用 TensorFlow Serving 为模型发布服务


TensorFlow Serving 可以将模型发布,从而使得咱们可以便捷地调用该模型,完成特定环境下的任务。TensorFlow Serving 将提供一个 URL 端点,咱们只须要向该端点发送 POST 请求,就能够获得一个 JSON 响应,该响应包含了模型的预测结果。能够看到,咱们根本就不用担忧硬件配置的问题,一个简单的 POST 请求就能够解决复杂的分类问题。


4.1 安装 TensorFlow Serving


一、添加 TensorFlow Serving的源(一次性设置)


 
 
$ echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list && \	
$ curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -


二、安装并更新 TensorFlow ModelServer


 
 
$ apt-get update && apt-get install tensorflow-model-server


一旦安装完成,就可使用以下命令开启 TensorFlow Serving 服务。


 
 
$tensorflow_model_server


4.2 将 Keras 模型导出为 SavedModel 格式


为了将训练好的模型加载到 TensorFlow Serving 服务器中,首先咱们须要将模型保存为 SavedModel 格式。TensorFlow 提供了 SavedModel 格式的导出方法,该方法简单易用,很快地导出 SavedModel 格式。


下面的代码会在指定的目录中建立一个 protobuf 文件,经过该文件,查询模型的版本号。在实际的使用中,请求服务的版本号,TensorFlow Serving 将会为咱们选择相应版本的模型进行服务。每一个版本的模型都会导出到相应的子目录下。


 
 
from tensorflow import keras	
	
# '/1' specifies the version of a model, or "servable" we want to export	
path_to_saved_model = 'SavedModel/inceptionv3_128_tf_flowers/1'	
	
# Saving the keras model in SavedModel format	
keras.experimental.export_saved_model(inception_model, path_to_saved_model)	
	
# Load the saved keras model back	
restored_saved_model = keras.experimental.load_from_saved_model(path_to_saved_model)


4.3 启动 TensorFlow Serving 服务器


在本地启动 TensorFlow Serving 服务器,可使用以下代码:


 
 
$ tensorflow_model_server --model_base_path=/home/ubuntu/Desktop/Medium/TF2.0/SavedModel/inceptionv3_128_tf_flowers/ --rest_api_port=9000 --model_name=FlowerClassifier


  • --model_base_path:该路径必须指定为绝对路径,不然就会报以下的错误:

 
 
Failed to start server. Error: Invalid argument: Expected model ImageClassifier to have an absolute path or URI; got base_path()=./inceptionv3_128_tf_flowers
  • --rest_api_port:Tensorflow Serving 将会在 8500 端口上启动一个 gRPC ModelServer 服务,而 REST API 会在 9000 端口开启。

  • --model_name:用于指定 Tensorflow Serving 服务器的名字,当咱们发送 POST 请求的时候,将会用到服务器的名字。服务器的名字能够按照咱们的喜爱来指定。


4.4 向TensorFlow服务器发送 REST请求


TensorFlow ModelServer 支持 RESTful API。咱们须要将预测请求做为一个 POST,发送到服务器的 REST 端点。在发送 POST 请求以前,先加载示例图像,并对它作一些预处理。


TensorFlow Serving 服务器的指望输入为(1,128,128,3)的图像,其中,"1" 表明 batch 的大小。经过使用 Keras 库中的图像预处理工具,可以加载图像并将其转化为指定的大小。


服务器 REST 端点的 URL 遵循如下格式:


 
 
http://host:port/v1/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]:predict


其中,/versions/${MODEL_VERSION} 是一个可选项,用于选择服务的版本号。下面的代码先加载了输入图像,并对其进行了预处理,而后使用上面的 REST 端点发送 POST 请求:


 
 
import json, requests	
from tensorflow.keras.preprocessing.image import img_to_array, load_img	
import numpy as np	
	
image_path = 'sunflower.jpg'	
# Loading and pre-processing our input image	
img = image.img_to_array(image.load_img(image_path, target_size=(128, 128))) / 255.	
img = np.expand_dims(img, axis=0)	
payload = {"instances": img.tolist()}	
	
# sending post request to TensorFlow Serving server	
json_response = requests.post('http://localhost:9000/v1/models/FlowerClassifier:predict', json=payload)	
pred = json.loads(json_response.content.decode('utf-8'))	
	
# Decoding the response using decode_predictions() helper function	
# You can pass "k=5" to get top 5 predicitons	
get_top_k_predictions(pred, k=3)


代码的输出以下:


 
 
Top 3 predictions:	
[('sunflowers', 0.978735), ('tulips', 0.0145516), ('roses', 0.00366251)]


5. 总结


最后对本文的要点简单总结以下:


  1. 利用 TensorFlow Datasets ,咱们只须要几行代码,就能够下载公开可用的数据集。不只如此, TensorFlow Datasets 还能有效构建数据集,对模型训练有很大的帮助。

  2. tf.keras 不只可以让咱们从头开始构建一个 CNN 模型,它还能帮助咱们利用预训练的模型,在短期内训练一个有效的花卉分类模型,而且得到更高的准确率。

  3. 使用 TensorFlow Serving 服务器可以将训练好的模型发布。咱们只须要调用 URL 端点,就能够轻松将训练好的模型集成到网站或者其余应用程序中。


相关连接:

https://medium.com/@himanshurawlani/getting-started-with-tensorflow-2-0-faf5428febae


(*本文为 AI科技大本营编译文章,转载请联系原做者)


CTA核心技术及应用峰会


5月25-27日,由中国IT社区CSDN与数字经济人才发展中心联合主办的第一届CTA核心技术及应用峰会将在杭州国际博览中心隆重召开,峰会将围绕人工智能领域,邀请技术领航者,与开发者共同探讨机器学习和知识图谱的前沿研究及应用。


更多重磅嘉宾请识别海报二维码查看点击阅读原文即刻抢购。添加小助手微信15101014297,备注“CTA”,了解票务以及会务详情。


640?wx_fmt=jpeg


推荐阅读


640?wx_fmt=png

点击阅读原文,了解CTA核心技术及应用峰会