Шаг-4: Выполняем аналогичный процесс для “входных” коэффициентов w1..w4, формулы тут примерно аналогичны предыдущему пункту.
Шаги 1..4 повторяются до тех пор, пока ошибка не станет меньше некоторой величины. Этот процесс весьма медленный, и может требоваться несколько тысяч итераций, однако выполняется он лишь однократно. Далее коэффициенты можно сохранить, и сеть уже обучена воспроизводить указанный при обучении набор данных. Эти весовые коэффициенты фактически и являются аналогом нейронных связей, появляющихся после обучения в “биологической” сети.
Более подробно формулы с примерами вычислений можно найти здесь. А мы рассмотрим программу на языке Python, реализующую данный метод.
import math, random
class MLP(object):
def __init__(self, n_in, n_hidden, n_out):
self.n_in = n_in
self.n_hidden = n_hidden
self.n_out = n_out
# Входные данные: массив [n_in + 1] инициализирован значениями 1.0
self.inputLayer = [1.0] * (n_in + 1)
# Веса входного-скрытого слоя: матрица [n_in+1]x[n_hidden] заполнена 0..1
self.wIH = [[random.random() for x in range(n_in + 1)] for y in range(n_hidden)]
# Скрытые нейроны: [n_hidden + 1]
self.hiddenLayer = [1.0] * (n_hidden + 1)
# Веса нейронов скрытого-выходного слоя: [n_hidden+1]x[n_out], 0..1
self.wHO = [[random.random() for x in range(n_hidden + 1)] for y in range(n_out)]
# Выходной слой: массив
self.outputLayer = [1.0] * n_out
def printValues(self):
print "Network: input/hidden/output: {}/{}/{}".format(self.n_in, self.n_hidden, self.n_out)
print "Вход", self.inputLayer
print "wIH", self.wIH
print "Скрытый слой", self.hiddenLayer
print "wHO", self.wHO
print "Выход", self.outputLayer
def printOutput(self):
print "Вход", self.inputLayer
print "Выход", self.outputLayer
def sigmoid(self, x):
# Функция активации
return 1.0 / (1.0 + math.exp(-x))
def derivative(self, x):
# Производная функции активации
return x * (1 - x)
def forwardPass(self, x):
# Прямое распространение
# Input
for p in range(len(x)):
self.inputLayer[p] = x[p]
# Input-Hidden
for h in range(self.n_hidden):
sum = 0.0
for i in range(len(self.inputLayer)):
sum += self.inputLayer[i] * self.wIH[h][i]
self.hiddenLayer[h] = self.sigmoid(sum)
# Hidden-Output
for o in range(self.n_out):
sum = 0.0
for h in range(len(self.hiddenLayer)):
sum += self.hiddenLayer[h] * self.wHO[o][h]
self.outputLayer[o] = self.sigmoid(sum)
def backPass(self, input, target):
# Обратное распространение
# Формулы основаны на статье
# https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/
learn_rate = 0.5
# Output->hidden layer adjust weights
for o in range(self.n_out):
for h in range(self.n_hidden):
deout = -(target[o] - self.outputLayer[o])
der = self.derivative(self.outputLayer[o])
hid = self.hiddenLayer[h]
der = deout * der * hid
prev = self.wHO[o][h]
self.wHO[o][h] -= learn_rate * der
# Hidden->input layer adjust weights
for h in range(self.n_hidden):
for i in range(self.n_in):
derSum = 0.0
for o in range(self.n_out):
deout = -(target[o] - self.outputLayer[o])
derOut = self.derivative(self.outputLayer[o])
der = deout * derOut * self.wHO[o][h]
derSum += der
derH = self.derivative(self.hiddenLayer[h])
derI = self.inputLayer[i]
der = derSum * derH * derI
prev = self.wIH[h][i]
self.wIH[h][i] -= learn_rate * der
def calcError(self, x, target):
# Вычисление ошибки: 0.5*Sum(dV^2)
err = 0.0
for p in range(self.n_out):
err += 0.5 * ((self.outputLayer[p] - target[p]) ** 2)
return err
Как можно видеть, создан класс MLP, принимающий на входе 3 параметра: число входных нейронов, число скрытых нейронов, число выходных нейронов.
Рассмотрим пример использования этой сети для логической функции XOR. Как известно, она имеет следующую таблицу истинности:
Таким образом, в нашей сети будет 2 входных параметра (их еще называют “характеристиками”) и 1 выходной. Количество скрытых нейронов пусть будет 2.