2016-04-23 2 views
0

Я пытаюсь понять обратное распространение, потому что я использую некоторый код python, но он замечает, что он работает правильно. Когда я тренируюсь с xor input-output, ошибка не сходится. Но если я изменил значение последнего выхода xor, оно сходится.Простой backpropagation Алгоритм нейронной сети (Python)

Если я ставлю некоторые целевой выходные значения> 1 ошибка сходятся цели-1, это-дус не видел, чтобы быть правым.

import numpy as np 
import random 

class neural_network(): 

    activation = [] #List of values with the values of activation of each layers 
    weightsIn = [] 
    weightsOut = [] 

    def __init__(self, sizeOfLayers): 
     ''' 
      sizeOfLayers: Tuple with numbers of neurons of each layer 
      (in, hidden, out) 
     ''' 
     if len(sizeOfLayers) > 3: 
      raise ValueError('Wrong number of layers') 

     self.sizeOfLayers = sizeOfLayers 
     for i in range(len(sizeOfLayers)): 
      if i == 0: 
       #input layer + bias 
       self.activation.append(sizeOfLayers[i]*[0.0] + [0.0]) 
      else: 
       self.activation.append(sizeOfLayers[i]*[0.0]) 
     # Wi = len(Hid) x len(IN)+1(bias) 
     self.weightsIn = np.random.random((sizeOfLayers[1], sizeOfLayers[0] + 1)) 
     # Wo = len(OUT) x len(Hid) 
     self.weightsOut = np.random.random((sizeOfLayers[2], sizeOfLayers[1])) 

    def forward(self, X): 
     ''' 
      X: Vetor de entradas 
     ''' 
     #In+bias add ativation vector 
     self.activation[0] = np.vstack((np.array([X]).T, np.array([1]))) 
     #sum of (weights x in) 
     self.sumHidden = self.weightsIn.dot(self.activation[0]) 
     #Ativation of hidden layer 
     self.activation[1] = (self.sigmoid(self.sumHidden)) 
     #sum of(out weights x activation of last layer) 
     self.sumOut = self.weightsOut.dot(self.activation[1]) 
     #activation of output 
     self.activation[2] = (self.sigmoid(self.sumOut)) 
     return self.activation[2].T 

    def backPropagate(self, Y, trainRate = 0.1): 
     ''' 
      Y: output target 
      trainRate: 
     ''' 
     if len(Y) != self.sizeOfLayers[2]: 
      raise ValueError('Wrong number of inputs') 

     #Calc of output delta 
     error_o = Y.T - self.activation[2].T 
     out_delta = self.sigmoidPrime(self.activation[2]) * error_o.T 
     #Calc of hidden delta 
     error_h = out_delta.T.dot(self.weightsOut) 
     hiden_delta = self.sigmoidPrime(self.activation[1]) * error_h.T 

     # update output weights output 
     change_o = self.activation[1] * out_delta.T 
     for i in range(self.sizeOfLayers[2]): 
      for j in range(self.sizeOfLayers[1]): 
       self.weightsOut[i][j] = self.weightsOut[i][j] + trainRate*change_o[j][i] 
     # update Input weights 
     change_h = self.activation[0] * hiden_delta.T 
     for i in range(self.sizeOfLayers[1]): 
      for j in range(self.sizeOfLayers[0]): 
       self.weightsIn[i][j] = self.weightsIn[i][j] + trainRate*change_h[j][i] 

     #Error 
     return np.sum((Y.T - self.activation[2].T)**2)/0.5 

    def sigmoid(self, z, derv = False): 
     if derv == False: 
      return 1/(1+np.exp(-z)) 

    def sigmoidPrime(self, z): 
     return self.sigmoid(z)*(1-self.sigmoid(z)) 

    def train(self, target, trainRate = 0.001, it = 50000): 
     for i in range(it): 
      error = 0.0 
      for t in target: 
       inputs = np.array(t[0]) 
       targets = np.array([t[1]]) 
       self.forward(inputs) 
       error = error + self.backPropagate(targets, trainRate) 

nn = neural_network((2,6,1)) 
xor = [ 
    [[0,0], [0]], 
    [[0,1], [1]], 
    [[1,0], [1]], 
    [[1,1], [0]] #If I change her to 1 it converges 
    ] 

nn.train(xor) 

Edit: Изменения были сделаны в соответствии с тем, что сказал Диего Stefano (спасибо Диего), но дос ошибки пока не сходятся.

import numpy as np 
import math 
import random 
from scipy.special import expit 
from sklearn.preprocessing import normalize 


class neural_network(object): 
    activation = [] 
    weightsIn = [] 
    weightsOut = [] 

    def __init__(self, sizeOfLayers): 
     ''' 
      sizeOfLayers: Tuple with numbers of neurons of each layer 
      (in, hidden, out) 
     ''' 
     self.sizeOfLayers = sizeOfLayers 
     for i in range(len(sizeOfLayers)): 
      self.activation.append(sizeOfLayers[i]*[0.0] + [0.0]) 

     self.weightsIn = np.random.normal(scale=0.1, size = (sizeOfLayers[1], sizeOfLayers[0] + 1)) 
     self.weightsOut = np.random.normal(scale=0.1, size = (sizeOfLayers[2], sizeOfLayers[1] + 1)) 


    def forward(self, X): 
     ''' 
      X: Vetor de entradas 
     ''' 
     #In+bias add ativation vector 
     self.activation[0] = np.vstack((np.array([X]).T, np.array([1]))) 
     #sum of (weights x in) 
     self.sumHidden = self.weightsIn.dot(self.activation[0]) 
     #+bias add ativation vector 
     self.activation[1] = np.vstack((expit(self.sumHidden), np.array([1]))) 
     #sum of(out weights x activation of last layer) 
     self.sumOut = self.weightsOut.dot(self.activation[1]) 
     #activation of output 
     self.activation[2] = (expit(self.sumOut)) 
     return self.activation[2].T 

    def backPropagate(self, X, Y, trainRate = 0.1): 
     self.forward(X) 
     #Calc of output delta 
     error_o = Y - self.activation[2].T 
     out_delta = self.sigmoidPrime(self.activation[2]) * error_o.T 
     #Calc of hidden delta 
     error_h = out_delta.T.dot(self.weightsOut) 
     hiden_delta = self.sigmoidPrime(self.activation[1]) * error_h.T 

     # update output weights output 
     change_o = self.activation[1] * np.transpose(out_delta) 

     self.weightsOut = self.weightsOut + trainRate*change_o.T 
     # update hidden weights output 
     change_h = self.activation[0].dot(hiden_delta[:-1].T) 
     self.weightsIn = self.weightsIn + trainRate*change_h.T 
     #error 
     return np.sum((Y - self.activation[2].T)**2)*0.5 


    def train(self, input_list, epochs): 
     for epoch in range(epochs): 
      ErrAcc = 0.0 
      for inputs, targets in input_list: 
       Err = self.backPropagate(np.array(inputs), np.array(targets), 0.2) 
       ErrAcc = ErrAcc + Err 
      if epoch % 1000 == 0: 
       print 'Epoch =', epoch, 'ErrAcc =', ErrAcc 

    def sigmoidPrime(self,x): 
     return expit(x)*(1-expit(x)) 


nn = neural_network((2,10,1)) 
xor = [ 
    [[0,0], [0]], 
    [[0,1], [1]], 
    [[1,0], [1]], 
    [[1,1], [0]] #If I change her to 1 it converges 
    ] 
nn.train(xor, 300000) 

ответ

0

Вот модификации, которые я сделал в своем коде, которые сделали его работу:

  1. Добавить перекосы в выходные нейроны тоже. Все нейроны в сети должны иметь это, поскольку он отделяет поле активации от начала координат и, следовательно, shifts your activation function left or right, greatly improving the chances of successful learning.

  2. Istead использования np.random.random, который genearates число в интервале [0,0, 1,0), чтобы инициализировать веса, использовать np.random.uniform для генерации случайных однородных поплавков в [-1.0, 1.0).

  3. Центр ваш вклад пространство вокруг начала координат (то есть, удалить среднее) и нормализовать его.

Вот как ваша инициализация должна быть:

for i in range(len(sizeOfLayers)): 
     self.activation.append(sizeOfLayers[i]*[0.0] + [0.0]) 

    self.weightsIn = np.random.uniform(-1,1,(sizeOfLayers[1], sizeOfLayers[0] + 1)) 
    self.weightsOut = np.random.uniform(-1,1,(sizeOfLayers[2], sizeOfLayers[1] + 1)) 

И тогда вы также должны добавить 1 к activation в функции forward:

self.activation[1] = np.vstack((self.sigmoid(self.sumHidden), np.array([1]))) 

Вы можете захотеть изменить скорость обучения, чтобы заставить его работать (около 0,5 работал на меня). Кроме того, ваш расчет среднеквадратичных ошибок неверен: вы должны умножить на 0,5, а не делиться.

Вот ваш измененный код:

import numpy as np 
import random 

class neural_network(): 

activation = [] #List of values with the values of activation of each layers 
weightsIn = [] 
weightsOut = [] 

def __init__(self, sizeOfLayers): 
    ''' 
     sizeOfLayers: Tuple with numbers of neurons of each layer 
     (in, hidden, out) 
    ''' 
    if len(sizeOfLayers) > 3: 
     raise ValueError('Wrong number of layers') 

    self.sizeOfLayers = sizeOfLayers 
    for i in range(len(sizeOfLayers)): 
     #input layer + bias 
     self.activation.append(sizeOfLayers[i]*[0.0] + [0.0]) 

    # Wi = len(Hid) x len(IN)+1(bias) 
    self.weightsIn = np.random.uniform(-1,1,(sizeOfLayers[1], sizeOfLayers[0] + 1)) 

    # Wo = len(OUT) x len(Hid) 
    self.weightsOut = np.random.uniform(-1,1,(sizeOfLayers[2], sizeOfLayers[1] + 1)) 

def forward(self, X): 
    ''' 
     X: Vetor de entradas 
    ''' 
    #In+bias add ativation vector 
    self.activation[0] = np.vstack((np.array([X]).T, np.array([1]))) 
    #sum of (weights x in) 
    self.sumHidden = self.weightsIn.dot(self.activation[0]) 
    #Ativation of hidden layer 
    self.activation[1] = np.vstack((self.sigmoid(self.sumHidden), np.array([1]))) 
    #sum of(out weights x activation of last layer) 
    self.sumOut = self.weightsOut.dot(self.activation[1]) 
    #activation of output 
    self.activation[2] = (self.sigmoid(self.sumOut)) 
    return self.activation[2].T 

def backPropagate(self, Y, trainRate = 0.1): 
    ''' 
     Y: output target 
     trainRate: 
    ''' 
    if len(Y) != self.sizeOfLayers[2]: 
     raise ValueError('Wrong number of inputs') 

    #Calc of output delta 
    error_o = Y.T - self.activation[2].T 
    out_delta = self.sigmoidPrime(self.activation[2]) * error_o.T 
    #Calc of hidden delta 
    error_h = out_delta.T.dot(self.weightsOut) 
    hiden_delta = self.sigmoidPrime(self.activation[1]) * error_h.T 

    # update output weights output 
    change_o = self.activation[1] * out_delta.T 
    for i in range(self.sizeOfLayers[2]): 
     for j in range(self.sizeOfLayers[1]): 
      self.weightsOut[i][j] = self.weightsOut[i][j] + trainRate*change_o[j][i] 
    # update Input weights 
    change_h = self.activation[0] * hiden_delta.T 
    for i in range(self.sizeOfLayers[1]): 
     for j in range(self.sizeOfLayers[0]): 
      self.weightsIn[i][j] = self.weightsIn[i][j] + trainRate*change_h[j][i] 

    #Error 
    return np.sum((Y.T - self.activation[2].T)**2)*0.5 

def sigmoid(self, z, derv = False): 
    if derv == False: 
     return 1/(1+np.exp(-z)) 

def sigmoidPrime(self, z): 
    return self.sigmoid(z)*(1-self.sigmoid(z)) 

def train(self, target, trainRate = 0.5, it = 50000): 
    for i in range(it): 
     error = 0.0 
     for t in target: 
      inputs = np.array(t[0]) 
      targets = np.array([t[1]]) 
      self.forward(inputs) 
      error = error + self.backPropagate(targets, trainRate) 

nn = neural_network((2,5,1)) 
xor = [ 
    [[-1.0, -1.0], [0]], 
    [[-1.0, 1.0], [1]], 
    [[ 1.0, -1.0], [1]], 
    [[ 1.0, 1.0], [0]] #If I change her to 1 it converges 
] 

nn.train(xor) 

for e in xor: 
    nn.forward(e[0]) 
    print nn.activation[2] 

Успехов!

+0

Спасибо, диего, я внесла ваши изменения, но ошибка для логики логики XOR еще не сходится! – bottega

+0

@bottega Вы пытались поднять число эпох? Кроме того, важная точка, о которой я говорил выше; вы можете добиться этого, заменив все нули во входных выборках вашего тренинга на «-1.0» (но только на входные образцы, так как вы используете сигмоидную функцию в выходном слое). –

Смежные вопросы