虽然Tensorflow2.0已经发布了!
但是我还是想写一些使用tensorflow1.x这一路的一些心得体会
反正2.0也是会兼容1.x的,哈哈哈(自我安慰(怎么就没有时间跟上google大佬们的步伐呢?))
简单来说2.0最大的亮点就推出Eager Execution模式,以便于模型的快速迭代开发。但依然包含传统的Graph Execution模式
在1.x的时候,我们是要建立graph(graph包含各种 const节点 和 非const节点,后面会仔细讲这两种的节点的定义和区别 ),
然后建立session并绑定建立的graph,之后session.run() 计算选定的节点
然而在2.0,默认Eager Execution模式,这意味着 op 在调用后会立即运行。
举几个简单的例子
# 在eager模式下可以直接进行运算
x = [[3.]]
m = tf.matmul(x, x)
print(m.numpy())
'''
[[9.]]
'''
a = tf.constant([[1,9],[3,6]])
print(a)
'''
tf.Tensor(
[[1 9]
[3 6]], shape=(2, 2), dtype=int32)
'''
b = tf.add(a, 2)
print(b)
'''
tf.Tensor(
[[ 3 11]
[ 5 8]], shape=(2, 2), dtype=int32)
'''
print(a*b)
'''
tf.Tensor(
[[ 3 99]
[15 48]], shape=(2, 2), dtype=int32)
'''
import numpy as np
s = np.multiply(a,b)
print(s)
'''
[[ 3 99]
[15 48]]
'''
确实是非常牛逼!比以前简单了不少!
tensorflow2.0更多的例子可以参考博客:https://blog.csdn.net/qq_31456593/article/details/88605510
目录
1、tf.Graph
2、(tf.variable_scope,tf.name_scope)和(tf.get_variable,tf.Variable)
2.1 tf.get_variable,tf.Variable
2.2 tf.variable_scope,tf.name_scope
3、tf.Session
第一个抽象是计算图tf.Graph,它使框架能够处理惰性评估模式(不是立即执行,这是“传统”命令式Python编程实现的)。
Graph可以是默认的,也可以用tf.Graph()显式的定义
Graph中包含子图(subgraph)、const节点和非const节点
const节点是指该节点的operation为Const
非const节点是指该节点的operation不为Const(比如,VariableV2、Identity、Assign、Add等等),也可以叫op节点(比如,Assign节点)
这样说好像有点模糊,举个例子:
a=tf.constant([1.0,2.0], name='a')
b=tf.constant([1.0,2.0], name='b')
result = tf.add(a,b,name='add')
tf.constant在图中创建1个const节点(比如,a和b),可以看到该节点的Operation:Const,这是一个const节点
tf.add在图中创建1个非Const节点(也可以说是,Add节点,name=‘add’),其输入(input为a和b)
可以用python代码的将图中的节点都打印出来
print(tf.get_default_graph().as_graph_def())
nodename=[n.name for n in tf.get_default_graph().as_graph_def().node]
print(nodename)
其中 tf.get_default_graph()是获取默认图,一般来说如果没有显式定义图,则所有节点都是添加在默认图的
输出为
node {
name: "a"
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@"
}
}
}
}
node {
name: "b"
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@"
}
}
}
}
node {
name: "add"
op: "Add"
input: "a"
input: "b"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
versions {
producer: 27
}
['a', 'b', 'add']
顺便提一下:
如何简单快捷的导出tensorboard
只要添加代码如下,运行之后就会自动弹出chrome网页,就可以看到了
from datetime import datetime
import os
def create_dir(dirname):
if not os.path.exists(dirname):
os.makedirs(dirname)
TIMESTAMP = "{0:%Y-%m-%dT%H-%M-%S/}".format(datetime.now())
graph_dir = 'visualize/' + TIMESTAMP#图的存放路径
create_dir(graph_dir)
writer = tf.summary.FileWriter(graph_dir)
writer.add_graph(tf.get_default_graph())
os.system('"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" http://localhost:6006')
os.system('"D:\\Users\\Leon_PC\\Anaconda3\\envs\\tensorflow_gpu\\Scripts\\tensorboard.exe" --logdir='+graph_dir)
其中chrome.exe的路径和tensorboard.exe的路径要适当修改
话说回tf.Graph
再举一个简单的例子:
d=tf.Variable(2.0, name="dddd", dtype=tf.float32)
c=tf.get_variable('ccc',shape=[1],dtype=tf.float32)
tensor_2 = tf.add(c, d, name='add_1')
tf.Variable在图中创建1个子图(subgraph,name=‘dddd’),子图的名称由tf.Variable()中name参数设置
该子图包含3个非const节点(Assign,VariableV2,Identity节点)和1个const节点(name=initial_value)
VariableV2的name等于子图的名称
tf.get_variable在图中创建1个子图(比如,子图ccc,name=ccc),
子图ccc包含3个非const节点(Operation=Assign,VariableV2,Identity)和一个子图(name=Initializer)
子图Initializer包含1个子图random_uniform
子图random_uniform包含4个非const节点(Operation=RandomUniform,Sub,Mul,Add)和3个const节点(name=shape,min,max)
tf.add在图中创建1个非Const节点(也可以说是,Add节点,name=‘add_1’),其输入(input为ccc/read(Identity节点)和dddd/read(Identity节点)
小结如下:
温馨提示:
如果没有用tf.Graph,则tensor会被定义再tf的默认图中,
程序结束后默认图中的节点不会被释放,所以再次运行程序的时候就会出现“Variable c already exists”这种问题
所以如果使用默认图的话,每次运行程序之前都要再最开始加上tf.reset_default_graph(),重置默认图,相当于清空默认图中的节点
tf创建变量有两种方式tf.variable() 和tf.get_variable()
tf.Variable() 的话每次都会新建变量
tf.get_variable( ) 拥有一个变量检查机制,会检测已经存在的变量是否设置为共享变量,如果已经存在的变量没有设置为共享变量,TensorFlow 运行到第二个拥有相同名字的变量的时候,就会报错;tf.get_variable() 如果遇到了已经存在名字的变量时,
它会单纯的提取这个同样名字的变量,如果不存在名字的变量再创建。
举个例子
import tensorflow as tf
tf.reset_default_graph()
with tf.variable_scope('V1'): #,reuse=tf.AUTO_REUSE
a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')
a3 = tf.get_variable(name='a1', shape=[1],initializer=tf.constant_initializer(1))
a4 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')
print(a1)#
print(a2)#
print(a3)#报错:ValueError: Variable V1/a1 already exists
print(a4)#
一般tf.get_variable( )在tf.variable_scope的作用域下使用,
tf.variable_scope( )创建1个子图(subgraph),包含所有在其下文中创建的节点(比如,a1和a2)
tf.Variable()因为每一次都会创建新的变量,如果变量已经存在比如a2,则会创建a2_1
而a3之所以报错是因为
在tf.variable_scope的作用域下,已经创建a1节点,没有参数reuse=tf.AUTO_REUSE,
故a1节点不是共享变量,所以不能用tf.get_variable( )去获取
再举个例子
import tensorflow as tf
tf.reset_default_graph()
with tf.variable_scope('V1',reuse=tf.AUTO_REUSE):
a1 = tf.get_variable(name='a1', shape=[1], initializer=tf.constant_initializer(1))
a2 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')
a3 = tf.get_variable(name='a1', shape=[1],initializer=tf.constant_initializer(1))
a4 = tf.Variable(tf.random_normal(shape=[2,3], mean=0, stddev=1), name='a2')
print(a1)#
print(a2)#
print(a3)#
print(a4)#
tf.variable_scope的作用域下,设置reuse=tf.AUTO_REUSE
tf.get_variable() 对于已经存在名字的变量, 会单纯的提取这个同样名字的变量,如果不存在名字的变量再创建,起到变量共享的作用。换句话说,如果reuse设置为None,tf.get_variable() 对于已经存在名字的变量会报错。
在variable_scope的作用域下,tf.get_variable()和tf.Variable()创建的节点都加了variable_scope_name前缀(比如,V1/a1:0、V1/a2:0 等等)
TF中有两种作用域类型
命名域 (name_scope),通过tf.name_scope 或 tf.op_scope创建;
变量域 (variable_scope),通过tf.variable_scope 或 tf.variable_op_scope创建;
这两种作用域,对于使用tf.Variable()方式创建的节点,具有相同的效果,都会在节点名称前面,加上域名称(比如,V1/a1:0,其中V1是域名,a1是节点名,则该节点的全称为V1/a1:0)。
name_scope不会作为tf.get_variable变量的前缀,但是会作为tf.Variable的前缀
举个例子
import tensorflow as tf
tf.reset_default_graph()
with tf.name_scope("my_name_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2,name='add_1')
print(v1.name)#var1:0
print(v2.name)#my_name_scope/var2:0
print(a.name)#my_name_scope/add_1:0
with tf.variable_scope("my_variable_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2,name='add_1')
print(v1.name)#my_variable_scope/var1:0
print(v2.name)#my_variable_scope/var2:0
print(a.name)#my_variable_scope/add_1:0
tf.name_scope( )创建1个子图(subgraph),包含所有在其下文中由tf.Variable创建的节点(比如,my_name_scope/var2:0)
重申! name_scope不会作为tf.get_variable变量的前缀,但是会作为tf.Variable的前缀!!
variable_scope会作为所有在其下文中创建的节点前缀(比如,my_variable_scope/var1:0,my_variable_scope/var2:0)
tf.Session().as_default():创建一个默认会话
那么问题来了,会话和默认会话有什么区别呢?
TensorFlow会自动生成一个默认的计算图,如果没有特殊指定,运算会自动加入这个计算图中。
TensorFlow中的会话也有类似的机制,但是TensorFlow不会自动生成默认的会话,而是需要手动指定。
tf.Session()创建一个会话,当上下文管理器退出时会话关闭和资源释放自动完成。
tf.Session().as_default()创建一个默认会话,当上下文管理器退出时,会话没有关闭,还可以通过调用会话进行run()和eval()操作,代码示例如下:
tf.Session()创建一个会话,当上下文管理器退出时会话关闭和资源释放自动完成。
import tensorflow as tf
a = tf.constant(1.0)
b = tf.constant(2.0)
with tf.Session() as sess:
print(a.eval())
print(b.eval(session=sess))
'''
tf.Session()创建一个会话,当上下文管理器退出时会话关闭和资源释放自动完成。
'''
tf.Session().as_default()创建一个默认会话,当上下文管理器退出时,会话没有关闭,还可以通过调用会话进行run()和eval()操作
import tensorflow as tf
a = tf.constant(1.0)
b = tf.constant(2.0)
with tf.Session().as_default() as sess:
print(a.eval())
print(b.eval(session=sess))
'''
tf.Session().as_default()创建一个默认会话,当上下文管理器退出时,会话没有关闭,还可以通过调用会话进行run()和eval()操作
'''
如果想让默认会话在退出上下文管理器时关闭会话,可以调用sess.close()方法。
'''
如果想让默认会话在退出上下文管理器时关闭会话,可以调用sess.close()方法。
'''
import tensorflow as tf
a = tf.constant(1.0)
b = tf.constant(2.0)
with tf.Session().as_default() as sess:
print(a.eval())
sess.close()
print(b.eval(session=sess))
tf.global_variables_initializer在图中创建1个非const节点(operation=NoOp,name=init),该节点的input为所有变量/Assign节点
在tf.Session中NoOp节点要首先被run,否则就会出现“FailedPreconditionError: Attempting to use uninitialized value”的错误
该错误的意思就是你准备使用未经初始化的VariableV2节点,所有VariableV2节点都应该被初始化才能使用
所有VariableV2节点都应该被初始化!!!!
举个例子
import tensorflow as tf
tf.reset_default_graph()
d=tf.Variable(2.0, name="dddd", dtype=tf.float32)
y = tf.assign(d, 1,name='y')
inittttt=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(inittttt)
print(sess.run(d))
print(sess.run(y))
print(sess.run(d))