一维线性回归:
个人理解就是拟合直线。拟合出一条尽量符合(穿过)最多数据(点)分布的直线。
直线的公式表达是:
f(x)是拟合的直线的值,实际值是y。现在的目的是要f(x)尽可能地接近y。而一般使用点到直线(拟合的直线)的距离差异来衡量接近程度。即均方误差。
公式比较复杂我就不输入了。
基于均方误差最小化来进行模型求解的方法也称为“最小二乘法”。
我们将均方误差表示成一个函数。可以得到一个关于a,b的二元函数。
而对于一个一元函数,我们知道极值是在它导数为0处取得。而对于一个多元函数,极值是在其各偏导都为0处取得。
因此通过对损失函数求偏导找到极(小)值即可得到最优参数。
多维线性回归:
大概原理同一纬相同,同样是使用最小二乘法进行估计参数。
一维线性回归代码实现:
通过pytorch实现一维线性回归。首先随机生成一堆点,通过matplotlib画出来;
# 创建随机数据
x_train = np.random.randn(10)+15 # 生成100个在15附近的数
y_train = np.random.randn(10)+10 # 生成100个在10附近的数
fig = plt.figure(figsize = (10, 10),facecolor='white')
plt.scatter(x_train,y_train) # 散点图
plt.grid() # 绘制数据分布图
plt.savefig("savefig_example_1.png")
plt.show()
随机点图:
将numpy.array转换成Tensor;
# 调整输入数据的形状: 在创建 torch 张量时,使用 unsqueeze 方法将其变为二维张量
x_train = torch.from_numpy(x_train).float().unsqueeze(1)
y_train = torch.from_numpy(y_train).float().unsqueeze(1)
建立模型;
# 构建线性模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression,self).__init__()
self.linear=nn.Linear(1,1) # 输入和输出都是一维的
def forward(self,x):
out = self.linear(x)
return out
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
model=LinearRegression().to(device)
定义损失函数和优化函数;
# 定义损失函数和优化器
criterion=nn.MSELoss()
optimizer=optim.SGD(model.parameters(),1e-3)
训练模型,训练好后预测结果并绘图;
# 训练模型。
Epoch=10000
for eopch in range(Epoch):
if torch.cuda.is_available():
inputs=Variable(x_train).cuda()
target=Variable(y_train).cuda()
else:
inputs=Variable(x_train)
target=Variable(y_train)
# 前向传播
inputs=inputs.float()
out=model(inputs)
loss=criterion(out,target)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每隔20次就打印出损失函数的值
if eopch%20==0:
print(loss.item())
# 将模型变成测试模式
model.eval()
model.cpu()
predict=model(Variable(x_train))
predict=predict.data.numpy()
fig = plt.figure(figsize = (10, 10),facecolor='white')
plt.plot(x_train.numpy(),y_train.numpy(),'ro',label="Original data")
plt.plot(x_train.numpy(),predict,label="Fitting Line")
plt.savefig("savefig_example_2.png")
plt.show()
回归结果图:
多维线性回归代码实现:
大致流程与一维回归相似,只是需要拟合的函数表达式变成了高次多项式,不是简答的直线方程(一元一次函数)。代码如下:
import matplotlib.pyplot as plt
import torch.nn as nn
import torch
import torch.optim as optim
from torch.autograd import Variable
# 待拟合的方程:y=0.9+0.5*x+3*x^2+2.4*x^3
# 参数方程:y=b+w1*x+w2*x^+w3*x^3
def make_features(x):
x=x.unsqueeze(1)
return torch.cat([x ** i for i in range(1,4)],1) # 生成 [x, x², x³]
# 需要拟合的目标参数
w_target=torch.FloatTensor([0.5,3,2.4]).unsqueeze(1)
b_target=torch.FloatTensor([0.9])
def f(x):
return x.mm(w_target)+b_target[0] # 与生成的[x, x², x³]相乘得到所需要的真实函数表达式
# 每次取batch_size个数据点,将它们转换为矩阵的形式
def get_batch(batch_size=32):
random=torch.randn(batch_size)
print(random)
x=make_features(random)
y=f(x)
if torch.cuda.is_available():
inputs=Variable(x).cuda()
target=Variable(y).cuda()
return inputs,target
else:
inputs=Variable(x)
target=Variable(y)
return inputs, target
# 模型
class poly_model(nn.Module):
def __init__(self):
super(poly_model,self).__init__()
self.poly=nn.Linear(3,1) # 模型的输入是3维,输出是1维
def forward(self,x):
out = self.poly(x)
return out
if torch.cuda.is_available():
model=poly_model().cuda()
else:
model=poly_model()
# 三件套
criterion=nn.MSELoss()
optimizer=optim.SGD(model.parameters(),1e-3)
# 模型训练
epoch=0
while True:
# 获取数据
batch_x,batch_y=get_batch()
output=model(batch_x)
loss=criterion(output,batch_y)
print_loss=loss.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
epoch+=1
if epoch%20==0:
print(print_loss)
#直到均方误差小于预设值时退出训练
if print_loss<1e-3:
break
# 绘制真实函数和拟合的多项式
# 生成一组固定的x值
x_plot = torch.linspace(-3, 3, 100)
x_features = make_features(x_plot)
if torch.cuda.is_available():
x_features = x_features.cuda()
model.eval() # 设置模型为评估模式
with torch.no_grad():
y_pred = model(x_features).cpu().numpy()
# 计算真实的y值
y_true = f(x_features.cpu()).numpy()
# 转换x值为numpy
x_plot = x_plot.cpu().numpy()
# 绘图
plt.figure(figsize=(10, 6))
plt.scatter(x_plot, y_true, label='real curve', color='blue', alpha=0.5)
plt.plot(x_plot, y_pred, label='fitting curve', color='red')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
回归结果图: