查看: 103|回复: 0

[等待归档] 教程 | TensorFlow从基础到实战:一步步教你创建交通标志分类神经网络

[复制链接]

23

主题

35

帖子

81

积分

注册会员

Rank: 2

积分
81
QQ
发表于 2017-10-31 15:58:21 | 显示全部楼层 |阅读模式 | 百度 
Martin C. Marti的评分为6--时间:2129-11-14 20:47:12,lian0011的评分为62--时间:2093-01-02 20:32:22。roim的评分为92--时间:2375-09-19 08:51:32!zhccool的评分为25--时间:2378-11-09 23:45:52.梦在朱楼的评分为34--时间:2397-04-26 04:17:02!mrlam的评分为17--时间:2461-05-08 07:35:02,
[size=1em]选自DataCamp

作者:Karlijn Willems

机器之心编译

参与:Panda


TensorFlow 已经成为了现在最流行的深度学习框架,相信很多对人工智能和深度学习有兴趣的人都跃跃欲试。对于初学者来说,TensorFlow 也是一个非常好的选择,它有非常丰富的入门学习资料和庞大的开发者社区。近日,数据科学学习平台 DataCamp 发表了一篇针对 TensorFlow 初学者的教程,从向量和张量的基本概念说起,一步步实现了一个分类交通标志图像的神经网络。机器之心对本教程进行了编译介绍。


深度学习是机器学习的一个子领域,包含了一系列受大脑的结构和功能启发得到的算法。






TensorFlow 是谷歌开发的第二个机器学习框架,可用于设计、构建和训练深度学习模型。你可以使用 TensorFlow 库进行数值计算,这本身似乎并没有什么特别的,但这些计算是使用数据流图完成的。在这些图中,节点表示数学运算,而边则表示数据——通常是多维的数组或张量,在这些边之间传递。


看到了吧?TensorFlow 的名字就源自神经网络在多维数组或张量上执行的这种运算!它本质上就是张量的流。这就是目前你需要了解的关于张量的所有内容,但在接下来的章节中,我们还会更加深入!


这份 TensorFlow 入门教程将会以一种交互式的方式为你呈现如何进行深度学习:



  • 首先你将了解张量。

  • 然后,本教程将简单介绍几种在你的系统上安装 TensorFlow 的方式,以便你能上手练习以及在你的工作空间中加载数据。

  • 之后,你将了解一些 TensorFlow 基础知识:你会看到你可以轻松开始执行一些简单计算。

  • 之后,你将开始进入实际工作:你将加载比利时交通标志数据,然后使用简单的统计和绘图工具对其进行探索。

  • 在你的探索中,你将看到你需要操作数据,以便你能将其馈送给你的模型。所以你需要花时间调整你的图片的大小,并将其转换成灰度图像。

  • 接下来,你终于可以开始做你自己的神经网络模型了!你将一层层地构建起你的模型。

  • 一旦设置好了架构,你就可以使用它来迭代式地训练你的模型,并且最终通过给它馈送一些测试数据来评估它。

  • 最后,你将得到一些用于未来进步的建议指导,以便你了解你能用你刚构建好的模型做什么以及你该如何继续使用 TensorFlow 进行学习。



你也可以在这里下载本教程:https://github.com/Kacawi/datacamp-community/blob/master/TensorFlow%20Tutorial%20For%20Beginners/TensorFlow%20Tutorial%20For%20Beginners.ipynb



另外,你可能也会对下面三个课程感兴趣:



  • Python 深度学习:https://www.datacamp.com/courses/deep-learning-in-python

  • DataCamp 的 Keras 教程:https://www.datacamp.com/community/tutorials/deep-learning-python

  • 使用 R 语言的 Keras 教程:https://www.datacamp.com/community/tutorials/keras-r-deep-learning



介绍张量



为了很好地了解张量,最好先了解一点线性代数和向量计算的知识。你在引言中已经读到了,张量在 TensorFlow 中是作为多维数据数组实现的,但为了完全理解张量及其在机器学习领域的应用,也许还是需要更多一些介绍。


平面向量(plane vector)


在你了解平面向量之前,我们先简单澄清一下「向量」的概念。向量是特殊类型的矩阵(即数字构成的矩形阵列)。因为向量是有序的数字集合,所以它们往往被看作是列矩阵:它们只有一列和一定数量的行。换句话说,你也可以将向量看作是有一个方向的标量。


记住:标量是「5 米」或「60 米/秒」这样的量,而向量则是「向北 5 米」或「向东 60 米/秒」这样的量。这两者之间的不同很显然:向量有一个方向。但是,到目前为止你看到的这些例子与你在机器学习问题中实际操作的向量可能相差很大。这很正常;数学向量的长度是纯数字:是绝对的。而方向则是相对的:它的度量是相对于某个参考方向,并且有弧度或度作单位。你通常假设方向是正的,并且从参考方向按逆时针方向旋转。






当然在视觉上你可以将向量表示成箭头,如上图所示。这意味着你可以将向量看作是有方向和长度的箭头。方向又箭头的头表示,而长度则由箭头的长度表示。
那么什么又是平面向量呢?


平面向量是最简单的张量配置。它们就像是你上面看到的常规向量,唯一的不同是它们处在一个向量空间中。为了更好地理解这一点,让我们从一个例子开始:你有一个 2×1 的向量。也就是说该向量属于一次配对两个数的实数集。或者换句话说,它们是一个二维空间的一部分。在这种情况,你可以使用箭头或射线在坐标 (x,y) 平面表示向量。


从一个标准位置(其中向量的起点为 (0,0))的坐标平面出发,你可以通过查看该向量的第一行来推导 x 坐标,同时你也可以在第二行找到 y 坐标。当然,并不一定总是要维持这种标准位置,向量可以在平面内平行移动而不发生改变。


注:类似地,对于大小为 3×1 的向量,那就是在谈论一个三维空间。你可以将该向量表示成一个三维图形,带有指向其向量速度位置的箭头:它们被画在标准的 x, y 和 z 轴上。


将这些向量表示到坐标平面上是很好的,但本质上,这些向量可以用来执行运算,为了帮助做到这一点,你可以将你的向量表示成基础或单位向量。


单位向量是指幅度为 1 的向量,通常用带有「帽子」的小写字母表示。如果你想将一个二维或三维向量表示成两个或三个正交分量(比如 x 轴、y 轴和 z 轴)的和,单位向量可以非常方便。


而且比如当你考虑将一个向量表示成分量的和时,你会发现你在讨论分量向量,其是两个或三个向量,它们的和即是原来给出的向量。


提示:这个视频用简单的家用物品解释了张量:https://www.youtube.com/watchv=f5liqUk0ZTw



张量


平面向量以及余向量(covector)和线性运算符(linear operator)这三者有一个共同点:它们都是张量的特定案例。你仍然记得前一节中如何将向量特征化为带有一个方向的标量。那么,张量就是一种带有幅度和多个方向的物理实体的一种数学表征。


而且,就向你通过单个数字表示一个标量,3 个数字的序列表示一个三维空间中的向量一样,三维空间中的张量可以通过具有 3R 个数字的数组表示。


这里的 R 表示张量的秩(rank):比如在一个三维空间中,一个第二秩张量(second-rank tensor)可以用 3^2=9 个数字表示。在一个 N 维空间中,标量仍然只需要一个数字,而向量则需要 N 个数字,张量则需要 N^R 个数字。这就是为什么你常会听到人们说标量是 0 秩的张量:因为没有方向,你可以使用一个数字表示它。


记住这一点,就能轻松识别和区分标量、向量和张量了:标量可以用单个数字表示,向量是一个有序的数字集合,张量是一个数字的阵列。


张量的独特之处在于分量和基向量的组合:基向量在参考系之间按一种方式变换,分量也只按这样一种方式变换以保证分量和基向量之间的组合不变。


安装 TensorFlow



现在你对 TensorFlow 已经有了一定程度的了解了,那就让我们开始上手安装这个库吧。这里需要说明一下,TensorFlow 提供了 Python、C++、Haskell、Java、Go、Rust 的 API,另外还有一个用于 R 语言的第三方软件包 tensorflow.


提示:如果你想知道更多 R 语言的深度学习软件包,可以参阅《keras: Deep Learning in R》:https://www.datacamp.com/community/tutorials/keras-r-deep-learning#gs.aLGxTIg


在本教程中,你要下载可以用 Python 编写你的深度学习项目的 TensorFlow 版本。在 TensorFlow 安装页面 https://www.tensorflow.org/install/,你可以看到一些使用 virtualenc、pip、Docker 和 lastly 安装 TensorFlow 的最常见方式和最新说明,当然另外也有其它一些在你的个人计算机上安装 TensorFlow 的方法。


注:如果你用的 Windows,你也可使用 Conda 安装 TensorFlow。但是因为这种安装方式是社区提供支持的,最好还是参考官方的安装说明:https://www.tensorflow.org/install/install_windows



现在你应该已经完成了安装,现在需要再次检查你是否正确安装了 TensorFlow,你可以将其导入到别名 tf 之下的工作空间:

  1. import tensorflow as tf
复制代码


注:在上面的代码中使用的别名 tf 是一种惯例——使用这个别名既能让你与其他在数据科学项目中使用 TensorFlow 的开发者保持一致,也有助于开源 TensorFlow 项目。


TensorFlow 入门:基础知识



你将能写一般的 TensorFlow 程序,你可以将其作为一个块(chunk)运行;当你使用 Python 时,一眼看上去这或许有点矛盾。但是,如果你愿意,你也可以使用 TensorFlow 的 Interactive Session,让你可以对 TensorFlow 进行更交互式的操作。当你习惯了 IPython 时,这会非常方便。


对于这个教程,我们的重点是第二个选项:这将有助于你通过 TensorFlow 上手深度学习。但在你深入之前,先让我们尝试一些轻量级的,之后再进入重量级挑战。


首先,在别名 tf 下导入 tensorflow 库,正如你在前一节看到的那样。然后初始化两个实际上是常量的变量。将一个 4 个数字的数组传递到 constant( ) 函数。


注:你可能也可以传入一个整数,但通常不会这样,你会发现你操作的是数组。正如引言中介绍的那样,张量就是关于数组!所以要确保你传递的是数组。接下来,你可以使用 multiply() 来将你的两个变量相乘。结果存储在 result 变量中。最后,在 print() 函数的帮助下显示 result 结果。






注:你已经在上面的 DataCamp Light 代码块中定义了常量,但你也可以使用另外两种类型的值,即占位符(placeholder)和变量(variable)。占位符是指没有分配的值,在你开始运行该 session 时会被初始化。正如其名,它只是张量的一个占位符,在 session 运行时总是得到馈送。变量是指值可以变化的量。而前面你已经见过的常量的值则不会变化。



这几行代码的结果是计算图中的一个抽象张量。但是可能与你预期的相反,result 实际上没有得到计算;它只是定义了模型,但没有运行进程来计算结果。你可以在显示输出中看到,其中并没有你希望看到的结果(比如 30)。这意味着 TensorFlow 的评估很懒惰!


但是,如果你确实想看到这个结果,你就必须以一种交互式会话的方式运行这段代码。做到这一点的方式有好几个,下面展示了在 DataCamp Light 代码块中的情况:






注:你可以使用以下代码来启动一个交互式 Session,运行 result,并在显示输出 output 之后再次自动关闭 Session。






在上面的代码块中,你刚刚定义了一个默认 Session,但要知道你也可以传递选项。比如说,你可以指定 config 参数,然后使用 ConfigProto 协议缓冲来为你的 session 增加配置选项。


比如说,如果你为你的 Session 增加了 config=tf.ConfigProto(log_device_placement=True),你就可以确保你录入了运算分配到的 GPU 和 CPU 设备。然后你就可以了解在该 session 中每个运算使用了哪个设备。比如当你为设备配置使用软约束时,你也可使用下面的配置 session: config=tf.ConfigProto(allow_soft_placement=True).


现在你已经装好了 TensorFlow,并且将其导入到了你的工作空间,你也了解了操作这个软件包的基础知识。现在是时候调整一下方向,关注一下数据了。就像了解其它事情一样,首先你要花时间探索和更好地了解你的数据,然后才能开始建模你的神经网络。


比利时交通标志:背景



尽管交通是一个通常你们都知道的主题,但不妨也简单了解一下这个数据集中的数据,看你在开始之前是否已经明白了一切。本质上,这一节将让你快速了解你进一步学习本教程所需的领域知识。


当然,因为我是比利时人,所以用了比利时的交通标志数据。这里给出了一些有趣的轶事:



  • 比利时交通标志通常为荷兰语和法语。了解这一点当然不错,但对于你要操作的数据集,这并不重要!

  • 比利时的交通标志分成六大类:警告标志、优先标志、禁令标志、强制性标志、与停车和在路上等待相关的标志、指示牌。

  • 在 2017 年 1 月 1 日,比利时移除了超过 30,000 块交通标志。它们都是与速度相关的优先标志。

  • 谈到移除,在比利时(而且可以扩展到整个欧盟),过多的交通标志一直以来都是一个讨论话题。



加载和探索数据



现在你已经得到了更多一些背景信息,该下载数据了:http://btsd.ethz.ch/shareddata/。你应该下载 BelgiumTS for Classification (cropped images) 右边的两个压缩包: 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 下的所有子目录;为此它借助了一种被称为列表推导式(list comprehension)的方法——这是一种构建列表的自然方法。基本上就是说:如果在 train_data_directory 中发现了一些东西,就双重检查这是否是一个目录;如果是,就将其加入到你的列表中。注意:每个子目录都代表了一个标签。

  • 接下来,你必须循环遍历这些子目录。首先你要初始化两个列表:labels 和 imanges。然后你要收集这些子目录的路径以及存储在这些子目录中的图像的文件名。之后,你可以使用 append() 函数来收集这两个列表中的数据。

  1. def load_data(data_directory):
  2.     directories = [d for d in os.listdir(data_directory)
  3.                    if os.path.isdir(os.path.join(data_directory, d))]
  4.     labels = []
  5.     images = []    for d in directories:
  6.         label_directory = os.path.join(data_directory, d)
  7.         file_names = [os.path.join(label_directory, f)
  8.                       for f in os.listdir(label_directory)
  9.                       if f.endswith(".ppm")]        for f in file_names:
  10.             images.append(skimage.data.imread(f))
  11.             labels.append(int(d))    return images, labels
  12. ROOT_PATH = "/your/root/path"train_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Training")
  13. test_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Testing")
  14. images, labels = load_data(train_data_directory)
复制代码


注意在上面的代码块中,训练数据和测试数据分别位于名为 Training 和 Testing 的文件夹中,这两个文件夹都是另一个目录 TrafficSigns 的子目录。在一个本地机器上,其路径可能是这样的:/Users/yourName/Downloads/TrafficSigns,之后带有两个子文件夹 Training 和 Testing。


交通标志统计数据


加载好你的数据后,就可以做些数据检查(data inspection)了!首先你可以使用 images 数组的 ndim 和 size 属性做一些相当简单的分析:


注意 images 和 labels 变量都是列表,所以你可能需要使用 np.array() 将这些变量转换成你工作空间中的数组。这里已经为你做好了!






注:响应输出的 images[0] 实际上是由数组中的数组表示的单个图像。一开始这可能看起来与直觉相反,但随着你在机器学习或深度学习应用中对图像操作的进一步理解,你会习惯的。


接下来,你也可以简单看看 labels,但现在你应该不会太过惊讶了:






这些数字能让你了解你的导入有多成功以及你的数据的确切大小。大略看看,一切都是按照你预期的方式执行的,而且如果你考虑到你正在处理数组中的数组,那么你会看到数组的大小是相当大的。


提示:试试将以下属性添加到你的数组中,即使用 flags、itemsize 和 nbytes 属性获取关于内存布局(memory layout)、一个数组元素的字节长度和总消耗字节数的更多信息。你可以在上面的 DataCamp Light 块中的 IPython 控制台中测试这些属性!


接下来,你也可以看看这些交通标志数据的分布情况:






干得漂亮!现在让我们仔细看看你做出的直方图!






你可以清楚地看到,所有类型的交通标志都在该数据集中得到了平等地表示。这是后面你开始建模神经网络之前操作你的数据时所需要处理的东西。


大略来看,你可以看到该数据集中有的标签的分量比其它标签更重:标签 22、32、38 和 61 显然出类拔萃。现在记住这一点,在下一节你会更深入地了解!


可视化交通标志数据


前面的小型分析和检查已经让你对这些数据有所了解了,但是当你的数据基本上是由图像构成时,你应该通过可视化的方式来探索你的数据。


我们先来看看一些随机的交通标志:



  • 首先,确保你在常用别名 plt 下导入了 matplotlib 软件包的 pyplot 模块。

  • 然后,你需要创建一个带有 4 个随机数字的列表。这些会被用于从 images 数组中选择你在前一节检查过的交通标志。在这个案例中,你会选择 300、2250、3650 和 4000.

  • 接下来,对于列表长度中的每个元素,即从 0 到 4,你要创建一个没有轴的子图(subplot)(这样它们就不会关注所有东西,而只会单独关注于图像!)。在这些子图中,你将展示与索引 i 中数字相符的 images 数组中的特定图像。在第一次循环中,你会把 300 传递给 images[],在第二轮传递 2250,依此类推。最后你需要调整子图使它们之间具有足够的宽度。

  • 最后使用 show() 函数展示你的图表!



代码如下:

  1. # Import the `pyplot` module of `matplotlib`
  2. import matplotlib.pyplot as plt
  3. # Determine the (random) indexes of the images that you want to see
  4. traffic_signs = [300, 2250, 3650, 4000]
  5. # Fill out the subplots with the random images that you defined
  6. for i in range(len(traffic_signs)):
  7.     plt.subplot(1, 4, i+1)
  8.     plt.axis('off')
  9.     plt.imshow(images[traffic_signs[i]])
  10.     plt.subplots_adjust(wspace=0.5)
  11. plt.show()
复制代码


因为该数据集包含 62 个标签,你大概也猜到了这些交通标志彼此之间存在差异。


但你还注意到了什么?仔细看看下面的图像:






这四张图像的大小不一样!


显然你可以尝试调整包含在 traffic_signs 列表中的数字,并对这个观察进行更全面的跟踪。但实际上,这是一个重要的观察结果——当你开始操作你的数据以便将其输入神经网络时,你会需要将这个观察结果考虑进来。


让我们通过输出包含在这些子图中的特定图像的形状(shape)、最小值和最大值来确认图片大小不同的假设。


下面的代码与前面用来创建上面的图的代码非常相似,但不同的地方在于你将交替大小和图像,而不只是绘制接连的图像。

  1. # Import `matplotlib`import matplotlib.pyplot as plt# Determine the (random) indexes of the imagestraffic_signs = [300, 2250, 3650, 4000]# Fill out the subplots with the random images and add shape,# min and max valuesfor i in range(len(traffic_signs)):
  2.     plt.subplot(1, 4, i+1)
  3.     plt.axis('off')
  4.     plt.imshow(images[traffic_signs[i]])
  5.     plt.subplots_adjust(wspace=0.5)
  6.     plt.show()
  7.     print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape,
  8.                                                   images[traffic_signs[i]].min(),
  9.                                                   images[traffic_signs[i]].max()))
复制代码


注:你如何在 shape: {0}, min: {1}, max: {2} 串上使用 format() 方法来填充你定义的参数 {0}、{1} 和 {2}。






现在你已经看到了松散的图像,你可能还需要再看看你在数据探索的开始阶段输出的直方图:你可以通过绘制所有 62 个类的整体情况以及属于每个类的一张图像来轻松做到这一点。

  1. # Import the `pyplot` module as `plt`import matplotlib.pyplot as plt
  2. # Get the unique labels unique_labels = set(labels)# Initialize the figureplt.figure(figsize=(15, 15))# Set a counteri = 1# For each unique label,for label in unique_labels:    # You pick the first image for each label
  3.     image = images[labels.index(label)]    # Define 64 subplots
  4.     plt.subplot(8, 8, i)        # Don't include axes
  5.     plt.axis('off')        # Add a title to each subplot
  6.     plt.title("Label {0} ({1})".format(label, labels.count(label)))       # Add 1 to the counter
  7.     i += 1
  8.     # And you plot this first image
  9. plt.imshow(image)   
  10. # Show the plotplt.show()
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x


可能是最好的文件格式转换网站
回复
百度搜狗360奇虎

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

快速回复 返回顶部 返回列表