TensorFlow2.0入门2-1 猫狗分类实战和可视化隐藏层

猫狗分类

内容总结自吴恩达TensorFlow2.0的课程
不同于之前在人造的数据集,我们这次试用了真实的数据集。

数据处理

下载数据集

注意路径要写的是绝对路径,而且需要事先安装wget。

!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
base = 'C:/Users/dlaicourse-master/Course 2'
local_zip = base + '/tmp/cats_and_dogs_filtered.zip'
# 以读的方式打开压缩文件
# r读,w写,x创建一个新的并且写入,a在后面添加
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')

# Directory with our training cat/dog pictures
train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')

# Directory with our validation cat/dog pictures
validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')

打印数据名

# os.listdir返回所给路径下的所有文件名的列表
train_cat_fnames = os.listdir( train_cats_dir )
train_dog_fnames = os.listdir( train_dogs_dir )

print(train_cat_fnames[:10])
print(train_dog_fnames[:10])

在这里插入图片描述

获取每种数据的数量

print('total training cat images :', len(os.listdir(      train_cats_dir ) ))
print('total training dog images :', len(os.listdir(      train_dogs_dir ) ))

print('total validation cat images :', len(os.listdir( validation_cats_dir ) ))
print('total validation dog images :', len(os.listdir( validation_dogs_dir ) ))

在这里插入图片描述

数据集可视化

引入头文件
%matplotlib inline

import matplotlib.image as mpimg
import matplotlib.pyplot as plt

# 设置我们要画的图的参数
nrows = 4
ncols = 4
# 我们要选择进行可视化的数据集的起始位置
pic_index = 0 
绘图
# 设置图片为4行4列,图片大小为16x16
fig, ax = plt.subplots(nrows=4, ncols=4, figsize=(4 * nrows, 4 * ncols))

pic_index+=8

next_cat_pix = [os.path.join(train_cats_dir, fname) 
                for fname in train_cat_fnames[ pic_index-8:pic_index] 
               ]

next_dog_pix = [os.path.join(train_dogs_dir, fname) 
                for fname in train_dog_fnames[ pic_index-8:pic_index]
               ]

for i, img_path in enumerate(next_cat_pix+next_dog_pix):
  # 这里注意图片是4x4的。画图时不能用ax[1].imshow
  img = mpimg.imread(img_path)
  ax[int(i/4),i%4].imshow(img)
  ax[int(i/4),i%4].axis('Off')

plt.show()

在这里插入图片描述

设计训练模型

引入头文件

import tensorflow as tf

设计模型

model = tf.keras.models.Sequential([
    # 我们的数据是150x150而且是三通道的,所以我们的输入应该设置为这样的格式。
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2), 
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'), 
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(), 
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'), 
    # 二分类只需要一个输出
    tf.keras.layers.Dense(1, activation='sigmoid')  
])

打印模型相关信息

model.summary()

在这里插入图片描述

进行优化方法选择和一些超参数设置

from tensorflow.keras.optimizers import RMSprop
# 因为只有两个分类。所以用2分类的交叉熵,使用RMSprop,学习率为0.001.优化指标为accuracy
model.compile(optimizer=RMSprop(lr=0.001),
              loss='binary_crossentropy',
              metrics = ['acc'])'])

数据处理(利用ImageDataGenerator自动打标签)

因为我们的读取数据的时候不一定有标签,我们可以通过将图片放在不同的路径下的方式,来让ImageDataGenerator替我们自动打好标签。

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 把每个数据都放缩到0到1范围内
train_datagen = ImageDataGenerator( rescale = 1.0/255. )
test_datagen  = ImageDataGenerator( rescale = 1.0/255. )

# 生成训练集的带标签的数据
train_generator = train_datagen.flow_from_directory(train_dir,  # 训练图片的位置
                                                    batch_size=20, # 每一个投入多少张图片训练
                                                    class_mode='binary', # 设置我们需要的标签类型
                                                    target_size=(150, 150))  # 将图片统一大小     
# 生成验证集带标签的数据
validation_generator =  test_datagen.flow_from_directory(validation_dir,  # 验证图片的位置
                                                         batch_size=20, # 每一个投入多少张图片训练
                                                         class_mode  = 'binary', # 设置我们需要的标签类型
                                                         target_size = (150, 150))  # 将图片统一大小


在这里插入图片描述

进行训练

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

在这里插入图片描述

使用我们自己的图片进行验证

这里随便从网上找几张照片放在base+’/tmp/content/'的目录下即可。我的图片是从这个网站下载的。

import numpy as np
from keras.preprocessing import image
filePath = base + '/tmp/content/'
keys = os.listdir(filePath)
# 获取所有文件名
# for i,j,k in os.walk(filePath):
#     keys = k
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:按垂直方向(行顺序)堆叠数组构成一个新的数组,我们一次只有一个数据所以不这样也可以
  images = np.vstack([x])
  # batch_size批量大小,程序会分批次地预测测试数据,这样比每次预测一个样本会快。因为我们也只有一个测试所以不用也可以
  classes = model.predict(images, batch_size=10)
  print(classes[0])
  
  if classes[0]>0:
    print(fn + " is a dog")
    
  else:
    print(fn + " is a cat")

 

在这里插入图片描述
可以看到有一个猫识别错了,我们来进行分析一下。
在这里插入图片描述
可能是因为猫太小了,而且离屏幕比较远的缘故,在下一篇博客里,将尝试用数据增强的方法看看能不能解决该问题。

可视化隐藏层

import numpy as np
import random
from tensorflow.keras.preprocessing.image import img_to_array, load_img


# 让我们定义一个新模型,该模型将图像作为输入,并输出先前模型中所有层的中间表示。
successive_outputs = [layer.output for layer in model.layers[1:]]
# 进行可视化模型搭建,设置输入和输出
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)
# 选取一张随机的图片
cat_img_files = [os.path.join(train_cats_dir, f) for f in train_cat_fnames]
dog_img_files = [os.path.join(train_dogs_dir, f) for f in train_dog_fnames]
img_path = random.choice(cat_img_files + dog_img_files)  # 随机选取一个

img = load_img(img_path, target_size=(150, 150))  # 以指定大小读取图片
x = img_to_array(img)  # 变成array
x = x.reshape((1,) + x.shape)  # 变成 (1, 150, 150, 3)

# 统一范围到0到1
x /= 255

# 运行我们的模型,得到我们要画的图。
successive_feature_maps = visualization_model.predict(x)

# 选取每一层的名字
layer_names = [layer.name for layer in model.layers]

# 开始画图
for layer_name, feature_map in zip(layer_names, successive_feature_maps):
  if len(feature_map.shape) == 4:
    # 只绘制卷积层,池化层,不画全连接层。
    n_features = feature_map.shape[-1]  # 最后一维的大小,也就是通道数,也是我们提取的特征数
    # feature_map的形状为 (1, size, size, n_features)
    size = feature_map.shape[1]
    # 我们将在此矩阵中平铺图像
    display_grid = np.zeros((size, size * n_features))
    for i in range(n_features):
      # 后期处理我们的特征,使其看起来更美观。
      x = feature_map[0, :, :, i]
      x -= x.mean()
      x /= x.std()
      x *= 64
      x += 128
      x = np.clip(x, 0, 255).astype('uint8')
      # 我们把图片平铺到这个大矩阵中
      display_grid[:, i * size : (i + 1) * size] = x
    # 绘制这个矩阵
    scale = 20. / n_features
    plt.figure(figsize=(scale * n_features, scale))  # 设置图片大小
    plt.title(layer_name)  # 设置题目
    plt.grid(False)  # 不绘制网格线
    # aspect='auto'自动控制轴的长宽比。 这方面对于图像特别相关,因为它可能会扭曲图像,即像素不会是正方形的。
    # cmap='viridis'设置图像的颜色变化
    plt.imshow(display_grid, aspect='auto', cmap='viridis')

在这里插入图片描述

绘制精度和损失曲线

# 得到精度和损失值
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 )
plt.plot  ( epochs, val_acc )
plt.title ('Training and validation accuracy')
plt.legend(('Training accuracy','validation accuracy'))
plt.figure()

# 绘制损失曲线
plt.plot  ( epochs,     loss )
plt.plot  ( epochs, val_loss )
plt.legend(('Training loss','validation loss'))
plt.title ('Training and validation loss'   )

在这里插入图片描述
我们从曲线可以看到,我们的神经网络出现了过拟合的现象,而且我们验证集的正确率比较低。在下一篇博客中,将试用dropout方式解决过拟合。

终止程序

结束程序释放资源。signal模块可以在linux下正常使用,但在windows下却有一些限制。好像不能正常运行。

import os, signal
os.kill(os.getpid(), signal.SIGKILL)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值