计算图
节点tf.constant() :每次运行都一样(常量)
import tensorflow as tf
two_node = tf.constant(2)
another_pointer_at_two_node = two_node
two_node = None
print two_node
print another_pointer_at_two_node
计算图:
import tensorflow as tf
two_node = tf.constant(2)
three_node = tf.constant(3)
sum_node = two_node + three_node ## equivalent to tf.add(two_node, three_node)
计算图
会话
tf.Session()、占位符tf.placeholder()(每次运行都不一样) 和 feed_dict
会话的作用是处理内存分配和优化,使我们能够实际执行由计算图指定的计算。你可以将计算图想象为我们想要执行的计算的「模版」:它列出了所有步骤。为了使用计算图,我们需要启动一个会话,它使我们能够实际地完成任务;例如,遍历模版的所有节点来分配一堆用于存储计算输出的存储器。为了使用 TensorFlow 进行各种计算,你既需要计算图也需要会话。
创建会话对象后,可以使用 sess.run(node) 返回节点的值
占位符是一种用于接受外部输入的节点:使用 sess.run() 的 feed_dixt 属性给占位符placeholder赋值2。传递给 feed_dict 的 dict 格式,其关键应该是与图中的占位符节点相对应的变量(如前所述,它实际上意味着指向图中占位符节点的指针)。相应的值是要分配给每个占位符的数据元素——通常是标量或 Numpy 数组。
import tensorflow as tf
input_placeholder = tf.placeholder(tf.int32)
sess = tf.Session()
print sess.run(input_placeholder, feed_dict={input_placeholder: 2})
计算路径
变量 tf.get_variable() & 副作用
变量由来:每次运行都一样的 tf.constant 和每次运行都不一样的 tf.placeholder。我们常常要考虑第三种情况:一个通常在运行时保持值不变的节点也可以被更新为新值。必须相对于全局图是唯一的,所以要明了你使用过的所有命名,确保没有重复。例如,一个 3x8 矩阵形状是 [3, 8]。要创建一个标量,就需要使用形状为 [] 的空列表。
有两种将值放入变量的方法:初始化器 和 tf.assign()。
import tensorflow as tf
count_variable = tf.get_variable("count", [])
zero_node = tf.constant(0.)
assign_node = tf.assign(count_variable, zero_node)
sess = tf.Session()
sess.run(assign_node)
print sess.run(count_variable)
tf.assign(target, value) 是具备一些独特属性:
-
恒等运算。tf.assign(target, value) 不做任何有趣的运算,通常与 value 相等。
-
副作用。当计算「流经」assign_node 时,副作用发生在图中的其他节点上。此时,副作用是用存储在 zero_node 中的值替换 count_variable 的值。
-
非依赖边。即使 count_variable 节点和 assign_node 在图中是相连的,但它们彼此独立。这意味着计算任一节点时,计算不会通过边回流。然而,assign_node 依赖于 zero_node,它需要知道分配了什么。
当我们调用 sess.run(assign_node) 时,计算路径会通过 assign_node 和 zero_node。
当计算流经图中的任何节点时,它还会执行由该节点控制的任何副作用,如图中绿色所示。由于 tf.assign 的特殊副作用,与 count_variable(v之前为「null」)关联的内存现在被永久设置为 0。这意味着当我们下一次调用 sess.run(count_variable) 时,不会引发任何异常。相反,我们会得到 0 值。
初始化器 initializer
'''
# 错误:
import tensorflow as tf
const_init_node = tf.constant_initializer(0.)
count_variable = tf.get_variable("count", [], initializer=const_init_node)
sess = tf.Session()
print sess.run([count_variable])
'''
# 正确:
import tensorflow as tf
const_init_node = tf.constant_initializer(0.)
count_variable = tf.get_variable("count", [], initializer=const_init_node)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
print sess.run(count_variable)
已将 get_variable 的 initializer 属性设置为指向 const_init_node,但它只是在图中的节点之间添加了一个新的连接。我们需要通过会话使 const_init_node 去更新变量。
图中,添加另一个特殊的节点:init = tf.global_variables_initializer()。与 tf.assign() 类似,这是一个带有副作用的节点。与 tf.assign() 相反,实际上我们不需要指定它的输入是什么!tf.global_variables_initializer() 将在其创建时查看全局图并自动将依赖关系添加到图中的每个 tf.initializer。当我们在之后使用 sess.run(init) 对它求值时,它会告诉每个初始化程序执行变量初始化,并允许我们运行 sess.run(count_variable) 而不出错。
变量共享
优化器
在深度学习中,典型的「内循环」训练如下:
1. 获取输入和 y
2. 根据输入和参数,计算推测y_
3. 根据推测y_与 y 之间的差异计算「损失」loss
4. 根据损失的梯度更新参数
用 tf.Print 调试
import tensorflow as tf
two_node = tf.constant(2)
three_node = tf.constant(3)
sum_node = two_node + three_node
print_sum_node = tf.Print(sum_node, [two_node, three_node])
sess = tf.Session()
print sess.run(print_sum_node)
'''
类似当前代码,但是比该代码还要精简
'''
import tensorflow as tf
two_node = tf.constant(2)
three_node = tf.constant(3)
sum_node = two_node + three_node
sess = tf.Session()
answer, inspection = sess.run([sum_node, [two_node, three_node]])
print inspection
print answer
'''
最差,看不到中间值,不好进行调试
'''
import tensorflow as tf
two_node = tf.constant(2)
three_node = tf.constant(3)
sum_node = two_node + three_node
sess = tf.Session()
print sess.run(sum_node)
代码实现
import tensorflow as tf
'''建立计算图'''
## 第一步:
# 参数——变量——更新
m = tf.get_variable("m", [], initializer=tf.constant_initializer(0.))
b = tf.get_variable("b", [], initializer=tf.constant_initializer(0.))
init = tf.global_variables_initializer()
## 第二步:
## 参数——占位符——建立计算
input_placeholder = tf.placeholder(tf.float32)
output_placeholder = tf.placeholder(tf.float32)
x = input_placeholder
y = output_placeholder
y_guess = m * x + b
loss = tf.square(y - y_guess)
## 第三步:
## 建立优化器——计算路径
optimizer = tf.train.GradientDescentOptimizer(1e-3)
train_op = optimizer.minimize(loss)
'''
train_op 回溯输入和损失的计算路径,寻找变量节点。对于它找到的每个变量节点,计算该变量对于损失的梯度。然后计算该变量的新值:当前值减去梯度乘以学习率的积。最后,它执行赋值操作更新变量的值。
当我们调用 sess.run(train_op) 时,它对我们的所有变量做了一个梯度下降的步骤。
'''
''' 开始会话'''
sess = tf.Session()
sess.run(init)
### perform the training loop
import random
## set up problem
true_m = random.random()
true_b = random.random()
for update_i in range(10000):
## (1) get the input and output
input_data = random.random()
output_data = true_m * input_data + true_b
## (2), (3), and (4) all take place within a single call to sess.run()!
_loss, _ = sess.run([loss, train_op], feed_dict={input_placeholder: input_data, output_placeholder: output_data})
print (update_i, _loss)
### finally, print out the values we learned for our two variables
print ("True parameters: m=%.4f, b=%.4f" % (true_m, true_b))
print ("Learned parameters: m=%.4f, b=%.4f" % tuple(sess.run([m, b])))
我的总结
固定值:tf.constant ()——直接赋值
占位符:tf.placeholder()——使用 sess.run() 的 feed_dixt 属性进行赋值——代表数据X与Y
更新值(变量):tf.get_variable()——使用初始化器initializer+sess.run(init) 和 tf.assign()进行赋值——代表参数w与b
会话:tf.Session()——建立会话
返回: sess.run(node)——计算
调试:tf.print()——