Линейная регрессия в PyTorch

еще одно простое понимание градиентного спуска

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

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

Сумма минимальна, когда градиенты равны нулю:

Полный список математических доказательств приведен по адресу: линейно-регрессионно-доказательство.

Возьмем простой набор точек:

data = np.array([
    [1, 2],
    [1,10],
    [2, 3],
    [3, 6],
    [5, 8],
    [7, 14]
])

и просто примените формулу выше в pytorch:

points = torch.from_numpy(data)
X = points[:,0:1].float()
Y = points[:,1:2].float()
m = (torch.mean(X*Y)-torch.mean(X)*torch.mean(Y))/(torch.mean(X*X)-torch.mean(X)*torch.mean(X)).float()
b = torch.mean(Y) - m* torch.mean(X).float()
print("m(slope)=",m.data.numpy(),"n(y-intercept)=",n.data.numpy()[0][0])

Результат будет:

m(slope)= 1.312139 n(y-intercept)= 3.0030644

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

Набор данных для обучения нейронов имеет вид: x,y,(mx+n=y), где:

  • x,y ввод данных
  • mx+n=y — это цель (мы должны найти m и n так, чтобы mx+n было как можно ближе к y), которая показывает:
  • формула потери (ошибки-стоимости): сумма квадратов (y-(mx+n))
#making result predictable
torch.manual_seed(1)
m = Variable(torch.randn(1, 1,), requires_grad=True)
n = Variable(torch.randn(1, 1,), requires_grad=True)
X = points[:,0:1].float()  
Y = points[:,1:2].float()
alpha = 0.01
epochs = 150
for i in range(epochs):
    prediction = m*X + n
    loss = torch.sum((prediction - Y)**2)
    #calculate dSSE/dm, dSSE/dn         
    loss.backward()
      
    with torch.no_grad():
        m -= alpha * m.grad
        n -= alpha * n.grad
        # Manually zero the gradients after updating weights
        m.grad.zero_()
        n.grad.zero_()
print("loss=",loss.data.numpy())  
print("m(slope)=",m[0][0].data.numpy(),"n(y-intercept)=",n[0][0].data.numpy())

Мы получим:

loss= 51.190907
m(slope)= 1.3139911 n(y-intercept)= 3.0030644

Наконец, мы можем определить «впечатляющую» нейронную сеть (очевидно) только из одного нейрона, используя предопределенные методы pytorch:

class LinearRegressionModel(torch.nn.Module):
    def __init__(self, input_dim, output_dim):
        super(LinearRegressionModel, self).__init__()
        self.linear = torch.nn.Linear(input_dim, output_dim)
    
    def forward(self, x):
        out = self.linear(x)
        return out
    
model = LinearRegressionModel(input_dim=1, output_dim=1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
inputs = Variable(torch.from_numpy(x)).float()
labels = Variable(torch.from_numpy(y)).float()
for epoch in range(450):
    #1. clear gradients w.r.t. parameters
    optimizer.zero_grad()
    #2. forward to get output
    outputs = model(inputs)
    #3 calculate loss (scalar value)
    loss = criterion(outputs, labels)
    #4 calculate gradients w.r.t. parameters
    loss.backward()
    #5 updating parameters
    optimizer.step()
print("loss:",loss.data.numpy())
m = model.linear.weight.data.numpy()[0][0]
b = model.linear.bias.data.numpy()[0]
print("m(slope)=",m,"n(y-intercept)=",b)

И получить примерно такой же результат:

loss: 8.531794
m(slope)= 1.3125678 n(y-intercept)= 3.0095923

Вышеприведенный код в формате Jupyter Notebook доступен на странице линейная регрессия.