一句话说明
- 在 TensorFlow 1.x 版本中,
tf.Graph()用于创建一个新的计算图,而会话(tf.Session())则用于执行计算图中的操作 - 本文将分别给出明确创建图(
tf.Graph())和不明确创建图创建会话的示例,并说明它们之间的区别
不明确创建图
当不指定图时,TensorFlow 会使用一个全局默认的计算图。以下是一个简单的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13# 在TensorFlow 2.x中可以通过下面的代码替换 `import tensorflow as tf`,仍可在TensorFlow 2.x环境中使用TensorFlow 1.x
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
# 定义操作,使用默认计算图
a = tf.constant(3.0)
b = tf.constant(4.0)
c = tf.add(a, b)
# 创建会话并执行操作
with tf.Session() as sess:
result = sess.run(c)
print("不使用 tf.Graph() 的结果:", result)在这个示例中,我们没有显式地创建计算图,TensorFlow 会使用默认的计算图来定义操作
a、b和c。然后创建一个会话并在该会话中运行操作c,最终得到计算结果
明确创建图(使用tf.Graph())
也可以使用
tf.Graph()函数,创建一个新的独立计算图,并在这个图中定义操作。以下是示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 在TensorFlow 2.x中可以通过下面的代码替换 `import tensorflow as tf`,仍可在TensorFlow 2.x环境中使用TensorFlow 1.x
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
# 创建一个新的计算图
graph = tf.Graph()
# as_default() 只在 with 上下文中生效,退出后默认图会恢复为原来的全局默认图
with graph.as_default():
# 在新的计算图中定义操作
a = tf.constant(5.0)
b = tf.constant(6.0)
c = tf.add(a, b)
# 创建会话并指定使用新的计算图
with tf.Session(graph=graph) as sess:
result = sess.run(c)
print("使用 tf.Graph() 的结果:", result)在这个示例中,我们做了以下操作:
- 首先使用
tf.Graph()创建了一个新的计算图graph - 然后使用
graph.as_default()上下文管理器,将这个新的计算图设置为默认图,并在其中定义操作a、b和c - 最后创建一个会话,并通过
graph=graph参数指定该会话使用我们创建的新计算图,在会话中运行操作c并得到结果
- 首先使用
多图管理(TensorFlow 1.x)
- TensorFlow 1.x中创建和管理多个计算图的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35import tensorflow as tf
# 创建第一个计算图
graph1 = tf.Graph()
with graph1.as_default():
# 在图1中定义变量和操作
a = tf.constant(5, name='a')
b = tf.constant(3, name='b')
c = tf.add(a, b, name='sum')
# 在图1中初始化所有变量
init1 = tf.global_variables_initializer()
# 创建第二个计算图
graph2 = tf.Graph()
with graph2.as_default():
# 在图2中定义不同的变量和操作
x = tf.constant(10, name='x')
y = tf.constant(4, name='y')
z = tf.multiply(x, y, name='product')
# 在图2中初始化所有变量
init2 = tf.global_variables_initializer()
# 创建会话执行图1
with tf.Session(graph=graph1) as sess1:
sess1.run(init1)
result1 = sess1.run(c)
print("图1的结果:", result1) # 输出: 图1的结果: 8
# 创建会话执行图2
with tf.Session(graph=graph2) as sess2:
sess2.run(init2)
result2 = sess2.run(z)
print("图2的结果:", result2) # 输出: 图2的结果: 40
多图管理的必要性
- 隔离性 :不同的图完全隔离,变量和操作不会相互干扰。这在以下场景特别有用:
- 同时运行多个模型
- 比较不同模型结构
- 隔离训练和推理图
- 资源管理 :每个图有自己的资源集合,可以独立释放,避免内存泄漏
- 命名空间 :不同图中的操作可以有相同的名称而不会冲突
- 并行执行 :可以在不同线程中同时运行不同的图(每个线程有自己的会话)
- 调试 :当出现问题时,可以更容易地定位是哪个图出现了错误
多图管理的最佳实践
- 使用
with graph.as_default():上下文管理器来明确操作属于哪个图 - 会话(Session)和图(Graph)是一一对应的,需要为每个图创建独立的会话,明确关闭不再需要的会话以释放资源
- 一般情况可以不用明确创建多个图 ,仅维护一个默认的图即可,更好的做法是在单个图中使用不同的名称作用域(namescope)来组织操作
- 多线程运行时需要维护不同的图,确保图不会被同时访问(注:不同图的变量命名也可以相同,也就是可以使用相同的代码来定义)
- 在 TensorFlow 2.x 中,默认启用了即时执行(Eager Execution)模式,不再需要显式地创建计算图和会话
关于图的作用域示例
as_default()只在 with 上下文中生效,退出后默认图会恢复为原来的全局默认图:1
2
3
4with new_graph.as_default():
op1 = tf.constant(1) # 属于 new_graph
op2 = tf.constant(2) # 属于全局默认图(不是 new_graph)嵌套多个
as_default()的示例(不建议使用)1
2
3
4
5
6
7
8g1 = tf.Graph()
g2 = tf.Graph()
with g1.as_default():
a = tf.constant(1) # 属于 g1
with g2.as_default():
b = tf.constant(2) # 属于 g2通过 tf.get_default_graph() 可以检查当前默认图:
1
2with new_graph.as_default():
print(tf.get_default_graph() is new_graph) # 输出 True
新增变量及其初始化
在已经创建session后,依然是可以加入新的变量的,但是需要进行初始化才可以使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import tensorflow as tf
var1 = tf.Variable(3, dtype=tf.float32)
var2 = tf.Variable(5, dtype=tf.float32)
add_op1 = tf.add(var1, var2)
sess = tf.Session()
init_op = tf.global_variables_initializer() # 初始化所有变量
sess.run(init_op)
result1 = sess.run(add_op1)
print("两个变量的和:", result1)
# 在Session后继续创建变量
var3 = tf.Variable(7, dtype=tf.float32)
add_op2 = tf.add(add_op1, var3)
init_new_var = tf.variables_initializer([var3]) # 初始化新创建的变量
sess.run(init_new_var)
result2 = sess.run(add_op2)
print("三个变量的和:", result2)
sess.close() # 显式关闭会话
# 两个变量的和: 8.0
# 三个变量的和: 15.0注意:TensorFlow 1.x中,所有变量都需要初始化(因为变量定义操作不会分配内存,只有在初始化后才会分配内存),重复初始化变量会将变量重置为初始化值