A
A
Ander8132019-11-18 21:06:41
Python
Ander813, 2019-11-18 21:06:41

What is wrong with building a neural network?

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()

    exp_res = np.array().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)

I tried it on very easy examples (even simpler than this one), everything works fine, but as soon as the examples are taken, at least a little more difficult, such as this one:
test = np.array()

exp_res = np.array()

And neuronac, although in the course of training it reduces the error, but just a little.
The question is what is actually wrong. I'm new in this topic, the formulas and the learning algorithm seem to be correct, but I can't say for sure.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
A
Ander813, 2019-11-19
@Ander813

So, the error was when updating the weights:

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

What should have been:
def adjastment(layer, weight, koef, error):
    for i in range(weight.shape[0]):
        weight[i] += koef*layer[i]*error
    return weight

I was too clever and because of this, even if the weights shifted in the right direction, but the shift was less. And the longer the network was trained, the smaller the bias.

A
Alexey, 2019-11-19
@Messiah_v2

Struggled with the same problem. The network is pretty much the same.
So far, on the Internet, I found that in our case we are looking for an error by MSE.
Works great on a small network. To scalability very fastidious way.
If formulas in formulas are not lost, then Binary cross-entropy is a possible solution.
https://towardsdatascience.com/understanding-binar... - the example shows logistic regression, but can be applied to our model as well. I understand how. If I find a solution I'll post it.
PS It's strange that it's already pouring on 9 incoming parameters ... I generally need 568))

X
xmoonlight, 2019-11-19
@xmoonlight

I'm new in this topic, the formulas and the learning algorithm seem to be correct, but I can't say for sure .
The answer is simple: as soon as you can say EXACTLY: correct or not, you will find the answer. And to do this - disassemble the logic and code.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question