Deep learning 四

接下来几篇文章包含以下内容

理解卷积神经网络(convnet)

使用数据增强来降低过拟合

使用预训练的卷积神经网络进行特征提取

微调预训练的卷积神经网络

将卷积神经网络学到的内容及其如何做出分类决策可视化

一、卷积神经网络简介

下列代码将会展示一个简单的卷积神经网络。它是conv2D层和MaxPooling2D层的堆叠

from keras import layers
from keras import models

model= models.Seguential ()model.add(layers .Conv2D(32, 
(3,3),activation='relu'input_shape=(28,28, 1)))

model.add(layers .MaxPooling2D((2, 2)))

model.add(layers .Conv2D(64, (3,3), activation='relu'))

model.add(layers .MaxPooling2D((2, 2)))model.add(layers.Conv2D(64,
 (3,3),activation='relu'))

重要的是,卷积神经网络接收形状为(image_height,image_width,image_channels)的输人张量(不包括批量维度)。本例中设置卷积神经网络处理大小为(28,28,1)的输人张量这正是MNIST图像的格式。我们向第一层传人参数 input_shape=(28,28,1)来完成此设置

我们来看一下目前卷积神经网络的架构。

 

可以看到,每个conv2D层和MaxPooling2D层的输出都是一个形状为(height,width,channels)的3D 张量。宽度和高度两个维度的尺寸通常会随着网络加深而变小。通道数量由传入conv2D层的第一个参数所控制(32或64)。下一步是将最后的输出张量[大小为(3,3, 64)]输人到一个密集连接分类器网络中即 Dense 层的堆叠。

这些分类器可以处理1D 向量,而当前的输出是3D 张量首先,我们需要将3D输出展平为 1D,然后在上面添加几个 Dense 层。

"""在卷积神经网络上添加分类器"""

model.add(layers.Flatten())
model.add(layers.Dense(64,activation='relu'))
model.add(layers.Dense(10,activation='softmax'))

现在的网络架构

 

"""在MNIST数字图像上训练这个卷积神经网络"""

from keras.datasets import mnist
from keras.utils import to_categorical
(train images, train labels), (test images, test labels) = mnist.load data()

train_images = train_images.reshape((60000,28,28,1)
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape((10000,28,28,1))
test_images = test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=5,batch_size=64)


'''在测试数据评估'''
>>>test_loss, test_acc = model.evaluate(test_images, test_labels)
>>>test_acc
0.99080000000000001

在之前密集连接网络的测试精度为 97.8%,但这个简单卷积神经网络的测试精度达到了99.3%

1.卷积计算

        密集连接层和卷积层的根本区别在于,Dense 层从输人特征空间中学到的是全局模式(比如对于MNIST数字,全局模式就是涉及所有像素的模式),而卷层学到的是局部模式(见图 5-1),对于图像来说,学到的就是在输人图像的二维小窗口中发现的模式。在上面的例子中这些窗口的大小都是3x3。

                                图5-1图像可以被分解为局部模式,如边缘、纹理等 

这个重要特性使卷积神经网络具有以下两个有趣的性质。

口卷积神经网络学到的模式具有平移不变性(translation invariant)。卷积神经网络在图像右下角学到某个模式之后,它可以在任何地方识别这个模式,比如左上角。对于密集连接网络来说,如果模式出现在新的位置,它只能重新学习这个模式。这使得卷积神经网络在处理图像时可以高效利用数据(因为视觉世界从根本上具有平移不变性),它只需要更少的训练样本就可以学到具有泛化能力的数据表示。

口卷积神经网络可以学到模式的空间层次结构(spatial hierarchies of patterns),见图5-2第一个卷积层将学习较小的局部模式(比如边缘),第二个卷积层将学习由第一层特征组成的更大的模式,以此类推。这使得卷积神经网络可以有效地学习越来越复杂、越来越抽象的视觉概念(因为视觉世界从根本上具有空间层次结构)。

        对于包含两个空间轴(高度和宽度)和一个深度轴(也叫通道轴)的3D张量,其卷积也叫特征图 (feature map)。对于RGB图像,深度轴的维度大小等于3因为图像有3个颜色通道红色、绿色和蓝色。对于黑白图像(比如 MNIST 数字图像),深度等于1(表示灰度等级)。卷积运算从输人特征图中提取图块,并对所有这些图块应用相同的变换,生成输出特征图(outputfeature map)。该输出特征图仍是一个3D 张量,具有宽度和高度,其深度可以任意取值,因为输出深度是层的参数,深度轴的不同通道不再像 RGB 输入那样代表特定颜色,而是代表过滤器(filter)。过滤器对输入数据的某一方面进行编码,比如,单个过滤器可以从更高层次编码这样个概念:“输人中包含一张脸。” 

 

        图5-2 视觉世界形成了视觉模块的空间层次结构:超局部的边缘组合成局部的对象,比如眼睛

                                或耳朵,这些局部对象又组合成高级概念,比如“猫”

在MNIST示例中,第一个卷积层接收一个大小为(28,28,1)的特征图,并输出一个大小为(26,26,32)的特征图,即它在输人上计算 32个过滤器。对于这32个输出通道,每个通道都包含一个26x26的数值网格,它是过滤器对输人的响应图(response map)表示这个过滤器模式在输人中不同位置的响应(见图 5-3)。这也是特征图这一术语的含义:深度轴的每个维度都是一个特征(或过滤器),而2D 张量 output[:, :, n] 是这个过器在输入上的响应的二维空间图(map)。

卷积由以下两个关键参数所定义

从输入中提取的图块尺寸:这些图块的大小通常是3x3或5x5。本中为3x3这是很常见的选择。
输出特征图的深度:卷积所计算的过滤器的数量。本例第一层的深度为 32,最后一层的深度是 64。

 对于Keras的conv2D层,这些参数都是向层传人的前几个参数:Conv2D(output_depth,(window_height,window width))。


卷积的工作原理:在3D输人特征图上滑动(slide)这些3x3或5x5的在个可能的位置停止并提取周围特征的3D 图块[形状为(window_height,window_width,inputdepth)]。然后每个3D图块与学到的同一个权重矩阵[叫作卷积核(convolution kernel)]做张量积,转换成形状为 (output_depth,)的1D向量。然后对所有这些向量进行空间重组使其转换为形状为(height,width, output_depth)的3D输出特征图。输出特征图中的每个空间位置都对应于输入特征图中的相同位置(比如输出的右下角包含了输入右下角的信息)。举个例子,利用3x3的窗口,向量output[i,j,:]来自3D图块input[i-1:i+1,j-1:j+1,:]。整个过程详见图 5-4。

注意,输出的宽度和高度可能与输入的宽度和高度不同。不同的原因可能有两点。
        边界效应,可以通过对输入特征图进行填充来抵消。
        使用了步幅(stride)。 

(1).理解边界效应与填充


        假设有一个5x5的特征图(共25 个方块 )。其中只有9个方块可以作为中心放人一个3x3的窗口,这9个方块形成一个3x3 的网格(见图5-5)。因此,输出特征图的尺寸是3x3它比输入尺寸小了一点,在本例中沿着每个维度都正好缩小了2个方块。在前一个例子中你也可以看到这种边界效应的作用:开始的输人尺寸为 28x28,经过第一个卷积层之后尺寸变为26x26。

 

                                图5-5在5x5的输人特征图中,可以提取3x3图块的有效位置

        如果你希望输出特征图的空间维度与输入相同,那么可以使用填充 (padding)。填充是在输人特征图的每一边添加适当数目的行和列,使得每个输入方块都能作为卷积窗口的中心。对于3x3的窗口,在左右各添加一列,在上下各添加一行。对于5x5 的窗口,各添加两行和两列(见图5-6)。

                         图5-6对5x5的输人进行填充,以便能够提取出25个3x3的图块

对于conv2D层,可以通过 padding 参数来设置填充,这个参数有两个取值:"valid"表示不使用填充(只使用有效的窗口位置);"same”表示“填充后输出的宽度和高度与输入相同”padding参数的默认值为"valid"。

(2).理解卷积步幅


        影响输出尺寸的另一个因素是步幅的概念。目前为止,对卷积的描述都假设卷积窗口的中心方块都是相邻的。但两个连续窗口的距离是卷积的一个参数,叫作步幅,默认值为 1。也可以使用步进卷积(strided convolution),即步幅大于1的卷积。在图5-7中你可以看到用步幅为2的3x3卷积从5x5输人中提取的图块(无填充)。 

                                                         图5-7  2x2步幅的3x3卷积图块

步幅为 2意味着特征图的宽度和高度都被做了2倍下采样(除了边界效应引起的变化)。虽然步进卷积对某些类型的模型可能有用,但在实践中很少使用。熟悉这个概念是有好处的。

为了对特征图进行下采样,我们不用步幅,而是通常使用最大池化(max-pooling)运算

 2.最大池化运算

        在卷积神经网络示例中,你可能注意到,在每个MaxPooling2D 层之后,特征图的尺寸都会减半。例如,在第一个MaxPooling2D层之前,特征图的尺寸是 26x26,但最大池化运算将其减半为 13x13。这就是最大池化的作用:对特征图进行下采样,与步进卷积类似。最大池化是从输入特征图中提取窗口,并输出每个通道的最大值。它的概念与卷积类似但是最大池化使用硬编码的 max 张量运算对局部图块进行变换,而不是使用学到的线性变换(卷积核 )。最大池化与卷积的最大不同之处在于,最大池化通常使用2x2 的窗口和步幅2,其目的是将特征图下采样2倍。与此相对的是,卷积通常使用3x3 窗口和步幅1。
        这时模型的卷积基(convolutional base)如下所示。

model_no_max_pool = models.Sequential()
model_no_max_pool.add(layers.Conv2D(32, (3,3),activation='relu,
                      input_shape=(28,28,1)))
model_no_max_pool.add(layers.Conv2D(64, (3,3),activation='relu') )
model_no_max_pool.add(layers.Conv2D(64,  (3,3),activation='relu') )

模型架构如下

这种架构有什么问题?有如下两点问题。
口这种架构不利于学习特征的空间层级结构。第三层的3x3窗口中只包含初始输入的7x7窗中所包含的信息。卷积神经网络学到的高级模式相对于初始输入来说仍然很小这可能不足以学会对数字进行分类(你可以试试仅通过7像素x7像素的窗口观察图像来识别其中的数字)。我们需要让最后一个卷积层的特征包含输人的整体信息。

口最后一层的特征图对每个样本共有22x22x64=30976个元素。这太多了。如果你将其展平并在上面添加一个大小为 512的 Dense 层,那一层将会有 1580 万个参数。这对于这样一个小模型来说太多了,会导致严重的过拟合。
简而言之,使用下采样的原因,一是减少需要处理的特征图的元素个数,二是通过让连续卷积层的观察窗口越来越大(即窗口覆盖原始输入的比例越来越大),从而引人空间过滤器的层级结构。

注意,最大池化不是实现这种下采样的唯一方法。你已经知道,还可以在前一个卷积层中使用步幅来实现。此外,你还可以使用平均池化来代替最大池化,其方法是将每个局部输入图块变换为取该图块各通道的平均值.而不是最大值。但最大池化的效果往往比这些替代方法更好简而言之,原因在于特征中往往编码了某种模式或概念在特征图的不同位置是否存在(因此得名特征图),而观察不同特征的最大值而不是平均值能够给出更多的信息。因此,最合理的子采样策略是首先生成密集的特征图(通过无步进的卷积)然后观察特征每个小图块上的最大激活而不是查看输人的稀疏窗口(通过步进卷积)或对输入图块取平均,因为后两种方法可能导致错过或淡化特征是否存在的信息。


现在理解了卷积神经网络的基本概念,即特征图、卷积和最大池化,并且也知道如何构建一个小型卷积神经网络来解决简单问题,比如 MNIST 数字分类。

二、在小型数据集上从头开始训练一个卷积神经网络

使用很少的数据来训练一个图像分类模型,这是很常见的情况

来看一个实例,我们将重点讨论猫狗图像分类,数据集中包含 4000 张猫和狗的图像2000 张猫的图像,2000 张狗的图像)。我们将 2000 张图像用于训练,1000 张用于验证,1000张用于测试。

1.深度学习与小数据问题的相关性

        有时你会听人说,仅在有大量数据可用时,深度学习才有效。这种说法部分正确:深度学习的一个基本特性就是能够独立地在训练数据中找到有趣的特征,无须人为的特征工程,而这只在拥有大量训练样本时才能实现。对于输入样本的维度非常高(比如图像)的问题尤其如此但对于初学者来说,所谓“大量”样本是相对的,即相对于你所要训练网络的大小和深度而言。只用几十个样本训练卷积神经网络就解决一个复杂问题是不可能的,但如果模型很小并做了很好的正则化,同时任务非常简单,那么几百个样本可能就足够了。由于卷积神经网络学到的是局部的、平移不变的特征,它对于感知问题可以高效地利用数据。虽然数据相对较少但在非常小的图像数据集上从头开始训练一个卷积神经网络,仍然可以得到不错的结果,而且无须任何自定义的特征工程。

        此外,深度学习模型本质上具有高度的可复用性,比如,已有-个在大规模数据集上训练的图像分类模型或语音转文本模型,你只需做很小的修改就能将其复用于完全不同的问题。特别是在计算机视觉领域,许多预训练的模型(通常都是在ImageNet 数据集上训练得到的)现在都可以公开下载,并可以用于在数据很少的情况下构建强大的视觉模型。

2.下载数据

 https://www.kaggle.com/c/dogs-vs-cats/data下载原始数据集

这个数据集包含25 000张猫狗图像(每个别都有 12500张)大小为543MB(压缩后。下载数据并解压之后,你需要创建一个新数据集,其中包含三个子集:每个类别各 1000个样本的训练集、每个类别各500个样本的验证集和每个类别各500个样本的测试集。

"""将图像复制到训练、验证和测试的目录"""

import os, shutil

# The path to the directory where the original
# dataset was uncompressed
'''原始数据集解压目录的路径'''
original_dataset_dir = '/Users/fchollet/Downloads/kaggle_original_data/train'


# The directory where we will
# store our smaller dataset
'''保存较小数据集的目录'''
base_dir = '/Users/fchollet/Downloads/cats_and_dogs_small'
os.mkdir(base_dir)


# Directories for our training,
# validation and test splits
'''分别对应划分后的训练,验证和测试的目录'''
train_dir = os.path.join(base_dir, 'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
os.mkdir(test_dir)


# Directory with our training cat pictures
'''猫的训练图像目录'''
train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir)


# Directory with our training dog pictures
'''狗的训练图像目录'''
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)


# Directory with our validation cat pictures
'''猫的验证图像目录'''
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)


# Directory with our validation dog pictures
'''狗的验证图像目录'''
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)


# Directory with our validation cat pictures
'''猫的测试图像目录'''
test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)


# Directory with our validation dog pictures
'''狗的测试图像目录'''
test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir)


# Copy first 1000 cat images to train_cats_dir
'''将前1000张猫的图像复制到train_cats_dir'''
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src, dst)


# Copy next 500 cat images to validation_cats_dir
'''将接下来500张猫的图像复制到validation_cats-dir'''
fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src, dst)
 
   
# Copy next 500 cat images to test_cats_dir
"""将接下来500张猫的图像复制到test_cats_dir"""
fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src, dst)

    
# Copy first 1000 dog images to train_dogs_dir
"""将前1000张狗的图像复制到train_dogs_dir"""
fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_dogs_dir, fname)
    shutil.copyfile(src, dst)

    
# Copy next 500 dog images to validation_dogs_dir
"""将接下来500张狗的图像复制到validation_dogs_dir"""
fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src, dst)

    
# Copy next 500 dog images to test_dogs_dir
"""将接下来500张狗的图像复制到test_dogs_dir"""
fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)

我们来看每个分组(训练/验证/测试)中分别包含多少张图像

所以我们的确有 2000 张训练图像、1000 张验证图像和 1000 张测试图像。每个分组中两个类别的样本数相同,这是一个平衡的二分类问题,分类精度可作为衡量成功的指标。

 

3.构建网络

在前一个MNIST示例中,我们构建了一个小型卷积神经网络。我们将复用相同的总体结构,即卷积神经网络由 conv2D层(使用relu 激活)和MaxPooling2D层交替堆叠构成。
但由于这里要处理的是更大的图像和更复杂的问题,你需要相应地增大网络,即再增加一个conv2D+MaxPooling2D 的组合。这既可以增大网络容量,也可以进一步减小特征图的尺寸使其在连接 Flatten 层时尺寸不会太大。本例中初始输人的尺寸为 150x150(有些随意的选择),所以最后在 Flatten 层之前的特征图大小为7x7。

注意 网络中特征图的深度在逐渐增大(从32 增大到 128),而特征图的尺寸在逐渐减小(从150X150减小到7X7)。这几乎是所有卷积神经网络的模式

这是一个二分类问题,所以网络最后一层是使用 sigmoid 激活的单一单元(大小为1的 Dense层)。这个单元将对某个类别的概率进行编码。

"""将猫狗分类的小型卷积神经网络实例化"""

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu',
                        input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

特征图的维度变化

 

在编译这一步,和前面一样,我们将使用 RMSprop 优化器。因为网络最后一层是单一 sigmoid单元,所以我们将使用二元交叉熵作为损失函数(提醒一下,前面的文章列出了各种情况下应该使用的损失函数)。

 

"""配置模型用于训练"""

from keras import optimizers

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

4.数据预处理

将数据输入神经网络之前,应该将数据格式化为经过预处理的浮点数张量。
现在,数据以JPEG文件的形式保存在硬盘中,所以数据预处理步骤大致如下。

(1)读图像文件。


(2)将JPEG文件解码为RGB像素网格


(3)将这些像素网格转换为浮点数张量。


(4)将像素值(0255范围内)缩放到[0区间(正如所知,神经网络喜欢处理较小的输入值)。

这些步骤可能看起来有点吓人,但幸运的是,Keras 拥有自动完成这些步骤的工具。Keras有一个图像处理辅助工具的模块,位于 keras.preprocessing.image。特别地,它包含ImageDataGenerator 类,可以快速创建 Python生成器,能够将硬盘上的图像文件自动转换为预处理好的张量批量。下面我们将用到这个类。

"""使用 ImageDataGenerator 从目录中读取图像"""

from keras.preprocessing.image import ImageDataGenerator

# All images will be rescaled by 1./255
"""将所有图像乘以1/255缩放"""
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        # This is the target directory
        """目标目录"""
        train_dir,
        # All images will be resized to 150x150
        """将所有图像的大小调整为150 * 150"""
        target_size=(150, 150),
        batch_size=20,
        # Since we use binary_crossentropy loss, we need binary labels
        """因为使用了binary_crossentropy损失,所以需要用二进制标签"""
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

理解Python生成器
Python生成器(Python generator)是一个类似于迭代器的对象,一个可以和 forin运算符一起使用的对象。生成器是用yiela运算符来构造的。下面一个生成器的例子,可以生成整数。

def generator():
        i=0
        whileTrue:

                i+=1;

                yield i


for item in generator():

        print(item)

        if item>4:
                break

输出结果如下

1

2

3

4

5

我们来看一下其中一个生成器的输出: 它生成了150x150的RGB 图像[形状为(20, 150,150,3)]与二进制标签[形状为(20,)]组成的批量。每个批量中包含 20个样本(批量大小)。注意,生成器会不停地生成这些批量,它会不断循环目标文件夹中的图像。因此,你需要在某个时刻终止(break)迭代循环。

for data_batch, labels_batch in train_generator:
    print('data batch shape:', data_batch.shape)
    print('labels batch shape:', labels_batch.shape)
    break


"""输出结果"""
data batch shape: (20, 150, 150, 3)
labels batch shape: (20,)

        利用生成器,我们让模型对数据进行拟合。我们将使用 fit_generator 方法来拟合,它在数据生成器上的效果和 ft 相同。它的第一个参数应该是一个 Pvthon 生成器,可以不停地生成输入和目标组成的批量,比如 train_generator。因为数据是不断生成的,所以 Keras模型要知道每一轮需要从生成器中抽取多少个样本。这是 steps_per_epoch 参数的作用:从生成器中抽取steps_per_epoch 个批量后(即运行了 steps_per_epoch 次梯度下降),拟合过程将进人下一个轮次。本例中,每个批量包含 20个样本,所以读取完所有 2000个样本需要 100个批量。
        使用fit_generator时,你可以传人一个validation_data参数,其作用和在fit方法中类似。值得注意的是,这个参数可以是一个数据生成器,但也可以是 Numpy 数组组成的元组。如果向 validation_data传人一个生成器,那么这个生成器应该能够不停地生成验证数据批量,因此你还需要指定 validation_steps 参数,说明需要从验证生成器中抽取多少个批次用于评估。

"""利用批量生成器拟合模型"""

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=50)

"""始终在训练完成后保存模型,这是一种良好实践"""

"""保存模型"""
model.save('cats_and_dogs_small_1.h5')


"""绘制训练过程中的损失曲线和精度曲线"""
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(len(acc))

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()


                                                                训练精度和验证精度

 

                                                                训练损失和验证损失

        从这些图像中都能看出过拟合的特征。训练精度随着时间线性增加,直到接近 100%,而验证精度则停留在 70%~72%。验证损失仅在 5 轮后就达到最小值,然后保持不变,而训练损失则一直线性下降,直到接近于0。
        因为训练样本相对较少(2000个),所以过拟合是你最关心的问题。前面已经介绍过几种降低过拟合的技巧,比如 dropout 和权重衰减(L2正则化)。现在我们将使用一种针对于计算机视觉领域的新方法,在用深度学习模型处理图像时几乎都会用到这种方法,它就是数据增强data augmentation 。 

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值