動手學深度學習(tensorflow)---學習筆記整理(一、預備知識篇)

學習視頻來源爲b站動手學深度學習系列視頻:https://space.bilibili.com/209599371/channel/detail?cid=23541

由於上述視頻爲MXNet/Gluon框架編寫,所以代碼部分參考網站爲:https://trickygo.github.io/Dive-into-DL-TensorFlow2.0/#/

本文主要是學習該系列視頻所整理筆記,可能很多內容直接原文整理,如有需要可以去上述兩個網站進行學習。

深度學習是什麼?

這個問題不同人有不同的理解,我粗淺的理解就是,模擬人腦的結構對數據進行觀察,並發現數據潛在的特徵。

這樣說可能不太形象,舉個例子:一個桶裏有鐵屑和木屑,機器學習是通過一種方法來進行分離,例如SVM思想,往桶裏倒入水,就可以將木屑和鐵屑從二維平面映射到三維空間,從而實現分離;而深度學習例如人去觀察鐵屑和木屑的不同,然後提取出特徵,然後快速識別出來(人一個一個把鐵屑挑出來的感覺,當然計算機模擬的人腦挑的速度足夠快)。

以上是個人理解,歡迎大家糾正等。

tensorflow基礎:

這裏其實課程中主要講述了一些實踐,詳細原理沒怎麼說。

引入tensorflow庫,並命名爲tf。(可以不命名,但是命名比較方便,試試就能體會出來)

import tensorflow as tf

輸出tensorflow版本

print(tf.__version__)

然後定義一個tf矩陣/張量

x = tf.constant([1,2,3,4,5,6,7,8,9,10,11,12])

這裏解釋下張量的概念,類型名Tensor,如果大家使用過numpy或者pandas可以發現,創建或者讀取的矩陣是這兩個褲特有的類型,同樣tensorflow的變量也有一個特殊的稱呼,叫做張量,可以理解成tensorflow的特有結構,其本質就是個矩陣...不太理解就當成矩陣就好。(下屬可能說張量/矩陣時直接以矩陣代替)

張量/矩陣的改變形狀/維度

X = tf.reshape(x,(3,4))
#輸出結果Tensor("Reshape:0", shape=(3, 4), dtype=int32)
#上面的x.reshape((3, 4))也可寫成x.reshape((-1, 4))或x.reshape((3, -1))。
# 由於x的元素個數是已知的,這裏的-1是能夠通過元素個數和其他維度的大小推斷出來的。

(x原本爲[1,2,3,4,5,6,7,8,9,10,11,12],現在改變成3*4的矩陣了)

創建0、1矩陣

#創建0向量,緯度爲2*3*4
x=tf.zeros((2,3,4))
print(x)
#創建1向量,緯度爲2*3*4
x=tf.ones((2,3,4))
print(x)

創建自定義矩陣

x = tf.constant([1,2,3,4,5,6,7,8,9,10,11,12])

輸出矩陣形狀/維度

print(x.shape)

張量類型轉換

#cast數據類型轉換
Y = tf.cast(Y, tf.float32)

按元素進行矩陣加減乘除以及指數運算等

#元素加法
print("加法",X+Y)
#元素乘法除法
print("乘法",X*Y)
print("除法",X/Y)
#按元素元素指數運算
Y = tf.cast(Y, tf.float32)
print("指數",tf.exp(Y))

(元素類型不同是沒法操作的,使用前先用cast函數統一類型喲~~)

廣播機制:當對兩個形狀不同的tensor按元素運算時,可能會觸發廣播(broadcasting)機制:先適當複製元素使這兩個tensor形狀相同後再按元素運算。(copy自上述引文)

假設A和B分別是3行1列和1行2列的矩陣,如果要計算A + B,那麼A中第一列的3個元素被廣播(複製)到了第二列,而B中第一行的2個元素被廣播(複製)到了第二行和第三行。如此,就可以對2個3行2列的矩陣按元素相加。

矩陣乘法、連結等操作

#矩陣乘法
print("矩陣除法",tf.matmul(X, tf.transpose(Y)))
#矩陣連結,二維的包括行連結和列連結,由axis決定,高維度的可以其他維度連結
print("行連結",tf.concat([X,Y],axis = 0))
print("列連結",tf.concat([X,Y],axis = 1))

判斷兩矩陣是否相等

#判斷兩個元素是否相等
print(tf.equal(X,Y))

張量元素求和

sess = tf.Session()
print("張量",tf.reduce_sum(X))
print("張量值",sess.run(tf.reduce_sum(X)))

注意!輸出張量和輸出張量值是不一樣的,前者輸出的是這個張量的各種信息,例如張量名稱、形狀、類型等,後者即爲張量的值,也就是矩陣的值,上述一直輸出的都是張量,而不是張量值。本模塊進行輸出就可以發現區別了(本文編譯器爲pycharm,好像jupyter可以直接輸出張量值...)

按索引輸出

print("索引",sess.run(X[0:2]))
print("索引",sess.run(X[0:2][1]))
print("索引",sess.run(X[0:2][1][1]))

(自己動手輸出一下就知道多加[]是什麼意思了~很有趣)

修改矩陣數值

X = tf.Variable(X)
init = tf.global_variables_initializer()
sess.run(init)
#修改X變量,但是需要進行初始化才能進行操作
#修改某1,2位置數爲19
print(sess.run(X[1,2].assign(19)))
#修改第一列爲99
print(sess.run(X[1:2,:].assign(tf.ones(X[1:2,:].shape, dtype = tf.int32)*99)))

(此處需要了解一些tensorflow的初始化機制,本文就不具體介紹了,其實我目前也不是很瞭解哈~都是報錯後纔想起來(小聲音嘟嘟,我比較菜~))

關於內存開銷的相關理論:

在前面的例子裏我們對每個操作新開內存來存儲運算結果。舉個例子,即使像Y = X + Y這樣的運算,我們也會新開內存,然後將Y指向新內存。爲了演示這一點,我們可以使用Python自帶的id函數:如果兩個實例的ID一致,那麼它們所對應的內存地址相同;反之則不同。(copy自引文)

驗證程序:

#內存開銷
X = tf.Variable(X)
Y = tf.cast(Y, dtype=tf.int32)
before = id(Y)
Y = Y + X
print(id(Y) == before)
#輸出爲否

兩種避免的寫法:

如果想指定結果到特定內存,我們可以使用前面介紹的索引來進行替換操作。在下面的例子中,我們先通過zeros_like創建和Y形狀相同且元素爲0的tensor,記爲Z。接下來,我們把X + Y的結果通過[:]寫進Z對應的內存中。

Z = tf.Variable(tf.zeros_like(Y))
before = id(Z)
Z[:].assign(X + Y)
print(id(Z) == before)
#輸出爲真

實際上,上例中我們還是爲X + Y開了臨時內存來存儲計算結果,再複製到Z對應的內存。如果想避免這個臨時內存開銷,我們可以使用assign_{運算符全名}函數。

before = id(X)
X.assign_add(Y)
print(id(X) == before)
#輸出爲真

tensorflow和numpy的轉換

其實通過發現num的數據類型和tensorflow的數據類型雖然不一樣,其本質都是矩陣(包括pandas),所以有特定的函數進行類型轉化

np轉tf

P = np.ones((2,3))
D = tf.constant(P)

tf轉np

np.array(D)

自動求梯度

神經網絡中最不可缺少的就是自動求梯度這一方法~(懂的應該深有體會...)

設y=2*x*x,其導數應爲4x。

求解過程如下:

import tensorflow as tf
sess = tf.Session()
#新建一個矩陣
x = tf.reshape(tf.Variable([1,2,3,4], dtype=tf.float32),(4,1))
print(x)
with tf.GradientTape() as t:
    t.watch(x)
    y = 2 * tf.matmul(tf.transpose(x), x)

dy_dx = t.gradient(y, x)
#如果不初始化是無法run的
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(dy_dx))

再寫一個z、y公式詳見代碼內

with tf.GradientTape(persistent=True) as g:
    g.watch(x)
    y = x * x
    z = y * y
    dz_dx = g.gradient(z, x)  # 108.0 (4*x^3 at x = 3)
    dy_dx = g.gradient(y, x)  # 6.0
print(sess.run(dz_dx),sess.run(dy_dx))

教程中還提供一個方法,我沒怎麼看懂。。。掛個代碼,大家自己研究研究吧

#控制流求梯度
def f(a):
    b = a * 2
    while tf.norm(b) < 1000:
        b = b * 2
    if tf.reduce_sum(b) > 0:
        c = b
    else:
        c = 100 * b
    return c

查詢函數文檔相關操作

經常我們使用各種框架或者函數,不瞭解參數、返回值或者含義等就可以進行查詢其文檔來了解具體含義

當我們想知道一個模塊裏面提供了哪些可以調用的函數和類的時候,可以使用dir函數。下面我們打印dtypesrandom模塊中所有的成員或屬性。(copy自引文)

print(dir(tf.dtypes))
print(dir(tf.random))

想了解某個函數或者類的具體用法時,可以使用help函數。讓我們以ones函數爲例,查閱它的用法。(copy自引文)

print(help(tf.ones))

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章