天天看點

誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

誤差反向傳播和深度學習相關技巧總結

文章目錄

  • 誤差反向傳播和深度學習相關技巧總結
    • 一、誤差反向傳播法
      • 1.幾個問題
      • 2.簡單層(加法、乘法層)、激活函數層、Affine/softmax層的實作
      • 3.誤差反向傳播的實作
    • 二、與學習相關的技巧
      • 1.關于參數的更新
      • 2.權重的初始值
      • 3、其它與之相關的學習技巧
    • 三、總結

一、誤差反向傳播法

1.幾個問題

  • 誤差反向傳播的目的是什麼?

    為了能夠更高效的計算權重參數的梯度方法,數值微分雖然很好了解,但是它的計算量确實很大,執行效率很低。

  • 反向傳播的理論依據?

    首先要明白的是求梯度,就是求導數。傳遞局部導數原理成立的原理就是基于鍊式法則

2.簡單層(加法、乘法層)、激活函數層、Affine/softmax層的實作

說明:通過計算圖,人們可以直覺地把握整個計算過程,計算圖的節點是由局部構成的,局部計算構成全局計算。建議自己動手手推BP(反向傳播)神經網絡!注:以下代碼和内容都是學習《深度學習入門》一書的學習筆記。

  • 加法層和乘法層的實作比較簡單,加法層反向傳播中,隻需要将上遊的值原封不動的傳給下遊;乘法層的反向傳播中需要将上遊的值乘以正向傳播的輸入信号的“翻轉值”。以下是python實作的代碼:
import numpy as np

class Addlayer:#加法層
    def __init__(self):
        pass
    def forward(self,x,y):
        out=x+y
        return out
    def backward(self,dout):
        dx=dout*1
        dy=dout*1
        return dx,dy

class Mulayer:#乘法層
    def __init__(self):
      self.x=None
      self.y=None
    def forward(self,x,y):
        self.x=x
        self.y=y
        out =x*y
        return out
    def backward(self,dout):
        dx=dout*self.y
        dy=dout*self.x
        return dx,dy
           
  • ReLU和Sigmoid層的實作

    由于ReLu的計算圖比較簡單,以下展示的是Sigmoid的計算圖,建議多動手去推導這個過程

誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

熟悉上面這個過程之後,以後就隻要關注下面這個輸入和輸出就OK了。

誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

以下為python代碼實作方式

class Sigmoid:
    def __init__(self):
        self.out = None

    def forward(self, x):
        out = sigmoid(x)
        self.out = out
        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out

        return dx
           
  • Affine層的實作

    Affine層就是算層與層之間的點積的,注意算點積的反向傳播的時候要乘以輸入信号的轉置。以下為Affine的計算圖

    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    以下為Affine層的python代碼實作
class Affine:
    def __init__(self,W,b):
        self.W=W
        self.b=b
        self.X = None
        self.dW=None
        self.db=None
    def forward(self,x):
        self.x=x
        out=np.dot(x,self.W)+self.b
        return out
    def backward(self,dout):
        self.dx = np.dot(dout , self.W.T)
        self.dW=np.dot(self.x.T,dout)
        self.db=np.sum(dout,axis=0)#為什麼是求和?

        return dx
           

問題:為什麼Affine層反向傳播過程中,db是對dout的列求和?

參見損失值對b的梯度

  • Softmax-With-Loss層的實作

    這裡的話就是Softmax層和損失函數層(下面用交叉熵誤差)的反向傳播,下面先介紹Softmax層的計算公式和計算圖

    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    Softmax輸出層的計算圖如下,反向傳播隻标注了a1->y1這一條神經網絡,其它的同理。推理過程中需要注意的是"/"節點,"X"節點以及"EXP"節點的反向傳播,這裡是要用一個整體的代換。
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    損失函數(交叉熵誤差)的計算圖如下
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    弄懂了上面這些細節之後,以後就隻需要關注經過一個層的輸入和輸出就可以了,以下是Softmax-With-loss的簡潔版,其中的ai是神經網絡推理過程的得分,ti是正确解标簽。
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    以下是Softmax-with-loss層的python代碼實作
class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None  # softmax的輸出
        self.t = None  # 監督資料

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)

        return self.loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        if self.t.size == self.y.size:  # 監督資料是one-hot-vector的情況
            # test=self.y - self.t
            dx = (self.y - self.t) / batch_size
        else:
            dx = self.y.copy()
            dx[np.arange(batch_size), self.t] -= 1
            dx = dx / batch_size#為什麼要除以batch_size的大小?

        return dx
           

3.誤差反向傳播的實作

  • 以下為主要的python源代碼
# coding: utf-8
import sys, os

sys.path.append(os.pardir)

import timejiqiao
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
from common.util import smooth_curve
import matplotlib.pyplot as plt
start = time.time()
# 讀入資料
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_sizejiqiao=10)

iters_num = 10000#疊代次數
train_size = x_train.shape[0]
batch_size = 100jiqiao
learning_rate = 0.1jiqiao
jiqiao
train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)#随機選擇了100組資料
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    # 梯度
    # grad = network.numerical_gradient(x_batch, t_batch)
    grad = network.gradient(x_batch, t_batch)

    # 更新
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)

    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print(train_acc, test_acc)
print(len(train_loss_list))
x=np.arange(iters_num)
plt.plot(x, smooth_curve(train_loss_list))
plt.xlabel("iterations")
plt.ylabel("loss")
plt.title("gradient")
# plt.title("numerical_gradient")
# plt.legend()
plt.show()
end = time.time()
print("time: ",str(end-start)+"s ")
           
  • 以下為實驗結果,可以看到整個代碼的運作時間隻要21.7s,速度比數值微分求梯度的時間快了不知道多少倍(反正用數值微分求梯度的運作時間在我目前這台機器上我是沒跑出來。)說明用反向傳播的方法更優。
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
    經過1萬次學習之後,損失值減小了許多,接近0了。
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

二、與學習相關的技巧

1.關于參數的更新

  • 這裡介紹了SGD、Momentum、AdaGrad、Adam四種optimizer方式,首先來看一下這四種跟新參數的優化方式在mnist資料集上的實驗結果。
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

    我們可看到SGD在一千次學習之後,損失函數的值保持在0.2-0.3之間,損失函數下降得慢且保持一種"之"字型的形狀在下降,這就使SGD的學習效率變得很低。思考SGD為什麼會呈"之"字型?

    -> 因為SGD在某一個方向上下降得很快(比如y方向上),在另一個方向上下降得很慢(比如x軸),這就會造成SGD參數的更新造成一定的波動,進而會影響損失函數的更新。

  • 對于其它三種優化算法,這裡不作太多的說明,有興趣可以了解Adam詳解

2.權重的初始值

  • 思考一個問題? -> 可以将權重初識值設為0?或者可以将所有權重值設成一樣的值嗎?

    –>>>答案顯示然是不能的,因為假如所有的權重都是一樣的,在正向傳播中,傳遞給下一層的值都是相同的,這就意味着在反向傳播中,同一層的權重會更新相同的值,那麼就使神經網絡擁有許多不同的權重喪失了意義。(防止權重"權重均一化",随機生成初始值)

  • 第二個問題?->什麼樣的權重分布才能使神經網絡的學習不會出現梯度消失?看下面的這照實驗圖檔。這個是使用了sigmoid激活函數,且權重的标準差為0.01.
誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

從上圖中可以看出大多數資料會偏向0和1的情況,是以随着學習的不斷進行,反向傳播的值會不斷減小,最終會消失,這個就叫做梯度消失?->怎麼樣解決梯度消失,更換激活函數或者更改權重的标準差

若改變上面語句為

實驗結果就為如下圖所示,這裡做了僅僅是将權重的初始值使用标準差為1/(根号n)的高斯分布進行初始化。

誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

下面,這裡展示基于std=0.01,Xavier初始值、he初始值(激活函數使用ReLU函數、标準差為根号2/n)的訓練資料比較。

誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

3、其它與之相關的學習技巧

  • Batch Normalization

    Batch Normalization 是通過在Affine層之後強制的調整激活之的分布,使激活值擁有适當的廣度。

    優點:

    1.不僅僅極大提升了訓練速度,收斂過程大大加快;

    2.還能增加分類效果,一種解釋是這是類似于Dropout的一種防止過拟合的正則化表達方式,是以不用Dropout也能達到相當的效果;

    3.另外調參過程也簡單多了,對于初始化要求沒那麼高,而且可以使用大的學習率等

    用數學式表達如下:

    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結
  • 過拟合

    原因:

  1. 訓練集的數量級和模型的複雜度不比對。訓練集的數量級要小于模型的複雜度;
  2. 訓練集和測試集特征分布不一緻;
  3. 樣本裡的噪音資料幹擾過大,大到模型過分記住了噪音特征,反而忽略了真實的輸入輸出間的關系;
  4. 權值學習疊代次數足夠多(Overtraining),拟合了訓練資料中的噪聲和訓練樣例中沒有代表性的特征

    方法-> 權值衰減(在學習的過程中對打的權重進行懲罰)

  • Dropout(作為抑制過拟合的方法)
    誤差反向傳播和深度學習相關技巧總結誤差反向傳播和深度學習相關技巧總結

三、總結

通過前六章的學習,大緻明白了神經網絡的學習層次,以及各種優化的方法,最後得出一個結論是應該多動手去算,最底層就是數學推導的過程,多想想為什麼?換一種方式可不 可以?

繼續閱讀