В чем ошибка при составлении нейронной сети?

import numpy as np

#функция для удобной генерации весов
#in_ сколько нейронов на слое из которого выходят синопсы
#out сколько нейронов на слое, куда ведут синопсы
def generate_weights(in_, out):
    return np.random.sample((in_, out))

#функция активатор. в данном случае сигмойд.
def activator(x, der=False):
    if der:
        return x*(1-x)
    else:
        return 1/(1+np.exp(-x))

#на вход подаем слой и веса, которые ведут к следующему слою
#пример l3 = l2, weights2
def forward(layer, weight):
    return activator(np.dot(layer, weight))

#поиск ошибки. На вход подаем слой для которого ищем ошибку, веса ведущие к этому слою и предыдущую ошибку
#пример l2_error = l2, weight2, l3_error
def find_error(layer, weight, error):
    return np.dot(weight, error)*activator(layer, True)

#поправка весов с учетом ошибки. На вход подаем слой из которого исходят синапсы,
#веса, для которых ищем поправку, коэф обучаемости, и ошибку слоя в который ведут веса.
#пример weights2 = l2, weights2, коэф[0;1], l3_error
def adjastment(layer, weight, koef, error):
    weight = weight.T
    for i in range(len(error)):
        for j in range(weight.shape[0]):
            weight[j] += koef*layer*error[i]

    return weight.T


class NeuralNetwork:
    def __init__(self, exp_res, offsets, weights, start=None):
        #генерируем веса из словаря
        self.weights = [generate_weights(j[0], j[1]) for i,j in weights.items()]
        #определяем размер тренировочного набора
        self.LEN = start.shape[0]
        #определяем последний слой (для последнего слоя принцып обработки немного отличается)
        self.LAST = len(weights)+1
        #создаем словарь в котором будут храниться все слои
        self.layers = {}
        #слои где должы быть добавлены нейроны смещения
        self.offsets = offsets
        #ошибки слоев
        self.errors = {}
        #ожидаемый результат
        self.exp_res = exp_res
        #проверяем нужно ли добавить нейрон смещения для 1 слоя
        if self.offsets['l1']:
            self.start = np.array([np.append(i,1) for i in start])
        else:
            self.start = start

    #считаем слои друг за другом
    def update_layers(self):
        for i in range(2, len(self.weights)+2):
            #слой для которого считаем         предыдущий слой      веса ведущие в этот слой
            self.layers['l'+str(i)] = forward(self.layers['l'+str(i-1)], self.weights[i-2])\
                if self.offsets['l' + str(i)] == False else \
                np.append(forward(self.layers['l'+str(i-1)], self.weights[i-2]), 1)

    #Вычисляем ошибку
    def calc_error(self, num):
        #ошибка последнего слоя = (ожидаемый результат - полученный) * производную последнего слоя
        self.errors['l'+str(self.LAST)+'_error'] = (self.exp_res[num]-self.layers['l'+str(self.LAST)]) * \
            activator(self.layers['l'+str(self.LAST)], True)
        for i in range(len(self.layers)-1,1,-1):
            if self.offsets['l'+str(i)]:
                self.errors['l'+str(i)+'_error'] = find_error(self.layers['l' + str(i)][:-1], self.weights[i-1][:-1],\
                    self.errors['l'+str(i+1)+'_error'])
            else:
                self.errors['l'+str(i)+'_error'] = find_error(self.layers['l' + str(i)], self.weights[i-1],\
                    self.errors['l'+str(i+1)+'_error'])

    #обновляем веса
    def update_weights(self, koef):
        for i in range(len(self.weights)):
            self.weights[i] = adjastment(self.layers['l'+ str(i+1)], self.weights[i], koef, self.errors['l' + str(i+2) + '_error'])

    #функция отвечающая за обучение нейронной сети.
    #на вход получает коэф обучаемости, количество эпох и через какое количество эпох выводить результат обучения сети
    #если control == None результат не печатается, а веса возвращаются как результат работы функции.
    def run(self, koef, times, control=None):
        for i in range(times):
            total_error = 0
            for n in range(self.LEN):
                self.layers['l1'] = self.start[n]
                self.update_layers()
                self.calc_error(n)
                self.update_weights(koef)
                if i % control == 0 and control is not None:
                    for j in self.errors['l'+str(self.LAST)+'_error']:
                        total_error += (1/len(self.layers['l'+str(self.LAST)]))*j*j
                    print('ожидаемый результат\t',self.exp_res[n])
                    print('полученный\t', self.layers['l'+str(self.LAST)])
                    print('итерация\t', i)
                    print('\n\n')
            if i % control == 0 and control is not None:
                print('ошибка\t', total_error)
                print('\n\n')
        if control is None:
            return self.weights


if __name__ == '__main__':
    test = np.array([[0,0,0],
                     [0,0,1],
                     [0,1,0],
                     [0,1,1],
                     [1,0,0],
                     [1,0,1],
                     [1,1,0],
                     [1,1,1]])

    exp_res = np.array([[0,0,1,1,1,1,0,0]]).T

    #слои на которых нужно добавить нейроны смещения.
    offsets = {'l1': True,
               'l2': True,
               'l3': False}

    #определяем сколько на каждом слое будет нейронов.
    #разница 2 и 3 получается из-за того что есть нейрон смещения.
    weights = {'l1': (4,2),
               'l2': (3,1)}


    training = NeuralNetwork(exp_res, offsets, weights, start=test)
    training.run(0.5, 10001, 2000)

Пробовал ее на совсем легких примерах (даже проще чем этот) все работает нормально, но как только берутся примеры хоть чуть чуть сложнее, как например вот такой:
test = np.array([[1,1,1,
                  0,0,0,
                  0,0,0],
                 [0,0,0,
                  1,1,1,
                  0,0,0],
                 [0,0,0,
                  0,0,0,
                  1,1,1],
                 [1,0,0,
                  1,0,0,
                  1,0,0],
                 [0,1,0,
                  0,1,0,
                  0,1,0],
                 [0,0,1,
                  0,0,1,
                  0,0,1],
                 [1,1,1,
                  1,0,0,
                  1,0,0],
                 [1,1,1,
                  0,1,0,
                  0,1,0],
                 [1,1,1,
                  0,0,1,
                  0,0,1],
                 [1,0,0,
                  1,1,1,
                  1,0,0],
                 [0,1,0,
                  1,1,1,
                  0,1,0],
                 [0,0,1,
                  1,1,1,
                  0,0,1],
                 [1,0,0,
                  1,0,0,
                  1,1,1],
                 [0,1,0,
                  0,1,0,
                  1,1,1],
                 [0,0,1,
                  0,0,1,
                  1,1,1],
                 [0,0,0,
                  0,0,0,
                  0,0,0]])

exp_res = np.array([[0.8,0.2],
                    [0.8,0.2],
                    [0.8,0.2],
                    [0.2,0.8],
                    [0.2,0.8],
                    [0.2,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.8,0.8],
                    [0.2,0.2]])

И нейронака, хоть в ходе обучения и уменьшает ошибку, но совсем чуть-чуть.
Вопрос в том, что собственно не так. В этой теме я новенький, формулы и алгоритм обучения вроде правильные, но точно это сказать я не могу.
  • Вопрос задан
  • 565 просмотров
Решения вопроса 1
@Ander813 Автор вопроса
Итак, ошибка была при обновлении весов:
def adjastment(layer, weight, koef, error):
    weight = weight.T
    for i in range(len(error)):
        for j in range(weight.shape[0]):
            weight[j] += koef*layer*error[i]

    return weight.T

Что должно было быть:
def adjastment(layer, weight, koef, error):
    for i in range(weight.shape[0]):
        weight[i] += koef*layer[i]*error
    return weight

Перемудрил и из-за этого, пускай веса и смещались в правильную сторону, но смещение это было меньше. И чем дольше сеть обучалась, тем меньше было смещение.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@Messiah_v2
Боролся с такой же проблемой. Сеть почти такая же.
Пока на просторах интернета нашел то, что в нашем случае ошибку ищем по MSE.
На небольшой сети работает на отличненько. К масштабируемости очень привередливый способ.
Если формулы в формулах не теряетесь, то Binary cross-entropy возможное решение.
https://towardsdatascience.com/understanding-binar... - на примере показана логистическая регрессия, но можно применить и к нашей модели. Сам разбираюсь как. Если найду решение отпишу.

P.S. Странно что сыпется уже на 9 входящих параметрах... мне вообще требуется 568))
Ответ написан
Комментировать
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
В этой теме я новенький, формулы и алгоритм обучения вроде правильные, но точно это сказать я не могу.
Ответ прост: как только сможете сказать ТОЧНО: правильные или нет, так и найдёте ответ. А чтобы это сделать - разбирайте логику и код.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы