5.变量
constan与variable的区别:
- 常量也是常数,经常我们需要在训练模型的时候更新权重与偏置矩阵
- 一个常量存储于图中,并且当图加载时需要重新复制;一个变量独立地存储,并且存在与参数服务中。
以上两点解释了,当权重很大时,constant消耗代价很大,并且减慢了加载图的速度。我们看下图存储的内容:
import tensorflow as tf my_const = tf.constant([1.0, 2.0], name="my_const") print(tf.get_default_graph().as_graph_def())
node { name: "my_const" op: "Const" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "value" value { tensor { dtype: DT_FLOAT tensor_shape { dim { size: 2 } } tensor_content: "\000\000\200?\000\000\000@" } } } } versions { producer: 21 } [Finished in 3.0s]
- 创建变量
为了声明一个变量,你需要实例化一个tf.Variable,注意V
大写。
x = tf.Variable(...) x.initializer # init x.value() # read op x.assign(...) # write op x.assign_add(...) # and more
创建变量的旧方式是调用tf.Variable(<initial-value>, name=<optional-name>)
s = tf.Variable(2, name="scalar") m = tf.Variable([[0, 1], [2, 3]], name="matrix") W = tf.Variable(tf.zeros([784,10]))
然而这种方式被TensorFlow摒弃了,推荐我们使用tf.get_variable来创建,因为这样可以更好地实现变量共享。通过tf.get_variable
,我们可以internal name,shape,type和initializer提供给初始值。注意当我们通过tf.constant作为initializer时,不需要提供shape
tf.get_variable( name, shape=None, dtype=None, initializer=None, regularizer=None, trainable=True, collections=None, caching_device=None, partitioner=None, validate_shape=True, use_resource=None, custom_getter=None, constraint=None )
s = tf.get_variable("scalar", initializer=tf.constant(2)) m = tf.get_variable("matrix", initializer=tf.constant([[0, 1], [2, 3]])) W = tf.get_variable("big_matrix", shape=(784, 10), initializer=tf.zeros_initializer())
- 初始化变量
在使用一个变量之前,需要先初始化,否则将会报错:FailedPreconditionError: Attempting to use uninitialized value
.可以通过以下语句来打印出没有初始化的变量:
print(session.run(tf.report_uninitialized_variables()))
(1)初始化所有的变量:
with tf.Session() as sess: sess.run(tf.global_variables_initializer())
(2)初始化部分变量tf.variables_initializer()
with tf.Session() as sess: sess.run(tf.variables_initializer([a, b]))
(3) 初始化单个变量tf.Variable.initializer
with tf.Session() as sess: sess.run(W.initializer)
- 查看变量的值
从session取出值
# V is a 784 x 10 variable of random values V = tf.get_variable("normal_matrix", shape=(784, 10), initializer=tf.truncated_normal_initializer()) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(sess.run(V))
通过tf.Variable.eval()取出值
with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(V.eval())
- 变量赋值
通过tf.Variable.assign()
W = tf.Variable(10) W.assign(100) with tf.Session() as sess: sess.run(W.initializer) print(W.eval()) # >> 10
为什么输出的是10而不是100呢?W.assign(100)
并没有将100赋值给 W,而是创建了一个assign op.为了使这个op起到效果,我们需要在session运行op
W = tf.Variable(10) assign_op = W.assign(100) with tf.Session() as sess: sess.run(assign_op) print(W.eval()) # >> 100
注意此时我们不必去初始化W,因为assign()已经为我们实现。
# in the [source code](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/variables.py) self._initializer_op = state_ops.assign(self._variable, self._initial_value, validate_shape=validate_shape).op**
有趣的例子:
# create a variable whose original value is 2 a = tf.get_variable('scalar', initializer=tf.constant(2)) a_times_two = a.assign(a * 2) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) sess.run(a_times_two) # >> 4 sess.run(a_times_two) # >> 8 sess.run(a_times_two) # >> 16
tf.Variable.assign_add()
和 tf.Variable.assign_sub()
,这两个操作需要初始化
W = tf.Variable(10) with tf.Session() as sess: sess.run(W.initializer) print(sess.run(W.assign_add(10))) # >> 20 print(sess.run(W.assign_sub(2))) # >> 18
session之间的变量相互独立
W = tf.Variable(10) sess1 = tf.Session() sess2 = tf.Session() sess1.run(W.initializer) sess2.run(W.initializer) print(sess1.run(W.assign_add(10))) # >> 20 print(sess2.run(W.assign_sub(2))) # >> 8 print(sess1.run(W.assign_add(100))) # >> 120 print(sess2.run(W.assign_sub(50))) # >> -42 sess1.close() sess2.close()
如果一个变量依赖于另一个变量,需要初始化
# W is a random 700 x 10 tensor W = tf.Variable(tf.truncated_normal([700, 10])) U = tf.Variable(W * 2)
U = tf.Variable(W.initialized_value() * 2)
6 交互的会话
InteractiveSession是我们在shell或者IPython操作很方便
sess = tf.InteractiveSession() a = tf.constant(5.0) b = tf.constant(6.0) c = a * b print(c.eval()) # we can use 'c.eval()' without explicitly stating a session sess.close()
7. 控制依赖
有时候,graph有多个运算时op,并且我们想指定它们的执行顺序时,可以通过tf.Graph.control_dependencies([control_inputs])实现。
# your graph g have 5 ops: a, b, c, d, e with g.control_dependencies([a, b, c]): # `d` and `e` will only run after `a`, `b`, and `c` have executed. d = ... e = …
8. 导入数据
8.1 placeholder和feed_dict(旧方法)
我们在教程1提到过,TensorFlow程序执行通常包括两个阶段
阶段1:声明一个graph 阶段2:使用一个session来执行计算,来评估图中的变量
我们声明graphs的时候,不许要知道计算所需变量的值,这如同实名一个关于x和y的函数:f(x,y)=2x+y
,其中x和y是实际值的占位符(placeholder)
graph创建之后,我们需要稍后再提供值的时候来定义一个placeholder:
tf.placeholder(dtype, shape=None, name=None)
需要注意的是dtype
和shape
需要自己声明的;当shape=none
的时候, 表名可以接受任意shape的张量tensors。
下面是一个实例:
a = tf.placeholder(tf.float32, shape=[3]) # a is placeholder for a vector of 3 elements b = tf.constant([5, 5, 5], tf.float32) c = a + b # use the placeholder as you would any tensor with tf.Session() as sess: print(sess.run(c))
我们知道,此时执行上面程序会报错,因为还没有提供给a值,下面使用feed_dict把值传给a
with tf.Session() as sess: # compute the value of c given the value of a is [1, 2, 3] print(sess.run(c, feed_dict={a: [1, 2, 3]})) # [6. 7. 8.]
8.2 tf.data(新方法)
此部分结合教程3讲解