Раздел прогнозирования. Проект интернет-магазина

 Раздел прогнозирования. Введение и план

В этой лекции мы продолжим наш проект интернет-магазина, а точнее, рассмотрим процесс обработки данных в Python. Также мы очертим содержание данного раздела. Дело в том, что это большой раздел, и легко забыть, в чём его цель.

Напомним, что в наших более ранних курсах мы рассматривали логистическую регрессию для двоичной классификации, когда мы собирали некоторые данные и пытались спрогнозировать появление одной из двух возможных меток. К примеру, в качестве входных переменных мы могли взять время, проведённое на сайте, и количество просмотренных страниц, а прогнозировали, купит ли пользователь что-то или нет. Как вы помните, если задача имеет только две входные переменные, мы можем изобразить их графически на двухмерной плоскости, а затем провести прямую между двумя классами – скажем, «купит» и «не купит»:

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

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

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

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

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

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

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

В моём предыдущем курсе по логистической регрессии мы обсуждали двоичную классификацию. Но что делать, если мы хотим одновременно классифицировать более двух вещей и если вместо того, чтобы просто прогнозировать «купит – не купит», мы хотим предсказать любое количество действий пользователя – покупка, начало оплаты, добавление в корзину, очистка корзины и так далее? Другим примером может быть классификация марки автомашины, основываясь на её изображении, ведь в мире существует куда больше двух марок машины, а потому здесь требуется классификатор, способный классифицировать более двух вещей.

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

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

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

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

Не забывайте, что это типичные стадии машинного обучения. Сначала мы создаём «мозг», но этот мозг не слишком умён, поскольку ещё не обучен, и поэтому прогнозы будут не очень точными. Затем мы его обучаем, и лишь после обучения мозг будет способен давать точные прогнозы, причём именно потому, что мы попытались научить его этому.

Подготовка данных для интернет-магазина

Я уже загрузил библиотеки Numpy и Pandas.

import numpy as np

import pandas as pd

Для загрузки данных используем функцию

pd.read_csv, файл ecommerce_data.csv.

df = pd.read_csv(‘ecommerce_data.csv’)

Если вы хотите увидеть, что в файле, используйте команду

df.head()

Она показывает первые пять строк файла.

Итак, выйдем из оболочки и начнём работу с файлом процесса. Если вы не хотите писать код, а сразу его просмотреть, зайдите на github, соответствующий файл называется process.py. Прежде всего загрузим библиотеки Numpy и Pandas.

import numpy as np

import pandas as pd

Далее мы напишем функцию get_data. Она, во-первых, считывает данные из файла, как мы это сделали чуть ранее, а во-вторых, преобразует их в матрицы Numpy, поскольку так легче работать.

def get_data():

df = pd.read_csv(‘ecommerce_data.csv’)

data = df.as_matrix()

Далее нам необходимо разделить наши x и y. Y – это последний столбец, поэтому x у нас будет всеми остальными столбцами, за исключением последнего.

X = data[:, :-1]

Y = data[:, -1]

Далее, как мы говорили, необходимо нормализовать числовые столбцы. Для х1 это значение х1 минус среднее значение, поделённое на среднее отклонение. То же самое и для х2.

X[:,1] = (X[:,1] – X[:,1].mean()) / X[:,1].std()

X[:,2] = (X[:,2] – X[:,2].mean()) / X[:,2].std()

Перейдём теперь к работе над столбцом категорий, которым является время суток. Для этого возьмём форму оригинального х и на его основе создадим новый Х2 размерности Nx(D+3), поскольку у нас четыре категории. Обратите внимание, что большинство значений x будут совпадать.

N, D = X.shape

X2 = np.zeros((N, D+3))

X2[:,0:(D-1)] = X[:,0:(D-1)]

Теперь напишем код прямого кодирования для остальных четырёх столбцов. Сначала сделаем это простым способом. Для каждого наблюдения считываем значение времени суток, которое, как вы помните, принимает значение 0, 1, 2 и 3, и записываем это значение в Х2.

for n in xrange(N):

t = int(X[n,D-1])

X2[n,t+D-1] = 1

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

Z = np.zeros((N, 4))

Z[np.arange(N), X[:,D-1].astype(np.int32)] = 1

В таком случае нужно будет дописать ещё одну строку

X2[:,-4:] = Z

assert(np.abs(X2[:,-4:] – Z).sum() < 10e-10)

И конец функции.

return X2, Y

Для логистической регрессии нам нужны только двоичные данные, а не полный их набор, поэтому напишем функцию get_binary_data, которая будет вызывать функцию get_data, а затем фильтровать её результат, отбирая только классы 0 и 1.

def get_binary_data():

X, Y = get_data()

X2 = X[Y <= 1]

Y2 = Y[Y <= 1]

return X2, Y2

Это всё, что касается подготовки данных.

Проект интернет-магазина. Создание прогнозов

 Соответствующий файл называется ann_predict.py.

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

import numpy as np

from process import get_data

Центральная задача этого файла – показать, как использовать прямое распространение в нейронной сети при обработке данных интернет-магазина и как делать прогнозы.

Итак, для начала загрузим данные – это всего лишь функция get_data.

X, Y = get_data()

Теперь случайным образом инициируем весовые коэффициенты нашей нейронной сети, поскольку мы ещё не знаем, как их обучать. Итак, создадим M = 5 единиц скрытого слоя, D у нас соответствует количеству признаков x, K – это количество уникальных значений Y и потому пробегает значения от 0 до K-1. W1 – матрица размерности DxM, b1 – вектор размерности M, W2 – матрица размерности MxK, b2 – вектор размерности K.

M = 5

D = X.shape[1]

K = len(set(Y))

W1 = np.random.randn(D, M)

b1 = np.zeros(M)

W2 = np.random.randn(M, K)

b2 = np.zeros(K)

Разумеется, нам понадобится функция софтмакс.

def softmax(a):

expA = np.exp(a)

return expA / expA.sum(axis=1, keepdims=True)

Далее идёт функция прямого распространения, в качестве аргументов использующие X, W1, b1, W2, b2. В качестве функции активации используем гиперболический тангенс.

def forward(X, W1, b1, W2, b2):

Z = np.tanh(X.dot(W1) + b1)

return softmax(Z.dot(W2) + b2)

Теперь мы можем получить собственно выход нейронной сети.

P_Y_given_X = forward(X, W1, b1, W2, b2)

predictions = np.argmax(P_Y_given_X, axis=1)

Запишем также функцию для вычисления точности – коэффициента классификации. Функция использует в качестве аргументов значения целевых переменных и полученных прогнозных значений. Сразу же выведем её на экран.

def classification_rate(Y, P):

return np.mean(Y == P)

print ‘’Score:’’, classification_rate(Y, predictions)

Запустим программу.

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

Проект интернет-магазина. Обучение нейронной сети

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

import numpy as np

import matplotlib.pyplot as plt

from sklearn.utils import shuffle

from process import get_data

def y2indicator(y, K)

N = len(y)

ind = np.zeros((N, K))

for i in xrange(N):

ind[i, y[i]] = 1

return ind

X, Y = get_data()

X, Y = shuffle(X, Y)

Y = Y.astype(np.int32)

M = 5

D = X.shape[1]

K = len(set(Y))

Преобразуем наши данные в учебный и проверочный наборы – это тоже можно скопировать из предыдущего файла. Как и тогда, первые 100 примеров будут учебным набором, остальные – проверочным.

Xtrain = X[:-100]

Ytrain = Y[:-100]

Ytrain_ind = y2indicator(Ytrain, K)

Xtest = X[-100:]

Ytest = Y[-100:]

Ytest_ind = y2indicator(Ytest, K)

Теперь случайным образом инициируем весовые коэффициенты. W1 будет размерности DxM, b1 – ряд нулей размерности M, у W2 размерность MxK, а b2 – это нули размерности K.

W1 = np.random.randn(D, M)

b1 = np.zeros(M)

W2 = np.random.randn(M, K)

b2 = np.zeros(K)

Функцию softmax мы можем скопировать полностью, а вот функцию forward надо немного дописать. Функции predict, classification_rate и cross_entropy можно также скопировать с предыдущего файла.

def softmax(a):

expA – np.exp(a)

return expA / expA.sum(axis=1, keepdims=True)

def forward(X, W1, b1, W2, b2):

Z = np.tanh(X.dot(W1) + b1)

return softmax(Z.dot(W2) + b2)

def predict(P_Y_given_X):

return np.argmax(P_Y_given_X, axis=1)

def classification_rate(Y, P):

return np.mean(Y == P)

def cross_entropy(T, pY):

return –np.mean(T*np.log(pY))

Теперь мы готовы к основному учебному циклу. Коэффициент обучения установим равным 0,001, количество циклов – 10 000.

train_costs = []

test_costs = []

learning_rate = 0.001

for i in xrange(10000):

pYtrain, Ztrain = forward(Xtrain, W1, b1, W2, b2)

pYtest, Ztest = forward(Xtest, W1, b1, W2, b2)

ctrain = cross_entropy(Ytrain_ind, pYtrain)

ctest = cross_entropy(Ytest_ind, pYtest)

train_costs.append(ctrain)

ctest.append(ctest)

Затем можем приступать к градиентному спуску.

W2 -= leraning_rate*Ztrain.T.dot(pYtrain – Ytrain_ind)

b2 -= learning_rate*(pYtrain – Ytrain_ind).sum()

dZ = (pYtrain – Ytrain_ind).dot(W2.T) * (1 – Ztrain*Ztrain)

W1 -= leraning_rate*Xtrain.T.dot(dZ)

b1 -= learning_rate*dZ.sum(axis=0)

if i % 1000 == 0:

print i, ctrain, ctest

После этого мы можем вывести на экран коэффициент классификации и значение функции затрат. Эту часть кода тоже можно просто скопировать из предыдущего примера.

print ‘’Final train classification_rate:’’, classification_rate(Ytrain, predict(pYtrain))

print ‘’Final test classification_rate:’’, classification_rate(Ytest, predict(pYtest))

legend1, = plt.plot(train_costs, label=’train cost’)

legend2, = plt.plot(test_costs, label=’test cost’)

plt.legend([legend1, legend2])

plt.show()

Запустим программу и посмотрим, что получится. Как и ожидалось, функция затрат для учебного набора несколько ниже, чем для проверочного. Коэффициент классификации равен 97% для учебного набора и 92% для проверочного. Это несколько лучше, чем в случае логистической регрессии.

Софтмакс

 Сейчас рассмотрим проблему, что будет, если наши исходящие данных имеют более двух категорий.

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

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

Другим примером является известная база данных MNIST, в которой необходимо категоризировать каждое изображение в качестве определённой цифры от 0 до 9.

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

P(Y= 0|X)=1-P(Y=1|X).

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

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

В таком случае обнаружение результата с принадлежностью к классу 1, рассчитывается по формуле:

P(Y= 1|X)= \frac{e^a__1}{e^a__1 + e^a__2},

a_1 = w^T_1 x, a_2 = w^T_2 x,

а с принадлежностью к классу 2 – по формуле:

P(Y= 2|X)= \frac{e^a__2}{e^a__1 + e^a__2},

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

Заметьте, что такой способ представления очень легко расширить до K классов. В таком случае у нас получается новая матрица

размерности DxK. Мы вычисляем результат, возводя в экспоненту каждую исходящую переменную, а затем нормализуя их:

P(Y= k|X)= \frac{e^a__k}{Z},

Z = e^a__1+ e^a__2 + \; ....\; + e^a__k.

Получившаяся исходящая переменная, которую я обозначил через A, обычно называется активацией:

A_N_x_K = X_N_x_K W_N_x_K \rightarrow Y_N_x_K = softmax (A_N_x_K).

Обучение логистической регрессии с помощью софтмакс

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

import numpy as np

import matplotlib.pyplot as plt

Итак, у нас уже импортированы библиотеки Nympy и Matplotlib. Теперь нам нужно перемешать наши данные и, естественно, загрузить сами данные.

from sklearn.utils import shuffle

from process import get_data

Нам также нужна функция, преобразующая целевые переменные в матрицу показателей. Назовём её y2indicator.

def y2indicator(y, K)

N = len(y)

ind = np.zeros((N, K))

for i in xrange(N):

ind[i, y[i]] = 1

return ind

Теперь загружаем данные и перемешиваем их.

X, Y = get_data()

X, Y = shuffle(X, Y)

Y = Y.astype(np.int32)

D = X.shape[1]

K = len(set(Y))

Теперь разделим наши данные на учебный и проверочный наборы. Учебным набором будем считать первые 100 примеров.

Xtrain = X[:-100]

Ytrain = Y[:-100]

Ytrain_ind = y2indicator(Ytrain, K)

Xtest = X[-100:]

Ytest = Y[-100:]

Ytest_ind = y2indicator(Ytest, K)

Следующее – инициализация весовых коэффициентов. W пусть будет иметь гауссово распределение с размерностью DxK, а b – набором нулей размерности K.

W = np.random.randn(D, K)

b = np.zeros(K)

Далее определим функции softmax, forward, predict, classification_rate и cross_entropy.

def softmax(a):

expA – np.exp(a)

return expA / expA.sum(axis=1, keepdims=True)

def forward(X, W, b):

return softmax(X.dot(W) + b)

def predict(P_Y_given_X):

return np.argmax(P_Y_given_X, axis=1)

def classification_rate(Y, P):

return np.mean(Y == P)

def cross_entropy(T, pY):

return –np.mean(T*np.log(pY))

Справившись со всем этим, мы можем заняться нашим учебным циклом и запустить градиентный спуск. Коэффициент обучения установим равным 0,001, количество циклов – равным 10 000, причём после каждых 1 000 циклов будем выводить на экран значение функции затрат.

train_costs = []

test_costs = []

learning_rate = 0.001

for i in xrange(10000):

pYtrain = forward(Xtrain, W, b)

pYtest = forward(Xtest, W, b)

ctrain = cross_entropy(Ytrain_ind, pYtrain)

ctest = cross_entropy(Ytest_ind, pYtest)

train_costs.append(ctrain)

test_costs.append(ctest)

W -= leraning_rate*Xtrain.T.dot(pYtrain – Ytrain_ind)

b -= learning_rate*(pYtrain – Ytrain_ind).sum(axis=0)

if i % 1000 == 0:

print i, ctrain, ctest

И наконец мы можем вывести на экран учебный и проверочный коэффициенты классификации.

print ‘’Final train classification_rate:’’, classification_rate(Ytrain, predict(pYtrain))

print ‘’Final test classification_rate:’’, classification_rate(Ytest, predict(pYtest))

Закончив всё это, подпишем для удобства графики.

legend1, = plt.plot(train_costs, label=’train cost’)

legend2, = plt.plot(test_costs, label=’test cost’)

plt.legend([legend1, legend2])

plt.show()

Запустим программу. Итак, как мы видим, наша функция затрат учебного набора несколько меньше функции затрат проверочного набора. Точность у нас получилась равной 93% для учебного набора и равной 86% – для проверочного набора. Это несколько хуже, чем в случае двоичной классификации.

Софтмакс в коде

В этой лекции я покажу вам, как реализовать функцию софтмакс в коде.

Итак, прежде всего надо импортировать библиотеку Numpy.

import numpy as np

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

a = np.random.randn(5)

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

expa = np.exp(a)

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

Теперь нам нужно полученные числа поделить на их сумму.

answer = expa / expa.sum()

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

answer.sum()

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

A = np.random.randn(100, 5)

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

expA = np.exp(A)

Теперь они все положительны. Следующий этап – деление на сумму.

expA / expA.sum()

answer = expA / expA.sum()

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

answer = expA / expA.sum(axis=1)

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

answer = expA / expA.sum(axis=1, keepdims=True)

Тогда всё будет в порядке. Вы можете проверить результат и удостовериться, что сумма по строкам равна единице, а также проверить значение знаменателя.

answer.sum(axis=1)

expA.sum(axis=1, keepdims=True)

Функция возвращает двухмерный массив. Мы можем проверить это, запустив команду

expA.sum(axis=1, keepdims=True).shape

В результате мы видим массив размерностью 100×1 вместо просто 100.

Сигмоида и софтмакс

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

Сначала давайте выпишем уравнение для софтмакс. Мы знаем, что вероятность того, что y = 1, равна

P(Y= 1|X)= \frac{e^w^T_1x}{e^w^T_1x + e^w^T_0x}.

Тогда вероятность того, что y = 0, равна единице минус вышеуказанное выражение.

Возьмём первое уравнение для p(Y = 1|X) и поделим числитель и знаменатель на Попробуйте сделать это самостоятельно и посмотрите, что у вас получится. Я бы хотел, чтобы вы поставили видео на паузу и попробовали сами найти ответ на этот вопрос, перед тем как мы перейдём к следующему слайду.

Получим:

P(Y= 1|X)= \frac{1}{1 + e(w_0 - w_1)^Tx}.

Получилось выражение для сигмоиды. Что это значит?

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

Краткие итоги раздела прогнозирования

Поскольку это довольно длинный раздел, давайте кратко подведём итог всему тому, что мы сделали.

Не забывайте, что этот курс был создан для разработки идей, основанных на двоичной линейной классификации, а конкретно – на логистической регрессии.

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

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

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

Наконец, мы применили наш код нейронной сети для создания прогнозов в наших данных для интернет-магазина, реализовав ряд шагов для предварительной подготовки данных.

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

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

Вывод кода для примера:

import numpy as np

import pandas as pd

+

def softmax(a):

expA – np.exp(a)

return expA / expA.sum(axis=1, keepdims=True)

def forward(X, W1, b1, W2, b2):

Z = np.tanh(X.dot(W1) + b1)

return softmax(Z.dot(W2) + b2)

def predict(P_Y_given_X):

return np.argmax(P_Y_given_X, axis=1)

def classification_rate(Y, P):

return np.mean(Y == P)

def cross_entropy(T, pY):

return –np.mean(T*np.log(pY))

Андрей Никитенко
Андрей Никитенко
Задать вопрос эксперту
Понравилась статья? Поделить с друзьями:
Комментариев: 1
  1. Ольга

    Здравствуйте. Дайте, пожалуйста, ссылку на github. Не могу найти(

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

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Share via
Copy link