TensorFlow深度学习项目实战

978-7-115-56389-7
作者: [美]卢卡·马萨罗(Luca Massaron)[美]阿尔贝托·博斯凯蒂(Alberto Boschetti)[美]‎阿列克谢·格里高瑞夫(Alexey Grigorev)[印]阿布舍克·塔库尔(Abhishek Thakur)[新加]拉贾林加帕·尚穆加马尼(Rajalingappaa Shanmugamani)
译者: 魏博刘昌灵司竹月刘小晴
编辑: 吴晋瑜

图书目录:

详情

本书旨在利用 TensorFlow 针对各种现实场景设计深度学习系统,引导读者实现有趣的深度学习项目。本书涵盖 10 个实践项目,如用目标检测 API 标注图像、利用长短期记忆神经网络(LSTM)预测股票价格、构建和训练机器翻译模型、检测 Quora 数据集中的重复问题等。通过阅读本书,读者可以了解如何搭建深度学习的 TensorFlow 环境、如何构建卷积神经网络以有效地处理图像、如何利用长短期记忆神经网络预测股票价格,以及如何实现一个能够自己玩电子游戏的人工智能(AI)! 本书适合数据科学家、机器学习和深度学习领域的从业者以及人工智能技术的爱好者 阅读。

图书摘要

版权信息

书名:TensorFlow深度学习项目实战

ISBN:978-7-115-56389-7

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    [美] 卢卡•马萨罗(Luca Massaron)

     [美] 阿尔贝托•博斯凯蒂(Alberto Boschetti)

     [美] 阿列克谢•格里高瑞夫(Alexey Grigorev)

     [印] 阿布舍克•塔库尔(Abhishek Thakur)

     [新加坡] 拉贾林加帕•尚穆加马尼(Rajalingappaa Shanmugamani)

译    魏 博 刘昌灵 司竹月  刘小晴

责任编辑 吴晋瑜

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


Copyright ©Packt Publishing 2018. First published in the English language under the title TensorFlow Deep Learning Projects (9781788398060). All rights reserved.

本书由英国Packt Publishing公司授权人民邮电出版社有限公司出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


本书旨在利用TensorFlow针对各种现实场景设计深度学习系统,引导读者实现有趣的深度学习项目。本书涵盖10个实践项目,如用目标检测API标注图像、利用长短期记忆神经网络(LSTM)预测股票价格、构建和训练机器翻译模型、检测Quora数据集中的重复问题等。通过阅读本书,读者可以了解如何搭建深度学习的TensorFlow环境、如何构建卷积神经网络以有效地处理图像、如何利用长短期记忆神经网络预测股票价格,以及如何实现一个能够自己玩电子游戏的人工智能(AI)。

本书适合数据科学家、机器学习和深度学习领域的从业者以及人工智能技术的爱好者阅读。


非常感谢Yukiko和Amelia的一贯支持、帮助和耐心等待。

——Luca Massaron

Luca Massaron是一名数据科学家,也是一家公司的市场研究总监,长期从事多元统计分析、机器学习和客户分析等工作,有10多年的解决实际问题的经验,擅长运用推理、统计、数据挖掘和算法为客户创造价值。他对数据分析技术非常感兴趣,乐于向专业人员和非专业人员展示数据驱动的知识发现的巨大潜力。他坚信通过简单明了的解释和对行业的基本理解可以实现很多目标。

Alberto Boschetti是一名数据科学家,在信号处理和统计方面有丰富的经验。他拥有通信工程博士学位,目前从事自然语言处理、机器学习和分布式处理等方向的工作。他经常参加学术讨论、大型会议和其他活动,关注数据科学技术的最新进展。

非常感谢我的妻子Larisa和我的儿子Arkadij对本书的等待和支持。

——Alexey Grigorev

Alexey Grigorev是经验丰富的数据科学家、机器学习工程师和软件开发人员,拥有超过8年的专业经验。他原是一名Java开发人员,后转而从事数据科学工作。现在,Alexey是Simplaex公司的数据科学家,主要使用Java和Python进行数据清理、数据分析和建模。他擅长的领域是机器学习和文本挖掘。

Abhishek Thakur是一名数据科学家,主要关注应用机器学习和深度学习。他在2014年获得了德国波恩大学的计算机科学硕士学位,之后在多个行业工作。他的研究方向是自动化机器学习。他热衷于参加机器学习竞赛,在Kaggle竞赛中获得过全球第三名的好成绩。

感谢我的妻子Ezhil、家人和朋友的支持!感谢让我受益良多的所有老师和同事们!

——Rajalingappaa Shanmugamani

Rajalingappaa Shanmugamani是新加坡SAP公司的一名深度学习主管。他曾在多家初创公司工作,负责开发计算机视觉产品。他拥有印度理工学院的硕士学位,其毕业论文是关于计算机视觉在制造业中的应用。


Marvin Bertin是在线课程创作,也是技术图书的审稿人,主要关注深度学习、计算机视觉以及基于 TensorFlow 的自然语言处理等技术方向。他拥有机械工程学士学位和数据科学硕士学位,曾在美国加利福尼亚州旧金山湾区的企业担任机器学习工程师和数据科学家,主要从事推荐系统、自然语言处理和生物技术应用等方面的工作。目前他在一家初创公司工作,从事针对早期癌症检测开发深度学习算法的工作。


魏博 中国科学院计算机软件研究博士,前阿里巴巴视频搜索引擎算法专家,Opera新闻推荐算法专家,曾任志诺维思(北京)基因科技有限公司技术总监,现为北京字节跳动网络有限公司数据智能策略负责人。长期致力于数据科学在多个领域中的应用和产品落地。译作有《数据科学R语言实现》《概率图模型R语言》和《大规模数据分析和建模:基于Spark与R》。

刘昌灵 清华大学计算神经学在读博士,现为志诺维思(北京)基因科技有限公司算法专家,曾荣获全国大学生数学建模竞赛和美国大学生数学建模大赛一等奖。

司竹月 北京理工大学计算机数据挖掘硕士,前阿里巴巴视频搜索引擎算法工程师,现为北京字节跳动网络有限公司推荐算法工程师。

刘小晴 中国人民大学计算机(机器学习方向)硕士,现为志诺维思(北京)基因科技有限公司算法工程师。


TensorFlow是目前非常流行的用于机器学习和深度学习的框架。它为训练不同类型的深度学习模型提供了一个快速、高效的框架,可使训练后的模型拥有较高的准确率。本书通过10个实践项目,帮助你掌握基于TensorFlow的深度学习技术。

本书首先介绍如何搭建正确的TensorFlow环境。通过阅读本书,你可以了解如何使用TensorFlow训练不同类型的深度学习模型,其中包括卷积神经网络(CNN)、循环神经网络(RNN)、长短期记忆神经网络(LSTM)以及生成对抗网络(GAN);可以构建端到端的深度学习的解决方案,以处理真实世界的各种问题,例如图像处理、企业人工智能系统和自然语言处理等;还可以训练高性能的模型,例如为图像自动生成描述、预测股票的价格走势、构建智能聊天机器人等。本书还涉及一些高级内容,例如推荐系统和强化学习。

学完本书,你可以了解深度学习的有关概念,以及这些概念在TensorFlow中的相应实现,并能使用TensorFlow构建和训练自己的深度学习模型,进而具备解决多种类型的问题的技能。

本书适合数据科学家、机器学习和深度学习从业者以及人工智能爱好者阅读,可帮助他们提升构建真实智能系统的知识水平和专业能力。如果你希望通过TensorFlow完成实际项目,以掌握不同的深度学习概念和算法,本书应是首选!

第 1 章介绍如何采用必要的预处理步骤从图像中提取合适的特征。对于卷积神经网络,我们将使用Matplotlib生成的简单图像。

第2章介绍如何构建实时目标检测应用程序。该应用程序可以使用TensorFlow的目标检测API(一些预训练好的卷积神经网络,即TensorFlow检测Model Zoo)及OpenCV标注图像、视频和网络摄像头捕捉的影像。

第3章介绍如何借助或不借助预训练模型生成图像描述。

第4章介绍如何构建GAN以逐步再现所需的图像。使用的数据集是手写字符数据集(数字和字母都是Chars74K的)。

第5章介绍如何预测一维信号(股票价格),即根据股票的历史价格,使用LSTM预测其未来价格,并让预测更加准确。

第6章介绍如何使用TensorFlow构建和训练先进的机器翻译模型。

第7章介绍如何从零开始构建智能聊天机器人,以及如何与之进行交互。

第8章讨论检测Quora数据集中重复问题的方法——这些方法也可以用于其他类似的数据集。

第9章介绍如何用TensorFlow构建推荐系统,以及如何对其进行简单的评估。

第10章介绍如何构建可以玩转《登月着陆器》游戏的人工智能系统。该游戏基于已有的OpenAI Gym项目展开并使用TensorFlow进行整合。OpenAI Gym提供了不同的游戏环境,可以帮助使用者了解使用AI智能体的方法及其背后TensorFlow神经网络模型的算法。

本书的示例可以在Windows、Ubuntu和macOS上运行。读者应事先了解Python编程语言、机器学习和深度学习的基础知识,并且熟悉TensorFlow。

CodeInText:表示正文中的代码、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter句柄。例如,TqdmUpTo类是一个tqdm包装器,支持在下载时使用进度显示。

代码段的格式如下所示:

import numpy as np
import urllib.request
import tarfile
import os
import zipfile
import gzip
import os
from glob import glob
from tqdm import tqdm

命令行的输入或输出如下所示:

epoch 01: precision: 0.064
epoch 02: precision: 0.086
epoch 03: precision: 0.106
epoch 04: precision: 0.127
epoch 05: precision: 0.138
epoch 06: precision: 0.145
epoch 07: precision: 0.150
epoch 08: precision: 0.149
epoch 09: precision: 0.151
epoch 10: precision: 0.152

 

黑体:用于显示专业名词术语或重点强调的词或语句。

 

警告或重要的注释以这样的形式显示。

 

提示和技巧以这样的形式显示。


本章将构建一个简单的模型,以解决交通标志识别问题,这是本书的第一个项目。在这个模型中,深度学习的表现非常出色。简单来说,只要给定一幅交通标志的彩色图像,模型就能够识别出它是什么交通标志。

本章主要包括以下内容:

本章会用到一些交通标志,以完成图像预测任务,因此需要构建相应的数据集。幸运的是,德国für Neuroinformatik研究所的研究人员构建了一个包含约40000幅不同图像的数据集,其中包含43种交通标志。我们使用的数据集是德国交通标志识别基准(German Traffic Sign Recognition Benchmark,GTSRB)竞赛的一部分。该竞赛会对参赛者们为实现同一目标而构建的模型的性能进行评选。尽管这个数据集比较陈旧(2011年),但是对于本项目来说,不失为一个不错的选择。

要获取上述数据集,请自行搜索GTSRB_Final_Training_Images.zip文件。

 

在运行代码之前,请先下载文件并将其解压到该代码所在的目录下。解压后,得到的是一个名为GTSRB的包含数据集的文件夹。在此感谢为这一开源数据集做出贡献的人。

图 1-1~图 1-3给出了一些交通标志图像的示例。限速20km/h的交通标志如图1-1所示。直行或右转的交通标志如图1-2所示。环岛的交通标志如图1-3所示。

可以看到,交通标志图像的亮度并不一致(有些很暗,有些很亮),它们的大小、拍摄视角和背景也不尽相同,并且其中可能混杂着其他交通标志。

数据集的组织方式如下:所有标签相同的图像位于同一文件夹中。例如,文件路径GTSRB/Final_Training/Images/00040/所指文件夹中的图像标签均为40,而文件路径GTSRB/Final_Training/Images/00005/所指文件夹中的图像标签为5。注意,这些图像均为PPM格式——一种无损压缩格式,这种格式的图像支持很多开源的编码器/解码器。

图1-1

图1-2

图1-3

本项目会用到一个具有图1-4所示结构的简单卷积神经网络。

在上述结构中,还有以下参数:

(1)二维卷积层中滤波器的个数和核的大小;

(2)最大池化层中核的大小;

(3)全连接层中的单元数;

(4)批大小、优化算法、学习步骤(最终的衰减率)、各层的激活函数和轮数。

图1-4

模型的第一步操作是读入图像并对其进行标准化处理,即图像预处理。事实上,我们不能在图像尺寸不统一的情况下开展后续工作。因此,首先要加载图像并且将其变换为指定的尺寸(32×32)。除此之外,我们需要对标签进行one-hot编码,得到一个43维的矩阵,让矩阵中的每一维只有一个元素有效,同时把图像的颜色空间从RGB模式转为灰度模式。我们通过观察图像可以发现,所需要的信息不在标志图像的颜色中,而是在图像的形状和设计中。

接着,打开Jupyter Notebook,编写代码。先设置一些全局变量,包括类的数量(43)和变换后图像的尺寸:

N_CLASSES = 43
RESIZED_IMAGE = (32, 32)

接下来,定义一个函数,用来读取给定目录下的所有图像,然后把这些图像转换成给定形状,转为灰度图,并对标签做one-hot编码。这里需要使用一个名为Dataset的元组:

import matplotlib.pyplot as plt
import glob
from skimage.color import rgb2lab
from skimage.transform import resize
from collections import namedtuple
import numpy as np
np.random.seed(101)
%matplotlib inline
Dataset = namedtuple('Dataset', ['X', 'y'])
def to_tf_format(imgs):
    return np.stack([img[:, :, np.newaxis] for img in imgs],
axis=0).astype(np.float32)
def read_dataset_ppm(rootpath, n_labels, resize_to):
images = []
labels = []
for c in range(n_labels):    
   full_path = rootpath + '/' + format(c, '05d') + '/'
   for img_name in glob.glob(full_path + "*.ppm"):
     img = plt.imread(img_name).astype(np.float32)
     img = rgb2lab(img / 255.0)[:,:,0]      
     if resize_to:        
       img = resize(img, resize_to, mode='reflect')
     label = np.zeros((n_labels, ), dtype=np.float32)
     label[c] = 1.0                
    images.append(img.astype(np.float32))
     labels.append(label)
return Dataset(X = to_tf_format(images).astype(np.float32),
                 y = np.matrix(labels).astype(np.float32))
dataset = read_dataset_ppm('GTSRB/Final_Training/Images', N_CLASSES,
RESIZED_IMAGE) 
print(dataset.X.shape)
print(dataset.y.shape)

因为用了skimage模块,所以图像的读取、变换、改变尺寸的操作将非常简单。我们在代码实现中决定对原始的颜色空间(RGB)进行转化,只保留亮度分量。在这里,另一个可以较好地进行转化的颜色空间是YUV,其中只有Y分量应该被保留为灰度图。

运行代码的结果如下:

(39209, 32, 32, 1)
(39209, 43)

注意输出格式:观察矩阵的维度为4。第一个维度代表观察值的索引(近40000),其他3个维度表示图像信息(32×32的一维灰度图)。这是用TensorFlow处理的图像的默认形状(详见代码中的_tf_format函数)。

对于标签矩阵,行是观察值的索引,列是标签的one-hot编码。

为了更好地理解观察矩阵,我们输出第一个样本的特征向量(见图1-5)和标签向量:

图1-5

plt.imshow(dataset.X[0, :, :, :].reshape(RESIZED_IMAGE)) #sample
print(dataset.y[0, :]) #label
[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

可以发现,图像就是特征向量,其尺寸为32×32。标签向量只在第一个位置值为1。

输出最后一个样本,如图1-6所示。

plt.imshow(dataset.X[-1, :, :, :].reshape(RESIZED_IMAGE)) #sample
print(dataset.y[-1, :]) #label
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]

图1-6

特征向量的尺寸保持不变,仍为32×32,而标签向量只在最后一个位置值为1。

这就是构建模型需要的两部分信息。尤其要注意图像的形状,因为在用深度学习处理图像的过程中这很关键。与经典机器学习的观察矩阵相比,这里的维度为4。

图像预处理的最后一步是训练集/测试集的分割。我们希望在数据集的一个子集上训练模型,并在其补集(测试集)上测试模型的性能,为此需要用到sklearn提供的函数:

from sklearn.model_selection import train_test_split 
idx_train, idx_test = train_test_split(range(dataset.X.shape[0]), 
test_size=0.25, random_state=101)
X_train = dataset.X[idx_train, :, :, :]
X_test = dataset.X[idx_test, :, :, :]
y_train = dataset.y[idx_train, :]
y_test = dataset.y[idx_test, :]
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)

在这个例子中,我们用数据集中75%的样本训练,用其余25%的样本测试。此时,代码的实际输出如下:

(29406, 32, 32, 1)
(29406, 43)
(9803, 32, 32, 1)
(9803, 43)

首先,我们需要一个用于创建小批量训练数据的函数。事实上,在每次训练迭代中,我们都需要插入从训练集中提取的小批量样本。这里需要创建一个函数,该函数将观察值、标签和批大小作为参数,并返回一个小批量样本生成器。此外,为了在训练数据中引入一些可变性,我们在函数中加入另一个参数(重洗数据),以使每个生成器有可能包含不同的小批量数据。这样将迫使模型学习输入、输出的关系,而不是去记忆序列。

def minibatcher(X, y, batch_size, shuffle): 
assert X.shape[0] == y.shape[0]
n_samples = X.shape[0] 
if shuffle:
   idx = np.random.permutation(n_samples) 
else:
   idx = list(range(n_samples))
for k in range(int(np.ceil(n_samples/batch_size))):
   from_idx = k*batch_size    
   to_idx = (k+1)*batch_size    
   yield X[idx[from_idx:to_idx], :, :, :], y[idx[from_idx:to_idx], :]

为了测试这一函数,我们用如下代码输出batch_size=10000时小批量样本的形状:

for mb in minibatcher(X_train, y_train, 10000, True): 
print(mb[0].shape, mb[1].shape)

输出的结果如下:

(10000, 32, 32, 1) (10000, 43)
(10000, 32, 32, 1) (10000, 43)
(9406, 32, 32, 1) (9406, 43)

不出所料,训练集中的29406个样本被分成了两个有10000个元素的小批量样本和一个有9406个元素的小批量样本。当然,标签矩阵中也有相同数量的元素。

现在我们可以构建模型了。首先,需要确定模型的模块,可以从创建全连接层开始,加入可变数量的单元(作为参数)且不加入激活层。我们采用xavier初始化方法对系数(权重)进行初始化,偏置设为0。输出等于输入张量乘以权重,再加上偏置。需要注意的是,权重的维度是动态定义的,因此可用于模型中的任何地方。

import tensorflow as tf 
def fc_no_activation_layer(in_tensors, n_units): 
w = tf.get_variable('fc_W', 
   [in_tensors.get_shape()[1], n_units],
   tf.float32,
   tf.contrib.layers.xavier_initializer())
b = tf.get_variable('fc_B',
   [n_units, ], 
   tf.float32,
   tf.constant_initializer(0.0)) 
return tf.matmul(in_tensors, w) + b

下面我们来创建带激活函数的全连接层。值得一提的是,这里的激活函数采用leaky ReLU,用如下方法来实现:

def fc_layer(in_tensors, n_units): 
return tf.nn.leaky_relu(fc_no_activation_layer(in_tensors, n_units))

然后,创建一个卷积层,参数包含输入数据、核的大小以及滤波器(或神经元)个数。采用与全连接层相同的激活函数。在这种情况下,输出层需要通过leaky ReLU激活函数激活:

def conv_layer(in_tensors, kernel_size, n_units): 
w = tf.get_variable('conv_W',
   [kernel_size, kernel_size, in_tensors.get_shape()[3], n_units],           
   tf.float32,
   tf.contrib.layers.xavier_initializer())
b = tf.get_variable('conv_B',
   [n_units, ],
   tf.float32,
   tf.constant_initializer(0.0))
return tf.nn.leaky_relu(tf.nn.conv2d(in_tensors, w, [1, 1, 1, 1], 'SAME') + b)

再创建池化层maxpool_layer。这里,核的尺寸和步长都是平方级的:

def maxpool_layer(in_tensors, sampling): 
return tf.nn.max_pool(in_tensors, [1, sampling, sampling, 1], [1, sampling, sampling, 1], 'SAME')

最后要创建的是定义dropout层,用来正则化网络。dropout层的定义相当简单。只需要记住,它在训练时会用到,预测时不会用到。因此,需要一个额外的条件运算符来定义是否使用dropout层:

def dropout(in_tensors, keep_proba, is_training): 
return tf.cond(is_training, lambda: tf.nn.dropout(in_tensors, keep_proba), lambda:in_tensors)

最后,我们需要把各模块组合起来并构建模型。构建的模型包含以下几层。

(1)二维卷积层,5×5,共32个滤波器。

(2)二维卷积层,5×5,共64个滤波器。

(3)展平层。

(4)全连接层,共1024个单元。

(5)40%的dropout层。

(6)全连接层(无激活函数)。

(7)Softmax层。

代码如下:

def model(in_tensors, is_training): 
# First layer: 5x5 2d-conv, 32 filters, 2x maxpool, 20% drouput 
with tf.variable_scope('l1'): 
   l1 = maxpool_layer(conv_layer(in_tensors, 5, 32), 2)
   l1_out = dropout(l1, 0.8, is_training) 
# Second layer: 5x5 2d-conv, 64 filters, 2x maxpool, 20% drouput 
with tf.variable_scope('l2'):
   l2 = maxpool_layer(conv_layer(l1_out, 5, 64), 2)
   l2_out = dropout(l2, 0.8, is_training) 
with tf.variable_scope('flatten'):    
   l2_out_flat = tf.layers.flatten(l2_out) 
# Fully collected layer, 1024 neurons, 40% dropout 
with tf.variable_scope('l3'):
   l3 = fc_layer(l2_out_flat, 1024)    
   l3_out = dropout(l3, 0.6, is_training)
# Output
with tf.variable_scope('out'):   
   out_tensors = fc_no_activation_layer(l3_out, N_CLASSES) 
return out_tensors

现在我们需要定义函数来训练模型并在测试集上测试其性能。注意,下面的代码都属于train_model函数,为了便于解释,我们将其拆分成若干块。

函数的参数包括训练集、测试集及其对应的标签、学习率、轮数、批大小(每个训练批次的样本数量)。首先,需要定义TensorFlow占位符——一个用于小批量图像,一个用于小批量标签,一个用于选择是否运行代码以进行训练(主要用于dropout层):

from sklearn.metrics import classification_report, confusion_matrix 
def train_model(X_train, y_train, X_test, y_test, learning_rate, max_epochs, batch_  
size): 
in_X_tensors_batch = tf.placeholder(tf.float32, shape = (None, 
RESIZED_IMAGE[0], RESIZED_IMAGE[1], 1))
in_y_tensors_batch = tf.placeholder(tf.float32, shape = (None, N_CLASSES)) 
is_training = tf.placeholder(tf.bool)

接下来,定义输出、度量分数和优化器。这里用AdamOptimizersoftmax(logits)下的交叉熵作为损失函数:

logits = model(in_X_tensors_batch, is_training)
out_y_pred = tf.nn.softmax(logits)
loss_score = tf.nn.softmax_cross_entropy_with_logits(logits=logits,
labels=in_y_tensors_batch) 
loss = tf.reduce_mean(loss_score) 
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)

最后,用小批量样本训练模型:

with tf.Session() as session:    
   session.run(tf.global_variables_initializer())    
   for epoch in range(max_epochs):    
    print("Epoch=", epoch)    
     tf_score = []   
     for mb in minibatcher(X_train, y_train, batch_size, shuffle = True):    
       tf_output = session.run([optimizer, loss],
                               feed_dict = {in_X_tensors_batch : mb[0],  
                                            in_y_tensors_batch : b[1], 
                                             is_training : True})
       tf_score.append(tf_output[1])
     print(" train_loss_score=", np.mean(tf_score))

训练之后,我们需要在测试集上测试模型。这里使用整个测试集进行测试,而不使用小批量样本。由于不使用dropout层,对应的参数is_training需要设为False

   print("TEST SET PERFORMANCE")
   y_test_pred, test_loss = session.run([out_y_pred, loss],
                                         feed_dict = {in_X_tensors_batch :X_test,
in_y_tensors_batch : y_test,is_training : False})

最后,输出分类结果并绘制混淆矩阵(以及它的log2版本),以观察误分类的情况:

   print(" test_loss_score=", test_loss)
   y_test_pred_classified = np.argmax(y_test_pred, axis=1).astype(np.int32)
   y_test_true_classified = np.argmax(y_test, axis=1).astype(np.int32)
   print(classification_report(y_test_true_classified, y_test_pred_classified))
   cm = confusion_matrix(y_test_true_classified, y_test_pred_classified)
   plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
   plt.colorbar()
   plt.tight_layout()    
   plt.show()
   #log2版本,用于观察错误分类的情况
   plt.imshow(np.log2(cm + 1), interpolation='nearest',cmap=plt.get_cmap("tab20"))
   plt.colorbar()    
   plt.tight_layout()    
   plt.show()
tf.reset_default_graph()

最后,让我们运行包含如下参数的函数。这里将参数分别设置为学习率0.001、轮数10以及每个小批量包含256个样本:

train_model(X_train, y_train, X_test, y_test, 0.001, 10, 256)

输出如下:

Epoch= 0
train_loss_score= 3.4909246
Epoch= 1
train_loss_score= 0.5096467
Epoch= 2
train_loss_score= 0.26641673
Epoch= 3
train_loss_score= 0.1706828
Epoch= 4
train_loss_score= 0.12737551
Epoch= 5
train_loss_score= 0.09745725
Epoch= 6
train_loss_score= 0.07730477
Epoch= 7
train_loss_score= 0.06734192
Epoch= 8
train_loss_score= 0.06815668
Epoch= 9
train_loss_score= 0.060291935
TEST SET PERFORMANCE
test_loss_score= 0.04581982

每个类别的分类结果如下:

 precision recall f1-score support
 0 1.00 0.96 0.98 67
 1 0.99 0.99 0.99 539
 2 0.99 1.00 0.99 558
 3 0.99 0.98 0.98 364
 4 0.99 0.99 0.99 487
 5 0.98 0.98 0.98 479
 6 1.00 0.99 1.00 105
 7 1.00 0.98 0.99 364
 8 0.99 0.99 0.99 340
 9 0.99 0.99 0.99 384
 10 0.99 1.00 1.00 513
 11 0.99 0.98 0.99 334
 12 0.99 1.00 1.00 545
 13 1.00 1.00 1.00 537
 14 1.00 1.00 1.00 213
 15 0.98 0.99 0.98 164
 16 1.00 0.99 0.99 98
 17 0.99 0.99 0.99 281
 18 1.00 0.98 0.99 286
 19 1.00 1.00 1.00 56
 20 0.99 0.97 0.98 78
 21 0.97 1.00 0.98 95
 22 1.00 1.00 1.00 97
 23 1.00 0.97 0.98 123
 24 1.00 0.96 0.98 77
 25 0.99 1.00 0.99 401
 26 0.98 0.96 0.97 135
 27 0.94 0.98 0.96 60
 28 1.00 0.97 0.98 123
 29 1.00 0.97 0.99 69
 30 0.88 0.99 0.93 115
 31 1.00 1.00 1.00 178
 32 0.98 0.96 0.97 55
 33 0.99 1.00 1.00 177
 34 0.99 0.99 0.99 103
 35 1.00 1.00 1.00 277
 36 0.99 1.00 0.99 78
 37 0.98 1.00 0.99 63
 38 1.00 1.00 1.00 540
 39 1.00 1.00 1.00 60
 40 1.00 0.98 0.99 85
 41 1.00 1.00 1.00 47 
 42 0.98 1.00 0.99 53 
avg/total 0.99 0.99 0.99 9803

可以看到,模型在测试集上达到了0.99的精度。此外,召回率和f1值也为0.99。测试集的损失与最后一次迭代的损失相近,由此说明模型运行稳定,没有出现过拟合或欠拟合的现象。

混淆矩阵如图1-7所示。图1-8是图1-7所示的混淆矩阵的log2版本(实际为彩色图)。

图1-7

图1-8

请思考如下问题。

(1)如果添加或去掉一些卷积层或全连接层,那么模型的性能会有何变化?

(2)本章的项目反映了dropout层对正则化的必要性。请尝试改变dropout层的比例,观察输出的过拟合和欠拟合现象。

(3)请在你所在的城市拍摄多个交通标志,实际测试一下训练好的模型。

本章介绍了如何使用卷积神经网络(Convolutional Neural Network,CNN)识别交通标志。第2章将用CNN完成更加复杂的项目。


相关图书

ChatGPT原理与应用开发
ChatGPT原理与应用开发
深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
深度学习:从基础到实践(上、下册)
深度学习:从基础到实践(上、下册)
动手学深度学习(PyTorch版)
动手学深度学习(PyTorch版)
深度学习与医学图像处理
深度学习与医学图像处理
深度强化学习实战:用OpenAI Gym构建智能体
深度强化学习实战:用OpenAI Gym构建智能体

相关文章

相关课程