1、数据集介绍
Google的“Quick Draw”数据集是一个开源的数据集。该数据集共有345个类别,共5000万张图片,所有这些图片都是由参与挑战的1500万名用户在20s或者更短的时间内绘制完成。
这里将在10个类别的100万张图片上进行学习,为了测试模型的辨别力,特意选择了一些比较相似的图像
2、Quick Draw图像分类
2.1 数据获取
从Google 下载数据,并将其保存至名为"data_files"的空目录下面。
具体操作如下:访问地址https://console.cloud.goole.com/storage/browser/quickdraw_dataset/full/numpy_bitmap?pli=1,下载10个数据集,保存到"data_files"目录下面。
下载之后重命名文件,去掉文件前缀,修改之后如下所示:
2.2 设置环境
首先,导入依赖项:
import tensorflow as tf
from tensorflow.keras.datasets import mnist
import numpy as np
import h5py
from sklearn.model_selection import train_test_split
import os
from os import walk
新建一些常量,以便后续使用
batch_size = 128
img_rows, img_cols = 28, 28 # image dims
用os.walk
方法从"data_files"文件夹中提取数据集的文件名。
注意:文件名保存在列表变量filenames中
data_path = "data_files/" # folder for image files
for (dirpath, dirnames, filenames) in walk(data_path):
pass # file names accumulate in list 'filenames'
print(filenames)
要使用不同的图像运行此示例,只需将10个不同的文件下载到data_files文件夹中。
下一步,定义模型所需的其他值。图像总数可在此处更改。
#图像总数num_images
num_images = 1000000 ### 如果出现内存问题,可减少此数字
num_files = len(filenames) # *** 共包含10个文件 ***
images_per_category = num_images//num_files
seed = np.random.randint(1, 10e7)
i=0
print(images_per_category)
2.3 数据预处理
接着将图像加载到内存中。
遍历所有文件,在获得文件路径后,加载该文件或图像集(x)。然后,将x转换为浮点数,除以255,令其值在0-1范围内。之后,为这组图像x创建一个标签y。
第一组图像,标签为0;下一组图像,标签为1;以知道最后一组图像,标签为9,标签y由变量i控制递增。
接下来,对集合x和y进行切片,将图像和标签还原给x和y。之后,将x和y累加到x_all和y_all中。如果是第一次循环(即i>0),则将x和y拼接到x_all和y_all上。当该循环终止时,x_all和y_all将分别包含图像和图像的标签。
for file in filenames:
file_path = data_path + file
x = np.load(file_path)
x = x.astype('float32') ##图片标准化
x /= 255.0
y = [i] * len(x) # 为图片创建数字标签
x = x[:images_per_category] # 获取图像岩本
y = y[:images_per_category] # 获取标签样本
if i == 0: #第一次循环时创建两个新列表
x_all = x
y_all = y
else: #将x和y拼接到x_all和y_all两个列表当中
x_all = np.concatenate((x,x_all), axis=0)
y_all = np.concatenate((y,y_all), axis=0)
i += 1
#x_all和y_all将分别包含图像和图像的标签
print(len(x_all))
print(len(y_all))
用sklearn.model.selection
中的train_test_split
方法,将训练集和测试集以8:2的比例进行分割,x_train和x_test分别代表训练集和测试集。
#将数据数组拆分为训练集和测试集 8:2
x_train, x_test, y_train, y_test = train_test_split(x_all, y_all, test_size=0.2, random_state=42)
由于需要使用卷积神经网络进行图像分类,需将x_train和y_train变形为原来的图像大小28*28*1
,前两个维度是图像的高度和宽度(单位为像素),第三个维度表示每个像素的灰度
#由于需要使用卷积神经网络进行图像分类,需将x_train和y_train变形为原来的图像大小
# 28*28*1,前两个维度是图像的高度和宽度(单位为像素),第三个维度表示每个像素的灰度
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
# 创建input_shape,该参数将用于convNet的第一层
input_shape = (img_rows, img_cols, 1)
print(x_train.shape)
print(x_test.shape)
对y_train和y_test标签进行独热编码
#对y_train和y_test标签进行独热编码
y_train = tf.keras.utils.to_categorical(y_train, num_files)
y_test = tf.keras.utils.to_categorical(y_test, num_files)
进一步以9:1的比例分割为训练集和验证集
print('分割前:')
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
#进一步以9:1的比例分割为训练集和验证集
x_train, x_valid, y_train, y_valid = train_test_split(x_train, y_train, test_size=0.1, random_state=42)
print('分割后:')
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
print(x_valid.shape[0],'valid samples')
2.4 模型创建
该模型共有两个卷积层(均使用ReLU激活函数),卷积层之后均插入了最大池化层和dropout层;后接一个Flatten层将卷积层的输出展平为一维向量;之后是一个一维全连接层(同样使用ReLU激活函数);最后是一个dropout层和一个10单元的softmax层。softmax层输出单元的激活给出了该图像属于各图像类别的概率。该人工神经网络有足够的实验空间。
#模型定义
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Conv2D(64, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
#softmax层输出单元的激活给出了该图像属于各图像类别的概率
model.add(tf.keras.layers.Dense(num_files, activation='softmax'))#num_files=10
print("Compiling...........")
2.5 模型训练和测试
现在可以使用fit方法来训练模型。要注意验证机的使用方法与训练集不同。callbacks列表可用于保存最佳模型或在学习停止时(前提是所有更新轮次尚未完成)。
epochs=10 # for testing, for training use 25
callbacks=[tf.keras.callbacks.TensorBoard(log_dir = os.path.join('tb_log_dir'), histogram_freq = 0)]
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
callbacks=callbacks,
verbose=1,
validation_data=(x_valid, y_valid))
这里由于硬件跟不上,我只设置epochs=10,显卡好的就设置25或更大。
为确定模型的准确度,可采用evaluate
方法。需要注意的是,此次评估使用了测试集。
#评估模型
score = model.evaluate(x_test, y_test, verbose=1)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
还可以对测试图像进行随机采样,可通过以下代码查看模型效果。从文件名中提取标签,输出该标签以供参照,随后成对输出预测标签与实际标签。
#对测试图像随机采样
import os
labels = [os.path.splitext(file)[0] for file in filenames]
print(labels)
print("\nFor each pair in the following, the first label is predicted, second is actual\n")
for i in range(20):
t = np.random.randint(len(x_test) )
x1= x_test[t]
x1 = x1.reshape(1,28,28,1)
p = model.predict(x1)
print("-------------------------")
print(labels[np.argmax(p)])
print(labels[np.argmax(y_test[t])])
print("-------------------------")
2.6 模型保存、加载和重新测试
保存模型
#保存模型
model.save("./QDrawModel.h5")
删除模型
del model
重新加载模型
from tensorflow.keras.models import load_model
import numpy as np
#加载保存的模型
model = load_model('./QDrawModel.h5')
model.summary()
打印出20个时装的测试样本,确认神经网络工作正常。
#打印出20个时装的测试样本,验证神经网络是否正常工作
print("For each pair, first is predicted, second is actual")
for i in range(20):
t = np.random.randint(len(x_test))
x1= x_test[t]
x1 = x1.reshape(1,28,28,1)
p = model.predict(x1)
print("-------------------------")
print(labels[np.argmax(p)])
print(labels[np.argmax(y_test[t])])
print("-------------------------")