Нейронные сети: вступление


Итак, после длительного перерыва продолжим исследование методов прогнозирования. Наиболее перспективным, на мой взгляд, является прогнозирование с использованием нейронных сетей.

Искусственная нейронная сеть представляют собой систему соединённых и взаимодействующих между собой простых процессоров (искусственных нейронов). Такие процессоры обычно довольно просты, особенно в сравнении с процессорами, используемыми в персональных компьютерах. Каждый процессор подобной сети имеет дело только с сигналами, которые он периодически получает, и сигналами, которые он периодически посылает другим процессорам. И тем не менее, будучи соединёнными в достаточно большую сеть с управляемым взаимодействием, такие локально простые процессоры вместе способны выполнять довольно сложные задачи.

Выдержка из википедии

Нейронная сеть состоит из нейронов и связей между ними(аксоны). Нейрон представляет из себя нелинейный сумматор: суммирует сигналы поступающие на входы (каждый с определенным коэффициентом) и над полученной суммой выполняет нелинейное преобразование (передаточная функция или функция активации). Полученный результат может быть передан другим нейронам (так же с различными коэффициентами).

Для того что бы нейронная сеть выполняла какую-либо определенную задачу, необходимо произвести ее обучение, которое заключается в подборе весовых коэффициентов между нейронами: на вход подается входной сигнал, вычисляется выходной сигнал и сравнивается с требуемым и в зависимости от величины ошибки изменяются весовые коэффициенты, чтобы снизить величину ошибки. И так много (зачастую даже очень много) раз. Однократный проход по всем обучающим данным называется итерацией. На начальном этапе обучения весовым коэффициентам присваиваются случайные значения.

Схема многослойной нейронной сети

Схема многослойной нейронной сети

Когда необходимо предсказать следующее значение временного ряда, как правило используют трехслойную нейронную сеть (1-й слой — входной, 2-й — скрытый, 3-й — выходной слой), которая обучается на опытных данных с помощью метода обратного распространения ошибки. Подробнее об этом методе можно прочитать в википедии.

Существует множество программных средств, которые умеют создавать, обучать и тестировать нейронные сети и на их основе строить прогнозы, но… мы пойдем другим путем.

В качестве фундамента для экспериментов над нейронными сетями воспользуемся простой питоновской библиотекой bpnn.py . С ее помощью можно построить многослойную нейронную сеть и обучить ее методом обратного распространения ошибки — то что доктор прописал.

Для начала взглянем на ее исходный код, благо он небольшой:

# Back-Propagation Neural Networks
# 
# Written in Python.  See http://www.python.org/
# Placed in the public domain.
# Neil Schemenauer <nas@arctrix.com>

import math
import random
import string

random.seed(0)

# calculate a random number where:  a <= rand < b
def rand(a, b):
    return (b-a)*random.random() + a

# Make a matrix (we could use NumPy to speed this up)
def makeMatrix(I, J, fill=0.0):
    m = []
    for i in range(I):
        m.append([fill]*J)
    return m

# our sigmoid function, tanh is a little nicer than the standard 1/(1+e^-x)
def sigmoid(x):
    return math.tanh(x)

# derivative of our sigmoid function, in terms of the output (i.e. y)
def dsigmoid(y):
    return 1.0 - y**2

class NN:
    def __init__(self, ni, nh, no):
        # number of input, hidden, and output nodes
        self.ni = ni + 1 # +1 for bias node
        self.nh = nh
        self.no = no

        # activations for nodes
        self.ai = [1.0]*self.ni
        self.ah = [1.0]*self.nh
        self.ao = [1.0]*self.no

        # create weights
        self.wi = makeMatrix(self.ni, self.nh)
        self.wo = makeMatrix(self.nh, self.no)
        # set them to random vaules
        for i in range(self.ni):
            for j in range(self.nh):
                self.wi[i][j] = rand(-0.2, 0.2)
        for j in range(self.nh):
            for k in range(self.no):
                self.wo[j][k] = rand(-2.0, 2.0)

        # last change in weights for momentum   
        self.ci = makeMatrix(self.ni, self.nh)
        self.co = makeMatrix(self.nh, self.no)

    def update(self, inputs):
        if len(inputs) != self.ni-1:
            raise ValueError('wrong number of inputs')

        # input activations
        for i in range(self.ni-1):
            #self.ai[i] = sigmoid(inputs[i])
            self.ai[i] = inputs[i]

        # hidden activations
        for j in range(self.nh):
            sum = 0.0
            for i in range(self.ni):
                sum = sum + self.ai[i] * self.wi[i][j]
            self.ah[j] = sigmoid(sum)

        # output activations
        for k in range(self.no):
            sum = 0.0
            for j in range(self.nh):
                sum = sum + self.ah[j] * self.wo[j][k]
            self.ao[k] = sigmoid(sum)

        return self.ao[:]

    def backPropagate(self, targets, N, M):
        if len(targets) != self.no:
            raise ValueError('wrong number of target values')

        # calculate error terms for output
        output_deltas = [0.0] * self.no
        for k in range(self.no):
            error = targets[k]-self.ao[k]
            output_deltas[k] = dsigmoid(self.ao[k]) * error

        # calculate error terms for hidden
        hidden_deltas = [0.0] * self.nh
        for j in range(self.nh):
            error = 0.0
            for k in range(self.no):
                error = error + output_deltas[k]*self.wo[j][k]
            hidden_deltas[j] = dsigmoid(self.ah[j]) * error

        # update output weights
        for j in range(self.nh):
            for k in range(self.no):
                change = output_deltas[k]*self.ah[j]
                self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k]
                self.co[j][k] = change
                #print N*change, M*self.co[j][k]

        # update input weights
        for i in range(self.ni):
            for j in range(self.nh):
                change = hidden_deltas[j]*self.ai[i]
                self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j]
                self.ci[i][j] = change

        # calculate error
        error = 0.0
        for k in range(len(targets)):
            error = error + 0.5*(targets[k]-self.ao[k])**2
        return error

    def test(self, patterns):
        for p in patterns:
            print(p[0], '->', self.update(p[0]))

    def weights(self):
        print('Input weights:')
        for i in range(self.ni):
            print(self.wi[i])
        print()
        print('Output weights:')
        for j in range(self.nh):
            print(self.wo[j])

    def train(self, patterns, iterations=1000, N=0.5, M=0.1):
        # N: learning rate
        # M: momentum factor
        for i in range(iterations):
            error = 0.0
            for p in patterns:
                inputs = p[0]
                targets = p[1]
                self.update(inputs)
                error = error + self.backPropagate(targets, N, M)
            if i % 100 == 0:
                print('error %-.5f' % error)

def demo():
    # Teach network XOR function
    pat = [
        [[0,0], [0]],
        [[0,1], [1]],
        [[1,0], [1]],
        [[1,1], [0]]
    ]

    # create a network with two input, two hidden, and one output nodes
    n = NN(2, 2, 1)
    # train it with some patterns
    n.train(pat)
    # test it
    n.test(pat)

if __name__ == '__main__':
    demo()

В функции demo показан пример использования библиотеки: в массив pat записывается совокупность входных сигналов и требуемых реакций нейронной сети; потом создается нейронная сеть с двумя входными нейронами, двумя нейронами в скрытом слое и одним выходным нейроном; производится обучение; и в конце — тестирование обученной нейронной сети.

Обратим внимание на исходный код функции train — в качестве параметров ей можно передать не только множество для обучения, но и указать количество итераций, скорость обучения и коэффициент импульса (коэффициент импульса позволяет сгладить резкие скачки коррекции весовых коэффициентов относительно других коррекций — немного путано, но мы еще к нему вернемся).

Демо для библиотеки bpnn.py

Демо для библиотеки bpnn.py

Продолжение следует, а на сегодня пока все.

, , ,



  1. Пока нет комментариев.
(никто не узнает)