0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Для начинающего<strong>Data Scientist-а</strong>очень важно понять внутреннюю структуру<strong>нейронной сети</strong>. Это руководство поможет вам создать собственную сеть с нуля, не используя для этого сложных учебных библиотек, к коим относится, например,<strong>TensorFlow</strong>. Материал написан на основании статьи американского учёного<a>Джеймса Лоя</a>(Технологический университет штата Джорджия).</p>
1
<p>Для начинающего<strong>Data Scientist-а</strong>очень важно понять внутреннюю структуру<strong>нейронной сети</strong>. Это руководство поможет вам создать собственную сеть с нуля, не используя для этого сложных учебных библиотек, к коим относится, например,<strong>TensorFlow</strong>. Материал написан на основании статьи американского учёного<a>Джеймса Лоя</a>(Технологический университет штата Джорджия).</p>
2
<h2>Что такое нейронная сеть?</h2>
2
<h2>Что такое нейронная сеть?</h2>
3
<p>Очень часто в статьях по нейронным сетям авторы описывают их, проводя параллели с мозгом. Описать нейронную сеть можно и в качестве математической функции, отображающей заданный вход в желаемый результат.</p>
3
<p>Очень часто в статьях по нейронным сетям авторы описывают их, проводя параллели с мозгом. Описать нейронную сеть можно и в качестве математической функции, отображающей заданный вход в желаемый результат.</p>
4
<p>Итак,<strong>нейронные сети</strong>включают в себя следующие компоненты: - х, входной слой; - ŷ, выходной слой; - набор весов и смещений между каждым слоем W и b; - произвольное количество скрытых слоев; - выбор функции активации для любого скрытого слоя σ (в данной статье будем использовать функцию активации Sigmoid). На диаграмме, представленной ниже, отображена архитектура 2-слойной нейронной сети (учтите, что входной уровень, как правило, исключается во время подсчёта числа слоев).</p>
4
<p>Итак,<strong>нейронные сети</strong>включают в себя следующие компоненты: - х, входной слой; - ŷ, выходной слой; - набор весов и смещений между каждым слоем W и b; - произвольное количество скрытых слоев; - выбор функции активации для любого скрытого слоя σ (в данной статье будем использовать функцию активации Sigmoid). На диаграмме, представленной ниже, отображена архитектура 2-слойной нейронной сети (учтите, что входной уровень, как правило, исключается во время подсчёта числа слоев).</p>
5
<p>Идём дальше. Создание класса Neural Network на "Питоне" выглядит следующим образом:</p>
5
<p>Идём дальше. Создание класса Neural Network на "Питоне" выглядит следующим образом:</p>
6
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)<h2>Обучение нейронной сети</h2>
6
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)<h2>Обучение нейронной сети</h2>
7
<p>Выход ŷ простой 2-слойной нейронной сети: В уравнении, которое приведено выше, веса W и смещения b - единственные переменные, влияющие на выход ŷ. Разумеется, правильные значения для смещений и весов определяют<strong>точность предсказаний</strong>. А сам процесс тонкой настройки смещений и весов на основании входных данных называют обучением нейронной сети.</p>
7
<p>Выход ŷ простой 2-слойной нейронной сети: В уравнении, которое приведено выше, веса W и смещения b - единственные переменные, влияющие на выход ŷ. Разумеется, правильные значения для смещений и весов определяют<strong>точность предсказаний</strong>. А сам процесс тонкой настройки смещений и весов на основании входных данных называют обучением нейронной сети.</p>
8
<p>В обучающем процессе каждая итерация включает ряд шагов: 1) вычисление прогнозируемого выхода ŷ (прямого распространения); 2) обновление смещений и весов (обратное распространение).</p>
8
<p>В обучающем процессе каждая итерация включает ряд шагов: 1) вычисление прогнозируемого выхода ŷ (прямого распространения); 2) обновление смещений и весов (обратное распространение).</p>
9
<p>Процесс обучения хорошо иллюстрирует последовательный график:</p>
9
<p>Процесс обучения хорошо иллюстрирует последовательный график:</p>
10
<h2>Прямое распространение</h2>
10
<h2>Прямое распространение</h2>
11
<p>Как видно на графике, прямым распространением называют несложное вычисление, причём для базовой двухслойной нейронной сети вывод задаётся следующей формулой: Давайте теперь добавим в наш код функцию прямого распространения. Для простоты предполагается, что смещения равны нулю.</p>
11
<p>Как видно на графике, прямым распространением называют несложное вычисление, причём для базовой двухслойной нейронной сети вывод задаётся следующей формулой: Давайте теперь добавим в наш код функцию прямого распространения. Для простоты предполагается, что смещения равны нулю.</p>
12
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))<p>Чтобы оценить "добротность" наших прогнозов, воспользуемся функцией потери.</p>
12
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))<p>Чтобы оценить "добротность" наших прогнозов, воспользуемся функцией потери.</p>
13
<h2>Функция потери</h2>
13
<h2>Функция потери</h2>
14
<p>Вообще, существует много доступных функций потерь, и на выбор влияет характер нашей проблемы. Мы же будем применять в качестве функции потери<strong>сумму квадратов ошибок</strong>: Суммой квадратов ошибок называют среднее значение разницы между каждым фактическим и прогнозируемым значением. Что касается цели обучения, то она как раз в том и состоит, чтобы<strong>найти набор смещений и весов, который минимизирует</strong>вышеупомянутую функцию потери.</p>
14
<p>Вообще, существует много доступных функций потерь, и на выбор влияет характер нашей проблемы. Мы же будем применять в качестве функции потери<strong>сумму квадратов ошибок</strong>: Суммой квадратов ошибок называют среднее значение разницы между каждым фактическим и прогнозируемым значением. Что касается цели обучения, то она как раз в том и состоит, чтобы<strong>найти набор смещений и весов, который минимизирует</strong>вышеупомянутую функцию потери.</p>
15
<h2>Обратное распространение</h2>
15
<h2>Обратное распространение</h2>
16
<p>Когда ошибка нашего прогноза, то есть потери, измерены, необходимо отыскать способ<strong>обратного распространения ошибки</strong>, обновив смещения и веса. И чтобы узнать подходящую нам сумму, нужную для корректировки смещений и весов, требуется знать производную функцию потери по отношению к смещениям и весам.</p>
16
<p>Когда ошибка нашего прогноза, то есть потери, измерены, необходимо отыскать способ<strong>обратного распространения ошибки</strong>, обновив смещения и веса. И чтобы узнать подходящую нам сумму, нужную для корректировки смещений и весов, требуется знать производную функцию потери по отношению к смещениям и весам.</p>
17
<p>Здесь давайте вспомним, что<strong>производной функции называют тангенс угла наклона</strong>функции. Раз есть производная, можно просто обновить смещения и веса, уменьшив либо увеличив их (смотрите диаграмму выше). Это называют<strong>градиентным спуском</strong>.</p>
17
<p>Здесь давайте вспомним, что<strong>производной функции называют тангенс угла наклона</strong>функции. Раз есть производная, можно просто обновить смещения и веса, уменьшив либо увеличив их (смотрите диаграмму выше). Это называют<strong>градиентным спуском</strong>.</p>
18
<p>Однако мы не сможем непосредственно посчитать производную функции потерь по отношению к смещениям и весам, ведь уравнение функции потерь не включает в себя смещения и веса. На помощь приходит правило цепи: Да, это было громоздко, зато позволило нам получить то, что необходимо - производную функции потерь (наклон) по отношению к весам. А значит, можно регулировать веса.</p>
18
<p>Однако мы не сможем непосредственно посчитать производную функции потерь по отношению к смещениям и весам, ведь уравнение функции потерь не включает в себя смещения и веса. На помощь приходит правило цепи: Да, это было громоздко, зато позволило нам получить то, что необходимо - производную функции потерь (наклон) по отношению к весам. А значит, можно регулировать веса.</p>
19
<p>Теперь добавим в наш код функцию обратного распространения (backpropagation):</p>
19
<p>Теперь добавим в наш код функцию обратного распространения (backpropagation):</p>
20
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<h2>Проверка работы нейронной сети</h2>
20
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<h2>Проверка работы нейронной сети</h2>
21
<p>Когда полный код для выполнения обратного и прямого распространения есть, можно рассмотреть нейросеть на примере и посмотреть, как всё работает. На картинке вы видите<strong>идеальный набор весов</strong>. И наша нейронная сеть должна изучить его. Давайте потренируем сеть на 1500 итераций. Рассматривая график потерь на итерациях, можно заметить, что потеря монотонно уменьшается до минимума. Всё это соответствует алгоритму спуска градиента, о котором уже упоминали. Теперь посмотрим на вывод (окончательное предсказание) после 1500 итераций:</p>
21
<p>Когда полный код для выполнения обратного и прямого распространения есть, можно рассмотреть нейросеть на примере и посмотреть, как всё работает. На картинке вы видите<strong>идеальный набор весов</strong>. И наша нейронная сеть должна изучить его. Давайте потренируем сеть на 1500 итераций. Рассматривая график потерь на итерациях, можно заметить, что потеря монотонно уменьшается до минимума. Всё это соответствует алгоритму спуска градиента, о котором уже упоминали. Теперь посмотрим на вывод (окончательное предсказание) после 1500 итераций:</p>
22
<p><strong>Итак, мы сделали это</strong>! Алгоритм обратного и прямого распространения показал успешную работу нейросети, а сами предсказания сходятся на истинных значениях. Но нужно добавить, что существует<strong>незначительная разница</strong>между фактическими значениями и предсказаниями. Это нормально и даже желательно, т. к.<strong>предотвращается переобучение</strong>, позволяя нейросети лучше обобщать невидимые данные.</p>
22
<p><strong>Итак, мы сделали это</strong>! Алгоритм обратного и прямого распространения показал успешную работу нейросети, а сами предсказания сходятся на истинных значениях. Но нужно добавить, что существует<strong>незначительная разница</strong>между фактическими значениями и предсказаниями. Это нормально и даже желательно, т. к.<strong>предотвращается переобучение</strong>, позволяя нейросети лучше обобщать невидимые данные.</p>
23
23