PyTorch
实现深度学习笔记,尽量坚持每周持续更新,欢迎大家订阅!关注
、点赞
、✌收藏
、订阅
专栏参考资料:本专栏主要以沐神《动手学深度学习》为学习资料,记录自己的学习笔记,能力有限,如有错误,欢迎大家指正。同时沐神上传了的教学视频和教材,大家可以前往学习。
线性回归是机器学习中非常常用的模型之一,特别在研究定量数据的问题中,它能分析变量之间的关系,并给出很好的解释。此外,它还是新方法的一个良好起点:许多有趣的统计学习方法可以被视为线性回归的推广或扩展。例如Lasso回归
,岭回归
,logistic regression
,softmax回归
。具体理论介绍部分大家可以看我这篇文章:统计学习方法之线性回归详解
简单线性回归模型具体形式可以如下表示:
y = w 1 x 1 + w 2 x 2 + . . . + w n x n + b y = w_1x_1+w_2x_2+...+w_nx_n+b y=w1x1+w2x2+...+wnxn+b
写成向量的形式:
Y = W T X + b Y = W^TX+b Y=WTX+b
在我们拿到一堆数据之后,我们要做就是找到最好的参数 W , b W,b W,b,如何找到最好的参数呢?在那之前我们介绍一下损失函数和梯度下降
损失函数是衡量一个模型拟合的重要指标,表示实际值和拟合值之间的差距,在线性回归中,损失函数也被称作平方误差函数。我们之所以要求出误差的平方和,是因为一般我们认为误差是非负的,而误差绝对值在求导时不太便利,而误差平方损失函数,对于大多数问题,特别是回归问题,都是一个合理的选择。具体定义如下:
L ( W ^ , b ^ ) = 1 2 m ∑ i = 1 m ( y ( i ) − W T x ( i ) − b ) 2 L(\hat{W},\hat{b})=\frac{1}{2m}\sum_{i=1}^{m}(y^{(i)} - W^Tx^{(i)}-b)^2 L(W^,b^)=2m1i=1∑m(y(i)−WTx(i)−b)2
我们的目标便是选择出可以使得损失函数能够最小的模型参数,因为线性回归是一个很简单的问题,所有大部分情况下都存在解析解,对L求梯度为0的点。为了方便表示,这里我将 b b b也放入到 W W W中,则有:
Y = W T X Y = W^TX Y=WTX
其中, w 0 = b w_0=b w0=b x 0 = 1 x_0=1 x0=1,此时对上述求梯度为0后可以得到正规方程解:
W = ( X T X ) − 1 X T y W = (X^TX)^{-1}X^Ty W=(XTX)−1XTy
梯度下降是一种优化算法,后续还会介绍一些其他的优化方法,例如Adam,SGD等。本章暂时用梯度下降来计算参数。梯度下降背后的思想是:开始时我们随机选择一个参数的组合,计算损失函数,然后我们寻找下一个能让损失函数值下降最多的参数组合。
具体公式如下:
w i : = w i − η d L d w i w_{i} := w_i - \eta\frac{dL}{dw_i} wi:=wi−ηdwidL
我们持续这么做直到得到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。此时如何设置合适的 η \eta η值是需要我们考虑的,如果 η \eta η太大,则可能到不了最低点,导致无法收敛,如果 η \eta η太小,那收敛过程太慢,这些细节问题在之后再讨论,接下来我们来看看如何实现一个简单的线性回归模型。
导入相关库
import random
import torch
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
为了方便举例,这里使用模拟数据集进行展示。假设样本来自标准正态分布,每个样本有两个特征,我们生成1000个数据集, w = [ 1 , − 1 ] T w=[1,-1]^T w=[1,−1]T, b = 2 b=2 b=2, ϵ \epsilon ϵ是一个均值为0,标准差为0.1的正态分布
def simulation_data(w,b,n):
X = torch.normal(0,1,(n,len(w)))#生成标准正态分布
y = torch.matmul(X, w)+b#计算回归拟合值
y += torch.normal(0,0.1,y.shape) #加上随机扰动项
return X,y.reshape((-1,1))
true_w = torch.tensor([-1,1],dtype=torch.float32)
true_b = 2
features, target = simulation_data(true_w,true_b,1000)
此时已经生成好了模拟数据集,下面我们绘制图形观察一下
plt.scatter(features[:,(1)].detach().numpy(),target.detach().numpy(),2)
从上图我可以看出,y和一个特征之间的关系呈现明显的线性关系。
下面我们开始初始化我们要求的参数,通常将 w w w设置为均值为0的正态分布, b b b设置为0向量
w = torch.normal(0,0.1,(2,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)
初始化参数之后,我们下一步就是开始定义我们的线性回归模型
def reg(X,w,b):
return torch.matmul(X,w)+b
def loss_fun(y_hat,y):
return(y_hat-y)**2/2/len(y)
def gd(params,n):
with torch.no_grad():#在外面不需要求解梯度,只有参数更新的时候求参数
for param in params:
param -= n*param.grad#进行梯度下降
param.grad.zero_()#重新将梯度设置为0,这样就不会受到上一次影响
n = 0.01#学习率
num_epochs = 3#训练次数
net = reg
loss = loss_fun
X = features
y = target
for epoch in range(num_epochs):
l = loss(reg(X,w,b),y)#计算损失函数
l.sum().backward()#反向传播求梯度
gd([w,b],n)#更新参数
with torch.no_grad():
train = loss(net(features,w,b),target)
print(f'epoch{epoch+1},loss:{float(train.mean()):f}')
epoch1,loss:0.001797
epoch2,loss:0.001763
epoch3,loss:0.001729
由于本例中是模拟数据集,我们知道真实的参数,因此可以计算出参数估计的误差
print(f'w的误差:{true_w-w.reshape(true_w.shape)}')
print(f'b的误差:{true_b-b}')
w的误差:tensor([-0.8461, 0.8311], grad_fn=)
b的误差:tensor([1.4857], grad_fn=)
大家可以尝试使用其他的学习率,来看一下结果的差异性,一般较常用的是0.01
0.03
0.1
0.3
1
本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!