Как построить трехслойную нейронную сеть с нуля

1656674900 kak postroit trehslojnuyu nejronnuyu set s nulya

Дафна Корнелисс

0rCroNAUgLmigWLgWzbT1ffp1yFUqr4TsOwN
Фотография Тайланд Хамелин на Unsplash

В этой публикации я расскажу о шагах, необходимых для создания a три слой нейронной сети. Я рассмотрю проблему и объясню процесс вместе с важнейшими понятиями.

Проблема, которую нужно решить

У фермера в Италии возникла проблема с этикетной машиной: она перепутала этикетки трех сортов вина. Сейчас у него осталось 178 бутылок и никто не знает, какой сорт их сделал! Чтобы помочь этому бедному человеку, мы построим a классификатор распознающий вино по 13 признакам вина.

9hi4uXDfAP97lsSUoJQZmKomiT9AegFGIoZ3

Тот факт, что наши данные обозначены (одной из трех этикеток сорта), делает это a Контролируемое обучение проблема. По сути мы хотим использовать наши входные данные (178 неклассифицированных бутылок вина), передать их через нашу нейронную сеть, а затем получить правильную этикетку для каждого сорта вина как выход.

Мы научим наш алгоритм, чтобы становиться все лучше и лучше в предвидении (y-hat), какая бутылка к какой марке принадлежит.

Теперь пора начать строить нейронную сеть!

Подход

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

FDWrPCgJTJbH3MPUSyT0tgG2Zi2TYczZDOAj
Обзор 3-уровневой нейронной сети, классификатора вина

Кратко:

  • Входящий слой (x) состоит из 178 нейронов.
  • A1, первый слой, состоящий из 8 нейронов.
  • А2, второй слой, состоит из 5 нейронов.
  • A3, третий и исходный слой, состоит из 3 нейронов.

Шаг 1: обычная подготовка

Импортируйте все необходимые библиотеки (NumPy, skicit-learn, pandas) и набор данных, а также определите x и y.

#importing all the libraries and dataset
import pandas as pdimport numpy as np
df = pd.read_csv('../input/W1data.csv')df.head()
# Package imports
# Matplotlib import matplotlibimport matplotlib.pyplot as plt
# SciKitLearn is a machine learning utilities libraryimport sklearn
# The sklearn dataset module helps generating datasets
import sklearn.datasetsimport sklearn.linear_modelfrom sklearn.preprocessing import OneHotEncoderfrom sklearn.metrics import accuracy_score

Шаг 2: инициализация

Прежде чем мы сможем использовать наши весы, мы должны их инициализировать. Поскольку у нас еще нет значения для весов, мы используем случайные значения от 0 до 1.

В Python, random.seed функция генерирует «случайные числа». Однако случайные числа не действительно случайны. Сгенерированные числа есть псевдослучайныйчто означает, что числа генерируются по сложной формуле, что делает их случайными. Чтобы сгенерировать числа, формула принимает предыдущее сгенерированное значение в качестве входных данных. Если предыдущее значение не было создано, для первого значения часто используется время.

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

np.random.seed(0)

Шаг 3: прямое распространение

Существует примерно две части обучения нейронной сети. Во-первых, вы продвигаетесь вперед через NN. То есть вы «делаете шаги» вперед и сравниваете эти результаты с реальными значениями, чтобы получить разницу между вашим результатом и тем, каким он должен быть. Вы в основном видите, как работает NN и находите ошибки.

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

5W4PMaH25UEe40tRUDbVDC7og51z0igKwXlE

Теперь мы берем наш z1 (наш линейный шаг) и пропускаем его через наш первый функция активации. Функции активации очень важны в нейронных сетях. По сути они превращают входной сигнал в выходной — поэтому их также называют Передаточные функции. Они знакомят нелинейные свойства к нашим функциям путем преобразования линейного входа в нелинейный выход, что делает возможным представление более сложных функций.

Есть разные типы функций активации (подробно описано в данной статье). Для этой модели мы решили использовать тонх функция активации для наших двух скрытых слоев – A1 и A2 – которая дает нам исходное значение от -1 до 1.

Поскольку это a проблема многоклассовой классификации (у нас есть 3 выходные метки), мы будем использовать softmax для исходного уровня – A3 – поскольку это вычислит вероятности для классов, выбрасывая значения от 0 до 1.

gYlH0AENAen9ENfZHFLUSPO55QHBxeAJAK59
функция tanh

Пропустив z1 через функцию активации, мы создали наш первый скрытый слой – A1 – который можно использовать как входные данные для вычисления следующего линейного шага z2.

NzEFXU1tOIbpqcbBuH9b1Hp6sSjS3buGDScK

У Python этот процесс выглядит так:

# This is the forward propagation functiondef forward_prop(model,a0):        # Load parameters from model    W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'], model['W3'],model['b3']        # Do the first Linear step     z1 = a0.dot(W1) + b1        # Put it through the first activation function    a1 = np.tanh(z1)        # Second linear step    z2 = a1.dot(W2) + b2        # Put through second activation function    a2 = np.tanh(z2)        #Third linear step    z3 = a2.dot(W3) + b3        #For the Third linear activation function we use the softmax function    a3 = softmax(z3)        #Store all results in these values    cache = {'a0':a0,'z1':z1,'a1':a1,'z2':z2,'a2':a2,'a3':a3,'z3':z3}    return cache

В конце концов все наши значения хранятся в кэше.

Шаг 4: обратное распространение

После прямого распространения через нашу NN мы распространяем наш градиент ошибок, чтобы обновить наши весовые параметры. Мы знаем свою ошибку и хотим минимизировать ее, по возможности.

Мы делаем это, принимая производная функции ошибки, по отношению к весам (W) нашей НМ, используя градиентный спуск.

Представим этот процесс с помощью аналогии.

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

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

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

m8Xo6IMJOekf9jdAWTq0jPwCljHlRYc3cbIx

Функция потерь представлена ​​горой. Чтобы получить низкие потери, алгоритм придерживается наклона — то есть производной функции потерь.

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

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

yYETGNqV2TLJsWtttVOKOTM89d2gro-dbweZ

Мы всегда начинаем с расчетов наклон функции потерь по отношению к z, наклону линейного шага, который мы берём.

Обозначения таковы: dv является производной функции потерь по переменной v.

GdkfhHiVWvdczRJ47nnXNduOs9Cc7VD9Jr3t

Далее вычисляем наклон функции потерь учитывая наши весы и предубеждения. Поскольку это 3-слойный NN, мы повторим этот процесс для z3,2,1+W3,2,1 и b3,2,1. Распространение в обратном направлении от выходного к входному слою.

lwb8WY18okHbEZMwv933Cotyls3EQ5TG5R39

Вот как этот процесс выглядит на Python:

# This is the backward propagation functiondef backward_prop(model,cache,y):
# Load parameters from model    W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'],model['W3'],model['b3']        # Load forward propagation results    a0,a1, a2,a3 = cache['a0'],cache['a1'],cache['a2'],cache['a3']        # Get number of samples    m = y.shape[0]        # Calculate loss derivative with respect to output    dz3 = loss_derivative(y=y,y_hat=a3)
# Calculate loss derivative with respect to second layer weights    dW3 = 1/m*(a2.T).dot(dz3) #dW2 = 1/m*(a1.T).dot(dz2)         # Calculate loss derivative with respect to second layer bias    db3 = 1/m*np.sum(dz3, axis=0)        # Calculate loss derivative with respect to first layer    dz2 = np.multiply(dz3.dot(W3.T) ,tanh_derivative(a2))        # Calculate loss derivative with respect to first layer weights    dW2 = 1/m*np.dot(a1.T, dz2)        # Calculate loss derivative with respect to first layer bias    db2 = 1/m*np.sum(dz2, axis=0)        dz1 = np.multiply(dz2.dot(W2.T),tanh_derivative(a1))        dW1 = 1/m*np.dot(a0.T,dz1)        db1 = 1/m*np.sum(dz1,axis=0)        # Store gradients    grads = {'dW3':dW3, 'db3':db3, 'dW2':dW2,'db2':db2,'dW1':dW1,'db1':db1}    return grads

Шаг 5: этап обучения

Для того чтобы достичь оптимальные весы и смещение что даст нам желаемый результат (три сорта вина), нам придется поезд наша нейронная сеть.

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

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

Таким же образом вы должны указать «скорость обучения» для модели. Скорость обучения является множителем для обновления параметров. Он определяет, насколько быстро они могут изменяться. Если уровень обучения низкий, обучение занимает больше времени. Однако если скорость обучения слишком высока, мы можем пропустить минимум. Скорость обучения выражается как:

WbtYyr8LAqllg-qqUMKgd7QXYF7by14NX3qB
  • := означает, что это определение, а не уравнение или доказанное утверждение.
  • a называется скорость обучения альфа
  • дл(вт) является производной общей потери относительно нашего веса w
  • да является производным от альфа

После некоторых экспериментов мы выбрали скорость обучения 0,07.

# This is what we return at the endmodel = initialise_parameters(nn_input_dim=13, nn_hdim= 5, nn_output_dim= 3)model = train(model,X,y,learning_rate=0.07,epochs=4500,print_loss=True)plt.plot(losses)
t96e4a19Lzjs3CQcsvGfqPEXZVXzl-zL1JmC

Наконец есть наш график. Вы можете построить график вашей точности и/или потери, чтобы получить хороший график точности прогноза. После 4500 эпох наш алгоритм имеет точность 99,4382022472%.

Краткий итог

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

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

Затем вычисляем разница между нашим прогнозом (y-hat) и ожидаемым результатом (y) и использовать это значение ошибки при обратном распространении.

Во время обратного распространения мы берем нашу ошибку – разницу между нашим прогнозом y-hat и y – и математически проталкиваем ее обратно через NN в другом направлении. Мы учимся на своих ошибках.

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

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

C0p7wTfuU3eBYeDP01K-TKmgvy2N-xYFW6KU
Обзор прямого и обратного распространения

На эту публикацию вдохновлена ​​недельная задача Bletchley Machine Learning Bootcamp, которая началась 7 февраля. В течение следующих девяти недель я один из 50 студентов, которые будут изучать основы машинного обучения. Еженедельно мы обсуждаем другую тему и должны подать задачу, которая требует от вас подлинного понимания материалов.

Если у вас возникнут вопросы или предложения, сообщите мне!

Или если вы хотите проверить весь код, вы можете найти его здесь на Kaggle.

Рекомендуемые видео для более глубокого понимания нейронных сетей:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *