tensorflow-基础知识

tensorflow中,Graph是一个就像一个大容器,OP、Tensor、Variable是这个大容器的组成部件。

Graph管理Tensor对象,Session管理Variable对象。Variable对象必须在Session对象内初始化。初始化所有Variable对象,把.global_variables_initializer() Op传给Session.run()。初始化部分Variable对象,把.variables_initializer() Op传给Session.run()。Variable.assign()Op,修改Variable对象,必须在Session对象中运行。.assign_add()创建自增Op,.assign_sub()创建自减Op。不同Session对象独立维护在Graph对象定义的Variable对象值。Optimizer类自动训练机器学习模型,自动修改Variable对象值。创建Variable对象时trainable参数设False,只允许手工修改值。

1、基本元素

 

1.1 图(Graph)

class tf.Graph

  1. TensorFlow中的计算,表示为一个数据流图,简称“图”
  2. 一个Graph实例就是一个图,由一组Operation对象和Tensor对象构成:每个Operation对象(简记为op)表示最小的计算单元,每个Tensor对象表示在operations间传递的基本数据单元
  3. 如果你没有注册自己的图,系统会提供一个默认图。你可通过调用tf.get_default_graph()显式地访问这个图,也可以不理会这个图,因为调用任一个operation函数时,如调用constant op,c=tf.constant(4.0),一个表示operation的节点会自动添加到这个图上,此时c.graph就指这个默认图。
  4. 如果我们创建了一个Graph实例,并想用它取代上面的默认图,把它指定为一个新的默认图,至少是临时换一下,可以调用该Graph实例的as_default()方法,并得到一个Python中的上下文管理器(context manager),来管理临时默认图的生命周期,即with ...下的代码区域。

为了向默认图添加一个操作,可以简单地调用定义了一个新的 Opertation 的函数:

c = tf.constant(4.0)
assert c.graph is tf.get_default_graph()

另外一个典型的用法包括 Graph.as_default() 这个上下文管理器(context manager)在上下文环境中覆盖了当前的默认图。

g = tf.Graph()
with g.as_default():
# Define operations and tensors in `g`.
  c = tf.constant(30.0)
  assert c.graph is g

重要提示:这个类构建图是非线程安全的。所有的操作应该从单个线程中创建,否则必须提供外部同步。除非明确指明,所有方法都是非线程安全的。

 

1.1.1 Graph的属性

内部属性

    • 与operation相关: 
      • _nodes_by_id:dict( op的id => op ),按id记录所有添加到图上的op
      • _nodes_by_name:dict( op的name => op ),按名字记录所有添加到图上的op
      • _next_id_counter:int,自增器,创建下一个op时用的id
      • _version:int,记录所有op中最大的id
      • _default_original_op:有些op需要附带一个original_op,如replica op需要指出它要对哪个op进行复制
      • _attr_scope_map:dict( name scope => attr ),用于添加一组额外的属性到指定scope中的所有op
      • _op_to_kernel_label_map:dict( op type => kernel label ),kernel可能是指operation中更底层的实现
      • _gradient_override_map:dict( op type => 另一个op type ),把一个含自定义gradient函数的注册op,用在一个已存在的op上
    • 与命名域name scope相关: 
      • _name_stack:字符串,嵌套的各个scopes的名字拼成的栈,用带间隔符”/”的字符串表示
      • _names_in_use: dict( name scope => 使用次数 )
    • 与device相关: 
      • _device_function_stack: list,用来选择device的函数栈,每个元素是一个device_function(op),用来获取op所在device
    • 与控制流相关: 
      • _control_flow_context:一个context对象,表示当前控制流的上下文,如CondContext对象,WhileContext对象,定义在ops/control_flow_ops.py。实际上,控制流也是一个op,用来控制其他op的执行,添加一些条件依赖的关系到图中,使执行某个operation前先查看依赖
      • _control_dependencies_stack:list,一个控制器栈,每个控制器是一个上下文,存有控制依赖信息,表明当执行完依赖中的operations和tensors后,才能执行此上下文中的operations
    • 与feed和fetch相关: 
      • _unfeedable_tensors:set,定义不能feed的tensors
      • _unfetchable_ops:set,定义不能fetch的ops
      • _handle_feeders:dict( tensor handle placeholder => tensor dtype )
      • _handle_readers:dict( tensor handle => 它的read op )
      • _handle_movers:dict( tensor handle => 它的move op )
      • _handle_deleters:dict( tensor handle => 它delete op )
    • 图需要: 
      • _seed:当前图内使用的随机种子
      • _collections:dict( collection name => collection ),相当于图中的一块缓存,每个collection可看成一个list,可以存任何对象
      • _functions:定义图内使用中的一些函数
      • _container:资源容器resource container,用来存储跟踪stateful operations,如:variables,queues
      • _registered_ops:注册的所有操作
    • 程序运行需要: 
      • _finalized:布尔值,真表示Graph属性都已确定,不再做修改
      • _lock:保证读取Graph某些属性(如:_version)时尽可能线程安全
    • TensorFlow框架需要: 
      • _graph_def_version:图定义的版本
    • 其他: 
      • _building_function:该图是否表示一个函数
      • _colocation_stack:保存共位设置(其他op都与指定op共位)的栈

对外属性

  • tf.Graph.version,也就是self._version,记录最新的节点version,即图中最大op id,但是与GraphDef的version无关
  • tf.Graph.graph_def_versions,也就是self._graph_def_versions,GraphDef版本,定义在tensorflow/tensorflow/core/framework/graph.proto
  • tf.Graph.seed,也就是self._seed,此图内使用的随机种子
  • tf.Graph.building_function,也就是self._building_function
  • tf.Graph.finalized,也就是self._finalized,表明组装图阶段是否完成

1.1.2 Graph的主要方法

tf.graph.__init__()

创建一个新的空的图。

 

tf.Graph.as_default()

返回一个使得当前图成为默认图的上下文管理器
这个方法应该在你想要在相同的过程中创建多图时被使用。为了方便,一个全局默认图已经被提供,如果你没有明确创建一个新的图,所有的操作将会被添加进这张图。当你使用这个方法时,请使用 with 关键字明确在接下来的代码块范围内创建的操作应该加进这张图。
默认图是当前线程的一个属性,如果你创建了一个新的线程,并且希望在这个线程里使用默认图,你必须在这个线程的函数里明确添加 with g.as_default():
下面的代码示例(相对于上述解释)是等价的:

# 1. Using Graph.as_default():
g = tf.Graph()
with g.as_default():
  c = tf.constant(5.0)
  assert c.graph is g

# 2. Constructing and making default:
with tf.Graph().as_default() as g:
  c = tf.constant(5.0)
  assert c.graph is g

返回: 一个用于将当前图作为默认图的上下文管理器

 

tf.Graph.as_graph_def(from_version=None, add_shapes=False)

返回一个表示这个图的序列化的 GraphDef。

这个序列化的 GraphDef 可以被引入另一个图(使用 import_graph_def())或者使用 C++ Session API。
这个方法是线程安全的。

参数
from_version: 可选的,如果被设定,将返回一个 GraphDef,它包含仅从这张图的版本属性有了给定值后加入这张图的节点(nodes),表明包括的节点version(即op id)的范围,from_version之前的节点都不要。
add_shapes: 如果是真值,给每个带有输出推断图形的结点添加一个_output_shapes列表属性。(每个节点都要添加输出tensors的形状信息到_output_shapes)
返回: 一个 GraphDef协议缓冲区(protocol buffer)
引起的错误: ValueError: 如果 graph_def 太大

 

tf.Graph.as_graph_element(obj, allow_tensor=True, allow_operation=True)

该获取信息的方法实际上完成了一个验证加转换的工作,给定一个obj,看它能否对应到图中的元素,可以是一个operation,也可以是一个tensor,如果对应,则以operation或tensor的身份返回它自己。该方法可以被多个线程同时调用。 

参数

(1) obj:可以是一个Tensor对象,或一个Operation对象,或tensor名,或operation名,或其他对象;

(2) allow_tensor:真表示obj可以是tensor;

(3) allow_operation:真表示obj可以是operation

 

get系列方法,可被多个线程同时调用:
tf.Graph.get_operation_by_name(name):根据名字获取某个operation
tf.Graph.get_tensor_by_name(name):根据名字获取某个tensor
tf.Graph.get_operations():获取所有operations


判断是否可feed或可fetch
tf.Graph.is_feedable(tensor)
tf.Graph.is_fetchable(tensor_or_op)


设置不可feed或不可fetch
tf.Graph.prevent_feeding(tensor)
tf.Graph.prevent_fetching(op)

 

 

tf.Graph.finalize()

结束这个图,使它只读
在调用g.finalize()后,不能向g添加任何新的操作。当这个图在多线程间共享时,为了保证没有操作添加到这个图,可以调用这个方法,例如当使用一个 QueueRunner时

 

tf.Graph.finalized

如果这个图已经结束,它为真

 

tf.Graph.control_dependencies(control_inputs)

返回一个明确控制依赖(control dependencies)的上下文管理器

使用 with 关键字明确所有在上下文内创建的操作应该在control_inputs上有控制依赖。例如:

with g.control_dependencies([a, b, c]):
# `d` and `e` will only run after `a`, `b`, and `c` have executed.
d = ...
e = ...

control_dependencies()的多重调用可以嵌套,在这种情况下,基于所有活动的上下文中的 control_inputs 的联合,一个新的 Operation 将拥有控制依赖。

with g.control_dependencies([a, b]): # Ops constructed here run after `a` and `b`.
	with g.control_dependencies([c, d]): # Ops constructed here run after `a`, `b`, `c`, and `d`.

你可以通过None来清除控制依赖。

with g.control_dependencies([a, b]): # Ops constructed here run after `a` and `b`.
	with g.control_dependencies(None): # Ops constructed here run normally, not waiting for either `a` or `b`.
with g.control_dependencies([c, d]): # Ops constructed here run after `c` and `d`, also not waiting for either `a` or `b`.

:控制依赖应用于那些在上下文内建立的操作。很少在上下文中使用使用一个 op 或者 tensor 时不添加一个控制依赖。下面的例子解释了这一点:

 

#tf.Graph.control_dependencies(control_inputs)
# 错误代码
def my_func(pred, tensor):
	t = tf.matmul(tensor, tensor)
	with tf.control_dependencies([pred]):
		# 乘法操作(op)没有创建在该上下文,所以没有被加入依赖控制
		return t

# 正确代码
def my_func(pred, tensor):
	with tf.control_dependencies([pred]):
		# 乘法操作(op)创建在该上下文,所以被加入依赖控制中
		#执行完pred之后再执行matmul
		return tf.matmul(tensor, tensor)

 

参数:
control_inputs:一个 Operation 或者 Tensor 对象列表,它上下文内定义的操作被运行前被执行或者计算。也可以为None来清除控制依赖。
返回
一个明确在上下文内所有操作的控制依赖的上下文管理器
引起的错误
TypeError: 如果 control_inputs 不是一个 Operation 或者Tensor 对象的列表。

 

tf.Graph.devide(device_name_or_function)

返回一个明确默认设备的使用的上下文管理器
device_name_or_function 参数可以是一个设备名字符串,一个设备函数或者None:
如果这个参数是一个设备名字符串,所有在此上下文构建的操作将被指派给是这个名称的设备,除非它被一个嵌套的 device() 上下文所覆盖
如果这个参数是函数,它将被视为一个从 Operation 对象到设备名字符串的函数,并且每次一个新的Operation被创建时都会被调用。这个Operation将会被指派给这个带有返回名的设备
如果是None,所有从封闭的上下文调用的device()将会被忽略
想了解关于设备名字符串的合法语法,请在DeviceNameUtils中查阅相关文档

示例:

 

with g.device('/gpu:0'):
	# All operations constructed in this context will be placed
	# on GPU 0.
	with g.device(None):
		# All operations constructed in this context will have no
		# assigned device.

# Defines a function from `Operation` to device string.
def matmul_on_gpu(n):
	if n.type == "MatMul":
		return "/gpu:0"
	else:
		return "/cpu:0"

with g.device(matmul_on_gpu):
	# All operations of type "MatMul" constructed in this context
	# will be placed on GPU 0; all other operations will be placed
	# on CPU 0.

 

:设备范围可能会被op包装器或者其他库代码所覆盖。例如,一个变量指定操作 v.assign()必须被tf.Variable v所托管(colocated),并且不兼容的设备将被忽略。
参数
device_name_or_function:在上下文中使用的设备名或函数
返回值
一个为新创建的操作明确默认设备的上下文管理器

 

tf.Graph.name_scope(name)

返回为操作创建分层的上下文管理器
一张图维持一个命名空间栈,在当前上下文生命期,一个 with name_scope(…):声明将一个新的名称压栈。
name参数将解释如下
一个字符串(没有以’/’结尾)将创建一个新的命名空间,在此空间name会附加到所有在上下文里创建的操作的前缀。如果name之前被用过,可以通过调用self.unique_name(name)使它变为独特的name
一个从之前a with g.name_scope(…) as scope: 声明捕获的空间将被视为一个绝对命名空间,这使得它有可能代表现有的空间
一个None值或者空字符串将会重置当前命名空间到最高层(空的)命名空间
示例:

# tf.Graph.name_scope(name)
# 一个图中包含有一个名称范围的堆栈,在使用name_scope(...)之后,将压(push)新名称进栈中,
#并在下文中使用该名称
with tf.Graph().as_default() as g:
	c = tf.constant(5.0, name="c")
	assert c.op.name == "c"
	c_1 = tf.constant(6.0, name="c")
	assert c_1.op.name == "c_1"

	# Creates a scope called "nested"
	with g.name_scope("nested") as scope:
		nested_c = tf.constant(10.0, name="c")
		assert nested_c.op.name == "nested/c"

		# Creates a nested scope called "inner".
		with g.name_scope("inner"):
			nested_inner_c = tf.constant(20.0, name="c")
			assert nested_inner_c.op.name == "nested/inner/c"

		# Create a nested scope called "inner_1".
		with g.name_scope("inner"):
			nested_inner_1_c = tf.constant(30.0, name="c")
			assert nested_inner_1_c.op.name == "nested/inner_1/c"

			# Treats `scope` as an absolute name scope, and
			# switches to the "nested/" scope.
			with g.name_scope(scope):
				nested_d = tf.constant(40.0, name="d")
				assert nested_d.op.name == "nested/d"

				with g.name_scope(""):
					e = tf.constant(50.0, name="e")
					assert e.op.name == "e"

空间本身的命名可以被with g.name_scope(…) as scope:所捕获,它在变量空间内存有空间的命名。这个结果可以在一个空间内命名代表执行操作的所有结果的操作(This value can be used to name an operation that represents the overall result of executing the ops in a scope)。

参数:
name: 一个空间的命名
返回:
一个设置(install)name为新的命名空间的上下文管理器
一张图实例支持任意多个被命名标志的“集合”,为了方便,当建立一个很大的图时。集合能存储一组相关的对象。例如,tf.Variable为所有在图建立期间创建的变量使用一个集合(名为tf.GraphKeys.VARIABLES)。调用者可以通过指定一个新的命名来定义额外的集合。

 

tf.Graph.add_to_collection(name,value)

将value值存入给定name的collection
注意collections不是sets,所以有可能将同一个值多次加入一个collection。
参数:
names: collection的关键字(key)。 GraphKeys类包含许多标准集合名称
value:加入collection的值

 

tf.Graph.add_to_collections(names,value)

将value存入给定的names的collections中
注意collections不是sets,所以有可能将同一个值多次加入一个collection。这个函数保证忽略names中的重复值,但不会检查names中任意一个collection的value里已存在的成员。(This function makes sure that duplicates in names are ignored, but it will not check for pre-existing membership of value in any of the collections in names.)
names可以是可迭代的,但是如果它是个字符串,它将被视为一个单集合名
参数:
names: 要加入的collections的关键字(keys)。GraphKeys类包含许多标准集合名称
value:加入collections的值

 

tf.Graph.get_collection(name,scope=None)

返回给定名称集合的值的列表
这个方法不同于get_collection_ref(),后者总是返回真正的集合(如果存在),因此每次被调用时,它总是返回一个新的列表。(This is different from get_collection_ref() which always returns the actual collection list if it exists in that it returns a new list each time it is called.)
参数
name:集合的关键字。例如 GraphKeys类含有许多类的标准命名
scope:(可选)如果提供了,结果过滤列表仅包含那些没有名称属性总不返回,名称(name)属性匹配使用re.match得到的条目。如果一个 空间(scope)被提供,那么choice或者re.match意味着一个没有特殊前缀标记过滤器的空间。
返回:
给定名称的集合中值的列表,或者空表(当没有值加入集合)。这个列表包含一些按顺序的值,在这个顺序下它们被收集。

 

1.2 占位符(placeholder)

tf.placeholder(dtype, shape=None, name=None)

此函数可以理解为形参,用于定义过程,在执行的时候再赋具体的值。

参数:

  • dtype:数据类型。常用的是tf.float32,tf.float64等数值类型
  • shape:数据形状。默认是None,就是一维值,也可以是多维,比如[2,3], [None, 3]表示列是3,行不定
  • name:名称。

 

1.3 常量(constant)

 

1.3.1 Constant Value Tensors

tensorflow基本的数据类型有14种,在这几本数据类型上,给与了3种主要的包装类型,分别是Constants value tensors,Sequence和Random Tensors。

 

数据类型 Python 类型 描述
DT_FLOAT tf.float32 32 位浮点数.
DT_DOUBLE tf.float64 64 位浮点数.
DT_INT64 tf.int64 64 位有符号整型.
DT_INT32 tf.int32 32 位有符号整型.
DT_INT16 tf.int16 16 位有符号整型.
DT_INT8 tf.int8 8 位有符号整型.
DT_UINT8 tf.uint8 8 位无符号整型.
DT_STRING tf.string 可变长度的字节数组.每一个张量元素都是一个字节数组.
DT_BOOL tf.bool 布尔型.
DT_COMPLEX64 tf.complex64 由两个32位浮点数组成的复数:实数和虚数.
DT_QINT32 tf.qint32 用于量化Ops的32位有符号整型.
DT_QINT8 tf.qint8 用于量化Ops的8位有符号整型.
DT_QUINT8 tf.quint8 用于量化Ops的8位无符号整型.

tf.constant(value,dtype = None,shape = None,name = "Constant")
这是最基础的一个,参数种dtype建议增加,若不增加,tensorflow会默认加一个,程序可能会有bug,shape对value进行一次形状变化,需要传入一个python列表;name为图中保存的名字。
示例:
a =tf.constant(np.arange(10),dtype = tf.float32,shape = [2,5],name = "constant")

 

tf.zeros(shape,dtype = tf.float32,name = None)

tf.ones(shape,dtype = tf.float32,name = None)
这两个函数差不多,一个生成全为0的常量,一个生成全为1的常量,默认的格式tf.float32.

 

tf.zeros_like(tensor,dtype=None,name = None)

tf.ones_like(tensor,dtype=None,name = None)
这俩函数基本一样,需要传入一个tensor,导出一个同结构全0/1的tensor,数据类型可能变化。

 

tf.fill(dims,value,name = None)

dims的参数其实和shape是一样的,这个函数生成了一个以dims(列表)为结构,value为值的一个tensor。

1.3.2 Sequences

生成一维tensor,主要由两个函数,分别是linspace 和 range,用法有稍微的区别。


tf.linspace(start,stop,num,name = None )
生成一个一维tensor,以start为开始,以stop为结束,这两个数都必须是float,num为总个数(int)。 print(tf.linspace(0.0,10.0,11).eval()) 结果为 [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]


tf.range(start,limit,delta = 1,name = "range")
生成一个一维tensor,以start为开始,最大不超过limit,间隔为delta。建议使用整数,浮点数可能会出现精度问题。

1.3.3 Random Tensors

生成常用的多维随机数。包括几个生成器和一个种子设置方法。
tf.random_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)
tf.truncated_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)
这两函数都是生成正态随机数,区别是truncated在生成随机数后,如果随机数在两倍标准差之外,就重新生成一个,直到生成最终结果。参数中shape为一个列表,表示形状,mean和stddev分别标书均值和标准差,seed为随机数种子。和其他python随机语法一样,固定seed以后,生成的随机数将不变。


tf.random.uniform(shape,minval = 0.0,maxval = 1.0,dtype = tf.float32,seed = None)
这个函数生成从0到1中平均分布的数值。


tf.random_shuffle(value,seed = None,name = None)
传入一个tensor,然后将这个rensor进行随机洗牌。

1.4 变量(variable)

当训练模型时,用变量来存储和更新参数。变量包含张量 (Tensor)存放于内存的缓存区。建模时它们需要被明确地初始化,模型训练后它们必须被存储到磁盘。这些变量的值可在之后模型训练和分析时被加载。

当创建一个变量时,你将一个张量作为初始值传入构造函数Variable()。 TensorFlow提供了一系列操作符来初始化张量,初始值是常量或是随机值。在初始化时需要指定张量的shape,变量的shape通常是固定的,但TensorFlow提供了高级的机制来重新调整。

Tensor、Op对象不可变(immutable)。.Variable()构造方法创建Variable对象,包含Session.run()调用中可持久化的可变张量值。

我们通过tf.Variable构造一个variable添加进图中,Variable()构造函数需要变量的初始值(是一个任意类型、任意形状的tensor),这个初始值指定variable的类型和形状。通过Variable()构造函数后,此variable的类型和形状固定不能修改了,但值可以用assign方法修改。

如果想修改variable的shape,可以使用一个assign op,令validate_shape=False.

通过Variable()生成的variables就是一个tensor,可以作为graph中其他op的输入。另外,Tensor类重载的所有操作符都被转载到此variables中,所以可以通过对变量调用方法,将节点添加到图形中。

1.4.1 新建与初始化

 

tf.Variable

tf.Variable.__init__(initial_value=None, trainable=True, collections=None, validate_shape=True, caching_device=None, name=None, variable_def=None, dtype=None)

新变量添加到collections 列出的图集合中,默认添加到 [GraphKeys.VARIABLES]。

如果 trainable 是True,变量也添加到图集合 GraphKeys.TRAINABLE_VARIABLES.

这个构造器创建了两个操作节点,一个变量操作和一个赋值操作,用于将初始值赋给变量。

  • initial_value:  一个Tensor,或者可以转化为Tensor的Python对象,这是变量的初始值,可以传入数值,列表,numpy数组,tf的tensor等。初始值必须指定shape除非validate_shape 被设置为False。但是对一个变量来说,最好使用固定结构的变量。
  • trainable:  如果是True,变量也默认添加到GraphKeys.TRAINABLE_VARIABLES,collections默认添加到图的[GraphKeys.VARIABLES] 中。这是很多优化器类使用的默认变量列表。

在tf.Variables的类中有add,sub,dtype、name,get_shape()等属性和方法

Variable() 构造器需要一个初始值,可以是任意类型和shape 的Tensor。初始值定义了变量的type和shape。构造完成之后,变量的type和shape 是固定的。可以使用assign 方法来修改变量的值。

如果你想修改变量的shape,你必须使用assign 操作,并且 validate_shpe=False。

 

初始化器

tf.variables_initilizer(var_list,name = "nint")

tf.global_variables_initializer()

前者对指定的一个变量列表进行初始化,后者则对所有的变量进行初始化。

注意:这里的初始化只是在计算图中定义了这样的一个节点,这个节点的运算是将变量进行初始化,所以在实际计算中,还是要调用sess.run(initializer),才能真正的完成初始化过程。

 

查询变量

tf.gloable_variables()

显示图中所有的变量。

tf.trainable_variables()

显示图中可训练的变量。

 

初始值生成函数

 

(1)生成tensor

tf.ones | tf.zeros

tf.ones(shape,type=tf.float32,name=None)

用法类似,都是产生尺寸为shape的张量(tensor)

示例:

tf.zeros([2, 3], int32)

 

tf.ones_like | tf.zeros_like

tf.ones_like(tensor,dype=None,name=None)

tf.zeros_like(tensor,dype=None,name=None)

新建一个与给定的tensor类型大小一致的tensor,其所有元素为1和0

示例:

tensor=[[1, 2, 3], [4, 5, 6]]

x = tf.ones_like(tensor)

 

tf.fill

tf.fill(shape,value,name=None)

创建一个形状大小为shape的tensor,其初始值为value

示例:

tf.fill([2,3],2)

 

tf.constant

tf.constant(value,dtype=None,shape=None,name=’Const’)

创建一个常量tensor,按照给出value来赋值,可以用shape来指定其形状。value可以是一个数,也可以是一个list。

如果是一个数,那么这个常亮中所有值的按该数来赋值。

如果是list,那么len(value)一定要小于等于shape展开后的长度。赋值时,先将value中的值逐个存入。不够的部分,则全部存入value的最后一个值。

示例:

v4_1 = tf.constant([1, 2, 3, 4, 5, 6, 7])

v4_2 = tf.constant(-1.0, shape=[2, 3])

(2)生成序列

tf.linspace | tf.range

tf.linspace(start,stop,num,name=None)

tf.range(start,limit=None,delta=1,name=’range’)

这两个放到一起说,是因为他们都用于产生等差数列,不过具体用法不太一样。

tf.linspace在[start,stop]范围内产生num个数的等差数列。不过注意,start和stop要用浮点数表示,不然会报错

tf.range在[start,limit)范围内以步进值delta产生等差数列。注意是不包括limit在内的。

 

(3)生成随机数

tf.random_normal | tf.truncated_normal | tf.random_uniform

tf.random_normal(shape,mean=0.0,stddev=1.0,dtype=tf.float32,seed=None,name=None)

tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)

tf.random_uniform(shape,minval=0,maxval=None,dtype=tf.float32,seed=None,name=None)

这几个都是用于生成随机数tensor的。尺寸是shape

random_normal: 正太分布随机数,均值mean,标准差stddev

truncated_normal:截断正态分布随机数,均值mean,标准差stddev,不过只保留[mean-2*stddev,mean+2*stddev]范围内的随机数

random_uniform:均匀分布随机数,范围为[minval,maxval]

tf.random_shuffle

tf.random_shuffle(value,seed=None,name=None)

沿着value的第一维进行随机重新排列

示例:

v8_5 = tf.random_shuffle([[1,2,3],[4,5,6],[6,6,6]], seed=134, name="v8_5")

tf.random_crop(value, size, seed=None, name=None)

 

tf.multinomial(logits, num_samples, seed=None, name=None)

 

tf.random_gamma(shape, alpha, beta=None, dtype=tf.float32, seed=None, name=None)

 

tf.set_random_seed(seed)

 

tf.get_variable

 

tf.get_variable(name, shape=None, dtype=dtypes.float32, initializer=None,

                 regularizer=None, trainable=True, collections=None,

                 caching_device=None, partitioner=None, validate_shape=True,

                 custom_getter=None)

如果在该命名域中之前已经有名字=name的变量,则调用那个变量;如果没有,则根据输入的参数重新创建一个名字为name的变量。

initializer: 初始化工具,有tf.zero_initializer, tf.ones_initializer, tf.constant_initializer, tf.random_uniform_initializer,tf.random_normal_initializer,tf.truncated_normal_initializer等。

initializer(初始化)

 

tf.constant_initializer(value=0, dtype=tf.float32)

 

tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)

 

tf.truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)

 

tf.random_uniform_initializer(minval=0, maxval=None, seed=None, dtype=tf.float32)

 

tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32)

 

tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)

 

tf.ones_initializer(dtype=tf.float32, partition_info=None)

 

tf.orthogonal_initializer(gain=1.0, dtype=tf.float32, seed=None)

 

tf.get_variable与tf.variable的对比

 

相同点

通过两函数创建变量的过程基本一样,且tf.variable函数调用时提供的维度(shape)信息以及初始化方法(initializer)的参数和tf.Variable函数调用时提供的初始化过程中的参数基本类似。

不同点

两函数指定变量名称的参数不同,对于tf.Variable函数,变量名称是一个可选的参数,通过name="v"的形式给出。而tf.get_variable函数,变量名称是一个必填的参数,它会根据变量名称去创建或者获取变量。

tf.get_variable在创建变量时会查名字,如果给的名字在之前已经被别的变量占用,则会报错,不会创建相应变量。而tf.variable并不进行检查,如果有重复,则自动的修改名字,加上数字来进行区别。所以从这来看要想共享变量并不能通过使用相同的名字来调用多次 tf.get_variable 和 tf.variable 做到。

 

1使用tf.Variable时,如果检测到命名冲突,系统会自己处理。使用tf.get_variable()时,系统不会处理冲突,而会报错。

import tensorflow as tf
w_1 = tf.Variable(3, name="w_1")
w_2 = tf.Variable(1, name="w_1")
print w_1.name
print w_2.name
# 输出
# w_1:0
# w_1_1:0

*********************************************************************

import tensorflow as tf
w_1 = tf.get_variable(name="w_1", initializer=1)
w_2 = tf.get_variable(name="w_1", initializer=2)
# 错误信息
# ValueError: Variable w_1 already exists, disallowed. Did
# you mean to set reuse=True in VarScope?

当我们需要共享变量的时候,需要使用tf.get_variable()。在其他情况下,这两个的用法是一样的。

2由于tf.Variable() 每次都在创建新对象,所有reuse=True 和它并没有什么关系。对于get_variable(),来说,如果已经创建的变量对象,就把那个对象返回,如果没有创建变量对象的话,就创建一个新的。

import tensorflow as tf
with tf.variable_scope("scope1"):
   w1 = tf.get_variable("w1", shape=[])
   w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
   w1_p = tf.get_variable("w1", shape=[])
   w2_p = tf.Variable(1.0, name="w2")
print(w1 is w1_p, w2 is w2_p)
# 输出
# True  False

 

tf.trainable_variables

返回所有可训练的变量。

在创造变量(tf.Variable, tf.get_variable 等操作)时,都会有一个trainable的选项,表示该变量是否可训练。这个函数会返回图中所有trainable=True的变量。

tf.get_variable(…), tf.Variable(…)的默认选项是True, 而 tf.constant(…)只能是False。

各种优化器类使用这个集合作为默认的变量列表去优化。

tf.all_variables

返回的是所有变量的列表

1.4.2 变量的保存与读取

tensorflow使用Saver类进行变量的保存和读取,系统的变量将被保存到checkpoints中,point我简单的理解成快照,其本质是tensorflow使用二进制保存的变量名到变量值的map映射文件。

1.5 tf.Operation 

Operation是teansorflow 中操作节点的抽象化,有0个或多个输入和0个或多个输出,在运行后使用tf.get_default_session().run(op)进行运行,或者op.run(),这是前面的简化调用方式。主要属性与方法如下:

tf.Operation.name 获取名称
tf.Operation.type 获取属性
tf.Operation.inputs 获取输入值
tf.Operation.control_inputs 获取输入依赖值
tf.Operation.outputs 获取输出值
tf.Operation.device 获取操作设备
tf.Operation.graph 获取graph
tf.Operation.run(feed_dict=None, session=None) 如果op传入的是placeholder 对象,则需要使用feed_dict参数进行传入。
tf.Operation.get_attr(name) 获取op该属性的对应值。

1.6 tf.Tensor

tensor代表一个operation的结果。从tensorflow 的实际运行来说,tensor是operation一个输出的句柄,但是tensor所引用的并不持有具体的值,而是保持一个计算过程,在session调用的时候,可以使用这个计算过程来得到最终的结果。在python api中主要由两方面基本的内容:
(1)一个tensor可以被传递到另外一个operation,从而形成最终的数据流。这样,session中只需要对最后一个计算进行编码即可。
(2)在session调用最终的图之后,可以使用session.run()或者t.eval()对tensor的值进行计算。
常用的属性和函数如下:
tf.Tensor.dtype 数据类型
tf.Tensor.name tensor名称
tf.Tensor.value_index 在input中的index
tf.Tensor.graph 返回图名
tf.Tensor.op 返回操作名
tf.Tensor.consumers() 返回使用了这个tensorflow 的op列表
tf.Tensor.eval(feed_dict=None, session=None) 需要在session中使用,可以事先使用placeholder
tf.Tensor.get_shape() 获取形状
tf.Tensor.set_shape(shape) 设置形状
tf.Tensor.device 获取计算的设备

3、正则

在损失函数上加上正则项是防止过拟合的一个重要方法。

tensorflow中对参数使用正则项分为两步:

1. 创建一个正则方法(函数/对象)

2. 将这个正则方法(函数/对象),应用到参数上

3.1 创建正则方法函数

tf.contrib.layers.l1_regularizer(scale, scope=None)

返回一个用来执行L1正则化的函数,函数的签名是func(weights)。

参数:

  • scale: 正则项的系数.
  • scope: 可选的scope name

tf.contrib.layers.l2_regularizer(scale, scope=None)

返回一个执行L2正则化的函数.

tf.contrib.layers.sum_regularizer(regularizer_list, scope=None)

返回一个可以执行多种(个)正则化的函数.意思是,创建一个正则化方法,这个方法

是多个正则化方法的混合体.

参数:

regularizer_list: regulizer的列表。

3.2 应用正则化方法到参数上

tf.contrib.layers.apply_regularization(regularizer, weights_list=None)

参数:

  • regularizer:就是我们上一步创建的正则化方法
  • weights_list: 想要执行正则化方法的参数列表,如果为None的话,就取GraphKeys.WEIGHTS中的weights.

 

5、控制

 

tf.control_dependencies()

control_dependencies(self, control_inputs)

只有在 control_inputs被执行以后,上下文管理器中的操作才会被执行。例如:

  1. with tf.control_dependencies([a, b, c]):  
  2.      # `d` and `e` will only run after `a`, `b`, and `c` have executed.  
  3.      d = ...  
  4.      e = ...  
  5.      c= tf.no_op(name='train') # tf.no_op;什么也不做

 

只有[a,b,c]都被执行了才会执行d和e操作,这样就实现了流的控制。

也能通过参数None清除控制依赖,例如:

  1. with g.control_dependencies([a, b]):  
  2.       # Ops constructed here run after `a` and `b`.  
  3.       with g.control_dependencies(None):  
  4.         # Ops constructed here run normally, not waiting for either `a` or `b`.  
  5.         with g.control_dependencies([c, d]):  
  6.           # Ops constructed here run after `c` and `d`, also not waiting  
  7.           # for either `a` or `b`.  

注意

控制依赖只对那些在上下文环境中建立的操作有效,仅仅在context中使用一个操作或张量是没用的。

6、Saver

我们经常在训练完一个模型之后希望保存训练的结果,这些结果指的是模型的参数,以便下次迭代的训练或者用作测试。Tensorflow针对这一需求提供了Saver类。

  1. Saver类提供了向checkpoints文件保存和从checkpoints文件中恢复变量的相关方法。Checkpoints文件是一个二进制文件,它把变量名映射到对应的tensor值 。
  2. 只要提供一个计数器,当计数器触发时,Saver类可以自动的生成checkpoint文件。这让我们可以在训练过程中保存多个中间结果。例如,我们可以保存每一步训练的结果。
  3. 为了避免填满整个磁盘,Saver可以自动的管理Checkpoints文件。例如,我们可以指定保存最近的N个Checkpoints文件。

 

Class tf.train.Saver

保存和恢复变量

最简单的保存和恢复模型的方法是使用tf.train.Saver 对象。构造器给graph的所有变量,或是定义在列表里的变量,添加save 和 restore ops。saver 对象提供了方法来运行这些ops,定义检查点文件的读写路径。

检查点是专门格式的二进制文件,将变量name 映射到 tensor value。检查checkpoin 内容最好的方法是使用Saver 加载它。

Savers 可以使用提供的计数器自动计数checkpoint 文件名。这可以是你在训练一个模型时,在不同的步骤维持多个checkpoint。例如你可以使用 training step number 计数checkpoint 文件名。为了避免填满硬盘,savers 自动管理checkpoint 文件。例如,你可以最多维持N个最近的文件,或者没训练N小时保存一个checkpoint.

通过传递一个值给可选参数 global_step ,你可以编号checkpoint 名字。

  1. saver.save(sess, 'my-model', global_step=0) ==>filename: 'my-model-0'  
  2. saver.save(sess, 'my-model', global_step=1000) ==>filename: 'my-model-1000'  

另外,Saver() 构造器可选的参数可以让你控制硬盘上 checkpoint 文件的数量。

  • max_to_keep:  表明保存的最大checkpoint 文件数。当一个新文件创建的时候,旧文件就会被删掉。如果值为None或0,表示保存所有的checkpoint 文件。默认值为5(也就是说,保存最近的5个checkpoint 文件)。
  • keep_checkpoint_every_n_hour:  除了保存最近的max_to_keep checkpoint 文件,你还可能想每训练N小时保存一个checkpoint 文件。这将是非常有用的,如果你想分析一个模型在很长的一段训练时间内是怎么改变的。例如,设置 keep_checkpoint_every_n_hour=2 确保没训练2个小时保存一个checkpoint 文件。默认值10000小时无法看到特征。

注意,你仍然必须调用save() 方法去保存模型。传递这些参数给构造器并不会自动为你保存这些变量。

一个定期保存的训练程序如下这样:

  1. #Create a saver  
  2. saver=tf.train.Saver(...variables...)  
  3. #Launch the graph and train, saving the model every 1,000 steps.  
  4. sess=tf.Session()  
  5. for step in xrange(1000000):  
  6.     sess.run(...training_op...)  
  7.     if step % 1000 ==0:  
  8.         #Append the step number to the checkpoint name:  
  9.         saver.save(sess,'my-model',global_step=step)  

除了checkpoint 文件之外,savers 还在硬盘上保存了一个协议缓存,存储最近的checkpoint 列表。这用于管理 被编号的checkpoint 文件,并且通过latest_checkpoint() 可以很容易找到最近的checkpoint 的路径。协议缓存存储在紧挨checkpoint 文件的名为 'checkpoint' 的文件中。

如果你创建了几个savers,你可以调用save() 指定协议缓存的文件名。

tf.train.Saver.__init__(var_list=None, reshape=False, shared=False, max_to_keep=5, keep_checkpoint_every_n_hour=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None)

创建一个Saver

构造器添加操作去保存和恢复变量。

var_list 指定了将要保存和恢复的变量。它可以传dict 或者list

  • 变量名字的dict: key 是将用来在checkpoint 文件中存储和恢复的变量的名称。
  • 变量的list:  变量的 op name

可选参数 reshape ,如果为True,允许从保存文件中恢复一个不同shape 的变量,但元素的数量和type一致。如果你reshap 了一个变量而又想从一个旧的文件中恢复,这是非常有用的。

可选参数 shared,如果为True,通知每个设备上共享的checkpoint.

tf.train.Saver.save(sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix='meta', write_meta_graph=True)

保存变量

这个方法运行通过构造器添加的操作。它需要启动图的session。被保存的变量必须经过了初始化。

方法返回新建的checkpoint 文件的路径。路径可以直接传给restore() 进行调用。

参数:

  • sess:  用于保存变量的Session
  • save_path:  checkpoint 文件的路径。如果saver 是共享的,这是共享checkpoint 文件名的前缀。
  • global_step:  如果提供了global step number,将会追加到 save_path 后面去创建checkpoint 的文件名。可选参数可以是一个Tensor,一个name Tensor或integer Tensor.

返回值:

一个字符串:保存变量的路径。如果saver 是被共享的,字符串以'-?????-of-nnnnn' 结尾。'nnnnn' 是共享的数目。

保存变量

用tf.train.Saver() 创建一个Saver 来管理模型中的所有变量。

如果你不给tf.train.Saver() 传入任何参数,那么server 将处理graph 中的所有变量。其中每一个变量都以变量创建时传入的名称被保存

tf.train.Saver.restore(sess, save_path)

恢复之前保存的变量

这个方法运行构造器为恢复变量所添加的操作。它需要启动图的Session。恢复的变量不需要经过初始化,恢复作为初始化的一种方法。

save_path 参数是之前调用save() 的返回值,或调用 latest_checkpoint() 的返回值。

参数:

  • sess:  用于恢复参数的Session
  • save_path:  参数之前保存的路径

 

posted on 2017-10-26 11:45  执剑长老  阅读(5582)  评论(0编辑  收藏  举报