20分钟了解TensorFlow基础

作者 | Chidume Nnamdi ???? 翻译 | linlh、余杭、通夜 编辑 | 王立鱼、约翰逊·李加薪 原文链接: https://blog.bitsrc.io/learn-tensorflow-fundamentals-in-20-minutes-cdef2dec331a

介绍:TensorFlow是一个由Google创建的开源软件库,用于实现机器学习和深度学习系统。

这两个名字包含一系列共同挑战的强大算法 - 使得计算机学习如何自动发现复杂模式和/或做出最佳决策。

TensorFlow:现代化的机器学习库

TensorFlow,由Google在2015年11月面向公众开源,是从创建和使用其前身DistBelief中吸取多年的经验的结果。

它设计为灵活,高效,可扩展,轻便。任何形状和大小的计算机都可以运行它,从智能手机一路支持到大型计算集群。它配备了轻量级的软件,可以即时生成训练好的模型,有效地消除了重新实现模型的麻烦。

TensorFlow包含开源的创新和社区参与,同时也具有大公司的支持,指导和稳定性。

正是因为有着大量的优势,TensorFlow适合个人和企业,从初创公司到大型公司,以及Google。即从2015年11月开源以来,TensorFlow已经成为最为令人兴奋的机器学习库之一。它被越来越多地应用到研究,生产和教育中。

TensorFlow库有着持续的改进,增加和优化,社区的发展也非常迅速。

TensorFlow:名字中包含了什么呢?

张量(Tensor)是在深度学习中最基本的表示数据的方式。简单的说,张量就是多维数组,有着更高维度的二维表格(矩阵)的拓展。

  • 一个张量,简单地说,就是一个n为的矩阵

一般来说,如果你对矩阵数学更熟悉,你可以像矩阵一样考虑张量!

在这篇文章中,我们会讨论,并简单的了解TensorFlow的基础内容:Variables, Sessions, Placeholders等等。同时,我们会展示如何在你的系统上安装TensorFlow。

安装TensorFlow

如果你是刚刚安装了Python(或者是为了学习TensorFlow的目的安装的),你可以从下面的pip安装开始:

pip install tensorflow

但是,这个方法的坏处在于,TensorFlow会覆盖现有的包,并安装特定的版本来满足依赖性。

如果你要使用这个Python来做其他用途的话,这个方法是不可行的。一个常见的做法就是在虚拟环境中安装TensorFlow,通过一个叫做virtualenv的软件实现。这取决于你的环境,你可能不需要在你的机器上安装virtualenv。要安装virtualenv的话,输入:

pip install virtualenv

查看http://virtualenv.pypa.io 获取更多的操作指南。

为了在虚拟环境中安装TensorFlow,你必须要先创建虚拟环境——在这篇文章汇总,我们选在将其放在~/envs目录中,可以随意放在你喜欢的任何地方。

cd ~mkdir envsvirtualenv ~/envs/tensorflow

这会在~/envs目录下创建一个名为TensorFlow的虚拟环境(会展现为~/envs/tensorflow目录的形式)。要启动这个虚拟环境,使用:

source ~/envs/tensorflow/bin/activate

提示会发现变化表明环境已经启动了。

(tensorflow)

在这个使用输入pip的安装命令:

(tensorflow) pip install tensorflow

这样TensorFlow就会安装在虚拟环境中了,而不是影响到已经安装在你电脑中其他软件包了。最后,要退出虚拟环境的话,输入:

(tensorflow) deactivate

这样你就可以回到正常的提示窗口了。

直到最近TensorFlow一直很难与Windows机器一起使用。 但是到了TensorFlow 0.12,Windows上的安装到来了! 它很简单:

pip install tensorflow

上面是CPU的版本,或者是

pip install tensorflow-gpu

GPU的版本(假设你已经有了CUDA 8)

TensorFlow的“HelloWorld”

现在,我们已经安装并设置好了TensorFlow的环境。开始写一个简单的TensorFlow的程序吧,将“Hello”和“World”结合起来,显示出字段——“HelloWorld”。

尽管这看起来非常简单明了,但是这个例子会介绍很多TensorFlow中的核心元素,以及它不同常规Python程序的地方。

首先,我们跑一个简单的安装和版本检测(如果你是使用virtualenv的安装方式,确保你在运行TensorFlow的代码前有激活环境):

/** inst_check.py **/import tensorflow as tfprint(tf.__version__)

上面的代码会在终端上输出TensorFlow的版本信息。运行下面的命令来执行脚本:

python inst_check.py

在终端上会显示出你的TensorFlow版本:

python inst_check.py1.4.0

如果正确的话,输出应该是你安装在系统上的TensorFlow版本信息。版本不匹配是导致问题发生最有可能的原因。

我们完成了检测TensorFlow的版本。接下来实现HelloWorld的例子。下面是完整的代码:

/** helloworld.py **/
import tensorflow as tfh = tf.constant("Hello")w = tf.constant(" World!")hw = h + wwith tf.Session() as sess:   ans = sess.run(hw)   print(ans)

假设你熟悉Python和imports,这里的第一行代码:

import tensorflow as tf

就不需要进行解释了。接下来,我们定义常量(constant)“Hello”和“World!”,然后两个常量拼接起来:

import tensorflow as tfh = tf.constant(“Hello”)w = tf.constant(“ World!”)hw = h + w

到这里,你可能想知道(如果有的话)这与执行此操作的简单Python代码有何不同:

ph = “Hello”pw = “ World!”phw = h + w

关键的地方在于变量hw在两个例子中所包含的东西。我们可以使用print命令来确认下。在纯Python的例子中我们得到:

>print phwHello World!

但是,在TensorFlow的例子中,输出是完全不同的:

>print hwTensor(“add:0”, shape=(), dtype=string)

这可能不是你期待的!

hw = h + w

TensorFlow的代码并没有计算h和w的和,而是将求和运算添加到稍后要完成的计算图中。

接下来,会话(Session)对象作为一个外部TensorFlow计算机制的接口,可以让我们执行这已经定义好的部分的计算图。代码:

ans = sess.run(hw)

这一行实际上计算了hw(按照我们之前定义好的计算h和w的和),下面打印ans显示预期的“hello World!”内容。

到此完成了第一个TensorFlow的例子。运行下面的命令来执行脚本:

python helloworld.py

会话(Session)

按照上面的代码,你应该已经注意到了Session的使用。现在是时候了解下会话是什么了。

会话对象是TensorFlow API的一部分,它在Python对象和我们的数据之间进行通信,以及为我们定义的对象分配内存的实际计算系统,存储中间变量,最后返回结果给我们。

sess = tf.Session()

会话对象的执行部分是由.run()方法完成的。当调用的时候,这个方法按照下面的方式完成一组计算:首先从请求的输出开始,然后从后往前自行,根据一系列的依赖计算必须执行的结点。因此,图的计算部分取决于我们的输出查询。

在我们的例子中,我们请求计算结点f,并得到5的数值作为输出。

outs = sess.run(f)

当我们的计算任务完成,使用sess.close()命令来结束会话是一个好的习惯,确保所有会话使用的资源都被释放了。这是要保持的一个非常重要的习惯,尽管我们没有要求一定要这样做。

sess.close()

关于构造函数的注释

tf.函数可以认为是一个构造函数,但更准确地说,实际上根本不是一个构造函数,而是一个工厂方法,有时不仅仅是创建操作符对象。

计算图的介绍

TensorFlow可以让我们实现机器学习算法,通过创建和计算操作来进行交互。这些交互的形式我们称之为“计算图”,我们可以在上面直观地表示出复杂的功能架构。

对于新了解这个概念的人来说,图形是指一组互连的实体,通常称为节点或顶点。这些节点通过边相连。在数据流图中,边允许数据定向地从一个节点流动到另外一个节点。

在TensorFlow中,每个图的节点表示可能应用于某些输入的操作,并且可以生成传递给其他节点的输出。

图的操作包含了各式各样的函数,从简单的计算,比如减法和乘法到复杂的,等下我们会介绍。还包括更多一般的操作,如创建摘要,生成常量值等。

我们来看看一个简单的例子:

在上面的例子中,我们看到一个基本加法的图。由圆圈表示的函数接收两个输入,图中为两个指向函数的箭头。输出1和4相加的结果:5,图中显示为函数的输出指向。这个结果可以传递给另外的函数,或者是简单的返回给客户。我们也可以看下用一个简单的方程式来表示这个图:

以上说明了在构造计算图时如何使用图,节点和边的两个基本构建块。让我们来看看他们的特性:

  • 节点,通常表示成圆形,椭圆形或者方框,代表某种计算或者行为,或者是图中上下文的数据。在上面的例子中,操作“add”是单独的结点。
  • 边是传递给操作和从操作传递的实际值,通常绘制为箭头。在“add” 的例子中,输入1和2都是通向节点的边,而输出3是通向节点的边。 从概念上讲,我们可以将边视为不同操作之间的链接,因为它们将信息从一个节点传递到下一个节点。

对于这个图还可以继续深入挖掘!根据箭头的指引,数据的传输方向是从左往右,现在从左边开始,把这个图拆解开来。

  1. 起初这两个值从左侧流入图中,即 9 和 5. 它们来自不同的图,从文件中读取或是直接由客户端输入
  2. 每一个初始值都被传输到其中一个显式节点,在图中标记为 a 和 b. “输入”节点只是起到传递值的作用——节点 a 接收值 9 并输出等值到节点c 和 d, 而节点 b 则对值 5 进行相同的操作。
  3. 节点 c 是乘法操作。它接收来自节点 a 和节点 b 的值 9 和 5,并将值 45 输出到节点 e .同时节点 d 对同等的输入值进行加法操作并将结果值 14 输出到节点 e。
  4. 最后,图中的末端节点 e ,是另一个“加法”节点。它接收值 45 和 14 ,并将它们相加,然后输出结果值 59 作为图的最终结果。

以下将上述的图表示成一系列的等式:

如果 a = 5 , b=3 ,想求解 e 的话,只需要将e用 a 和 b 表示出来,并将 a,b 的值代入等式即可

基于此,计算部分完成!下述是值得推敲的概念:

  • “输入”节点的工作机制非常有用,它允许用户将单个输入值中继到后面的节点。否则客户端(或传入初始值的人)必须将每个输入值显式传递给图中的多个节点。 客户端只需要关心第一次传入的值,并且重复使用的任何输入都会被进行抽象,接下来会介绍抽象图。
  • 小考题:首先执行 c 和 d 中的哪一个?还是说其他的节点? 答案是:无法辨别 。从这张图中无法知道首先执行 c 和 d 中的哪一个。 有些人会从左到右和从上到下阅读图表,并简单地假设节点c将首先运行,但重要的是,要注意图表可以很容易地在节点 c 的基础上绘制 d 。 其他人可能会认为这些节点同时运行,但由于各种限制原因,情况并非总是如此。实际上,较好的方式是将它们视为彼此独立运行,因为节点c不依赖于来自节点d的任何信息,所以它不必等待节点 d 以完成其操作;反之也同样成立:节点 d 不需要来自节点c的任何信息。

构建你的一个TensorFlow图

上面的部分已经让我们对下面的图有了一定的了解,这里是关于TensorFlow的代码:

import tensorflow as tfa = tf.constant(9, name=”input_a”)b = tf.constant(5, name=”input_b”)c = tf.mul(a,b, name=”mul_c”)d = tf.add(a,b, name=”add_d”)e = tf.add(c,d, name=”add_e”)

现在我们一行一行地来看。首先,你会注意到导入的声明:

import tensorflow as tf

这句代码没有令人疑惑的地方,导入TensorFlow库并命名为tf。这是按照惯例,因为当我们使用它的各种功能时,更容易输入“tf”而不是一遍又一遍拼写比较长的“tensorflow”!

接下来,我们关注下两个变量的赋值:

a = tf.constant(9, name=”input_a”)b = tf.constant(5, name=”input_b”)

在这里,我们定义“输入”节点,a和b。这两行代码使用了我们的第一个TensorFlow操作:tf.constant()。在TensorFlow中,任何在图中的计算节点称作一个操作(Operation)或者简写为Op。传入一个单一的Tensor值,输出同样的值给直接相连的结点。

为了方便,这个函数帮我们自动将数值常量5和9转换成Tensor对象。我们还传入一个可选的字符串名称参数,可以使用该参数为我们创建的节点提供标识符。

c = tf.mul(a,b, name=”mul_c”)d = tf.add(a,b, name=”add_d”)

这里,我们定义的图的下两个节点,都使用到了之前定义的节点。节点c使用tf.mul Op,接收两个输入,输出是这两个输入的乘积结果。

同样的,节点d使用tf.add,一个输出为两个输入和的操作。我们再次为这两个Ops传递一个名称(这是你会经常看到的)。

注意,我们并不需要自己分别定义图中节点的边,当你在TensorFlow创建一个节点时,你包含了操作计算所有需要的节点了,软件会帮你画这些连接。

e = tf.add(c,d, name=”add_e”)

最后一行定义图的最后一个节点。e使用tf.add,和节点d是类似的。但是这时它的输入是节点c和d,正是像上面描述的图一样。有了这个,我们的第一个,虽然很小的图已经完全定义好了!如果你想要在Python脚本或者shell中执行上面的代码,它完全可以运行了,但实际上它不会做任何事情。

记住——这只是定义的过程。为了简要了解运行图的内容,我们可以在最后添加以下两行以使我们的图输出最终的节点:

sess = tf.Session()sess.run(e)

如何你在交互式的环境中运行,比如Python Shell或者Jupyter/iPython Notebook,你会看到正确的输出:

…>>> sess = tf.Session()>>> sess.run(e)

数据类型

张量有一个数据类型。通过图形的基本数据单位是数值、布尔值或字符串元素。当我们从上一个代码示例中打印出张量对象c时,我们看到它的数据类型是一个浮点数。因为我们没有指定数据的类型,所以TensorFlow自动默认为它。

例如,9被视为整数,而像9.1这样有小数点的任何数都被视为浮点数。

我们可以通过在创建张量对象时指定要处理的数据类型来显式地选择数据类型。通过属性dtype,我们可以看到给定的张量对象被设置了什么类型的数据:

/** data_types.py **/c = tf.constant(9.0, dtype=tf.float64)print(c)print(c.dtype)Out:Tensor(“Const_10:0”, shape=(), dtype=float64)<dtype: ‘float64’>

常量

在TensorFlow中,使用函数constant来创建常量,常量的声明是constant(value, dtype=None, shape=None, name='Const', verify_shape=False),value是一个恒定值将用于进一步计算,dtype是数据类型参数(例如,float32/64, int8/16等等。),shape是可选的尺寸形状,name是一个可选的张量名字,最后一个参数是一个布尔值,表示验证值的形状。

如果你需要在你的训练模型中包含特定值的常量,那么常量对象可以如下例所示:

z = tf.constant(5.2, name="x", dtype=tf.float32)

张量的形状

张量的形状是每个维中的元素个数。在图形构造过程中,TensorFlow自动推断形状。张量的形状,既描述了张量中的维数,也描述了每个维的长度。

张量形状可以是Python列表,也可以是包含有序整数集的元组:列表中的数字和维度一样多,每个数字都描述了对应维度的长度。例如,列表[3,4]描述了长度为3的三维张量在第一个维度的形状,长度为4的三维张量在第二个维度的形状。注意,可以使用元组(())或列表([])定义形状。

让我们来看看更多的例子来进一步说明这一点:

/** tensor_shapes/py **/
# Shapes that specify a 0-D Tensor (scalar) # e.g. any single number: 7, 1, 3, 4, etc.s_0_list = []s_0_tuple = ()# Shape that describes a vector of length 3# e.g. [1, 2, 3]s_1 = [3]# Shape that describes a 3-by-2 matrix# e.g [[1 ,2],# [3, 4],# [5, 6]]s_2 = (3, 2)

我们可以通过传递None作为维度的值来分配一个灵活的长度。将None作为形状传递将告诉TensorFlow允许任何形状的张量。也就是说,一个任意维数任意长度的张量:

# Shape for a vector of any length:s_1_flex = [None]# Shape for a matrix that is any amount of rows tall, and 3 columns wide:s_2_flex = (None, 3)# Shape of a 3-D Tensor with length 2 in its first dimension, and variable-# length in its second and third dimensions:s_3_flex = [2, None, None]# Shape that could be any Tensors_any = None

tf.shape 操作可以用来找到一个张量的形状,如果需要的话。它只需要接收你想要找到形状的张量对象,就能以int32向量的形式返回:

import tensorflow as tf# …create some sort of mystery tensor# Find the shape of the mystery tensorshape = tf.shape(mystery_tensor, name=”mystery_shape”)
  • 张量只是矩阵的超级集合!
  • tf.shape与任何其他操作一样,shape直到在会话中执行时才会运行。

命名

张量对象可以用命名来标识,它是内部字符串。

与 dtype 同理,可以使用 .name 属性来查看对象的命名:

/** names.py **/with tf.Graph().as_default():c1 = tf.constant(4,dtype=tf.float64,name=’c’)c2 = tf.constant(4,dtype=tf.int32,name=’c’)print(c1.name)print(c2.name)
Out:c:0c_1:0

Tensor对象的命名是其对应操作的名称(“c”;与冒号连接),后面是生成它的操作输出中的张量索引 - 可能有多个。

命名范围

在TensorFlow中,可以将大型的复杂图组合在一起,以便易于管理。

节点可以按名称分组,通过使用 tf.name_scope(“前缀”)Op和 with 语句来完成。

/** name_scopes.py **/with tf.Graph().as_default():c1 = tf.constant(4,dtype=tf.float64,name=’c’)with tf.name_scope(“prefix_name”):c2 = tf.constant(4,dtype=tf.int32,name=’c’)c3 = tf.constant(4,dtype=tf.float64,name=’c’)print(c1.name)print(c2.name)print(c3.name)
Out:c:0prefix_name/c:0prefix_name/c_1:0

在示例中,将变量 c2 和 c3 中包含的对象范围 prefix_name 下进行分组,该变量在其名称中为前缀。

前缀用于将图形划分为具有某种语义含义的子图。

Feed 字典

Feed用于临时替换张量值操作的输出,参数 feed_dict 用于覆盖图中的Tensor 值,并且将 Python 字典对象作为输入,字典中的键是会被覆盖的 Tensor 对象的句柄,而值可以是数字、字符串、列表或NumPy数组(如前所述),feed_dict 可用于指定输入值。

小贴士:值必须与Tensor 键具有相同的类型(或能够转换为相同的类型)

下图所示是使用 feed_dic 去重写之前图中的 a 值:

/** feed_dict.py **/import tensorflow as tf# Create Operations, Tensors, etc (using the default graph)a = tf.add(2, 5)b = tf.mul(a, 3)# Start up a `Session` using the default graphsess = tf.Session()# Define a dictionary that says to replace the value of `a` with 15replace_dict = {a: 15}# Run the session, passing in `replace_dict` as the value to `feed_dict`sess.run(b, feed_dict=replace_dict) # returns 45
# Open Sessionsess = tf.Session()# Run the graph, write summary statistics,etc.…# Close the graph, release its resourcessess.close()

变量

Tensorflow 中的特定对象叫做变量。与每次运行 Session 时“重新填充”数据的其他 Tensor 对象不同,它们可以在图中保持固定的状态。

与其他的 Tensor 对象类似,变量也可以作为图中其他操作的输入

变量的使用可通过两步搞定:

  • 调用 tf.Variable() 函数,以创建一个变量并定义其初始值
  • 通过在 session 会话中执行 tf.global_variables_initializer() 方法进行初始化,这会为变量分配内存并设定初始值

与其他的 Tensor 对象同理,变量可在运行模块时进行计算,如下所示:

/** variable.py **/
init_val = tf.random_normal((1,5),0,1)var = tf.Variable(init_val, name=’var’)print(“pre run: \n{}”.format(var))init = tf.global_variables_initializer()with tf.Session() as sess:sess.run(init)post_var = sess.run(var)print(“\npost run: \n{}”.format(post_var))
Out:pre run:Tensor(“var/read:0”, shape=(1, 5), dtype=float32)post run:[[ 0.85962135 0.64885855 0.25370994 -0.37380791 0.63552463]]

值得注意的是,如果再次执行该代码,可看到每次都会生成新的变量,表示形式为变量名称_1 :

pre run:Tensor(“var_1/read:0”, shape=(1, 5), dtype=float32)

小贴士:为了重复使用相同的变量,可使用 tf.get_variables() 函数,而不是 tf.Variable().

占位符

占位符是由 TensorFlow 指定的用于输入值的结构。 也可以认为它们是空变量,稍后将填充数据。它们首先用于构造我们的图形,并且只有在执行时才会使用输入数据。占位符可选 shape 参数。

如果 shape 参数被输入或作为 None 传递,那么可以用任何大小的数据替换占位符:

ph = tf.placeholder(tf.float32,shape=(None,10))

每当定义一个占位符,都必须用传入输入值,否则将抛出异常。

/** placeholders.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 的占位符,即内存中稍后存储值的位置。

然后创建一个Tensor,它是将x乘以2的运算。

注意,还没有为 x 定义初始值。

现在定义了操作(y),可在会话中运行。创建一个会话对象,然后只运行 y 变量。

请注意,这意味着如果定义了更大的操作图,也只能运行图的一小部分。

这个子图评估实际上是 TensorFlow 的一个卖点,非常标新立异。运行 y 需要获取 x 的值,可在 feed_dict 参数中定义以运行。

在这里声明 x 的值是[1,2,3],在运行 y 后,得到结果为 [2,4,6] 。

结论

TensorFlow是一个功能强大的框架,可以轻松地处理数学表达式和多维数组 - 这在机器学习中是必不可少的。

之前已经介绍了TensorFlow的基础知识,之后将开始进入 TensorFlow 的深化阶段。

在随后的教程中,将了解如何利用 TensorFlow 库来解决优化问题并制定预测分析方程式。

还将使用线性回归方程和 Logistic 回归训练模型来解决XOR问题。

感谢阅读,请随时发表评论!

原文发布于微信公众号 - AI研习社(okweiwu)

原文发表时间:2019-05-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券