文章目录
一、Tensorflow中的变量
· 上节我说,在tensorflow中,所有的操作或者变量都是一个个节点,其实这对于变量的描述不够精确。其实官方的说法是这样的:Tensorflow中的变量是一个个有着特定形状和数据类型的张量(tensor)。
· 这里普及一下张量的概念。我是这么理解的:张量可以看做是一个特殊的向量:零阶张量的元素是标量(例如,0就是一个零阶张量),一阶张量的元素是零阶张量(例如,[0,0]就是一个一阶张量),二阶张量的元素是一阶张量(例如,[ [0,0], [1,1] ]就是一个二阶张量),以此类推。 所以张量的物理意义很明显:零阶是标量,一阶是矢量,二阶是矩阵,三阶是立体结构由矩阵拼接起来,四阶以后就比较抽象了,这里就不说了,因为我说不出来了 。
· 可以看到,在tensorflow中所有的变量都是张量节点,这意味着在tensorflow中的计算均是很复杂的张量计算,尤其矩阵计算。因此,大家应该知道为什么tensorflow能很愉快地做机器学习了吧。
· 值得一提的是:张量必须进行初始化操作后才合法,创建张量的操作只是规定了它的结构和初始化的方法。
二、创建变量
2.1 环境准备
import tensorflow as tf
2.2 Creating variables
· 在Tensorflow中,变量是一个类:tf.Variable,因此我们创建变量就是在用这个类的构造函数,其构造函数有三个入参:其一是张量的形状(shapes),其二是张量内部的数据类型(默认是float32),其三是此张量在图中的名称。
#######################################
######## Defining Variables ###########
#######################################
# Create three variables with some default values.
weights = tf.Variable(tf.random_normal([2, 3], stddev=0.1),
name="weights")
biases = tf.Variable(tf.zeros([3]), name="biases")
#biases_0 = tf.assign(biases, tf.ones([3]))
custom_variable = tf.Variable(tf.zeros([3]), name="custom")
# Get all the variables' tensors and store them in a list.
all_variables_list = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
- 可见虽然官方上说,定义变量时,指定是张量的shapes。但是上面构造的时候,不仅定义了张量的shapes,也给出了给张量赋值的具体方法:如上面的 正太分布赋值 和 全零赋值。
- 创建完变量后,所有的变量都会储存在一个列表里,可以用
tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
取出来。 - 关于tf.assign操作放在2.5节讲
· 注意:也可以用tf.get_variable(…)来创建变量,据说这种方法更好一点,但是我还是喜欢更加直观的tf.Variable,这里给出这种方法的官方说明:tf.get_variable
2.3 Initialization
· 在其他操作运行之前,所有的变量都应该被初始化。我们可以这样比喻:变量的创建是在组装汽车,不同的变量组成了不同的汽车组件,而变量的初始化是汽车的启动器,只有启动器执行了,这些组件才有用。
· 初始化操作可以有三种:给特定的某个变量执行初始化,给全局所有变量执行初始化以及用另一个变量给当前变量初始化。
- Initializing Specific Variables
· 使用tf.variables_initializer给特定的变量初始化。
# "variable_list_custom" is the list of variables that we want to initialize.
variable_list_custom = [weights, custom_variable]
# The initializer
init_custom_op = tf.variables_initializer(var_list=variable_list_custom)
- Global variable initialization
· 使用tf.global_variables_initializer()给所有的变量进行并行的初始化。其实这个操作就是给所有保存全部变量的列表进行tf.variables_initializer。
# Method-1
# Add an op to initialize the variables.
init_all_op = tf.global_variables_initializer()
# Method-2
init_all_op = tf.variables_initializer(var_list=all_variables_list)
- Initialization of a variables using other existing variables
# Create another variable with the same value as 'weights'.
WeightsNew = tf.Variable(weights.read_value(), name="WeightsNew")
# Now, the variable must be initialized.
init_WeightsNew_op = tf.variables_initializer(var_list=[WeightsNew])
2.4 Run the Session
· 可以通过,Variable.eval()得到里面的值。如果没有进行初始化,则会报错。
with tf.Session() as sess:
sess.run(init_custom_op)
print(weights.eval())
print(custom_variable.eval())
#以上操作没有初始化biases,所以会报错
# print(sess.run(biases))
sess.run(init_weightsNew_op)
print(weightsNew.eval())
sess.run(init_all_op)
print(biases.eval())
输出结果为:
[[ 0.1077401 -0.16742168 0.06057863]
[-0.27632776 0.1984974 0.03617979]]
[0. 0. 0.]
[[ 0.1077401 -0.16742168 0.06057863]
[-0.27632776 0.1984974 0.03617979]]
[0. 0. 0.]
注意:如果重复运行sess.run(init_custom_op)
,weights的值是不同的,可见变量的值确实是在初始化的时候被赋予的。
2.5 tf.assign
` 这个操作有时候也会使用,用于给变量赋值。注意:在tensorflow中所有的操作(op),只有在run之后才会生效。
- 运行
with tf.Session() as sess:
sess.run(init_all_op)
print(biases.eval())
sess.run(tf.assign(biases,tf.ones([3])))
#相当于运行如下操作
#sess.run(biases_0)
print(biases.eval())
- 得到
[0. 0. 0.]
[1. 1. 1.]
三、图示
如果运行如下代码,再用tensorboard打开,就可以很清晰的看到我们定义的变量,以及作用在变量上的操作了。
# coding: utf-8
import tensorflow as tf
import os,sys
tf.app.flags.DEFINE_string('f', '', 'kernel')
tf.app.flags.DEFINE_string('log_dir1', os.path.dirname(os.path.abspath(__file__)) + '/logs','logsDire')
FLAGS = tf.app.flags.FLAGS
weights = tf.Variable(tf.random_normal([2, 3], stddev=0.1), name = "weights")
biases = tf.Variable(tf.zeros([3]),name = "biases")
biases_0 = tf.assign(biases, tf.ones([3]),name="assign_biases")
custom_variable = tf.Variable(tf.zeros([3]),name="custom")
init_all_op = tf.global_variables_initializer()
with tf.Session() as sess:
writer = tf.summary.FileWriter(os.path.expanduser(FLAGS.log_dir1),sess.graph)
sess.run(init_all_op)
print(weights.eval())
print(custom_variable.eval())
#print(weightsNew.eval())
sess.run(biases_0)
print(biases.eval())
可以看到:
· 我来稍微解释一下吧:可以看到,在图里面保存的是我们定义的name属性的节点,不过是什么操作在图例都是节点,比较明显的就是:init操作,正太分布的操作以及那个赋值操作。尤其看到那个assign赋值节点,这个也是可以有name的。
- 三种不同的线
1. 灰色实线: Dataflow edge,表示操作之间的数据流流动,在本例中表示把正态分布的数据流传递给变量。Edge showing the data flow between operations. Edges flow upwards unless arrowheads specify otherwise.
2. 灰色虚线: Control dependency edge,表示操作之间控制依赖。本例中表示,变量操作的使用依赖于初始化操作。Edge showing the control dependency between operations.
3. 橘色实线: Reference edge,表示操作节点如果运行了,可以改变被指向张量的值。本例中表示,assgin操作如果被运行,则可以改变biases的值。Edge showing that the outgoing operation node can mutate the incoming tensor.
- 三种节点的形状
1. 矩形: 表示名称空间,一种颜色代表一种名称空间 ,名称空间是可扩展的,说明其内部会有很多的操作
2. 椭圆形: 表示操作节点
3. 圆形: 表示常量节点
这里给出weights和random_normal的内部结构图。
· 这就可以很清楚的看到,我们是如何定义一个张量结构的:先构建了一个2x3形状的常量,然后初始化后给weights赋值。仔细想一下也没有大不了的嘛!