# Import `tensorflow`
import tensorflow as tf
# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])
# Multiply
result = tf.multiply(x1, x2)
# Intialize the Session
sess = tf.Session()
# Print the result
print(sess.run(result))
# Close the session
sess.close()
# Print the `images` dimensions
print(images.ndim)
# Print the number of `images`'s elements
print(images.size)
# Print the first instance of `images`
images[0]
# Print the `labels` dimensions
print(labels.ndim)
# Print the number of `labels`'s elements
print(labels.size)
# Count the number of labels
print(len(set(labels)))
# Import the `pyplot` module
import matplotlib.pyplot as plt
# Make a histogram with 62 bins of the `labels` data
plt.hist(labels, 62)
# Show the plot
plt.show()
# Import the `pyplot` module of `matplotlib`import matplotlib.pyplot as plt
# Determine the (random) indexes of the images that you want to see
traffic_signs =[300,2250,3650,4000]# Fill out the subplots with the random images that you defined for i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()技术支持
# Import `matplotlib`import matplotlib.pyplot as plt
# Determine the (random) indexes of the images
traffic_signs =[300,2250,3650,4000]# Fill out the subplots with the random images and add shape, min and max valuesfor i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape,
images[traffic_signs[i]].min(),
images[traffic_signs[i]].max()))技术支持
# Import the `pyplot` module as `plt`import matplotlib.pyplot as plt
# Get the unique labels
unique_labels =set(labels)# Initialize the figure
plt.figure(figsize=(15,15))# Set a counter
i =1# For each unique label,for label in unique_labels:# You pick the first image for each label
image = images[labels.index(label)]# Define 64 subplots
plt.subplot(8,8, i)# Don't include axes
plt.axis('off')# Add a title to each subplot
plt.title("Label {0} ({1})".format(label, labels.count(label)))# Add 1 to the counter
i +=1# And you plot this first image
plt.imshow(image)# Show the plot
plt.show()技术支持
# Import the `transform` module from `skimage`from skimage import transform
# Rescale the images in the `images` array
images28 =[transform.resize(image,(28,28))for image in images]技术支持
注意,由于进行了缩放,您的 min 与 max 值也发生了变化;它们现在似乎都落在相同的范围内,这很好,因为您就不一定需要再对数据进行归一化了!
图像灰度化
正如本节开头所说,在回答分类问题时,图像中的颜色影响较小。这就是为什么您还要进行图像灰度化。
注意,不过,您也可以自行测试,如果不执行这一步,模型的最终结果会如何变化。
就像进行缩放那样,您仍可依赖 Scikit-Image 来帮忙;这次需要使用的是 color 模块中的 rgb2gray() 函数。
这将会很轻松!
不过,别忘了先把 images28 转回数组,因为 rgb2gray() 需要数组作为参数。
# Import `rgb2gray` from `skimage.color`from skimage.color import rgb2gray
# Convert `images28` to an array
images28 = np.array(images28)# Convert `images28` to grayscale
images28 = rgb2gray(images28)技术支持
通过绘制部分图像再次检查灰度化的结果;这里您同样可以复用并稍作修改代码,来展示调整后的图像:
import matplotlib.pyplot as plt
traffic_signs =[300,2250,3650,4000]for i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images28[traffic_signs[i]], cmap="gray")
plt.subplots_adjust(wspace=0.5)# Show the plot
plt.show()技术支持
# Import `matplotlib`import matplotlib.pyplot as plt
import random
# Pick 10 random images
sample_indexes = random.sample(range(len(images28)),10)
sample_images =[images28[i]for i in sample_indexes]
sample_labels =[labels[i]for i in sample_indexes]# Run the "correct_pred" operation
predicted = sess.run([correct_pred], feed_dict={x: sample_images})[0]# Print the real and predicted labelsprint(sample_labels)print(predicted)# Display the predictions and the ground truth visually.
fig = plt.figure(figsize=(10,10))for i inrange(len(sample_images)):
truth = sample_labels[i]
prediction = predicted[i]
plt.subplot(5,2,1+i)
plt.axis('off')
color='green'if truth == prediction else'red'
plt.text(40,10,"Truth: {0}\nPrediction: {1}".format(truth, prediction),
fontsize=12, color=color)
plt.imshow(sample_images[i], cmap="gray")
plt.show()技术支持
然而,只看随机图像并不能让您深入了解模型实际表现。因此,接下来加载测试数据。
注意,这里复用了您在教程开头定义的 load_data() 函数。
# Import `skimage`from skimage import transform
# Load the test data
test_images, test_labels = load_data(test_data_directory)# Transform the images to 28 by 28 pixels
test_images28 =[transform.resize(image,(28,28))for image in test_images]# Convert to grayscalefrom skimage.color import rgb2gray
test_images28 = rgb2gray(np.array(test_images28))# Run predictions against the full test set.
predicted = sess.run([correct_pred], feed_dict={x: test_images28})[0]# Calculate correct matches
match_count =sum([int(y == y_)for y, y_ inzip(test_labels, predicted)])# Calculate the accuracy
accuracy = match_count /len(test_labels)# Print the accuracyprint("Accuracy: {:.3f}".format(accuracy))技术支持
记得在未使用 with tf.Session() as sess: 启动 TensorFlow 会话的情况下,最后用 sess.close() 关闭会话。
深度学习是机器学习的一个子领域,它是一组受大脑结构与功能启发而来的算法。
TensorFlow 是 Google 创建的第二个机器学习框架,被用于设计、构建和训练深度学习模型。您可以用 TensorFlow 库进行数值计算,这本身看起来并不特别,但这些计算是通过数据流图来完成的。在这些图中,节点代表数学运算,边代表数据,通常是多维数据数组或张量,在这些边之间传递。
明白了吗?“TensorFlow”的名字正来源于神经网络对多维数据数组(张量)执行的操作!它从字面意义上就是张量的流动。关于张量,您目前只需了解这些,接下来的章节会更深入!
今天这篇面向初学者的 TensorFlow 教程将以互动的方式带您开展深度学习:
下载本教程的 notebook 请点击这里。
您也可以对这门课程感兴趣:Deep Learning in Python,DataCamp 的Keras 教程或R 版 keras 教程。
走近张量(Tensors)
要深入理解张量,具备一定的线性代数与向量微积分基础会很有帮助。您在引言中已读到,张量在 TensorFlow 中作为多维数据数组实现,但为了完全把握张量及其在机器学习中的用途,仍需要更多铺垫。
平面向量
在谈论平面向量之前,先快速回顾一下“向量”这个概念;向量是特殊类型的矩阵,即数字的矩形数组。由于向量是有序的数字集合,常被视为列矩阵:只有一列,若干行。换言之,您也可将向量看作赋予了方向的标量大小。
请记住:标量的例子如“5 米”或“60 米/秒”,而向量的例子如“向北 5 米”或“向东 60 米/秒”。两者的区别显然在于向量具有方向。不过,迄今为止您看到的这些例子,似乎与在机器学习问题中遇到的向量相去甚远。这很正常;数学向量的长度是纯数值:是绝对量。另一方面,方向是相对量:相对于某个参考方向来测量,单位为弧度或角度。通常假设方向为正,并相对于参考方向逆时针旋转。
在可视化上,您当然会像上图那样用箭头表示向量。这意味着您也可以把向量看作既有方向又有长度的箭头。箭头的尖端指示方向,而箭身长度表示大小。
那么,平面向量是什么呢?
平面向量是张量最直观的设定。它们与您上面见到的普通向量很相似,唯一的区别是它们处在一个向量空间中。为更好理解这一点,让我们从例子出发:假设您有一个 2 X 1 的向量。这意味着该向量属于成对出现的实数集合。换言之,它们属于二维空间。在这种情况下,您可以在坐标平面 (x,y) 上用箭头或射线表示向量。
在标准位置(向量的终点位于原点 (0,0))的坐标平面上,您可以通过查看向量的第一行得到 x 坐标,而第二行给出 y 坐标。当然,并不总需要保持这种标准位置:向量可以在平面内沿自身平行移动而不发生变化。
注意,类似地,对于大小为 3 X 1 的向量,您讨论的是三维空间。您可以将其表示为三维图形,箭头指向向量空间中的位置:它们绘制在标准的 x、y 和 z 轴上。
拥有这些向量并在坐标平面上表示它们固然很好,但本质上,您之所以需要向量,是为了对其进行运算。帮助您做到这一点的一种方法是将向量表示为基或单位向量。
单位向量是模为 1 的向量。您经常会看到小写字母上带“^”符号来表示单位向量。若要将一个二维或三维向量表示为两个或三个正交分量(如 x 轴和 y 轴,或再加上 z 轴)的和,单位向量将非常方便。
当您谈到将一个向量(例如)表示为分量之和时,实际上说的是分量向量,即两个或多个向量,其和等于给定向量。
提示:观看这个视频,它借助日常家居物品来解释张量!
张量
除了平面向量,共变向量与线性算子也是另外两种情形,这三者有一个共同点:它们都是张量的特例。您还记得上一节中如何将向量刻画为赋予了方向的标量大小。那么,张量就是对可能具有大小并有多个方向的物理实体的数学表示。
同样地,就像在三维空间中用一个数字表示标量,用三个数字的序列表示向量一样,张量可以在三维空间中用一个包含 3^R 个数字的数组来表示。
该表示中的“R”代表张量的秩(rank):这意味着在三维空间中,二阶张量可由 3 的 2 次方,即 9 个数字表示。在 N 维空间中,标量仍只需一个数字,向量需要 N 个数字,而张量需要 N^R 个数字。这也解释了为何常说标量是 0 阶张量:因为它们没有方向,可以用一个数字表示。
在此基础上,识别并区分标量、向量和张量就相对容易了:标量可用单个数字表示,向量由有序数字集合表示,张量由数字数组表示。
张量的独特之处在于其分量与基向量的组合:基向量在不同参考系之间以一种方式变换,而分量则以恰好相反的方式变换,从而保持分量与基向量的组合不变。
安装 TensorFlow
现在您对 TensorFlow 有了更多了解,是时候开始安装库了。需要说明的是,TensorFlow 为 Python、C++、Haskell、Java、Go、Rust 提供 API,另有 R 的第三方包
tensorflow。提示:如果您想进一步了解 R 中的深度学习包,可查看 DataCamp 的keras:R 语言深度学习教程。
在本教程中,您将下载一个版本的 TensorFlow,以便用 Python 为深度学习项目编写代码。在 TensorFlow 安装页面上,您会看到使用
virtualenv、pip、Docker 安装 TensorFlow 的常见方法与最新说明,最后还列出了一些在个人电脑上安装 TensorFlow 的其它方式。注意 如果您在 Windows 上工作,也可以通过 Conda 安装 TensorFlow。但由于该安装方式由社区支持,最好查阅官方安装指南。
完成安装流程后,是时候通过在工作区中以别名
tf导入它,来再次确认 TensorFlow 是否正确安装:注意,上述代码行所用的别名是一种“约定”——一方面有助于与其他在数据科学项目中使用 TensorFlow 的开发者保持一致,另一方面也与开源的 TensorFlow 项目保持一致性。
TensorFlow 入门:基础
通常您会把 TensorFlow 程序写好后“成块”运行;当您使用 Python 时,这乍看有点矛盾。不过,如果您愿意,也可以使用 TensorFlow 的交互式会话,这样就能以更互动的方式使用该库。这对于习惯使用 IPython 的人尤其方便。
在本教程中,您将专注于第二种方式:这将帮助您快速上手在 TensorFlow 中进行深度学习。但在进一步深入之前,先尝试一些小示例,再开始“重活”。
首先,像上一节所示那样,以别名
tf导入tensorflow库。然后初始化两个实际上是常量的变量。向constant()函数传入一个包含四个数字的数组。注意,您也可以传入一个整数,但更多时候您会使用数组。正如引言中所述,张量就是关于数组的!所以请确保传入一个数组 :) 接下来,使用
multiply()来将两个变量相乘。将结果存储在result变量中。最后,通过print()函数打印result。注意,在上面的 DataCamp Light 代码块中,您定义的是常量。不过,您还可以使用另外两种类型的值,即占位符,它们是未赋值的,将在您运行会话时由会话初始化。顾名思义,它仅是一个占位的张量,每次会话运行时都会被喂入;还有 变量,即可以改变的值。正如您可能已经明白的,常量则是不会改变的值。
这些代码行的结果是在计算图中的一个抽象张量。然而,与预期相反,
result实际上并没有被计算。它只是定义了模型,但没有执行任何过程来计算结果。您可以从打印输出看到:并没有出现您期望的结果(即 30)。这意味着 TensorFlow 采用惰性求值!不过,如果您想看到结果,就需要在交互式会话中运行这段代码。可以通过几种方式实现,正如下方 DataCamp Light 代码块所示:
注意,您也可以使用以下代码来启动交互式会话,运行
result,并在打印output后自动关闭会话:在以上代码块中,您只是定义了一个默认会话,但也要知道,您同样可以传入可选项。例如,您可以指定
config参数,再使用ConfigProto协议缓冲区为会话添加配置项。例如,如果您添加
到会话中,将确保记录分配给某个操作的 GPU 或 CPU 设备。您将获得该会话中每个操作使用了哪些设备的信息。例如,当您在设备放置上使用软约束时,也可以使用如下配置:
现在,您已经安装并在工作区中导入了 TensorFlow,也过了一遍使用该包的基础,是时候暂时把它放一边,把注意力转向数据。像往常一样,在开始构建神经网络之前,您会先花时间去探索和理解数据。
比利时交通标志:背景
尽管交通这个主题大家都很熟悉,但在开始之前,简要过一遍该数据集中包含的观测内容也无妨,以确认您理解无误。本节的本质是帮助您掌握继续学习本教程所需的领域知识。
当然,因为我是比利时人,我也会穿插一些趣闻轶事 :)
加载并探索数据
现在您已经获取了更多背景信息,是时候在这里下载数据集了。您应当获取列在“BelgiumTS for Classification (cropped images)”旁的两个 zip 文件,名为“BelgiumTSC_Training”和“BelgiumTSC_Testing”。
提示:下载完成(或在完成本教程后下载)后,看看数据的文件夹结构!您会发现测试和训练数据文件夹各包含 61 个子文件夹,这些子文件夹对应本教程中用于分类的 62 种交通标志类型。此外,您会发现文件扩展名为
.ppm(Portable Pixmap Format)。您下载的是交通标志的图像!让我们开始将数据导入工作区。先从用户自定义函数(UDF)
load_data()下方的代码行开始:ROOT_PATH。这是您放置训练与测试数据目录的路径。join()函数将具体路径拼接到ROOT_PATH。将这两个具体路径分别存储到train_data_directory和test_data_directory。load_data()函数,并将train_data_directory传入。load_data()函数本身首先会收集train_data_directory中的所有子目录;它通过列表推导完成,这是构造列表的很自然方式——基本逻辑是:如果在train_data_directory中找到某样东西,就再检查它是否是目录,若是,则将其加入列表。请记住,每个子目录代表一个标签。labels和images。然后,收集这些子目录的路径以及存放于这些子目录中的图像文件名。随后,使用append()将数据加入这两个列表。注意,在上述代码中,训练与测试数据分别位于名为“Training”和“Testing”的文件夹中,二者均是另一个目录“TrafficSigns”的子目录。在本地机器上,可能是类似“/Users/Name/Downloads/TrafficSigns”的路径,下面再有“Training”和“Testing”两个子文件夹。
提示:复习 Python 中如何编写函数,请参阅 DataCamp 的Python 函数教程。
交通标志统计
数据加载完成后,就该做一些数据检查了!您可以先借助
images数组的ndim与size属性来做一个很简单的分析:注意
images和labels变量是列表,因此在您自己的工作区中,可能需要用np.array()将其转换为数组。这里已经替您完成了!注意,您打印出来的
images[0]实际上是一张由数组嵌套数组表示的单张图像!一开始这可能不太直观,但当您在机器学习或深度学习中处理图像时,会逐渐习惯。接下来,您也可以简单看看
labels,不过此时应该不会有太多意外:这些数字已经能让您对导入是否成功以及数据的具体规模有些认识。乍看之下,一切都如预期执行,同时考虑到这里是数组中嵌套数组,您也会发现该数组的规模不小。
提示 试着为数组添加以下属性,以获取更多信息:通过
flags、itemsize和nbytes属性,分别查看内存布局、单个数组元素的字节长度,以及数组元素总共消耗的字节数。您可以在上方的 DataCamp Light 代码块中的 IPython 控制台测试!接下来,您还可以看看交通标志的分布:
干得好!现在让我们更仔细看看您绘制的直方图!
乍看之下,可以发现某些标签在数据集中出现得更频繁:22、32、38 和 61 尤其显眼。此刻先记在心里,下一节会更深入探究!
可视化交通标志
前面的小分析或检查已经让您对所处理的数据有了些概念,但当数据主要由图像组成时,探索数据的首要步骤应是对其进行可视化。
让我们看看一些随机交通标志:
matplotlib包的pyplot模块以别名plt导入。images数组中选择交通标志图像。本例使用300、2250、3650和4000。i对应的特定images数组中的图像。在第一次循环中,将300传给images[],第二次为2250,依此类推。最后,调整子图以保证它们之间有足够的间距。show()函数显示您的图!开始吧:
从该数据集包含的 62 个标签您已猜到,这些标志彼此不同。
但您还注意到了什么?再仔细看看下面的图像:
这四张图像的尺寸并不相同!
您当然可以修改
traffic_signs列表中的数字,更深入地验证这一观察。但不管怎样,这是一个重要发现,等您进一步处理数据以便将其输入神经网络时,需要将此考虑在内。让我们通过打印子图中这些特定图像的形状、最小值和最大值,来验证“尺寸不同”的假设。
下面的代码与上面绘制图像的代码很相似,但不同之处在于,这里您将交替输出尺寸和图像,而不是只把图像并排绘制出来:
注意,您在字符串
"shape: {0}, min: {1}, max: {2}"上使用format()方法来填入您定义的参数{0}、{1}和{2}。在已查看单张图像之后,您或许还想回顾一下在数据探索最初步骤中打印的直方图;您可以很容易地通过绘制 62 个类别的概览图,并为每个类别展示一张对应的图像来实现:
注意,虽然定义了 64 个子图,但并不会全部显示图像(因为只有 62 个标签!)。还要注意,这里同样没有显示坐标轴,以确保读者的注意力不偏离主题:交通标志!
正如您在上面的直方图中大致推测的那样,标签 22、32、38 和 61 的交通标志明显更多。这个假设在该图中得到证实:您可以看到标签 22 有 375 个实例,标签 32 有 316 个,标签 38 有 285 个,最后标签 61 有 282 个。
您此时可能会问的一个更有意思的问题是:这些实例之间是否存在联系——也许它们都是指示性标志?
仔细一看:标签 22 和 32 是禁止标志,而 38 和 61 分别是指示性标志和优先权标志。这意味着这四者之间并无直接联系,除了一个事实:在数据集中占比较高的标志中,有一半属于禁止类。
特征提取
现在您已经充分探索了数据,是时候“撸起袖子”了!先简要回顾一下您发现的内容,以确保在处理时不遗漏任何步骤:
既然明确了需要改进的点,就可以开始以一种适合输入神经网络或其它模型的方式来处理数据。先从提取一些特征开始——您将对图像进行缩放,并将
images数组中的图像转换为灰度图。之所以进行颜色转换,主要是因为在当前这样的分类问题中,颜色影响较小。而在检测任务中,颜色作用很大!因此那种情况下不需要做此转换!图像缩放
为了解决图像尺寸不一致,您要对图像进行缩放;借助
skimage(Scikit-Image)这一图像处理算法集合库即可轻松完成。本例中将用到
transform模块,它提供了resize()函数;您会再次看到我们使用列表推导,将每张图像缩放至 28×28 像素。您再次看到列表的构造方式:对于images数组中的每张图像,都执行来自skimage库的变换操作。最后,将结果存入images28变量:是不是很简单?
注意,图像现在是四维的:如果将
images28转为数组,并连同shape属性一起打印,您会看到images28的维度为(4575, 28, 28, 3)。这些图像是 784 维的(因为每张图像为 28×28 像素)。您可以复用上文用
traffic_signs变量绘制 4 张随机图像的代码来检查缩放结果。只是别忘了将所有对images的引用改为images28。看看结果:
注意,由于进行了缩放,您的
min与max值也发生了变化;它们现在似乎都落在相同的范围内,这很好,因为您就不一定需要再对数据进行归一化了!图像灰度化
正如本节开头所说,在回答分类问题时,图像中的颜色影响较小。这就是为什么您还要进行图像灰度化。
注意,不过,您也可以自行测试,如果不执行这一步,模型的最终结果会如何变化。
就像进行缩放那样,您仍可依赖 Scikit-Image 来帮忙;这次需要使用的是
color模块中的rgb2gray()函数。这将会很轻松!
不过,别忘了先把
images28转回数组,因为rgb2gray()需要数组作为参数。通过绘制部分图像再次检查灰度化的结果;这里您同样可以复用并稍作修改代码,来展示调整后的图像:
注意,确实需要指定颜色映射
cmap为"gray"才能以灰度显示图像。这是因为imshow()默认会使用类似热力图的颜色映射。更多信息请见这里。提示:既然您在本教程中多次复用该功能,可以考虑将其封装成函数 :)
这两步都很基础;您还可以在数据上尝试其他操作,如数据增强(旋转、模糊、平移、改变亮度……)。如果愿意,您也可以搭建一整套数据处理流水线来依次处理图像。
用 TensorFlow 开展深度学习
现在您已探索并处理好数据,接下来就用 TensorFlow 包来构建神经网络架构吧!
构建神经网络模型
就像您在 Keras 中可能做过的一样,接下来要逐层构建神经网络。
若您尚未这样做,请将
tensorflow以常用别名tf导入工作区。然后使用Graph()初始化计算图,用于定义计算。注意,仅有计算图时并不会进行任何计算,因为它不持有任何值。它只定义了您稍后要运行的操作。在这里,您通过
as_default()设置一个默认上下文,它返回一个上下文管理器,将该计算图设为默认图。如果您想在同一进程中创建多个图,可使用该方法:若不显式创建新图,所有操作都会被添加到这个全局默认图中。接下来,您就可以向图中添加操作。回想一下使用 Keras 的经历,您会先构建模型,然后在编译时定义损失函数、优化器和指标。而在使用 TensorFlow 时,这些都会在一个步骤中完成:
run()函数传入的数据集中获得值!flatten()将输入展平,使其形状从[None, 28, 28](灰度图形状)变为[None, 784]的数组。[None, 62]的 logits。logits 是对前一层未缩放输出进行线性理解的函数输入。reduce_mean()封装该函数,对张量各维元素取均值。0.001。您已成功用 TensorFlow 创建了第一个神经网络!
如果愿意,您也可以打印(大部分)变量的值,以便快速回顾或检查刚刚编写的代码:
提示:如果看到类似“
module 'pandas' has no attribute 'computation'”的错误,请尝试在命令行运行pip install --upgrade dask升级dask包。更多信息请见这条 StackOverflow 帖子。运行神经网络
既然您已逐层搭建好模型,接下来就真正运行它!为此,您首先需要使用
Session()初始化会话,并将您在上一节定义的graph传入。然后使用run()运行会话,并将上一节中定义的已初始化操作(init变量)作为参数传入。接下来,使用这个已初始化的会话开始 epoch 或训练循环。本例中选择
201,因为您希望记录最后一个loss_value;在循环中,您通过会话运行训练优化器和在上一节中定义的损失(或准确率)指标。您还传入feed_dict参数,以将数据馈送给模型。每 10 个 epoch,都会打印一条日志,为您提供有关模型损失或成本的更多信息。正如在 TensorFlow 基础部分所见,无需手动关闭会话;这一步会为您完成。不过,如果您想尝试不同的设置,且像下面的代码块一样将会话定义为
sess,则可能需要通过sess.close()手动关闭:请记住,您也可以运行下面这段代码,但它会在结束后立即关闭会话,就像本教程开头所展示的那样:
注意,这里使用
global_variables_initializer(),因为initialize_all_variables()已被弃用。您已经成功训练了模型!并不难,对吧?
评估您的神经网络
您还没完全结束;仍需评估神经网络。在本例中,您可以先随机选取 10 张图像,通过比较预测标签与真实标签,粗略了解模型表现。
您可以先打印出来,但为何不直接使用
matplotlib绘制交通标志本身来进行可视化对比呢?然而,只看随机图像并不能让您深入了解模型实际表现。因此,接下来加载测试数据。
注意,这里复用了您在教程开头定义的
load_data()函数。记得在未使用
with tf.Session() as sess:启动 TensorFlow 会话的情况下,最后用sess.close()关闭会话。接下来做什么?
如果您想继续使用本教程中的数据集和模型,可尝试以下事项:
务必查看由 Nishant Shukla 撰写的Machine Learning With TensorFlow 一书。
提示 也可以体验一下 TensorFlow Playground 和 TensorBoard。
如果您想继续在图像方向深挖,强烈推荐 DataCamp 的scikit-learn 教程,它使用 PCA、K-Means 和支持向量机(SVM)来处理 MNIST 数据集。或查看其它教程,例如这篇同样使用比利时交通标志数据集的教程。