TensorFlow2.0入门2-2 猫狗分类实战之数据增强与dropout

猫狗分类实战之数据增强与dropout

详细的代码注释以及数据下载见上一篇文章
这次我们都使用了100次epoch,所以等待时间比较久(我的电脑一个就要跑一个小时)。所以我已经把训练好的模型上传,大家下载即可。
地址:https://pan.baidu.com/s/14kzmsIGLqUefDroaKrLOxQ
提取码:pfyf
读取方式如下:

model.save(base + '/model/' + 'model.h5')
model = tf.keras.models.load_model(SAVE_PATH + 'model')

读取完之后就可以直接进行继续的训练或者预测了。

原始方式

训练数据

我们没用使用数据增强与dropout。

# !wget --no-check-certificate \
#     https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip \
#     -O /tmp/cats_and_dogs_filtered.zip
  
import os
import zipfile
import tensorflow as tf
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator

base = 'C:/Users/dlaicourse-master/Course 2'

local_zip = base + '/tmp/cats_and_dogs_filtered.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall(base + '/tmp')
zip_ref.close()

base_dir = base + '/tmp/cats_and_dogs_filtered'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')

train_cats_dir = os.path.join(train_dir, 'cats')

train_dogs_dir = os.path.join(train_dir, 'dogs')

validation_cats_dir = os.path.join(validation_dir, 'cats')

validation_dogs_dir = os.path.join(validation_dir, 'dogs')

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

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

# 进行归一化处理
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

# 利用ImageDataGenerator自动打上标签
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')

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


绘制精度和损失曲线

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 accuracy')
plt.plot(epochs, val_acc, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')

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.save(base + '/model/' + 'model1.h5')

在这里插入图片描述
从结果图我们可以看到,随着训练的进行,训练数据的正确率不断上升,验证数据的准确率却在不到10次迭代的情况下稳定到了一个0.7-0.8的正确率。这显然是出现了过拟合的现象,我们使用我们上次那只被错误识别的猫进行测试。结果如下:

自己数据的测试

在这里插入图片描述

import numpy as np
from keras.preprocessing import image
import tensorflow as tf
import os
base = 'C:/Users/46002/dlaicourse-master/Course 2'
filePath = base + '/tmp/content/'
keys = os.listdir(filePath)
# 获取所有文件名
model = tf.keras.models.load_model(base + '/model/' + 'model1.h5')
for fn in keys:
  # 对图片进行预测
  # 读取图片
  path = base + '/tmp/content/' + fn
  img = image.load_img(path, target_size=(150, 150))
  x = image.img_to_array(img)
  # 在第0维添加维度变为1x150x150x3,和我们模型的输入数据一样
  x = np.expand_dims(x, axis=0)
  # np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组,我们一次只有一个数据所以不这样也可以
  x = x / 255
  images = np.vstack([x])
  # batch_size批量大小,程序会分批次地预测测试数据,这样比每次预测一个样本会快。因为我们也只有一个测试所以不用也可以
  classes = model.predict(images, batch_size=1)
  print(classes)
  
  if classes[0]>0.5:
    print(fn + " is a dog")
  else:
    print(fn + " is a cat")

在这里插入图片描述
可以看到并没有预测成功,但是其他数据都预测正确了。

使用数据增强

在这个分类中有着数据不足的情况。如果数据不足很多特征就无法习得,所以效果就不会很好。而现在流行的最先进的神经网络都是成千上万的图片数据,大的数据集是效果好的保证。所以我们要使用数据增强的方式来扩充我们的数据集。
数据增强采取了对数据的翻转,缩放,裁剪等方式,大大的丰富了我们的数据集。

训练数据

import os
import zipfile
import tensorflow as tf
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator

base = 'C:/Users/dlaicourse-master/Course 2'
local_zip = base + '/tmp/cats_and_dogs_filtered.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall(base + '/tmp')
zip_ref.close()

base_dir = base + '/tmp/cats_and_dogs_filtered'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')

train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')

validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')

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

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

# 这里的代码进行了更新,原来这里只进行归一化处理,现在要进行数据增强。
train_datagen = ImageDataGenerator(
      rescale=1./255,  # 进行归一化处理把数据都放到0-1范围内。
      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(rescale=1./255)

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

# 利用我们的ImageDataGenerator来读取数据
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=100,  
      epochs=100,
      validation_data=validation_generator,
      validation_steps=50, 
      verbose=2)

观察精度和损失曲线

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 accuracy')
plt.plot(epochs, val_acc, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')

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.save(base + '/model/' + 'model2.h5')

在这里插入图片描述
可以明显的看到正确率比较之前上升了大约10%,过拟合情况得到缓解。

自己数据的测试

import numpy as np
from keras.preprocessing import image
import tensorflow as tf
import os
base = 'C:/Users/dlaicourse-master/Course 2'
filePath = base + '/tmp/content/'
keys = os.listdir(filePath)
# 获取所有文件名
model = tf.keras.models.load_model(base + '/model/' + 'model2.h5')
for fn in keys:
  # 对图片进行预测
  # 读取图片
  path = base + '/tmp/content/' + fn
  img = image.load_img(path, target_size=(150, 150))
  x = image.img_to_array(img)
  # 在第0维添加维度变为1x150x150x3,和我们模型的输入数据一样
  x = np.expand_dims(x, axis=0)
  # np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组,我们一次只有一个数据所以不这样也可以
  x = x / 255
  images = np.vstack([x])
  # batch_size批量大小,程序会分批次地预测测试数据,这样比每次预测一个样本会快。因为我们也只有一个测试所以不用也可以
  classes = model.predict(images, batch_size=1)
  print(classes)
  
  if classes[0]>0.5:
    print(fn + " is a dog")
  else:
    print(fn + " is a cat")

在这里插入图片描述
识别失败了,不仅如此,而且第一个猫的数据也错误识别了。我们可以了解到,虽然进行了数据增强整体正确率有所提高,但是对于某个单独的数据来说并不一定识别的更好。而且根本的问题可能是由于这和我们训练的数据不一致,数据里没有长得像这样的猫。
新增的错误图片如下:
在这里插入图片描述

使用数据增强与dropout

由于我们的数据量比较小,所以很容易出现过拟合的问题,也就是我们的神经网络学到了本来不该学习到的错误特征,所以我们采取dropout方法,让神经元随机失活,这样减小了神经网络对某些特定神经元的依赖也就一定程度上减小的过拟合的问题。

训练数据

  
import os
import zipfile
import tensorflow as tf
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator

base = 'C:/Users/Course 2'
local_zip = base + '/tmp/cats_and_dogs_filtered.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall(base + '/tmp')
zip_ref.close()

base_dir = base + '/tmp/cats_and_dogs_filtered'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')

train_cats_dir = os.path.join(train_dir, 'cats')

train_dogs_dir = os.path.join(train_dir, 'dogs')

validation_cats_dir = os.path.join(validation_dir, 'cats')

validation_dogs_dir = os.path.join(validation_dir, 'dogs')
# 模型处添加了dropout随机失效,也就是说有时候可能不用到某些神经元,失效率为0.5
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy',
              optimizer=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,
      fill_mode='nearest')

test_datagen = ImageDataGenerator(rescale=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')

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

观察精度和损失曲线

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 accuracy')
plt.plot(epochs, val_acc, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')

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.save(base + '/model/' + 'model3.h5')

在这里插入图片描述
可以看到整体的正确率并没有太大的差距,可能因为对比上面,本来就没有出现过拟合现象。这告诉我们并可能不是什么时候都需要dropout。

自己数据的测试

import numpy as np
from keras.preprocessing import image
import tensorflow as tf
import os
base = 'C:/Users/46002/Desktop/大二下/机器学习/吴恩达tf2.0/dlaicourse-master/Course 2'
filePath = base + '/tmp/content/'
keys = os.listdir(filePath)
# 获取所有文件名
model = tf.keras.models.load_model(base + '/model/' + 'model3.h5')
for fn in keys:
  # 对图片进行预测
  # 读取图片
  path = base + '/tmp/content/' + fn
  img = image.load_img(path, target_size=(150, 150))
  x = image.img_to_array(img)
  # 在第0维添加维度变为1x150x150x3,和我们模型的输入数据一样
  x = np.expand_dims(x, axis=0)
  # np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组,我们一次只有一个数据所以不这样也可以
  x = x / 255
  images = np.vstack([x])
  # batch_size批量大小,程序会分批次地预测测试数据,这样比每次预测一个样本会快。因为我们也只有一个测试所以不用也可以
  classes = model.predict(images, batch_size=1)
  print(classes)
  
  if classes[0]>0.5:
    print(fn + " is a dog")
  else:
    print(fn + " is a cat")

在这里插入图片描述
依旧没有成功,而且第一个数据又发生了错误。我们下一次使用迁移学习,看看能不能识别正确。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值