BPニューラルネットワークPython


空き期间、暇で无事、最も基础的なBPニューラルネットワークを书きます.
順方向ネットワーク伝達は比較的簡単で,直接行列が乗算され,ここでは無視される.主に逆方向のネットワーク伝達について:1:出力ネットワーク誤差=出力層損失関数導関数*損失関数2:隠し層ネットワーク誤差=出力層損失関数導関数*(次層誤差*中間重み)3:重み更新=元の重み+学習率*(前分岐転置*後誤差)4:バイアス更新=元のバイアス+学習率*(前分岐転置*後誤差)
実際の動作では,バイアスは重み行列に直接配置して計算することができ,出力層は不要である.
import numpy as np

def tanh(x):
    return np.tanh(x)
def tanh_deriv(x):      #       
    return 1.0 - np.tanh(x) * np.tanh(x)

def sigmoid(x):
    return 1 / (1 + np.exp(-x))
def sigmod_derivate(x): #       
    return x * (1 - x)

# layers:	   ,       
# activation:	    
class NeuralNetwork:                    #   
    def __init__(self, layers, activation='sigmoid'):
    	if activation == 'sigmoid':
            self.activation = sigmoid
            self.activation_deriv = sigmod_derivate
        elif activation == 'tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv	
           
        #     
	self.weights = []                   #    +             
        self.panel   = []                   #   
        self.error   = []                   #   
        
        self.panel.append(np.zeros(layers[0]+1))
        for i in range(1, len(layers)-1):
            self.weights.append((2*np.random.random((layers[i-1]+1, layers[i]+1))-1)*0.25)
            self.panel.append(np.zeros(layers[i]+1))
            self.error.append(np.zeros(layers[i]+1))
	self.weights.append((2 * np.random.random((layers[-2] + 1, layers[-1])) - 1) * 0.25)
        self.panel.append(np.zeros(layers[-1]))
        self.error.append(np.zeros(layers[-1]))
        	 
    # inputs:          
    def predict(self, inputs):          #     
        inputs = [inputs]
        temp = np.ones([np.array(inputs).shape[1]+1])
        temp[:-1] = np.array(inputs)
        inputs = temp
        
    self.panel[0] = np.array(inputs)
        for i in range(len(self.weights)):
            self.panel[i+1] = self.activation(np.dot(self.panel[i], self.weights[i]))           #       
        return self.panel[-1]

    # case:	   
    # label:	    
    # learn:	   
    def back_propagate(self, case, label, learn):                                      #     
        self.predict(case)
        
        self.error[-1] = (label - self.panel[-1])*self.activation_deriv(self.panel[-1])         #       
        for i in range(len(self.panel)-2, 0, -1):
            self.error[i-1] = (self.error[i].dot(self.weights[i].T))*self.activation_deriv(self.panel[i])                         #        

        for i in range(len(self.weights)):
            self.weights[i] += learn * np.atleast_2d(self.panel[i]).T.dot(np.atleast_2d(self.error[i]))   #     

    # X:	     
    # y:	      
    # epochs:	    
    # learn:	   
    def train(self, X, y, epochs=10000, learn=0.05):
        for k in range(epochs):
            i = np.random.randint(np.array(X).shape[0])
            case = X[i]
            label = np.array(y[i])
            self.back_propagate(case, label, learn)

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0, 0], [1, 1], [1, 1], [0,0]])
nn = NeuralNetwork([2, 5, 2, 2], activation='tanh')			#     
nn.train(X, y, 10000, 0.2)						#   

for case in X:								#   
    print(nn.predict(case))