簡體   English   中英

我的神經網絡實現中的錯誤? 來自吳恩達的 class

[英]Bug in my Neural Network implementation? From Andrew Ng's class

我正在學習 Andrew Ng 的深度學習介紹 class ,我正在嘗試為原型網絡實現 python class。 網絡輸入是 (64,64,3) 的圖像,展平為 (12288,1),具有任意數量的隱藏層,以及具有 1 個節點和 sigmoid 激活 function 的 output 層。 我想我理解了求解權重和梯度的結構和方程,但即使從頭開始重新實現,網絡也只能預測每個輸入的 0,output 概率在相似范圍內,即 [[0.36001726 0.30796208 0.30430954 0.3458 , ...]]。

網絡結構如下:

  • 使用self.init_params()初始化網絡,它為每一層生成一個隨機權重矩陣,以及一個與層大小匹配的 np.zeros 偏置向量。

  • 調用 model.fit(x, y) 然后:

    • 使用self.forward()進行前向傳遞,計算除具有 sigmoid 的最后一層之外的所有層的線性傳遞和 relu。

    • 使用self.compute_cost()計算此通行證的成本

    • 使用self.backward()計算梯度。 我認為大部分復雜性都在這里,並且可能存在錯誤。

    • 用學習率乘以剛剛計算的梯度來更新參數。

  • 調用model.predict(x_test) ,它使用 x_test 進行前向傳遞,並使用最后一層的 sigmoid output 來計算概率。 這些都匹配並且總是 <.5,這意味着預測為零。

訓練/測試數據沒有問題,因為簡單的 scikit-learn 邏輯回歸正在做出合理的預測。 你能幫我找出錯誤嗎?

class nn:
    def __init__(self, layers, lr=.005):
        self.layers = layers
        self.n_layers = len(layers)-1
        self.lr = lr
        self.grads = {}
        self.params = self.init_params()
        
    def init_params(self):
        params = {}
        L = self.layers
        for l in range(1, len(L)):
            params[f'w{l}'] = np.random.rand(L[l], L[l-1]) * 0.01
            params[f'b{l}'] = np.zeros((L[l], 1))
        return params
            
    def relu(self, z):
        return np.maximum(z, 0)
    
    def sigmoid(self, z):
        return 1 / (1+np.exp(-z))
    
    def forward(self, x):
        a = x
        L = self.layers
        n_layers = self.n_layers
        par = self.params
        for l in range(1, n_layers):
            z = np.dot(self.params[f'w{l}'], a) + self.params[f'b{l}']
            a = self.relu(z)
            self.params[f'z{l}'] = z
            self.params[f'a{l}'] = a
            
        z = np.dot(self.params[f'w{n_layers}'], self.params[f'a{n_layers-1}']) + self.params[f'b{n_layers}']
        a = self.sigmoid(z)
        self.params[f'z{n_layers}'] = z
        self.params[f'a{n_layers}'] = a
        
    def compute_score(self):
        # cross entropy loss
        m = self.m
        y = self.y
        y_hat = self.params[f'a{self.n_layers}']
        cost = (-1/m) * (np.dot(y, np.log(y_hat).T) + np.dot((1-y), np.log(1-y_hat).T))
        
    def back_sigmoid(self, da, z):
        s = 1/(1+np.exp(-z))  
        dz = da * s * (1-s)
        return dz
    
    def back_relu(self, da, z):
        dz = np.array(da, copy=True)
        dz[z <= 0] = 0
        return dz
        
    def back_linear(self, dz, a_prev, w):
        m = self.m
        dw = (1/m) * np.dot(dz, a_prev.T)
        db = (1/m) * np.sum(dz, axis=1, keepdims=True)
        da_prev = np.dot(w.T, dz)
        return dw, db, da_prev
        
    def backward(self):
        # compute daL
        m = len(self.y)
        nl = self.n_layers
        last_a = self.params[f'a{nl}']
        dal = -(np.divide(self.y, last_a) - np.divide(1-self.y, 1-last_a))
        self.grads[f'da{nl}'] = dal
        
        # first backward step (sigmoid)
        dzl = self.back_sigmoid(dal, self.params[f'z{nl}'])
        self.grads[f'dz{nl}'] = dzl
        
        a_prev = self.params[f'a{nl-1}']
        dw, db, da_prev = self.back_linear(dzl, a_prev, self.params[f'w{nl}'])
        self.grads[f'dw{nl}'] = dw
        self.grads[f'db{nl}'] = db
        self.grads[f'da{nl-1}'] = da_prev
        
        # rest of backward steps (relu)
        for l in reversed(range(1, nl)):
            da = self.grads[f'da{l}']
            dzl = self.back_relu(da, self.params[f'z{l}'])
            self.grads[f'dz{l}'] = dzl

            a_prev = self.params[f'a{l-1}']
            dw, db, da_prev = self.back_linear(dzl, a_prev, self.params[f'w{l}'])
            self.grads[f'dw{l}'] = dw
            self.grads[f'db{l}'] = db
            self.grads[f'da{l-1}'] = da_prev
        
            
    def fit(self, x, y, n_cycles=100):
        self.params['a0'] = x
        self.y = y
        self.m = y.shape[1]
        for i in range(n_cycles):
            self.forward(x)
            self.compute_score()
            self.backward()
            self.update_params()
    
    def update_params(self):
        for l in range(1, len(self.layers)):
            self.params[f'w{l}'] = self.params[f'w{l}'] - self.lr*self.grads[f'dw{l}']
            self.params[f'b{l}'] = self.params[f'b{l}'] - self.lr*self.grads[f'db{l}']
            
    def predict(self, x):
        self.forward(x)
        yhat = self.params[f'a{self.n_layers}']
        print(yhat)
        return 1. * (yhat >= .5)

layers = [12288, 5, 3, 1]
network = nn(layers)
network.fit(x_train, y_train, n_cycles=100)
network.predict(x_test) # gives all 0s

在我的本地機器上運行代碼時,有兩條錯誤消息。 第一個是關於 numpy 導入,可以通過將 numpy 作為 np 導入(將 numpy 作為 np 導入)來刪除。 另一個錯誤是由於 x_train,y_train 未在全局空間上定義而出現的。 看起來它直接用於調用 network.fit() function 沒有事先聲明和定義。 但是由於您上面的問題表明您已經運行程序沒有錯誤,唯一可能的問題可能是 model 沒有針對設定的時期數進行訓練。 看起來培訓只進行了一次

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM