欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

keras对猫、狗数据集进行分类(二)

程序员文章站 2022-07-13 11:56:57
...

深入学习小图像数据集的一种常见且高效的方法是利用预先训练的网络。预先训练的网络只是先前在大型数据集上训练的保存网络,通常是在大规模图像分类任务上。如果这个原始数据集足够大且足够通用,则预训练网络学习的空间特征层次结构可以有效地充当我们的视觉世界的通用模型,因此它的特征可以证明对许多不同的计算机视觉问题有用,即使这些新问题可能涉及与原始任务完全不同的类。例如,可以在ImageNet上训练网络(其中类主要是动物和日常物品),然后将这个训练有素的网络重新用于远程识别图像中的家具物品。与许多较旧的浅层学习方法相比,学习特征在不同问题中的这种可移植性是深度学习的关键优势,并且它使得深度学习对于小数据问题非常有效。
  在我们的例子中,我们将考虑在ImageNet数据集上训练的大型预测网(140万个标记图像和1000个不同类)。
 ImageNet包含许多动物类别,包括不同种类的猫和狗,因此我们可以期望在我们的猫与狗分类问题上表现得非常好。

 我们将使用由Karen Simonyan和Andrew Zisserman于2014年开发的VGG16架构,这是一种简单且广泛使用的ImageNet架构。虽然它是一个较旧的模型,远远不是现有技术水平,并且比其他许多近期型号更重,但我们之所以选择它,是因为它的架构类似于您已经熟悉的,并且易于理解而不引入任何新概念。这可能是你第一次遇到其中一个可爱的模型名称--VGG,ResNet,Inception,Inception-ResNet,Xception ......你会习惯他们,因为如果你继续深入学习计算机,他们会经常出现视力。
 
 有两种方法可以利用预先训练的网络:*特征提取*和*微调*。我们将涵盖它们。让我们从特征提取开始。

特征提取

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

正如我们之前看到的,用于图像分类的小行星包括两部分:它们以一系列汇集和卷积层开始,它们以密集连接的分类器结束。第一部分称为模型的“卷积基础”。在convnets的情况下,“特征提取”将仅包括获取先前训练的网络的卷积基础,运行新数据
 通过它,并在输出之上训练一个新的分类器。
为什么只重用卷积基数?我们可以重复使用密集连接的分类器吗?一般来说,应该避免。原因很简单,卷积基础学习的表示可能更通用,因此更可重复使用:信号网的特征图是图片上一般概念的存在图,无论计算机视觉如何,这都可能是有用的手头的问题。另一方面,分类器学习的表示必然非常特定于训练模型的类集 - 它们将仅包含关于整个图像中该类或该类的存在概率的信息。此外,在密集连接的图层中找到的表示不再包含有关_where_对象的任何信息位于输入图像中:这些图层摆脱了空间的概念,而对象位置仍然由卷积特征图描述。对于对象位置很重要的问题,密集连接的特征在很大程度上是无用的。
 注意,由特定卷积层提取的表示的一般性(以及因此可重用性)的级别取决于模型中的层的深度。模型中较早出现的图层会提取局部的,高度通用的特征贴图(例如可视边缘,颜色和纹理),而更高层的图层会提取更抽象的概念(例如“猫耳朵”或“狗眼”)。

GG16型号与Keras预先包装在一起。 您可以从`keras.applications`模块导入它。 这是列表image分类模型(所有在ImageNet数据集上预先训练过的)都可以作为`keras.applications`的一部分使用:
* Xception
* InceptionV3
* ResNet50
* VGG16
* VGG19
* MobileNet

示例代码:

from keras.applications import VGG16
import os
from keras.preprocessing.image import ImageDataGenerator
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt

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

print(conv_base.summary())

base_dir = '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(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, 2000)
validation_features,  validation_labels = extract_features(validation_dir, 1000)
test_features, test_labels = extract_features(test_dir, 1000)

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

model = Sequential()
model.add(Dense(256, activation='relu',
                input_dim=4 * 4 * 512))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))

model.compile(optimizer=RMSprop(lr=2e-5),
              loss='binary_crossentropy',
              metrics=['acc'])

hist = model.fit(train_features, train_labels,
                 epochs=30,
                 batch_size=20,
                 validation_data=(validation_features, validation_labels))


acc = hist.history['acc']
val_acc = hist.history['val_acc']
loss = hist.history['loss']
val_loss = hist.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()

model = Sequential()
model.add(conv_base)
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

print(model.summary())

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(1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir,
    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')

model.compile(loss='binary_crossentropy',
              optimizer=RMSprop(lr=2e-5),
              metrics=['acc'])

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


model.save('cats_and_dogs_small_3.h5')


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


'''
微调

另一种广泛使用的模型重用技术,是对特征提取的补充,是_fine-tuning_。
 微调包括解冻用于特征提取的冻结模型基础的一些顶层,并联合训练模型的新添加部分(在我们的例子中,完全连接的分类器)
和这些顶层。这被称为“微调”,因为它稍微调整了重复使用的模型的更抽象的表示,以使它们与手头的问题更相关。

 我们之前已经说过,有必要冻结VGG16的卷积基础,以便能够在顶部训练随机初始化的分类器。出于同样的原因,只有在顶部
的分类器已经被训练之后,才可能微调卷积基的顶层。如果分类尚未经过训练,则在训练期间通过网络传播的误差信号将太大,
并且先前由被微调的层学习的表示将被破坏。因此,微调网络的步骤如下:

 * 1)在已经训练过的基础网络上添加自定义网络。
 * 2)冻结基础网络。
 * 3)训练你添加的部分。
* 4)解冻基础网络中的某些层。
* 5)联合训练这些层和你添加的部分。
 
在进行特征提取时,我们已经完成了前3个步骤。让我们继续第4步:我们将解冻`conv_base`,然后冻结其中的各个层。
'''
conv_base.trainable = True
set_trainable = True
for layer in conv_base.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable:
        layer.trainable = True
    else:
        layer.trainable = False

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

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_4.h5')

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


def smooth_curve(points, factor=0.8):
  smoothed_points = []
  for point in points:
    if smoothed_points:
      previous = smoothed_points[-1]
      smoothed_points.append(previous * factor + point * (1 - factor))
    else:
      smoothed_points.append(point)
  return smoothed_points

plt.plot(epochs,
         smooth_curve(acc), 'bo', label='Smoothed training acc')
plt.plot(epochs,
         smooth_curve(val_acc), 'b', label='Smoothed validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs,
         smooth_curve(loss), 'bo', label='Smoothed training loss')
plt.plot(epochs,
         smooth_curve(val_loss), 'b', label='Smoothed validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

 

相关标签: keras