神经网络中的参数是神经网络实现分类或回归问题中重要的部分。在tensorflow中,变量(tf.Variable)的作用就是保存和更新神经网络中的参数。和其他编程语言类似,tensorflow中的变量也需要指定初始值。因为在神经网络中,给参数赋予随机初始值最为常见,所以一般也使用随机数给tensorflow中的变量初始化。下面一段代码给出了一种在tensorflow中声明一个2*3矩阵变量的方法:
代码语言:javascript复制weights = tf.Variable(tf.random_normal([2, 3], stddev = 2))
在神经网络中,偏置值(bias)通常会使用常数来设置初始值。以下代码给出了一个样例:
代码语言:javascript复制biases = tf.Variable(tf.zeros([3]))
以上代码将会生成一个初始值全部为零且长度为3的变量。除了使用随机数或常数,tensorflow也支持通过其他变量的初始值来初始化新的变量。以下代码给出了具体的方法。
代码语言:javascript复制w2 = tf.Variable(weights.initialized_value( ))
w3 = tf.Variable(weights.initialized_value( ) * 2.0)
以上代码中,w2的初始值被设置成了与weights变量相同。w3的初始值则是weights初始值的两倍。在tensorflow中,一个变量的值在被使用之前,这个变量的初始化过程需要被明确地调用。以下样例介绍了如何通过变量实现神经网络的参数并实现前向传播过程。
代码语言:javascript复制import tensorflow as tf
# 声明w1、w2两个变量。这里还通过seed参数设定了随机种子。
# 这样可以保证每次运行得到的结果是一样的。
w1 = tf.Variable(tf.random_normal((2,3), stddev = 1, seed = 1 ))
w2 = tf.Variable(tf.random_normal((3,1), stddev = 1, seed = 1 ))
# 暂时将输入的随机向量定义为一个常量。注意这里x是一个1*2的矩阵。
x = tf.constant([0.7, 0.9])
# 描述前向传播算法获得神经网络的输出
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
sess = tf.Session( )
# 这里不能直接通过sess.run(y)来获取y的取值
# 因为w1和w2都还没有运行初始化过程。以下两行分别初始化了w1和w2两个变量。
sess.run(w1.initializer) #初始化w1。
sess.run(w2.initializer) #初始化w2。
#输出[[3.95757794]]
print(sess.run(y))
sess.close()
以上程序实现了神经网络的前向传播过程。从这段代码可以看出,当声明了变量w1、w2之后,可以通过w1和w2来定义神经网络的前向传播过程并得到中间结果a和最后答案y。
在tensorflow程序的第二步回生命一个会话(session),并通过会话计算结果。在上面的样例中,当会话定义完成之后就可以真正运行定义好的计算了。但在计算y之前,需要将所有用到的变量初始化。也就是说,虽然在变量定义时给出了变量初始化的方法,但这个方法并没有被真正运行。所以在计算y之前,需要通过运行w1.initializer和w2.initializer来给变量赋值。虽然直接调用每个变量的初始化过程是一个可行的方案,但是当变量数目增多,或者变量之间存在依赖关系时,耽搁调用的方案就比较麻烦了。为了解决这个问题,tensorflow提供了一种更加便捷的方式来完成变量初始化过程。以下程序展示了通过tf.global_variables_initializer函数实现初始化所有变量的过程。
代码语言:javascript复制init_op = tf.global_variables_initializer( )
sess.run(init_op)
通过tf.global_variables_initializer函数,就不需要将变量一个一个初始化了。这个函数也会自动处理变量之间的依赖关系。变量和张量的关系:在tensorflow中,变量声明函数tf.Variable是一个运算,这个运算的输出结果就是一个张量。
类似张量,维度(shape)和类型(type)也是变量最重要的两个属性。和大部分程序语言类似,变量的类型是不可以改变的。一个变量在构建之后,它的类型就不能再改变了。比如在上面给出的前向传播样例中,w1的类型为random_normal结果的默认类型tf.float32,那么它将不能被赋予其他类型的值。一下代码将会爆出类型不匹配的错误。
代码语言:javascript复制w1 = tf.variable(tf.random_normal([2. 3], stddev=1), name= "w1")
w2 = tf.variable(tf.random_normal([2. 3], dtype=tf.float64, stddev = 1), name= "w2")
w1.assign(w2)
'''
程序将报错:
TypeError:Input 'value' of 'Assign' Op has type float64 that does not match type float32 of argument 'ref'
'''
维度是变量另一个重要的属性。和类型不大一样的是,维度在程序运行中是有可能改变的,但是需要通过设置参数validate_shape=False。下面给出了一段示范代码。
代码语言:javascript复制w1 = tf.Variable(tf.random_normal([2 ,3], stddev=1), name="w1")
w2 = tf.Variable(tf.random_normal([2 ,2], stddev=1), name="w2")
# 下面这句话会报维度不匹配的错误:
# ValueError: Dimension 1 in both shapes must be equal, but are 3 and 2
# for 'Assign_1' (op: 'Assign') with input shapes: [2, 3], [2, 2].
tf.assign(w1 ,w2)
#这句话可以被成功执行
tf.assign(w1, w2, validate_shape=False )