TensorFlow學習系列(二):形狀和動態維度
目錄
這篇教程主要去理解一些關於Tensorflow的維度形狀概念,希望在後續的教程中能幫你節約除錯程式的時間 :) 。
那麼什麼是張量呢?
簡單的說,張量就是一個擁有 n 維度的陣列,並且其中的值都擁有相同的型別,比如整型,浮點型,布林型等等。
張量可以用我們所說的形狀來描述:我們用列表(或元祖)來描述我們的張量的每個維度的大小,例如:
一個 n 維度的張量可以表示為:(D_0, D_1, D_2, …, D_n-1)
一個 * W x H * 大小的張量(一般我們成為矩陣):(W, H)
一個尺度是 W 的張量(一般我們稱之為向量):(W, )
一個簡單的標量(或者與之等價的):()或者(1, )
注意:* D_,W,H **都是整型。
關於一維張量的一些注意:我們不可能通過觀察 TF 中的向量形狀來確定向量是行向量還是列向量。實際上這並不重要。有關更多資訊,請檢視這個Stackoverflow關於Numpy堆疊溢位的回答(這大致與TensorFlow表示法相同):
在 TF 中,一個張量如下表述:
my_tensor = tf.constant(0., shape=[6,3,7])
print(my_tensor) # -> Tensor("Const_1:0" , shape=(6, 3, 7), dtype=float32)
我們可以發現,一個張量應該包含如下內容:
一個名字,它用於鍵值對的儲存,用於後續的檢索:Const: 0
一個形狀描述, 描述資料的每一維度的元素個數:(6,3,7)
資料型別,比如 float32
現在,我們來談這篇文章的重點:TensorFlow中張量的兩種形狀!一種是靜態形狀,另一種是動態形狀。
靜態形狀和動態形狀
靜態形狀
靜態維度是指當你在建立一個張量或者由操作推匯出一個張量時,這個張量的維度是確定的。它是一個元祖或者列表。
TensorFlow將盡最大努力去猜測不同張量的形狀(在不同操作之間),但是它不會總是能夠做到這一點。特別是如果您開始用未知維度定義的佔位符執行操作(例如,當你使用批操作時)。
要在程式碼中使用靜態形狀(訪問/更改),你將使用Tensor本身的不同函式,並在名稱中使用下劃線:
注意:靜態形狀是非常有用的,特別是當你除錯的時候,你可以使用 print
函式將張量形狀進行列印,從而判斷自己的設計是否正確。
動態形狀
當你在執行你的圖時,動態形狀才是真正用到的。這種形狀是一種描述原始張量在執行過程中的一種張量。
如果你定義了一個沒有標明具體維度的佔位符,即用None
表示維度,那麼當你將值輸入到佔位符時,這些無維度就是一個具體的值,並且任何一個依賴這個佔位符的變數,都將使用這個值。
如果在程式碼中操作動態形狀(訪問/更改),你將使用主作用域中的不同函式,並且名稱中沒有下劃線:
注意:當你要處理一些動態維度時,那麼使用動態形狀是非常方便的。
一個真實的使用案例:RNN
讓我們需要去構建一個RNN時,我們將輸入一個動態的形狀,這個形狀將去處理任何長度的輸入資料。
在訓練階段,我們將使用動態佔位符來定義批處理大小 batch_size
,然後我們使用 TensorFlow API 來建立一個 LSTM 網路。那麼,你最終將得到如下這樣的:
你現在需要去初始化一個狀態,比如 init_state = cell.zero_state(batch_size, tf.float32) ...
。
但是,批處理大小 batch_size
具體應該等於多少呢?而且我們想要它是一個動態的數值,那麼我們應該怎麼選擇呢?如果你閱讀原始碼,那麼就會發現 TensorFlow 允許很多不同的資料型別,如下:
Args:
batch_size: int, float, or unit Tensor representing the batch size.
int
和float
不能被使用,因為當你定義你的圖時,你實際上是不知道 batch_size
的具體大小是多少的。這很重要。
最有意思的地方是最後一種型別: unit Tensor representing the batch size
,如果你在看原始文件,那麼你會發現 unit Tensor
就是一個零維度的張量,也就是說,它就是一個標量。那麼,你是怎麼得到標量張量呢?
如果你在靜態形狀上嘗試得到,你們如下:
my_tensor = tf.placeholder(tf.float32)
batch_size = my_tensor.get_shape()[0] # Dimension(None)
print(batch_size)
# -> ?
batch_size
將返回 Dimension(None)
型別,即輸出是 ?
。這個型別只能用作佔位符的維度。
其實,你實際想做的是在圖中使用這個動態引數 batch_size
,那麼你必須使用動態形狀,如下:
my_tensor = tf.placeholder(tf.float32)
batch_size = tf.shape(my_tensor)[0] # <tf.Tensor 'strided_slice:0' shape=() dtype=int32>
print(batch_size)
# -> Tensor("strided_slice:0", shape=(), dtype=int32)
你看,此時 batch_size
在 TensorFlow 中是零維度的張量型別來描述的。
總結
在除錯時,使用靜態形狀
除了除錯,都是用動態形狀,尤其是當你在吹未定義的維度時。
注意:在使用RNN API時,TensorFlow非常在意將初始狀態設定為 zero_state
,但是為什麼需要手動定義這種方式?不解。
你可能希望在執行圖時,自己控制 init_state
的初始化狀態。 那麼你實際上可以使用 feed_dict
來為圖中的任何變數提供初始變數,如下:
sess.run(encoder_final_state, feed_dict={
my_placeholder: new_input,
init_state: previous_encoder_final_state
})
現在,你可以動手寫一下了。So easy!
References:
如果覺得內容有用,幫助多多分享哦 :)
長按或者掃描如下二維碼,關注 “CoderPai” 微訊號(coderpai)。新增底部的 coderpai 小助手,新增小助手時,請備註 “演算法” 二字,小助手會拉你進演算法群。如果你想進入 AI 實戰群,那麼請備註 “AI”,小助手會拉你進AI實戰群。