Знакомство с простейшей нейронной сетью и ее пошаговая реализация

Как-то раз я наткнулся на книгу под названием «Создай свою нейросеть», автор которой -Тарик Рашид и после прочтения остался доволен, в отличие от многих других методичек по нейронным сетям, которые по-своему, несомненно, хороши, в этой книге все подавалось простым языком c достаточным количеством примеров и советов

Вдохновившись этой книгой, я хочу пройтись пошагово- а именно по практической части — написанию кода простой нейронной сети.

Эта статья для тех, кто хочет заниматься нейронными сетями и машинным обучением, но пока с трудом понимает эту удивительную область науки. Ниже будет описан самый простой скелет кода нейронной сети, чтобы многие поняли простейший принцип построения и взаимодействия всего того, из чего состоит эта нейронная сеть.

image

Теории по машинному обучению и нейронным сетям на хабре и так достаточно. Но если кому-то это необходимо, некоторые ссылки я оставлю в конце статьи. А сейчас, приступаем непосредственно к написанию кода, причем писать мы будем на python, будет лучше, если при написании кода вы будете использовать jupyter-notebook

Шаг 1. Инициализация сети


Сначала нам, конечно же, надо инициализировать все действующие компоненты нашей сети

#импортируем numpy — это библиотека языка Python, добавляющая поддержку больших многомерных массивов и матриц
import numpy
# импортируем scipy.special , -scipy содержит модули для оптимизации, интегрирования, специальных функций, обработки изображений и  многих других задач, нам же здесь нужна наша функция активации, имя которой - "сигмоида "
import scipy.special
#Вероятно, нам понадобится визуализировать наши данные
import matplotlib.pyplot 

# Определяем наш класс нейронной сети
class neuralNetwork:
    
    # Инициализация нашей  нейронной сети
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): #В параметрах мы записываем обязательный self, входные данные,  данные  скрытого слоя, выходные данные ,скорость обучения соответственно)
        # устанавливаем количество узлов для входного , скрытого слоя, выходного слоя
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        # Тут обозначены веса матрицы, wih -  вес между входным и скрытым слоем , а  так же  who- вес между скрытым и выходным  слоем
        self.wih = numpy.random.rand(self.hnodes, self.inodes)
        self.who = numpy.random.rand(self.onodes, self.hnodes)

        # Скорость обучения -это наш гиперпараметр, то есть, параметр , который мы подбираем ручками, и в зависимости от того, как нам это удобно нам, и , конечно же, нейронной сети
        self.lr = learningrate
        
        # Наша Сигмоида- функция активации
        self.activation_function = lambda x: scipy.special.expit(x)

Сигмоида


Эта функция относится к классу непрерывных функций, принимает на вход произвольное вещественное(т.е не обязательно целое) число и на выходе дает вещественное число в интервале от 0 до 1.

В частности, большие (по модулю) отрицательные числа превращаются в ноль, а большие положительные – в единицу.

Выход ее хорошо интерпретируется, как уровень активации нейрона: от отсутствия активации (0) до полностью насыщенной активации (1).

Сигмоида выражается формулой:

image

График сигмоидальной функции в соответствии с рисунком ниже:

image

Сигмоидальная функция является:

  • непрерывной;
  • монотонно возрастающей;
  • дифференцируемой.

В данном коде сигмоида присутствует, как вы можете видеть, под именем expit(x)

Немного о том, как выглядит узел в нейронной сети


image

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

1-я Функция занимается тем, что получает все входные, с учетом весов, данные, и иногда даже с учетом нейрона смещения(специальный нейрон, который просто позволяет графикам подвинуться, а не смешиваться в одну некрасивую кучу, вот и все)

2-я Функция принимает в качестве параметра то самое значение, которое насуммировала первая функция, и эта вторая функция называется функцией активации. В нашем случае -cигмоида

Продолжаем:

Часть 2. Тренировка Нейронной Сети


def train(self, inputs_list, targets_list):
        # Конвертируем наш список в двумерный массив
        inputs = numpy.array(inputs_list, ndmin=2).T # поступающие на вход данные input
        targets = numpy.array(targets_list, ndmin=2).T #целевые значения targets
        
        # Подсчет сигнала в скрытом слое
        hidden_inputs = numpy.dot(self.wih, inputs)
        # Подсчет сигналов, выходящих из скрытого слоя к выходному слою. Тут в нашем узле, куда поступали все данные в переменную hidden_inputs (1я функция), эта переменная подается  как параметр в Сигмоиду - функцию активации (2я функция)
        hidden_outputs = self.activation_function(hidden_inputs)
        
        # Подсчет сигналов в конечном(выходном) слое
        final_inputs = numpy.dot(self.who, hidden_outputs)
        # Подсчет  сигналов, подающихся в функцию активации
        final_outputs = self.activation_function(final_inputs)
        
        # Значение ошибки (Ожидание - Реальность)
        output_errors = targets - final_outputs
        # Ошибка скрытого слоя становится ошибкой ,которую мы получили для <b>ошибки выходного слоя</b>, но уже <b>распределенные по весам между скрытым и выходным слоями</b>(иначе говоря с учетом умножения соответствующих весов) 
        hidden_errors = numpy.dot(self.who.T, output_errors) 
        
        # Обновление весов между скрытым слоем и выходным (Явление того, что люди зовут ошибкой обратного распространения)
        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
        
        # Обновление весов между скрытым слоем и входным(Та же ошибка ошибка обратного распространения в действии)
        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))
        
        pass

И вот мы приближаемся к концу

Часть 3. Опрос нейронной сети


#Создаем функцию , которая будет принимать входные данные
 def query(self, inputs_list):
        # Конвертируем поданный список входных данных в двумерный массив
        inputs = numpy.array(inputs_list, ndmin=2).T
        # Подсчет сигналов в скрытом слое
        hidden_inputs = numpy.dot(self.wih, inputs)
        # Подсчет сигналов, поданных в функцию активации
        hidden_outputs = self.activation_function(hidden_inputs)
        
        #Подсчет сигналов в конечном выходном слое
        final_inputs = numpy.dot(self.who, hidden_outputs)
        #Подсчет сигналов в конечном выходном слое, переданных в функцию активации
        final_outputs = self.activation_function(final_inputs)
        
        return final_outputs

Доводим дело до конца


 
#Подаем конкретное значение для входного , скрытого ,выходного слоев соответственно(указываем количество <b>нод</b>- узлов в ряду входного, скрытого, выходного соответственно
input_nodes = 3
hidden_nodes = 3
output_nodes = 3

# Возьмем коэффициент обучения - скорость обучения равной, например... 0.3!
learning_rate = 0.3

# Создаем нейронную сеть(n это объект класса neuralNetwork , при его создании запустится конструктор __init__  , и дальше все будет включаться по цепочке
n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)

P.S


Выше была представлена способная на вычисления, простейшая модель нейронной сети. Но какого-то конкретного применения показано не было.

При желании, можно продолжить этот код, добавив в него возможность распознавания рукописного текста MNIST, для этого вы можете полностью разобраться(и просто позабавиться), имея этот jupyter-файл , моя же задача была продемонстрировать код и по возможности разжевать что присутствует и зачем. Ссылки на теорию, как и обещал, прикреплю в конце, ну а так же вы найдете Github и книгу Тарика Рашида, их я тоже оставлю

1.Полезная ссылка на Гитхаб
2.Книга «Создай свою нейронную сеть»
3.Теория по машинному обучению 1
4.Теория по машинному обучению 2
5.Теория по машинному обучению 3
6.Теория по машинному обучению 4

Также можно ознакомиться с этим курсом
Поддержать автора
Поделиться публикацией

Комментарии 20

    +7
    Объясню в чём суть, для тех кто не разбирается в программировании. Вот смотрите, есть библиотека которая делает нейронную сеть. У этой библиотеки есть следующие функции: принять_начальные_данные, запустить_нейронную_сеть, показать_результаты. И что мы делаем? Как думаете?

    Библиотека.принять_начальные_данные
    Библиотека.запустить_нейронную_сеть
    Библиотека.показать_результаты
      –3
      на sklearn подобная задача делается в несколько строчек кода да еще и быстрее.
      scikit-learn.org/stable/modules/neural_networks_supervised.html
        +1
        Моя задача была пошагово объяснить устройство простой нейронной сети начинающим. Это даже указано в заголовке статьи
          +3
          Я как-то не очень понимаю за что заминусовали автора. Вроде как из библиотек он взял нампай для матричного умножения и скипай для какой-то функции. Ну, конечно, можно было еще и матрицы перемножать самостоятельно, только зачем? Это вроде и так должно быть очевидно
        +10
        Листал Хабр, бац! вижу «Знакомство с простейшей нейронной сетью и ее пошаговая реализация» «Машинное обучение», «Программирование»

        Ура! Наконец то появилась статья не про то как подключать библиотеки на питоне, а про внутреннюю реализацию таких сетей!

        У меня же висит технический долг перед самим собой, создать сеть распознающую определенную категорию геометрических объектов! Так чего же ждем? Вперед! К новым вершинам знаний!

        Потираю руки, наливаю кофе, откидываюсь в кресле, тынц!

        1. берем питон
        2. делаем импорт либ
        3. вызываем из либы сеть
        4. профит!

        <тут картинка с недопитым кофем и пустым вращающимся креслом >

        Чем дальше, тем сильнее ощущение, что тут питонистам индульгенция выдана по теме «нейронные сети и машинное обучение: расскажите всем какие замечательные у вас есть библиотеки» :)
          0
          Если технический английский — не слишком большая проблема, то вот — www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch26.pdf — от ребят из Analog Devices, весьма подробно, формулы только по делу, картинки опять же, хотя и черно-белые. И без лишних комплексов — примеры приведены на Бейсике ;-)
            0
            3. вызываем из либы сеть

            Покажите пожалуйста строчку кода, где это происходит. Я так просмотрел бегло. Библиотек по машинному обучению и нейронным сетям вроде как у автора нет
              0
              «Функция активации, имя которой -Сигмоида» это разве не оно?

              На самом деле, автору надо было всего лишь указать 3 хаба в списке хабов,
              — «Питон»
              — «Машинное обучение»
              — «Программирование»

              Я думаю, что в этом случае, многие просто прошли бы мимо и не выразили бы свое возмущение. Плюс, зачем делать сознательно чрезмерно завлекательный первый абзац?

              По этой же книге я и хочу пройтись пошагово, а именно по практической части — написанию кода простой нейронной сети.

              Эта статья для тех, кто хочет заниматься нейронными сетями и машинным обучением, но пока с трудом понимает эту удивительную область науки. Ниже будет описан самый простой скелет кода нейронной сети, чтобы многие поняли простейший принцип построения и взаимодействия всего того, из чего состоит эта нейронная сеть

                +1
                Функция активации, имя которой -Сигмоида» это разве не оно

                Ну это просто функция 1/(1+e^-x)
                Ее можно было и в ручную написать. И было бы у автора не
                import scipy.special
                
                self.activation_function = lambda x: scipy.special.expit(x)
                

                а что-нибудь типа:
                self.activation_function = lambda x: 1/(1+e**-x) 
                

                На самом деле, автору надо было всего лишь указать 3 хаба в списке хабов,
                — «Питон»
                — «Машинное обучение»
                — «Программирование»

                Ну да, я согласен, наверное стоило бы подчеркнуть, что речь пойдет про питон. Люди, которые не знают питоновских библиотек или тем более смутно понимают питоновский синтаксис останутся разочарованными.
                  +2
                  И объяснить хотя бы бегло в 1 абзаце, что такое сигмоида и почему выбрана она. В сети куча картинок на тему «сигмоида» vs «линейная» vs «ступенчатая» функции активации нейрона. Вот первая попавшаяся ссылка например.
                  Я не сомневаюсь, что этой статьей автор делает хорошее дело, но все же имеет смысл дать возможность людям понять, что такое «сигмоида» и почему она лучше для задач классификации/распознавания.
            +1
            Зашел сюда, потому как в нейронных сетях полный валянок, но очень хочу разобраться.
            Пожалуйста, кто-нибудь, дайте ссылку/напишите статью/ткните пальцем как сделать с все с нуля?
            И существует ли вообще вариант для технаря (аля поставить галочки в какой-то софтине/сервисе/онлайн, чтоб создать и обучить чему-то сеть)?
              0
              Самая простая статья на понимание нейросетей была у этого товарища на мой взгляд neuralnetworksanddeeplearning.com
              И существует ли вообще вариант для технаря (аля поставить галочки в какой-то софтине/сервисе/онлайн, чтоб создать и обучить чему-то сеть)?

              Библиотеки scikit-learn.org/stable/index.html или Keras в принципе позволяют за несколько строчек все сделать. Вариант отдельной программы не знаю
                0
                Спасибо, познавательно.
                0
                Похоже в соседней теме то что вам нужно:
                Пример простой нейросети на C++
                Там конечно не так няшно и аккуратно как здесь, зато там есть торты и можно ими кидаться :)
                  0
                  +4
                  шо, опять, вводная по нейросетям?
                    0
                    есть стандарты типа
                    import numpy as np

                    а то новички понатырят кода с разных источников и будут сидеть дуплить почему Ваш кусок не работает с другими.
                      0
                      Попробовал сделать пример по вашей статье, столкнулся со следующими проблемами:
                      1. В строках (в первом блоке)
                      self.wih = numpy.random.rand(self.hnodes, self.inodes))
                      self.who = numpy.random.rand(self.onodes, self.hnodes))
                      лишняя закрывающая скобка
                      2. При копировании кусков программы из разных мест статьи иногда ломаются отступы, а для Python'а это критично. Возможно лучше было бы весь код поместить в один блок.
                      3. Все-таки новичку не совсем понятно, что делать дальше с полученной в самом конце перменной n. Правильно ли я понимаю, что теперь нужно будет загрузить где-то данные для тренировки и затем вызвать:

                      n.train(mydata) // тренировать нейросеть
                      n.query(myquery) // посмотреть как она работает

                        0
                        Вот, глянь на файл. Вот тут указано, как дальше быть
                        А именно глянь с 4 ячейки — тут (In:[4]), там код увеличится у тебя в размерах :)
                        +1

                        Вот этот курс «Deep Learning на пальцах» скорее можно назвать знакомством с нейросетями, недавно стартовал — топчик, на русском, бесплатно.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое