线性回归
回归(regression)是能为一个或多个自变量与因变量之间关系建模的一类方法。在自然科学和社会科学领域,回归经常用来表示输入和输出之间的关系。线性回归基于几个假设:首先自变量X和因变量y之间的关系是线性的,即y可以表示为x中元素的加权 和,这里通常允许包含观测值的一些噪声;其次,我们假设任何噪声都比较正常,如噪声遵循正态分布。
线性回归基本元素
为了得到一个线性模型,我们需要收集一个数据集称为训练集(training data set),每行数据称为一个样本(sample), 预测的目标称为标签(label)。预测所依据的因变量称为特征(feature)。
通常用来表示数据集中的样本数。对索引为i的 样本,其输入表示为
,
为特征数, 其对应的标签为
。
线性表示的目标是标签可以表示为特征的加权和, 如下:
称为权重(weight),权重决定了每个特征对我们预测值的影响。b称为偏置(bias)、 偏移量(offset)或截距(intercept)
将所有特征放进向量中, 并将所有权重放进
,可以用更简洁的表达模型:
损失函数
损失函数(loss function) 能够量化目标的实际值与预测值之间的差距。通常我们会选择非负数作为损失,且数值越小表示损失越小, 完美预测时的损失为0。回归问题中最常用的损失函数是平方误差函数。当样本的预测值为
,其相应的真 实标签为
时,平方误差可以定义为以下公式:
为了度量模型在整个数据集上的质量, 我们需要计算在训练集n个样本上的损失均值。
在训练模型时,我们希望寻找一组参数,这组参数能最小化在所有训练样本上的总损失。
随机梯度下降
梯度下降最简单的用法是计算损失函数(数据集中所有样本的损失均值)关于模型参数的导数(在这里也可 以称为梯度)。但实际中的执行可能会非常慢:因为在每一次更新参数之前,我们必须遍历整个数据集。因此, 我们通常会在每次需要计算更新的时候随机抽取一小批样本,这种变体叫做小批量随机梯度下降(minibatch stochastic gradient descent)。
在每次迭代中,我们首先随机抽样一个小批量B,它是由固定数量的训练样本组成的。然后,我们计算小批量的平均损失关于模型参数的导数(也可以称为梯度)。最后,我们将梯度乘以一个预先确定的正数η,并从当前参数的值中减掉。
我们用下面的数学公式来表示这一更新过程(∂表示偏导数):
算法的步骤如下:(1)初始化模型参数 (2)从数据集中随机抽取小批量样本且在负梯度的方向上更新参数,并不断迭代这一步骤。对于平方损失和仿射变换,我们可以明确地写成如
|B|表示每个小批量中的样本数,这也称为批量大小(batch size)。η表示学习率(learning rate)。批量 大小和学习率的值通常是手动预先指定,而不是通过模型训练得到的。这些可以调整但不在训练过程中更新的参数称为超参数(hyperparameter)。
导入库
import numpy
import torch
from torch import nn
from torch.utils import data
import matplotlib.pyplot as plt
构建数据集
首先定义一个数据生成函数
def synthentic_data(w, b, n_samples):
x = torch.normal(0, 1, (n_samples, len(w))
y = torch.matmul(x, w) + b
y = y + torch.normal(0, 0.01, y.shape )
return x, y.reshape((-1,1))
然后定义w, b, 生成数据
true_w = torch.tensor([2.56, 3.2])
true_b = torch.tensor([4])
features, lables = synthetic_data(true_w, true_b, n_samples=1000)
数据可视化,画出散点图
from matplotlib_inline import backend_inline
backend_inline.set_matplotlib_formats('svg')
fig, ax = plt.subplots(figsize=(5,3))
ax.scatter(features[:,0], lables, c='r',marker='o')
ax.set_xlabel("features")
ax.set_ylabel("label")
ax.set_title('linear regrssion')
plt.show()
读取数据集
def load_array(data_array, batch_size, is_train=True):
dataset = data.TensorDataset(*data_array)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
train_iter = load_array((features, labels), batch_size=64, is_train=True)
定义网络
net = nn.Sequential(nn.linear(2, 1))
定义误差函数
loss = nn.MSELoss()
定义优化器
trainer = nn.optim.SGD(net.parameters(), lr=0.03)
训练过程
num_epochs = 10
for epoch in range(num_epochs):
for x, y in data_iter :
l = loss(net(x), y)
trainer.zero_grad()
l.backward()
trainer.step()
l = loss(net(x), y)
print(f'epoch{epoch+1} : loss:{l:f}')
结果查看
w = net[0].weight.data
b = net[0].bias.data
print(f'true_w:{true_w}, w:{w}')
print(f'true_b:{true_b}, b:{b}')