查看原文
其他

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

热爱技术的 AI科技大本营 2019-05-25

作者 | Himanshu Rawlani

译者 | Monanfei,责编 | 琥珀

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


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


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

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

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

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

 

本教程的所有源代码都已发布到 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 tfdsprint(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_validation 和 raw_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() 的作用。



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



采取 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) # ORfor 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


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



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


tf.keras 是一个符合 Keras API 标准的 TensorFlow 实现,它是一个用于构建和训练模型的高级API,而且对 TensorFlow 特定功能的支持相当好(例如 eager execution 和 tf.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 APIdef 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 次数,再例如直接对 trian 和 validation 调用 .repeat() 功能,并传递给 .fit() 函数,这样就可以保证模型在数据集上循环训练指定的 epoch 次数。


在调用 .fit() 函数之前,我们需要先计算几个相关的参数:


# Calculating number of images in train, val and test setsnum_train, num_val, num_test = (metadata.splits['train'].num_examples * weight/10 for weight in SPLIT_WEIGHTS)steps_per_epoch = round(num_train)//BATCH_SIZEvalidation_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 绘制曲线图:


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


这些可视化图能让我们更加深入了解模型的训练程度。在模型训练过程中,确保训练集和验证集的精度在逐渐增加,而损失逐渐减少,这是非常重要的。


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

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


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


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


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 V2base_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 的训练步骤相同,如下图所示,我们绘制了训练集和验证集的判据指标随训练过程变化的曲线图:



开始训练预训练模型后,训练集和验证集的评估指标随着训练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 modelbase_model.trainable = True# Let's take a look to see how many layers are in the base modelprint("Number of layers in the base model: ", len(base_model.layers))
# Fine tune from this layer onwardsfine_tune_at = 249
# Freeze all the layers before the `fine_tune_at` layerfor 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 原始的预训练集非常相似,那么微调可能会导致模型过拟合。如下图所示,在微调之后,我们再次绘制了训练集和验证集的评估指标的变化。


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


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


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


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


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


4.1 安装 TensorFlow Serving


1、添加 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 -


2、安装并更新 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 exportpath_to_saved_model = 'SavedModel/inceptionv3_128_tf_flowers/1'
# Saving the keras model in SavedModel formatkeras.experimental.export_saved_model(inception_model, path_to_saved_model)
# Load the saved keras model backrestored_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, requestsfrom tensorflow.keras.preprocessing.image import img_to_array, load_imgimport numpy as np
image_path = 'sunflower.jpg'# Loading and pre-processing our input imageimg = 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 serverjson_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 predicitonsget_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”,了解票务以及会务详情。



推荐阅读


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

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存