tensorflow是什么 线性关系

大多数 Python 库被编写为 Python 的自然扩展形式当你导入一个库时,你得到的是一组变量、函数和类他们扩展并补充了你的代码「工具箱」。当你使用它们时你能预期到返回的結果是怎样的。在我看来当谈及 TensorfFlow 时,应该把这种认知完全抛弃思考什么是 tensorflow是什么 及其如何与其他代码进行交互从根本上来说就是错误嘚。

Python 和 tensorflow是什么 之间的关系可以类比 Javascript 和 HTML 之间的关系Javascript 是一种全功能的编程语言,可以做各种美妙的事情HTML 是用于表示某种类型的实用计算抽潒(此处指可由 Web 浏览器呈现的内容)的框架。Javascript 在交互式网页中的作用是组装浏览器看到的 HTML 对象然后在需要时通过将其更新为新的 HTML 来与其茭互。

与 HTML 类似tensorflow是什么 是用于表示某种类型的计算抽象(称为「计算图」)的框架。但我们用 Python 操作 tensorflow是什么 时我们用 Pyhton 代码做的第一件事就昰构建计算图。一旦完成我们做的第二件事就是与它进行交互(启动 tensorflow是什么 的「会话」)。但重要的是要记住计算图不在变量内部;洏是处在全局命名空间中。正如莎士比亚所说:「所有的 RAM 都是一个阶段所有的变量都仅仅是指针」

第一个关键抽象:计算图

当你在浏览 tensorflow昰什么 文档时,可能会发现对「图形」和「节点」的间接引用如果你仔细阅读,你甚至可能已经发现了这个页面(https://www.tensorflow是什么.org/programmers_guide/graphs)该页面涵蓋了我将以更准确和技术化的方式去解释的内容。本节是一篇高级攻略把握重要的直觉概念,同时忽略一些技术细节

那么:什么是计算图?它本质上是一个全局数据结构:是一个有向图用于捕获有关如何计算的指令。

让我们来看看构建计算图的一个示例在下图中,仩半部分是我们运行的代码及其输出下半部分是生成的计算图。

可见仅仅导入 tensorflow是什么 并不会给我们生成一个有趣的计算图。而只是一個单独的空白的全局变量。但当我们调用一个 tensorflow是什么 操作时会发生什么?

快看!我们得到了一个节点它包含常量 2。很惊讶吧这来洎于一个名为 tf.constant 的函数。当我们打印这个变量时我们看到它返回一个 tf.Tensor 对象,它是一个指向我们刚刚创建的节点的指针为了强调这一点,鉯下是另外一个示例:

每次我们调用 tf.constant 时我们都会在图中创建一个新的节点。即使该节点的功能与现有节点相同即使我们将节点重新分配给同一个变量,或者即使我们根本没有将其分配给一个变量结果都是一样的。

好啦让我们更进一步:

现在我们正谈论—这才是我们嫃正想要的计算图!请注意,+ 操作在 tensorflow是什么 中过载因此同时添加两个张量会在图中增加一个节点,尽管它表面上看起来不像是 tensorflow是什么 操莋

事实证明,并没有计算图只包含计算步骤;不包含结果。至少……现在还没有!

第二个关键抽象: 会话

如果错误地理解 tensorflow是什么 抽象概念也有个「疯狂三月」(NCAA 篮球锦标赛大部分在三月进行),那么会话将成为每年的一号种子选手会话有着那样令人困惑的殊荣是因為其反直觉的命名却又普遍存在—几乎每个 tensorflow是什么 呈现都至少一次明确地调用 tf.Session()。

会话的作用是处理内存分配和优化使我们能够实际执行甴计算图指定的计算。你可以将计算图想象为我们想要执行的计算的「模版」:它列出了所有步骤为了使用计算图,我们需要启动一个會话它使我们能够实际地完成任务;例如,遍历模版的所有节点来分配一堆用于存储计算输出的存储器为了使用 tensorflow是什么 进行各种计算,你既需要计算图也需要会话

会话包含一个指向全局图的指针,该指针通过指向所有节点的指针不断更新这意味着在创建节点之前还昰之后创建会话都无所谓。

创建会话对象后可以使用 sess.run(node) 返回节点的值,并且 tensorflow是什么 将执行确定该值所需的所有计算

一般来说,sess.run() 的调用往往是 tensorflow是什么 最大的瓶颈之一因此调用它的次数越少越好。如果可以的话在一个 sess.run() 的调用中返回多个项目,而不是进行多个调用

迄今为圵,我们所做的计算一直很乏味:没有机会获得输入所以它们总是输出相同的东西。一个更有价值的应用可能涉及构建一个计算图它接受输入,以某种(一致)方式处理它并返回一个输出。

最直接的方法是使用占位符占位符是一种用于接受外部输入的节点。

... 这是一個糟糕的例子因为它引发了一个异常。占位符预计会被赋予一个值但我们没有提供一个值,所以 tensorflow是什么 崩溃了

这就好多了。注意传遞给 feed_dict 的 dict 格式其关键应该是与图中的占位符节点相对应的变量(如前所述,它实际上意味着指向图中占位符节点的指针)相应的值是要汾配给每个占位符的数据元素——通常是标量或 Numpy 数组。

第三个关键抽象:计算路径

让我们看看另一个使用占位符的示例:

为什么第二次调鼡 sess.run() 会失败即使我们没有评估 input_placeholder,为什么仍会引发与 input_placeholder 相关的错误答案在于最终的关键 tensorflow是什么 抽象:计算路径。幸运的是这个抽象非常直觀。

当我们在依赖于图中其他节点的节点上调用 sess.run() 时我们也需要计算那些节点的值。如果这些节点具有依赖关系那么我们需要计算这些徝(依此类推……),直到达到计算图的「顶端」即节点没有父节点时。

所有三个节点都需要进行求值以计算 sum_node 的值最重要的是,这包含了我们未填充的占位符并解释了异常!

根据图结构,我们不需要计算所有节点才能评估我们想要的节点!因为我们在评估 three_node 时不需要评估 placehoolder_node所以运行 sess.run(three_node) 不会引发异常。

tensorflow是什么 仅通过必需的节点自动进行计算这一事实是该框架的一个巨大优势如果计算图非常大并且有许多不必要的节点,那么它可以节省大量调用的运行时间它允许我们构建大型的「多用途」计算图,这些计算图使用单个共享的核心节点集合并根据所采取的不同计算路径去做不同的事情。对于几乎所有应用而言根据所采取的计算路径考虑 sess.run() 的调用是很重要的。

至此我们已經看到两种类型的「无祖先」节点(no-ancestor node):每次运行都一样的 tf.constant 和每次运行都不一样的 tf.placeholder。我们常常要考虑第三种情况:一个通常在运行时保持徝不变的节点也可以被更新为新值

变量对于使用 tensorflow是什么 进行深度学习是至关重要的,因为模型的参数就是变量在训练期间,你希望通過梯度下降在每个步骤更新参数;但在评估时你希望保持参数不变,并将大量不同的测试集输入模型通常,模型所有可训练参数都是變量

要创建变量,就需要使用 tf.get_variable()tf.get_variable() 的前两个参数是必需的,其余参数是可选的它们是 tf.get_variable(name,shape)name 是一个唯一标识这个变量对象的字符串。它必須相对于全局图是唯一的所以要明了你使用过的所有命名,确保没有重复shape 是与张量形状对应的整数数组,它的语法非常直观:按顺序每个维度只有一个整数。例如一个 3x8 矩阵形状是 [3, 8]。要创建一个标量就需要使用形状为 [] 的空列表。

噫另一个异常。当首次创建变量节點时它的值基本上为「null」,并且任何试图对它求值的操作都会引发这个异常我们只能在将值放入变量之后才能对其求值。主要有两种將值放入变量的方法:初始化器和 tf.assign()我们先看看 tf.assign():

恒等运算。tf.assign(target, value) 不做任何有趣的运算通常与 value 相等。副作用当计算「流经」assign_node 时,副作用发苼在图中的其他节点上此时,副作用是用存储在 zero_node 中的值替换 count_variable 的值非依赖边。即使 count_variable 节点和 assign_node 在图中是相连的但它们彼此独立。这意味着計算任一节点时计算不会通过边回流。然而assign_node 依赖于 zero_node,它需要知道分配了什么

「副作用」节点支撑着大部分 tensorflow是什么 深度学习工作流程,所以请确保自己真正理解了在该节点发生的事情当我们调用 sess.run(assign_node) 时,计算路径会通过 assign_node 和 zero_node

当计算流经图中的任何节点时,它还会执行由该節点控制的任何副作用如图中绿色所示。由于 tf.assign 的特殊副作用与 count_variable(之前为「null」)关联的内存现在被永久设置为 0。这意味着当我们下一次調用 sess.run(count_variable) 时不会引发任何异常。相反我们会得到 0 值。成功!

接下来让我们看看初始化器:

那好,这里发生了什么为什么初始化器不工莋?

问题出现在会话和图之间的分离我们已将 get_variable 的 initializer 属性设置为指向 const_init_node,但它只是在图中的节点之间添加了一个新的连接我们还没有做任何解决异常根源的事:与变量节点(存储在会话中,而不是计算图中)相关联的内存仍然设置为「null」我们需要通过会话使 const_init_node 去更新变量。

你鈳能会遇到带有变量共享的 tensorflow是什么 代码其涉及创建作用域并设置「reuse = True」。我强烈建议不要在自己的代码中使用变量共享如果你想在多个哋方使用单个变量,只需以编程方式记录指向该变量节点的指针并在需要时重新使用它。换言之对于想要保存在内存中的每个变量,伱只需要调用一次 tf.get_variable()

最后:进行真正的深度学习!如果你跟上我的节奏,那么其余概念对你来说应该非常简单

在深度学习中,典型的「內循环」训练如下:

2. 根据输入和参数计算「推测」值

4. 根据损失的梯度更新参数

让我们把所有东西放在一个快速脚本里解决简单的线性回歸问题:

就像你看到的一样,损失基本上变为零并且我们对真实参数进行了很好的估计。我希望你只对代码中的以下部分感到陌生:

将┅个节点添加到图中并将一个指针存储在变量 train_op 中。train_op 节点没有输出但是有一个十分复杂的副作用:

train_op 回溯输入和损失的计算路径,寻找变量节点对于它找到的每个变量节点,计算该变量对于损失的梯度然后计算该变量的新值:当前值减去梯度乘以学习率的积。最后它執行赋值操作更新变量的值。

因此基本上当我们调用 sess.run(train_op) 时,它对我们的所有变量做了一个梯度下降的步骤当然,我们也需要使用 feed_dict 填充输叺和输出占位符并且我们还希望打印损失的值,因为这样方便调试

当你用 tensorflow是什么 开始做更复杂的事情时,你需要进行调试一般来说,检查计算图中发生了什么是相当困难的因为你永远无法访问你想打印的值—它们被锁定在 sess.run() 的调用中,所以你不能使用常规的 Python 打印语句具体来说,假设你是想检查一个计算的中间值在调用 sess.run() 之前,中间值还不存在但是,当你调用的 sess.run() 返回时中间值又不见了!

让我们看┅个简单的示例。

这让我们看到了答案是 5但是,如果我们想要检查中间值two_node 和 three_node,怎么办检查中间值的一个方法是向 sess.run() 中添加一个返回参數,该参数指向要检查的每个中间节点然后在返回后,打印它的值

这通常是有用的,但当代码变得越来越复杂时这可能有点棘手。┅个更方便的方法是使用 tf.Print 语句令人困惑的是,tf.Print 实际上是一种具有输出和副作用的 tensorflow是什么 节点!它有两个必需参数:要复制的节点和要打茚的内容列表「要复制的节点」可以是图中的任何节点;tf.Print 是一个与「要复制的节点」相关的恒等操作,意味着输出的是输入的副本但昰,它的副作用是打印出「打印列表」里的所有当前值

有关 tf.Print 一个重要且有点微妙的点:打印是一个副作用。像所有其他副作用一样只偠在计算流经 tf.Print 节点时才会进行打印。如果 tf.Print 节点不在计算路径上则不会打印任何内容。特别的是即使 tf.Print 节点正在复制的原始节点位于计算蕗径上,但 tf.Print 节点本身可能不在请注意这个问题!当这种情况发生时(总会发生的),如果你没有明确地找到问题所在它会让你感到十汾沮丧。一般来说最好在创建要复制的节点后,立即创建你的 tf.Print 节点

希望这篇博文可以帮助你更好地理解什么是 tensorflow是什么,它是如何工作嘚以及怎么使用它总而言之,本文介绍的概念对所有 tensorflow是什么 项目都很重要但只是停留在表面。在你探索 tensorflow是什么 的旅程中你可能会遇箌其他各种你需要的有趣概念:条件、迭代、分布式 tensorflow是什么、变量作用域、保存和加载模型、多图、多会话和多核、数据加载器队列等等。我将在未来的博文中讨论这些主题但如果你使用官方文档、一些代码示例和一点深度学习的魔力来巩固你在本文学到的思想,我相信伱一定可以弄明白 tensorflow是什么!

本文使用tensorflow是什么训练多元线性回歸模型并将其与scikit-learn做比较。数据集来自Andrew Ng的网上公开课程

对于梯度下降算法变量是否标准化很重要。在这个例子中变量一个是面积,一個是房间数量级相差很大,如果不归一化面积在目标函数和梯度中就会占据主导地位,导致收敛极慢

我要回帖

更多关于 tensorflow 的文章

 

随机推荐