tensorflow入门(一) 计算图、张量、会话的概念

news2024/11/15 15:54:36

1、计算图

计算图是tensorflow中最基本的一个概念,tensorflow中的所有计算都被转化成计算图上的节点。tensorflow的名字已经说明了它最重要的两个概念------tensor和flow。张量这个概念在数学或者物理学中可以有不同的解释,在tensorflow中,张量可以被简单地理解为多维数组。tensorflow的第一个词tensor表明了它的数据结构,那么flow则体现了它的计算模型。flow翻译成中文就是“流”,它直观地表达了张量之间通过计算相互转化的过程,tensorflow这一个通过计算图的形式来表述计算的编程系统。tensorflow中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系。下图展示了两个向量相加样例程序的计算图。

                                                              

上图中每个节点都是一个运算,而每一条边代表了计算之间的依赖关系。如果一个运算的输入依赖于另一个运算的输出,那么这两个运算有依赖关系。a和b这两个常量不依赖任何其他计算,而add计算则依赖读取两个常量的取值。于是在上图中可以看到有一条从a到add的边和一条从b到add的边。在上图中没有任何计算依赖add的结果,于是代表加法的节点add没有任何指向其他节点的边。所有tensorflow的程序都可以通过类似上图的计算图的形式来表示,这就是tensorflow的基本计算模型。

 tensorflow程序一般可以分为两个阶段。在第一个阶段需要定义计算图中所有的计算,第二个阶段为执行计算。以下代码给出了计算定义阶段的样例。

import tensorflow as tf
a = tf.constant([1.0 2.0], name = "a")
b = tf.constant([2.0 3.0], name = "b")
result = a + b

在python中一般采用"import tensorflow as tf"的形式类载入tensorflow,这样可以使用"tf"来代替"tensorflow"作为模块名称,使得整个程序更加简洁。这是tensorflow中非常实用的技巧。在这个过程中,tensorflow会自动将定义的计算转化为计算图上的节点。在tensorflow程序中,系统会自动维护一个默认的计算图,通过tf.get_default_graph函数可以获取当前默认的计算图。以下代码示意了如何获取默认计算图以及如何查看一个运算所属的计算图。

# 通过a.graph可以查看张量所属的计算图。因为没有特意指定,所以这个计算图应等于
# 当前默认的计算图。所以下面这个操作输出值为True。
print(a.graph is tf.get_default_graph())

除了使用默认的计算图,TensorFlow支持通过tf.Graph函数来生成新的计算图。不同计算图上的张量和运算都不会共享。以下的代码示意了如何在不同计算图上定义和使用变量。

import tensorflow as tf

g1 = tf.Graph()
with g1.as_default():
   #在计算图g1中定义变量“v”,并设置初始值为0。
   v = tf.get_variable("v", shape = [1], initializer = tf.zeros_initializer)


g2 = tf.Graph()
with g2.as_default():
   #在计算图g2中定义变量“v”,并设置初始值为1。
   v = tf.get_variable("v", shape = [1], initializer = tf.ones_initializer)

#在计算图g1中读取变量"v"的取值
with tf.Session(graph=g1) as sess:
   tf.initialize_all_variables().run()
   with tf.variable_scope("", reuse=True):
      #在计算图g1中,变量“v”的取值应该为0,所以下面这行会输出[0.]
      print(sess.run(tf.get_variable("v")))

#在计算图g2中读取变量"v"的取值
with tf.Session(graph=g2) as sess:
   tf.initialize_all_variables().run()
   with tf.variable_scope("", reuse=True):
      # 在计算图g2中,变量“v”的取值应该为1,所以下面这行会输出[1.]。
      print(sess.run(tf.get_variable("v")))


Output:
-----
[0.]
[1.]
-----

注:为什么tf.Graph()表示实例化了一个类,一个用于tensorflow计算和表示用的数据流图,通俗来讲:在代码中添加的操作(画中的节点)和数据(画中的线条)都是画在纸上的“画”,而图就是呈现在这些画的纸,你可以利用很多线程生成很多张图,但是默认图就只有一张。tf.Graph().as_default表示将这个类实例,也就是新生成的图作为整个tensorflow 运行环境的默认图,如果只有一个主线程不写也灭有关系,tensorflow里面已经存了一张默认图,可以使用tf.get_default_graph()来调用(显示这张默认纸),当你有多个线程就可以创造多个tf.Graph()。就是你可以有一个图画本,有很多张图纸,这时候就会有一个默认图的概念了。

以上代码产生了两个计算图,每个计算图中定义了一个名字为"v"的变量。在计算图g1中,将"v"初始化为0;在计算图g2中,将v初始化为1。可以看到当运行不同计算图时,变量v的值也是不一样的。tensorflow中的计算图不仅仅可以用来隔离张量和计算,它还提供了管理张量和计算的机制。计算图可以通过tf.Graph.device函数来指定运行计算的设备。这为tensorflow使用GPU提供了机制。

以下程序可以将加法计算跑在GPU上。

g = tf.Graph()
# 指定计算运行的设备
with g.device('/gpu:0'):
   result = a + b

在一个计算图中,可以通过集合(collection)来管理不同类别的资源。比如通过tf.add_to_collection函数可以将资源加入一个或多个集合中,然后通过tf.get_collection获取一个集合里面的所有资源。这里的资源可以是张量、变量或者运行tensorflow程序所需要的队列资源,等等。为了方便实用,tensorflow也自动管理了一些最常用的集合,下面是几个最常用的自动维护的集合。

集合名称集合内容使用场景
tf.GraphKeys.VARIABLES 所有变量  持久化tensorflow模型
tf.GraphKeys.TRAINABLE_VARIABLES可学习的变量(一般指神经网络的参数)模型训练、生成模型可视化的内容
tf.GraphKeys.SUMMARIES日志生成相关的张量tensorflow计算可视化
tf.GraphKeys.GUEUE_RUNNERS    处理输入的GueueRunner输入处理
tf.GraphKeys.MOVING_AVERAGE_VARIABLES所有计算了滑动平均值的变量计算变量的滑动平均值

2、张量

从tensorflow的名字就可以看出来张量(tensor)是一个很重要的概念。在tensorflow程序中,所有的数据都是通过张量的形式来表示。从功能的角度上看,张量可以被简单的理解为多维数组,其中零阶张量表示标量(scalar),也就是一个数;第一阶张量为向量(vector),也就是一个一维数组;第n阶张量可以理解为一个n维数组。但张量在tensorflow中的实现并不是直接采用数组的形式,它只是对tensorflow中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。

以向量加法为例,当运行如下代码时,并不会得到加法的结果,而会得到对结果的一个引用。

import tensorflow as tf
# tf.constant是一个计算,这个计算的结果为一个张量,保存在变量a中。
a = tf.constant([1.0, 2.0], name = "a")
b = tf.constant([2.0, 3.0], name = "b")
result = tf.add(a, b, name = 'add')
print result
'''
输出:
Tensor("add:0", shape = (2,), dtype=float32)
'''

从以上代码可以看出tensorflow中的张量和numpy中的数组不同,tensorflow计算的结果不是一个具体的数字,而是一个张量的结构。从上面的代码的运行结果可以看出,一个张量中主要保存了三个属性:名字(name)、维度(shape)和类型(type)。张量的第一个属性名字不仅是一个张量的标识符,它同样也给出了这个张量是如何计算出来的。tensorflow中所有计算都可以通过计算图的模型来建立,而计算图上的每一个节点代表了一个计算,计算的结果就保存在张量中,所以张量和计算图上节点所代表的计算结果是对应的。

  • 张量的命名就可以通过"node:src_output"的形式来给出。其中node为节点的名称,src_output表示当前张量来自节点的第几个输出。比如上面代码打出来的“add:0”就说明了result这个张量是计算节点"add"输出的第一个结果。
  • 张量的第二个属性是张量的维度(shape)。这个属性描述了一个张量的维度信息。比如上面样例中shape=(2,)说明了张量result是一个一维数组,这个数组的长度为2。
  • 张量的第三个属性是类型(type),每一个张量会有一个唯一的类型。tensorflow会对参与运算的所有张量进行类型的检查,当发现类型不匹配时会报错。

比如运行一下程序时就会得到类型不匹配的错误:

import tensorflow as tf
a = tf.constant([1, 2], name = "a")
b = tf.comstant([2.0, 3.0], name = "b")
result = a + b 

这段程序和上面的样例基本一模一样,唯一不同的是把其中一个加数的小数点去掉了,这会使得加数a的类型为整数而加数b的类型为实数,这样程序会报类型不匹配的错误:

ValueError: Tensor conversion requested dtype int32 for Tensor with dtype
float32: 'Tensor("b:0", shape=(2,), dtype = float32)'

如果将第一个加数指定成实数类型"a = tf.constant([1, 2], name = "a", dtype = tf.float32)",那么两个加数的类型相同就不会报错了。如果不指定类型,tensorflow会给出默认的类型,比如不带小数点的数会被默认为int32,带小数点的默认为float32。因为使用默认类型有可能会导致潜在的类型不匹配,所以一般建议通过指定dtype来明确指出或者常量的类型。tensorflow支持14种不同的类型,主要包括了实数(tf.float32、tf.float64),整数(tf.int8、tf.int16、tf.int64、tf.unit8)、布尔型(tf.bool)和复数(tf.complex64、tf.complex128)。和tensorflow的计算模型相比,tensorflow的数据模型相对比较简单。张量使用主要可以总结为两大类。第一类用途是对中间计算结果的引用。当一个计算包含很多中间结果时,使用张量可以大大提高代码的可读性。以下为使用张量和不使用张量记录中间结果来完成向量相加的功能的代码对比。

import tensorflow as tf

# 使用张量记录中间结果
a = tf.constant([1.0, 2.0], name = "a")
b = tf.constant([2.0, 3.0], name = "b")
result = a + b

# 直接计算向量的和,这样可读性会比较差。
result = tf.constant([1.0, 2.0], name = "a") + tf.constant([2.0, 3.0], name = "b")

从上面的样例程序可以看到,a和b其实就是对常量生成这个运算结果的引用,这样在做加法时就可以直接使用这两个变量,而不需要再去生成这些常量。当计算的复杂度增加时(比如在构建深层神将网络时)通过张量来引用计算的中间结果可以使代码的可阅读性大大提升。同时,通过张量来存储中间的结果可以方便获取中间结果。比如在卷积神经网络中,卷积层或者池化层有可能改变张量的维度,通过result.get_shape函数来获取结果张量的维度信息可以免去人工计算的麻烦。使用张量的第二类情况是当计算图构造完成后,张量可以用来获取计算结果,也就是得到真实的数字。比如在上面的代码中,可以使用tf.Session().run(result)语句得到计算结果。

3、会话

会话拥有并管理tensorflow程序运行时所有的资源。所有计算完成之后需要关闭会话来帮助系统回收资源,否则就可能出现资源泄露的问题。tensorflow中使用会话的模式一般有两种,第一种模式需要明确调用会话生成函数和关闭会话函数,这种模式的代码流程如下:

# 创建一个会话。
sess = tf.Session()

# 使用这个创建好的会话来得到关心的运算结果。比如可以调用sess.run(result).
sess.run(...)

# 关闭会话使得本次运行中使用到的资源可以被释放。
sess.close()

使用这种模式时,在所有计算完成之后,需要明确调用Session.close函数来关闭会话并释放资源。然而,当程序因为异常而退出时,关闭会话的函数可能就不会被执行从而导致资源泄露。为了解决异常退出时资源释放的问题,tensorflow可以通过python的上下文管理器来使用会话。以下代码展示了如何使用这种模式。

# 创建一个会话,并通过python中的上下文管理器来管理这个会话。
with tf.Session() as sess:
     #使用创建好的会话来计算关心的结果
     sess.run(...)
# 不需要再调用"Session.close()"函数来关闭会话
# 当上下文退出时会话关闭和资源释放也自动完成了。

通过python上下文管理器的机制,只有将所有的计算放在"with"的内部就可以。当上下文管理器退出时会自动释放所有资源。这样既解决了因为异常退出时资源释放的问题,同时也解决了忘记调用Session.close函数而产生的资源泄露。

前文介绍过tensorflow会自动生成一个默认的计算图,如果没有特殊指定,运算会自动加入这个计算图中。TensorFlow中的会话也有类似的机制,但tensorflow不会自动生成默认的会话,而是需要手动指定。默认的会话被指定之后可以通过tf.tensor.eval函数来计算一个张量的取值。以下代码展示了通过设定默认会话计算张量的取值。

sess = tf.Session()
with sess.as_default():
   print(result.eval())

以下代码也可以完成相同的功能。

sess = tf.Session()

  # 以下两个命令有相同的功能
  print(sess.run(result))
  print(result.eval(session = sess))

在交互式环境下(比如python脚本或者jupyter的编辑器下),通过设置默认会话的方式来获取张量的取值更加方便。所以tensorflow提供了一种在交互式环境下直接构建默认会话的函数。这个函数就是就是tf.IneractiveSession。使用这个函数会自动生成的会话注册为默认会话。以下代码展示了tf.InteractiveSession函数的用法。

sess = tf.InteractiveSession()
print(result.eval())
sess.close()

 通过tf.InteractiveSession函数可以省去将产生的会话注册为默认会话的过程。无论使用哪种方法都可以通过ConfigProto Protocol Buffer来配置需要生成的会话。下面给出了通过ConfigProto配置会话的方法:

config = tf.ConfigProto(allow_soft_placement = True, log_device_placement = True)
sess1  = tf.InteractiveSession(config = config)
sess2  = tf.Session(config = config)

通过ConfigProto可以配置类似并行的线程数、GPU分配策略、运算超时时间等参数。在这些参数中,最常使用的有两个。

第一个是allow_soft_placement,这是一个布尔型的参数,当它为True时,在以下任意一个条件成立时,GPU上的运算可以放到CPU上进行:

  1. 运算无法在GPU上执行。
  2. 没有GPU资源(比如运算被指定在第二个GPU上运行,但是机器只有一个GPU)。
  3. 运算输入包含对CPU计算结果的引用。

这个参数的默认值为False,但是为了使得代码的可移植性更强,在有GPU的环境下这个参数一般会被设置为True。不同的GPU驱动版本可能对计算的支持有略微的区别,通过将allow_soft_placement参数设置为True,当某些运算无法被当前GPU支持时,可以自动调整到CPU上,而不是报错。类似地,通过将这个参数设置为True,可以让程序在拥有不同数量的GPU机器上顺利运行。

第二个使用得比较多的配置参数是log_device_placement。这也是一个布尔型的参数,当它为True时日志中将会记录每个节点被安排在哪个设备上以方便调试,在生产环境中将这个参数设置为False可以减少日志量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78823.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于tensorflow的深层神经网络(三)如何用tensorflow优化神经网络

1、神经网络优化算法 梯度下降算法主要用户优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法,从而使神经网络模型在训练数据上的损失函数尽可能小。反向传播算法是训练神经网络的核心算法,它可以根据定义…

红黑树的插入过程

一棵红黑树是一种特殊的二叉查找树,具有以下性质: 每个节点要么是红色,要么是黑色。根节点是黑色。每个叶子节点(NIL)是黑色。如果一个节点是红色的,那么它的两个儿子都是黑色的。从任意一个节点到其每个叶…

71.qt quick-可伸展菜单-抽屉栏示例 通用QML界面(一键换肤)

在我们之前章节已经提供过了抽屉栏和菜单伸展栏: 63.qt quick-QML侧边滑动栏(不需要任何图片资源,支持自定义左右方向和大小)_诺谦的博客-CSDN博客_qml侧边栏68.qt quick-qml多级折叠下拉导航菜单 支持动态添加/卸载 支持qml/widget加载等_诺谦的博客-CSDN博客_qml下拉菜单 由…

三维家发生工商变更:注册资本减少46%,美凯龙、阿里等股东退出

近日,云工业软件服务商广东三维家信息科技有限公司(下称“三维家”)发生工商变更,注册资本由16.9254亿元变更为9亿元,同比减少46.83%。同时,包括红星美凯龙、阿里巴巴等多名股东退出,变更时间为…

01.Spring源码整体脉络介绍及源码编译——四

IOC是核心 IOC 容器加载过程【重要】:所有模块都依赖IOC,aop,循环依赖都依赖IOC IOC控制反转,控制理念,来解决层与层之间的耦合。DI注入实现 怎么讲Bean交给IOC容器来管理 配置类xml,注解 加载spring上下…

java计算机毕业设计ssm学院校友信息管理系统的设计与实现5yqhy(附源码、数据库)

java计算机毕业设计ssm学院校友信息管理系统的设计与实现5yqhy(附源码、数据库) 项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts…

【Java基础篇】基础知识易错集锦(二)

我们同样用几道例题来回顾相对应的基础知识; 解析: 首先我呢区分一下实例变量和局部变量; 局部变量:定义在方法内部的变量;实例变量:定义在类中但在任何方法之外,你也可以理解为全局变量&…

16.C预处理器和C库

文章目录C预处理器和C库16.1翻译程序的第一步16.2明示常量:#define16.3在#define中使用参数16.3.1用宏参数创建字符串:#运算符16.3.2预处理器黏合剂:##运算符16.3.3变参宏:...和__VA_ARGS__16.4宏和函数的选择16.5文件包含&#x…

NCTF2022 calc题目复现

calc(环境变量注入getshell) 经典计算器题目,看着有点眼熟,没错,就是buu三月赛的一道题目。由于那时候web可能都算不上入门,所以也就没有复现。比赛时就网上看了看三月赛的wp,但是没有什么用&a…

IEEE 二进制浮点数的表示

今天,我来将 IEEE 二进制浮点数的表示方式进行一个简单的介绍。 浮点数 在 C 语言中,有两种存储浮点数的方式,分别是 float 和 double ,当然了还有long double。这几种浮点型所容纳的长度不同,当然它们存储的精度也就…

[附源码]JAVA毕业设计新型药物临床信息管理系统(系统+LW)

[附源码]JAVA毕业设计新型药物临床信息管理系统(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 …

p5.第一章 Python基础入门 -- 运算符、优先级和表达式 (五)

1.2.3.2.11 False等价 False等价布尔值,相当于bool(value) 空容器 空集合set空字典dict空列表list空元组tuple空字符串None0# bool(value)是布尔函数# In: bool(1), bool(0) # Out: (True

离散数学·支配集、覆盖集、独立集和匹配

支配集 简而言之——V-支配集后剩下的点,都能在支配集中找到相邻的点 支配数的符号是γ0(有关点的集,下标为0) 例 右下角相同颜色的为同一个支配集 要注意极小性 整个V就是支配集(所以说支配集找极大没有意义&#xf…

测试员凡尔赛,工作三年晒出11月工资条,直言加班太累了

最近有工作3年的测试员晒出自己11 月份的工资条,并直言加班太累了。 从工资条上可以看到,这个收入确实不算低,才3年时间,月工资就已经到了二万五了,这个工资已经可以击败绝大多数行业了。 不过二万五只是税前工资&am…

第二证券|系统性稳地产政策加力 租购并举制度加快建立

在房地产职业深度调整期,下一年方针走向备受关注。虽然日前召开的中心政治局会议没提及房地产,可是从其对经济方针的表述能够预见,作为经济支柱产业的房地产职业,下一年将在稳经济中发挥更重要的效果,国家将持续出台系…

[附源码]Python计算机毕业设计SSM基于的装修公司运营管理管理系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

一文彻底搞懂ssh的端口转发

文章目录背景什么是端口转发?本地端口转发本地端口转发的语法场景1场景二ssh -L参数解释ssh 远程端口的安全问题远程端口转发远程端口转发的语法场景一远程端口转发和本地端口转发要在哪台服务器上执行场景二ssh -R 参数解释端口转发的选项端口转发需要修改哪些ssh配…

fastdfs部署详解

fastdfs部署 官方github支持 官方解释:FastDFS 是一个开源的高性能分布式文件系统。它的主要功能包括:文件存储、文件同步和文件访问(文件上传和文件下载),它可以解决高容量和负载均衡问题。FastDFS应该能满足图片分享…

10 款开源工具

1. JIRA 2. Git 3. Jenkins 4. Selenium 5. Groovy 6、Spock 7. Maven 8. Gradle 9. Docker 10. Linux 本文主要介绍Java程序员应该在2019年学习的一些基本和高级工具。如果你是一位经验丰富的Java开发人员,你可能对这些工具很熟悉,但如果不是&…

Java 并发编程<13>-ThreadPoolExecutor的springboot应用

Java 并发编程<13>-ThreadPoolExecutor的springboot应用 Java并发编程<10>安全集合 ...... Java 并发编程<1>-线程实现的方式 线程池简介 a .为什么使用线程池 降低系统资源消耗&#xff0c;通过重用已存在的线程&#xff0c;降低线程创建和销毁造成的消…