专栏首页用户5033944的专栏迁移学习之快速搭建【卷积神经网络】
原创

迁移学习之快速搭建【卷积神经网络】

前言

卷积神经网络 概念认识:https://cloud.tencent.com/developer/article/1822928

卷积神经网络 简单模型搭建:https://cloud.tencent.com/developer/article/1822778

本篇文章带大家熟悉“迁移学习”的开发流程,介绍如何使用预先训练好的神经网络,结合实际的功能需求,来实现一些图像任务;比如:实现对猫和狗的图像进行分类。

预先训练好的神经网络,通常称为“预训练模型”,它在大型数据集上进行训练,取得业界认可的效果,开源给广大开发者使用的模型。本文主要介绍在keras中的关于图像任务的开源模型。

比如:在ImageNet数据集上预训练过的用于图像分类的模型 VGG16、VGG19、ResNetV2、InceptionV3、MobileNetV2、DenseNet、NASNet等等模型。

top-1 accuracy和 top-5 accuracy 是指模型在 ImageNet 验证数据集上的性能;

Depth 是指网络的拓扑深度;这包括激活层、批次规范化层等。

这是官网的链接keras预训练模型,大家可以去探索一下

迁移学习方式

我们可以直接使用预训练模型,毕竟效果挺好的;提供输入信息,经过模型处理,直接输出结果。

也可以使用预训练模型的一部分网络结构,使用其特定的功能(比如:特征提取),然后根据给定任务自定义搭建一部分网络结构(比如:实现分类),最后组合起来就形成一个完整的神经网络啦。本文主要将这种方式。

预训练模型的优点

1)模型在足够大的数据集中训练,通常是业界的通用模型(比如:图像视觉的模型);

2)预训练模型的权重是已知了,往往不用再花时间去训练;只需训练我们自定义的网络结构即可。

思路流程

  1. 导入数据集
  2. 探索集数据,并进行数据预处理
  3. 构建模型(搭建神经网络结构、编译模型)预训练模型 + 自定义模型
  4. 训练模型(把数据输入模型、评估准确性、作出预测、验证预测)
  5. 使用训练好的模型

一、导入数据集

使用谷歌开源的数据集,包含几千张猫和狗图像;然后把数据集分为训练集、验证集、测试集。

# 该数据集包含几千张猫和狗图像;
# 下载并提取包含图像的 zip 文件,然后创建一个tf.data.Data.Dataset,
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

BATCH_SIZE = 32
IMG_SIZE = (160, 160)

# 用于使用tf.keras.preprocessing.image_dataset_from_directory 进行拆分训练集和验证集。
train_dataset = image_dataset_from_directory(train_dir,
                                             shuffle=True,
                                             batch_size=BATCH_SIZE,
                                             image_size=IMG_SIZE)

validation_dataset = image_dataset_from_directory(validation_dir,
                                                  shuffle=True,
                                                  batch_size=BATCH_SIZE,
                                                  image_size=IMG_SIZE)

由于原始数据集不包含测试集,因此将创建一个测试集。在验证集中将其中 20% 移动到测试集。

val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))
print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))

二、探索集数据,并进行数据预处理

将训练集的前 9 张图片和标签打印出来

class_names = train_dataset.class_names

plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

数据集预处理——数据增强

由于该数据集只有几千张猫和狗图像,属于小数据集,在模型训练时容易产生过拟合的;于是使用数据增强,对训练图像进行随机旋转和水平翻转,使得训练样本多样性。

data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])

RandomFlip("horizontal") 对图片进行 随机水平反转

RandomRotation(0.2) 对图片进行 随机旋转

查看一下效果:

for image, _ in train_dataset.take(1):
  plt.figure(figsize=(10, 10))
  first_image = image[0]
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    augmented_image = data_augmentation(tf.expand_dims(first_image, 0))
    plt.imshow(augmented_image[0] / 255)
    plt.axis('off')

数据集预处理——缩放像素值

将图片像素值从[0,255]重新缩放到[-1,1]

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)

为什么是除以127.5,再整体偏移-1呢?由于图片的像素范围是0~255,我们把它变成-1~1的范围,于是每张图像(训练集、测试集)都除以127.5,这时得到的范围是0~2,再整体偏移-1,就得到-1~1的范围啦。

三、构建模型

常见卷积神经网络(CNN),主要由几个 卷积层Conv2D 和 池化层MaxPooling2D 层组成。卷积层池化层的叠加实现对输入数据的特征提取,最后连接全连接层实现分类。

  • 特征提取——卷积层池化层
  • 实现分类——全连接层

这里用到“迁移学习”的思想,使用“预训练模型”作为特征提取;实现分类的全连接层有我们自己搭建。

3.1)特征提取——MobileNet V2

特征提取使用谷歌开发的MobileNet V2 模型,它是再ImageNet 数据集上预先训练的,该数据集由 140 万张图像和 1000 个类组成。

我们只使用MobileNet V2 模型的卷积层和池化层,生成base_model;不用它的全连接层,毕竟我们的输出只是识别猫和狗,不用识别1000多个类嘛。

# 使用MobileNet V2 的特征提取的网络结构、权重
IMG_SHAPE = IMG_SIZE + (3,)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,
                                               weights='imagenet')

include_top=False,是指不用MobileNet V2模型的全连接层。

对图像进行特征提取,生成feature_batch

image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print(feature_batch.shape)

冻结base_model,对预先训练好的模型,不再重新进行训练了

base_model.trainable = False

查看一下base_model的网络结构 base_model.summary( )

base_model的模型结构实在太大了,这里显示了一小部分。

3.2)实现分类

使用GlobalAveragePooling2D将每张图像转换为单个 1280 元素矢量

global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
feature_batch_average = global_average_layer(feature_batch)
print(feature_batch_average.shape)

由于进行猫和狗分类,对每个图像进行单个预测,正数预测类 1,负数预测类 0;于是全连接层用1个神经元就可以了。

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

3.3)搭建整体网络结构

通过使用Keras 功能 API将数据增强、重新缩放、base_model、feature_batch层、分类层prediction_batch 串联在一起来,构建模型。

inputs = tf.keras.Input(shape=(160, 160, 3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)

3.4)编译模型

由于有两个类(猫和狗),使用二进制交叉熵损失;

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

查看一下整体的网络结构 tf.keras.utils.plot_model(model)

或者用这种方式看看 model.summary( )

四、训练模型

这里我们输入准备好的训练集数据(包括图像、对应的标签),测试集的数据(包括图像、对应的标签),模型一共训练10次。

history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset)

下图是训练过程的截图:

通常loss越小越好,对了解释下什么是loss;简单来说是 模型预测值 和 真实值 的相差的值,反映模型预测的结果和真实值的相差程度;

通常准确度accuracy 越高,模型效果越好。从上图可以看到验证集的准确性高达95%。

评估模型

使用预训练模型MobileNet V2 作为图像特征提取器时,结合我们自定义分类层,看看训练集和验证集的准确性/损失的学习曲线。

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()

五、使用模型

通常使用 model.predict( ) 函数进行预测。

完整代码

'''
Tensorflow2.x  Python3 
'''
# 导入库
import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf

from tensorflow.keras.preprocessing import image_dataset_from_directory

# 该数据集包含几千张猫和狗图像;
# 下载并提取包含图像的 zip 文件,然后创建一个tf.data.Data.Dataset,
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

BATCH_SIZE = 32
IMG_SIZE = (160, 160)

# 用于使用tf.keras.preprocessing.image_dataset_from_directory 进行拆分训练集和验证集。
train_dataset = image_dataset_from_directory(train_dir,
                                             shuffle=True,
                                             batch_size=BATCH_SIZE,
                                             image_size=IMG_SIZE)

validation_dataset = image_dataset_from_directory(validation_dir,
                                                  shuffle=True,
                                                  batch_size=BATCH_SIZE,
                                                  image_size=IMG_SIZE)

# 由于原始数据集不包含测试集,因此将创建一个测试集。在验证集中将其中 20% 移动到测试集。
val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
print('Number of validation batches: %d' % tf.data.experimental.cardinality(validation_dataset))
print('Number of test batches: %d' % tf.data.experimental.cardinality(test_dataset))

# 将训练集的前 9 张图片和标签打印出来
class_names = train_dataset.class_names
plt.figure(figsize=(10, 10))
for images, labels in train_dataset.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")


# 数据集预处理——数据增强,对训练图像进行随机旋转和水平翻转,使得训练样本多样性。
data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])

# 数据集预处理——缩放像素值,将图片像素值从[0,255]重新缩放到[-1,1].
preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)

# 使用MobileNet V2 模型的卷积层和池化层,生成base_model;不用它的全连接层
IMG_SHAPE = IMG_SIZE + (3,)
base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
                                               include_top=False,
                                               weights='imagenet')

# 对图像进行特征提取,生成feature_batch
image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print(feature_batch.shape)

# 冻结base_model,对预先训练好的模型,不再重新进行训练了
base_model.trainable = False

# 查看一下base_model的网络结构
base_model.summary()

# 实现分类
# 使用GlobalAveragePooling2D将每张图像转换为单个 1280 元素矢量
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
feature_batch_average = global_average_layer(feature_batch)
print(feature_batch_average.shape)
# 对每个图像进行单个预测,正数预测类 1,负数预测类 0;
prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
print(prediction_batch.shape)

# 搭建整体网络结构
inputs = tf.keras.Input(shape=(160, 160, 3))
x = data_augmentation(inputs)
x = preprocess_input(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)

# 编译模型
base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

# 查看一下整体的网络结构
tf.keras.utils.plot_model(model)
model.summary()

# 训练模型
history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset)

# 评估模型
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')

plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()

参考

Tensorflow官网案例

卷积神经网络 概念认识:https://cloud.tencent.com/developer/article/1822928

卷积神经网络 简单模型搭建:https://cloud.tencent.com/developer/article/1822778

卷积神经网络 训练模型遇到过拟合问题,如何解决:https://cloud.tencent.com/developer/article/1822920

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 卷积神经网络(三) ——inception网络、迁移学习

    卷积神经网络(三) ——inception网络、迁移学习 (原创内容,转载请注明来源,谢谢) 一、Inception网络 1、简介 前面的文章中,有各种的卷积模...

    用户1327360
  • Colab 超火的 Keras/TPU 深度学习免费实战,有点 Python 基础就能看懂的快速课程

    想要真的了解深度学习,除了看视频,拿数据和算力真枪实弹的练手可能比各种理论知识更重要。

    新智元
  • Colab超火的Keras/TPU深度学习免费实战,有点Python基础就能看懂的快速课程

    想要真的了解深度学习,除了看视频,拿数据和算力真枪实弹的练手可能比各种理论知识更重要。

    统计学家
  • Colab超火的Keras/TPU深度学习免费实战,有点Python基础就能看懂的快速课程

    想要真的了解深度学习,除了看视频,拿数据和算力真枪实弹的练手可能比各种理论知识更重要。

    大数据文摘
  • 【深度学习】④--卷积神经网络与迁移学习

    1. 图像识别与定位 图像的相关任务可以分成以下两大类和四小类: 图像识别,图像识别+定位,物体检测,图像分割。 ? 图像的定位就是指在这个图片中不但识别...

    Spark学习技巧
  • 【一统江湖的大前端(9)】TensorFlow.js 开箱即用的深度学习工具

    TensorFlow是Google推出的开源机器学习框架,并针对浏览器、移动端、IOT设备及大型生产环境均提供了相应的扩展解决方案,TensorFlow.js就...

    大史不说话
  • 文献 | 2010-2016年被引用次数最多的深度学习论文(修订版)

    一、书籍 Deep learning (2015) 作者:Bengio 下载地址:http://www.deeplearningbook.org/ 二、理论 1...

    深度学习思考者
  • 深度学习不得不会的迁移学习(Transfer Learning)

    在传统的机器学习的框架下,学习的任务就是在给定充分训练数据的基础上来学习一个分类模型;然后利用这个学习到的模型来对测试文档进行分类与预测。然而,...

    小草AI
  • OpenCV4最全系统化学习路线图与教程!

    OpenCV4.0发布以来,其依靠良好的接口代码、系统级别的优化、更加通用易学的函数调用,集成OpenVINO与tensorflow、caffe等模型加速推断、...

    小小詹同学
  • 人人都会深度学习之Tensorflow基础快速入门

    《Tensorflow基础快速入门》课程的目的是帮助广大的深度学习爱好者,逐层深入,步步精通当下最流行的深度学习框架Tensorflow。该课程包含Tensor...

    吴生
  • 吴恩达最新TensorFlow专项课程开放注册,你离TF Boy只差这一步

    以前,吴恩达的机器学习课程和深度学习课程会介绍很多概念与知识,虽然也会有动手实验,但它们主要是为了帮助理解。在这一份 Coursera 新课中,吴恩达与谷歌大脑...

    机器之心
  • 吴恩达最新TensorFlow专项课程开放注册,你离TF Boy只差这一步

    以前,吴恩达的机器学习课程和深度学习课程会介绍很多概念与知识,虽然也会有动手实验,但它们主要是为了帮助理解。在这一份 Coursera 新课中,吴恩达与谷歌大脑...

    磐创AI
  • 视频教程 | 如何用Python搭建可以画风迁移的人工智能

    艺术源于生活,它诠释了我们在生活中的经历与情感。那么我们能搭建一个AI艺术家吗?答案是肯定的。这听起来很不可思议,我们可以使用一个艺术家的风格来训练出一个神经网...

    AI科技大本营
  • 使用Keras进行深度学习(二): CNN讲解及实践

    前言:现今最主流的处理图像数据的技术当属深度神经网络了,尤其是卷积神经网络CNN尤为出名。本文将通过讲解CNN的介绍以及使用keras搭建CNN常用模型LeNe...

    磐创AI
  • OpenCV4系统化学习路线图与教程

    OpenCV4.0发布以来,其依靠良好的接口代码、系统级别的优化、更加通用易学的函数调用,集成OpenVINO与tensorflow、caffe等模型加速推断、...

    磐创AI
  • OpenCV4系统化学习路线图与教程

    OpenCV4.0发布以来,其依靠良好的接口代码、系统级别的优化、更加通用易学的函数调用,集成OpenVINO与tensorflow、caffe等模型加速推断、...

    计算机视觉研究院
  • 迁移学习和fine-tune的区别

    迁移学习(Transfer learning) 顾名思义就是把已训练好的模型参数迁移到新的模型来帮助新模型训练。考虑到大部分数据或任务都是存在相关性的,所以通过...

    狼啸风云
  • ApacheCN 深度学习译文集 2020.9

    ApacheCN_飞龙
  • TensorFlow 全网最全学习资料汇总之TensorFlow的技术应用【4】

    【AI研习社】关注AI前沿、开发技巧及技术教程等方面的内容。欢迎技术开发类文章、视频教程等内容投稿,邮件发送至:zhangxian@leiphone.com 随...

    AI研习社

扫码关注云+社区

领取腾讯云代金券