Нейросеть обучается угадыванию столбца матрицы (простейшая нейронка)
Есть код простейшей нейросети на 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 шт):
Отвечаю по пунктам:
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 знакомились, хотя-бы поверхностно, до того, как кинуться писать нейросети?
На самом деле сами действия, которые происходят с точки зрения математических вычислений, я понял. То есть то, что outputs это массив размерностью 4 на 1, что в нем записано произведение матрицы входных значений и весов. Также, что полученный результат из первого вопроса мы умножаем на err, и все остальное.
Мой основной вопрос тогда звучит - ЗАЧЕМ мы это делаем? То есть, мы изначально произвели несколько действий, следуя теории работы с нейросетью перцептроном:
- перемножение входных значений на веса
- сделали нормирование этих значений через сигмоиду
- вычитая полученный массив из массива с правильными ответами мы получили ошибку err (на сколько наша нейросеть ошиблась в первой итерации)
А вот дальше мы должны сделать коррекцию весов. И это переменная adjustments, которую мы прибавим к старым весам. И вот как именно она посчитана - я не понимаю с точки зрения алгоритма вычислений этой коррекции. Что именно мы сделали, и почему мы именно это сделали? По каким правилам мы здесь шли?
Выдержка из теории: "Здесь мы должны следовать градиентному спуску, и рассчитать вектор градиента ошибки. Это вектор из частных производных функции по всем ее аргументам. Его размерность равна количеству всех искомых весов, а направлен он в этом пространстве в сторону локального возрастания функции ошибки. Это значит, что градиент со знаком «-» направлен в сторону локального убывания ошибки. И мы можем немного подвинуться вдоль анти-градиента в сторону новых весов, где ошибка уже будет меньше."
У нас есть наша ошибка err. Что мы дальше сделали с ней в этом длинном произведении, и почему именно так? Брали мы здесь производную от чего-то или нет? И зачем мы вычитаем нашу ошибку из вектора, где все единицы?