Tensorflow2.0学习(十一) — 猫狗分类迁移学习实战

这一节我们将用Tensorflow2.0完成一个图像领域处理的重要任务,即是“迁移学习”。迁移学习简单来说就是一个预训练的模型(已经在别的数据集上训练过的)重新使用在另一个数据集或任务中。迁移学习不仅大大减小了我们的新数据集的训练时间和难度,而且使得模型的泛化能力更强。那么这一节课我们就通过迁移学习来完成一个猫狗分类的例子。关于迁移学习的底层原理或更多信息,朋友们可以观看其它博主更详细的博客,或者博主在后续的博客更新中也会提到更深的原理部分。

顺便附上Tensorflow官方教程的链接:https://tensorflow.google.cn/tutorials/images/transfer_learning

一.数据集的加载

1.导入相关库。

from __future__ import absolute_import, division, print_function, unicode_literals
import os 
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow.contrib.eager as tfe

2.允许Tensorflow的eager execution模块运行。

tf.enable_eager_execution()

3.数据集的划分和加载。其中(8,1,1)分别代表训练集、测试集和验证集的比例。tfds.load中的with_info如果是true代表返回的数据集是一个元组,里面不仅仅包含了数据集还包含了和数据集有关的一切信息。而as_supervised=True则代表返回的是数据集特征+标签,如果是False那么只仅仅返回了数据集特征而没有标签。

split_weights = (8,1,1) #数据划分的比例
splits = tfds.Split.TRAIN.subsplit(weighted=split_weights)
(raw_train,raw_validation,raw_test),metadata = tfds.load('cats_vs_dogs',split=list(splits),with_info=True,as_supervised=True)

4.查看切分的数据集信息。

print(raw_train)
print(raw_validation)
print(raw_test)

可以看出返回的types中包含了unit8(图片)和int64(标签)。

5.将标签转为字符串并定义显示函数查看图片。

get_label_name = metadata.features['label'].int2str #数字转字符串
for image, label in raw_train.take(2): #显示2张图片
  plt.figure()
  plt.imshow(image)
  plt.title(get_label_name(label))

6.定义图片预处理函数并用tf.dataset相关的映射函数对数据集进行预处理以及划定batch_size的大小。

IMG_SIZE =100

def format_example(image,label):
  image = tf.cast(image,tf.float32) #将图片转为float32格式
  image = image/255.0 #图片归一化
  image = tf.image.resize(image,(IMG_SIZE,IMG_SIZE)) #修改图片尺寸
  return image,label

train = raw_train.map(format_example) #将预处理函数映射到数据中
valiadation = raw_validation.map(format_example)
test = raw_test.map(format_example)
batch_size = 32
shuffle_buffer_size = 1000 #训练缓存空间大小
train_batches = train.shuffle(shuffle_buffer_size).batch(batch_size)
valiadation_batches = valiadation.batch(batch_size)
test_batches = test.batch(batch_size)

7.查看经过预处理后,图片的尺寸。

for image_batch,label_batch in train_batches.take(1): #取一张图片
  pass
image_batch.shape

可以看出图片尺寸已成功被预处理了。

二.预训练模型的加载

1.在这次训练迁移学习中,我们使用google的预训练后的MobileNetV2来作为base_model,在这里我们的include_top参数设为False,因为我们只需要预训练模型的前面层,而最后一层(分类的输出个数)必须要满足我们现在任务的需求,因此需要重新定义。而weight='imagenet'的意思则为,该预训练模型的权重是采用在imagenet数据上训练后的权重。

image_shape = (IMG_SIZE,IMG_SIZE,3)
base_model = tf.keras.applications.MobileNetV2(input_shape=image_shape,include_top=False,weights='imagenet')

2.查看一个image_batch输入模型后的输出是什么样的。

feature_batch = base_model(image_batch)
print(feature_batch.shape)

3.将模型的可训练模式设为False。这里的意思是说我模型训练时权重参数不可再改变,冻结所有层并以之前imagenet训练的权重参数进行训练。

base_model.trainable = False

4.定义top层来满足我们本次任务的需要(分类个数),原因看第1点。这里globalaveragepooling2D层相当于全连接层,基本在迁移学习中都是用它来将前面特征数量转为单维向量。

global_average_layer = tf.keras.layers.GlobalAveragePooling2D() 
feature_batch_average = global_average_layer(feature_batch) #输入该层并查看输出
print(feature_batch_average.shape)

5.定义最后的分类结果层并查看输出结果。

prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
print(prediction_batch.shape)

6.将base_model和后面top层混合一起。

model = tf.keras.Sequential([
    base_model,
    global_average_layer,
    prediction_layer                 
])

三.模型的参数设置及训练。

1.模型相关参数设置。因为为二分类任务(猫和狗),因此loss函数为binary_crossentropy。

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate),
              loss='binary_crossentropy',
              metrics=['accuracy'])

2.打印模型概要。

model.summary()

3.设置模型训练次数。为了加快训练时间,这里epochs选为2。

initial_epochs = 2
steps_per_epoch = 10
validation_steps = 20

4.模型训练。

history = model.fit(train_batches,epochs=initial_epochs,validation_data=valiadation_batches)

5.定义函数训练过程显示函数并查看结果曲线。

def show_train_history(train_history,train,validation):
    plt.plot(train_history.history[train]) #绘制训练数据的执行结果
    plt.plot(train_history.history[validation]) #绘制验证数据的执行结果
    plt.title('Train History') #图标题 
    plt.xlabel('epoch') #x轴标签
    plt.ylabel(train) #y轴标签
    plt.legend(['train','validation'],loc='upper left') #添加左上角图例
show_train_history(history,'acc','val_acc')

四.对模型进行微调并训练。

我们还可以通过微调的方式提高模型的训练成功率。什么是微调?这里指的是冻结预训练模型MobileNetV2的基础层(基础层提取的图片特征基本适用于大部分图片,所以不微调这部分),微调它的后面一些重要的分类层,对它们进行解冻然后训练。

1.将模型首先设为可训练的,然后查看模型的总层数,设置101层-155层为可训练,前面100层为不可训练。

base_model.trainble = True
print(len(base_model.layers))
fine_tune_at = 100
for layer in base_model.layers[:fine_tune_at]:
  layer.trainble = False

2.模型参数重新设置,调低学习率。

model.compile(loss='binary_crossentropy',optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate/10),metrics=['accuracy'])

3.模型重新训练次数设置。训练次数同样为2次。

fine_tune_epochs=2
total_epochs =  initial_epochs + fine_tune_epochs

4.模型重新训练。这边initial_epoch的意思为从上次的训练之后再接着训练。

history_fine = model.fit(train_batches,epochs=total_epochs,initial_epoch=history.epoch[-1],validation_data=valiadation_batches)

5.查看训练结果曲线。

 

本节分享了一个迁移学习的实例,朋友们如果有兴趣还可以试试其它的pretrained的base_model并看看结果如何。谢谢你们的观看和支持!

 

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值