Mini-patch:從零開始的反向傳播(附詳細代碼)

文章將重點介紹mini-patch逐步實現的反向傳播算法。有許多教程和博客詳細介紹了反向傳播算法,以及演算和代數背後的所有邏輯。因此,我將跳過這一部分,並在數學和使用Python的實現中切入方程式。

Mini-patch:從零開始的反向傳播(附詳細代碼)

關於為什麼我們應該從頭開始實現一個算法,即使幾乎所有框架都已經可以使用它,這也是一個長期存在的普遍問題。顯然,在使用某些高級框架時,你甚至都不會注意到反向傳播確實發揮了魔力。要完全顛倒地理解它,一次嘗試肯定是不夠的。反向傳播在遊戲中也是可以進行實驗的。

為什麼要使用mini-patch?

mini-patch的原理很簡單。通過將數據分成小批處理,並在訓練循環的每次迭代中為算法提供一部分數據集,可以節省內存和處理時間。一次饋入10000x10000矩陣不僅會消耗內存,還會花費很長時間才能運行。相反,每次迭代將其降低到50個不僅會減少內存使用量,而且可以跟蹤進度。

注意:這與隨機方法不同,在隨機方法中,我們從每個類別的數據中抽取了分層樣本,並在假設模型可以推廣的基礎上進行訓練。

開始實驗

這是將用於實驗的數據頭。

Mini-patch:從零開始的反向傳播(附詳細代碼)

此處的目標變量是佔用率,它是類別變量(0/1)。這將是我們將要編碼的架構。

Mini-patch:從零開始的反向傳播(附詳細代碼)

算法:

對於i:= 1到i:= m:

執行正向傳播或正向傳遞以計算每一層中神經元的激活值。

Mini-patch:從零開始的反向傳播(附詳細代碼)

反向傳播步驟:

  • 使用數據中的標籤計算誤差項(MSE或LogLoss或您的期望):
Mini-patch:從零開始的反向傳播(附詳細代碼)

  • 隱藏層中的誤差項使用以下公式計算:
Mini-patch:從零開始的反向傳播(附詳細代碼)

  • 設置梯度:
    初始化Δ= 0
Mini-patch:從零開始的反向傳播(附詳細代碼)

3.梯度下降和權重更新步驟:

Mini-patch:從零開始的反向傳播(附詳細代碼)

代碼展示:

<code>weight_dim = [5,H,1] 
#[number of input features, number of hidden units, number of output units]

print("Initializing using He initialization")
np.random.seed(3)
w1 = np.random.randn(weight_dim[1],weight_dim[0]) * np.sqrt(2/weight_dim[0]) # 0.01
b1 = np.zeros((weight_dim[1],1))
w2 = np.random.randn(weight_dim[2],weight_dim[1]) * np.sqrt(2/weight_dim[1]) # 0.01
b2 = np.zeros((weight_dim[2],1))/<code>

如前所述,這將是一個三層網絡。為了使梯度和誤差方程更好,更容易地識別,我們保持層的數量簡潔。之後,我們將定義一個函數,該函數將用作網絡中的轉發器。

<code>def forward(X,w1,w2,b1,b2):
    z1 = np.matmul(w1,np.transpose(np.asmatrix(X))) + b1
    a1 = sigmoid(z1)

    z2 = np.matmul(w2, a1) + b2
    a2 = sigmoid(z2)
    
    return z1, a1, z2, a2/<code>

這裡要注意的一件事是,已經將Input層視為我的第0層。可能還有其他博客/教程被認為是第一名。因此,絕對要為所需的索引編制索引。

因此,現在,在初始化權重和偏差並定義前向傳播函數之後,我們將在size = data-of-setset / N的mini-patch上定義反向傳播函數。通過調整N來調整所需的批次大小。

<code>def backprop(w1,b1,w2,b2,X_train,X_test):
    
    for i in range(epoch):
        
        no_of_batches = len(X_train) // N
        
        for j in range(no_of_batches):
            
            # Initilazing gradients
            
            delta1 = np.zeros(w1.shape)   #(5,5)
            delta2 = np.zeros(w2.shape)   #(1,5)
            db1 = 0.0
            db2 = 0.0
            
            
            for row in range(j*N,(j+1)*N):
                
                # Drop the date column and the index column
                X = X_train[row, 2:7]
                Y = X_train[row, 7]
                
                #feed forward
                z1  ,  a1  ,  z2  , a2 = forward(X,w1,w2,b1,b2)
                #(5,1) (5,1) (1,1) (1,1)
                
                h = a2 # (1,1)
                   
                # initializations

                d3 = a2 - Y  #(1,1)
                
                delta2 += d3 * np.transpose(a2)  #(1,1)
                db2 += d3

                d2 = np.multiply((np.transpose(w2) * d3), sigmoid_gradient(z1),dtype=float)  #(5,1)
 
                delta1 += d2 * np.transpose(a1)  #(5,5)

                db1 += d2
                        
            
            # Gradient Descent Step
            #updating weights after every batch by averaging the gradients
            w1 = w1 - lr * 1.0/N * delta1 #taking the average of gradients
            b1 = b1 - lr * 1.0/N * db1
            w2 = w2 - lr * 1.0/N * delta1
            b2 = b2 - lr * 1.0/N * db2
            
            
            
        print("************************************************")
        print("Train error after epoch {} is: ".format(i), np.sum(error(calc_out(X_train[:,2:7],w1,b1,w2,b2),X_train[:,7])) / len(X_train) * 100)    
        print("Test error after epoch {} is: ".format(i), np.sum(error(calc_out(X_test[:,2:7],w1,b1,w2,b2),X_test[:,7])) / len(X_test) * 100)
        print("************************************************")
        print()
    
        train_error[i] = np.sum(error(calc_out(X_train[:,2:7],w1,b1,w2,b2),X_train[:,7])) / len(X_train) * 100
        test_error[i] = np.sum(error(calc_out(X_test[:,2:7],w1,b1,w2,b2),X_test[:,7])) / len(X_test) * 100
        
    return [w1,b1,w2,b2]/<code>

步驟分解

  • 如前所述,Ist循環會遍歷您想要使模型遍歷數據的次數,只需將其放在神經網絡術語“時代”中即可。
  • 第二次循環:指定了批次數量後,此循環針對每個時期“ i”遍歷每個微型批次
  • 第三循環遍歷該小批量中的每個訓練示例,並計算梯度和誤差值
  • 最後,對於每個批次,都執行梯度下降步驟,並對權重矩陣進行更改。

這就是mini-patch的反向傳播實現。需要注意的是,此實驗為網絡中的每一層使用了一個矩陣變量,當網絡規模擴大時,這是一種不明智的做法,我們這樣做是為了瞭解它的實際工作原理。如果要增加“隱藏層”的數量,可以簡單地使用3d矩陣進行誤差和梯度計算,其中第3維將保存該層的值。


分享到:


相關文章: