天天看點

Tensorflow快餐教程(2) - 标量運算

Tensorflow的Tensor意為張量。一般如果是0維的數組,就是一個資料,我們稱之為标是Scalar;1維的數組,稱為向量Vector;2維的數組,稱為矩陣Matrics;3維及以上的數組,稱為張量Tensor。

在機器學習中,用途最廣泛的是向量和矩陣的運算。這也是我們學習中的第一個難關。

不過,這一節我們先打标量的基礎。

上節我們學過,Tensorflow的運作需要一個Session對象。下面代碼中所用的sess都是通過

sess = tf.Session()           

擷取的Session對象,以下就都省略不寫了。

标量Scalar

标量是指隻有一個數字的結構。

我們嘗試将一個整數賦給一個Tensorflow的常量,看看是什麼效果:

>>> a10 = 1     >>> b10 = tf.constant(a10)     >>> print(b10)     Tensor("Const_6:0", shape=(), dtype=int32)     >>> sess.run(b10)     1           

我們可以看到,tf.constant(a10)生成了一個shape為空的,類型為int32的張量。

Tensorflow是一個經過資料類型優化的高性能系統,是以對于資料類型的要求比較高。

比如我們想對上面的标量b10進行求正弦值的運算,就會得到下面的錯誤,sin運算隻支援浮點數和複數類型:

>>> b11 = tf.sin(b10)     Traceback (most recent call last):       File "<stdin>", line 1, in <module>       File "/usr/lib/python3.6/site-packages/tensorflow/python/ops/gen_math_ops.py", line 6862, in sin         "Sin", x=x, name=name)       File "/usr/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py", line 609, in _apply_op_helper         param_name=input_name)       File "/usr/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py", line 60, in _SatisfiesTypeConstraint         ", ".join(dtypes.as_dtype(x).name for x in allowed_list)))     TypeError: Value passed to parameter 'x' has DataType int32 not in list of allowed values: float16, bfloat16, float32, float64, complex64, complex128           

後面我們還會多次遇到資料類型不符合要求,以至于無法運算的錯誤。

是以我們首先要學習下Tensorflow的資料類型。

Tensorflow的資料類型

Tensorflow主要支援以下資料類型

  • 整型:
    • tf.int8: 8位帶符号整數
    • tf.uint8: 8位無符号整數
    • tf.int16: 16位帶符号整數
    • tf.int32: 32位帶符号整數
    • tf.int64: 64位帶符号整數
  • 浮點型:
    • tf.float32: 32位浮點數
    • tf.float64: 64位浮點數
  • 複數:
    • tf.complex64: 64位複數
    • tf.complex128: 128位複數

在Tensorflow的很多運算中,都支援通過dtype=的方式來指定資料類型。

例:

>>> b01 = tf.constant(1,dtype=tf.uint8)     >>> print(b01)     Tensor("Const_7:0", shape=(), dtype=uint8)     >>> b02 = tf.constant(1,dtype=tf.float64)     >>> print(b02)     Tensor("Const_8:0", shape=(), dtype=float64)     >>> sess.run(b01)     1     >>> sess.run(b02)     1.0           

Tensor到某類型資料的轉換

通過tf.constant函數,我們可以将資料轉換成Tensor。同樣,Tensorflow也提供了Tensor到各種資料類型的轉換函數。

例,将Tensor轉換成tf.int32:

>>> b03 = tf.to_int32(b02)     >>> print(b03)     Tensor("ToInt32:0", shape=(), dtype=int32)     >>> sess.run(b03)     1     >>> b04 = sess.run(b03)     >>> print(b04)     1           

從上面代碼可以看到,b03 run的結果就是一個整數,不是Tensor.

類似的函數還有tf.to_int64, tf.to_float, tf.to_double等。

定義這麼多函數太麻煩了,還有一個通用的轉換函數tf.cast. 格式為:tf.cast(Tensor, 類型名)。

>>> b05 = tf.cast(b02, tf.complex128)     >>> sess.run(b05)     (1+0j)           

飽和轉換

如果是将大類型如int64轉成小類型int16,tf.cast轉換可能會産生溢出。這在機器學習的計算中是件可怕的事情。在這種情況下,我們就需要使用飽和類型轉換saturate_cast來保駕護航。

比如我們要把65536轉換成tf.int8類型:

>>> b06 = tf.constant(65536,dtype=tf.int64)     >>> print(b06)     Tensor("Const_9:0", shape=(), dtype=int64)     >>> sess.run(b06)     65536     >>> b07 = tf.saturate_cast(b06,tf.int8)     >>> sess.run(b07)     127           

标量算術運算

标量Tensor常量可以進行算術運算。本質上是調用tf.add, tf.sub, tf.mul, tf.truediv, tf.mod等重載函數。

>>> d01 = tf.constant(1)     >>> d02 = tf.constant(2)     >>> d_add = d01 + d02     >>> print(d_add)     Tensor("add:0", shape=(), dtype=int32)     >>> d_sub = d01 - d02     >>> print(d_sub)     Tensor("sub:0", shape=(), dtype=int32)     >>> d_mul = d01 * d02     >>> print(d_mul)     Tensor("mul:0", shape=(), dtype=int32)     >>> d_div = d01 / d02     >>> print(d_div)     Tensor("truediv:0", shape=(), dtype=float64)     >>> d_mod = d01 % d02     >>> print(d_mod)     Tensor("mod:0", shape=(), dtype=int32)     >>> d_minus = -d01     >>> print(d_minus)     Tensor("Neg:0", shape=(), dtype=int32)           

對于除法多說兩句,Tensor有兩種除法,一種是"/",另一種是"//"。"/"是浮點除法,對應的是tf.truediv,而"//"是計算整除,對應tf.floordiv。

>>> d_div = d01 / d02     >>> print(d_div)     Tensor("truediv:0", shape=(), dtype=float64)     >>> d_div2 = d01 // d02     >>> print(d_div2)     Tensor("floordiv:0", shape=(), dtype=int32)           

标量邏輯運算

對于>, <, >=, <=等關系,都會生成一個需要Session來運算的Tensor對象。隻有==是例外,它會立即傳回這兩個Tensor是否是同一對象的結果。

>>> d11 = d01 > d02     >>> d12 = d01 < d02     >>> d13 = d01 == d02     >>> d14 = d01 >= d02     >>> d15 = d01 <= d02     >>> print(d11)     Tensor("Greater_1:0", shape=(), dtype=bool)     >>> print(d12)     Tensor("Less:0", shape=(), dtype=bool)     >>> print(d13)     False     >>> print(d14)     Tensor("GreaterEqual:0", shape=(), dtype=bool)     >>> print(d15)     Tensor("LessEqual:0", shape=(), dtype=bool)     >>> d11 = d01 > d02           

常用标量數學函數

首先還是強調一下注意類型,比如整形,一定要先轉換成浮點型才能進行sqrt,sin等數學函數計算。

>>> d31 = tf.constant(100, dtype=tf.float64)     >>> d32 = tf.sqrt(d31)     >>> sess.run(d32)     10.0           

另外不要忘了,像sin, cos, tan這些函數是支援複數的哦。

>>> d40 = tf.constant(1+2j)     >>> d41 = tf.sin(d40)     >>> sess.run(d41)     (3.165778513216168+1.9596010414216063j)           

中間結果也可以不用Tensor儲存,直接用立即數,例:

>>> d42 = tf.cos(0.5+0.3j)     >>> sess.run(d42)     (0.917370851271881-0.14599480570180629j)           

常量、占位符和變量

前面我們主要使用立即數和常量。常量是通過tf.constant定義的,一旦定義就不能改變值的Tensor。如果要想改變Tensor的值,有兩種變法:一種是根本就不指派,先放個占位符;另一種是初始化成一個帶值的變量,将來再改變值。

下面簡單介紹一下占位符和變量。

placeholder占位符

在算法計算時,有很多公式需要的數值是需要從外部拿到的,随時替換的。這時候我們就可以用一個占位符來寫Tensor,需要計算時再把真資料通過feed_dict給填充進去就可以。

我們來看個例子:

>>> d50 = tf.placeholder(tf.float32, name ="input1")     >>> d51 = tf.sin(d50)     >>> sess.run(d51, feed_dict={d50: 0.2})     0.19866933           

d50開始隻用個placeholder,這樣的話是沒有辦法通過之前不加feed_dict參數的sess.run來運作的。通過指定feed_dict={d50: 0.2},我們就用資料替換掉了placeholder,就可以正常運作了。

變量

變量與占位符不同的一點是,變量在使用之前需要做初始化。

初始化不但要在變量定義時寫,還要調用相應的函數在使用前執行才可以。

我們還是舉例說明:

>>> d60 = tf.Variable(1, dtype=tf.float32, name='number1')     >>> d61 = tf.tan(d60)     >>> init_op = tf.global_variables_initializer()     >>> sess.run(init_op)     >>> sess.run(d61)     1.5574077           

在使用變量之前,我們可以一次性調用tf.global_variables_initializer函數去初始化所有變量,并且通過Session去執行。在此之後才能使用變量。

變量初始化之後,就可以通過assign函數來賦新值,例:

>>> d62 = d60.assign(d60 * 2)     >>> sess.run(d62)     2.0     >>> sess.run(d61)     -2.1850398           

小結

小結一下,這節主要介紹了資料類型,标量常用的計算函數,還有使用占位符和變量的方法。

下一節我們正式開始線性代數之旅,走進向量、矩陣和張量。