Машинное обучение — это ветвь искусственного интеллекта (ИИ), вращающаяся вокруг разработки и использования математических методов, которые позволяют программному обеспечению делать прогнозы без явного программирования для них.

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

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

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

Машинное обучение можно разделить на два типа.

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

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 не сойдется к нулю или к порогу, или к заранее определенному числу итераций.

Обобщить,

  1. Инициализируйте параметрыmи b в нашей модели y_pred = m * X + b= m * X + b нулевыми или случайными значениями.
  2. Оцените выходные данные y_pred, используя значения, инициализированные для параметров m и b для входных данных X .
  3. Вычислите среднеквадратичную ошибку между прогнозируемым выходом y_predи фактическим выходом y.
  4. Рассчитайте градиенты dL/dm и dL/db, которые показывают, как изменится функция потерь, когда мы немного увеличим значения параметров m и b .
  5. Используя градиенты, рассчитанные на предыдущем шаге, обновите значения параметров mи b, где значения параметров увеличиваются, если градиент отрицателен, и наоборот, используя уравнение m = m - α * dL/dm.
  6. Вычислите 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.

Шаги обучения для многомерной линейной регрессии следующие:

  • Это будет похоже на этапы одномерной линейной регрессии.
  1. Прямое распространение:

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.