当数据不够时,有以下方法进行处理,本节主要是介绍数据增强。
Cat_vs_Dog数据下载:
import os, shutil
# 原始数据集解压目录的路径
original_dataset_dir = 'C:\\Users\\Administrator\\Python_learning\\kaggle_original_data'
# 保存较小数据集的目录
base_dir = 'C:\\Users\\Administrator\\Python_learning\\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)
# 将前 2000 张猫的图像复制到 train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张猫的图像复制到 validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来的 1000 张猫的图像复制到 test_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(3000, 4000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
# 将前 2000 张狗的图像复制到 train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 test_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(3000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_dogs_dir, fname)
shutil.copyfile(src, dst)
建立网络
面对的是一个二分类问题,所以网络最后一层是使用 sigmoid 激活的单一单元(大小为1 的 Dense 层)。
from tensorflow.keras import layers
from tensorflow.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()
配置模型用于训练
因为网络最后一层是单一 sigmoid
单元,所以我们将使用 二 元 交 叉 熵 作 \color{red}二元交叉熵作 二元交叉熵作为损失函数。
from tensorflow.keras import optimizers
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
数据预处理基本步骤:
- Keras 拥有自动完成这些步骤的工具。Keras有一个图像处理辅助工具的模块,位于
keras.preprocessing.image
。- keras.preprocessing.image它包含ImageDataGenerator 类,可以快速创建 P y t h o n 生 成 器 \color{red}Python 生成器 Python生成器,能够将硬盘上的图像文件自动转换为 预 处 理 好 的 张 量 批 量 \color{red}预处理好的张量批量 预处理好的张量批量。
- P y t h o n 生 成 器 ( P y t h o n g e n e r a t o r ) \color{red}Python 生成器(Python generator) Python生成器(Pythongenerator)是一个类似于迭代器的对象,一个可以和
for ...in
运算符一起使用的对象。生成器是用yield
运算符来构造的。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 将所有图像乘以 1/255 缩放
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir, #目标目录
target_size=(150, 150), #将所有图像的大小调整为 150×150
batch_size=20,
class_mode='binary')
#因为使用了 binary_crossentropy损失,所以需要用二进制标签
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
Python批量生成器
for data_batch, labels_batch in train_generator:
print('data batch shape:', data_batch.shape)
print('labels batch shape:', labels_batch.shape)
break
- Python生成器 在此处生成了
150×150
的 RGB 图像[形状为(20,150, 150, 3)
]与二进制标签[形状为(20,)
]组成的批量。每个批量中包含 20 个样本(批量大小)。- 生 成 器 会 不 停 地 生 成 这 些 批 量 \color{red}生成器会不停地生成这些批量 生成器会不停地生成这些批量,它会不断循环目标文件夹中的图像。因此,需要在某个时刻终止(
break
)迭代循环。
利用批量生成器拟合模型
history = model.fit_generator(
train_generator,
steps_per_epoch=200, # steps_per_epoch * batch_size = 4000(训练数据为4000)
epochs=30,
validation_data=validation_generator,
validation_steps=50)
fit_generator
方法来拟合,它在数据生成器上的效果和fit
相同。fit_generator
参数:
- 第一个参数是Python 生成器
:可以不停地生成输入和目标组成的批量,比如train_generator
。
- 第二个参数是steps_per_epoch
:从生成器中抽取steps_per_epoch
个批量后(即运行了steps_per_epoch
次梯度下降),拟合过程将进入下一个轮次。本例中,每个批量包含 20 个样本,所以读取完所有 4000 个样本需要 200个批量。
- 第三个参数是validation_data
:这个参数可以是一个数据生成器,但也可以是 Numpy 数组组成的元
组。 如果向 validation_data 传入一个生成器,那么这个生成器应该能够不停地生成验证数据批量,因此你还需要指定validation_steps
参数,说明需要从验证生成器中抽取多少个批次用于评估。
保存模型
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(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()
这些图像中都能看出过拟合的特征。训练精度随着时间线性增加,直到接近 100%,而验证精度则停留在 70%~72%。验证损失仅在 5 轮后就达到最小值,然后保持不变,而训练损失则一直线性下降,直到接近于 0。
数据增强的定义:
数据增强是从现有的训练样本中生成更多的训练数据,其方法是利用多种能够生成可信图像的随机变换来增加
(augment)样本。
数据增强的目标: 模 型 在 训 练 时 不 会 两 次 查 看 完 全 相 同 的 图 像 。 \color{red}模型在训练时不会两次查看完全相同的图像。 模型在训练时不会两次查看完全相同的图像。让模型能够观察到数据的更多内容,从而具有更好的泛化能力。
在 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')
rotation_range
是角度值(在 0~180 范围内),表示图像随机旋转的角度范围。width_shift
和height_shift
是图像在水平或垂直方向上平移的范围(相对于总宽度或总高度的比例)。shear_range
是随机错切变换的角度。zoom_range
是图像随机缩放的范围。horizontal_flip
是随机将一半图像水平翻转。如果没有水平不对称的假设(比如真实世界的图像),这种做法是有意义的。fill_mode
是用于填充新创建像素的方法,这些新像素可能来自于旋转或宽度/高度平移。
显示几个随机增强后的训练图像
# 图像预处理工具的模块
from tensorflow.keras.preprocessing import image
fnames = [os.path.join(train_cats_dir, fname) for
fname in os.listdir(train_cats_dir)]
# 选择一张图像进行增强
img_path = fnames[3]
# 读取图像并调整大小
img = image.load_img(img_path, target_size=(150, 150))
# 将其转换为形状 (150, 150, 3) 的 Numpy 数组
x = image.img_to_array(img)
# 将其形状改变为 (1, 150, 150, 3)
x = x.reshape((1,) + x.shape)
#生成随机变换后的图像批量。
#循环是无限的,因此你需要在某个时刻终止循环
i = 0
for batch in datagen.flow(x, batch_size=1):
plt.figure(i)
imgplot = plt.imshow(image.array_to_img(batch[0]))
i += 1
if i % 4 == 0:
break
plt.show()
增加过dropout层,降低过拟合
为了进一步降低过拟合,你还需要向模型中添加一个 Dropout
层,添加到密集连接分类器之前。
定义一个包含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'])
利用数据增强生成器训练卷积神经网络
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), # 将所有图像的大小调整为 150×150
batch_size=20,
# 书上是32,但是32*200(steps_per_epoch)大于了4000,运行会报错,所以改为20.
class_mode='binary')
# 因为使用了 binary_crossentropy损失,所以需要用二进制标签
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
# 书上是32,但是32*200(steps_per_epoch)大于了4000,运行会报错,所以改为20.
class_mode='binary',
#查看更改后的图片
save_to_dir=r'C:\\Users\\cats_and_dogs_small\\Sample',
save_prefix='trans_',
save_format='jpg')
history = model.fit_generator(
train_generator,
steps_per_epoch=200, # steps_per_epoch * batch_size = 200 * 32 = 4000
epochs=100,
validation_data=validation_generator,
validation_steps=50)
保存模型并画出验证曲线
model.save('cats_and_dogs_small_2.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(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()
通过进一步使用正则化方法以及调节网络参数以得到更高的精度。但只靠从头开始训练自己的卷积神经网络,再想提高精度就十分困难,因为可用的数据太少。下一步需要使用预训练的模型,这是接下来两节的重点。
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import os, shutil
# 原始数据集解压目录的路径
original_dataset_dir = 'C:\\Users\\Administrator\\Python_learning\\kaggle_original_data'
# 保存较小数据集的目录
base_dir = 'C:\\Users\\Administrator\\Python_learning\\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)
# 将前 2000 张猫的图像复制到 train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张猫的图像复制到 validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来的 1000 张猫的图像复制到 test_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(3000, 4000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
# 将前 2000 张狗的图像复制到 train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 test_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(3000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_dogs_dir, fname)
shutil.copyfile(src, dst)
# 构建网络
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.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
# 图像预处理
# 将所有图像乘以 1/255 缩放
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir, #目标目录
target_size=(150, 150), #将所有图像的大小调整为 150×150
batch_size=20,
class_mode='binary')
#因为使用了 binary_crossentropy损失,所以需要用二进制标签
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
# 利用批量生成器拟合模型
history = model.fit_generator(
train_generator,
steps_per_epoch=200, # steps_per_epoch * batch_size = 4000
epochs=30,
validation_data=validation_generator,
validation_steps=50)
# 保存模型
model.save('cats_and_dogs_small_1.h5')
# 绘制训练过程中的损失曲线和精度曲线
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()
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import os, shutil
# 原始数据集解压目录的路径
original_dataset_dir = 'C:\\Users\\Administrator\\Python_learning\\kaggle_original_data'
# 保存较小数据集的目录
base_dir = 'C:\\Users\\Administrator\\Python_learning\\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)
# 将前 2000 张猫的图像复制到 train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张猫的图像复制到 validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# 将接下来的 1000 张猫的图像复制到 test_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(3000, 4000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
# 将前 2000 张狗的图像复制到 train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(2000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
# 将接下来 1000 张狗的图像复制到 test_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(3000, 3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_dogs_dir, fname)
shutil.copyfile(src, dst)
# 增加过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'])
# 图像预处理
# 训练数据增强
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), # 将所有图像的大小调整为 150×150
batch_size=20,
class_mode='binary')
# 因为使用了 binary_crossentropy损失,所以需要用二进制标签
#验证数据没有增强
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
# 利用批量生成器拟合模型
history = model.fit_generator(
train_generator,
steps_per_epoch=200, # steps_per_epoch * batch_size = 6400
epochs=100,
validation_data=validation_generator,
validation_steps=50)
# 保存模型
model.save('cats_and_dogs_small_1.h5')
# 绘制训练过程中的损失曲线和精度曲线
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()