Подробное объяснение реализации регуляризации с нуля в Python.
Всем привет! Это пошаговое руководство «Уравнение в код», часть 4, последняя в этой серии.
В предыдущих статьях мы говорили о линейной задаче отделимости в части 1, нелинейной задаче отделимости во части 2 и стохастическом градиентном спуске. (SGD) в часть 3. Как и другие части, часть 4 самодостаточна, вы можете просто игнорировать предыдущие статьи.
В части 4 мы поговорим о том, как реализовать регуляризацию для задачи регрессии, что может сделать нашу модель более надежной.
Вот полный код, regression_without_regularization.py и regression_with_regularization.py.
Содержание структурировано следующим образом.
- Регуляризация
- Подделать некоторые образцы данных
- Предварительная обработка
- Внедрение без регуляризации
- Реализация с регуляризацией
- Резюме
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