#创建数据集
import torch
import matplotlib.pyplot as plt
def create(w,b,sample):
x=torch.normal(0,1,size=(sample,len(w))) #以方差为0,标准差为1的分布,随机生成行为sample,列为len(w)的矩阵
y=x[:,0]*w[0]+x[:,1]*w[1]+b #生成y
y+=torch.normal(0,0.01,y.shape) # 加噪声
return x,y.reshape(-1,1) #(-1,1)代表生成1列,前面的行数-1会根据列数1自动算出来
t_w=torch.tensor([2,-3.4])
t_b=1
features,labels=create(t_w,t_b,100)
features[:,1].shape,labels.shape
#(torch.Size([100]), torch.Size([100, 1]))
看一下生成的数据集
plt.plot(features[:,1],labels[:,0],'r+')#(x,y,表示形状)
plt.show()
以上根据t_w, t_b生成的类线性数据集,现在我们来拟合一条直线
w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)
#tensor([[-0.0088],[ 0.0072]], requires_grad=True),
# tensor([0.], requires_grad=True)
随机生成的线性回归模型是y=w.T *x+b,
def linear(x,w,b):
return torch.matmul(x,w)+b
但是w的较小,近乎是一条横线,可以看一下
plt.plot(features[:,1],labels[:,0],'r+')
xfit=torch.linspace(-5,5,2)
yfit=w[1].detach()*xfit+b.detach()
plt.plot(xfit,yfit,'k-')
plt.show()
模型出来之后,现在对模型里的损失进行优化,以均方损失为例
下面是损失函数
def loss(y_hat,y):
return (y_hat-y)**2/2/len(y)#均方损失,整体数据的经验风险
进行优化w,b
def sgd(params,lr):
with torch.no_grad():#现在不需要BP,所以得把梯度固定住
for param in params:
param -= lr*param.grad()#lr是每次前进的步长(学习率)
param.grad.zero_()#不把梯度清零的话,前后梯度会累加
现在已经定义完成,我们开始遍历这100个样本
lr=0.5
for eporch in range(5):
x,y=features,labels
y_hat=linear(x,w,b)#构建模型
l=loss(y_hat,y)#经验风险
l.sum().backward()#l=loss是张量,必须转化为标量才可以求梯度
sgd([w,b],lr)#梯度下降
with torch.no_grad():
print('eporch:{}, loss={}'.format(eporch+1,loss(y_hat,y).sum()))
根据此时的[w,b]此时我们再看一下图像
再增加五次遍历损失结果如下
此时图像如下
在样本集过多的情况下 不必对整个数据集进行优化,因为梯度下降比较贵,可以采用小批量随机梯度下降法
整体代码如下
import torch
import matplotlib.pyplot as plt
import numpy as np
import random
def create(w,b,sample):
x=torch.normal(0,1,size=(sample,len(w)))
y=x[:,0]*w[0]+x[:,1]*w[1]+b
y+=torch.normal(0,0.01,y.shape)
return x,y.reshape(-1,1)
t_w=torch.tensor([2,-3.4])
t_b=1
features,labels=create(t_w,t_b,100)
features[:,1].shape,labels.shape
plt.plot(features[:,1],labels[:,0],'r+')
plt.show()
w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)
#w,b
plt.plot(features[:,1],labels[:,0],'r+')
xfit=torch.linspace(-5,5,2)
yfit=w[1].detach()*xfit+b.detach()
plt.plot(xfit,yfit,'k-')
plt.show()
def linear(x,w,b):
return torch.matmul(x,w)+b
def get_batch_size(features,labels,batch_size):
num=len(labels)
indice=list(range(num))
random.shuffle(indice)
for i in range(0,num,batch_size):
batch=torch.tensor(indice[i:min(i+batch_size,num)])
yield features[batch],labels[batch]
def loss(y_hat,y,batch_size):
return (y_hat-y)**2/2/batch_size
def sgd(params,lr):
with torch.no_grad():
for param in params:
param.data -= lr*param.grad
param.grad.zero_()
lr=0.5
batch_size=10
for eporch in range(5):
for x,y in get_batch_size(features,labels,batch_size):
y_hat=linear(x,w,b)
l=loss(y_hat,y,batch_size)
l.sum().backward()
sgd([w,b],lr)
with torch.no_grad():
print('eporch:{}, loss={}'.format(eporch+1,loss(y_hat,y,batch_size).sum()))
建议大家在jupyter运行,可以方便看到曲线的变化