пятница, 3 января 2014 г.

Простой перцептрон


Простой перцептрон состоит из нескольких входов inp_t[1], inp_t[2] ... inp_t[n].
Каждому входу соответствует некий вес  w[1], w[2] ... w[n].
Также имеется вход активации inp_b с весом w_b.
На вход активации постоянно подается единица,  а вес на входе активации задает порог срабатывания перцептрона.

На выходе перцептрона  может быть либо единица 1 либо -1 в зависимости от входных сигналов и весовых коэффициентов.

Условие срабатывания перцептрона ( когда на выходе появляется единица) :

w_b +   w[1] *  inp_t[1] + w[2] *  inp_t[2] + ...+ w[n] *  inp_t[n]  > 0

Но можно и не различать входы inp_t и inp_b, а просто предположить, что у перцептрона  есть еще один вход inp_t[0], на который всегда подается единица, а w_b записать как w[0].
Тогда условие срабатывания перцептрона можно записать так:

w[0] *  inp_t[0] + w[1] *  inp_t[1] + w[2] *  inp_t[2] + ...+ w[n] *  inp_t[n]  > 0

Обучение перцептрона сводится к такому подбору весов w[0]...w[n] , при которых для всех
входных наборов данных  (inp_t[1], inp_t[2] ... inp_t[n]),  (inp_t[1], inp_t[2] ... inp_t[n]) ... (inp_t[1], inp_t[2] ... inp_t[n]), на выходе появлялось бы требуемое целевое значение out_t , соответствующее каждому входному набору.

Если реальное выходное значение перцептрона  out_r  отличается от требуемого целевого значения out_t,  то необходимо подправить веса w[0]....w[n] перцептрона.

На каждом шаге обучения веса w[0]....w[n] должны изменяться в соответствии с правилом:

w[i] += t * (out_t - out_r) * inp_t[i]

где  t - это небольшая константа (обычно  0,05 - 0,2) , которая задает скорость обучения.

Например обучим перцептрон логической функции дизъюнкции (операции ИЛИ).

 inp_t[1]  inp_t[2]  out_t

0    0   -1
0    1    1
1    0    1
1    1    1

На вход алгоритму подаем скорость обучения t = 0,1
и входной вектор из четырех тестовых наборов [[0,0,-1],[0,1,1],[1,0,1],[1,1,1]]
в соответствии с таблицей истинности логической операции ИЛИ.
на выходе должны получить вектор весовых коэффициентов w[0]....w[n]



Алгоритм обучения простого перцептрона:

import random

def PerTrain(t, v):

    w = []

    # инициализируем начальные веса маленькими случайными значениями
    for i in range(len(v[0])):
        w.append((random.randrange(-5,5))/50.0)

    chw = True
    while (chw == True):

       chw = False
      
       for tst_n in v:
           
            # получаем входные значения из тесового набора
            # единицу добавляем для входа активации  ( inp_t[0] = 1)
            inp_t = [1] + tst_n[0:len(tst_n) - 1]
          
            # получаем целевое выходное значение из тестового набора
            out_t = tst_n[len(tst_n) - 1]
          
            # реальное выходное значение будет вычислено позже
            out_r = 0

            # вычисляем выходное значение перцептрона (out_r)
            for i in range(len(w)):
                out_r += w[i] * inp_t[i]

            if out_r > 0:
                out_r = 1
            else:
                out_r = -1

           
            if (out_r != out_t):
                chw = True
                # если на каком либо тестовом наборе перцептрон не сработал, то пересчитываем веса
                for i in range(len(w)):
                    w[i] += t * (out_t - out_r) * inp_t[i]
                   
                break  

    return w

rez = PerTrain(0.1,[[0,0,-1],[0,1,1],[1,0,1],[1,1,1]])

print(rez)



Например получили такие веса:

[-0.1, 0.14, 0.16]

Проверяем:

print(1*-0.1 + 0*0.14 + 0*0.16)
print(1*-0.1 + 0*0.14 + 1*0.16)
print(1*-0.1 + 1*0.14 + 0*0.16)
print(1*-0.1 + 1*0.14 + 1*0.16)

в результате получаем:

-0.1
0.06
0.04000000000000001
0.2

что действительно соответствует дизъюнкции:

-1
 1
 1
 1