使用Tensorflow的转移学习的图像分类器
迁移学习是一种在一个问题上训练神经网络的技术,然后将训练好的神经网络应用于一个不同但相关的问题。它的重点是存储在解决一个问题时获得的知识,并将其应用于不同但相关的问题。迁移学习减少了训练时间,并产生一个表现良好的模型。
例如,在学习识别柠檬时获得的知识可以应用于识别橙子。柠檬和橙子是不同但相关的问题。神经网络经过微调以满足用户的需求,而不是从头开始训练。
在本教程中,我们将建立一个模型,对玩石头、纸、剪刀游戏的手的图像进行分类。我们将从TensorFlow中心下载一个预训练的MobileNet-v2卷积神经网络。然后,我们将对它进行微调,对玩石头、剪刀、布游戏的手的图像进行分类。
前提条件
要继续学习本教程,读者应该。
- 知道如何使用TensorFlow建立[深度学习模型]。
- 了解[卷积神经网络]的基础知识。
- 使用[谷歌Colab]。
导入重要的库
对于本教程,请导入以下库。
import matplotlib.pylab as plt
import tensorflow as tf
import tensorflow_hub as hub
import os
import numpy as np
import tensorflow_datasets as tfds
这些库在建立我们的转移学习模型中很重要。这些库的功能分别如下。
matplotlib.pylab- 它是一个可视化库。我们使用Matplotlib来绘制线图、数字和图表。
tensorflow- 它是一个用于机器学习和人工智能的开源库。我们用它来为我们的图像分类模型创建输入层、辍学层和密集层。
tensorflow_hub- 它是一个TensorFlow资源库,包含预训练模型的集合。
os- 它使我们能够与操作系统互动。Python中的OS模块提供了创建和删除目录、获取其内容、改变和识别当前目录的函数。
numpy- 它将把图像数据集转换成数组。它还使我们能够对数组进行数学运算。
tensorflow_datasets- 它是一个TensorFlow库,是由一系列随时可用的数据集组成的。
下载图像数据集
我们将使用以下代码从tensorflow_datasets ,下载石头、布、剪刀的图像数据集。
datasets, info = tfds.load(name='rock_paper_scissors', with_info=True, as_supervised=True, split=['train','test'])
我们已经下载了该数据集,并将其保存到train 和test 集。
为了检查我们的数据集中的可用信息,运行这个命令。
info
输出显示如下。

从上面的图片中,我们总共有2892张图片。图像大小为300 by300 像素,我们有3个类。让我们来显示一些图像。
显示图片
为了显示图像,我们将指定要显示的图像集。我们将使用以下代码显示train 集。
train, info_train = tfds.load(name='rock_paper_scissors', with_info=True, split='test')
tfds.show_examples(info_train,train)
图片显示如下。

图像洗牌
我们通过洗牌来减少模型的偏差。洗牌使模型能够学习而不是记忆图像。
dataset=datasets[0].concatenate(datasets[1])
dataset=dataset.shuffle(3000)
在上面的代码中,我们首先将两个图像集(训练和测试)连接起来。然后,对3000张图像进行随机洗牌。
将数据集分割成三组
洗完数据集后,将数据集分成三组。培训集、验证集和测试集。
-
培训集:它被用来训练模型。模型从这个集合中学习。
-
验证集:它被用来微调模型的超参数,以便我们能有一个优化的模型。
-
测试集:它用于评估训练后的最终模型。它检查模型是否能做出准确的预测。
我们使用以下代码分割数据集。
rsp_val=dataset.take(600)
rsp_test_temp=dataset.skip(600)
rsp_test=rsp_test_temp.take(400)
rsp_train=rsp_test_temp.skip(400)
从上面的代码中,我们将600 图像作为验证集,400 图像作为测试集,400 图像作为训练集。
图像归一化和调整大小
图像规范化是将图像的像素强度值的范围改为预定义范围的过程。通常,预定义的范围通常是[0,1],或[-1,1]。在本教程中,我们希望我们的像素范围是[0, 1]。
图像大小调整是改变图像大小的过程。这使得调整后的图像能够适应你正在构建的神经网络。要执行这个过程,请使用以下函数。
def scale(image, label):
image = tf.cast(image, tf.float32)
image /= 255.0
return tf.image.resize(image,[224,224]), tf.one_hot(label, 3)
从上面的代码来看,我们通过将图像除以255来执行图像的正常化。它将改变像素范围为0,1。代码还使用tf.image.resize 方法将我们的图像大小调整为224乘224。这与预训练的MobileNet-v2卷积神经网络的图像大小相同。
最后,代码使用tf.one_hot 方法进行了一次热编码。一次热编码将分类变量(石头、纸、剪刀)转换为整数值(0、1、2)。神经网络能理解整数值(数值)。在这个过程之后,我们需要为每个集合添加一个批次大小。
添加批量大小
批量大小是指在一次迭代(epoch)过程中,每组使用的数据样本的数量。我们将设置批处理大小为64 。这是用以下函数完成的。
def get_dataset(batch_size=64):
train_dataset_scaled = rsp_train.map(scale).shuffle(1900).batch(batch_size)
test_dataset_scaled = rsp_test.map(scale).batch(batch_size)
val_dataset_scaled = rsp_val.map(scale).batch(batch_size)
return train_dataset_scaled, test_dataset_scaled, val_dataset_scale
从上面的代码来看,每个集合(训练、验证和测试)在一个迭代(epoch)期间都会有64 图像。
我们调用get_dataset ,将其应用于数据集。
train_dataset, test_dataset, val_dataset = get_dataset()
最后,缓存训练集和验证集,以便模型可以使用。
缓存数据集
要缓存数据集,请使用这段代码。
train_dataset.cache()
val_dataset.cache()
这个数据集现在已经可以使用了。下一步是下载MobileNet-v2卷积神经网络。
下载MobileNet-v2卷积神经网络
要下载这个神经网络,请运行这个命令。
feature_extractor = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
这个模型已经用不同的图像进行了预训练。MobileNet-v2遵循卷积神经网络架构。它是由特征提取层(卷积层和池化层的集合)和全连接层组成的。
我们将应用这个模型对玩石头、剪刀、布游戏的手的图像进行分类。为了使用这个模型,我们从MobileNet-v2模型中提取特征提取器层。然后,我们在建立模型时将特征提取层作为输入层。
从MobileNet-v2模型中提取特征提取器层
MobileNet-v2模型的特征提取层是由一系列堆叠的卷积层和池化层组成的。这一层非常重要,用于从输入图像中提取重要的特征。
我们使用以下代码提取该层。
feature_extractor_layer = hub.KerasLayer(feature_extractor, input_shape=(224,224,3))
这个层已经被训练过了。为了确保在我们建立神经网络时它不会被训练,请运行以下代码。
feature_extractor_layer.trainable = False
初始化神经网络
我们按以下方式初始化我们的神经网络。
model = tf.keras.Sequential([
feature_extractor_layer,
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(3,activation='softmax')
])
从上面的代码来看,我们正在建立一个连续的模型,允许层与层之间相互建立。我们将feature_extractor_layer 作为神经网络的输入。然后,我们添加一个Dropout 层,以防止模型过拟合。
最后,添加Dense 层,这是该神经网络的输出层。它有3个神经元,因为我们的模型有三个类。我们使用softmax ,因为我们有两个以上的类。
要检查这个模型的摘要,请使用这个代码。
model.summary()

图片显示了模型类型(顺序)和初始化层。它还显示了模型的总参数(2,261,827)。一些参数是可训练的,而另一些是不可训练的。可训练的参数(3,843)是神经网络将训练的参数。不可训练的参数(2,257,984)是来自feature_extractor_layer ,它们已经被训练过了。与可训练参数相比,不可训练参数的数量更多。这将节省训练时间。
模型编译
在模型编译中,我们确定神经网络所使用的metrics 、optimizer 、loss function 。
衡量标准
它被用来计算神经网络的准确性分数。这决定了模型做出准确预测的概率。
优化器
它用于提高模型的性能,因为它从训练集中学习。优化器在训练期间对模型进行故障排除,并消除错误。最常见的优化器是Adam 优化器,我们将在这个神经网络中使用。
损失函数
它用于确定模型的总误差。我们将使用CategoricalCrossentropy ,因为我们的数据集是由三个类别组成的(石头、纸、剪刀)。要编译这个模型,请使用这个代码。
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=['acc'])
下一步是将我们编译的模型拟合到train_dataset 和val_dataset 。
模型拟合
在模型拟合过程中,模型将从train_dataset 。val_dataset ,用于微调模型参数,以便我们有一个优化的模型。
history = model.fit_generator(train_dataset, epochs=2, validation_data=val_dataset)
我们还设置了epochs=2 。在训练期间,模型将通过train_dataset 和val_dataset 迭代这个次数。当我们运行这段代码时,训练过程将开始并产生以下输出。

从上面的图片来看,第一个历时后的模型准确度得分是0.8333 。这代表83.33% 。在第二次迭代后,准确率得分增加到0.9722 ,这代表97.22 。该模型改善并增加了做出正确分类的机会。
使用测试集的准确度得分
测试准确率得分是用来评估训练后的最终模型的。它检查使用测试数据集的模型性能。
result=model.evaluate(test_dataset)
准确率得分如下所示。
7/7 [==============================] - 1s 88ms/step - loss: 0.6086 - acc: 0.9850
准确率得分是98,50% 。这表明我们的模型在使用训练和测试数据集时都表现良好。下一步是使用该模型进行预测。
进行预测
我们使用测试数据集中的10张图片来进行预测。for 循环将被用来从测试数据集中选择10张图片。
for test_sample in rsp_test.take(10):
image, label = test_sample[0], test_sample[1]
image_scaled, label_arr= scale(test_sample[0], test_sample[1])
image_scaled = np.expand_dims(image_scaled, axis=0)
选择完图像后,让我们打印预测结果。
打印预测结果
我们将打印actual label 和predicted label 。actual label 代表测试数据集中的实际图像类别/类。predicted label 是模型预测的类别/类。
img = tf.keras.preprocessing.image.img_to_array(image)
pred=model.predict(image_scaled)
print(pred)
plt.figure()
plt.imshow(image)
plt.show()
print("Actual Label: %s" % info.features["label"].names[label.numpy()])
print("Predicted Label: %s" % info.features["label"].names[np.argmax(pred)])
我们有tf.keras.preprocessing.image.img_to_array 方法,将图像转换成数组。我们使用predict 方法来进行预测。预测结果显示如下。

从上面的图片来看,该模型能够做出正确的预测。Actual Label 与Predicted Label 相同。
我们来看看另一个预测结果。

对于这个结果,模型能够做出正确的预测。Actual Label 与Predicted Label 相同。这表明我们的图像分类器模型训练有素。让我们保存这个训练好的模型。
保存模型
要保存模型,请使用这段代码。
model.save('./models/', save_format='tf')
这段代码将保存模型并产生以下输出。

上面的输出显示了我们的模型被保存的目录。我们可以加载这个模型并在将来使用它来进行预测。
总结
在本教程中,我们已经学会了如何使用迁移学习建立一个图像分类器。我们从TensorFlow中心下载了MobileNet-v2卷积神经网络。下载的模型被用来建立对玩石头、剪刀、布游戏的手的图像进行分类的模型。
最后,我们测试了该模型,它可以做出准确的预测。使用本教程,读者应该能够得出这个模型。