Линейная регрессия — это широко используемый метод статистического анализа, который использует регрессионный анализ в математической статистике для определения количественной связи между двумя или более переменными. Регрессия используется для прогнозирования взаимосвязи между входными переменными и выходными переменными, особенно когда значение входной переменной изменяется, значение выходной переменной также изменяется. Модель регрессии — это просто функция, представляющая отображение входных переменных в выходные переменные.
Одномерная линейная регрессия
Одномерная линейная модель очень проста, если предположить, что у нас есть переменнаяи цель, каждый я соответствует точке данных, желающих построить модель
является результатом нашего предсказания, надеюсь,соответствовать цели, с точки зрения непрофессионала, найти эту функцию подходящейОшибка минимизируется, то есть минимизируемое значение выражается как:
LЭто широко известно как функция стоимости, которая представляет собой среднеквадратичное расстояние между прогнозируемым значением и истинным значением.В статистике это обычно называется MAE (среднеквадратическая ошибка) среднеквадратичной ошибкой. Подставим предыдущую функциональную формулу в функцию стоимости и рассмотрим параметры w и b, которые необходимо решить, как независимые переменные функции L, мы можем получить
Теперь задача состоит в том, чтобы решить задачу минимизацииLКогда значения w и b, то есть формула оптимизации основной цели,
Есть два пути решения
1) Метод наименьших квадратов
Решение для w и b - это процесс минимизации функции потерь, который в статистике называется методом наименьших квадратов «оценкой параметра» модели линейной регрессии. Мы можем продифференцировать L(w,b) по w и b соответственно, чтобы получить(В чем суть метода наименьших квадратов)
Пусть два приведенных выше уравнения равны 0, можно получить решение в замкнутой форме оптимального решения w и b:
2) Градиентный спуск
Первый попавшийся алгоритм оптимизации, очень простой, но очень мощный, часто используется в глубоком обучении, поэтому давайте начнем с простого примера, чтобы понять принцип градиентного спуска.
градиент
Градиент математически является производной, и если это многомерная функция, то градиент является частной производной. Например, функция f(x, y), то градиент f равен
Может называться grad f(x, y) или ∇?(?,?)∇f(x,y). Градиент конкретной точки (?0, ?0)(x0, y0) равен ∇?(?0, ?0)∇f(x0, y0).
Что означает градиент? Геометрически говоря, значение градиента точки — это место, где функция изменяется быстрее всего, в частности, для функции f(x, y) в точке (?0,?0)(x0,y0) вдоль градиента в направлении ∇?(?0, ?0)∇f(x0, y0), функция возрастает быстрее всего, то есть по направлению градиента быстрее можно найти точку максимума функции, или наоборот по градиенту В обратном направлении мы можем быстрее найти точку минимума функции.
Градиентный спуск
Понимая градиенты, мы можем понять принцип градиентного спуска. Выше нам нужно минимизировать эту ошибку, то есть нам нужно найти точку минимума этой ошибки, тогда мы можем найти эту точку минимума по противоположному направлению градиента.
Мы можем посмотреть на интуитивное объяснение. Например, когда мы находимся где-то на большой горе, потому что мы не знаем, как спуститься с горы, мы решаем делать по одному шагу за раз, то есть, когда мы достигаем положения, решаем градиент текущего положение, вдоль отрицательного направления градиента, а также сделать шаг вниз от текущего самого крутого положения, а затем продолжить решение градиента текущего положения и сделать шаг по самому крутому и легкому спуску к положению этого шага. И так шаг за шагом, пока не почувствуем, что достигли подножия горы. Конечно, если мы будем продолжать в том же духе, возможно, что мы не дойдем до подножия горы, а дойдем до нижней части определенной части горы.
По аналогии с нашей задачей, мы продолжаем изменять значения w и b вдоль противоположного направления градиента и, наконец, находим наилучший набор w и b, который минимизирует ошибку.
При обновлении нам нужно определить величину каждого обновления. Например, в примере спуска с горы нам нужна длина шага, который мы делаем каждый раз, когда спускаемся. Эта длина называется скоростью обучения.Это означает, что эта скорость обучения очень важна. Разные скорости обучения приведут к разным результатам. Если скорость обучения слишком мала, это приведет к очень медленному снижению. Если скорость обучения слишком велика, это приведет к очень очевидным прыжки.
Наконец, наша формула обновления
Путем итеративного обновления в конечном итоге мы можем найти набор оптимальных w и b, что является принципом градиентного спуска.
код
import torch
import numpy as np
from torch.autograd import Variable
import matplotlib.pyplot as plt
def fun1():
torch.manual_seed(2017)
x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],
[9.779], [6.182], [7.59], [2.167], [7.042],
[10.791], [5.313], [7.997], [3.1]], dtype=np.float32)
y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
[3.366], [2.596], [2.53], [1.221], [2.827],
[3.465], [1.65], [2.904], [1.3]], dtype=np.float32)
plt.ion()
plt.figure()
plt.plot(x_train, y_train, 'bo')
plt.show()
# 转换成 Tensor
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)
# w = Variable(torch.randn(1), requires_grad=True) # 随机初始化
# b = Variable(torch.zeros(1), requires_grad=True) # 使用 0 进行初始化
w = torch.randn(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
print('w:', w)
print('b:', b)
def linear_model(x):
return x * w + b
y_ = linear_model(x_train)
plt.figure()
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()
# 计算误差
def get_loss(y_, y):
return torch.mean((y_ - y_train) ** 2)
loss = get_loss(y_, y_train)
print(loss)
# 自动求导
loss.backward()
# 查看 w 和 b 的梯度
print(w.grad)
print(b.grad)
# 更新一次参数
w.data = w.data - 1e-2 * w.grad.data
b.data = b.data - 1e-2 * b.grad.data
y_ = linear_model(x_train)
plt.figure()
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
for e in range(100): # 进行 10 次更新
y_ = linear_model(x_train)
loss = get_loss(y_, y_train)
w.grad.zero_() # 记得归零梯度
b.grad.zero_() # 记得归零梯度
loss.backward()
w.data = w.data - 1e-2 * w.grad.data # 更新 w
b.data = b.data - 1e-2 * b.grad.data # 更新 b
# print('epoch: {}, loss: {}, {}'.format(e, loss.item(), w.grad))
print("epoch:{}, loss:{}, w:{}-{}, b:{}-{}".format(e, loss, w, w.grad, b, b.grad))
# plt.figure()
# plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
# plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
# plt.show()
# # plt.pause(0.5)
# plt.close()
# input("Press Enter to Continue") # 之后改成识别输出
y_ = linear_model(x_train)
plt.figure()
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
print("w", w)
print("b", b)
print("-" * 10)
if __name__ == '__main__':
fun1()
Вывод выполнения:
w: tensor([2.2691], requires_grad=True)
b: tensor([0.], requires_grad=True)
tensor(153.3520, grad_fn=<MeanBackward0>)
tensor([161.0043])
tensor([22.8730])
epoch:0, loss:3.135774850845337, w:tensor([0.4397], requires_grad=True)-tensor([21.9352]), b:tensor([-0.2576], requires_grad=True)-tensor([2.8870])
epoch:1, loss:0.3550890386104584, w:tensor([0.4095], requires_grad=True)-tensor([3.0163]), b:tensor([-0.2593], requires_grad=True)-tensor([0.1687])
epoch:2, loss:0.30295437574386597, w:tensor([0.4051], requires_grad=True)-tensor([0.4424]), b:tensor([-0.2573], requires_grad=True)-tensor([-0.2005])
epoch:3, loss:0.30131959915161133, w:tensor([0.4041], requires_grad=True)-tensor([0.0922]), b:tensor([-0.2548], requires_grad=True)-tensor([-0.2502])
...
epoch:93, loss:0.2522490322589874, w:tensor([0.3743], requires_grad=True)-tensor([0.0294]), b:tensor([-0.0477], requires_grad=True)-tensor([-0.2048])
epoch:94, loss:0.2518215477466583, w:tensor([0.3740], requires_grad=True)-tensor([0.0294]), b:tensor([-0.0456], requires_grad=True)-tensor([-0.2043])
epoch:95, loss:0.2513962388038635, w:tensor([0.3737], requires_grad=True)-tensor([0.0293]), b:tensor([-0.0436], requires_grad=True)-tensor([-0.2037])
epoch:96, loss:0.250973105430603, w:tensor([0.3734], requires_grad=True)-tensor([0.0292]), b:tensor([-0.0416], requires_grad=True)-tensor([-0.2032])
epoch:97, loss:0.250552237033844, w:tensor([0.3731], requires_grad=True)-tensor([0.0291]), b:tensor([-0.0395], requires_grad=True)-tensor([-0.2027])
epoch:98, loss:0.25013336539268494, w:tensor([0.3728], requires_grad=True)-tensor([0.0291]), b:tensor([-0.0375], requires_grad=True)-tensor([-0.2022])
epoch:99, loss:0.24971675872802734, w:tensor([0.3725], requires_grad=True)-tensor([0.0290]), b:tensor([-0.0355], requires_grad=True)-tensor([-0.2017])
w tensor([0.3725], requires_grad=True)
b tensor([-0.0355], requires_grad=True)
- Исходные данные:
- Первая подгонка:
- Вторая подгонка:
- окончательный эффект:
Ссылаться на:
В чем суть метода наименьших квадратов?
Объяснение принципа алгоритма градиентного спуска - машинное обучение
Что такое градиентный спуск?
Резюме градиентного спуска