Deep MNIST for Experts解讀(一):概覽

Deep MNIST for Experts解讀(一)
https://www.tensorflow.org/get_started/mnist/pros


Tensorflow依賴於後端的高度優化的C++庫,爲了與C++庫交互,需要session。
所以,Tensorflow的編程模式是先創建一個計算圖,再交接session去計算。
這與平常的編程模式不太一樣,尤其在調試時感受比較明顯。比如查一個變量的運行時的值,一般跑起來後可以直接查看,但在Tensorflow中,必須要等到session.run()才能看到。


Session與InteractiveSession的區別是什麼?
答:Session是Tensorflow的標準方式,把一個計算圖搞完後,整體提交session,完成計算。在這種情況下,建構OP對象時是沒有session的,所以在後面必須顯示的使用session.run()。但InteractiveSession不同,它出現後,OP對象在構建時,就會把它做爲缺省session安裝上去,所以自帶session,可以直接調用運算函數完成計算(Tensor.eval() 和 Operation.run() )。這種好處是,可以隨時構建計算節點,然後隨時計算結果,不用時刻去想session的事情,故名交互式Session。參見:http://blog.csdn.net/zcf1784266476/article/details/70272905
代碼:
import tensorflow as tf


sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# 注意下面這一行,這裏使用了c.eval(),如果使用session,可能會是:sess=tf.Session() print(sess.run(c)) 
# 而且,InteractiveSession在用完後需要顯式關閉
print(c.eval())
sess.close()


Tensorflow爲什麼要使用圖計算模式?
Numpy是Tensorflow的好幫手,尤其擅長矩陳運算。但在普通的python環境與numpy(真正的重活是C++環境在幹)之間轉換,特別是在GPU或分佈式下,切換成本還是比較高的。所以頻繁在python與C++之間切換導致了低效。使用python去描述計算圖,然後一次性提交sesion,然後一次性提交session,交由C++去完成計算,性能好很多。


Deep MNIST for Experts的前半部分仍然在解釋mnist_softmax.py,參見之前兩篇的博客:
http://blog.csdn.net/vagrantabc2017/article/details/77063792
http://blog.csdn.net/vagrantabc2017/article/details/77101799
這裏進一步複習一下。
x = tf.placeholder(tf.float32, shape=[None, 784])
#x = tf.placeholder(tf.float32, shape=[每批次多少張圖片, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
#y_ = tf.placeholder(tf.float32, [每批次多少張圖片, 10])


W爲什麼會是784*10?
答:因爲是輸入是一個圖,有784個點(features),並且有10個輸出(0到9).所以W的是shape[features數量,輸出數量]。


y = tf.matmul(x, w) + b
矩陣相乘後得到shape[每批次多少張圖片,10],再加b.
舉個例子,假設2張圖片,b的
xW=tf.constant([[0,1,2,3,4,5,6,7,8,9],
               [9,8,7,6,5,4,3,2,1,0]])
b=tf.constant([0,0,1,0,0,0,0,0,0,0])
res = xW + b
輸出:
[[0 1 3 3 4 5 6 7 8 9]
 [9 8 8 6 5 4 3 2 1 0]]
可見,加b就是在xW乘積的每行都重疊一個b的行向量。
激活函數:softmax,輸出屬於某一類的概率
損失函數:交叉熵函數,softmax的輸出向量[Y1,Y2,Y3...]和樣本的實際標籤做一個交叉熵.
優化器用於計算損失函數的坡度並將坡度應用於變量。Tensorflow提供以下優化器:
tf.train.Optimizer
tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer
現在只了熟悉GradientDescentOptimizer,其它以後再說。
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
內部處理(看上去還是比較抽象):
1. 計算坡度
2. 計算參數更新步數
3. 對參數應用更新步數




打印出y看看,在mnist_softmax.py的for _ in range(1000):複合語句之後(外面)插入一句:
print(sess.run(y, feed_dict={x: mnist.test.images,
                                      y_: mnist.test.labels}))
得到:
[[  0.43599528  -8.72492504   1.67129803 ...,  10.67329407  -0.38615787    2.09889698]
 [  4.16476679  -1.62994194  10.84041023 ..., -13.57742596   4.29881573   -8.53488922]
 [ -5.26533985   6.19166565   1.90310097 ...,   0.46886426   1.02612364   -1.4779768 ]
 ..., 
 [ -7.61233521  -6.62633181  -2.11581898 ...,   2.29557776   3.58375025    3.92177582]
 [ -2.38366461  -1.31900096  -1.06822062 ...,  -3.82995367   5.05690718   -3.35313249]
 [  3.45034647  -9.92010784   6.14171076 ...,  -6.9410162    0.33765018   -4.41856956]]
因爲y的shape是shape[每批次多少張圖片,10],所以每行有10個數。
讓我們構造個例子。
y=tf.constant([[-2,6,9,3,2,4,-8,1,5,-1], #每行找出最大數的座標。
               [4,5,6,-1,-2,8,10,1,3,4],
               [1,2,3,4,55,-9,7,2,-3,-1]])
y_=tf.constant([[0,0,1,0,0,0,0,0,0,0], #每行找出最大數的座標。
               [0,0,0,0,0,0,0,0,1,0],
               [0,0,0,0,1,0,0,0,0,0]])
correct = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) #兩個座標的位置是否一樣
print(sess.run(correct))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
print(sess.run(accuracy))
輸出:[ True False  True]
      0.666667
可見,以上我們人爲構造的例子,正確預測率爲三分之二,第二條沒預測對。
通過上面2篇半博客,mnist_softmax.py就介紹完了,如果再不懂,撞牆。。。:)


最後解釋兩個概念:
1. 什麼是logits?
答:從源碼logits=y可以看出,logits不就是模型xW+b嘛。
2. 什麼是 one-hot ?
答:只有一個熱點,形如[0,0,1,0,0,0]的只有一個1,其它都是0的形式就是one-hot.


下面接着說多層卷積網。
據說識別率可以達到99.2%,而上個softmax模型不管咋搞只有92%,十個字裏面錯一個,想想還是頭痛。
下面學習源碼樣例mnist_deep.py。
什麼是修改線性單元ReLU?
先得說說修正器。修正器是激活函數的一種。我們學了softmax激活函數 ,大概瞭解sigmoid激活函數,修改器也是激活函數的一種。
修改器的定義;f(x)=x+=max(0,x)
參見:https://en.wikipedia.org/wiki/Rectifier_(neural_networks)
據說比sigmoid要好使,在DNN中最流行。
這個說完了,ReLU就好解釋了,不就是使用修正器作激活函數的神經單元嘛。
這個函數比較硬,也就是說,在負值段是0,在原點突然就向上拔高,線條不柔和。所以又有了softplus。
softplus定義:f(x)=ln[1+exp(x)]
它的導數正好是Logistic函數: 1/[1+exp(-x)]

想象一下平躺在地上的一根鋼條,用腳踩住中間,雙手把一端向上掰上來,彎折的部分也是很柔和的,不會有一個尖角,對了,就是這個形狀。



回頭再看mnist_deep.py,除了main和deepnn,還有四個函數,先處理掉前兩個。
第一個簡單函數:weight_variable:這裏涉及一個函數initial = tf.truncated_normal(shape, stddev=0.1)。這個函數生成一個正態分佈的tensor對象。
練習:
#生成一個10元素的向量,元素值隨機,要求均值爲0,標準差爲1。
x = tf.truncated_normal([10])
輸出:
[ 0.34689453 -0.80089593 -1.72287786 -0.41869378  0.77246767 -1.75758398 -0.53423828  0.00332778  0.85409206 -1.41753328]
#要求同上,但標準差(standard deviation,即stddev)爲0.1.
x = tf.truncated_normal([10],stddev=0.1)
輸出:
[ 0.18521971  0.10536867 -0.11113615  0.10921837 -0.1070381   0.14818405  0.07154682 -0.10790845  0.17011671 -0.0928892 ]
第二個簡單函數:bias_variable,bias初值全部爲0.1,沒啥說的。
x = tf.constant(0.1, shape=[5])
輸出:[ 0.1  0.1  0.1  0.1  0.1]


剩下兩個函數其實內容挺多的,看完deepnn後再說。
conv2d:只有一句:tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME'),完成卷積運算。
x: input輸入。
W:一個四維的tensor,[filter_height, filter_width, in_channels, out_channels]
strides=[1, 1, 1, 1]:
padding: 兩種取值方式 "SAME", "VALID". VAlID就是順着砍甘蔗,到最左或最後,不夠一整節的就扔了。SAME是不夠就前後補0,先簡單這樣理解着。


max_pool_2x2:也只有一句:tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
這兩句是卷積神經網絡模型的關鍵所在,先留第一個遺留問題。


deepnn中,分了幾層:
1.第一卷積層
2.第二卷積層
3.全聯接層
4.dropout層
5.輸出層
每層的含義,留下第二個遺留問題。


main函數
注意的是,計算圖採用了deepnn模型。
之後softmax,交叉熵與前面一樣,沒什麼可說的。
優化器採用了AdamOptimizer,不再是坡度優化,算第三個遺留問題。
其它代碼,如果前面的懂了,這裏並不困難。


所以,在後面的內容中,我們主要看這三個遺留問題。(待續)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章