1. 程式人生 > >TensorFlow學習系列(二):形狀和動態維度

TensorFlow學習系列(二):形狀和動態維度

這篇教程是翻譯Morgan寫的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.

intfloat不能被使用,因為當你定義你的圖時,你實際上是不知道 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實戰群。