【 學習體會】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))

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