Создание нейронных сетей с нуля в Python

Python компьютерное зрение

Автор | Рашида Насрин Sucky Компилировать|ВКонтакте Источник|Средний

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

Рекомендую внимательно прочитать раздел «Идеи нейронных сетей». Но если вы не уверены, не волнуйтесь. Вы можете перейти в раздел реализации. Я разбил его на более мелкие части, чтобы помочь понять.

Как работают нейронные сети

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

Здесь «слой1» — это входной объект. «Слой1» переходит к другому узлу Layer2 и, наконец, выводит предсказанный класс или гипотезу. layer2 — это скрытый слой. Можно использовать несколько скрытых слоев.

Вы должны спроектировать свою нейронную сеть в соответствии с вашим набором данных и требованиями к точности.

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

Процесс перехода от уровня 1 к уровню 3 называется прямым распространением. Шаги прямого распространения:

  1. Инициализируйте коэффициенты θ для каждой входной функции. Допустим, у нас есть 100 обучающих примеров. Это означает 100 строк данных. В этом случае размер нашей входной матрицы составляет 100x10, если мы предполагаем 10 входных признаков. Хорошо сейчасθ1θ_1размер. Количество строк должно совпадать с количеством входных объектов. В данном примере это 10. Количество столбцов должно соответствовать размеру выбранного вами скрытого слоя.

  2. Умножьте входной признак X на соответствующий θ, затем добавьте член смещения. Передайте результат через функцию активации.

Доступно несколько функций активации, таких как sigmoid, tanh, relu, softmax, swish.

Я буду использовать сигмовидную функцию активации для демонстрации нейронной сети.

Здесь «а» представляет скрытый слой или слой 2, а b представляет смещение.

g(z) — сигмовидная функция активации:

  1. Инициализировать скрытый слойθ2\theta_2. Размер будет равен длине скрытого слоя, умноженной на количество выходных классов. В этом примере следующий слой является выходным, потому что у нас больше нет скрытых слоев.

  2. Затем нам нужно следовать тому же процессу, что и раньше. Умножьте θ и скрытый слой, чтобы получить прогнозируемый результат через сигмовидный слой активации.

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

Обратное распространение — это процесс перехода от выходного слоя ко второму слою. В ходе этого процесса мы вычисляем ошибку.

  1. Во-первых, вычтите предсказанный результат из исходного результата y, это нашδ3\delta_3.

  1. Теперь рассчитайтеθ2\theta_2градиент. будетδ3\delta_3умножить наθ2\theta_2. умножается на "a2a^2"умножить"1a21-a^2". В приведенной ниже формуле надстрочный индекс 2 над буквой "а" означает слой 2. Пожалуйста, не поймите неправильно, что это квадрат.

  1. Вычислите градиент без регуляризации с количеством обучающих выборок mδ\delta.

обучать сеть

исправитьδ\delta. Умножьте входные функции наδ2\delta_2Умножьте на скорость обучения, чтобы получитьθ1\theta_1. Пожалуйста, обрати вниманиеθ1\theta_1измерение.

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

Если вы заметили, эта формула функции стоимости почти такая же, как функция стоимости логистической регрессии.

Реализация нейронных сетей

Я буду использовать набор данных из курса машинного обучения Эндрю Нг на Coursera. Загрузите набор данных по ссылке ниже:

GitHub.com/RA большой 048/…

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

  1. Сначала импортируйте необходимые пакеты и наборы данных.
import pandas as pd
import numpy as np
xls = pd.ExcelFile('ex3d1.xlsx')
df = pd.read_excel(xls, 'X', header = None)

Вот первые пять строк набора данных. Это пиксельные значения чисел.

В этом наборе данных входные и выходные переменные организованы на отдельных листах Excel. Давайте импортируем выходную переменную:

y = pd.read_excel(xls, 'y', header=None)

Это также первые пять строк набора данных. Выходными переменными являются числа от 1 до 10. Цель этого проекта — предсказывать числа, используя входные переменные, хранящиеся в «df».

  1. Найдите размерность входных и выходных переменных
df.shape
y.shape

Форма входной переменной или df составляет 5000 x 400, а форма выходной переменной или y равна 5000 x 1.

  1. Определение нейронных сетей

Для простоты будем использовать только один скрытый слой, состоящий из 25 нейронов.

hidden_layer = 25

Получите выходной класс.

y_arr = y[0].unique()#输出:
array([10,  1,  2,  3,  4,  5,  6,  7,  8,  9], dtype=int64)

Как вы можете видеть выше, существует 10 выходных классов.

  1. Инициализировать тета и смещение

Мы случайным образом инициализируем θ для слоя 1 и слоя 2. Так как у нас три этажа, то будетθ1\theta_1иθ2\theta_2.

θ1\theta_1Размер: размер слоя 1 x размер слоя 2

θ2\theta_2Размер: размер слоя 2 x размер слоя 3

Из шага 2 форма «df» составляет 5000 x 400. Это означает, что существует 400 входных функций. Итак, размер слоя 1 равен 400. Когда мы указываем размер скрытого слоя как 25, размер слоя 2 равен 25. У нас есть 10 выходных классов. Итак, размер слоя 3 равен 10.

θ1\theta_1Размеры: 400 х 25

θ2\theta_2Размер: 25×10

Точно так же будет два случайно инициализированных смещения b1 и b2.

b1b_1Размер : размер слоя 2 (25 в данном случае)

b1b_1Размер : размер слоя 3 (в данном случае 10)

Определите функцию, которая случайным образом инициализирует тета:

def randInitializeWeights(Lin, Lout):
    epi = (6**1/2) / (Lin + Lout)**0.5
    w = np.random.rand(Lout, Lin)*(2*epi) -epi
    return w

Используйте эту функцию для инициализации тета

hidden_layer = 25
output =10
theta1 = randInitializeWeights(len(df.T), hidden_layer)
theta2 = randInitializeWeights(hidden_layer, output)
theta = [theta1, theta2]

Теперь инициализируйте термин смещения, который мы обсуждали выше:

b1 = np.random.randn(25,)
b2 = np.random.randn(10,)
  1. реализовать прямое распространение

Используйте формулу в разделе «Прямое распространение».

Для удобства задайте функцию для умножения тета и X

def z_calc(X, theta):
    return np.dot(X, theta.T)

Мы также будем использовать функцию активации несколько раз. Также определите функцию

def sigmoid(z):
    return 1/(1+ np.exp(-z))

Теперь я шаг за шагом продемонстрирую прямое распространение. Сначала вычислите член z:

z1 =z_calc(df, theta1) + b1

Теперь пропустите этот z1 через функцию активации, чтобы получить скрытый слой.

a1 = sigmoid(z1)

a1 — скрытый слой. Размер a1 5000 x 25. Повторите тот же процесс для вычисления слоя 3 или выходного слоя.

z2 = z_calc(a1, theta2) + b2
a2 = sigmoid(z2)

Форма a2 5000 x 10. 10 столбцов представляют 10 классов. a2 — это наш слой 3 или конечный результат. Если бы в этом примере было больше скрытых слоев, то в процессе перехода от одного слоя к другому было бы больше повторяющихся шагов. Этот процесс вычисления выходного слоя с использованием входных признаков называется прямым распространением.

l = 3  #层数
b = [b1, b2]
def hypothesis(df, theta):
    a = []
    z = []
    for i in range (0, l-1):
        z1 = z_calc(df, theta[i]) + b[i]
        out = sigmoid(z1)
        a.append(out)
        z.append(z1)
        df = out
    return out, a, z
  1. реализовать обратное распространение

Это процесс вычисления градиентов в обратном порядке и обновления θ. Перед этим нам нужно изменить 'y'. У нас 10 классов на "у". Но нам нужно разделить каждый класс в своей колонке. Например, для колонки 10 класса. Мы заменим 1 на 10 и 0 на остальные классы. Таким образом, мы создадим отдельный столбец для каждого класса.

y1 = np.zeros([len(df), len(y_arr)])
y1 = pd.DataFrame(y1)
for i in range(0, len(y_arr)):
    for j in range(0, len(y1)):
        if y[0][j] == y_arr[i]:
            y1.iloc[j, i] = 1
        else: 
            y1.iloc[j, i] = 0
y1.head()

Раньше я шаг за шагом демонстрировал прямой проход, затем, чтобы уместить все это в одну функцию, я сделаю то же самое для обратного прохода. Используя формулу градиента из раздела обратного распространения выше, сначала вычислитеδ3\delta_3. Мы будем использовать z1, z2, a1 и a2 из реализации прямого прохода.

del3 = y1-a2

Теперь рассчитайте delta2 по следующей формуле:

Вот дельта2:

del2 = np.dot(del3, theta2) * a1*(1 - a1)

Здесь нам нужно выучить новое понятие. Это сигмовидный градиент. Формула сигмовидного градиента:

Если вы заметили, это точно так же, как **a(1-a)** в дельта-формуле. Поскольку a является сигмовидным (z). Напишем функцию на сигмовидном градиенте:

def sigmoid_grad(z):
    return sigmoid(z)*(1 - sigmoid(z))

Наконец, обновите θ, используя следующую формулу:

Нам нужно выбрать скорость обучения. Я выбрал 0,003. Я рекомендую вам попробовать другие курсы обучения и посмотреть, как они работают:

theta1 = np.dot(del2.T, pd.DataFrame(a1)) * 0.003
theta2 = np.dot(del3.T, pd.DataFrame(a2)) * 0.003

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

def cost_function(y, y_calc, l):
    return (np.sum(np.sum(-np.log(y_calc)*y - np.log(1-y_calc)*(1-y))))/m

Здесь m — количество обучающих экземпляров. Комбинированный код:

m = len(df)
def backpropagation(df, theta, y1, alpha):
    out, a, z = hypothesis(df, theta)
    delta = []
    delta.append(y1-a[-1])
    i = l - 2
    while i > 0:
        delta.append(np.dot(delta[-i], theta[-i])*sigmoid_grad(z[-(i+1)]))
        i -= 1
    theta[0] = np.dot(delta[-1].T, df) * alpha
    for i in range(1, len(theta)):
        theta[i] = np.dot(delta[-(i+1)].T, pd.DataFrame(a[0])) * alpha
    out, a, z = hypothesis(df, theta)
    cost = cost_function(y1, a[-1], 1)
    return theta, cost
  1. обучать сеть

Я буду обучать сеть с 20 эпохами. Я снова инициализирую тета в этом фрагменте кода.

theta1 = randInitializeWeights(len(df.T), hidden_layer)
theta2 = randInitializeWeights(hidden_layer, output)
theta = [theta1, theta2]
cost_list = []
for i in range(20):
    theta, cost= backpropagation(df, theta, y1, 0.003)
    cost_list.append(cost)
cost_list

Я использовал скорость обучения 0,003 и работал в течение 20 эпох. Но см. ссылку на GitHub в конце статьи. Я пробовал тренировать модель с разной скоростью обучения и разным количеством эпох.

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

  1. Прогнозировать выход и рассчитывать точность

Просто используйте функцию гипотезы и передайте обновленное θ, чтобы предсказать результат:

out, a, z = hypothesis(df, theta)

Теперь вычислите точность,

accuracy= 0
for i in range(0, len(out)):
    for j in range(0, len(out[i])):
        if out[i][j] >= 0.5 and y1.iloc[i, j] == 1:
            accuracy += 1
accuracy/len(df)

Точность 100%. Идеально, верно? Но мы не всегда получаем 100% точность. Иногда хорошо получить точность 70%, это зависит от набора данных.

Поздравляем! Вы только что разработали полную нейронную сеть!

Ссылка GitHub на полный рабочий код

Оригинальная ссылка

Добро пожаловать на сайт блога Panchuang AI:panchuang.net/

sklearn машинное обучение китайские официальные документы:sklearn123.com/

Добро пожаловать на станцию ​​сводки ресурсов блога Panchuang:docs.panchuang.net/