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

Теории по машинному обучению и нейронным сетям на хабре и так достаточно. Но если кому-то это необходимо, некоторые ссылки я оставлю в конце статьи. А сейчас, приступаем непосредственно к написанию кода, причем писать мы будем на 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)Немного о том, как выглядит узел в нейронной сети

На картинке изображен самый, что ни на есть узел, только представлен он обычно в виде круга, а не прямоугольника. Как мы видим, внутри прямоугольника(ну или круга) — это все абстрактно, находятся 2 функции:
1-я Функция занимается тем, что получает все входные, с учетом весов, данные, и иногда даже с учетом нейрона смещения(специальный нейрон, который просто позволяет графикам подвинуться, а не смешиваться в одну некрасивую кучу, вот и все)
2-я Функция принимает в качестве параметра то самое значение, которое насуммировала первая функция, и эта вторая функция называется функцией активации. В нашем случае -Сигмоида
Продолжаем:
Часть 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.Github
2.Книга «Создай свою нейронную сеть»
3.Теория по машинному обучению 1
4.Теория по машинному обучению 2
5.Теория по машинному обучению 3
6.Теория по машинному обучению 4
Также можно ознакомиться с этим курсом.
Комментарии (19)
 - Vinchi13.02.2019 17:02- на sklearn подобная задача делается в несколько строчек кода да еще и быстрее. 
 scikit-learn.org/stable/modules/neural_networks_supervised.html - 0xUL Автор13.02.2019 17:11- Моя задача была пошагово объяснить устройство простой нейронной сети начинающим. Это даже указано в заголовке статьи  - Sychuan13.02.2019 21:37+1- Я как-то не очень понимаю за что заминусовали автора. Вроде как из библиотек он взял нампай для матричного умножения и скипай для какой-то функции. Ну, конечно, можно было еще и матрицы перемножать самостоятельно, только зачем? Это вроде и так должно быть очевидно 
 
 
 - tuxi13.02.2019 18:46- Листал Хабр, бац! вижу «Знакомство с простейшей нейронной сетью и ее пошаговая реализация» «Машинное обучение», «Программирование» 
 
 Ура! Наконец то появилась статья не про то как подключать библиотеки на питоне, а про внутреннюю реализацию таких сетей!
 
 У меня же висит технический долг перед самим собой, создать сеть распознающую определенную категорию геометрических объектов! Так чего же ждем? Вперед! К новым вершинам знаний!
 
 Потираю руки, наливаю кофе, откидываюсь в кресле, тынц!
 …
 1. берем питон
 2. делаем импорт либ
 3. вызываем из либы сеть
 4. профит!
 
 <тут картинка с недопитым кофем и пустым вращающимся креслом >
 
 Чем дальше, тем сильнее ощущение, что тут питонистам индульгенция выдана по теме «нейронные сети и машинное обучение: расскажите всем какие замечательные у вас есть библиотеки» :) - Alyoshka197613.02.2019 20:08- Если технический английский — не слишком большая проблема, то вот — www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch26.pdf — от ребят из Analog Devices, весьма подробно, формулы только по делу, картинки опять же, хотя и черно-белые. И без лишних комплексов — примеры приведены на Бейсике ;-) 
  - Sychuan13.02.2019 21:38- 3. вызываем из либы сеть 
 Покажите пожалуйста строчку кода, где это происходит. Я так просмотрел бегло. Библиотек по машинному обучению и нейронным сетям вроде как у автора нет - tuxi13.02.2019 22:09+1- «Функция активации, имя которой -Сигмоида» это разве не оно? 
 
 На самом деле, автору надо было всего лишь указать 3 хаба в списке хабов,
 — «Питон»
 — «Машинное обучение»
 — «Программирование»
 
 Я думаю, что в этом случае, многие просто прошли бы мимо и не выразили бы свое возмущение. Плюс, зачем делать сознательно чрезмерно завлекательный первый абзац?
 - … 
 По этой же книге я и хочу пройтись пошагово, а именно по практической части — написанию кода простой нейронной сети.
 …
 Эта статья для тех, кто хочет заниматься нейронными сетями и машинным обучением, но пока с трудом понимает эту удивительную область науки. Ниже будет описан самый простой скелет кода нейронной сети, чтобы многие поняли простейший принцип построения и взаимодействия всего того, из чего состоит эта нейронная сеть
  - Sychuan13.02.2019 22:33- Функция активации, имя которой -Сигмоида» это разве не оно 
 Ну это просто функция 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 хаба в списке хабов, 
 — «Питон»
 — «Машинное обучение»
 — «Программирование»
 Ну да, я согласен, наверное стоило бы подчеркнуть, что речь пойдет про питон. Люди, которые не знают питоновских библиотек или тем более смутно понимают питоновский синтаксис останутся разочарованными. - tuxi13.02.2019 22:53+1- И объяснить хотя бы бегло в 1 абзаце, что такое сигмоида и почему выбрана она. В сети куча картинок на тему «сигмоида» vs «линейная» vs «ступенчатая» функции активации нейрона. Вот первая попавшаяся ссылка например. 
 Я не сомневаюсь, что этой статьей автор делает хорошее дело, но все же имеет смысл дать возможность людям понять, что такое «сигмоида» и почему она лучше для задач классификации/распознавания.
 
 
 
 
 - webviktor13.02.2019 20:31+1- Зашел сюда, потому как в нейронных сетях полный валянок, но очень хочу разобраться. 
 Пожалуйста, кто-нибудь, дайте ссылку/напишите статью/ткните пальцем как сделать с все с нуля?
 И существует ли вообще вариант для технаря (аля поставить галочки в какой-то софтине/сервисе/онлайн, чтоб создать и обучить чему-то сеть)? - Sychuan13.02.2019 21:41- Самая простая статья на понимание нейросетей была у этого товарища на мой взгляд neuralnetworksanddeeplearning.com 
 - И существует ли вообще вариант для технаря (аля поставить галочки в какой-то софтине/сервисе/онлайн, чтоб создать и обучить чему-то сеть)? 
 Библиотеки scikit-learn.org/stable/index.html или Keras в принципе позволяют за несколько строчек все сделать. Вариант отдельной программы не знаю
  - raamid14.02.2019 16:15- Похоже в соседней теме то что вам нужно: 
 Пример простой нейросети на C++
 Там конечно не так няшно и аккуратно как здесь, зато там есть торты и можно ими кидаться :)
 
 - ZNY14.02.2019 16:16- есть стандарты типа 
 - import numpy as np
 а то новички понатырят кода с разных источников и будут сидеть дуплить почему Ваш кусок не работает с другими.
 - raamid15.02.2019 03:41- Попробовал сделать пример по вашей статье, столкнулся со следующими проблемами: 
 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) // посмотреть как она работает
 
 
           
 
DartAlex
Объясню в чём суть, для тех кто не разбирается в программировании. Вот смотрите, есть библиотека которая делает нейронную сеть. У этой библиотеки есть следующие функции: принять_начальные_данные, запустить_нейронную_сеть, показать_результаты. И что мы делаем? Как думаете?
Библиотека.принять_начальные_данные
Библиотека.запустить_нейронную_сеть
Библиотека.показать_результаты