TensorFlow/[TensorFlow 学习笔记 ] 3 计算机视觉 2-数据增强,迁移学习,以及 dropout
图片二分类
在上一篇文章中,你学习了如何创建卷积神经网络,以及 ImageGenerator
来创建并训练一个完整的深度学习模型。但之前使用的数据都是计算机生成的,这些数据中的物体都在图片中心,图片宽高一样。而真实世界的图片数据是多种多样的。
数据来自于 Kaggle 的一个数据集 "Dogs vs. Cats" dataset,这个数据集有 25000 张图片,我们只选取了其中的 2000 张图片,用于快速训练模型。
首先下载数据。
1 | !wget --no-check-certificate \ |
然后解压数据集。
1 | import os |
解压的文件夹结构如下:
- cats_and_dogs_filtered
- train
- cats
- dogs
- validation
- cats
- dogs
- train
下面定义文件夹
1 | base_dir = 'cats_and_dogs_filtered' |
打印文件名:
1 | train_cat_fnames = os.listdir( train_cats_dir ) |
查看图片数量
1 | print('total training cat images :', len(os.listdir( train_cats_dir ) )) |
输出结果如下:
1 | total training cat images : 1000 |
下面随机选择一些图片,进行可视化。
首先定义一些参数:
1 | %matplotlib inline |
然后展示 8 张猫的图片和 8张狗的图片。
1 | # Set up matplotlib fig, and size it to fit 4x4 pics |
图片如下所示。可以看到每张图片的大小都一样,并且每张图片里的猫或者狗的位置、大小、朝向,都相差较大。

下面定义一个和之前一样的模型进行训练。将所有图片裁剪为 \(150 \times 150\)。
1 | import tensorflow as tf |
训练完成后,将训练集和测试集,在训练过程中的准确率和 loss 进行可视化。
1 | #----------------------------------------------------------- |
模型在训练集上的准确率是 100%,而在验证集上的准确率是 72%,模型明显过拟合了。
这是因为我们的训练数据太少了。下面,我们使用数据增强来减轻过拟合。
数据增强
在 ImageGenerator
中,数据增强只需要设置参数即可。
1 | train_datagen = ImageDataGenerator( |
参数解释如下:
- rotation_range:随机旋转
[-rotation_range, rotation_range]
之间的数值 - width_shift_range:纵向偏移比例
- height_shift_range:横向偏移比例
- shear_range:错切变换,效果就是让所有点的 x 坐标(或者 y 坐标)保持不变,而对应的 y 坐标(或者 x 坐标)则按比例发生平移,且平移的大小和该点到 x 轴(或 y 轴)的垂直距离成正比。
- zoom_range:可以让图片在长或宽的方向进行放大,指定放大的比例。
- horizontal_flip:是否水平翻转
- fill_mode:当对图片进行平移、放缩、错切等操作时,图片中会出现一些缺失的地方,那这些缺失的地方该用什么方式补全呢?就由 fill_mode 中的参数确定
其他模型定义以及训练代码不变。
训练完成后,再把准确率和 loss 的训练曲线画出来,如下所示:


# Dropout
可以看到,虽然减轻了过拟合。但是 loss 不够稳定,在后面的 epoch
会震荡。我们只需要修改模型,添加一个 Dropout
层即可。
1 | model = tf.keras.models.Sequential([ |
添加 Dropout
层后,模型训练曲线如下所示:


完整代码如下:
1 | !wget --no-check-certificate \ |
1 | import matplotlib.pyplot as plt |
迁移学习
下面,使用在 ImageNet
上训练好的 InceptionV3
来进行迁移学习。
首先下载模型文件,定义 InceptionV3
模型。
include_top
设置为False
,表示 不加载全连接层。weights
设置为None
,表示不使用预定义好的权重。
然后冻结所有层,取出名为 mixed7
的网络层的 output
,作为 last_output
。
1 | import os |
然后,将 last_output
经过 Flatten()
、Dense
、Dropout
、Dense
层,得到最终的输出。
1 | from tensorflow.keras.optimizers import RMSprop |
下面进行数据处理。
1 | !wget --no-check-certificate \ |
训练模型:
1 | history = model.fit( |
最后画出模型迭代的准确率和 loss 的曲线。
1 | import matplotlib.pyplot as plt |
图片多分类
上面,我们只说了 2 分类。下面,我们来说说图片多分类。
使用的数据集是手写数字图片。数据下载地址:https://www.kaggle.com/datamunge/sign-language-mnist/home。包括 2 个文件夹:sign_mnist_test.csv
和 sign_mnist_train.csv
。
下面定义一个函数 get_data()
,读取数据和标签。
1 | def get_data(filename): |
然后读取训练集和测试集。
1 | training_images, training_labels = get_data('sign_mnist_train.csv') |
输出如下:
1 | (27455, 28, 28) |
接着添加一个 channel 的维度,并构建 ImageDataGenerator
。
1 | # 添加一个 channel 的维度 |
输出如下:
1 | (27455, 28, 28, 1) |
下面定义模型并开开始训练。
注意这里使用了 。
- 如果你的
targets
是 one-hot 编码,用categorical_crossentropy
- 如果你的
tagets
是 数字编码 ,用sparse_categorical_crossentropy
1 | model = tf.keras.models.Sequential([ |
画出训练过程的准确率和 loss 曲线。
1 | import matplotlib.pyplot as plt |

