🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 一、基础 ## 变量 TensorFlow 是一种表示计算的方式,直到请求时才实际执行。 从这个意义上讲,它是一种延迟计算形式,它能够极大改善代码的运行: + 更快地计算复杂变量 + 跨多个系统的分布式计算,包括 GPU。 + 减少了某些计算中的冗余 我们来看看实际情况。 首先,一个非常基本的 python 脚本: ```py x = 35 y = x + 5 print(y) ``` 这个脚本基本上只是“创建一个值为`35`的变量`x`,将新变量`y`的值设置为它加上`5`,当前为`40`,并将其打印出来”。 运行此程序时将打印出值`40`。 如果你不熟悉 python,请创建一个名为`basic_script.py`的新文本文件,并将该代码复制到该文件中。将其保存在你的计算机上并运行它: ``` python basic_script.py ``` 请注意,路径(即`basic_script.py`)必须指向该文件,因此如果它位于`Code`文件夹中,则使用: ``` python Code/basic_script.py ``` 此外,请确保已激活 Anaconda 虚拟环境。 在 Linux 上,这将使你的提示符看起来像: ``` (tensorenv)username@computername:~$ ``` 如果起作用,让我们将其转换为 TensorFlow 等价形式。 ```py import tensorflow as tf x = tf.constant(35, name='x') y = tf.Variable(x + 5, name='y') print(y) ``` 运行之后,你会得到一个非常有趣的输出,类似于`<tensorflow.python.ops.variables.Variable object at 0x7f074bfd9ef0>`。 这显然不是`40`的值。 原因在于,我们的程序实际上与前一个程序完全不同。 这里的代码执行以下操作: + 导入`tensorflow`模块并将其命名为`tf` + 创建一个名为`x`的常量值,并为其赋值`35` + 创建一个名为`y`的变量,并将其定义为等式`x + 5` + 打印`y`的等式对象 微妙的区别是,`y`没有像我们之前的程序那样,给出`x + 5`的当前值”。 相反,它实际上是一个等式,意思是“当计算这个变量时,取`x`的值(就像那样)并将它加上`5`”。 `y`值的计算在上述程序中从未实际执行。 我们来解决这个问题: ```py import tensorflow as tf x = tf.constant(35, name='x') y = tf.Variable(x + 5, name='y') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) print(session.run(y)) ``` 我们删除了`print(y)`语句,而是创建了一个会话,并实际计算了`y`的值。这里有相当多的样板,但它的工作原理如下: + 导入`tensorflow`模块并将其命名为`tf` + 创建一个名为`x`的常量值,并为其赋值`35` + 创建一个名为`y`的变量,并将其定义为等式`x + 5` + 使用`tf.global_variables_initializer()`初始化变量(我们将在此详细介绍) + 创建用于计算值的会话 + 运行第四步中创建的模型 + 仅运行变量`y`并打印出其当前值 上面的第四步是一些魔术发生的地方。在此步骤中,将创建变量之间的依赖关系的图。在这种情况下,变量`y`取决于变量`x`,并且通过向其添加`5`来转换它的值。请记住,直到第七步才计算该值,在此之前,仅计算等式和关系。 1)常量也可以是数组。预测此代码将执行的操作,然后运行它来确认: ```py import tensorflow as tf x = tf.constant([35, 40, 45], name='x') y = tf.Variable(x + 5, name='y') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) print(session.run(y)) ``` 生成包含 10,000 个随机数的 NumPy 数组(称为`x`),并创建一个存储等式的变量。 ![](https://img.kancloud.cn/10/21/1021516926b4170f79eda66f3b59d7b8_141x20.gif) 你可以使用以下代码生成 NumPy 数组: ```py import numpy as np data = np.random.randint(1000, size=10000) ``` 然后可以使用`data`变量代替上面问题 1 中的列表。 作为一般规则,NumPy 应该用于更大的列表/数字数组,因为它具有比列表更高的内存效率和更快的计算速度。 它还提供了大量的函数(例如计算均值),通常不可用于列表。 3)你还可以在循环更新的变量,稍后我们将这些变量用于机器学习。 看看这段代码,预测它会做什么(然后运行它来检查): ```py import tensorflow as tf x = tf.Variable(0, name='x') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(5): x = x + 1 print(session.run(x)) ``` 4)使用上面(2)和(3)中的代码,创建一个程序,计算以下代码行的“滑动”平均值:`np.random.randint(1000)`。 换句话说,保持循环,并在每个循环中,调用`np.random.randint(1000)`一次,并将当前平均值存储在在每个循环中不断更新变量中。 5)使用 TensorBoard 可视化其中一些示例的图。 要运行 TensorBoard,请使用以下命令:`tensorboard --logdir=path/to/log-directory`。 ```py import tensorflow as tf x = tf.constant(35, name='x') print(x) y = tf.Variable(x + 5, name='y') with tf.Session() as session: merged = tf.summary.merge_all() writer = tf.summary.FileWriter("/tmp/basic", session.graph) model = tf.global_variables_initializer() session.run(model) print(session.run(y)) ``` 要了解 Tensorboard 的更多信息,请访问我们的[可视化课程](http://learningtensorflow.com/Visualisation/)。 ## 数组 在本教程中,我们将处理图像,以便可视化数组的更改。 数组是强大的结构,我们在前面的教程中简要介绍了它。 生成有趣的数组可能很困难,但图像提供了很好的选择。 首先,下载此图像到你的计算机(右键单击,并寻找选项“图片另存为”)。 ![](https://img.kancloud.cn/a7/41/a7418b40a4f21adc2443426c7648ea46_3685x5528.jpg) 此图片来自[维基共享的用户 Uoaei1](https://commons.wikimedia.org/wiki/Main_Page#/media/File:Dactylorhiza_majalis_Spechtensee_01.JPG)。 要处理图像,我们需要`matplotlib`。 我们还需要`pillow`库,它会覆盖已弃用的 PIL 库来处理图像。 你可以使用 Anaconda 的安装方法在你的环境中安装它们: ``` conda install matplotlib pillow ``` 要加载图像,我们使用`matplotlib`的图像模块: ```py import matplotlib.image as mpimg import os # 首先加载图像 dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" # 加载图像 image = mpimg.imread(filename) # 打印它的形状 print(image.shape) ``` 上面的代码将图像作为 NumPy 数组读入,并打印出大小。 请注意,文件名必须是下载的图像文件的完整路径(绝对路径或相对路径)。 你会看到输出,即`(5528, 3685, 3)`。 这意味着图像高 5528 像素,宽 3685 像素,3 种颜色“深”。 你可以使用`pyplot`查看当前图像,如下所示: ```py import matplotlib.pyplot as plt plt.imshow(image) plt.show() ``` 现在我们有了图像,让我们使用 TensorFlow 对它进行一些更改。 ## 几何操作 我们将要执行的第一个转换是转置,将图像逆时针旋转 90 度。 完整的程序如下,其中大部分是你见过的。 ```py import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # 再次加载图像 dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" image = mpimg.imread(filename) # 创建 TF 变量 x = tf.Variable(image, name='x') model = tf.global_variables_initializer() with tf.Session() as session: x = tf.transpose(x, perm=[1, 0, 2]) session.run(model) result = session.run(x) plt.imshow(result) plt.show() ``` 转置操作的结果: ![](https://img.kancloud.cn/df/9c/df9c3048a954df64ab524a79f320cdbe_800x600.png) 新东西是这一行: ```py x = tf.transpose(x, perm=[1, 0, 2]) ``` 该行使用 TensorFlow 的`transpose`方法,使用`perm`参数交换轴 0 和 1(轴 2 保持原样)。 我们将要做的下一个操作是(左右)翻转,将像素从一侧交换到另一侧。 TensorFlow 有一个称为`reverse_sequence`的方法,但签名有点奇怪。 这是文档所说的内容(来自[该页面](https://tensorflow.google.cn/api_docs/python/tf/reverse_sequence)): > ```py > tf.reverse_sequence( > input, > seq_lengths, > seq_axis=None, > batch_axis=None, > name=None, > seq_dim=None, > batch_dim=None > ) > ``` > > 反转可变长度切片。 > > 这个操作首先沿着维度`batch_axis`对`input`却偏,并且对于每个切片`i`,沿着维度`seq_axis`反转第一个`seq_lengths [i]`元素。 > > `seq_lengths`的元素必须满足`seq_lengths [i] <= input.dims [seq_dim]`,而`seq_lengths`必须是长度为`input.dims [batch_dim]`的向量。 > > 然后,输入切片`i`给出了沿维度`batch_axis`的输出切片`i`,其中第一个`seq_lengths [i]`切片沿着维度`seq_axis`被反转。 对于这个函数,最好将其视为: + 根据`batch_dim`迭代数组。 设置`batch_dim = 0`意味着我们遍历行(从上到下)。 + 对于迭代中的每个项目 + 对第二维切片,用`seq_dim`表示。 设置`seq_dim = 1`意味着我们遍历列(从左到右)。 + 迭代中第`n`项的切片由`seq_lengths`中的第`n`项表示 让我们实际看看它: ```py import numpy as np import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # First, load the image again dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" image = mpimg.imread(filename) height, width, depth = image.shape # Create a TensorFlow Variable x = tf.Variable(image, name='x') model = tf.global_variables_initializer() with tf.Session() as session: x = tf.reverse_sequence(x, [width] * height, 1, batch_dim=0) session.run(model) result = session.run(x) print(result.shape) plt.imshow(result) plt.show() ``` 新东西是这一行: ```py x = tf.reverse_sequence(x, np.ones((height,)) * width, 1, batch_dim=0) ``` 它从上到下(沿着它的高度)迭代图像,并从左到右(沿着它的宽度)切片。 从这里开始,它选取大小为`width`的切片,其中`width`是图像的宽度。 > 译者注: > > 还有两个函数用于实现切片操作。一个是[`tf.reverse`](https://tensorflow.google.cn/api_docs/python/tf/manip/reverse),另一个是张量的下标和切片运算符(和 NumPy 用法一样)。 代码`np.ones((height,)) * width`创建一个填充值`width`的 NumPy 数组。 这不是很有效! 不幸的是,在编写本文时,似乎此函数不允许你仅指定单个值。 “翻转”操作的结果: ![](https://img.kancloud.cn/fd/59/fd596f1ccfe182bcbccb07932a47e456_800x600.png) 1)将转置与翻转代码组合来顺时针旋转。 2)目前,翻转代码(使用`reverse_sequence`)需要预先计算宽度。 查看`tf.shape`函数的文档,并使用它在会话中计算`x`变量的宽度。 3)执行“翻转”,从上到下翻转图像。 4)计算“镜像”,复制图像的前半部分,(左右)翻转然后复制到后半部分。 ## 占位符 到目前为止,我们已经使用`Variables`来管理我们的数据,但是有一个更基本的结构,即占位符。 占位符只是一个变量,我们将在以后向它分配数据。 它允许我们创建我们的操作,并构建我们的计算图,而不需要数据。 在 TensorFlow 术语中,我们随后通过这些占位符,将数据提供给图。 ```py import tensorflow as tf x = tf.placeholder("float", None) y = x * 2 with tf.Session() as session: result = session.run(y, feed_dict={x: [1, 2, 3]}) print(result) ``` 这个例子与我们之前的例子略有不同,让我们分解它。 首先,我们正常导入`tensorflow`。然后我们创建一个名为`x`的`placeholder`,即我们稍后将存储值的内存中的位置。 然后,我们创建一个`Tensor`,它是`x`乘以 2 的运算。注意我们还没有为`x`定义任何初始值。 我们现在定义了一个操作(`y`),现在可以在会话中运行它。我们创建一个会话对象,然后只运行`y`变量。请注意,这意味着,如果我们定义了更大的操作图,我们只能运行图的一小部分。这个子图求值实际上是 TensorFlow 的一个卖点,而且许多其他类似的东西都没有。 运行`y`需要了解`x`的值。我们在`feed_dict`参数中定义这些来运行。我们在这里声明`x`的值是`[1,2,3]`。我们运行`y`,给了我们结果`[2,4,6]`。 占位符不需要静态大小。让我们更新我们的程序,让`x`可以接受任何长度。将`x`的定义更改为: ```py x = tf.placeholder("float", None) ``` 现在,当我们在`feed_dict`中定义`x`的值时,我们可以有任意维度的值。 代码应该仍然有效,并给出相同的答案,但现在它也可以处理`feed_dict`中的任意维度的值。 占位符也可以有多个维度,允许存储数组。 在下面的示例中,我们创建一个 3 乘 2 的矩阵,并在其中存储一些数字。 然后,我们使用与以前相同的操作,来逐元素加倍数字。 ```py import tensorflow as tf x = tf.placeholder("float", [None, 3]) y = x * 2 with tf.Session() as session: x_data = [[1, 2, 3], [4, 5, 6],] result = session.run(y, feed_dict={x: x_data}) print(result) ``` 占位符的第一个维度是`None`,这意味着我们可以有任意数量的行。 第二个维度固定为 3,这意味着每行需要有三列数据。 我们可以扩展它来接受任意数量的`None`维度。 在此示例中,我们加载来自上一课的图像,然后创建一个存储该图像切片的占位符。 切片是图像的 2D 片段,但每个“像素”具有三个分量(红色,绿色,蓝色)。 因此,对于前两个维度,我们需要`None`,但是对于最后一个维度,需要 3(或`None`也能用)。 然后,我们使用 TensorFlow 的切片方法从图像中取出一个子片段来操作。 ```py import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # First, load the image again dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" raw_image_data = mpimg.imread(filename) image = tf.placeholder("uint8", [None, None, 3]) slice = tf.slice(image, [1000, 0, 0], [3000, -1, -1]) with tf.Session() as session: result = session.run(slice, feed_dict={image: raw_image_data}) print(result.shape) plt.imshow(result) plt.show() ``` > 译者注:使用下标和切片运算符也可以实现切片。 结果是图像的子片段: ![](https://img.kancloud.cn/56/1c/561c64c0afc5c3e2250302e97b1fba2e_800x600.png) 1)在官方文档中查看 TensorFlow 中的[其他数组函数](https://www.tensorflow.com/versions/master/api_docs/python/array_ops.html#slicing-and-joining)。 2)将图像分成四个“角”,然后再将它拼在一起。 3)将图像转换为灰度。 一种方法是只采用一个颜色通道并显示。 另一种方法是将三个通道的平均值作为灰色。 ## 交互式会话 现在我们有了一些例子,让我们更仔细地看看发生了什么。 正如我们之前已经确定的那样,TensorFlow 允许我们创建操作和变量图。这些变量称为张量,表示数据,无论是单个数字,字符串,矩阵还是其他内容。张量通过操作来组合,整个过程以图来建模。 首先,确保激活了`tensorenv`虚拟环境,一旦激活,请输入`conda install jupyter`来安装`jupter books`。 然后,运行`jupyter notebook`以启动 Jupyter Notebook(以前称为 IPython Notebook)的浏览器会话。 (如果你的浏览器没有打开,请打开它并在浏览器的地址栏中输入`localhost:8888`。) 单击`New`(新建),然后单击`Notebooks`(笔记本)下的`Python 3`(Python 3)。这将启动一个新的浏览器选项卡。通过单击顶部的`Untitled`(无标题)为该笔记本命名,并为其命名(我使用`Interactive TensorFlow`)。 > 如果你以前从未使用过 Jupyter 笔记本(或 IPython 笔记本),请查看[此站点](http://opentechschool.github.io/python-data-intro/core/notebook.html)来获得简介。 接下来,和以前一样,让我们创建一个基本的 TensorFlow 程序。 一个主要的变化是使用`InteractiveSession`,它允许我们运行变量,而不需要经常引用会话对象(减少输入!)。 下面的代码块分为不同的单元格。 如果你看到代码中断,则需要先运行上一个单元格。 此外,如果你不自信,请确保在运行之前将给定块中的所有代码键入单元格。 ```py import tensorflow as tf session = tf.InteractiveSession() x = tf.constant(list(range(10))) ``` 在这段代码中,我们创建了一个`InteractiveSession`,然后定义一个常量值,就像一个占位符,但具有设置的值(不会改变)。 在下一个单元格中,我们可以求解此常量并打印结果。 ```py print(x.eval()) ``` 下面我们关闭打开的会话。 ```py session.close() ``` 关闭会话非常重要,并且很容易忘记。 出于这个原因,我们在之前的教程中使用`with`关键字来处理这个问题。 当`with`块完成执行时,会话将被关闭(如果发生错误也会发生这种情况 - 会话仍然关闭)。 现在让我们来看更大的例子。 在这个例子中,我们将使用一个非常大的矩阵并对其进行计算,跟踪何时使用内存。 首先,让我们看看我们的 Python 会话当前使用了多少内存: ```py import resource print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) ``` 在我的系统上,运行上面的代码之后,使用了 78496 千字节。 现在,创建一个新会话,并定义两个矩阵: ```py import numpy as np session = tf.InteractiveSession() X = tf.constant(np.eye(10000)) Y = tf.constant(np.random.randn(10000, 300)) ``` 让我们再看一下我们的内存使用情况: ```py print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) ``` 在我的系统上,内存使用率跃升至 885,220 Kb - 那些矩阵很大! 现在,让我们使用`matmul`将这些矩阵相乘: ```py Z = tf.matmul(X, Y) ``` 如果我们现在检查我们的内存使用情况,我们发现没有使用更多的内存 - 没有实际的`Z`的计算。 只有当我们求解操作时,我们才真正计算。 对于交互式会话,你可以使用`Z.eval()`,而不是运行`session.run(Z)`。 请注意,你不能总是依赖`.eval()`,因为这是使用“默认”会话的快捷方式,不一定是你要使用的会话。 如果你的计算机比较低级(例如,ram 低于 3Gb),那么不要运行此代码 - 相信我! ```py Z.eval() ``` 你的计算机会考虑很长一段时间,因为现在它才实际执行这些矩阵相乘。 之后检查内存使用情况会发现此计算已经发生,因为它现在使用了接近 3Gb! ```py print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)) ``` 别忘了关闭你的会话! ```py session.close() ``` 注意:我建议使用新的 Jupyter Notebook,因为上面的示例代码可能会被意外再次执行,可能导致计算机崩溃! 1)创建一个整数值的大矩阵(至少 10,000,000)(例如,使用 NumPy 的`randint`函数)。 创建矩阵后检查内存使用情况。 然后,使用 TensorFlow 的`to_float`函数将矩阵转换为浮点值。 再次检查内存使用情况,看到内存使用量增加超过两倍。 “加倍”是由创建矩阵的副本引起的,但是“额外增加”的原因是什么? 执行此实验后,你可以使用此代码显示图像。 ```py from PIL import Image from io import BytesIO # 从字符串读取数据 im = Image.open(BytesIO(result)) im ``` > 提示:确保在每一步之后仔细测量内存使用情况,因为只是导入 TensorFlow 就会使用相当多的内存。 2)使用 TensorFlow 的图像函数将上一个教程中的图像(或其他图像)转换为 JPEG 并记录内存使用情况。 ## 可视化 在本课中,我们将介绍如何使用 TensorBoard 创建和可视化图。 我们在第一课变量中简要地浏览了 TensorBoard 那么什么是 TensorBoard 以及我们为什么要使用它呢? TensorBoard 是一套 Web 应用程序,用于检查和理解你的 TensorFlow 运行和图。 TensorBoard 目前支持五种可视化:标量,图像,音频,直方图和图。 你将在 TensorFlow 中的计算用于训练大型深度神经网络,可能相当复杂且令人困惑,TensorBoard 将使你更容易理解,调试和优化 TensorFlow 程序。 要实际查看 TensorBoard,请单击[此处](https://www.tensorflow.org/get_started/graph_viz)。 这就是 TensorBoard 图的样子: ![](https://img.kancloud.cn/b4/4c/b44c3f0fb83a908a3fdbc1aa3202fd46_960x473.gif) ## 基本的脚本 下面我们有了构建 TensorBoard 图的基本脚本。 现在,如果你在 python 解释器中运行它,会返回 63。 ```py import tensorflow as tf a = tf.add(1, 2,) b = tf.multiply(a, 3) c = tf.add(4, 5,) d = tf.multiply(c, 6,) e = tf.multiply(4, 5,) f = tf.div(c, 6,) g = tf.add(b, d) h = tf.multiply(g, f) with tf.Session() as sess: print(sess.run(h)) ``` 现在我们在代码末尾添加一个`SummaryWriter`,这将在给定目录中创建一个文件夹,其中包含 TensorBoard 用于构建图的信息。 ```py with tf.Session() as sess: writer = tf.summary.FileWriter("output", sess.graph) print(sess.run(h)) writer.close() ``` 如果你现在运行 TensorBoard,使用`tensorboard --logdir=path/to/logs/directory`,你会看到在你给定的目录中,你得到一个名为`output`的文件夹。 如果你在终端中访问 IP 地址,它将带你到 TensorBoard,然后如果你点击图,你将看到你的图。 ![](https://img.kancloud.cn/7f/ff/7fff951c229f8b11c9e141112ee965a9_429x220.png) 在这一点上,图遍布各处,并且相当难以阅读。 因此,请命名一些部分来其更更加可读。 ![](https://img.kancloud.cn/bb/0c/bb0c4085ec1f7389791ee712feacb336_571x351.png) ## 添加名称 在下面的代码中,我们只添加了`parameter`几次。`name=[something]`。 这个`parameter`将接受所选区域并在图形上为其命名。 ```py a = tf.add(1, 2, name="Add_these_numbers") b = tf.multiply(a, 3) c = tf.add(4, 5, name="And_These_ones") d = tf.multiply(c, 6, name="Multiply_these_numbers") e = tf.multiply(4, 5, name="B_add") f = tf.div(c, 6, name="B_mul") g = tf.add(b, d) h = tf.multiply(g, f) ``` 现在,如果你重新运行 python 文件,然后再次运行`tensorboard --logdir=path/to/logs/directory`,你现在将看到,在你命名的特定部分上,你的图有了一些名称。 然而,它仍然非常混乱,如果这是一个巨大的神经网络,它几乎是不可读的。 ![](https://img.kancloud.cn/a6/88/a6881fa6d5aafd550a2e450aaf21e95b_857x494.png) ## 创建作用域 如果我们通过键入`tf.name_scope("MyOperationGroup"):`给图命名:并使用`with tf.name_scope("Scope_A"):`给图这样的作用域,当你重新运行你的 TensorBoard 时,你会看到一些非常不同的东西。 图现在更容易阅读,你可以看到它都在图的标题下,这里是`MyOperationGroup`,然后你有你的作用域`A`和`B`,其中有操作。 ```py # 这里我们定义图的名称,作用域 A,B 和 C。 with tf.name_scope("MyOperationGroup"): with tf.name_scope("Scope_A"): a = tf.add(1, 2, name="Add_these_numbers") b = tf.multiply(a, 3) with tf.name_scope("Scope_B"): c = tf.add(4, 5, name="And_These_ones") d = tf.multiply(c, 6, name="Multiply_these_numbers") with tf.name_scope("Scope_C"): e = tf.multiply(4, 5, name="B_add") f = tf.div(c, 6, name="B_mul") g = tf.add(b, d) h = tf.multiply(g, f) ``` 如你所见,图现在更容易阅读。 ![](https://img.kancloud.cn/f0/6f/f06fbbbda04d77ac16cce66a00a70a37_628x833.png) TensorBoard 具有广泛的功能,其中一些我们将在未来的课程中介绍。 如果你想深入了解,请先观看 [2017 年 TensorFlow 开发者大会的视频](https://www.youtube.com/embed/eBbEDRsCmv4?list=PLOU2XLYxmsIKGc_NBoIhTn2Qhraji53cv)。 在本课中,我们研究了: + TensorBoard 图的基本布局 + 添加摘要编写器来构建 TensorBoard + 将名称添加到 TensorBoard 图 + 将名称和作用域添加到 TensorBoard 有一个很棒的第三方工具叫做 TensorDebugger(TDB),TBD 就像它所谓的调试器一样。 但是与 TensorBoard 中内置的标准调试器不同,TBD 直接与 TensorFlow 图的执行交互,并允许一次执行一个节点。 由于标准 TensorBoard 调试器不能在运行 TensorFlow 图时同时使用,因此必须先写日志文件。 + 从[这里](https://github.com/ericjang/tdb)安装 TBD 并阅读材料(试试 Demo!)。 + 将 TBD 与此梯度下降代码一起使用,绘制一个图表,通过结果显示调试器的工作,并打印预测模型。 (注意:这仅仅与 2.7 兼容) ```py import tensorflow as tf import numpy as np # x 和 y 是我们的训练数据的占位符 x = tf.placeholder("float") y = tf.placeholder("float") # w 是存储我们的值的变量。 它使用“猜测”来初始化 # w[0] 是我们方程中的“a”,w[1] 是“b” w = tf.Variable([1.0, 2.0], name="w") # 我们的模型是 y = a*x + b y_model = tf.multiply(x, w[0]) + w[1] # 我们的误差定义为差异的平方 error = tf.square(y - y_model) # GradientDescentOptimizer 完成繁重的工作 train_op = tf.train.GradientDescentOptimizer(0.01).minimize(error) # TensorFlow 常规 - 初始化值,创建会话并运行模型 model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(1000): x_value = np.random.rand() y_value = x_value * 2 + 6 session.run(train_op, feed_dict={x: x_value, y: y_value}) w_value = session.run(w) print("Predicted model: {a:.3f}x + {b:.3f}".format(a=w_value[0], b=w_value[1])) ``` 这些特殊图标用于常量和摘要节点。 ![](https://img.kancloud.cn/dd/26/dd2673b6462de8ba26e2ba1259597477_754x470.png) ## 读取文件 TensorFlow 支持读取更大的数据集,特别是这样,数据永远不能一次全部保存在内存中(如果有这个限制则不会非常有用)。 你可以使用一些函数和选项,从标准 Python 一直到特定的操作。 TensorFlow 还支持编写自定义数据处理程序,如果你有一个包含大量数据的非常大的项目,这是值得研究的。 编写自定义数据加载是前期的一点努力,但以后可以节省大量时间。 此主题的更多信息,请查看[此处](https://www.tensorflow.org/versions/r0.11/how_tos/new_data_formats/index.html)的官方文档。 在本课程中,我们将介绍使用 TensorFlow 读取 CSV 文件,以及在图中使用数据的基础知识。 ### 占位符 读取数据的最基本方法是使用标准 python 代码读取它。 让我们来看一个基本的例子,从这个 [2016 年奥运会奖牌统计数据](https://pastebin.com/bPBrr46B)中读取数据。 首先,我们创建我们的图,它接受一行数据,并累计总奖牌。 ```py import tensorflow as tf import os dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/olympics2016.csv" features = tf.placeholder(tf.int32, shape=[3], name='features') country = tf.placeholder(tf.string, name='country') total = tf.reduce_sum(features, name='total') ``` 接下来,我将介绍一个名为`Print`的新操作,它打印出图形上某些节点的当前值。 它是一个单位元素,这意味着它将操作作为输入,只返回与输出相同的值。 ```py printerop = tf.Print(total, [country, features, total], name='printer') ``` 当你求解打印操作时会发生什么? 它基本上将当前值记录在第二个参数中(在本例中为列表`[country, features, total]`)并返回第一个值(`total`)。 但它被认为是一个变量,因此我们需要在启动会话时初始化所有变量。 接下来,我们启动会话,然后打开文件来读取。 请注意,文件读取完全是在 python 中完成的 - 我们只是在执行图形的同时读取它。 ```py with tf.Session() as sess: sess.run( tf.global_variables_initializer()) with open(filename) as inf: # 跳过标题 next(inf) for line in inf: # 使用 python 将数据读入我们的特征 country_name, code, gold, silver, bronze, total = line.strip().split(",") gold = int(gold) silver = int(silver) bronze = int(bronze) # 运行打印操作 total = sess.run(printerop, feed_dict={features: [gold, silver, bronze], country:country_name}) print(country_name, total) ``` 在循环的内部部分,我们读取文件的一行,用逗号分割,将值转换为整数,然后将数据作为占位符值提供给`feed_dict`。 如果你不确定这里发生了什么,请查看之前的占位符教程。 当你运行它时,你会在每一行看到两个输出。 第一个输出将是打印操作的结果,看起来有点像这样: ``` I tensorflow/core/kernels/logging_ops.cc:79] [\"France\"][10 18 14][42] ``` 下一个输出将是`print(country_name, total)`行的结果,该行打印当前国家/地区名称(python 变量)和运行打印操作的结果。 由于打印操作是一个单位函数,因此调用它的结果只是求值`total`的结果,这会将金,银和铜的数量相加。 它通常以类似的方式工作得很好。 创建占位符,将一些数据加载到内存中,计算它,然后循环使用新数据。 毕竟,这是占位符的用途。 ### 读取 CSV TensorFlow 支持将数据直接读入张量,但格式有点笨重。 我将通过一种方式逐步完成此操作,但我选择了一种特殊的通用方法,我希望你可以将它用于你自己的项目。 步骤是创建要读取的文件名的队列(列表),然后创建稍后将执行读取的读取器操作。 从这个阅读器操作中,创建在图执行阶段执行时用实际值替换的变量。 让我们来看看该过程的最后几个步骤: ```py def create_file_reader_ops(filename_queue): reader = tf.TextLineReader(skip_header_lines=1) _, csv_row = reader.read(filename_queue) record_defaults = [[""], [""], [0], [0], [0], [0]] country, code, gold, silver, bronze, total = tf.decode_csv(csv_row, record_defaults=record_defaults) features = tf.pack([gold, silver, bronze]) return features, country ``` 这里的读取器在技术上采用队列对象,而不是普通的 Python 列表,所以我们需要在将它传递给函数之前构建一个: ```py filename_queue = tf.train.string_input_producer(filenames, num_epochs=1, shuffle=False) example, country = create_file_reader_ops(filename_queue) ``` 由该函数调用产生的那些操作,稍后将表示来自我们的数据集的单个条目。 运行这些需要比平常更多的工作。 原因是队列本身不像正常操作那样位于图上,因此我们需要一个`Coordinator`来管理队列中的运行。 每次求值示例和标签时,此协调器将在数据集中递增,因为它们有效地从文件中提取数据。 ```py with tf.Session() as sess: tf.global_variables_initializer().run() coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(coord=coord) while True: try: example_data, country_name = sess.run([example, country]) print(example_data, country_name) except tf.errors.OutOfRangeError: break ``` 内部`while`循环保持循环,直到我们遇到`OutOfRangeError`,表明没有更多数据要还原。 有了这段代码,我们现在从数据集中一次得到一行,直接加载到我们的图形中。 还有其他用于创建批量和打乱的功能 - 如果你想了解这些参数的更多信息,请查看`tf.train.string_input_producer`和`tf.train.shuffle_batch`中的一些参数。 在本课中,我们研究了: + 在执行 TensorFlow 图时使用 Python 读取数据 + `tf.Print`操作 + 将数据直接读入 TensorFlow 图/变量 + 队列对象 + 更新第二个示例的代码(直接将文件读入 TensorFlow),使用与 python-version 相同的方式输出总和(即打印出来并使用`tf.Print`) + 在`create_file_reader_ops`中解包特征操作,即不执行`tf.pack`行。 更改代码的其余部分来满足一下情况,特征作为三个单独的特征返回,而不是单个打包的特征。 需要改变什么? + 将数据文件拆分为几个不同的文件(可以使用文本编辑器完成)并更新队列来全部读取它们。 + 使用`tf.train.shuffle_batch`将多行合成一个变量。 这对于较大的数据集比逐行读取更有用。 对于问题4,一个好的目标是在一个批量中加载尽可能多的数据,但不要太多以至于它会使计算机的 RAM 过载。 这对于这个数据集无关紧要,但以后请记住。 另外,使用批量时不会返回所有数据 - 如果批量未满,则不会返回。 ## 迁移到 AWS 在很多情况下,运行代码可能非常耗时,特别是如果你正在运行机器学习或神经网络。除非你在计算机上花费了大量资金,否则转向基于云的服务可能是最好的方法。 在本教程中,我们将采用一些 Tensorflow 代码并将其移至 Amazon Web 服务(AWS)弹性计算云实例(EC2)。 亚马逊网络服务(AWS)是一个安全的云服务平台,提供计算能力,数据库存储,内容交付和其他功能,来帮助企业扩展和发展。此外,亚马逊弹性计算云(Amazon EC2)是一种 Web 服务,可在云中提供可调整大小的计算能力。它旨在使 Web 级云计算对开发人员更轻松。 这样做的好处是,亚马逊拥有大量基于云的服务器,其背后有很多功能。这将允许你在网络上运行代码的时间,只有你能够从本地计算机运行代码的一半。这也意味着如果它是一个需要 5-8 个小时才能完成的大型文件,你可以在 EC2 实例上运行它,并将其保留在后台而不使用你的整个计算机资源。 > 创建一个 EC2 环境会花费你的钱,但它是一个非常少,8 小时可能大约 4.00 美元。 一旦你停止使用它,将不会收取你的费用。请访问[此链接](https://aws.amazon.com/ec2/pricing/)来查看价格。 ### 创建 EC2 实例 首先,访问 [AWS 控制台](https://console.aws.amazon.com/console/home?region=us-east-1)。 使用你的亚马逊帐户登录。如果你没有,则会提示你创建一个,你需要执行此操作才能继续。 接下来,请访问 [EC2 服务控制台](https://console.aws.amazon.com/ec2/v2/home?region=us-east-1)。 单击`Launch Instance`并在右上角的下拉菜单中选择你的地区(例如`sydney, N california`)作为你的位置。 接下来转到社区 AMI 并搜索 Ubuntu x64 AMI 和 TensorFlow(GPU),它已准备好通过 GPU 运行代码,但它也足以在其上运行基本或大型 Tensorflow 脚本,而且优势是 Tensorflow 已安装。 > 此时,将向你收取费用,因此请务必在完成后关闭机器。 你可以转到 EC2 服务,选择机器并停止它。 你不需要为未运行的机器付费。 系统将提示你如何连接到实例的一些信息。 如果你之前未使用过 AWS,则可能需要创建一个新密钥对才能安全地连接到你的实例。 在这种情况下,为你的密钥对命名,下载 pemfile,并将其存储在安全的地方 - 如果丢失,你将无法再次连接到你的实例! 单击“连接”来获取使用 pem 文件连接到实例的信息。 最可能的情况是你将使用以下命令来使用`ssh`: ``` ssh -i <certificante_name>.pem ubuntu@<server_ip_address> ``` ### 将你的代码移动到 AWS EC2 我们将使用以下示例继续我们的 EC2 实例,这来自前面的章节: ```py import tensorflow as tf import numpy as np # x 和 y 是我们的训练数据的占位符 x = tf.placeholder("float") y = tf.placeholder("float") # w 是存储我们的值的变量。 它使用“猜测”来初始化 # w[0] 是我们方程中的“a”,w[1] 是“b” w = tf.Variable([1.0, 2.0], name="w") # 我们的模型是 y = a*x + b y_model = tf.multiply(x, w[0]) + w[1] # 我们的误差定义为差异的平方 error = tf.square(y - y_model) # GradientDescentOptimizer 完成繁重的工作 train_op = tf.train.GradientDescentOptimizer(0.01).minimize(error) # TensorFlow 常规 - 初始化值,创建会话并运行模型 model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(1000): x_value = np.random.rand() y_value = x_value * 2 + 6 session.run(train_op, feed_dict={x: x_value, y: y_value}) w_value = session.run(w) print("Predicted model: {a:.3f}x + {b:.3f}".format(a=w_value[0], b=w_value[1])) ``` 有很多方法可以将此文件放到EC2实例上,但最简单的方法之一就是复制并粘贴内容。 首先,按`Ctrl + A`高亮以上所有代码,然后使用`Ctrl + C`复制所有代码 在 Amazon 虚拟机上,移动到主目录并使用新文件名打开`nano`,我们将在此示例中调用`basic.py `(以下是终端命令): ``` $ cd~/ $ nano <nameofscript>.py ``` `nano`程序将打开,这是一个命令行文本编辑器。 打开此程序后,将剪贴板的内容粘贴到此文件中。 在某些系统上,你可能需要使用`ssh`程序的文件选项,而不是按`Ctrl + V`进行粘贴。 在`nano`中,按`Ctrl + O`将文件保存在磁盘上,我们将其命名为`basic.py`,然后按`Ctrl + X`退出程序。 一旦你退出`nano`,输入`python basic.py`就可以了! 你现在应该看到终端中弹出代码的结果,因为你很可能会发现,这可能是一种执行大型数据程序的更好方法。 Facenet 是一款利用 Tensorflow 的人脸识别程序,它提供了预先训练的模型,供你下载和运行来查看其工作原理。 1)访问此链接并下载预先训练的人脸识别模型 2)使用上面的教程,将代码上传到 EC2 实例并使其运行。