TensorFlow深度學習筆記 實現(xiàn)與優(yōu)化深度神經(jīng)網(wǎng)絡(luò)

轉(zhuǎn)載請注明作者:夢里風林
Github工程地址:https://github.com/ahangchen/GDLnotes
歡迎star,有問題可以到Issue區(qū)討論
Google深度學習 官方教程地址
視頻/字幕下載

全連接神經(jīng)網(wǎng)絡(luò)

輔助閱讀:TensorFlow中文社區(qū)教程 - 英文官方教程

代碼見:full_connect.py

Linear Model

  • 加載lesson 1中的數(shù)據(jù)集
  • 將Data降維成一維,將label映射為one-hot encoding
def reformat(dataset, labels):
    dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32)
    # Map 0 to [1.0, 0.0, 0.0 ...], 1 to [0.0, 1.0, 0.0 ...]
    labels = (np.arange(num_labels) == labels[:, None]).astype(np.float32)
    return dataset, labels

TensorFlow Graph

  • 使用梯度計算train_loss,用tf.Graph()創(chuàng)建一個計算單元

    • 用tf.constant將dataset和label轉(zhuǎn)為tensorflow可用的訓練格式(訓練中不可修改)
    • 用tf.truncated_normal生成正太分布的數(shù)據(jù)筝闹,作為W的初始值,初始化b為可變的0矩陣
    • 用tf.variable將上面的矩陣轉(zhuǎn)為tensorflow可用的訓練格式(訓練中可以修改)
    • 用tf.matmul實現(xiàn)矩陣相乘,計算WX+b蒲祈,這里實際上logit只是一個變量甘萧,而非結(jié)果
    • 用tf.nn.softmax_cross_entropy_with_logits計算WX+b的結(jié)果相較于原來的label的train_loss,并求均值
    • 使用梯度找到最小train_loss
    optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
    
    • 計算相對valid_dataset和test_dataset對應的label的train_loss

    上面這些變量都是一種Tensor的概念梆掸,它們是一個個的計算單元扬卷,我們在Graph中設(shè)置了這些計算單元,規(guī)定了它們的組合方式,就好像把一個個門電路串起來那樣

TensorFLow Session

Session用來執(zhí)行Graph里規(guī)定的計算通殃,就好像給一個個門電路通上電通砍,我們在Session里,給計算單元沖上數(shù)據(jù)徒恋,That’s Flow.

  • 重復計算單元反復訓練800次,提高其準確度

    • 為了快速查看訓練效果欢伏,每輪訓練只給10000個訓練數(shù)據(jù)(subset)入挣,恩,每次都是相同的訓練數(shù)據(jù)
    • 將計算單元graph傳給session
    • 初始化參數(shù)
    • 傳給session優(yōu)化器 - train_loss的梯度optimizer硝拧,訓練損失 - train_loss径筏,每次的預測結(jié)果,循環(huán)執(zhí)行訓練
    with tf.Session(graph=graph) as session:
          tf.initialize_all_variables().run()
          for step in range(num_steps):
              _, l, predictions = session.run([optimizer, loss, train_prediction])
    
    • 在循環(huán)過程中障陶,W和b會保留滋恬,并不斷得到修正
    • 在每100次循環(huán)后,會用驗證集進行驗證一次抱究,驗證也同時修正了一部分參數(shù)
    valid_prediction.eval()
    
    • 最后用測試集進行測試
    • 注意如果lesson 1中沒有對數(shù)據(jù)進行亂序化恢氯,可能訓練集預測準確度很高,驗證集和測試集準確度會很低

    這樣訓練的準確度為83.2%

SGD

  • 每次只取一小部分數(shù)據(jù)做訓練鼓寺,計算loss時勋拟,也只取一小部分數(shù)據(jù)計算loss

    • 對應到程序中,即修改計算單元中的訓練數(shù)據(jù)妈候,
      • 每次輸入的訓練數(shù)據(jù)只有128個指黎,隨機取起點,取連續(xù)128個數(shù)據(jù):
    offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
    batch_data = train_dataset[offset:(offset + batch_size), :]
    batch_labels = train_labels[offset:(offset + batch_size), :]
    
    • 由于這里的數(shù)據(jù)是會變化的州丹,因此用tf.placeholder來存放這塊空間
    tf_train_dataset = tf.placeholder(tf.float32,
                                            shape=(batch_size, image_size * image_size))
    tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
    
    • 計算3000次醋安,訓練總數(shù)據(jù)量為384000,比之前8000000少

    準確率提高到86.5%墓毒,而且準確率隨訓練次數(shù)增加而提高的速度變快了

神經(jīng)網(wǎng)絡(luò)

  • 上面SGD的模型只有一層WX+b吓揪,現(xiàn)在使用一個RELU作為中間的隱藏層,連接兩個WX+b
    • 仍然只需要修改Graph計算單元為
        Y = W2 * RELU(W1*X + b1) + b2
    
    • 為了在數(shù)學上滿足矩陣運算所计,我們需要這樣的矩陣運算:
        [n * 10] = RELU([n * 784] · [784 * N] + [n * N]) · [N * 10] + [n * 10]  
    
    • 這里N取1024柠辞,即1024個隱藏結(jié)點
    • 于是四個參數(shù)被修改
    weights1 = tf.Variable(
              tf.truncated_normal([image_size * image_size, hidden_node_count]))
    biases1 = tf.Variable(tf.zeros([hidden_node_count]))
    weights2 = tf.Variable(
              tf.truncated_normal([hidden_node_count, num_labels]))
    biases2 = tf.Variable(tf.zeros([num_labels]))
    
    • 預測值計算方法改為
    ys = tf.matmul(tf_train_dataset, weights1) + biases1
    hidden = tf.nn.relu(ys)
    logits = tf.matmul(hidden, weights2) + biases2
    
    • 計算3000次,可以發(fā)現(xiàn)準確率一開始提高得很快主胧,后面提高速度變緩叭首,最終測試準確率提高到88.8%

深度神經(jīng)網(wǎng)絡(luò)實踐

代碼見nn_overfit.py

優(yōu)化

Regularization

在前面實現(xiàn)的RELU連接的兩層神經(jīng)網(wǎng)絡(luò)中习勤,加Regularization進行約束,采用加l2 norm的方法焙格,進行調(diào)節(jié):

代碼實現(xiàn)上图毕,只需要對tf_sgd_relu_nn中train_loss做修改即可:

  • 可以用tf.nn.l2_loss(t)對一個Tensor對象求l2 norm
  • 需要對我們使用的各個W都做這樣的計算(參考tensorflow官方example
l2_loss = tf.nn.l2_loss(weights1) + tf.nn.l2_loss(weights2)
  • 添加到train_loss上
  • 這里還有一個重要的點,Hyper Parameter: β
    • 我覺得這是一個拍腦袋參數(shù)眷唉,取什么值都行予颤,但效果會不同,我這里解釋一下我取β=0.001的理由
    • 如果直接將l2_loss加到train_loss上冬阳,每次的train_loss都特別大蛤虐,幾乎只取決于l2_loss
    • 為了讓原本的train_loss與l2_loss都能較好地對參數(shù)調(diào)整方向起作用,它們應當至少在同一個量級
    • 觀察不加l2_loss肝陪,step 0 時驳庭,train_loss在300左右
    • 加l2_loss后, step 0 時氯窍,train_loss在300000左右
    • 因此給l2_loss乘0.0001使之降到同一個量級
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels)) + 0.001 * l2_loss
    
    • 所有其他參數(shù)不變饲常,訓練3000次,準確率提高到92.7%
    • 黑魔法之所以為黑魔法就在于荞驴,這個參數(shù)可以很容易地影響準確率,如果β = 0.002贯城,準確率提高到93.5%

OverFit問題

在訓練數(shù)據(jù)很少的時候熊楼,會出現(xiàn)訓練結(jié)果準確率高,但測試結(jié)果準確率低的情況

  • 縮小訓練數(shù)據(jù)范圍:將把batch數(shù)據(jù)的起點offset的可選范圍變心芊浮(只能選擇0-1128之間的數(shù)據(jù)):
offset_range = 1000
offset = (step * batch_size) % offset_range
  • 可以看到鲫骗,在step500后,訓練集就一直是100%踩晶,驗證集一直是77.6%执泰,準確度無法隨訓練次數(shù)上升,最后的測試準確度是85.4%

DropOut

采取Dropout方式強迫神經(jīng)網(wǎng)絡(luò)學習更多知識

參考aymericdamien/TensorFlow-Examples中dropout的使用

  • 我們需要丟掉RELU出來的部分結(jié)果
  • 調(diào)用tf.nn.dropout達到我們的目的:
keep_prob = tf.placeholder(tf.float32)
if drop_out:
    hidden_drop = tf.nn.dropout(hidden, keep_prob)
    h_fc = hidden_drop
  • 這里的keep_prob是保留概率渡蜻,即我們要保留的RELU的結(jié)果所占比例术吝,tensorflow建議的語法是,讓它作為一個placeholder茸苇,在run時傳入
  • 當然我們也可以不用placeholder排苍,直接傳一個0.5:
if drop_out:
    hidden_drop = tf.nn.dropout(hidden, 0.5)
    h_fc = hidden_drop
  • 這種訓練的結(jié)果就是,雖然在step 500對訓練集預測沒能達到100%(起步慢)学密,但訓練集預測率達到100%后淘衙,驗證集的預測正確率仍然在上升
  • 這就是Dropout的好處,每次丟掉隨機的數(shù)據(jù)腻暮,讓神經(jīng)網(wǎng)絡(luò)每次都學習到更多彤守,但也需要知道毯侦,這種方式只在我們有的訓練數(shù)據(jù)比較少時很有效
  • 最后預測準確率為88.0%

Learning Rate Decay

隨著訓練次數(shù)增加,自動調(diào)整步長

  • 在之前單純兩層神經(jīng)網(wǎng)絡(luò)基礎(chǔ)上具垫,添加Learning Rate Decay算法
  • 使用tf.train.exponential_decay方法侈离,指數(shù)下降調(diào)整步長,具體使用方法官方文檔說的特別清楚
  • 注意這里面的cur_step傳給優(yōu)化器做修,優(yōu)化器在訓練中對其做自增計數(shù)
  • 與之前單純兩層神經(jīng)網(wǎng)絡(luò)對比霍狰,準確率直接提高到90.6%

Deep Network

增加神經(jīng)網(wǎng)絡(luò)層數(shù),增加訓練次數(shù)到20000

  • 為了避免修改網(wǎng)絡(luò)層數(shù)需要重寫代碼饰及,用循環(huán)實現(xiàn)中間層
# middle layer
for i in range(layer_cnt - 2):
     y1 = tf.matmul(hidden_drop, weights[i]) + biases[i]
     hidden_drop = tf.nn.relu(y1)
     if drop_out:
         keep_prob += 0.5 * i / (layer_cnt + 1)
         hidden_drop = tf.nn.dropout(hidden_drop, keep_prob)
  • 初始化weight在迭代中使用
for i in range(layer_cnt - 2):
     if hidden_cur_cnt > 2:
         hidden_next_cnt = int(hidden_cur_cnt / 2)
     else:
         hidden_next_cnt = 2
     hidden_stddev = np.sqrt(2.0 / hidden_cur_cnt)
     weights.append(tf.Variable(tf.truncated_normal([hidden_cur_cnt, hidden_next_cnt], stddev=hidden_stddev)))
     biases.append(tf.Variable(tf.zeros([hidden_next_cnt])))
     hidden_cur_cnt = hidden_next_cnt
  • 第一次測試時蔗坯,用正太分布設(shè)置所有W的數(shù)值,將標準差設(shè)置為1燎含,由于網(wǎng)絡(luò)增加了一層宾濒,尋找step調(diào)整方向時具有更大的不確定性,很容易導致loss變得很大
  • 因此需要用stddev調(diào)整其標準差到一個較小的范圍(怎么調(diào)整有許多研究屏箍,這里直接找了一個來用)
stddev = np.sqrt(2.0 / n)
  • 啟用regular時绘梦,也要適當調(diào)一下β,不要讓它對原本的loss造成過大的影響
  • DropOut時赴魁,因為后面的layer得到的信息越重要卸奉,需要動態(tài)調(diào)整丟棄的比例,到后面的layer颖御,丟棄的比例要減小
keep_prob += 0.5 * i / (layer_cnt + 1)
  • 訓練時榄棵,調(diào)節(jié)參數(shù),你可能遇到消失(或爆炸)的梯度問題潘拱,
    訓練到一定程度后疹鳄,梯度優(yōu)化器沒有什么作用,loss和準確率總是在一定范圍內(nèi)徘徊
  • 官方教程表示最好的訓練結(jié)果是芦岂,準確率97.5%瘪弓,
  • 我的nn_overfit.py開啟六層神經(jīng)網(wǎng)絡(luò),
    啟用Regularization禽最、DropOut腺怯、Learning Rate Decay,
    訓練次數(shù)20000(應該還有再訓練的希望川无,在這里雖然loss下降很慢了瓢喉,但仍然在下降),訓練結(jié)果是舀透,準確率95.2%

覺得我的文章對您有幫助的話栓票,給個star可好?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市走贪,隨后出現(xiàn)的幾起案子佛猛,更是在濱河造成了極大的恐慌,老刑警劉巖坠狡,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件继找,死亡現(xiàn)場離奇詭異,居然都是意外死亡逃沿,警方通過查閱死者的電腦和手機婴渡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凯亮,“玉大人边臼,你說我怎么就攤上這事〖傧” “怎么了柠并?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長富拗。 經(jīng)常有香客問我臼予,道長,這世上最難降的妖魔是什么啃沪? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任粘拾,我火速辦了婚禮,結(jié)果婚禮上创千,老公的妹妹穿的比我還像新娘缰雇。我一直安慰自己,他們只是感情好签餐,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布寓涨。 她就那樣靜靜地躺著盯串,像睡著了一般氯檐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上体捏,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天冠摄,我揣著相機與錄音,去河邊找鬼几缭。 笑死河泳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的年栓。 我是一名探鬼主播拆挥,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纸兔?” 一聲冷哼從身側(cè)響起惰瓜,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汉矿,沒想到半個月后崎坊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡洲拇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年奈揍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赋续。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡男翰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚕捉,到底是詐尸還是另有隱情奏篙,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布迫淹,位于F島的核電站秘通,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏敛熬。R本人自食惡果不足惜肺稀,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望应民。 院中可真熱鬧话原,春花似錦、人聲如沸诲锹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽归园。三九已至黄虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庸诱,已是汗流浹背捻浦。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留桥爽,地道東北人朱灿。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像钠四,于是被迫代替她去往敵國和親盗扒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容