簡體   English   中英

反向傳播python神經網絡中的錯誤

[英]Error in backpropagation python neural net

該死的東西根本不會學。 有時權重似乎變得微不足道。

我沒有玩過不同數量的隱藏層/輸入/輸出,但是該錯誤在不同大小的隱藏層中看起來是一致的。

from __future__ import division
import numpy
import matplotlib
import random

class Net:
    def __init__(self, *sizes):
        sizes = list(sizes)
        sizes[0] += 1
        self.sizes = sizes
        self.weights = [numpy.random.uniform(-1, 1, (sizes[i+1],sizes[i])) for i in range(len(sizes)-1)]

    @staticmethod
    def activate(x):    
        return 1/(1+numpy.exp(-x))


    def y(self, x_):
        x = numpy.concatenate(([1], numpy.atleast_1d(x_.copy())))
        o = [x] #o[i] is the (activated) output of hidden layer i, "hidden layer 0" is inputs
        for weight in self.weights[:-1]:
            x = weight.dot(x)
            x = Net.activate(x)
            o.append(x)
        o.append(self.weights[-1].dot(x))
        return o    

    def __call__(self, x):
        return self.y(x)[-1]

    def delta(self, x, t):
        o = self.y(x)
        delta = [(o[-1]-t) * o[-1] * (1-o[-1])]
        for i, weight in enumerate(reversed(self.weights)):
            delta.append(weight.T.dot(delta[-1]) * o[-i-2] * (1-o[-i-2]))
        delta.reverse()
        return o, delta            

    def train(self, inputs, outputs, epochs=100, rate=.1):
        for epoch in range(epochs):
            pairs = zip(inputs, outputs)
            random.shuffle(pairs)
            for x, t in pairs: #shuffle? subset? 
                o, d = self.delta(x, t)
                for layer in range(len(self.sizes)-1):
                    self.weights[layer] -=  rate * numpy.outer(o[layer+1], d[layer])


n = Net(1, 4, 1)
x = numpy.linspace(0, 2*3.14, 10)
t = numpy.sin(x)
matplotlib.pyplot.plot(x, t, 'g')
matplotlib.pyplot.plot(x, map(n, x), 'r')
n.train(x, t)
print n.weights
matplotlib.pyplot.plot(x, map(n, x), 'b')
matplotlib.pyplot.show()

我沒有在您的代碼中尋找特定的錯誤,但是您可以嘗試以下方法來進一步縮小問題范圍嗎? 否則,在大海撈針中找針很麻煩。

1)請嘗試使用真實的數據集來了解預期的結果(例如MNIST)和/或標准化數據,因為如果權重太小,則權重可能會變為NaN。

2)嘗試不同的學習率,並繪制成本函數與時期的關系圖,以檢查您是否正在收斂。 它看起來應該像這樣(請注意,我使用了minibatch學習並對每個紀元平均了minibatch塊)。

在此處輸入圖片說明

3)我看到您使用的是S型激活,您的實現是正確的,但是要使其在數值上更穩定,請從scipy.special expit(z)替換為1.0 / (1.0 + np.exp(-z)) (相同功能,但效率更高)。

4)實施梯度檢查。 在這里,您可以將解析解與數值近似的梯度進行比較

在此處輸入圖片說明

在此處輸入圖片說明

或者,產生更精確的梯度近似值的更好方法是計算兩點公式給出的對稱(或居中)差商

在此處輸入圖片說明

PS:如果您有興趣並且發現它有用,那么我可以在此處實現一個有效的香草NumPy神經網絡。

我修好了它! 感謝所有的建議。 我計算出了數字偏式,發現我的odelta正確,但是我乘錯了一些。 這就是為什么我現在使用numpy.outer(d[layer+1], o[layer])而不是numpy.outer(d[layer], o[layer+1])

我也跳過了一層更新。 這就是為什么我將for layer in range(self.hidden_layers)for layer in range(self.hidden_layers+1)更改for layer in range(self.hidden_layers) for layer in range(self.hidden_layers+1)

我還要補充一點,就是我在最初發布之前發現了一個錯誤。 我的輸出層增量不正確,因為我的網絡(有意地)沒有激活最終輸出,但是我的增量卻像是在計算。

主要使用一個隱藏層,一個隱藏單位網進行調試,然后移至2個輸入,每個2個神經元的3個隱藏層,2個輸出模型。

from __future__ import division
import numpy
import scipy
import scipy.special
import matplotlib
#from pylab import *

#numpy.random.seed(23)

def nmap(f, x):
    return numpy.array(map(f, x))

class Net:
    def __init__(self, *sizes):
        self.hidden_layers = len(sizes)-2
        self.weights = [numpy.random.uniform(-1, 1, (sizes[i+1],sizes[i])) for i in range(self.hidden_layers+1)]

    @staticmethod
    def activate(x):
        return scipy.special.expit(x)
        #return 1/(1+numpy.exp(-x))

    @staticmethod
    def activate_(x):
        s = scipy.special.expit(x)
        return s*(1-s)

    def y(self, x):
        o = [numpy.array(x)] #o[i] is the (activated) output of hidden layer i, "hidden layer 0" is inputs and not activated
        for weight in self.weights[:-1]:
            o.append(Net.activate(weight.dot(o[-1])))
        o.append(self.weights[-1].dot(o[-1]))
#        for weight in self.weights:
#            o.append(Net.activate(weight.dot(o[-1])))
        return o

    def __call__(self, x):
        return self.y(x)[-1]

    def delta(self, x, t):
        x = numpy.array(x)
        t = numpy.array(t)
        o = self.y(x)
        #delta = [(o[-1]-t) * o[-1] * (1-o[-1])]
        delta = [o[-1]-t]
        for i, weight in enumerate(reversed(self.weights)):
            delta.append(weight.T.dot(delta[-1]) * o[-i-2] * (1-o[-i-2]))
        delta.reverse() #surely i need this
        return o, delta

    def train(self, inputs, outputs, epochs=1000, rate=.1):
        errors = []
        for epoch in range(epochs):
            for x, t in zip(inputs, outputs): #shuffle? subset?
                o, d = self.delta(x, t)
                for layer in range(self.hidden_layers+1):
                    grad = numpy.outer(d[layer+1], o[layer])
                    self.weights[layer] -=  rate * grad

        return errors

    def rmse(self, inputs, outputs):
        return ((outputs - nmap(self, inputs))**2).sum()**.5/len(inputs)



n = Net(1, 8, 1)
X = numpy.linspace(0, 2*3.1415, 10)
T = numpy.sin(X)
Y = map(n, X)
Y = numpy.array([y[0,0] for y in Y])
matplotlib.pyplot.plot(X, T, 'g')
matplotlib.pyplot.plot(X, Y, 'r')
print 'output successful'
print n.rmse(X, T)
errors = n.train(X, T)
print 'tried to train successfully'
print n.rmse(X, T)
Y = map(n, X)
Y = numpy.array([y[0,0] for y in Y])
matplotlib.pyplot.plot(x, Y, 'b')
matplotlib.pyplot.show()

暫無
暫無

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

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