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
- TensorFlow中的计算,表示为一个数据流图,简称“图”
- 一个Graph实例就是一个图,由一组Operation对象和Tensor对象构成:每个Operation对象(简记为op)表示最小的计算单元,每个Tensor对象表示在operations间传递的基本数据单元
- 如果你没有注册自己的图,系统会提供一个默认图。你可通过调用
tf.get_default_graph()
显式地访问这个图,也可以不理会这个图,因为调用任一个operation函数时,如调用constant op,c=tf.constant(4.0)
,一个表示operation的节点会自动添加到这个图上,此时c.graph
就指这个默认图。 - 如果我们创建了一个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.prototf.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 类型 | 描述 |
|
| 32 位浮点数. |
|
| 64 位浮点数. |
|
| 64 位有符号整型. |
|
| 32 位有符号整型. |
|
| 16 位有符号整型. |
|
| 8 位有符号整型. |
|
| 8 位无符号整型. |
|
| 可变长度的字节数组.每一个张量元素都是一个字节数组. |
|
| 布尔型. |
|
| 由两个32位浮点数组成的复数:实数和虚数. |
|
| 用于量化Ops的32位有符号整型. |
|
| 用于量化Ops的8位有符号整型. |
|
| 用于量化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类。
- Saver类提供了向checkpoints文件保存和从checkpoints文件中恢复变量的相关方法。Checkpoints文件是一个二进制文件,它把变量名映射到对应的tensor值 。
- 只要提供一个计数器,当计数器触发时,Saver类可以自动的生成checkpoint文件。这让我们可以在训练过程中保存多个中间结果。例如,我们可以保存每一步训练的结果。
- 为了避免填满整个磁盘,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 名字。
- saver.save(sess, 'my-model', global_step=0) ==>filename: 'my-model-0'
- 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: 参数之前保存的路径