Нейронная сеть на Python с нуля своими руками | OTUS
🔥 BLACK FRIDAY!
Максимальная скидка -25% на всё. Успейте начать обучение по самой выгодной цене.
Выбрать курс

Курсы

Программирование
iOS Developer. Basic
-25%
Python Developer. Professional
-25%
Разработчик на Spring Framework
-25%
Golang Developer. Professional
-25%
Python Developer. Basic
-25%
iOS Developer. Professional
-25%
Highload Architect
-25%
JavaScript Developer. Basic
-25%
Kotlin Backend Developer
-25%
JavaScript Developer. Professional
-25%
Android Developer. Basic
-25%
Unity Game Developer. Basic
-25%
Разработчик C#
-25%
Программист С Web-разработчик на Python Алгоритмы и структуры данных Framework Laravel PostgreSQL Reverse-Engineering. Professional CI/CD Vue.js разработчик VOIP инженер Программист 1С Flutter Mobile Developer Супер - интенсив по Kubernetes Symfony Framework Advanced Fullstack JavaScript developer Супер-интенсив "Azure для разработчиков"
Инфраструктура
Мониторинг и логирование: Zabbix, Prometheus, ELK
-25%
DevOps практики и инструменты
-25%
Архитектор сетей
-25%
Инфраструктурная платформа на основе Kubernetes
-25%
Супер-интенсив «IaC Ansible»
-16%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-25%
Супер-интенсив "SQL для анализа данных"
-16%
Базы данных Сетевой инженер AWS для разработчиков Cloud Solution Architecture Разработчик голосовых ассистентов и чат-ботов Внедрение и работа в DevSecOps Администратор Linux. Виртуализация и кластеризация Нереляционные базы данных Супер-практикум по использованию и настройке GIT IoT-разработчик Супер-интенсив «ELK»
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Создаём нейронную сеть на Python с нуля

ML_Deep_23.5_site-5020-5727b5.png

Для начинающего Data Scientist-а очень важно понять внутреннюю структуру нейронной сети. Это руководство поможет вам создать собственную сеть с нуля, не используя для этого сложных учебных библиотек, к коим относится, например, TensorFlow. Материал написан на основании статьи американского учёного Джеймса Лоя (Технологический университет штата Джорджия).

Что такое нейронная сеть?

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

Итак, нейронные сети включают в себя следующие компоненты: — х, входной слой; — ŷ, выходной слой; — набор весов и смещений между каждым слоем W и b; — произвольное количество скрытых слоев; — выбор функции активации для любого скрытого слоя σ (в данной статье будем использовать функцию активации Sigmoid). На диаграмме, представленной ниже, отображена архитектура 2-слойной нейронной сети (учтите, что входной уровень, как правило, исключается во время подсчёта числа слоев).

1-20219-8da12f.png
Идём дальше. Создание класса Neural Network на «Питоне» выглядит следующим образом:

    class NeuralNetwork:
        def __init__(self, x, y):
            self.input      = x
            self.weights1   = np.random.rand(self.input.shape[1],4) 
            self.weights2   = np.random.rand(4,1)                 
            self.y          = y
            self.output     = np.zeros(y.shape)

Обучение нейронной сети

Выход ŷ простой 2-слойной нейронной сети: 2-20219-934615.png В уравнении, которое приведено выше, веса W и смещения b — единственные переменные, влияющие на выход ŷ. Разумеется, правильные значения для смещений и весов определяют точность предсказаний. А сам процесс тонкой настройки смещений и весов на основании входных данных называют обучением нейронной сети.

В обучающем процессе каждая итерация включает ряд шагов: 1) вычисление прогнозируемого выхода ŷ (прямого распространения); 2) обновление смещений и весов (обратное распространение).

Процесс обучения хорошо иллюстрирует последовательный график: 3-20219-f6b69d.png

Прямое распространение

Как видно на графике, прямым распространением называют несложное вычисление, причём для базовой двухслойной нейронной сети вывод задаётся следующей формулой: 4-20219-934615.png Давайте теперь добавим в наш код функцию прямого распространения. Для простоты предполагается, что смещения равны нулю.

    class NeuralNetwork:
        def __init__(self, x, y):
            self.input      = x
            self.weights1   = np.random.rand(self.input.shape[1],4) 
            self.weights2   = np.random.rand(4,1)                 
            self.y          = y
            self.output     = np.zeros(self.y.shape)

        def feedforward(self):
            self.layer1 = sigmoid(np.dot(self.input, self.weights1))
            self.output = sigmoid(np.dot(self.layer1, self.weights2))

Чтобы оценить «добротность» наших прогнозов, воспользуемся функцией потери.

Функция потери

Вообще, существует много доступных функций потерь, и на выбор влияет характер нашей проблемы. Мы же будем применять в качестве функции потери сумму квадратов ошибок: 5-20219-fd1901.png Суммой квадратов ошибок называют среднее значение разницы между каждым фактическим и прогнозируемым значением. Что касается цели обучения, то она как раз в том и состоит, чтобы найти набор смещений и весов, который минимизирует вышеупомянутую функцию потери.

Обратное распространение

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

Здесь давайте вспомним, что производной функции называют тангенс угла наклона функции. 6-20219-f71efd.png Раз есть производная, можно просто обновить смещения и веса, уменьшив либо увеличив их (смотрите диаграмму выше). Это называют градиентным спуском.

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

Теперь добавим в наш код функцию обратного распространения (backpropagation):

    class NeuralNetwork:
        def __init__(self, x, y):
            self.input      = x
            self.weights1   = np.random.rand(self.input.shape[1],4) 
            self.weights2   = np.random.rand(4,1)                 
            self.y          = y
            self.output     = np.zeros(self.y.shape)

        def feedforward(self):
            self.layer1 = sigmoid(np.dot(self.input, self.weights1))
            self.output = sigmoid(np.dot(self.layer1, self.weights2))

        def backprop(self):
            # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1
            d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))
            d_weights1 = np.dot(self.input.T,  (np.dot(2*(self.y - self.output) * sigmoid_derivative(self.output), self.weights2.T) * sigmoid_derivative(self.layer1)))

            # update the weights with the derivative (slope) of the loss function
            self.weights1 += d_weights1
            self.weights2 += d_weights2

Проверка работы нейронной сети

Когда полный код для выполнения обратного и прямого распространения есть, можно рассмотреть нейросеть на примере и посмотреть, как всё работает. 8-20219-042183.png На картинке вы видите идеальный набор весов. И наша нейронная сеть должна изучить его. Давайте потренируем сеть на 1500 итераций. Рассматривая график потерь на итерациях, можно заметить, что потеря монотонно уменьшается до минимума. Всё это соответствует алгоритму спуска градиента, о котором уже упоминали.
9-20219-d7f4af.png Теперь посмотрим на вывод (окончательное предсказание) после 1500 итераций:

10-20219-9bcfb1.png Итак, мы сделали это! Алгоритм обратного и прямого распространения показал успешную работу нейросети, а сами предсказания сходятся на истинных значениях. Но нужно добавить, что существует незначительная разница между фактическими значениями и предсказаниями. Это нормально и даже желательно, т. к. предотвращается переобучение, позволяя нейросети лучше обобщать невидимые данные.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
🎁 Максимальная скидка!
Черная пятница уже в OTUS! Скидка -25% на всё!