1. 程式人生 > >TensorFlow低階API(二)—— 張量

TensorFlow低階API(二)—— 張量

矩陣 ima ast class n-1 when 如果能 err session

簡介

正如名字所示,TensorFlow這一框架定義和運行涉及張量的計算。張量是對矢量和矩陣向潛在的更高維度的泛化。TensorFlow在內部將張量表示為基本數據類型的n維數組。

在編寫TensorFlow程序時,您操作和傳遞的主要對象是 tf.Tensor。tf.Tensor對象表示一個部分定義的計算,最終會生成一個值。TensorFlow程序首先會構建一個tf.Tensor對象圖,詳細說明如何基於其它可用張量計算每個張量,然後運行運行改圖的某些部分以獲得期望的結果。

tf.Tensor具有以下屬性:

  • 數據類型(例如float32、int32或string)
  • 形狀

張量中的每個元素都具有相同的數據類型,且該數據類型一定是已知的。形狀,即張量的維數和每個維度的大小,可能只有部分已知。如果其輸入的形狀也完全已知,則大多數操作會生成形狀完全已知的張量,但在某些情況下,只能在執行圖時獲得張量的形狀。

有些類型的張量有點特殊,TensorFlow指南的其它部分有所介紹。以下是主要特殊張量:

  • tf.Variable
  • tf.constant
  • tf.placeholder
  • tf.SparseTensor

除了tf.Variable以外,張量的值是不變的,這意味著對於單個執行任務,張量只是一個值。然而,兩次評估同一張量可能會返回不同的值。例如,該張量是從磁盤讀取數據的結果,或是生成隨機數的結果。

tf.Tensor對象的階是它本身的維數。階的同義詞包括:秩、等級或n維。請註意,TensorFlow中的階與數學中矩陣的階並不是同一個概念。如下表所示,TensorFlow中的每個階都對應一個不同的數學實例:

數學實例
0 標量(只有大小)
1 矢量(大小和方向)
2 矩陣(數據表)
3 3 階張量(數據立體)
n n 階張量(自行想象)

0階

以下摘要演示了創建0階變量的過程:

1 mammal = tf.Variable("Elephant", tf.string)
2 ignition = tf.Variable(451, tf.int16)
3 floating = tf.Variable(3.14159265359, tf.float64)
4 its_complicated = tf.Variable(12.3 - 4.85j, tf.complex64)

註意:字符串在 TensorFlow 中被視為單一項,而不是一連串字符。TensorFlow 可以有標量字符串,字符串矢量,等等。

1階

要創建1階tf.Tensor對象,您可以傳遞一個項目列表作為初始值。例如:

1 mystr = tf.Variable(["Hello"], tf.string)
2 cool_numbers  = tf.Variable([3.14159, 2.71828], tf.float32)
3 first_primes = tf.Variable([2, 3, 5, 7, 11], tf.int32)
4 its_very_complicated = tf.Variable([12.3 - 4.85j, 7.5 - 6.23j], tf.complex64)

更高階

2階tf.Tensor對象至少包含一行和一列:

1 mymat = tf.Variable([[7],[11]], tf.int16)
2 myxor = tf.Variable([[False, True],[True, False]], tf.bool)
3 linear_squares = tf.Variable([[4], [9], [16], [25]], tf.int32)
4 squarish_squares = tf.Variable([ [4, 9], [16, 25] ], tf.int32)
5 rank_of_squares = tf.rank(squarish_squares)
6 mymatC = tf.Variable([[7],[11]], tf.int32)

同樣,更高階的張量由一個n維數組組成。例如,在圖像處理過程中,會使用許多4階張量,維度對應批次大小、圖像寬度、圖像高度和顏色通道。

1 my_image = tf.zeros([10, 299, 299, 3])  # batch x height x width x color

獲取tf.Tensor對象的階

要確定tf.Tensor對象的階,需要調用 tf.rank 方法。例如,以下方法會程序化的確定上一節中所定義的tf.Tensor的階:

1 r = tf.rank(my_image)
2 # After the graph runs, r will hold the value 4.

引用tf.Tensor切片

由於tf.Tensor是n維單元數組,因此要訪問tf.Tensor中的某一單元,需要指定n個索引。

0階張量(標量)不需要索引,因為其本身就是單一數字。

對於1階張量(矢量),可以通過傳遞一個索引訪問某個數字:

1 my_scalar = my_vector[2]

請註意,如果想從矢量中動態的選擇元素,那麽在 [ ] 內傳遞的索引本身可以是一個標量tf.Tensor。

對於2階及以上的張量,情況更為有趣。對於2階tf.Tensor,傳遞兩個數字會如預期般返回一個標量:

1 my_scalar = my_matrix[1, 2]

而傳遞一個數字則會返回矩陣子矢量,如下所示:

1 my_row_vector = my_matrix[2]
2 my_column_vector = my_matrix[:, 3]

符號 是python切片語法,意味“不要觸碰該維度”。這對更高階的張量來說很有用,可以幫助訪問其子矢量,子矩陣,甚至其它子張量。

形狀

張量的形狀是每個維度中元素的數量。TensorFlow在圖的構建中自動推理形狀。這些推理的形狀可能具有已知階或未知階。如果階已知,則每個維度的大小可能已知或未知。

TensorFlow文件編制中通過三種符號約定來描述張量維度:階、形狀和維數。下表闡述了  三者如何相互關聯:

形狀維數示例
0 [] 0-D 0 維張量。標量。
1 [D0] 1-D 形狀為 [5] 的 1 維張量。
2 [D0, D1] 2-D 形狀為 [3, 4] 的 2 維張量。
3 [D0, D1, D2] 3-D 形狀為 [1, 4, 3] 的 3 維張量。
n [D0, D1, ... Dn-1] n 維 形狀為 [D0, D1, ... Dn-1] 的張量。

形狀可以通過整形Python列表/元組或者 tf.TensorShape 表示。

獲取tf.Tensor對象的形狀

可以通過兩種方法獲取tf.Tensor的形狀。在構建圖的時候,詢問有關張量形狀的已知信息通常很有幫助。可以通過查看shape屬性(屬於tf.Tensor對象)獲取這些信息。該方法會返回一個 TensorShape 對象,這樣可以方便地表示部分指定的形狀(因為在構建圖的時候,並不是所有形狀都完全已知)。

也可以獲取一個將在運行時表示另一個tf.Tensor的完全指定形狀的tf.Tensor。為此,可以調動 tf.shape 操作。如此以來,您可以構建一個圖,通過構建其它取決於輸入tf.Tensor的動態形狀的張量來控制張量的形狀。

例如,以下代碼展示了如何創建大小與給定矩陣中的列數相同的零矢量

1 zeros = tf.zeros(my_matrix.shape[1])

改變tf.Tensor對象的形狀

張量的元素數量是其所有形狀大小的乘積。標量的元素數量永遠是1。由於通常有許多不同的形狀具有相同數量的元素,因此如果能改變tf.Tensor的形狀並使其元素固定不變通常會很方便。為此,可以使用 tf.reshape

以下示例演示了如何重構張量:

 1 rank_three_tensor = tf.ones([3, 4, 5])
 2 matrix = tf.reshape(rank_three_tensor, [6, 10])  # Reshape existing content into
 3                                                  # a 6x10 matrix
 4 matrixB = tf.reshape(matrix, [3, -1])  #  Reshape existing content into a 3x20
 5                                        # matrix. -1 tells reshape to calculate
 6                                        # the size of this dimension.
 7 matrixAlt = tf.reshape(matrixB, [4, 3, -1])  # Reshape existing content into a
 8                                              #4x3x5 tensor
 9 
10 # Note that the number of elements of the reshaped Tensors has to match the
11 # original number of elements. Therefore, the following example generates an
12 # error because no possible value for the last dimension will match the number
13 # of elements.
14 yet_another = tf.reshape(matrixAlt, [13, 2, -1])  # ERROR!

數據類型

除維度外,張量還具有數據類型。如需數據類型的完整列表,請參閱 tf.Dtype 頁面。

一個tf.Tensor只能有一種數據類型。但是,可以將任意數據結構序列化為 string 並將其存儲在tf.Tensor中。

可以將tf.Tensor從一種數據類型轉型到另一種(通過 tf.cast ):

1 # Cast a constant integer tensor into floating point.
2 float_tensor = tf.cast(tf.constant([1, 2, 3]), dtype=tf.float32)

要檢查tf.Tensor的數據類型,請使用 Tensor.dtype 屬性。

用Python對象創建一個tf.Tensor時,可以選擇指定數據類型。如果不指定數據類型,TensorFlow會選擇一個可以表示您的數據的數據類型。TensorFlow會將Python整數轉型為 tf.int32,並將Python浮點型轉型為 tf.float32。此外,TensorFlow使用Numpy在轉換至數組時使用的相同規則。

評估張量

計算圖構建完畢後,您可以運行生成特定tf.Tensor的計算並獲取分配給它們的值。這對於程序調試通過非常有幫助,也是TensorFlow的大部分功能正常運行所必需的。

評估張量最簡單的方法是使用 Tensor.eval 方法。例如:

1 constant = tf.constant([1, 2, 3])
2 tensor = constant * constant
3 print(tensor.eval())

eval 方法僅在默認tf.Session處於活躍狀態時才起作用。例如:

1 sess = tf.Session()
2 
3 constant = tf.constant([1, 2, 3])
4 tensor = constant * constant
5 print(tensor.eval(session = sess))

Tensor.eval 會返回一個與張量相同的Numpy數組。

有時沒法在沒有背景信息的情況下評估tf.Tensor,因為它的值可能取決於無法獲取的動態信息。例如,在沒有為placehloder提供之的情況下,無法評估依賴於placeholder的張量:

1 p = tf.placeholder(tf.float32)
2 t = p + 1.0
3 t.eval()  # This will fail, since the placeholder did not get a value.
4 t.eval(feed_dict={p:2.0})  # This will succeed because we‘re feeding a value
5                            # to the placeholder.

請註意,可以提供任何tf.Tensor,而不僅僅是占位符。

其它模型構造可能會使評估tf.Tensor變得較為復雜。TensorFlow無法直接評估在函數內部或控制流結構內部定義的tf.Tensor。如果tf.Tensor取決於隊列中的值,那麽只有在某個項加入隊列後才能評估tf.Tensor;否則。評估將被擱置。在處理隊列時,請先調用 tf.train.start_queue_runners,在評估任何tf.Tensor。

輸出張量

出於調試目的,您可能需要輸出tf.Tensor的值。雖然 tfdbg 提供高級調試支持,但TensorFlow也有一個操作可以直接輸出tf.Tensor的值。

請註意,輸出tf.Tensor時很少使用以下模式:

1 t = <<some tensorflow operation>>
2 print(t)  # This will print the symbolic tensor when the graph is being built.
3           # This tensor does not have a value in this context.

上述代碼會輸出tf.Tensor對象(表示延遲計算),而不是其值。TensorFlow提供了 tf.Print 操作,該操作會返回其第一個張量參數(保持不變),同時輸出第二個參數傳遞的tf.Tensor集合。

要正確使用tf.Print,必須使用其返回值。例如:

1 t = <<some tensorflow operation>>
2 tf.Print(t, [t])  # This does nothing
3 t = tf.Print(t, [t])  # Here we are using the value returned by tf.Print
4 result = t + 1  # Now when result is evaluated the value of `t` will be printed.

在評估result時,會評估所有影響result的元素。由於result依靠t,而評估t會導致輸出其輸入(t的舊值),所以系統會輸出t。

參考鏈接:https://tensorflow.google.cn/guide/tensors#rank

TensorFlow低階API(二)—— 張量