《Python深度学习》第五章-3(预训练)读书笔记

Posted Paul-Huang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Python深度学习》第五章-3(预训练)读书笔记相关的知识,希望对你有一定的参考价值。

5.3 使用预训练的卷积神经网络

预训练网络(pretrained network):

  • 是一个之前已在大型数据集(通常是大规模图像分类任务)上 训 练 好 、 保 存 好 的 网 络 \\color{red}训练好、保存好的网络
  • 预训练网络 学 到 的 特 征 的 空 间 层 次 结 构 \\color{red}学到的特征的空间层次结构 可以有效地作为视觉世界的通用模型,在不同问题之间具有 可 移 植 性 \\color{red}可移植性
  • 由于预训练网络,使得深度学习 对 小 数 据 问 题 非 常 有 效 \\color{red}对小数据问题非常有效

使用预训练网络有两种方法: 特 征 提 取 ( f e a t u r e    e x t r a c t i o n ) \\color{red}特征提取(feature\\;extraction) (featureextraction) 微 调 模 型 ( f i n e − t u n i n g ) \\color{red}微调模型(fine-tuning) (finetuning)

5.3.1 特征提取

  1. 定义
    特 征 提 取 是 使 用 之 前 网 络 学 到 的 表 示 来 从 新 样 本 中 提 取 出 有 趣 的 特 征 。 \\color{red}特征提取是使用之前网络学到的表示来从新样本中提取出有趣的特征。 使

  2. 卷 积 基 \\color{red}卷积基

    • 图像分类的卷积神经网络包含两部分:首先是一系列池化层和卷积层,最后是一个密集连接分类器。第一部分叫作模型的 卷 积 基 ( c o n v o l u t i o n a l    b a s e ) \\color{red}卷积基(convolutional\\;base) (convolutionalbase)
    • 特征提取就是取出之前训练好的网络的卷积基,在上面运行新数据,然后 在 输 出 上 面 训 练 一 个 新 的 分 类 器 \\color{red}在输出上面训练一个新的分类器
      1. 为什么不用密集层:密集连接层的表示不再包含物体在输入图像中的 位 置 信 息 \\color{red}位置信息 。密集连接层舍弃了空间的概念,而物体位置信息仍然由卷积特征图所描述。
    • 某个卷积层提取的 表 示 的 通 用 性 \\color{red}表示的通用性 (以及可复用性)取决于 该 层 在 模 型 中 的 深 度 \\color{red}该层在模型中的深度

      模型型中更靠近底部的层提取的是局部的、高度通用的特征图(比如视觉边缘、颜色和纹理),而更靠近顶部的层提取的是更加抽象的概念(比如“猫耳朵”或“狗眼睛”)。

    • 如果你的新数据集与原始模型训练的数据集有很大差异,那么最好只使用模型的前几层来做特征提取,而不是使用整个卷积基。
    • 常用的模型内置于Keras 中。你可以从 keras.applications 模块中导入。
  3. VGG16模型

    from tensorflow.keras.applications import VGG16
    conv_base = VGG16(weights='imagenet',
    				  include_top=False,
    				  input_shape=(150, 150, 3))
    

    这里向构造函数中传入了三个参数。

    • weights 指定模型初始化的权重检查点
    • include_top 指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于 ImageNet 的 1000 个类别。因为我们打算使用自己的密集连接分类器(只有两个类别: cat 和 dog),所以不需要包含它。
    • input_shape输入到网络中的图像张量的形状。这个参数完全是可选的,如果不传入这个参数,那么网络能够处理任意形状的输入。
    conv_base.summary()
    

    最后的特征图形状为 (4, 4, 512) 。我们将在这个特征上添加一个密集连接分类器。下一步有两种方法可供选择。

    • 不使用数据增强的快速特征提取。
      这种方法速度快,计算代价低,因为对于每个输入图像只需运行一次卷积基,而卷积基是目前流程中计算代价最高的。
    • 使用数据增强的特征提取
      在顶部添加 Dense 层来扩展已有模型(即 conv_base ),并在输入数据上端到端地运行整个模型。

5.3.1.1. 不使用数据增强的快速特征提取

首先,运行ImageDataGenerator实例,将图像及其标签提取为Numpy数组。调用 conv_base 模型的predict方法来从这些图像中提取特征。第一种方法的代码: 保 存 你 的 数 据 在 \\color{red}保存你的数据在 conv_base 中的输出 然 后 将 这 些 输 出 作 为 输 入 用 于 新 模 型 \\color{red}然后将这些输出作为输入用于新模型

  1. 使用预训练的卷积基提取特征

    import os
    import numpy as np
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    
    base_dir = 'C:\\\\Users\\\\Administrator\\\\deep-learning-with-python-notebooks-master\\\\cats_and_dogs_small'
    train_dir = os.path.join(base_dir, 'train')
    validation_dir = os.path.join(base_dir, 'validation')
    test_dir = os.path.join(base_dir, 'test')
    
    datagen = ImageDataGenerator(rescale=1./255)
    batch_size = 20
    
    def extract_features(directory, sample_count):
    	features = np.zeros(shape=(sample_count, 4, 4, 512))
    	labels = np.zeros(shape=(sample_count))
    	generator = datagen.flow_from_directory(
    		directory,
    		target_size=(150, 150),
    		batch_size=batch_size,
    		class_mode='binary')
    	i = 0
    	for inputs_batch, labels_batch in generator:
    		features_batch = conv_base.predict(inputs_batch)
    		features[i * batch_size : (i + 1) * batch_size] = features_batch
    		labels[i * batch_size : (i + 1) * batch_size] = labels_batch
    		i += 1
    		if i * batch_size >= sample_count:
    			break
    	# 注意,这些生成器在循环中不断生成数据,
    	# 所以你必须在读取完所有图像后终止循环
    	return features, labels
    
    train_features, train_labels = extract_features(train_dir, 4000)
    validation_features, validation_labels = extract_features(validation_dir, 2000)
    test_features, test_labels = extract_features(test_dir, 2000)
    
    # 提取的特征形状为 (samples, 4, 4, 512) 。我们要将其输入到密集连接分类器中,
    # 所以首先必须将其形状展平为 (samples, 8192) 
    train_features = np.reshape(train_features, (4000, 4 * 4 * 512))
    validation_features = np.reshape(validation_features, (2000, 4 * 4 * 512))
    test_features = np.reshape(test_features, (2000, 4 * 4 * 512))
    
  2. 定义并训练密集连接分类器
    需要使用 dropout 正则化,并在刚刚保存的数据和标签上训练这个分类器。

    from tensorflow.keras import models
    from tensorflow.keras import layers
    from tensorflow.keras import optimizers
    model = models.Sequential()
    model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(1, activation='sigmoid'))
    model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
    			  loss='binary_crossentropy',
    			  metrics=['acc'])
    history = model.fit(train_features, train_labels,
    					epochs=30,
    					batch_size=20,
    					validation_data=(validation_features, validation_labels))
    
  3. 绘制结果

    import matplotlib.pyplot as plt
    
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    
    epochs = range(1, len(acc) + 1)
    
    plt.plot(epochs, acc, 'bo', label='Training acc')
    plt.plot(epochs, val_acc, 'b', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend()
    
    plt.figure()
    
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend()
    plt.show()
    


虽然 dropout 比率相当大,但模型几乎从一开始就过拟合。这是因为 本 方 法 没 有 使 用 数 据 增 强 \\color{red}本方法没有使用数据增强 使,而 数 据 增 强 对 防 止 小 型 图 像 数 据 集 的 过 拟 合 非 常 重 要 \\color{red}数据增强对防止小型图像数据集的过拟合非常重要

5.3.1.2.使用数据增强的特征提取

它的速度更慢,计算代价更高,但在训练期间可以使用数据增强。这种方法就是: 扩 展 \\color{red}扩展 conv_base 模型 然 后 在 输 入 数 据 上 端 到 端 地 运 行 模 型 \\color{red}然后在输入数据上端到端地运行模型

本方法计算代价很高,只在有 GPU 的情况下才能尝试运行。它在 CPU 上是绝对难以运行的。如果你无法在 GPU 上运行代码,那么就采用第一种方法。

  1. 在卷积基上添加一个密集连接分类器
    from tensorflow.keras import models
    from tensorflow.keras import layers
    
    model = models.Sequential()
    model.add(conv_base)
    model.add(layers.Flatten())
    model.add(layers.Dense(256, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    
    model.summary()
    
    • VGG16 的卷积基有 14 714 688 个参数,非常多。在其上添加的分类器有 200 万个参数。
    • 编译和训练模型之前,一定要“冻结”卷积基。 冻 结 \\color{red}冻结 (freeze)一个或多个层是指在训练过程中保持其权重不变。如果不这么做,那么卷积基之前学到的表示将会在训练过程中被修改。因为其上添加的 Dense 层是随机初始化的,所以非常大的权重更新将会在网络中传播,对之前学到的表示造成很大破坏。
  2. 冻结模型

    在 Keras 中, 冻 结 网 络 的 方 法 是 将 其 t r a i n a b l e 属 性 设 为 F a l s e \\color{red}冻结网络的方法是将其 trainable 属性设为 False trainableFalse

    >>> print('This is the number of trainable weights '
    	'before freezing the conv base:', len(model.trainable_weights))
    This is the number of trainable weights before freezing the conv base: 30
    
    >>> conv_base.trainable = False
    
    >>> print('This is the number of trainable weights '
    	'after freezing the conv base:', len(model.trainable_weights))
    This is the number of trainable weights after freezing the conv base: 4
    
    设置之后,只有添加的两个 Dense 层的权重才会被训练。总共有 4 个权重张量,每层2 个(主权重矩阵和偏置向量)。

    在编译之后修改了权重的 trainable 属性,那么应该重新编译模型,否则这些修改将被忽略。

  3. 利用冻结的卷积基端到端地训练模型
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    from tensorflow.keras import optimizers
    train_datagen = ImageDataGenerator(
    	rescale=1./255,
    	rotation_range=40,
    	width_shift_range=0.2,
    	height_shift_range=0.2,
    	shear_range=0.2,
    	zoom_range=0.2,
    	horizontal_flip=True,
    	fill_mode='nearest')
    	
    # 注意,不能增强验证数据
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    train_generator = train_datagen.flow_from_directory(
    	train_dir,#目标目录
    	target_size=(150, 150),#

    以上是关于《Python深度学习》第五章-3(预训练)读书笔记的主要内容,如果未能解决你的问题,请参考以下文章

    《Python深度学习》第五章-6(可视化类激活图)读书笔记

    《Python深度学习》第五章-1(CNN简介)读书笔记

    《Python深度学习》第五章-5(可视化过滤器)读书笔记

    《Python深度学习》第五章-4(可视化中间激活层)读书笔记

    Android深度探索——第五章读书笔记及心得

    Android深度探索--HAL与驱动开发----第五章读书笔记