TensorFlow2.0(2):數學運算

 

 

 

注:本系列全部博客將持續更新併發布在github上,您能夠經過github下載本系列全部文章筆記文件。javascript

 

1 基本運算:(+、-、*、/、//、%)

 

基本運算中全部實例都如下面的張量a、b爲例進行:css

In [1]:
import tensorflow as tf
a = tf.random.uniform([2, 3], minval=1, maxval=6,dtype=tf.int32)
b = tf.random.uniform([2, 3], minval=1, maxval=6,dtype=tf.int32)
In [3]:
a
Out[3]:
<tf.Tensor: id=3, shape=(2, 3), dtype=int32, numpy=
array([[1, 4, 5],
       [5, 1, 4]])>
In [4]:
b
Out[4]:
<tf.Tensor: id=7, shape=(2, 3), dtype=int32, numpy=
array([[1, 3, 5],
       [3, 5, 2]])>
 

(1)加(+)html

In [6]:
tf.add(a,b)  # 經過add方法執行加操做
Out[6]:
<tf.Tensor: id=12, shape=(2, 3), dtype=int32, numpy=
array([[ 2,  7, 10],
       [ 8,  6,  6]])>
In [8]:
a + b  # 也能夠經過操做符進行
Out[8]:
<tf.Tensor: id=16, shape=(2, 3), dtype=int32, numpy=
array([[ 2,  7, 10],
       [ 8,  6,  6]])>
 

(2)減(-)html5

In [10]:
tf.subtract(a,b)
Out[10]:
<tf.Tensor: id=18, shape=(2, 3), dtype=int32, numpy=
array([[ 0,  1,  0],
       [ 2, -4,  2]])>
In [11]:
a - b
Out[11]:
<tf.Tensor: id=20, shape=(2, 3), dtype=int32, numpy=
array([[ 0,  1,  0],
       [ 2, -4,  2]])>
 

(3)乘法(*)java

In [12]:
tf.multiply(a,b)
Out[12]:
<tf.Tensor: id=22, shape=(2, 3), dtype=int32, numpy=
array([[ 1, 12, 25],
       [15,  5,  8]])>
In [13]:
a * b
Out[13]:
<tf.Tensor: id=24, shape=(2, 3), dtype=int32, numpy=
array([[ 1, 12, 25],
       [15,  5,  8]])>
 

(4)除法(/)node

In [15]:
tf.divide(a,b)
Out[15]:
<tf.Tensor: id=28, shape=(2, 3), dtype=float64, numpy=
array([[1.        , 1.33333333, 1.        ],
       [1.66666667, 0.2       , 2.        ]])>
In [16]:
a/b
Out[16]:
<tf.Tensor: id=32, shape=(2, 3), dtype=float64, numpy=
array([[1.        , 1.33333333, 1.        ],
       [1.66666667, 0.2       , 2.        ]])>
 

(5)地板除法(//)python

In [17]:
tf.floor_div(a,b)
Out[17]:
<tf.Tensor: id=34, shape=(2, 3), dtype=int32, numpy=
array([[1, 1, 1],
       [1, 0, 2]])>
In [19]:
a // b
Out[19]:
<tf.Tensor: id=38, shape=(2, 3), dtype=int32, numpy=
array([[1, 1, 1],
       [1, 0, 2]])>
 

(6)取餘(%)jquery

In [54]:
tf.mod(b,a)
Out[54]:
<tf.Tensor: id=115, shape=(2, 2, 3), dtype=int32, numpy=
array([[[0, 1, 2],
        [0, 0, 2]],

       [[0, 1, 2],
        [0, 0, 2]]])>
In [55]:
b % a
Out[55]:
<tf.Tensor: id=117, shape=(2, 2, 3), dtype=int32, numpy=
array([[[0, 1, 2],
        [0, 0, 2]],

       [[0, 1, 2],
        [0, 0, 2]]])>
 

能夠看出,對於基本運算加(+)、減(-)、點乘(*)、除(/)、地板除法(//)、取餘(%),都是對應元素進行運算。linux

 

2 指數、開方、對數

 

(1)對數運算android

 

TensorFlow提供tf.math.log()方法來求對數,固然,求的是以天然常數$e$爲底的對數:

In [22]:
e = 2.71828183
a = tf.constant([e, e*e, e*e*e])
tf.math.log(a)
Out[22]:
<tf.Tensor: id=41, shape=(3,), dtype=float32, numpy=array([0.99999994, 2.        , 3.        ], dtype=float32)>
In [23]:
c = tf.fill([2,2],1.)
tf.math.log(c)
Out[23]:
<tf.Tensor: id=46, shape=(2, 2), dtype=float32, numpy=
array([[0., 0.],
       [0., 0.]], dtype=float32)>
 

注意:TensorFlow中沒有提供函數實現以其餘數值爲底的對數運算,例如$lo{g_2}8$, $lg100$。不過,咱們能夠經過其餘方式來求取,記得下面這個高中時學過的公式嗎:

 
$$lo{g_a}b = \frac{{lo{g_c}b}}{{lo{g_c}a}}$$
 

因此有:

In [24]:
f = tf.constant([[1., 9.], [16., 100.]])
g = tf.constant([[2., 3.], [2., 10.]])
In [25]:
tf.math.log(f) / tf.math.log(g)
Out[25]:
<tf.Tensor: id=52, shape=(2, 2), dtype=float32, numpy=
array([[0., 2.],
       [4., 2.]], dtype=float32)>
 

(2)指數運算

In [30]:
g = tf.constant([[2, 3], [2, 10]])
In [31]:
tf.pow(g, 2)
Out[31]:
<tf.Tensor: id=66, shape=(2, 2), dtype=int32, numpy=
array([[  4,   9],
       [  4, 100]])>
 

也能夠直接經過運算符來完成:

In [27]:
g ** 2
Out[27]:
<tf.Tensor: id=59, shape=(2, 2), dtype=int32, numpy=
array([[  4,   9],
       [  4, 100]])>
 

(3)開方

In [32]:
f = tf.constant([[1., 9.], [16., 100.]])
In [33]:
tf.sqrt(f)
Out[33]:
<tf.Tensor: id=69, shape=(2, 2), dtype=float32, numpy=
array([[ 1.,  3.],
       [ 4., 10.]], dtype=float32)>
 

天然常數$e$的指數運算:

In [34]:
d = tf.constant([[1.,2.],[3.,4.]])
In [35]:
tf.exp(d)
Out[35]:
<tf.Tensor: id=72, shape=(2, 2), dtype=float32, numpy=
array([[ 2.7182817,  7.389056 ],
       [20.085537 , 54.598152 ]], dtype=float32)>
 

注意:對數運算函數log()與指數運算函數在不一樣的模塊中。

在我看來,上面提到的指數運算與對數運算不在通知模塊以及沒有提供以其餘天然數爲底的對數運算,應該應該是TensorFlow中的遺留問題,但願可以在正式版中獲得修正。

 

3 矩陣相乘

In [36]:
import numpy as np
a = tf.constant(np.arange(6),shape=(2,3))
b = tf.constant(np.arange(6),shape=(3,2))
In [37]:
a
Out[37]:
<tf.Tensor: id=76, shape=(2, 3), dtype=int32, numpy=
array([[0, 1, 2],
       [3, 4, 5]])>
In [38]:
b
Out[38]:
<tf.Tensor: id=79, shape=(3, 2), dtype=int32, numpy=
array([[0, 1],
       [2, 3],
       [4, 5]])>
In [39]:
tf.matmul(a,b)
Out[39]:
<tf.Tensor: id=82, shape=(2, 2), dtype=int32, numpy=
array([[10, 13],
       [28, 40]])>
 

矩陣相乘也能夠經過符號來操做進行,用「@」表示:

In [41]:
a @ b
Out[41]:
<tf.Tensor: id=86, shape=(2, 2), dtype=int32, numpy=
array([[10, 13],
       [28, 40]])>
 

這裏的張量a和b都是二維的,但在實際應用中,數據每每高於二維,這時候怎麼應算呢?

In [42]:
a = tf.constant(np.arange(12),shape=(2,2,3))
b = tf.constant(np.arange(12),shape=(2,3,2))
In [43]:
a
Out[43]:
<tf.Tensor: id=90, shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]]])>
In [44]:
b
Out[44]:
<tf.Tensor: id=93, shape=(2, 3, 2), dtype=int32, numpy=
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])>
In [45]:
a @ b
Out[45]:
<tf.Tensor: id=96, shape=(2, 2, 2), dtype=int32, numpy=
array([[[ 10,  13],
        [ 28,  40]],

       [[172, 193],
        [244, 274]]])>
 

能夠看到,當高於二維的張量進行矩陣相乘時,最終的實現仍是二維矩陣相乘,只不過度成了多個二維矩陣,四維張量也是同樣的:

In [46]:
a = tf.constant(np.arange(24),shape=(2,2,2,3))
b = tf.constant(np.arange(24),shape=(2,2,3,2))
In [47]:
a @ b
Out[47]:
<tf.Tensor: id=104, shape=(2, 2, 2, 2), dtype=int32, numpy=
array([[[[  10,   13],
         [  28,   40]],

        [[ 172,  193],
         [ 244,  274]]],


       [[[ 550,  589],
         [ 676,  724]],

        [[1144, 1201],
         [1324, 1390]]]])>
 

4 Broadcasting機制

 

上面的全部實例中所用到的張量都是在維度數和形狀相同狀況下進行,那麼,當兩個張量維度數或者形狀不同時能不能進行運算呢?

In [48]:
a = tf.constant([1,2,3])
b = tf.constant(np.arange(12),shape=(2,2,3))
In [49]:
b
Out[49]:
<tf.Tensor: id=109, shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]]])>
In [50]:
a + b
Out[50]:
<tf.Tensor: id=111, shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 1,  3,  5],
        [ 4,  6,  8]],

       [[ 7,  9, 11],
        [10, 12, 14]]])>
In [51]:
a * b
Out[51]:
<tf.Tensor: id=113, shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 0,  2,  6],
        [ 3,  8, 15]],

       [[ 6, 14, 24],
        [ 9, 20, 33]]])>
 

能夠看到,一個一維的張量與一個三維張量進行運算是徹底沒有問題的,從運算結果上能夠看出,至關因而三維張量中的每一行數據與張量a進行運算,爲何能夠這樣運輸呢?這就得益於TensorFlow中的Broadcasting機制。

Broadcasting機制解除了只能維度數和形狀相同的張量才能進行運算的限制,當兩個數組進行算術運算時,TensorFlow的Broadcasting機制首先對維度較低的張量形狀數組填充1,從後向前,逐元素比較兩個數組的形狀,當逐個比較的元素值(注意,這個元素值是指描述張量形狀數組的值,不是張量的值)知足如下條件時,認爲知足 Broadcasting 的條件:

(1)相等

(2)其中一個張量形狀數組元素值爲1。

當不知足時進行運算則會拋出 ValueError: frames are not aligne 異常。算術運算的結果的形狀的每一元素,是兩個數組形狀逐元素比較時的最大值。

回到上面張量a與b相乘的例子,a的形狀是(3,),b的形狀是(2, 2, 3),在Broadcasting機制工做時,首先比較維度數,由於a的維度爲1,小於b的維度3,因此填充1,a的形狀就變成了(1,1,3),而後從最後端的形狀數組元素依次往前比較,先是就是3與3比,結果是相等,接着1與2相比,由於其中一個爲1,因此a的形狀變成了(1,2,3),繼續1與2比較,由於其中一個爲1,因此a的形狀變成了(2,2,3),a中的數據每一行都填充a原來的數據,也就是[1,2,3],而後在與b進行運算。

固然,在TensorFlow的Broadcasting機制運行過程當中,上述操做只是理論的,並不會真正的將a的形狀變成(2,2,3,),更不會將每一行填充[1,2,3],只是虛擬進行操做,真正計算時,依舊是使用原來的張量a。這麼作的好處是運算效率更高,也更節省內存。

再舉一些例子加深理解:

 
  • [ ] A:(2d array): 5 x 4
  • [ ] B:(1d array): 1
  • [ ] Result:(2d array): 5 x 4

  • [ ] A:(2d array): 5 x 4
  • [ ] B:(1d array): 4
  • [ ] Result:(2d array): 5 x 4

  • [ ] A:(3d array): 15 x 3 x 5
  • [ ] B:(3d array): 15 x 1 x 5
  • [ ] Result:(3d array): 15 x 3 x 5

  • [ ] A:(3d array): 15 x 3 x 5
  • [ ] B:(2d array): 3 x 5
  • [ ] Result:(3d array): 15 x 3 x 5

  • [ ] A:(3d array): 15 x 3 x 5
  • [ ] B:(2d array): 3 x 1
  • [ ] Result:(3d array): 15 x 3 x 5
 

一些反例(不知足 Broadcasting 規則 ):

 
  • [ ] A (1d array): 3
  • [ ] B (1d array): 4

  • [ ] A (2d array): 2 x 1
  • [ ] B (3d array): 8 x 4 x 3
 

5 範數

 

範數是泛函分析中的概念,指的是一種更寬泛的長度(距離)概念,只要知足非負、自反、三角不等式就能夠稱之爲距離。向量$v$的$p$範數可使用下面公式進行計算: $$|v|{|_p} = {\left[ {\sum\limits_{k = 1}^N {|{v_k}|p} } \right]^{1/p}}$$ 當$p = 1,2$時分別叫作1範數,2範數。除此之外,還有無窮範數: $$|v|{|_{ + \infty }} = \max (|v(i)|)$$ $$|v|{|_{ - \infty }} = \min (|v(i)|)$$

In [1]:
import tensorflow as tf
In [2]:
a = tf.constant([[1.,2.],[1.,2.]])
In [3]:
tf.norm(a, ord=1)  # 1範數
Out[3]:
<tf.Tensor: id=4, shape=(), dtype=float32, numpy=6.0>
In [4]:
tf.norm(a, ord=2)  # 2範數
Out[4]:
<tf.Tensor: id=10, shape=(), dtype=float32, numpy=3.1622777>
In [5]:
tf.norm(a)  # ord不指定時,默認是2
Out[5]:
<tf.Tensor: id=16, shape=(), dtype=float32, numpy=3.1622777>
 

咱們也能夠全手動地實現範數:

In [6]:
tf.sqrt(tf.reduce_sum(tf.square(a)))
Out[6]:
<tf.Tensor: id=21, shape=(), dtype=float32, numpy=3.1622777>
 

指定維度求範數:

In [7]:
tf.norm(a, ord=2, axis=0)
Out[7]:
<tf.Tensor: id=27, shape=(2,), dtype=float32, numpy=array([1.4142135, 2.828427 ], dtype=float32)>
In [8]:
tf.norm(a, ord=2, axis=1)
Out[8]:
<tf.Tensor: id=33, shape=(2,), dtype=float32, numpy=array([2.236068, 2.236068], dtype=float32)>
 

參考

相關文章
相關標籤/搜索