模型数学表达
n维输入 x = [ x 1 , x 2 , … , x n ] T \boldsymbol{x}=[x_1,x_2,\dots,x_n]^T x=[x1,x2,…,xn]T
直观的描述就是数据集中的各种特征就是输入,就是每一行中除了标签的属性(特征)
线性模型中对每个输入也有相应的权重和偏差
w
=
[
w
1
,
w
2
,
…
,
w
n
]
T
,
b
\boldsymbol{w} =[w_1,w_2,\dots,w_n]^T, b
w=[w1,w2,…,wn]T,b
本质上来说,w对应的就是每个输入特征的重要性,这也是线性模型能够做特征重要性排序以及特征重要性筛选的一个重要考察特征
结合起来的输出就是
y
=
w
1
x
1
+
w
2
x
2
+
⋯
+
w
n
x
n
y
=
<
w
,
x
>
+
b
y = w_1x_1+w_2x_2+\dots+w_nx_n \\ y = <\boldsymbol{w}, \boldsymbol{x}>+b
y=w1x1+w2x2+⋯+wnxny=<w,x>+b
同时能够把线性模型看成单层神经网络
输入层就是输入的数据,偏差就是阈值,权重就是边上的权重
学习的目的是使得一种模型能够通过一系列的计算使得模型能够拟合数据并在新数据下能够有更好的泛化性能(虽然泛化性能说的就是对新数据)。就需要我们在每个模型下制定一个能够衡量真实值和预测值差异的一个函数,让模型能够根据这个函数的指导下进一步的使得模型能够尽可能的(虽然有点不恰当)拟合数据,把这个衡量函数叫做损失函数(这是我自己对损失函数的理解)
我们定义均方损失函数(MSE)为
l
(
y
,
y
^
)
=
1
2
(
y
−
y
^
)
2
l(y,\hat{y}) = \frac{1}{2}(y-\hat{y})^2
l(y,y^)=21(y−y^)2
代入模型得
l
(
X
,
y
,
w
,
b
)
=
1
2
n
∑
i
=
1
n
(
y
i
−
<
x
i
,
w
>
−
b
)
2
l(X,y,w,b) = \frac{1}{2n} \sum_{i=1}^{n} (y_i-<x_i,w>-b)^2
l(X,y,w,b)=2n1i=1∑n(yi−<xi,w>−b)2
我们目的是要找到一组w和b来满足
w
∗
,
b
∗
=
a
r
g
m
i
n
l
(
X
,
y
,
w
,
b
)
w^*,b^* = {argmin} \;l(X,y,w,b)
w∗,b∗=argminl(X,y,w,b)
线性回归是有显式解的,推导如下:
梯度下降
优化过程中常用的方法是使用梯度下降。
基本的思路是计算当前函数在当前数据下(也可以是多个数据)的梯度,使参数能够沿着梯度负方向也就是损失下降最快的方向使得损失函数减小
如果使用整个数据集的数据进行梯度计算开销会非常大,往往使用的是小批量随机梯度下降
小批量指的是在数据集上抽样,抽出一定的数量的数据来做运算,随机指的是随机抽样。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存
在选择批量大小的时候要选择一个合适的大小,太大太小都会有不同的开销
实现
实现部分主要放我有理解的代码
从零实现
def sgd(params, lr, batch_size): #@save # 这里传入的parms是引用,所以导致他能够对参数进行更新
"""小批量随机梯度下降"""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
batch_size = 10 # 批量大小
lr = 1
num_epochs = 3 # 整个数据扫三遍
net = linreg
loss = squared_loss
#%%
for epoch in range(num_epochs):
listi = data_iter(batch_size, features, labels)
for X, y in listi:
l = loss(net(X, w, b), y) # X和y的小批量损失
# 因为l形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,
# 并以此计算关于[w,b]的梯度
# print("l: ", l.size())
l.sum().backward()
sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数
# sgd([w, b], lr, min(batch_size, l.size()[0])) # 使用参数的梯度更新参数
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, train loss {float(train_l.mean()):f}')
简洁实现
# nn是神经网络的缩写
from torch import nn
# 输入维度是2,输出是1
net = nn.Sequential(nn.Linear(2, 1)) # 支出输入维度输出维度
# 定义初始值
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
# 定义损失函数MSE
loss = nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03) # 制定参数和学习率
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y) # 放入训练
trainer.zero_grad() # 清零
l.backward() # pytorch做了sum
trainer.step() # 模型更新
l = loss(net(features), labels) # 算一下所有的数据的loss
print(f'epoch {epoch + 1}, loss {l:f}')