Linear Regression

Concept and Principle

  • 线性模型
    • 基本的线性模型可抽象为如下表示,其可以看作一个单层单神经元的神经网络
    • 线性模型有显示解
  • 优化
    • 梯度下降
      需要注意的是梯度是t-1时刻得来的,而且梯度是t-1时刻样本点、标签值以及W参数值对应的梯度,因为他们都是损失函数中的因变量
    • 成批计算梯度
      batch_size不能太大也不能太小。太小:并行计算难以发挥效果;太大:内存消耗增加、易陷入局部最优。batch_size是另一个重要的超参数。

Implementation

  • 从零实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import random
import torch
from torch.utils.data.dataloader import DataLoader

true_w=torch.tensor([2.2,3])
true_b=torch.tensor([-1.9])
num_examples=2500
batch_size=50
epoch=100
learning_rate=0.01
# 初始化参数
w=torch.normal(0,0.01,true_w.shape,requires_grad=True)
b=torch.zeros(true_b.shape,requires_grad=True)

def SyntheticData(w,b,num_examples):
X=torch.normal(0,1,size=(num_examples,len(w)))
# 支持多维度、不同维度的矩阵乘法
# 直接加b用了广播机制
y=torch.matmul(X,w) + b
# 增加噪声,使得不能完全拟合
y+=torch.normal(0,0.01,y.shape)

return X,y.view(-1,1)

# 生成小批量
def DataIter(batch_size,features,labels):
num_examples=len(features)

indices=list(range(num_examples))

# 打乱顺序
random.shuffle(indices)
for i in range(0,num_examples,batch_size):
batch_indices=torch.tensor(
indices[i:min(i+batch_size,num_examples)]
)

# Tensor可以接受一个列表的下标来取值
yield features[batch_indices],labels[batch_indices]

# 定义模型
def LinReg(X,w,b):

return torch.matmul(X,w)+b

# 定义损失函数
def SquaredLoss(y_hat,y):
return (y_hat-y.view(y_hat.shape))**2/2/batch_size

# 优化算法
def sgd(params,lr,batch_size):
with torch.no_grad():
for param in params:
param-=lr*param.grad
param.grad.zero_()


features,labels=SyntheticData(true_w,true_b,num_examples)

# 训练
def Train():

for i in range(epoch):
e_loss=[]
for X,y in DataIter(batch_size,features,labels):
out=LinReg(X,w,b)
# 将batch_size个损失求和
l=SquaredLoss(y,out).sum()
l.backward()
sgd([w,b],learning_rate,batch_size)

e_loss.append(l.item())

print(f"{i+1},loss:{sum(e_loss)/num_examples}")


Train()
# 简单验证
x=torch.tensor([108,2.666])
print(true_w,w)
print(true_b,b)
print(LinReg(x,true_w,true_b).item())
print(LinReg(x,w,b).item())
  • 简洁实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import numpy as np
import torch
from torch.utils import data
from torch import nn
from torch import optim

true_w=torch.tensor([2.2,3])
true_b=torch.tensor([-1.9])
num_examples=5000

def SyntheticData(w,b,num_examples):
X=torch.normal(0,1,size=(num_examples,len(w)))
y=torch.matmul(X,w)+b

y+=torch.normal(0,0.01,y.shape)

return X,y.view(-1,1)

features,labels=SyntheticData(true_w,true_b,num_examples)

# 使第一维成为两个Tensor的共同索引,所以两个Tensor的第一维size要相同
# 用来组成dataloader可处理的形式
dataset=data.TensorDataset(features,labels)
data_iter=data.dataloader.DataLoader(dataset,shuffle=True,batch_size=150)

net=nn.Sequential(nn.Linear(len(true_w),1,bias=True))
loss_f=nn.MSELoss()
opt=optim.SGD(net.parameters(),lr=0.01)

for epoch in range(100):
e_loss=[]

for X,y in data_iter:
out=net(X)
l=loss_f(out,y)

e_loss.append(l.item())
l.backward()
opt.step()
opt.zero_grad()

print(f"{epoch+1} {sum(e_loss)}")

x=torch.tensor([108,2.666])
print(true_w,true_b)
for i in net.parameters():
print(i)