2. 线性回归
将线性回归作为深度学习第一个入门的模型,让我们一起来实现吧!
因为要用到画图,数据制图,所以需要安装matplotlip,使用pip或者anaconda安装都可以。
pip install matplotlib
我们可以利用**scatter( )**方法制作散点图,但是需要注意,使用matplotlib制图时,**传入的Tensor数据格式必须转换成Numpy格式的数据。**示例如下:
import torch
import matplotlib.pyplot as plt
#数据
x=torch.Tensor([1.4,5,11,16,21])
y=torch.Tensor([14.4,29.6,62,85.5,113.4])
#将x,y转化为numpy数据类型,绘制散点图
plt.scatter(x.numpy(),y.numpy())
plt.show()
运行结果如下:可以看到这五个点符合线性规律,也就是能用一条直线去拟合这五个点。
理论部分不做讲解,可以查看线性回归传送门
2.1 简单数据线性回归
结合理论知识,利用pytorch来进行编程。
首先对输入变量和各参数进行初始化。构建Produce_X( )函数主要是生成矩阵X,X是由x和x0合并的,而rand函数随机初始化参数向量w,而且需要对其进行梯度下降法更新,所以设置requires_grad=True。
import torch
import matplotlib.pyplot as plt
#准备数据
#生成矩阵X
def Produce_X(x):
x0 = torch.ones(x.numpy().size) #用ones产生初始值为1,大小与x相同的向量
X = torch.stack((x,x0),dim=1) #stack函数将两个向量拼合
return X
x = torch.Tensor([1.4,5,11,16,21])
y = torch.Tensor([14.4,29.6,62,85.5,113.4])
X = Produce_X(x)
#定义权重w的变量
w = torch.rand(2,requires_grad=True)
接下来进行训练过程。定义一个train函数,用来不断地调整w的值,epochs代表轮数,表示遍历所有数据的次数,learning_rate代表学习率。output = inputs.mv(w)表示先进行前向传播,然后根据loss = (output - target).pow(2).sum()求出损失函数,然后进行反向传播loss.backward() 自动求出损失函数梯度,w.data -= learning_rate * w.grad 逐步对w进行更新。
但是更新完之后一定要清空w的grad值,使用**w.grad.zero_()**清空梯度值
inputs = X
target = y
def train(epochs=1,learning_rate=0.01):
for epoch in range(epochs):
#前向传播
output = inputs.mv(w) #公式:y=Xw
loss = (output - target).pow(2).sum()#公式:J = ∑(y-y')^2
#反向传播
loss.backward()
w.data -= learning_rate * w.grad #更新权重w,公式:w_(t+1)= w_(t) - 𝜼*▽J
w.grad.zero_() #清空grad的值
if epoch % 80 == 0:
draw(output,loss)
#plt.savefig('plot1.png', format='png')
return w,loss
为了能够观察到训练的变化,让程序80次打印输出一次图像,定义一个draw( )函数。
def draw(output,loss):
plt.cla()#清空图像画布
plt.scatter(x.numpy(), y.numpy())#绘制散点图样本点
plt.plot(x.numpy(), output.data.numpy(),'r-', lw=5)绘制出回归直线
plt.text(0.5, 0,'Loss=%s' % (loss.item()),fontdict={'size':20,'color':'red'})#打印出loss值
plt.pause(0.005)
设轮数为10000,学习率为1e-4,返回最终打印的损失值和权重
w,loss = train(10000,learning_rate = 1e-4) #学习率设置为1x10^(-4)
print("final loss:",loss.item())
print("weights:",w.data)
输出:
final loss: 8.217347145080566
weights: tensor([5.0818, 5.6184])
2.2 大规模数据线性回归
上面的例子只有5个样本,样本数过少,在一般场景肯定不适用,现在尝试输入10万个数据样本,再次进行线性回归,完整代码放下面:
import torch
import matplotlib.pyplot as plt
from time import perf_counter
#准备数据
#生成矩阵X
def Produce_X(x):
x0 = torch.ones(x.numpy().size) #用ones产生初始值为1,大小与x相同的向量
X = torch.stack((x,x0),dim=1) #stack函数将两个向量拼合
return X
x = torch.linspace(-3,3,100000)#用linspace产生(-3,3)区间内的100000个点
X = Produce_X(x)
y = x +1.2*torch.rand(x.size())#假设真实函数是y=x,我们在上面增加一些误差,更加符合实际情况
w = torch.rand(2) #定义权重w的变量
#如果支持CUDA,则采用CUDA加速
CUDA = torch.cuda.is_available()
if CUDA:
inputs = X.cuda()
target = y.cuda()
w = w.cuda()
w.requires_grad=True
else:
inputs = X
target = y
w = w
w.requires_grad=True
def draw(output,loss):
#print loss
if CUDA:
output= output.cpu()
plt.cla()
plt.scatter(x.numpy(), y.numpy())
plt.plot(x.numpy(), output.data.numpy(),'r-', lw=5)
plt.text(5,5,'Loss=%s' % (loss.item()),fontdict={'size':20,'color':'red'})
plt.pause(0.005)
def train(epochs=1,learning_rate=0.01):
for epoch in range(epochs):
#前向传播
output = inputs.mv(w) #公式:y=Xw
loss = (output - target).pow(2).sum()/100000 #公式:J = (∑(y-y')^2)/100000
#反向传播
loss.backward()
w.data -= learning_rate * w.grad #更新权重w,公式:w_(t+1)= w_(t) - 𝜼*▽J
w.grad.zero_() #清空grad的值
if epoch % 80 == 0:
draw(output,loss)
plt.show()
return w,loss
start = perf_counter()
w,loss = train(10000,learning_rate=1e-4) #学习率设置为1x10^(-4)
finish = perf_counter()
time = finish-start
print("计算时间:%s" % time)
print("final loss:",loss.item())
print("weights:",w.data)
计算时间:58.723048899999995
final loss: 0.12094969302415848
weights: tensor([0.9979, 0.5756], device='cuda:0')
2.3 神经网络的方法
实际上,pytorch中已经预先定义好了我们要用到的损失函数及优化函数,直接上代码,细节在代码注释:
import torch
import matplotlib.pyplot as plt
from torch import nn,optim
from time import perf_counter
#用linspace产生(-3,3)区间内的100000个点,并使用unsqueeze函数增加一个维度
x = torch.unsqueeze(torch.linspace(-3,3,100000),dim=1)
#假设真实函数是y=x,我们在上面增加一些误差,更加符合实际情况
y = x +1.2*torch.rand(x.size())
#定义一个回归的类LR,继承pytorch中nn(Neural Network)模块中的Module
class LR(nn.Module):
def __init__(self):
super(LR,self).__init__()
self.linear = nn.Linear(1,1) # 两个参数分别代表输入输出的维度
def forward(self,x): # 定义前向传播,反向传播好像本来就有不用再定义
out = self.linear(x)
return out
#如果支持CUDA,则采用CUDA加速
CUDA = torch.cuda.is_available()
if CUDA:
LR_model = LR().cuda()
inputs = x.cuda()
target = y.cuda()
else:
LR_model = LR()
inputs = x
target = y
criterion = nn.MSELoss() # nn模块预设有均方误差函数
optimizer = optim.SGD(LR_model.parameters(),lr=1e-4) # 以及随机梯度下降函数SGD,
# 第一个是需要优化的神经网络的参数,第二个是学习率
def draw(output,loss):
if CUDA:
output = output.cpu()
plt.cla()
plt.scatter(x.numpy(), y.numpy())
plt.plot(x.numpy(), output.data.numpy(),'r-', lw=5)
plt.text(0.5,0,'Loss=%s' % (loss.item()),fontdict={'size':20,'color':'red'})
plt.pause(0.005)
# 训练函数,参数依次是被训练的神经网络模型、损失函数、优化器、训练轮数
def train(model,criterion,optimizer,epochs):
for epoch in range(epochs):
#forward
output = model(inputs) # 将input传入神经网络模型,得到output
loss = criterion(output,target) # 用损失函数计算损失值
#backward
optimizer.zero_grad() # 清空权重梯度值
loss.backward() # 计算梯度
optimizer.step() # 权值更新
if epoch % 80 == 0:
draw(output,loss)
plt.show()
return model,loss
start = perf_counter()
LR_model,loss = train(LR_model,criterion,optimizer,10000)
finish = perf_counter()
time = finish-start
print("计算时间:%s" % time)
print("final loss:",loss.item())
print("weights:",list(LR_model.parameters()))
这就大功告成了,线性回归基本就这些,要仿照程序结构去写,神经网络的程序个人认为就是这种模块化的,因为他预设了很多库函数,简直不要方便太多!