什么是回归分析?
回归分析(Regression Analysis)是确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。在回归分析中,只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。如果回归分析中包括两个或两个以上自变量,且自变量和因变量之间是线性关系,则称为多元线性回归分析。
梯度下降法求一元线性回归
求线性回归公式 ,已知x和y,求w和b。
求解最佳参数,需要一个标准来对结果进行衡量,为此我们需要定量化一个目标函数式,使得计算机可以在求解过程中不断地优化。针对任何模型求解问题,都是最终都是可以得到一组预测值 ,对比已有的真实值 y,数据行数为 n,可以将损失函数定义如下:
求当Loss最小时的w和b的值。使用梯度下降法:
求导数(梯度):
更新导数(梯度):(学习率 )
例:11个房子的面积和价格:
面积(m^2) | 180 | 100 | 160 | 80 | 90 | 110 | 120 | 170 | 150 | 140 | 130 |
价格(万元) | 180 | 100 | 160 | 80 | 90 | 110 | 120 | 170 | 150 | 140 | 130 |
准备数据:x=np.array([0.18,0.1,0.16,0.08,0.09,0.11,0.12,0.17,0.15,0.14,0.13]),
y=np.array([0.18,0.1,0.16,0.08,0.09,0.11,0.12,0.17,0.15,0.14,0.13])
模型:
损失函数:
求导数(梯度):
更新导数(梯度):
代码:
import numpy as np
x = np.array([0.18, 0.1, 0.16, 0.08, 0.09, 0.11, 0.12, 0.17, 0.15, 0.14, 0.13])
y = np.array([0.18, 0.1, 0.16, 0.08, 0.09, 0.11, 0.12, 0.17, 0.15, 0.14, 0.13])
lr = 5 # 学习率
w = 10 # w初始值
n = 50 # 迭代次数
ya = w * x # 模型
w_list = [w]
for i in range(n):
w_gra = np.mean((w * x - y) * x) # 梯度
w = w - lr * w_gra
w_list.append(w)
loss = 1 / 2.0 * np.sum((w * x - y) ** 2)
print(f'第{i + 1}次,梯度:{w_gra:.4f} w :{w:.4f} 损失:{loss:.4f}')
运行结果:
第1次,梯度:0.1611 w :9.1945 损失:6.6109
第2次,梯度:0.1467 w :8.4611 损失:5.4805
第3次,梯度:0.1336 w :7.7933 损失:4.5434
第4次,梯度:0.1216 w :7.1853 损失:3.7665
第5次,梯度:0.1107 w :6.6317 损失:3.1225
第6次,梯度:0.1008 w :6.1277 损失:2.5886
第7次,梯度:0.0918 w :5.6688 损失:2.1460
第8次,梯度:0.0836 w :5.2509 损失:1.7790
第9次,梯度:0.0761 w :4.8705 损失:1.4748
第10次,梯度:0.0693 w :4.5240 损失:1.2226
第11次,梯度:0.0631 w :4.2086 损失:1.0136
第12次,梯度:0.0574 w :3.9215 损失:0.8403
第13次,梯度:0.0523 w :3.6600 损失:0.6966
第14次,梯度:0.0476 w :3.4219 损失:0.5775
第15次,梯度:0.0434 w :3.2052 损失:0.4787
第16次,梯度:0.0395 w :3.0078 损失:0.3969
第17次,梯度:0.0359 w :2.8281 损失:0.3290
第18次,梯度:0.0327 w :2.6645 损失:0.2728
第19次,梯度:0.0298 w :2.5155 损失:0.2261
第20次,梯度:0.0271 w :2.3799 损失:0.1875
第21次,梯度:0.0247 w :2.2564 损失:0.1554
第22次,梯度:0.0225 w :2.1439 损失:0.1288
第23次,梯度:0.0205 w :2.0416 损失:0.1068
第24次,梯度:0.0186 w :1.9483 损失:0.0885
第25次,梯度:0.0170 w :1.8635 损失:0.0734
第26次,梯度:0.0155 w :1.7862 损失:0.0608
第27次,梯度:0.0141 w :1.7158 损失:0.0504
第28次,梯度:0.0128 w :1.6518 损失:0.0418
第29次,梯度:0.0117 w :1.5934 损失:0.0347
第30次,梯度:0.0106 w :1.5403 损失:0.0287
第31次,梯度:0.0097 w :1.4919 损失:0.0238
第32次,梯度:0.0088 w :1.4479 损失:0.0198
第33次,梯度:0.0080 w :1.4078 损失:0.0164
第34次,梯度:0.0073 w :1.3713 损失:0.0136
第35次,梯度:0.0066 w :1.3381 损失:0.0113
第36次,梯度:0.0061 w :1.3078 损失:0.0093
第37次,梯度:0.0055 w :1.2803 损失:0.0077
第38次,梯度:0.0050 w :1.2552 损失:0.0064
第39次,梯度:0.0046 w :1.2324 损失:0.0053
第40次,梯度:0.0042 w :1.2116 损失:0.0044
第41次,梯度:0.0038 w :1.1926 损失:0.0037
第42次,梯度:0.0034 w :1.1754 损失:0.0030
第43次,梯度:0.0031 w :1.1597 损失:0.0025
第44次,梯度:0.0029 w :1.1454 损失:0.0021
第45次,梯度:0.0026 w :1.1324 损失:0.0017
第46次,梯度:0.0024 w :1.1205 损失:0.0014
第47次,梯度:0.0022 w :1.1097 损失:0.0012
第48次,梯度:0.0020 w :1.0999 损失:0.0010
第49次,梯度:0.0018 w :1.0910 损失:0.0008
第50次,梯度:0.0016 w :1.0828 损失:0.0007
利用PyTorch顺序结构实现梯度下降拟合线性回归
import torch
import matplotlib.pyplot as plt
# 准备数据
x_data = torch.tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
y_data = torch.tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
# 定义参数
w = torch.tensor([[10]], requires_grad=True, dtype=torch.float32) # 定义权重参数
b = torch.tensor([0], requires_grad=True, dtype=torch.float32)
learning_rate = 0.5 # 学习率
epoch = 5000 # 迭代次数
# 循环迭代逼近w和b真实值,也就是更新w和b
for i in range(epoch):
y_predict = torch.matmul(x_data, w) + b # 模型 正向传播
loss = (y_data - y_predict).pow(2).mean() # 计算 均方差 损失函数
if w.grad is not None:
w.grad.data.zero_() # 对参数w和b的grad进行归零,然后再反向传播
if b.grad is not None:
b.grad.data.zero_()
loss.backward() # 模型反向传播
w.data = w.data - learning_rate * w.grad # 更新模型中的权重
b.data = b.data - learning_rate * b.grad
print(f'第{i + 1}次:w:{w.item():.6f} b:{b.item():.6f} loss:{loss.item():.8f}')
print(f'最终的结果:w:{w.item():.6f} b:{b.item():.6f} loss:{loss.item():.8f}')
# 可视化
plt.scatter(x_data, y_data, 20, 'r')
y_predict = torch.matmul(x_data, w) + b
plt.plot(x_data, y_predict.detach().numpy())
plt.show()
利用PyTorch封装类实现梯度下降拟合线性回归
import torch
import matplotlib.pyplot as plt
class LModel():
def __init__(self, learning_rate):
self.w = torch.tensor([[10]], requires_grad=True, dtype=torch.float32) # 定义权重参数
self.b = torch.tensor([0], requires_grad=True, dtype=torch.float32)
self.learning_rate = learning_rate # 学习率
self.loss = None # 迭代次数
def forward(self, x, y):
y_pred = torch.matmul(x, self.w) + self.b
self.loss = (y - y_pred).pow(2).mean()
return y_pred
def backward(self):
if self.w.grad is not None:
self.w.grad.data.zero_()
if self.b.grad is not None:
self.b.grad.data.zero_()
self.loss.backward()
self.w.data = self.w.data - self.learning_rate * self.w.grad # 更新模型中的权重
self.b.data = self.b.data - self.learning_rate * self.b.grad
print(f'第{i + 1}次:w:{self.w.item():.6f} b:{self.b.item():.6f} loss:{self.loss.item():.8f}')
# 准备数据
x_data = torch.tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
y_data = torch.tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
epoch = 5000
model = LModel(learning_rate=0.5)
for i in range(epoch):
model.forward(x_data, y_data)
model.backward()
# 可视化
plt.scatter(x_data, y_data, 20, 'r')
y_predict = model.forward(x_data,y_data)
plt.plot(x_data, y_predict.detach().numpy())
plt.show()
利用PyTorch继承类实现梯度下降拟合线性回归
import torch
import matplotlib.pyplot as plt
# 固定继承于Model
class LinearModel(torch.nn.Module):
# 调用函数初始化
def __init__(self):
# 调用父类的init
super(LinearModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
# 前馈函数forward,对父类函数中的overwrite
def forward(self, x):
# 调用linear中的call(),以利用父类forward()计算wx+b
y_pred = self.linear(x)
return y_pred
# 数据
x_data = torch.Tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
y_data = torch.Tensor([[0.18], [0.1], [0.16], [0.08], [0.09], [0.11], [0.12], [0.17], [0.15], [0.14], [0.13]])
# 定义模型
model = LinearModel()
# 构造均方差 损失函数
criterion = torch.nn.MSELoss(size_average=False)
# 使用梯度下降法进行优化
optimizer = torch.optim.SGD(model.parameters(), lr=0.05)
# 迭代更新模型权重
for i in range(5000):
y_pred = model(x_data) # 前向传播计算y_pred
loss = criterion(y_pred, y_data) # 计算损失loss
optimizer.zero_grad() # 梯度清零
loss.backward() # 梯度反向传播
optimizer.step() # 根据传播的梯度以及学习率更新参数
print(loss)
# 输出模型权重值
print('w=', model.linear.weight.item())
print('b=', model.linear.bias.item())
# 预测值
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred=', y_test.data)
# 可视化
plt.figure()
plt.scatter(x_data, y_data, 20, 'r')
y_predict = model(y_data)
plt.plot(x_data, y_predict.detach().numpy())
plt.show()