机器学习入门之计算机视觉中的深度学习
小标 2018-11-28 来源 : 阅读 876 评论 0

摘要:本文主要向大家介绍了机器学习入门之计算机视觉中的深度学习,通过具体的内容向大家展现,希望对大家学习机器学习入门有所帮助。

本文主要向大家介绍了机器学习入门之计算机视觉中的深度学习,通过具体的内容向大家展现,希望对大家学习机器学习入门有所帮助。

包括:

理解卷积神经网络

使用数据增强缓解过拟合

使用预训练卷积网络做特征提取

微调预训练网络模型

可视化卷积网络学习结果以及分类决策过程
介绍卷积神经网络,convnets,深度学习在计算机视觉方面广泛应用的一个网络模型。

卷积网络介绍

在介绍卷积神经网络理论以及神经网络在计算机视觉方面应用广泛的原因之前,先介绍一个卷积网络的实例,整体了解卷积网络模型。用卷积网络识别MNIST数据集。

from keras import layersfrom keras import models

model = models.Sequential()

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)形状的张量作为输入(不包括batch size)。MNIST中,将图片转换成(28,28,1)形状,然后在第一层传递input_shape参数。
显示网络架构

model.summary()

________________________________________________________________
Layer (type)        Output Shape        Param #================================================================
conv2d_1 (Conv2D)   (None, 26, 26, 32)  320________________________________________________________________
maxpooling2d_1 (MaxPooling2D) (None, 13, 13, 32) 0________________________________________________________________
conv2d_2 (Conv2D)   (None, 11, 11, 64)  18496________________________________________________________________
maxpooling2d_2 (MaxPooling2D)   (None, 5, 5, 64) 0________________________________________________________________
conv2d_3 (Conv2D)   (None, 3, 3, 64)    36928================================================================
Total params: 55,744Trainable params: 55,744Non-trainable params: 0

可以看到每个Conv2D和MaxPooling2D网络层输出都是3D张量,形状为(height,width,channels).随着网络层的加深,长度和宽度逐渐减小;通道数通过Conv2D层的参数控制。
下一步连接Dense层,但当前输出为3D张量,需要将3D张量平铺成1D,然后添加Dense层。

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

因为是10分类,最后一层为10个神经元,激活函数为softmax。
最后的网络架构

>>> model.summary()
Layer (type)        Output Shape        Param #================================================================
conv2d_1 (Conv2D)   (None, 26, 26, 32)  320________________________________________________________________
maxpooling2d_1 (MaxPooling2D) (None, 13, 13, 32) 0________________________________________________________________
conv2d_2 (Conv2D)   (None, 11, 11, 64)  18496________________________________________________________________
maxpooling2d_2 (MaxPooling2D)   (None, 5, 5, 64) 0________________________________________________________________
conv2d_3 (Conv2D)   (None, 3, 3, 64)    36928________________________________________________________________
flatten_1 (Flatten) (None, 576)     0________________________________________________________________
dense_1 (Dense)     (None, 64)      36928________________________________________________________________
dense_2 (Dense)     (None, 10)      650================================================================
Total params: 93,322Trainable params: 93,322Non-trainable params: 0

(3,3,64)输出平摊成(576,)向量。
网络训练

from keras.datasets import mnistfrom 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') / 255test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255train_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_acc0.99080000000000001

在Dense网络上准确率为97.8%,基本卷积网络上准确率到99%.为什么简单的卷积网络工作效果这么好?回答之前,先了解Conv2D和MaxPooling2D层。

卷积操作

全连接网络和卷积网络的区别在于Dense全连接层学习输入特征空间的全局模式特征,而卷积神经网络学习输入特征空间的局部模式特征。
卷积网络的两个关键特性:

学习具有平移不变性的模式特征:一旦学习到图片左上角的模式特征,可以在任何地方识别,如右下角,这种特性使得图片处理更加有效,需要的样本相对减少(实际生活中具有平移不变性)

学习模式的空间层次结构:第一个卷积层将学习小的局部模式,如边缘,第二个卷积层将学习由第一层特征构成的更大图案,等等。这使得卷积网络能够有效地学习越来越复杂和抽象的视觉概念。(现实生活中许多都是分级的)。



image

卷积在3D张量上运算,称为特征映射,具有两个空间轴(高度和宽度)以及深度轴(也称为通道轴).对RGB三原色图片来说,通道数为3--红、绿、蓝;MNIST数据集中图片通道数为1--灰度图。卷积操作在输入特征图上小分片上,然后将多个操作结果生成最后的特征图。输出的特征图仍然是3D张量:width、height,深度可以是任意值,因为深度是网络层的一个参数,而且深度值不再代表红绿蓝颜色通道,表示过滤器的个数。过滤器对输入数据的特定方面进行编码:比如在高级别,单个过滤器可以编码“输入中存在面部”的概念。
卷积定义的两个参数:

卷积核大小:通常为3x3,5x5.

卷积核个数:卷积核个数等于本层网络输出层的深度。

Keras中,Conv2D网络层定义:Conv2D(output_depth, (window_height, window_width)) .
卷积:卷积核在上一层的特征图的全通道进行滑动,然后抽取形状为(window_height,window_width,input_depth)形状的3D片特征。每个3D片特征最后转换成1D向量(卷积运算--张量点积),形状(output_depth,),所有的结果向量整合形成最后的3D特征(height,width,output_depth).



image

输出结果的宽度和高度可能和输入宽度高度不同,由于:

Padding项;

Strides 步长

最大池化 MaxPooling

最大池化层的作用在于对特征图进行下采样。最大池化在特征图中选择window,然后每个通道的在窗口内求最大值。概念上与卷积操作类似,卷积操作在小patch 中做线性转换,最大池化是求最大值,通过tensor的max张量操作。最大池化通常采用2x2窗口,步长为2,特征图减半。卷积通常卷积核大小为3x3,步长为1。

下采样的目的在于减少要处理特征图的参数量,通过使连续的卷积层看到越来越大的窗口(就它们所涵盖的原始输入的比例而言)来促使空间滤波器层次结构。
最大池化并不是唯一的下采样方法。可以使用带步长卷积、或平均池化,但是最大池化的工作效果更好。

小数据集上训练卷积网络

计算机视觉中进场会遇到使用很少的数据集去训练一个图像分类模型。“小样本”意味着样本量在几百到几万张. 比如猫狗分类,共4000张图片,猫2000张,狗2000张。用2000张图片来训练--1000张验证集,1000张测试集。
首先不做任何正则化处理,直接训练,得到一个baseline模型,准确率为71%。主要问题在于模型过拟合。之后介绍data augmentation数据增强,减缓过拟合。训练后为82%。更有效的方法是用已训练好的模型最特征提取---准确率90%~96%,或者微调已训练好的网络做特征提取(97%)。这三种方法有助于在小数据集上的模型训练。

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

可能经常听说:深度学习只能工作在大数据集上。这种说法部分正确:深度学习的一个重要特性在于深度学习能自己在训练数据中寻找特征,而不需要人工干预,而这个特性只有在大数据样本量上才有效,特别是输入数据维度特别高时,eg图片。
但是,对于初学者来说,构成大量样本的内容与尝试训练的网络的大小和深度是相对的。用几十张图片训练卷积网络来解决一个十分复杂的问题是不可能的,但如果模型比较简单经过正则化处理,同时任务比较简单,几百张图片也能解决问题。因为卷积网络学习局部的、具有平移不变性的特征,它们在感知问题上具有很高的数据效率。 尽管相对缺乏数据,但无需额外的特征工程,即使在非常小的图像数据集上从头开始训练,卷积网络仍然会产生合理的结果。

更重要的是,深度学习模型本质上是高度可再利用的:例如,可以采用在大规模数据集上训练的图像分类或语音到文本模型,只需进行微小的更改,就可以重新用于显著不同的问题上。具体而言,以计算机视觉为例,许多预先训练好的模型(通常在ImageNet数据集上训练)提供公开下载,当样本量少时,可以用在模型中(做特征提取使用)提升工作效果。

数据下载

Keras中没有包括Dogs vs. Cats数据集。可以在Kaggle上下载。
图片格式为JPEGs.数据集包含25000张猫狗图片(一半一半)。下载解压缩后,创建一个新数据集包括3个文件夹:每类1000张的训练集、每类500张的验证集和每类500张的测试集。

import os,shutil#原始数据original_dataset_dir = '/Users/fchollet/Downloads/kaggle_original_data'#新数据集目录base_dir = '/Users/fchollet/Downloads/cats_and_dogs_small'os.mkdir(base_dir)#创建训练集、验证集、测试集目录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)#创建对应数据集下不同类别的目录train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir) 
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir) 
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir) 
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir) 
test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir) 
test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir) 
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]#取前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)

fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]#取500张猫图片for fname in fnames:#500张猫图片复制到验证集
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src, dst)

fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]#取500张猫图片for fname in fnames:#500张猫图片做测试集
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src, dst)#狗图片fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]#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)

fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]for fname in fnames:#500张狗图片做验证集
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src, dst) Copies the next 500fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]for fname in fnames:#500张狗图片做测试集
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)

构建模型

from keras import layersfrom 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'))

模型架构:

>>> model.summary()
Layer (type)            Output Shape                    Param #================================================================
conv2d_1 (Conv2D)       (None, 148, 148, 32)            896________________________________________________________________
maxpooling2d_1 (MaxPooling2D)   (None, 74, 74, 32)      0________________________________________________________________
conv2d_2 (Conv2D)       (None, 72, 72, 64)              18496________________________________________________________________
maxpooling2d_2 (MaxPooling2D)   (None, 36, 36, 64)      0________________________________________________________________
conv2d_3 (Conv2D)       (None, 34, 34, 128)             73856________________________________________________________________
maxpooling2d_3 (MaxPooling2D)   (None, 17, 17, 128)     0________________________________________________________________
conv2d_4 (Conv2D)       (None, 15, 15, 128)             147584________________________________________________________________
maxpooling2d_4 (MaxPooling2D)   (None, 7, 7, 128)       0________________________________________________________________
flatten_1 (Flatten)     (None, 6272)                    0________________________________________________________________
dense_1 (Dense)         (None, 512)                     3211776________________________________________________________________
dense_2 (Dense)         (None, 1)                       513================================================================
Total params: 3,453,121Trainable params: 3,453,121Non-trainable params: 0

编译阶段,使用RMSProp优化算法,binary crossentropy为损失函数。

from keras import optimizers

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

数据预处理

数据在送到网络模型之前应该转换成浮点类型的张量。目前数据集中数据格式为JPEG,所以处理步骤大致为:

读取图片文件;

将JPEG格式转换为RGB像素值;

转换成浮点类型张量;

将像素值(0~255)缩放到[0,1]之间。

针对上述步骤,Keras中有自动化处理方法。Keras中有一个图像处理模块,keras.preprocessing.image. 其中包括一个ImageDataGenerator类,可以将磁盘上的图片文件自动转换成预处理的张量batch批量。使用方法:

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)#将图片转换成150x150,类别为2;class_mode 确定返回标签的类型binary二分类 1D类型train_generator=train_datagen.flow_from_directory(train_dir,\n        target_size=(150,150),batch_size=20,class_mode='binary')

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

生成器generator的数据结果为150x150 RGB批量图片,尺寸为(20,150,150,3),二进制标签形状(20,)。每个批量大小为20个样本(batch_size为20). 注意-生成器无限期地生成这些批次:它在目标文件夹的图像上无休止地循环。

使用generator数据生成器对模型进行训练。使用fit_generator方法,对于数据生成器来说,相当于fit方法。fit_generator第一个参数是Python生成器类型,能不断地生成输入和标签批量。因为数据不断生成,Keras模型需要知道在声明一个epoch之前从发生器中抽取多少批量;steps_per_epoch参数:从生成器中生成 steps_per_epoch个批量数据;在经过steps_per_epoch次梯度下降后,在下一个epoch上进行训练。在这里,批量大小为20,一个epoch有100个批量,生成2000张图片样本。
使用fit_generator方法,可以传递validataion_data参数,和fit方法相似。值得注意的是,这个参数可以赋值为数据生成器,也可以是numpy数组的元组。如果validation_data参数是数据生成器,生成器能不断地生成数据,所以需要设置validation_steps参数,确定从生成器中生成多少验证集批量。

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

模型保存:

model.save('cats_and_dogs_small_1.h5')

训练集验证集准确率、损失值变化:



image

可以发现模型发生过拟合现象。训练准确率随着时间线性增加,直到100%,而验证集准确率在70-72%波动。验证集损失在5个epoch之后达到最小值,之后开始波动;训练集损失线性减少直到为0

因为训练集只有2000张图片,遇到的第一个问题就是模型过拟合。Dropout、权重衰减可以减缓过拟合,还有一个计算机视觉任务中,经常使用的处理方法:数据增强data augmentation。

数据增强

过度拟合是由于样本太少而无法学习,导致无法训练可以推广到新数据的模型。给定无限的数据,模型可以学习到手头数据分布的每个可能方面:永远不会过拟合。数据增强采用从现有训练样本生成更多训练数据的方法,通过大量随机变换来增加样本,从而产生新的可靠的图像样本。
目标是在训练时,模型将永远不会看到两张完全相同的图片。这有助于模型观察数据的更多方面并更好地概括数据。
Keras中,可以通过实例化ImageDataGenerator实例,确定图片转换方法,从而实现数据增强。

datagen = ImageDataGenerator(
    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')#用于填充新创建的像素的策略,在旋转或宽度/高度偏移后出现

如果使用这样的数据增强配置训练新网络,网络将永远不会看到两张相同的输入图片。但它看到的输入仍然是严重相互关联的,因为它们来自少量原始图像 - 无法生成新信息,只能重新混合现有信息。因此,这不可能完全摆脱过拟合。为了进一步减缓过拟合,需要增加Dropout层,在全连接层之前。
新网络模型:

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.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc'])

使用数据增强和Dropout训练网络。

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

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(train_dir,
target_size=(150, 150),batch_size=32,class_mode='binary')

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

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

model.save('cats_and_dogs_small_2.h5')#模型保存

使用数据增强和Dropout后,训练集、验证集准确率和损失函数变化。



image


模型不再过拟合:训练集曲线和验证集曲线几乎相互吻合。准确率82%,提高了15%左右。使用正则化技术,微调网络超参数,模型准确率会进一步提高,到86%~87%.但是很难继续提高,因为训练数据有限,样本量太少。另一种方法,可以采用预先训练好的网络模型,做特征提取,提高准确率。

使用预训练卷积网络

在小图像数据集上使用深度学习的一种常见且高效的方法是使用预训练网络。预训练网络是先前在大型数据集上训练的已保存网络,通常是处理大规模图像分类任务。如果这个原始数据集足够大且代表性强,则预训练网络学习的特征的空间层次结构可以有效地充当视觉世界的通用模型,因此其特征可以证明对许多不同的计算机视觉问题都有用,甚至这些新问题可能涉及与原始任务完全不同。例如,可以在ImageNet上训练网络(其中类主要是动物和日常物品),然后将这个训练好的网络重新用于识别图像中的家具物品任务中。与许多较旧的浅学习方法(传统机器学习方法)相比,学习特征在不同问题中的这种可移植性是深度学习的关键优势,并且它使得深度学习对于小数据问题非常有效。

比如在ImageNet数据集上训练的网络模型(140万个标记图像和1,000个不同类)。ImageNet包含许多动物类别,包括不同种类的猫和狗,因此可以期望在狗与猫的分类问题上表现良好。

使用VGG16网络架构,它是ImageNet的简单且广泛使用的convnet架构。
使用预训练网络有两种方法:特征提取和微调。

特征提取

特征提取包括使用先前网络学习的表示从新样本中提取有趣特征。然后,这些功能将通过一个新的分类器运行,该分类器从头开始训练。

如前所述,用于图像分类的网络包含两部分:它们以一系列池化和卷积层开始,并以密集连接的分类器结束。第一部分称为模型的卷积基础。在卷积网络中,特征提取包括获取先前训练的网络的卷积基础,通过它运行新数据,以及在输出之上训练新的分类器。


image


为什么只重用卷积网络?是否可以重复使用全连接分类器?一般来说,应该避免这样做。原因是卷积网络学习的表示可能更通用,因此更可重复使用:特征网络的特征图是图片上一般概念的存在图,无论处理的计算机视觉问题是什么,都可能是有用的。但是,分类器学习的表示必然特定于训练模型的类集 - 它们将仅包含关于整个图像中该类或该类的存在概率的信息。此外,在全连接网络层的输出表示不再包含有关对象在输入图像中的位置信息:这些表示消除了空间的概念,而卷积特征图还可以描述对象的位置信息。对于对象位置很重要的问题,全连接的特征表示在很大程度上是无用的。

注意,由特定卷积层提取的表示的一般性(以及因此可重用性)的级别取决于模型中网络层的深度。模型中较早出现的图层会提取局部的,高度通用的特征贴图(例如可视边缘,颜色和纹理),而较高层的图层会提取更抽象的概念(例如“猫耳朵”或“狗眼”) 。因此,如果训练数据集与训练原始模型的数据集有很大差异,那么最好只使用模型的前几层来进行特征提取,而不是使用整个卷积网络的输出。

在这种情况下,因为ImageNet类集包含多个dog和cat类,所以重用原始模型的全连接层中包含的信息可能是有益的。但是我们会选择不这样做,以便涵盖新问题的类集不与原始模型的类集重叠的更一般情况。通过使用在ImageNet上训练的VGG16网络的卷积网络来实现这一点,从猫和狗图像中提取有趣的特征,然后在这些特征之上训练狗与猫的分类器。
Keras中可以直接获取VGG16模型,包含在keras.applications模块中。其中还包括其他模型:

Xception

Inception V3

ResNet50

VGG16

VGG19

MobileNet

实例化VGG16模型:

from keras.application import vgg16

conv_base = VGG16(weights='imagenet',include_top=False,input_shape=(150, 150, 3))

构造器的3个参数:

weights:读取权重保存点文件,初始化模型;

include_top:是否包含网络的全连接层。模型,全连接层分类类别在ImageNet上的1000类。因为要使用自己创建的全连接分类器,可以不使用原来的全连接层;

input_shape:送到模型中图片张量的形状;参数是可选的:如果不传递参数,网络可以处理任意形状的输入。
VGG16网络模型架构:

>>> conv_base.summary()
Layer (type)                    Output Shape                Param #================================================================
input_1 (InputLayer)            (None, 150, 150, 3)         0________________________________________________________________
block1_conv1 (Convolution2D)    (None, 150, 150, 64)        1792________________________________________________________________
block1_conv2 (Convolution2D)    (None, 150, 150, 64)        36928________________________________________________________________
block1_pool (MaxPooling2D)      (None, 75, 75, 64)          0________________________________________________________________
block2_conv1 (Convolution2D)    (None, 75, 75, 128)         73856________________________________________________________________
block2_conv2 (Convolution2D)    (None, 75, 75, 128)         147584________________________________________________________________
block2_pool (MaxPooling2D)      (None, 37, 37, 128)         0________________________________________________________________
block3_conv1 (Convolution2D)    (None, 37, 37, 256)         295168________________________________________________________________
block3_conv2 (Convolution2D)    (None, 37, 37, 256)         590080________________________________________________________________
block3_conv3 (Convolution2D)    (None, 37, 37, 256)         590080________________________________________________________________
block3_pool (MaxPooling2D)      (None, 18, 18, 256)         0________________________________________________________________
block4_conv1 (Convolution2D)    (None, 18, 18, 512)         1180160________________________________________________________________
block4_conv2 (Convolution2D)    (None, 18, 18, 512)         2359808________________________________________________________________
block4_conv3 (Convolution2D)    (None, 18, 18, 512)         2359808________________________________________________________________
block4_pool (MaxPooling2D)      (None, 9, 9, 512)           0________________________________________________________________
block5_conv1 (Convolution2D)    (None, 9, 9, 512)           2359808________________________________________________________________
block5_conv2 (Convolution2D)    (None, 9, 9, 512)           2359808________________________________________________________________
block5_conv3 (Convolution2D)    (None, 9, 9, 512)           2359808________________________________________________________________
block5_pool (MaxPooling2D)      (None, 4, 4, 512)           0================================================================
Total params: 14,714,688Trainable params: 14,714,688Non-trainable params: 0

最后一层的特征图形状为(4,4,512).之后连接到全连接分类器上。有两种处理方法:

训练卷积网络模型部分,将输出结果保存在磁盘上,之后读取磁盘上的数据送到全连接分类器中。优点在于运行高效、快速,因为卷积网络部分针对每张输入图片只运行一次,而卷积部分是最耗时、耗费运算能力资源的;但同时不能使用数据增强;

将全连接分类器和卷积部分整合到一起,在输入数据上端到端的运行;可以使用数据增强,因为每次输入模型的图像都会通过模型经过卷积部分。

不使用数据增强的特征提取
使用ImageDataGenerator将磁盘文件和标签读取成张量形式,运行卷积部分的predict提取图片特征。

import osimport numpy as npfrom keras.preprocessing.image import ImageDataGenerator

base_dir = '/Users/fchollet/Downloads/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 = 20def 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, 2000)
validation_features,validation_labels=extract_features(validation_dir, 1000)
test_features, test_labels = extract_features(test_dir, 1000)

当前提取特征形状为(samples,4,4,512),在送到全连接层之前,需要先平铺成(samples,8192),。

train_features = np.reshape(train_features, (2000, 4 * 4 * 512))
validation_features=np.reshape(validation_features, (1000, 4 * 4 * 512))
test_featu    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标人工智能机器学习频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程