【 学习体会】Tensorflow1.x的一些学习体会

虽然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

 

下面我来谈谈tensorflow1.x(具体来说,是tensorflow1.12.0)

目录

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


 

1、tf.Graph

第一个抽象是计算图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(),重置默认图,相当于清空默认图中的节点


2、(tf.variable_scope,tf.name_scope)和(tf.get_variable,tf.Variable)

2.1 tf.get_variable,tf.Variable

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)#<tf.Variable 'V1/a1:0' shape=(1,) dtype=float32_ref>
print(a2)#<tf.Variable 'V1/a2:0' shape=(2, 3) dtype=float32_ref>
print(a3)#报错:ValueError: Variable V1/a1 already exists
print(a4)#<tf.Variable 'V1/a2_1:0' shape=(2, 3) dtype=float32_ref>


一般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)#<tf.Variable 'V1/a1:0' shape=(1,) dtype=float32_ref>
print(a2)#<tf.Variable 'V1/a2:0' shape=(2, 3) dtype=float32_ref>
print(a3)#<tf.Variable 'V1/a1:0' shape=(1,) dtype=float32_ref>
print(a4)#<tf.Variable 'V1/a2_1:0' shape=(2, 3) dtype=float32_ref>

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 等等)

 

2.2 tf.variable_scope,tf.name_scope

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)

 

3、tf.Session

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))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章