Выбрать главу

Шаг-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.