TensorFlow 深度學習筆記 TensorFlow實現與優化深度神經網絡

轉載請註明做者:夢裏風林
Github工程地址:https://github.com/ahangchen/GDLnotes
歡迎star,有問題能夠到Issue區討論
官方教程地址
視頻/字幕下載html

全鏈接神經網絡

輔助閱讀:TensorFlow中文社區教程 - 英文官方教程node

代碼見:full_connect.pypython

Linear Model

  • 加載lesson 1中的數據集
  • 將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()建立一個計算單元
    • 用tf.constant將dataset和label轉爲tensorflow可用的訓練格式(訓練中不可修改)
    • 用tf.truncated_normal生成正太分佈的數據,做爲W的初始值,初始化b爲可變的0矩陣
    • 用tf.variable將上面的矩陣轉爲tensorflow可用的訓練格式(訓練中能夠修改)
    • 用tf.matmul實現矩陣相乘,計算WX+b,這裏實際上logit只是一個變量,而非結果
    • 用tf.nn.softmax_cross_entropy_with_logits計算WX+b的結果相較於原來的label的train_loss,並求均值
    • 使用梯度找到最小train_loss
    optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
    • 計算相對valid_dataset和test_dataset對應的label的train_loss

    上面這些變量都是一種Tensor的概念,它們是一個個的計算單元,咱們在Graph中設置了這些計算單元,規定了它們的組合方式,就好像把一個個門電路串起來那樣git

TensorFLow Session

Session用來執行Graph裏規定的計算,就好像給一個個門電路通上電,咱們在Session裏,給計算單元衝上數據,That’s Flow.github

  • 重複計算單元反覆訓練800次,提升其準確度
    • 爲了快速查看訓練效果,每輪訓練只給10000個訓練數據(subset),恩,每次都是相同的訓練數據
    • 將計算單元graph傳給session
    • 初始化參數
    • 傳給session優化器 - train_loss的梯度optimizer,訓練損失 - train_loss,每次的預測結果,循環執行訓練
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])
  • 在循環過程當中,W和b會保留,並不斷獲得修正
  • 在每100次循環後,會用驗證集進行驗證一次,驗證也同時修正了一部分參數
valid_prediction.eval()
  • 最後用測試集進行測試
  • 注意若是lesson 1中沒有對數據進行亂序化,可能訓練集預測準確度很高,驗證集和測試集準確度會很低

這樣訓練的準確度爲83.2%算法

SGD

  • 每次只取一小部分數據作訓練,計算loss時,也只取一小部分數據計算loss
    • 對應到程序中,即修改計算單元中的訓練數據,
      • 每次輸入的訓練數據只有128個,隨機取起點,取連續128個數據:
      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), :]
    • 因爲這裏的數據是會變化的,所以用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次,訓練總數據量爲384000,比以前8000000少

    準確率提升到86.5%,並且準確率隨訓練次數增長而提升的速度變快了api

神經網絡

  • 上面SGD的模型只有一層WX+b,如今使用一個RELU做爲中間的隱藏層,鏈接兩個WX+b
    • 仍然只須要修改Graph計算單元爲
    Y = W2 * RELU(W1*X + b1) + b2
    • 爲了在數學上知足矩陣運算,咱們須要這樣的矩陣運算:
    [n * 10] = RELU([n * 784] · [784 * N] + [n * N]) · [N * 10] + [n * 10]
    • 這裏N取1024,即1024個隱藏結點
    • 因而四個參數被修改
    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次,能夠發現準確率一開始提升得很快,後面提升速度變緩,最終測試準確率提升到88.8%

深度神經網絡實踐

代碼見nn_overfit.py網絡

優化

Regularization

在前面實現的RELU鏈接的兩層神經網絡中,加Regularization進行約束,採用加l2 norm的方法,進行調節:session

代碼實現上,只須要對tf_sgd_relu_nn中train_loss作修改便可:app

  • 能夠用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: β
    • 我以爲這是一個拍腦殼參數,取什麼值都行,但效果會不一樣,我這裏解釋一下我取β=0.001的理由
    • 若是直接將l2_loss加到train_loss上,每次的train_loss都特別大,幾乎只取決於l2_loss
    • 爲了讓本來的train_loss與l2_loss都能較好地對參數調整方向起做用,它們應當至少在同一個量級
    • 觀察不加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
    • 全部其餘參數不變,訓練3000次,準確率提升到92.7%
    • 黑魔法之因此爲黑魔法就在於,這個參數能夠很容易地影響準確率,若是β = 0.002,準確率提升到93.5%

OverFit問題

在訓練數據不多的時候,會出現訓練結果準確率高,但測試結果準確率低的狀況

  • 縮小訓練數據範圍:將把batch數據的起點offset的可選範圍變小(只能選擇0-1128之間的數據):
offset_range = 1000
offset = (step * batch_size) % offset_range
  • 能夠看到,在step500後,訓練集就一直是100%,驗證集一直是77.6%,準確度沒法隨訓練次數上升,最後的測試準確度是85.4%

DropOut

採起Dropout方式強迫神經網絡學習更多知識

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

  • 咱們須要丟掉RELU出來的部分結果
  • 調用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的結果所佔比例,tensorflow建議的語法是,讓它做爲一個placeholder,在run時傳入
  • 固然咱們也能夠不用placeholder,直接傳一個0.5:
if drop_out:
    hidden_drop = tf.nn.dropout(hidden, 0.5)
    h_fc = hidden_drop
  • 這種訓練的結果就是,雖然在step 500對訓練集預測沒能達到100%(起步慢),但訓練集預測率達到100%後,驗證集的預測正確率仍然在上升
  • 這就是Dropout的好處,每次丟掉隨機的數據,讓神經網絡每次都學習到更多,但也須要知道,這種方式只在咱們有的訓練數據比較少時頗有效
  • 最後預測準確率爲88.0%

Learning Rate Decay

隨着訓練次數增長,自動調整步長

  • 在以前單純兩層神經網絡基礎上,添加Learning Rate Decay算法
  • 使用tf.train.exponential_decay方法,指數降低調整步長,具體使用方法官方文檔說的特別清楚
  • 注意這裏面的cur_step傳給優化器,優化器在訓練中對其作自增計數
  • 與以前單純兩層神經網絡對比,準確率直接提升到90.6%

Deep Network

增長神經網絡層數,增長訓練次數到20000

  • 爲了不修改網絡層數須要重寫代碼,用循環實現中間層
# 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
  • 第一次測試時,用正太分佈設置全部W的數值,將標準差設置爲1,因爲網絡增長了一層,尋找step調整方向時具備更大的不肯定性,很容易致使loss變得很大
  • 所以須要用stddev調整其標準差到一個較小的範圍(怎麼調整有許多研究,這裏直接找了一個來用)
stddev = np.sqrt(2.0 / n)
  • 啓用regular時,也要適當調一下β,不要讓它對本來的loss形成過大的影響
  • DropOut時,由於後面的layer獲得的信息越重要,須要動態調整丟棄的比例,到後面的layer,丟棄的比例要減少
keep_prob += 0.5 * i / (layer_cnt + 1)
  • 訓練時,調節參數,你可能遇到消失(或爆炸)的梯度問題
    訓練到必定程度後,梯度優化器沒有什麼做用,loss和準確率老是在必定範圍內徘徊
  • 官方教程表示最好的訓練結果是,準確率97.5%,
  • 個人nn_overfit.py開啓六層神經網絡,
    啓用Regularization、DropOut、Learning Rate Decay,
    訓練次數20000(應該還有再訓練的但願,在這裏雖然loss降低很慢了,但仍然在降低),訓練結果是,準確率95.2%

以爲個人文章對您有幫助的話,給個star可好?

土豪能夠打賞支持,一分也是愛:

圖片名稱

相關文章
相關標籤/搜索