tensorflow中,Graph是一個就像一個大容器,OP、Tensor、Variable是這個大容器的組成部件。
Graph管理Tensor對象,Session管理Variable對象。Variable對象必須在Session對象內初始化。初始化所有Variable對象,把.global_variables_initializer() Op傳給Session.run()。初始化部分Variable對象,把.variables_initializer() Op傳給Session.run()。Variable.assign()Op,修改Variable對象,必須在Session對象中運行。.assign_add()創建自增Op,.assign_sub()創建自減Op。不同Session對象獨立維護在Graph對象定義的Variable對象值。Optimizer類自動訓練機器學習模型,自動修改Variable對象值。創建Variable對象時trainable參數設False,只允許手工修改值。
1、基本元素
1.1 圖(Graph)
class tf.Graph
- TensorFlow中的計算,表示為一個數據流圖,簡稱“圖”
- 一個Graph實例就是一個圖,由一組Operation對象和Tensor對象構成:每個Operation對象(簡記為op)表示最小的計算單元,每個Tensor對象表示在operations間傳遞的基本數據單元
- 如果你沒有注冊自己的圖,系統會提供一個默認圖。你可通過調用
tf.get_default_graph()
顯式地訪問這個圖,也可以不理會這個圖,因為調用任一個operation函數時,如調用constant op,c=tf.constant(4.0)
,一個表示operation的節點會自動添加到這個圖上,此時c.graph
就指這個默認圖。 - 如果我們創建了一個Graph實例,並想用它取代上面的默認圖,把它指定為一個新的默認圖,至少是臨時換一下,可以調用該Graph實例的
as_default()
方法,並得到一個Python中的上下文管理器(context manager),來管理臨時默認圖的生命周期,即with ...
下的代碼區域。
為了向默認圖添加一個操作,可以簡單地調用定義了一個新的 Opertation 的函數:
c = tf.constant(4.0) assert c.graph is tf.get_default_graph()
另外一個典型的用法包括 Graph.as_default() 這個上下文管理器(context manager)在上下文環境中覆蓋了當前的默認圖。
g = tf.Graph() with g.as_default(): # Define operations and tensors in `g`. c = tf.constant(30.0) assert c.graph is g
重要提示:這個類構建圖是非線程安全的。所有的操作應該從單個線程中創建,否則必須提供外部同步。除非明確指明,所有方法都是非線程安全的。
1.1.1 Graph的屬性
內部屬性:
- 與operation相關:
_nodes_by_id
:dict( op的id => op ),按id記錄所有添加到圖上的op_nodes_by_name
:dict( op的name => op ),按名字記錄所有添加到圖上的op_next_id_counter
:int,自增器,創建下一個op時用的id_version
:int,記錄所有op中最大的id_default_original_op
:有些op需要附帶一個original_op
,如replica op需要指出它要對哪個op進行復制_attr_scope_map
:dict( name scope => attr ),用於添加一組額外的屬性到指定scope中的所有op_op_to_kernel_label_map
:dict( op type => kernel label ),kernel可能是指operation中更底層的實現_gradient_override_map
:dict( op type => 另一個op type ),把一個含自定義gradient函數的注冊op,用在一個已存在的op上
- 與命名域name scope相關:
_name_stack
:字符串,嵌套的各個scopes的名字拼成的棧,用帶間隔符”/”的字符串表示_names_in_use
: dict( name scope => 使用次數 )
- 與device相關:
_device_function_stack
: list,用來選擇device的函數棧,每個元素是一個device_function(op)
,用來獲取op所在device
- 與控制流相關:
_control_flow_context
:一個context對象,表示當前控制流的上下文,如CondContext
對象,WhileContext
對象,定義在ops/control_flow_ops.py。實際上,控制流也是一個op,用來控制其他op的執行,添加一些條件依賴的關系到圖中,使執行某個operation前先查看依賴_control_dependencies_stack
:list,一個控制器棧,每個控制器是一個上下文,存有控制依賴信息,表明當執行完依賴中的operations和tensors后,才能執行此上下文中的operations
- 與feed和fetch相關:
_unfeedable_tensors
:set,定義不能feed的tensors_unfetchable_ops
:set,定義不能fetch的ops_handle_feeders
:dict( tensor handle placeholder => tensor dtype )_handle_readers
:dict( tensor handle => 它的read op )_handle_movers
:dict( tensor handle => 它的move op )_handle_deleters
:dict( tensor handle => 它delete op )
- 圖需要:
_seed
:當前圖內使用的隨機種子_collections
:dict( collection name => collection ),相當於圖中的一塊緩存,每個collection可看成一個list,可以存任何對象_functions
:定義圖內使用中的一些函數_container
:資源容器resource container,用來存儲跟蹤stateful operations,如:variables,queues_registered_ops
:注冊的所有操作
- 程序運行需要:
_finalized
:布爾值,真表示Graph屬性都已確定,不再做修改_lock
:保證讀取Graph某些屬性(如:_version
)時盡可能線程安全
- TensorFlow框架需要:
_graph_def_version
:圖定義的版本
- 其他:
_building_function
:該圖是否表示一個函數_colocation_stack
:保存共位設置(其他op都與指定op共位)的棧
對外屬性:
tf.Graph.version
,也就是self._version
,記錄最新的節點version,即圖中最大op id,但是與GraphDef的version無關tf.Graph.graph_def_versions
,也就是self._graph_def_versions
,GraphDef版本,定義在tensorflow/tensorflow/core/framework/graph.prototf.Graph.seed
,也就是self._seed
,此圖內使用的隨機種子tf.Graph.building_function
,也就是self._building_function
tf.Graph.finalized
,也就是self._finalized
,表明組裝圖階段是否完成
1.1.2 Graph的主要方法
tf.graph.__init__()
創建一個新的空的圖。
tf.Graph.as_default()
返回一個使得當前圖成為默認圖的上下文管理器
這個方法應該在你想要在相同的過程中創建多圖時被使用。為了方便,一個全局默認圖已經被提供,如果你沒有明確創建一個新的圖,所有的操作將會被添加進這張圖。當你使用這個方法時,請使用 with 關鍵字明確在接下來的代碼塊范圍內創建的操作應該加進這張圖。
默認圖是當前線程的一個屬性,如果你創建了一個新的線程,並且希望在這個線程里使用默認圖,你必須在這個線程的函數里明確添加 with g.as_default():
下面的代碼示例(相對於上述解釋)是等價的:
# 1. Using Graph.as_default(): g = tf.Graph() with g.as_default(): c = tf.constant(5.0) assert c.graph is g # 2. Constructing and making default: with tf.Graph().as_default() as g: c = tf.constant(5.0) assert c.graph is g
返回: 一個用於將當前圖作為默認圖的上下文管理器
tf.Graph.as_graph_def(from_version=None, add_shapes=False)
返回一個表示這個圖的序列化的 GraphDef。
這個序列化的 GraphDef 可以被引入另一個圖(使用 import_graph_def())或者使用 C++ Session API。
這個方法是線程安全的。
參數:
from_version: 可選的,如果被設定,將返回一個 GraphDef,它包含僅從這張圖的版本屬性有了給定值后加入這張圖的節點(nodes),表明包括的節點version(即op id)的范圍,from_version
之前的節點都不要。
add_shapes: 如果是真值,給每個帶有輸出推斷圖形的結點添加一個_output_shapes列表屬性。(每個節點都要添加輸出tensors的形狀信息到_output_shapes
)
返回: 一個 GraphDef協議緩沖區(protocol buffer)
引起的錯誤: ValueError: 如果 graph_def 太大
tf.Graph.as_graph_element(obj, allow_tensor=True, allow_operation=True)
該獲取信息的方法實際上完成了一個驗證加轉換的工作,給定一個obj,看它能否對應到圖中的元素,可以是一個operation,也可以是一個tensor,如果對應,則以operation或tensor的身份返回它自己。該方法可以被多個線程同時調用。
參數:
(1) obj
:可以是一個Tensor對象,或一個Operation對象,或tensor名,或operation名,或其他對象;
(2) allow_tensor
:真表示obj可以是tensor;
(3) allow_operation
:真表示obj可以是operation
get系列方法,可被多個線程同時調用:
tf.Graph.get_operation_by_name(name):根據名字獲取某個operation
tf.Graph.get_tensor_by_name(name):根據名字獲取某個tensor
tf.Graph.get_operations():獲取所有operations
判斷是否可feed或可fetch
tf.Graph.is_feedable(tensor)
tf.Graph.is_fetchable(tensor_or_op)
設置不可feed或不可fetch
tf.Graph.prevent_feeding(tensor)
tf.Graph.prevent_fetching(op)
tf.Graph.finalize()
結束這個圖,使它只讀
在調用g.finalize()后,不能向g添加任何新的操作。當這個圖在多線程間共享時,為了保證沒有操作添加到這個圖,可以調用這個方法,例如當使用一個 QueueRunner時
tf.Graph.finalized
如果這個圖已經結束,它為真
tf.Graph.control_dependencies(control_inputs)
返回一個明確控制依賴(control dependencies)的上下文管理器
使用 with 關鍵字明確所有在上下文內創建的操作應該在control_inputs上有控制依賴。例如:
with g.control_dependencies([a, b, c]): # `d` and `e` will only run after `a`, `b`, and `c` have executed. d = ... e = ...
control_dependencies()的多重調用可以嵌套,在這種情況下,基於所有活動的上下文中的 control_inputs 的聯合,一個新的 Operation 將擁有控制依賴。
with g.control_dependencies([a, b]): # Ops constructed here run after `a` and `b`. with g.control_dependencies([c, d]): # Ops constructed here run after `a`, `b`, `c`, and `d`.
你可以通過None來清除控制依賴。
with g.control_dependencies([a, b]): # Ops constructed here run after `a` and `b`. with g.control_dependencies(None): # Ops constructed here run normally, not waiting for either `a` or `b`. with g.control_dependencies([c, d]): # Ops constructed here run after `c` and `d`, also not waiting for either `a` or `b`.
注:控制依賴應用於那些在上下文內建立的操作。很少在上下文中使用使用一個 op 或者 tensor 時不添加一個控制依賴。下面的例子解釋了這一點:
#tf.Graph.control_dependencies(control_inputs) # 錯誤代碼 def my_func(pred, tensor): t = tf.matmul(tensor, tensor) with tf.control_dependencies([pred]): # 乘法操作(op)沒有創建在該上下文,所以沒有被加入依賴控制 return t # 正確代碼 def my_func(pred, tensor): with tf.control_dependencies([pred]): # 乘法操作(op)創建在該上下文,所以被加入依賴控制中 #執行完pred之后再執行matmul return tf.matmul(tensor, tensor)
參數:
control_inputs:一個 Operation 或者 Tensor 對象列表,它上下文內定義的操作被運行前被執行或者計算。也可以為None來清除控制依賴。
返回:
一個明確在上下文內所有操作的控制依賴的上下文管理器
引起的錯誤:
TypeError: 如果 control_inputs 不是一個 Operation 或者Tensor 對象的列表。
tf.Graph.devide(device_name_or_function)
返回一個明確默認設備的使用的上下文管理器
device_name_or_function 參數可以是一個設備名字符串,一個設備函數或者None:
如果這個參數是一個設備名字符串,所有在此上下文構建的操作將被指派給是這個名稱的設備,除非它被一個嵌套的 device() 上下文所覆蓋
如果這個參數是函數,它將被視為一個從 Operation 對象到設備名字符串的函數,並且每次一個新的Operation被創建時都會被調用。這個Operation將會被指派給這個帶有返回名的設備
如果是None,所有從封閉的上下文調用的device()將會被忽略
想了解關於設備名字符串的合法語法,請在DeviceNameUtils中查閱相關文檔
示例:
with g.device('/gpu:0'): # All operations constructed in this context will be placed # on GPU 0. with g.device(None): # All operations constructed in this context will have no # assigned device. # Defines a function from `Operation` to device string. def matmul_on_gpu(n): if n.type == "MatMul": return "/gpu:0" else: return "/cpu:0" with g.device(matmul_on_gpu): # All operations of type "MatMul" constructed in this context # will be placed on GPU 0; all other operations will be placed # on CPU 0.
注:設備范圍可能會被op包裝器或者其他庫代碼所覆蓋。例如,一個變量指定操作 v.assign()必須被tf.Variable v所托管(colocated),並且不兼容的設備將被忽略。
參數:
device_name_or_function:在上下文中使用的設備名或函數
返回值:
一個為新創建的操作明確默認設備的上下文管理器
tf.Graph.name_scope(name)
返回為操作創建分層的上下文管理器
一張圖維持一個命名空間棧,在當前上下文生命期,一個 with name_scope(…):聲明將一個新的名稱壓棧。
name參數將解釋如下
一個字符串(沒有以’/’結尾)將創建一個新的命名空間,在此空間name會附加到所有在上下文里創建的操作的前綴。如果name之前被用過,可以通過調用self.unique_name(name)使它變為獨特的name
一個從之前a with g.name_scope(…) as scope: 聲明捕獲的空間將被視為一個絕對命名空間,這使得它有可能代表現有的空間
一個None值或者空字符串將會重置當前命名空間到最高層(空的)命名空間
示例:
# tf.Graph.name_scope(name) # 一個圖中包含有一個名稱范圍的堆棧,在使用name_scope(...)之后,將壓(push)新名稱進棧中, #並在下文中使用該名稱 with tf.Graph().as_default() as g: c = tf.constant(5.0, name="c") assert c.op.name == "c" c_1 = tf.constant(6.0, name="c") assert c_1.op.name == "c_1" # Creates a scope called "nested" with g.name_scope("nested") as scope: nested_c = tf.constant(10.0, name="c") assert nested_c.op.name == "nested/c" # Creates a nested scope called "inner". with g.name_scope("inner"): nested_inner_c = tf.constant(20.0, name="c") assert nested_inner_c.op.name == "nested/inner/c" # Create a nested scope called "inner_1". with g.name_scope("inner"): nested_inner_1_c = tf.constant(30.0, name="c") assert nested_inner_1_c.op.name == "nested/inner_1/c" # Treats `scope` as an absolute name scope, and # switches to the "nested/" scope. with g.name_scope(scope): nested_d = tf.constant(40.0, name="d") assert nested_d.op.name == "nested/d" with g.name_scope(""): e = tf.constant(50.0, name="e") assert e.op.name == "e"
空間本身的命名可以被with g.name_scope(…) as scope:所捕獲,它在變量空間內存有空間的命名。這個結果可以在一個空間內命名代表執行操作的所有結果的操作(This value can be used to name an operation that represents the overall result of executing the ops in a scope)。
參數:
name: 一個空間的命名
返回:
一個設置(install)name為新的命名空間的上下文管理器
一張圖實例支持任意多個被命名標志的“集合”,為了方便,當建立一個很大的圖時。集合能存儲一組相關的對象。例如,tf.Variable為所有在圖建立期間創建的變量使用一個集合(名為tf.GraphKeys.VARIABLES)。調用者可以通過指定一個新的命名來定義額外的集合。
tf.Graph.add_to_collection(name,value)
將value值存入給定name的collection
注意collections不是sets,所以有可能將同一個值多次加入一個collection。
參數:
names: collection的關鍵字(key)。 GraphKeys類包含許多標准集合名稱
value:加入collection的值
tf.Graph.add_to_collections(names,value)
將value存入給定的names的collections中
注意collections不是sets,所以有可能將同一個值多次加入一個collection。這個函數保證忽略names中的重復值,但不會檢查names中任意一個collection的value里已存在的成員。(This function makes sure that duplicates in names are ignored, but it will not check for pre-existing membership of value in any of the collections in names.)
names可以是可迭代的,但是如果它是個字符串,它將被視為一個單集合名
參數:
names: 要加入的collections的關鍵字(keys)。GraphKeys類包含許多標准集合名稱
value:加入collections的值
tf.Graph.get_collection(name,scope=None)
返回給定名稱集合的值的列表
這個方法不同於get_collection_ref(),后者總是返回真正的集合(如果存在),因此每次被調用時,它總是返回一個新的列表。(This is different from get_collection_ref() which always returns the actual collection list if it exists in that it returns a new list each time it is called.)
參數:
name:集合的關鍵字。例如 GraphKeys類含有許多類的標准命名
scope:(可選)如果提供了,結果過濾列表僅包含那些沒有名稱屬性總不返回,名稱(name)屬性匹配使用re.match得到的條目。如果一個 空間(scope)被提供,那么choice或者re.match意味着一個沒有特殊前綴標記過濾器的空間。
返回:
給定名稱的集合中值的列表,或者空表(當沒有值加入集合)。這個列表包含一些按順序的值,在這個順序下它們被收集。
1.2 占位符(placeholder)
tf.placeholder(dtype, shape=None, name=None)
此函數可以理解為形參,用於定義過程,在執行的時候再賦具體的值。
參數:
- dtype:數據類型。常用的是tf.float32,tf.float64等數值類型
- shape:數據形狀。默認是None,就是一維值,也可以是多維,比如[2,3], [None, 3]表示列是3,行不定
- name:名稱。
1.3 常量(constant)
1.3.1 Constant Value Tensors
tensorflow基本的數據類型有14種,在這幾本數據類型上,給與了3種主要的包裝類型,分別是Constants value tensors,Sequence和Random Tensors。
數據類型 | Python 類型 | 描述 |
---|---|---|
DT_FLOAT |
tf.float32 |
32 位浮點數. |
DT_DOUBLE |
tf.float64 |
64 位浮點數. |
DT_INT64 |
tf.int64 |
64 位有符號整型. |
DT_INT32 |
tf.int32 |
32 位有符號整型. |
DT_INT16 |
tf.int16 |
16 位有符號整型. |
DT_INT8 |
tf.int8 |
8 位有符號整型. |
DT_UINT8 |
tf.uint8 |
8 位無符號整型. |
DT_STRING |
tf.string |
可變長度的字節數組.每一個張量元素都是一個字節數組. |
DT_BOOL |
tf.bool |
布爾型. |
DT_COMPLEX64 |
tf.complex64 |
由兩個32位浮點數組成的復數:實數和虛數. |
DT_QINT32 |
tf.qint32 |
用於量化Ops的32位有符號整型. |
DT_QINT8 |
tf.qint8 |
用於量化Ops的8位有符號整型. |
DT_QUINT8 |
tf.quint8 |
用於量化Ops的8位無符號整型. |
tf.constant(value,dtype = None,shape = None,name = "Constant")
這是最基礎的一個,參數種dtype建議增加,若不增加,tensorflow會默認加一個,程序可能會有bug,shape對value進行一次形狀變化,需要傳入一個python列表;name為圖中保存的名字。
示例:
a =tf.constant(np.arange(10),dtype = tf.float32,shape = [2,5],name = "constant")
tf.zeros(shape,dtype = tf.float32,name = None)
tf.ones(shape,dtype = tf.float32,name = None)
這兩個函數差不多,一個生成全為0的常量,一個生成全為1的常量,默認的格式tf.float32.
tf.zeros_like(tensor,dtype=None,name = None)
tf.ones_like(tensor,dtype=None,name = None)
這倆函數基本一樣,需要傳入一個tensor,導出一個同結構全0/1的tensor,數據類型可能變化。
tf.fill(dims,value,name = None)
dims的參數其實和shape是一樣的,這個函數生成了一個以dims(列表)為結構,value為值的一個tensor。
1.3.2 Sequences
生成一維tensor,主要由兩個函數,分別是linspace 和 range,用法有稍微的區別。
tf.linspace(start,stop,num,name = None )
生成一個一維tensor,以start為開始,以stop為結束,這兩個數都必須是float,num為總個數(int)。 print(tf.linspace(0.0,10.0,11).eval()) 結果為 [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
tf.range(start,limit,delta = 1,name = "range")
生成一個一維tensor,以start為開始,最大不超過limit,間隔為delta。建議使用整數,浮點數可能會出現精度問題。
1.3.3 Random Tensors
生成常用的多維隨機數。包括幾個生成器和一個種子設置方法。
tf.random_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)
tf.truncated_normal(shape,mean = 0,stddev = 1,dtype = tf.float32,seed = None,name = None)
這兩函數都是生成正態隨機數,區別是truncated在生成隨機數后,如果隨機數在兩倍標准差之外,就重新生成一個,直到生成最終結果。參數中shape為一個列表,表示形狀,mean和stddev分別標書均值和標准差,seed為隨機數種子。和其他python隨機語法一樣,固定seed以后,生成的隨機數將不變。
tf.random.uniform(shape,minval = 0.0,maxval = 1.0,dtype = tf.float32,seed = None)
這個函數生成從0到1中平均分布的數值。
tf.random_shuffle(value,seed = None,name = None)
傳入一個tensor,然后將這個rensor進行隨機洗牌。
1.4 變量(variable)
當訓練模型時,用變量來存儲和更新參數。變量包含張量 (Tensor)存放於內存的緩存區。建模時它們需要被明確地初始化,模型訓練后它們必須被存儲到磁盤。這些變量的值可在之后模型訓練和分析時被加載。
當創建一個變量時,你將一個張量作為初始值傳入構造函數Variable()。 TensorFlow提供了一系列操作符來初始化張量,初始值是常量或是隨機值。在初始化時需要指定張量的shape,變量的shape通常是固定的,但TensorFlow提供了高級的機制來重新調整。
Tensor、Op對象不可變(immutable)。.Variable()構造方法創建Variable對象,包含Session.run()調用中可持久化的可變張量值。
我們通過tf.Variable構造一個variable添加進圖中,Variable()構造函數需要變量的初始值(是一個任意類型、任意形狀的tensor),這個初始值指定variable的類型和形狀。通過Variable()構造函數后,此variable的類型和形狀固定不能修改了,但值可以用assign方法修改。
如果想修改variable的shape,可以使用一個assign op,令validate_shape=False.
通過Variable()生成的variables就是一個tensor,可以作為graph中其他op的輸入。另外,Tensor類重載的所有操作符都被轉載到此variables中,所以可以通過對變量調用方法,將節點添加到圖形中。
1.4.1 新建與初始化
tf.Variable
tf.Variable.__init__(initial_value=None, trainable=True, collections=None, validate_shape=True, caching_device=None, name=None, variable_def=None, dtype=None)
新變量添加到collections 列出的圖集合中,默認添加到 [GraphKeys.VARIABLES]。
如果 trainable 是True,變量也添加到圖集合 GraphKeys.TRAINABLE_VARIABLES.
這個構造器創建了兩個操作節點,一個變量操作和一個賦值操作,用於將初始值賦給變量。
- initial_value: 一個Tensor,或者可以轉化為Tensor的Python對象,這是變量的初始值,可以傳入數值,列表,numpy數組,tf的tensor等。初始值必須指定shape除非validate_shape 被設置為False。但是對一個變量來說,最好使用固定結構的變量。
- trainable: 如果是True,變量也默認添加到GraphKeys.TRAINABLE_VARIABLES,collections默認添加到圖的[GraphKeys.VARIABLES] 中。這是很多優化器類使用的默認變量列表。
在tf.Variables的類中有add,sub,dtype、name,get_shape()等屬性和方法
Variable() 構造器需要一個初始值,可以是任意類型和shape 的Tensor。初始值定義了變量的type和shape。構造完成之后,變量的type和shape 是固定的。可以使用assign 方法來修改變量的值。
如果你想修改變量的shape,你必須使用assign 操作,並且 validate_shpe=False。
初始化器
tf.variables_initilizer(var_list,name = "nint")
tf.global_variables_initializer()
前者對指定的一個變量列表進行初始化,后者則對所有的變量進行初始化。
注意:這里的初始化只是在計算圖中定義了這樣的一個節點,這個節點的運算是將變量進行初始化,所以在實際計算中,還是要調用sess.run(initializer),才能真正的完成初始化過程。
查詢變量
tf.gloable_variables()
顯示圖中所有的變量。
tf.trainable_variables()
顯示圖中可訓練的變量。
初始值生成函數
(1)生成tensor:
tf.ones | tf.zeros
tf.ones(shape,type=tf.float32,name=None)
用法類似,都是產生尺寸為shape的張量(tensor)
示例:
tf.zeros([2, 3], int32)
tf.ones_like | tf.zeros_like
tf.ones_like(tensor,dype=None,name=None)
tf.zeros_like(tensor,dype=None,name=None)
新建一個與給定的tensor類型大小一致的tensor,其所有元素為1和0
示例:
tensor=[[1, 2, 3], [4, 5, 6]]
x = tf.ones_like(tensor)
tf.fill
tf.fill(shape,value,name=None)
創建一個形狀大小為shape的tensor,其初始值為value
示例:
tf.fill([2,3],2)
tf.constant
tf.constant(value,dtype=None,shape=None,name=’Const’)
創建一個常量tensor,按照給出value來賦值,可以用shape來指定其形狀。value可以是一個數,也可以是一個list。
如果是一個數,那么這個常亮中所有值的按該數來賦值。
如果是list,那么len(value)一定要小於等於shape展開后的長度。賦值時,先將value中的值逐個存入。不夠的部分,則全部存入value的最后一個值。
示例:
v4_1 = tf.constant([1, 2, 3, 4, 5, 6, 7])
v4_2 = tf.constant(-1.0, shape=[2, 3])
(2)生成序列
tf.linspace | tf.range
tf.linspace(start,stop,num,name=None)
tf.range(start,limit=None,delta=1,name=’range’)
這兩個放到一起說,是因為他們都用於產生等差數列,不過具體用法不太一樣。
tf.linspace在[start,stop]范圍內產生num個數的等差數列。不過注意,start和stop要用浮點數表示,不然會報錯
tf.range在[start,limit)范圍內以步進值delta產生等差數列。注意是不包括limit在內的。
(3)生成隨機數:
tf.random_normal | tf.truncated_normal | tf.random_uniform
tf.random_normal(shape,mean=0.0,stddev=1.0,dtype=tf.float32,seed=None,name=None)
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_uniform(shape,minval=0,maxval=None,dtype=tf.float32,seed=None,name=None)
這幾個都是用於生成隨機數tensor的。尺寸是shape
random_normal: 正太分布隨機數,均值mean,標准差stddev
truncated_normal:截斷正態分布隨機數,均值mean,標准差stddev,不過只保留[mean-2*stddev,mean+2*stddev]范圍內的隨機數
random_uniform:均勻分布隨機數,范圍為[minval,maxval]
tf.random_shuffle
tf.random_shuffle(value,seed=None,name=None)
沿着value的第一維進行隨機重新排列
示例:
v8_5 = tf.random_shuffle([[1,2,3],[4,5,6],[6,6,6]], seed=134, name="v8_5")
tf.random_crop(value, size, seed=None, name=None)
tf.multinomial(logits, num_samples, seed=None, name=None)
tf.random_gamma(shape, alpha, beta=None, dtype=tf.float32, seed=None, name=None)
tf.set_random_seed(seed)
tf.get_variable
tf.get_variable(name, shape=None, dtype=dtypes.float32, initializer=None,
regularizer=None, trainable=True, collections=None,
caching_device=None, partitioner=None, validate_shape=True,
custom_getter=None)
如果在該命名域中之前已經有名字=name的變量,則調用那個變量;如果沒有,則根據輸入的參數重新創建一個名字為name的變量。
initializer: 初始化工具,有tf.zero_initializer, tf.ones_initializer, tf.constant_initializer, tf.random_uniform_initializer,tf.random_normal_initializer,tf.truncated_normal_initializer等。
initializer(初始化)
tf.constant_initializer(value=0, dtype=tf.float32)
tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
tf.truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
tf.random_uniform_initializer(minval=0, maxval=None, seed=None, dtype=tf.float32)
tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32)
tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)
tf.ones_initializer(dtype=tf.float32, partition_info=None)
tf.orthogonal_initializer(gain=1.0, dtype=tf.float32, seed=None)
tf.get_variable與tf.variable的對比
相同點:
通過兩函數創建變量的過程基本一樣,且tf.variable函數調用時提供的維度(shape)信息以及初始化方法(initializer)的參數和tf.Variable函數調用時提供的初始化過程中的參數基本類似。
不同點:
兩函數指定變量名稱的參數不同,對於tf.Variable函數,變量名稱是一個可選的參數,通過name="v"的形式給出。而tf.get_variable函數,變量名稱是一個必填的參數,它會根據變量名稱去創建或者獲取變量。
tf.get_variable在創建變量時會查名字,如果給的名字在之前已經被別的變量占用,則會報錯,不會創建相應變量。而tf.variable並不進行檢查,如果有重復,則自動的修改名字,加上數字來進行區別。所以從這來看要想共享變量並不能通過使用相同的名字來調用多次 tf.get_variable 和 tf.variable 做到。
1、使用tf.Variable時,如果檢測到命名沖突,系統會自己處理。使用tf.get_variable()時,系統不會處理沖突,而會報錯。
import tensorflow as tf
w_1 = tf.Variable(3, name="w_1")
w_2 = tf.Variable(1, name="w_1")
print w_1.name
print w_2.name
# 輸出
# w_1:0
# w_1_1:0
*********************************************************************
import tensorflow as tf
w_1 = tf.get_variable(name="w_1", initializer=1)
w_2 = tf.get_variable(name="w_1", initializer=2)
# 錯誤信息
# ValueError: Variable w_1 already exists, disallowed. Did
# you mean to set reuse=True in VarScope?
當我們需要共享變量的時候,需要使用tf.get_variable()。在其他情況下,這兩個的用法是一樣的。
2、由於tf.Variable() 每次都在創建新對象,所有reuse=True 和它並沒有什么關系。對於get_variable(),來說,如果已經創建的變量對象,就把那個對象返回,如果沒有創建變量對象的話,就創建一個新的。
import tensorflow as tf
with tf.variable_scope("scope1"):
w1 = tf.get_variable("w1", shape=[])
w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
w1_p = tf.get_variable("w1", shape=[])
w2_p = tf.Variable(1.0, name="w2")
print(w1 is w1_p, w2 is w2_p)
# 輸出
# True False
tf.trainable_variables
返回所有可訓練的變量。
在創造變量(tf.Variable, tf.get_variable 等操作)時,都會有一個trainable的選項,表示該變量是否可訓練。這個函數會返回圖中所有trainable=True的變量。
tf.get_variable(…), tf.Variable(…)的默認選項是True, 而 tf.constant(…)只能是False。
各種優化器類使用這個集合作為默認的變量列表去優化。
tf.all_variables
返回的是所有變量的列表
1.4.2 變量的保存與讀取
tensorflow使用Saver類進行變量的保存和讀取,系統的變量將被保存到checkpoints中,point我簡單的理解成快照,其本質是tensorflow使用二進制保存的變量名到變量值的map映射文件。
1.5 tf.Operation
Operation是teansorflow 中操作節點的抽象化,有0個或多個輸入和0個或多個輸出,在運行后使用tf.get_default_session().run(op)進行運行,或者op.run(),這是前面的簡化調用方式。主要屬性與方法如下:
tf.Operation.name 獲取名稱
tf.Operation.type 獲取屬性
tf.Operation.inputs 獲取輸入值
tf.Operation.control_inputs 獲取輸入依賴值
tf.Operation.outputs 獲取輸出值
tf.Operation.device 獲取操作設備
tf.Operation.graph 獲取graph
tf.Operation.run(feed_dict=None, session=None) 如果op傳入的是placeholder 對象,則需要使用feed_dict參數進行傳入。
tf.Operation.get_attr(name) 獲取op該屬性的對應值。
1.6 tf.Tensor
tensor代表一個operation的結果。從tensorflow 的實際運行來說,tensor是operation一個輸出的句柄,但是tensor所引用的並不持有具體的值,而是保持一個計算過程,在session調用的時候,可以使用這個計算過程來得到最終的結果。在python api中主要由兩方面基本的內容:
(1)一個tensor可以被傳遞到另外一個operation,從而形成最終的數據流。這樣,session中只需要對最后一個計算進行編碼即可。
(2)在session調用最終的圖之后,可以使用session.run()或者t.eval()對tensor的值進行計算。
常用的屬性和函數如下:
tf.Tensor.dtype 數據類型
tf.Tensor.name tensor名稱
tf.Tensor.value_index 在input中的index
tf.Tensor.graph 返回圖名
tf.Tensor.op 返回操作名
tf.Tensor.consumers() 返回使用了這個tensorflow 的op列表
tf.Tensor.eval(feed_dict=None, session=None) 需要在session中使用,可以事先使用placeholder
tf.Tensor.get_shape() 獲取形狀
tf.Tensor.set_shape(shape) 設置形狀
tf.Tensor.device 獲取計算的設備
3、正則
在損失函數上加上正則項是防止過擬合的一個重要方法。
tensorflow中對參數使用正則項分為兩步:
1. 創建一個正則方法(函數/對象)
2. 將這個正則方法(函數/對象),應用到參數上
3.1 創建正則方法函數
tf.contrib.layers.l1_regularizer(scale, scope=None)
返回一個用來執行L1正則化的函數,函數的簽名是func(weights)。
參數:
- scale: 正則項的系數.
- scope: 可選的scope name
tf.contrib.layers.l2_regularizer(scale, scope=None)
返回一個執行L2正則化的函數.
tf.contrib.layers.sum_regularizer(regularizer_list, scope=None)
返回一個可以執行多種(個)正則化的函數.意思是,創建一個正則化方法,這個方法
是多個正則化方法的混合體.
參數:
regularizer_list: regulizer的列表。
3.2 應用正則化方法到參數上
tf.contrib.layers.apply_regularization(regularizer, weights_list=None)
參數:
- regularizer:就是我們上一步創建的正則化方法
- weights_list: 想要執行正則化方法的參數列表,如果為None的話,就取GraphKeys.WEIGHTS中的weights.
5、控制
tf.control_dependencies()
control_dependencies(self, control_inputs)
只有在 control_inputs被執行以后,上下文管理器中的操作才會被執行。例如:
- with tf.control_dependencies([a, b, c]):
- # `d` and `e` will only run after `a`, `b`, and `c` have executed.
- d = ...
- e = ...
- c= tf.no_op(name='train') # tf.no_op;什么也不做
只有[a,b,c]都被執行了才會執行d和e操作,這樣就實現了流的控制。
也能通過參數None清除控制依賴,例如:
- with g.control_dependencies([a, b]):
- # Ops constructed here run after `a` and `b`.
- with g.control_dependencies(None):
- # Ops constructed here run normally, not waiting for either `a` or `b`.
- with g.control_dependencies([c, d]):
- # Ops constructed here run after `c` and `d`, also not waiting
- # for either `a` or `b`.
注意:
控制依賴只對那些在上下文環境中建立的操作有效,僅僅在context中使用一個操作或張量是沒用的。
6、Saver
我們經常在訓練完一個模型之后希望保存訓練的結果,這些結果指的是模型的參數,以便下次迭代的訓練或者用作測試。Tensorflow針對這一需求提供了Saver類。
- Saver類提供了向checkpoints文件保存和從checkpoints文件中恢復變量的相關方法。Checkpoints文件是一個二進制文件,它把變量名映射到對應的tensor值 。
- 只要提供一個計數器,當計數器觸發時,Saver類可以自動的生成checkpoint文件。這讓我們可以在訓練過程中保存多個中間結果。例如,我們可以保存每一步訓練的結果。
- 為了避免填滿整個磁盤,Saver可以自動的管理Checkpoints文件。例如,我們可以指定保存最近的N個Checkpoints文件。
Class tf.train.Saver
保存和恢復變量
最簡單的保存和恢復模型的方法是使用tf.train.Saver 對象。構造器給graph的所有變量,或是定義在列表里的變量,添加save 和 restore ops。saver 對象提供了方法來運行這些ops,定義檢查點文件的讀寫路徑。
檢查點是專門格式的二進制文件,將變量name 映射到 tensor value。檢查checkpoin 內容最好的方法是使用Saver 加載它。
Savers 可以使用提供的計數器自動計數checkpoint 文件名。這可以是你在訓練一個模型時,在不同的步驟維持多個checkpoint。例如你可以使用 training step number 計數checkpoint 文件名。為了避免填滿硬盤,savers 自動管理checkpoint 文件。例如,你可以最多維持N個最近的文件,或者沒訓練N小時保存一個checkpoint.
通過傳遞一個值給可選參數 global_step ,你可以編號checkpoint 名字。
- saver.save(sess, 'my-model', global_step=0) ==>filename: 'my-model-0'
- saver.save(sess, 'my-model', global_step=1000) ==>filename: 'my-model-1000'
另外,Saver() 構造器可選的參數可以讓你控制硬盤上 checkpoint 文件的數量。
- max_to_keep: 表明保存的最大checkpoint 文件數。當一個新文件創建的時候,舊文件就會被刪掉。如果值為None或0,表示保存所有的checkpoint 文件。默認值為5(也就是說,保存最近的5個checkpoint 文件)。
- keep_checkpoint_every_n_hour: 除了保存最近的max_to_keep checkpoint 文件,你還可能想每訓練N小時保存一個checkpoint 文件。這將是非常有用的,如果你想分析一個模型在很長的一段訓練時間內是怎么改變的。例如,設置 keep_checkpoint_every_n_hour=2 確保沒訓練2個小時保存一個checkpoint 文件。默認值10000小時無法看到特征。
注意,你仍然必須調用save() 方法去保存模型。傳遞這些參數給構造器並不會自動為你保存這些變量。
一個定期保存的訓練程序如下這樣:
- #Create a saver
- saver=tf.train.Saver(...variables...)
- #Launch the graph and train, saving the model every 1,000 steps.
- sess=tf.Session()
- for step in xrange(1000000):
- sess.run(...training_op...)
- if step % 1000 ==0:
- #Append the step number to the checkpoint name:
- saver.save(sess,'my-model',global_step=step)
除了checkpoint 文件之外,savers 還在硬盤上保存了一個協議緩存,存儲最近的checkpoint 列表。這用於管理 被編號的checkpoint 文件,並且通過latest_checkpoint() 可以很容易找到最近的checkpoint 的路徑。協議緩存存儲在緊挨checkpoint 文件的名為 'checkpoint' 的文件中。
如果你創建了幾個savers,你可以調用save() 指定協議緩存的文件名。
tf.train.Saver.__init__(var_list=None, reshape=False, shared=False, max_to_keep=5, keep_checkpoint_every_n_hour=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None)
創建一個Saver
構造器添加操作去保存和恢復變量。
var_list 指定了將要保存和恢復的變量。它可以傳dict 或者list
- 變量名字的dict: key 是將用來在checkpoint 文件中存儲和恢復的變量的名稱。
- 變量的list: 變量的 op name
可選參數 reshape ,如果為True,允許從保存文件中恢復一個不同shape 的變量,但元素的數量和type一致。如果你reshap 了一個變量而又想從一個舊的文件中恢復,這是非常有用的。
可選參數 shared,如果為True,通知每個設備上共享的checkpoint.
tf.train.Saver.save(sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix='meta', write_meta_graph=True)
保存變量
這個方法運行通過構造器添加的操作。它需要啟動圖的session。被保存的變量必須經過了初始化。
方法返回新建的checkpoint 文件的路徑。路徑可以直接傳給restore() 進行調用。
參數:
- sess: 用於保存變量的Session
- save_path: checkpoint 文件的路徑。如果saver 是共享的,這是共享checkpoint 文件名的前綴。
- global_step: 如果提供了global step number,將會追加到 save_path 后面去創建checkpoint 的文件名。可選參數可以是一個Tensor,一個name Tensor或integer Tensor.
返回值:
一個字符串:保存變量的路徑。如果saver 是被共享的,字符串以'-?????-of-nnnnn' 結尾。'nnnnn' 是共享的數目。
保存變量
用tf.train.Saver() 創建一個Saver 來管理模型中的所有變量。
如果你不給tf.train.Saver() 傳入任何參數,那么server 將處理graph 中的所有變量。其中每一個變量都以變量創建時傳入的名稱被保存。
tf.train.Saver.restore(sess, save_path)
恢復之前保存的變量
這個方法運行構造器為恢復變量所添加的操作。它需要啟動圖的Session。恢復的變量不需要經過初始化,恢復作為初始化的一種方法。
save_path 參數是之前調用save() 的返回值,或調用 latest_checkpoint() 的返回值。
參數:
- sess: 用於恢復參數的Session
- save_path: 參數之前保存的路徑