Подробное объяснение реализации регуляризации с нуля в Python.

Всем привет! Это пошаговое руководство «Уравнение в код», часть 4, последняя в этой серии.

В предыдущих статьях мы говорили о линейной задаче отделимости в части 1, нелинейной задаче отделимости во части 2 и стохастическом градиентном спуске. (SGD) в часть 3. Как и другие части, часть 4 самодостаточна, вы можете просто игнорировать предыдущие статьи.

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

Вот полный код, regression_without_regularization.py и regression_with_regularization.py.

Содержание структурировано следующим образом.

  1. Регуляризация
  2. Подделать некоторые образцы данных
  3. Предварительная обработка
  4. Внедрение без регуляризации
  5. Реализация с регуляризацией
  6. Резюме

1 Регуляризация

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

Чтобы «не очень хорошо соответствовать обучающим данным» (середина на рисунке выше), мы обычно используем некоторые методы, чтобы избежать переобучения, такие как перекрестная проверка, отсев, нормализация партии и так далее.

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

2 Подделать некоторые образцы данных

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

Чтобы сделать данные более реальными, мы добавляем к ним немного шума. Вы можете увидеть в коде.

import numpy as np
import matplotlib.pyplot as plt
# random seed to make sure reimplement
np.random.seed(0)
# the real model line
def g(x):
    return 0.1 * (x + x**2 + x**3)
# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05
# plot
x = np.linspace(-2, 2, 100)
plt.plot(train_x, train_y, 'o')
plt.plot(x, g(x), linestyle='dashed')
plt.ylim(-1, 2)
plt.show()

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

3 Предварительная обработка

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

Но если мы выберем полиномиальную функцию степени 10, модель, скорее всего, усложнится.

Поскольку у нас есть 10 градусов и один член смещения, у нас также есть 11 параметров.

Мы реализуем это, чтобы смоделировать сложную ситуацию.

import numpy as np
import matplotlib.pyplot as plt
# random seed to make sure reimplement
np.random.seed(0)
# the real model line
def g(x):
    return 0.1 * (x + x**2 + x**3)
# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05
# standardization
mu = train_x.mean()
std = train_x.std()
def standardizer(x):
    return (x - mu) / std
std_x = standardizer(train_x)

# get matrix
def to_matrix(x):
    return np.vstack([
        np.ones(x.size),
        x,
        x ** 2,
        x ** 3,
        x ** 4,
        x ** 5,
        x ** 6,
        x ** 7,
        x ** 8,
        x ** 9,
        x ** 10,
    ]).T
mat_x = to_matrix(std_x)
# initialize parameter
theta = np.random.randn(mat_x.shape[1])
# predict function
def f(x):
    return np.dot(x, theta)
  • стандартизация: сначала мы стандартизируем наши данные
  • получить матрицу: мы делаем данные в виде матрицы для матричных операций, которые имитируют полиномиальную функцию степени 10
  • инициализировать параметр: инициализировать параметр в соответствии с размером входных данных
  • функция прогнозирования: это наша прогнозируемая функция, как и в приведенном выше уравнении.

4 Внедрение без регуляризации

Мы используем среднеквадратичную ошибку (MSE) в качестве функции стоимости.

# cost function
def E(x, y):
    return 0.5 * np.sum((y - f(x))**2)
# initialize error
error = E(mat_x, train_y)

Мы используем градиентный спуск для обновления параметров.

Версия, подобная массиву Numpy, может быть проста для понимания. Здесь я просто перечисляю три параметра, чтобы ясно видеть уравнение.

Код

# learning rate
ETA = 1e-4
# update parameter
for _ in range(epoch):
    theta = theta - ETA * np.dot(f(X) - train_y, mat_x)

Соединяем код вместе

# learning rate
ETA = 1e-4
# initialize difference between two epochs
diff = 1
######## training without regularization ########
while diff > 1e-6:
    # mat_x = (20, 4)
    # f(x) - y = (20,)
    theta = theta - ETA * (np.dot(f(mat_x) - train_y, mat_x))
    current_error = E(mat_x, train_y)
    diff = error - current_error 
    error = current_error
# save parameters
theta1 = theta
########## plot line ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))
# plot the line without regularization
theta = theta1
plt.plot(z, f(to_matrix(z)), linestyle='dashed')
plt.show()

Мы можем видеть, чему мы научились.

Вот полный код, regression_without_regularization.py

5 Реализация с регуляризацией

Срок регулирования L2 выглядит так

И мы объединяем функцию стоимости и термин регуляризации вместе.

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

Обратите внимание, что мы не используем лямбда для обновления параметра смещения тета 0.

Код

# regularization parameter
LAMBDA = 1
# initialize difference between two epochs
diff = 1
# initialize error
error = E(mat_x, train_y)
######## training without regularization ########
while diff > 1e-6:
    # notice we don't use regularization for theta 0
    reg_term = LAMBDA * np.hstack([0, theta[1:]])
    # update parameter
    theta = theta - ETA * (np.dot(mat_x.T, f(mat_x) - train_y) + reg_term)
    current_error = E(mat_x, train_y)
    diff = error - current_error
    error = current_error
# save parameters
theta2 = theta
########## plot the line with regularization ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))
theta = theta2
plt.plot(z, f(to_matrix(z)))
plt.show()

Модель выглядит так.

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

Вот полный код, regression_with_regularization.py

6 Резюме

Это заключительная статья пошагового проекта «Equation-to-Code». Надеюсь, они будут полезны для вас. Оставляйте комментарии, чтобы сообщить мне, легко ли понять мою статью. Спасибо за чтение.

Посмотрите другие мои публикации на Medium с категоризированным просмотром!
GitHub: BrambleXu
LinkedIn: Xu Liang
Блог: BrambleXu