Пример использования ООП (нейронная сеть)

На этом занятии мы применим наши знания ООП в Python и реализуем простую нейронную сеть. Пару слов, о том что это такое. Нейронная сеть представляет собой вот такую распределенную структуру. Здесь у нас имеется входной слой, далее несколько скрытых слоев нейронов и затем, выходной слой.

Принцип ее работы такой. На вход подаются данные, представленные в виде вещественных чисел от 0 до 1. Далее, эти числа проходят по связям между нейронами с разной степенью затухания, определяемой множителем w_ij. На входе каждого нейрона следующего слоя эти сигналы суммируются с учетом этих весов и на основе этой суммы формируется выходной сигнал соответствующего нейрона. Далее, эти сигналы подаются на нейроны следующего уровня, и так до последнего выходного слоя. По этим выходным числовым значениям делается вывод о свойствах входного сигнала. Разумеется, чтобы нейронная сеть работала, она должна быть обучена, то есть, веса ее связей должны быть должным образом настроены. Этот этап останется за рамками нашего занятия. Мы здесь лишь реализуем построение нейронной сети со случайными весами связей, а внутри каждого нейрона суммарный сигнал будет преобразовываться в выходной с помощью вот такой сигмоидальной функции:

Здесь z – это входной суммарный взвешенный сигнал, а y – выходное значение нейрона. Как видите, входной сигнал z из диапазона (-∞; +∞) масштабируется в диапазон (0;1). Поэтому эту функцию еще называют масштабирующей. Она гарантирует, что выходные значения всегда будут вещественными числами от 0 до 1.

Итак, реализуем такую нейронную сеть, схематично она представлена вот в таком виде. И начнем с описания класса нейронов.

Для этого создадим отдельный файл, в котором будет класс Neuro:

import math
 
class Neuro:
    def __init__(self, list_in, list_out):
        self.__in = list_in
        self.__out = list_out
        self.value = 0        # выходной сигнал с нейрона
 
    @property
    def list_in(self):
        return self.__in
 
    @list_in.setter
    def list_in(self, lst):
        self.__in = lst
 
    @property
    def list_out(self):
        return self.__out
 
    @list_out.setter
    def list_out(self, lst):
        self.__out = lst
 
    def act(self, x):
        return 1/(1+math.exp(-x))

Далее, создадим модуль для связей между нейронами:

class Link:
    def __init__(self, n_in, n_out, w = 0):
        self.__in = n_in
        self.__out = n_out
        self.__w = w
 
    @property
    def n_in(self):
        return self.__in
 
    @property
    def n_out(self):
        return self.__out
 
    @property
    def w(self):
        return self.__w

И, наконец, класс, описывающий создание и работы НС:

import random
from neuro import Neuro
from link import Link
 
class Network:
    def __init__(self, *args):
        self.__nlayers = len(args)  # число слоев
        self.__neuros = args   # число нейронов в кажом слое
        self.__layers = []
 
        #создаем нейроны в каждом слое
        for i in range( self.__nlayers ):
            self.__layers.append( [Neuro([], []) for n in range(self.__neuros[i])] )
 
        #создаем связи между нейронами
        for i in range( self.__nlayers ):
            for neuro in self.__layers[i]:      # перебираем нейроны i-го слоя
                list_in = 0 if i == 0 else [ Link(n_in, neuro, random.random()) for n_in in self.__layers[i-1] ]
                list_out = 0 if i == self.__nlayers-1 else [Link(neuro, n_out, random.random()) for n_out in self.__layers[i+1]]
                neuro.list_in = list_in
                neuro.list_out = list_out
 
    def run(self, v):
        # подаем на вход нейронов сигнал v
        for neuro, inp in zip(self.__layers[0], v):
            neuro.value = neuro.list_in = inp
 
        # проводим сигнал по нейронной сети
        for i in range(1, self.__nlayers):
            for neuro in self.__layers[i]:    # перебираем нейроны i-го слоя
                v = [ (link.n_in.value*link.w) for link in neuro.list_in ]
                neuro.value = neuro.act( sum(v) )
 
    def output(self):
        return [ neuro.value for neuro in self.__layers[-1] ]

Все это мы можем использовать, например, так:

from network import Network
 
net = Network(10, 5, 5)
net.run([1, 0.5, 0.1, 0.2, 0.7, 0.9, 1, 0.6, 0.3, 0.1])
out = net.output()
print( out )

Все, нейронная сеть готова!