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

rfqg2955 7年前發布 | 20K 次閱讀 神經網絡 深度學習 TensorFlow

全連接神經網絡

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

代碼見: full_connect.py

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</code></pre>

    TensorFlow Graph

    </li>
  • 使用梯度計算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
    • </ul>

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

      </li> </ul>

      TensorFLow Session

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

      • 重復計算單元反復訓練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%

        </li> </ul>

        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), :]
            </li>
          • 由于這里的數據是會變化的,因此用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少
          • </ul>

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

            </li> </ul>

            神經網絡

            • 上面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%
              </li> </ul>

              深度神經網絡實踐

              代碼見 nn_overfit.py

              優化

              Regularization

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

              代碼實現上,只需要對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: β
                • 我覺得這是一個拍腦袋參數,取什么值都行,但效果會不同,我這里解釋一下我取β=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%
                </li> </ul>

                OverFit問題

                在訓練數據很少的時候,會出現訓練結果準確率高,但測試結果準確率低的情況

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

                DropOut

                采取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)
                  </li>
                • 啟用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%
                • </ul>

                   

                   

                  來自:http://www.jianshu.com/p/ea1f82a33102

                   

 本文由用戶 rfqg2955 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!