PyTorch深度学习实战 | 猫狗分类
本文内容使用TensorFlow和Keras建立一个猫狗图片分类器。
本文内容使用TensorFlow和Keras建立一个猫狗图片分类器。
图1 猫狗图片
01、安装TensorFlow和Keras库
TensorFlow是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。
节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。它灵活的架构让你可以在多种平台上展开计算,例如台式计算机中的一个或多个CPU(或GPU),服务器,移动设备等等。
TensorFlow最初由Google大脑小组(隶属于Google机器智能研究机构)的研究员和工程师们开发出来,用于机器学习和深度神经网络方面的研究,但这个系统的通用性使其也可广泛用于其他计算领域。如图2所示。
图2 TensorFlow数据流图
运行Anaconda Prompt工具,在该工具命令窗口下安装数值计算开源库(tensorflow),如图3和图4所示,输入以下pip命令:
pip install tensorflow
图3 安装tensorflow库
图4 tensorflow库安装成功
Keras是一个由Python编写的开源人工神经网络库,可以作为Tensorflow、Microsoft-CNTK和Theano的高阶应用程序接口,进行深度学习模型的设计、调试、评估、应用和可视化,即高层神经网络API。
Keras的命名来自古希腊语“κέρας(牛角)”或“κραίνω(实现)”,意为将梦境化为现实的“牛角之门”。Keras的最初版本以Theano为后台,设计理念参考了Torch但完全由Python编写,自2017年起,Keras得到了Tensorflow团队的支持,其大部分组件被整合至Tensorflow的Python API中。在2018年Tensorflow 2.0.0公开后,Keras被正式确立为Tensorflow高阶API,即tf.keras。此外自2017年7月开始,Keras也得到了CNTK 2.0的后台支持。
Keras在代码结构上由面向对象方法编写,完全模块化并具有可扩展性,其运行机制和说明文档有将用户体验和使用难度纳入考虑,并试图简化复杂算法的实现难度。Keras支持现代人工智能领域的主流算法,包括前馈结构和递归结构的神经网络,也可以通过封装参与构建统计学习模型。在硬件和开发环境方面,Keras支持多操作系统下的多GPU并行计算,可以根据后台设置转化为Tensorflow、Microsoft-CNTK等系统下的组件。Keras为支持快速实验而生,能够把你的 idea 迅速转换为结果。
运行Anaconda Prompt工具,在该工具命令窗口下安装开源人工神经网络库(keras),输入以下pip命令:
pip install keras
如图5、图6所示。
图5 安装keras库
图6 keras库安装成功
环境配置好后,开始着手建立一个可以将猫狗图片分类的卷积神经网络,并使用到深度学习框架TensorFlow和Keras,配置网络以便远程访问Jupyter Notebook。
02、案例实现
【目的】
面向小数据集,使用keras进行数据增强;
使用keras构建两层卷积神经网络,实现猫狗分类;
对学习模型进行性能评估。
【原理】
基于keras框架,构建顺序神经网络,包含3层卷积,使用relu激活函数,同时使用max池化,后接2个全连接层,中间使用dropout进行降采样。
【训练时长】
50个epoch,每个epoch大概需要50秒,在it1080下训练过程共需要40分钟左右。
【数据资源】
cat_dog数据集,从kaggle猫狗数据集中随机抽取3000个样本,其中训练集包含猫狗各1000,测试集包含猫狗各500。
【步骤1】数据预处理
使用小数据集(几百张到几千张图片)构造高效、实用的图像分类器的方法,需要通过一系列随机变换进行数据增强,可以抑制过拟合,使得模型的泛化能力更好。
在Keras中,这个步骤可以通过keras.preprocessing.image.ImageGenerator来实现:
(1) 在训练过程中,设置要施行的随机变换
(2) 通过.flow或.flow_from_directory(directory)方法实例化一个针对图像batch的生成器,这些生成器可以被用作keras模型相关方法的输入,如fit_generator,evaluate_generator和predict_generator
导入相关资源的代码如下所示。
import numpy as np
from keras.preprocessing.image import ImageDataGenerator #图像预处理
import keras.backend as K
K.set_image_dim_ordering('tf')
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
加载数据的代码如下:
使用.flow_from_directory()来从jpgs图片中直接产生数据和标签
# 用于生成训练数据的对象
train_gen= ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# 用于生成测试数据的对象
test_datagen = ImageDataGenerator(rescale=1./255)
参数解释如下:
rotation_range是一个0~180的度数,用来指定随机选择图片的角度。
width_shift和height_shift用来指定水平和竖直方向随机移动的程度,这是两个0~1之间的比例。
rescale值将在执行其他处理前乘到整个图像上,图像在RGB通道都是0~255的整数,这样的操作可能使图像的值过高或过低,所以将这个值定为0~1之间的数。
shear_range是用来进行剪切变换的程度。
zoom_range用来进行随机的放大
horizontal_flip随机地对图片进行水平翻转,这个参数适用于水平翻转不影响图片语义的时候
fill_mode用来指定当需要进行像素填充,如旋转,水平和竖直位移时,如何填充新出现的像素
# 从指定路径小批量读取数据
train_data = train_gen.flow_from_directory(
'../datas/min_data/train', # t路径
target_size=(150, 150), # 图片大小
batch_size=32, # 每次读取的数量
class_mode='binary') # 标签编码风格
# 从测试集中分批读取验证数据
val_data= test_gen.flow_from_directory(
'../datas/min_data/test',
target_size=(150, 150),
batch_size=32,
class_mode='binary')
使用小数据集(几百张到几千张图片)构造高效、实用的图像分类器的方法,需要通过一系列随机变换进行数据增强,可以抑制过拟合,使得模型的泛化能力更好。
【步骤2】构建神经网络
模型包含3层卷积加上ReLU激活函数,再接max-pooling层,代码如下所示
model = Sequential()
model.add(Convolution2D(32, 3, 3, input_shape=(3, 150, 150)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
两个全连接网络,并以单个神经元和sigmoid激活结束模型。这种选择会产生二分类的结果,与这种配置相适应使用binary_crossentropy作为损失函数,每个卷积层的滤波器数目并不多。
为了防止过拟合,需要添加Dropout层,代码如下所示。
model.add(Flatten()) # 展平
model.add(Dense(64)) # 全连接
model.add(Activation('relu')) # 激活
model.add(Dropout(0.5)) # 降采样
model.add(Dense(1)) # 全连接
model.add(Activation('sigmoid')) # 激活
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
投入数据,训练网络,代码如下所示。
model.fit_generator(
train_data, # 训练集
samples_per_epoch=2000, # 训练样本数量
nb_epoch=50, # 训练次数
validation_data=val_data, #验证数据
nb_val_samples=800 # 验证集大小
)
model.save_weights('../model/cat_dog.h5') # 保存模型文件
完整代码如下所示。
【案例1】Conv_3.ipynb
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K
# 图片大小
img_width, img_height = 150, 150
train_data_dir = '../datas/min_data/train'
validation_data_dir = '../datas/min_data/test'
nb_train_samples = 2000
nb_val_samples =1000
epochs = 50
batch_size = 16
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
# 数据读取、数据增强
train_gen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
val_gen = ImageDataGenerator(rescale=1. / 255)
train_data= train_gen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
val_data=val_gen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
# 构建3层卷积神经网络
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# 添加站平层、全连接层、降采样层
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
# 定义损失函数和优化策略
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# 开始训练
model.fit_generator(
train_data,
steps_per_epoch=nb_train_samples // batch_size,
epochs=epochs,
validation_data=val_data,
validation_steps=nb_val_samples // batch_size)
# 保存
yaml_string = model.to_yaml()
with open('cat_dog.yaml', 'w') as outfile:
outfile.write(yaml_string)
model.save_weights('cat_dog.h5')
运行结果如下:
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
WARNING:tensorflow:From /home/yangrh/anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:1208: calling reduce_prod (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.
Instructions for updating:
keep_dims is deprecated, use keepdims instead
WARNING:tensorflow:From /home/yangrh/anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:1297: calling reduce_mean (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.
Instructions for updating:
keep_dims is deprecated, use keepdims instead
Epoch 1/50
125/125 [==============================] - 40s - loss: 0.7057 - acc: 0.5140 - val_loss: 0.6797 - val_acc: 0.5363
Epoch 2/50
125/125 [==============================] - 40s - loss: 0.6851 - acc: 0.5865 - val_loss: 0.6391 - val_acc: 0.6839
......
Epoch 50/50
125/125 [==============================] - 40s - loss: 0.3996 - acc: 0.8370 - val_loss: 0.5988 - val_acc: 0.7947
【性能评估】
50个epoch,每个epoch大概需要50秒,在it1080下训练过程共需要40分钟左右,在验证集上的准确率达到80%,训练准确率与错误率如图7所示。
图7 准确率与错误率
下面案例代码使用训练好的模型对猫狗图片进行分类。
【案例2】Predict_Model.ipynb
import os
import keras
import keras.backend as K
from tables.tests.test_tables import LargeRowSize
K.set_image_dim_ordering('tf')
import numpy as np
from keras import callbacks
from keras.models import Sequential, model_from_yaml, load_model
from keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPool2D
from keras.optimizers import Adam, SGD
from keras.preprocessing import image
from keras.utils import np_utils, plot_model
from sklearn.model_selection import train_test_split
from keras.applications.resnet50 import preprocess_input, decode_predictions
img_h, img_w = 150, 150
image_size = (150, 150)
nbatch_size = 256
nepochs = 48
nb_classes = 2
def pred_data():
with open('cat_dog.yaml') as yamlfile:
loaded_model_yaml = yamlfile.read()
model = model_from_yaml(loaded_model_yaml)
model.load_weights('cat_dog.h5')
sgd = Adam(lr=0.0003)
model.compile(loss='categorical_crossentropy',optimizer=sgd, metrics=['accuracy'])
images = []
path='../datas/pred/'
for f in os.listdir(path):
img = image.load_img(path + f, target_size=image_size)
img_array = image.img_to_array(img)
x = np.expand_dims(img_array, axis=0)
x = preprocess_input(x)
result = model.predict_classes(x,verbose=0)
print(f,result[0])
# 0表示猫,1表示狗
pred_data()
运行结果如下:
c7.jpg [0]
dog.33.jpg [0]
dog.34.jpg [1]
dog.41.jpg [0]
c3.jpg [0]
c1.jpg [1]
dog.36.jpg [0]
c4.jpg [0]
dog.35.jpg [0]
dog.39.jpg [0]
c5.jpg [0]
dog.38.jpg [0]
c2.jpg [0]
dog.40.jpg [0]
c6.jpg [1]
c0.jpg [0]
dog.37.jpg [0]
更多推荐
所有评论(0)