Нейросеть обучается угадыванию столбца матрицы (простейшая нейронка)

Есть код простейшей нейросети на Python. Нейросеть обучается правильно рассчитать столбец матрицы. Просьба объяснить, что происходит в данной строке:

adjustments = np.dot( input_layer.T, err * (outputs * (1 - outputs)))

В особенности, что происходит в каждом блоке, по пунктам:

1) outputs * (1 - outputs)
2) err * (outputs * (1 - outputs))
3) np.dot( input_layer.T, err * (outputs * (1 - outputs)))

Весь код:

import numpy as np

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

training_inputs = np.array([[0,0,1],
                            [1,1,1],
                            [1,0,1],
                            [0,1,1]])
training_outputs = np.array([[0],
                             [1],
                             [1],
                             [0]])
np.random.seed(1)
synaptic_weights = 2 * np.random.random((3,1)) - 1

print("Random weights: ")
print(synaptic_weights)

for i in range(20000):
    input_layer = training_inputs
    outputs = sigmoid( np.dot(input_layer, synaptic_weights) )

    err = training_outputs - outputs
    adjustments = np.dot( input_layer.T, err * (outputs * (1 - outputs)))

    synaptic_weights += adjustments

print( "Weights after study: " )
print(synaptic_weights)

print("Result: ")
print(outputs)

Спасибо!


Ответы (2 шт):

Автор решения: passant

Отвечаю по пунктам:

1) outputs * (1 - outputs)

Объект outputs представляет собой numpy-массив, в вашем случае размерностью 4(строки)х1(столбец) - то-есть вектор-столбец. Его значения поэлементно вычитаем из вектор-столбца, состоящего из всех 1, а тот вектор-столбец, который получается в результате этой операции умножаем поэлементно на вектор-столбцец outputs

2) err * (outputs * (1 - outputs))

Полученный в результате выполнения предыдущего действия вектор-столбец поэлементно умножаем на вектор-столбец err

3) np.dot( input_layer.T, err * (outputs * (1 - outputs)))

Функция np.dot выполняет скалярное произведение двух векторов. В вашем - случае вектор-строки, полученной транспонированием вектор-столбца input_layer и вектора, полученного на предыдущем шаге.

Надеюсь, разъяснил. Но у меня возник встречный вопрос - а вы с самим пакетом numpy знакомились, хотя-бы поверхностно, до того, как кинуться писать нейросети?

→ Ссылка
Автор решения: Nairobi

На самом деле сами действия, которые происходят с точки зрения математических вычислений, я понял. То есть то, что outputs это массив размерностью 4 на 1, что в нем записано произведение матрицы входных значений и весов. Также, что полученный результат из первого вопроса мы умножаем на err, и все остальное.

Мой основной вопрос тогда звучит - ЗАЧЕМ мы это делаем? То есть, мы изначально произвели несколько действий, следуя теории работы с нейросетью перцептроном:

  1. перемножение входных значений на веса
  2. сделали нормирование этих значений через сигмоиду
  3. вычитая полученный массив из массива с правильными ответами мы получили ошибку err (на сколько наша нейросеть ошиблась в первой итерации)

А вот дальше мы должны сделать коррекцию весов. И это переменная adjustments, которую мы прибавим к старым весам. И вот как именно она посчитана - я не понимаю с точки зрения алгоритма вычислений этой коррекции. Что именно мы сделали, и почему мы именно это сделали? По каким правилам мы здесь шли?

Выдержка из теории: "Здесь мы должны следовать градиентному спуску, и рассчитать вектор градиента ошибки. Это вектор из частных производных функции по всем ее аргументам. Его размерность равна количеству всех искомых весов, а направлен он в этом пространстве в сторону локального возрастания функции ошибки. Это значит, что градиент со знаком «-» направлен в сторону локального убывания ошибки. И мы можем немного подвинуться вдоль анти-градиента в сторону новых весов, где ошибка уже будет меньше."

У нас есть наша ошибка err. Что мы дальше сделали с ней в этом длинном произведении, и почему именно так? Брали мы здесь производную от чего-то или нет? И зачем мы вычитаем нашу ошибку из вектора, где все единицы?

→ Ссылка