Машинное обучение — это ветвь искусственного интеллекта (ИИ), вращающаяся вокруг разработки и использования математических методов, которые позволяют программному обеспечению делать прогнозы без явного программирования для них.
Он включает в себя создание алгоритмов и моделей, которые изучают шаблоны данных и опыт, позволяя системам автоматически улучшать свою производительность с течением времени.
В отличие от традиционного программирования, где явные правила и инструкции определяются программистами, машинное обучение опирается на алгоритмы, которые могут автоматически корректироваться и уточняться по мере обработки большего количества данных.
Этот повторяющийся процесс обучения позволяет программному обеспечению обнаруживать скрытые идеи, распознавать сложные закономерности и делать точные прогнозы или классификации.
Машинное обучение можно разделить на два типа.
- Контролируемое обучение:
- Входные данные предоставляются вместе с выходными во время обучения. Выходные данные можно предсказать с помощью модели контролируемого обучения.
2. Обучение без учителя:
- В неконтролируемом обучении предоставляются только входные данные. Скрытые закономерности в данных можно найти с помощью модели обучения без учителя.
Давайте подробно обсудим алгоритм под названием линейная регрессия. Он подпадает под обучение с учителем.
Примечание. Мы будем использовать программирование на Python для иллюстрации алгоритмов, обсуждаемых в этом посте, и вы можете найти исходный код в моем репозитории github.
Линейная регрессия
Для обучения моделей используется линейная регрессия
when there is a linear relationship between the inputs and outputs
.
- Чтобы лучше понять линейную регрессию, давайте рассмотрим простой набор данных, созданный вручную. У нас есть данные ниже, где
X
— вход, аY
— выход.
Примечание. Этот набор данных очень прост и создан вручную для демонстрации. Я объяснил с набором данных в реальном времени в конце поста.
- Задача состоит в том, чтобы построить модель линейной регрессии с использованием набора данных для прогнозирования выходных данных
Y
при любых произвольных входных данныхX
, которых нет в наборе данных. - Давайте построим этот набор данных на графике.
from matplotlib import pyplot as plt #declaring input and output of the training data set. x = [1,2,3,4,5,6] y = [3,5,7,9,11,13] #plottig the input X and output Y as graph fig, ax = plt.subplots() ax.scatter(x=x, y=y) ax.set(title="Sample data set with input (x) and output (y)") for i,j in zip(x, y): ax.annotate(" ("+str(i)+","+str(j)+")",xy=(i,j), size=12) plt.show()
- Из графика видно, что для заданных точек данных можно провести прямую линию.
- Мы можем определить приведенную ниже модель так, чтобы она соответствовала прямой линии, и использовать линейную регрессию, чтобы найти параметры
m
иb
в модели, которая подходит лучше всего. Y = m * X + b
Цель состоит в том, чтобы найти наилучшие значения параметров (наклон
m
и точка пересеченияb
), которые минимизируют ошибку между прогнозируемыми значениями и фактическими целевыми значениями.
- Если приглядеться, то можно определить параметры
m
иb
, которые помещаются между входомX
и выходомY
. - (т.е.)
Y = 2X + 1
, гдеm = 2
иb = 1
- Давайте посмотрим, как мы найдем вышеуказанные значения
m
иb
, используя линейную регрессию.
Шаги для обучения модели с использованием линейной регрессии следующие:
1. Инициализация:
- Начнем с инициализации значений параметров
m
иb
некоторыми произвольными значениями. - Эти значения могут быть выбраны случайным образом или равны нулю. Давайте обнулим параметры
m
иb
в нашей модели.
m = 0;
b = 0;
2. Прямое распространение:
- Оцените выход
y_pred
, используя значения, инициализированные для параметровm
иb
для входаx
, используя приведенное ниже уравнение. y_pred = m * x + b
import numpy;
y_pred = numpy.multiply(m, x) + b;
print(y_pred);
[0 0 0 0 0 0]
3. Определите функцию потерь:
- В линейной регрессии наиболее часто используемой функцией потерь является среднеквадратическая ошибка (MSE), которая измеряет среднеквадратичную разницу между прогнозируемыми значениями и фактическими целевыми значениями.
MSE (L) определяется по формуле:
L = (1/n) * Σ(y_pred - y)^2
.- где n — количество точек данных в наборе данных.
y_pred
— прогнозируемое значение для данного входаX
с использованием текущих значений параметров,y
— фактическое целевое значение, соответствующее входуX
.- Давайте посчитаем потери между прогнозируемыми значениями
y_pred
и фактическими значениямиy
.
n = len(x);
L = sum(np.square(numpy.subtract(y_pred, y)))/n
print(L);
75.66666666666667
4. Рассчитайте градиенты:
- Градиент показывает, как функция потерь изменяется по отношению к изменению каждого параметра.
- Мы используем значения градиента, чтобы решить, увеличивать или уменьшать текущие значения параметров, чтобы минимизировать функцию потерь
L
. - Нам нужно вычислить частные производные функции потерь по параметрам
m
иb
. - Градиенты рассчитываются следующим образом:
- dL/dm = (2/n) * Σ(X * (y_pred — y_actual)) — показывает, как изменится функция потерь, если мы немного увеличим значение
m
. - dL/db = (2/n) * Σ(y_pred — y_actual) — показывает, как изменится функция потерь, если мы немного увеличим значение
b
.
Примечание. Положительный градиент указывает, что увеличение значения параметра увеличивает функцию потерь, тогда как отрицательный градиент > указывает, что увеличение значения параметра уменьшит функцию потерь.
dL_m = (2/n) * sum(x * (y_pred - y)); print("dL_m = ", dL_m); dL_b = (2/n) * sum(y_pred - y); print("dL_b = ", dL_b); dL_m = -67.66666666666666 dL_b = -16.0
Давайте подробно рассмотрим, как мы пришли к уравнению для градиентов dL/dm и dL/db.
Примечание. Читатели, не заинтересованные в подробном выводе дифференциального исчисления, могут пропустить следующий раздел, не теряя общего понимания темы. Смело переходите к следующему шагу.
//To find the partial derivatives of L with respect to m and b, //we need to differentiate L with respect to m and b separately, //treating them as independent variables. L = (1/n) * Σ(y_pred - y_actual)^2 Since y_pred = m * X + b L = (1/n) * Σ(m * X + b - y_actual)^2 dL/dm = (1/n) * Σ d(m * X + b - y_actual)^2/dm //when y = x^2, dy/dx = 2x * dx/dx ∴ dL/dm = (1/n) * Σ(2 * (m * X + b - y_actual) * (d(m * X + b - y_actual)/dm)) dL/dm = (2/n) * Σ (m * X + b - y_actual) * (d(m * X)/dm + db/dm - dy_actual/dm) --- A d(m * X)/dm = m * dX/dm + X * dm/dm //Derivative of independent variable is zero. //Since X, dy_actual and b are indepenent of m, their derivatives are zero. ∴ d(m * X)/dm= X ---B ∴ db/dm = dy_actual/dm = 0 ---C //By substituting the equations B and C in A, we get ∴ dL/dM = (2/n) * Σ((m * X + b- y_actual) * X) (i.e) dL/dM = (2/n) * Σ((y_pred- y_actual) * X) Similarly, dL/db = (1/n) * Σ (2 * (m * X + b - y_actual) * d(m * X + b - y_actual)/db) dL/db = (1/n) * Σ (2 * (m * X + b - y_actual) * d(m * X)/db + db/db - dy_actual/db) ---A //Since m, X and dy_actual are indepenent of m, their derivatives are zero. d(m * X)/db = dy_actual/db = 0 ---B db/db = 1 ---C //By substituting the equations B and C in A, we get ∴ dL/db = (2/n) * Σ (m * X + b - y_actual) (i.e) dL/db = (2/n) * Σ(y_pred - y_actual)
5. Обновите параметры: (Обратное распространение с использованием градиентного спуска)
- Параметры обновляются итеративно с использованием градиентов, рассчитанных на предыдущем шаге.
- Это важный шаг, на котором мы оптимизируем параметры
m
иb
, чтобы уменьшить функцию потерьL
.
Уравнения обновления параметров следующие:
m = m - α * dL/dm
b = b - α * dL/db
Где: α (альфа) — скорость обучения, небольшое положительное значение, определяющее размер шага обновления.
- Градиенты
dL_m
иdL_b
, рассчитанные на предыдущем шаге, являются отрицательными и указывают на то, что потери уменьшаются при увеличении параметровm
иb
. - Давайте обновим наши параметры, используя градиенты
dL_m
иdL_b
.
alpha = 0.01;
m = m - (alpha * dL_m);
print("updated m = ", m);
b = b - (alpha * dL_b);
print("updated b = ", b);
updated m = 0.6766666666666666
updated b = 0.16
6. Повторите шаги 4 и 5:
- На предыдущем шаге параметры
m
иb
обновляются с нуля до0.67
и0.16
соответственно. - Это указывает на то, что параметры обновляются в правильном направлении (
m
в сторону2
иb
в сторону1
). - Предыдущие шаги следует повторять до тех пор, пока функция потерь
L
не сойдется к нулю или к порогу, или к заранее определенному числу итераций.
Обобщить,
- Инициализируйте параметры
m
иb
в нашей моделиy_pred = m * X + b= m * X + b
нулевыми или случайными значениями. - Оцените выходные данные
y_pred
, используя значения, инициализированные для параметровm
иb
для входных данныхX
. - Вычислите среднеквадратичную ошибку между прогнозируемым выходом
y_pred
и фактическим выходомy
. - Рассчитайте градиенты
dL/dm
иdL/db
, которые показывают, как изменится функция потерь, когда мы немного увеличим значения параметровm
иb
. - Используя градиенты, рассчитанные на предыдущем шаге, обновите значения параметров
m
иb
, где значения параметров увеличиваются, если градиент отрицателен, и наоборот, используя уравнениеm = m - α * dL/dm
. - Вычислите
y_pred
, используя обновленные значения параметров, и повторяйте описанные выше шаги, пока потери не сойдутся к нулю или заданному количеству итераций.
Давайте обучим нашу модель, повторив описанные выше шаги 100 раз в цикле, и посмотрим, как сходится потеря.
def train(x, y, m, b, epoch, alpha=0.01):
cost_at_each_step = []
m_at_each_step = []
b_at_each_step = []
for i in range(epoch):
#forward propagation
y_pred = np.multiply(x, m) + b;
#Computing loss (MSE)
L = sum(np.square(np.subtract(y_pred, y)))/n;
cost_at_each_step.append(L)
#calculate the gradients
dL_m = (2/n) * sum(x * (y_pred - y)) ;
dL_b = (2/n) * sum(y_pred - y) ;
m_at_each_step.append(m)
b_at_each_step.append(b)
#update the parameters
m = m - (alpha * dL_m);
b = b - (alpha * dL_b);
print("Loss at the end of the training", L);
print("Updated m = ", m);
print("Updated b = ", b);
#plot the graph between parameter m and loss function L at each step
plt.figure(figsize = (8,6))
plt.plot(m_at_each_step, cost_at_each_step)
plt.scatter(m_at_each_step, cost_at_each_step, marker='.', color='red')
plt.title("Loss vs m at each step")
plt.ylabel("Loss")
plt.xlabel("m")
plt.show()
#plot the graph between parameter m and loss function L at each step
plt.figure(figsize = (8,6))
plt.plot(b_at_each_step, cost_at_each_step)
plt.scatter(b_at_each_step, cost_at_each_step, marker='.', color='red')
plt.title("Loss vs b at each step")
plt.ylabel("Loss")
plt.xlabel("m")
plt.show()
train(x, y, m=0, b=0, epoch=100);
Loss at the end of the training 0.023819359608382714
Updated m = 2.0818800902162136
Updated b = 0.6494550806075945
- Приведенные выше графики показывают, как настраиваются параметры
m
иb
, а потери приближаются к нулю на каждом шаге. - Также параметры
m
иb
оптимизированы доm=2.081
иb=0.649
, что ближе к ожидаемым значениямm=2
иb=1
. - А потери уменьшаются с
75.67
и0.0238
- Именно так модели машинного обучения обучаются с использованием прошлых данных и используются для прогнозирования результатов в режиме реального времени.
Важность скорости обучения
- Скорость обучения
alpha
определяет, насколько параметрыm
иb
изменяются на каждом шаге. - Если мы установим более высокую скорость обучения, мы столкнемся с проблемой, называемой чрезмерная съемка.
- Давайте изменим скорость обучения
alpha
с0.01
с0.06
и посмотрим, как шаг градиента выходит за пределы допустимого.
train(x, y, m=0, b=0, alpha=0.06, epoch=100);
Loss at the end of the training 0.0006164560288729731
Updated m = 2.012483278426452
Updated b = 0.9446956990677258
- На приведенном выше графике показано, как параметры обновляются и потери перетасовываются на каждом шаге, когда скорость обучения высока.
- Хотя в нашем случае параметры модели сходились быстрее, более высокая скорость обучения может продлить оптимизацию, а иногда функции потерь не сходятся.
- Точно так же, если скорость обучения очень низкая, для сходимости требуется больше итераций.
- Таким образом, мы должны балансировать скорость обучения между крайностями.
Многомерная линейная регрессия:
- Модель, которую мы объяснили здесь, называется одномерной линейной регрессией, поскольку выход
Y
зависит только от одного входаX
. - Мы также можем обучать модели, в которых выход
Y
зависит от нескольких входовX1, X2, X3, ......, Xn
. - Алгоритм, используемый для обучения моделей для такого набора данных, называется многомерная линейная регрессия.
- Но ключевые понятия остаются прежними.
- Также очевидно, что набор данных является ключом к обучению с учителем.
- Давайте реализуем многомерную линейную регрессию для набора данных с открытым исходным кодом для прогнозирования цен на жилье.
Прогноз цен на жилье:
- Этот набор данных доступен в kaggle.
- Он содержит сведения о таких свойствах, как
location and age of the property, distance to the nearest train station, nearby stores, etc... and its price
.
Постановка задачи состоит в том, чтобы предсказать стоимость актива с учетом сведений о свойствах.
import pandas as pd housing = pd.DataFrame(pd.read_csv("RealEstate.csv")) housing.drop(["No"], axis=1, inplace = True) housing.head()
- У нас есть пять входов
X1, X2,...., X5
и выходY
.
Давайте преобразуем входные объекты
X1,X2,...,X5
, масштабируя их в диапазоне от0
до1
.
Этот процесс называется
Normalization
, и обычно он используется для того, чтобы входные данные высокого диапазона не преобладали над тренировочными весами.
- Также давайте разделим набор данных для обучения и проверки.
- Мы будем обучать модель, используя данные обучения, и оценивать модель, используя данные проверки.
- Это делается для того, чтобы избежать перенастройки модели на обучающие данные.
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() num_vars = ['X1 transaction date', 'X2 house age', 'X3 distance to the nearest MRT station', 'X4 number of convenience stores', 'X5 latitude', 'X6 longitude']; housing[num_vars] = scaler.fit_transform(housing[num_vars]) housing.head()
from sklearn.model_selection import train_test_split df_train, df_test = train_test_split(housing, train_size = 0.7, test_size = 0.3, random_state = 100) Y_train = df_train.pop('Y house price of unit area').to_numpy(); X_train = df_train.to_numpy(); Y_test = df_test.pop('Y house price of unit area').to_numpy(); X_test = df_test.to_numpy();
Модель многомерной линейной регрессии выглядит следующим образом.
Y = m[1] * X[1] + m[2] * X[2] + ..... +m[n] * X[n] + b
- где
n
— количество входов, аm
,b
— параметры. - Количество параметров модели
m
будет равно количеству входовX
.
Шаги обучения для многомерной линейной регрессии следующие:
- Это будет похоже на этапы одномерной линейной регрессии.
- Прямое распространение:
Y_pred = m[1] * X[1] + m[2] * X[2] + ..... +m[5] * X[5] + b
2. Функция потерь:
L = (1/n) * Σ(Y_pred - Y_actual)^2
3. Рассчитайте градиенты:
- Поскольку у нас есть параметры
m[i]
, связанные с каждым i-м входомX
, градиенты рассчитываются следующим образом: dL/dm(i) = (2/n) * Σ(X[i] * (y_pred - y_actual))
- Указывает, как изменяется функция потерь при изменении каждого параметра
m[i]
, связанного с входомX[i]
. dL/db = (2/n) * Σ(y_pred - y_actual)
- Указывает, как изменяется функция потерь при изменении параметра смещения
b
.
4. Обновите параметры:
- Уравнения обновления параметров следующие:
m[i] = m[i] - α * dL/dm(i)
b = b - α * dL/db
5. Повторите вышеуказанные шаги для определенного количества эпох:
- Давайте реализуем вышеупомянутые шаги в функции и обучим набор данных прогнозирования цен на жилье.
def train_multi_variate_regression(x, y, m, b, epoch, alpha=0.01):
for i in range(epoch):
#forward propagation
y_pred = np.matmul(x, m) + b;
#Computing loss (MSE)
L = sum(np.square(np.subtract(y_pred, y)))/n;
#calculate the gradients
dL_m = (2/n) * sum( np.matmul(np.transpose(x), np.subtract(y_pred, y))) ;
dL_b = (2/n) * sum(np.subtract(y_pred, y)) ;
#update the parameters
m = m - (alpha * dL_m);
b = b - (alpha * dL_b);
print("Loss at the end of the training", L);
print("Updated m = ", m);
print("Updated b = ", b);
return m, b;
m = np.array([0,0,0,0,0,0])
b = 0;
m, b = train_multi_variate_regression(X_train, Y_train, m, b, epoch=10000, alpha=0.001);
Loss at the end of the training 8949.990282355513
Updated m = [7.44713681 7.44713681 7.44713681 7.44713681 7.44713681 7.44713681]
Updated b = 18.433885481660813
- Модель обучена для
10000
итераций со скоростью обучения0.001
. - Я пришел к этим значениям, попробовав разные скорости обучения, и потери приблизились к
8950
. - Давайте посмотрим, как он предсказывает выходные данные для набора данных проверки.
y_pred = np.matmul(X_test, m) + b; report = pd.DataFrame(X_test, columns=['X1 transaction date', 'X2 house age','X3 distance to the nearest MRT station', 'X4 number of convenience stores', 'X5 latitude', 'X6 longitude']) report['Y house price of unit area'] = Y_test; report['Y_pred Predicted house price of unit area'] = y_pred; report.head(15)
- Из приведенного выше отчета видно, что прогнозируемый результат ближе к фактическому результату.
- Потеря оптимизирована до
8950
в конце обучения. - Дальнейшая оптимизация с использованием линейной регрессии невозможна. Может быть нелинейность в отношениях между входами и выходами.
Примечание. Линейная регрессия плохо подходит для подбора наборов данных, содержащих нелинейные отношения.
- Мы можем использовать методы глубокого обучения, такие как многослойные персептроны, для обучения наборов данных с нелинейными отношениями.
- Универсальная аппроксимационная теорема — это фундаментальная концепция алгоритмов глубокого обучения.
- Также это основные шаги во всех алгоритмах машинного обучения и глубокого обучения.
- В этом посте мы рассмотрели концепцию линейной регрессии и рассмотрели пример, демонстрирующий, как ее можно применить к реальным данным.
- Если вы только начинаете свой путь в науке о данных или хотите углубить свое понимание, линейная регрессия служит фундаментальным строительным блоком.
- Оцените его простоту и универсальность и раскройте потенциал получения ценной информации из ваших данных.
Удачного обучения!
Примечание. Исходный код всех примеров в статье доступен в моем репозитории GitHub.