python实现线性回归(人工数据集)
首先线性回归要有一个数据集,我们采用随机噪声的方式来实现:
w是参数张量,b是偏移张量,data_size是数据集大小
def generate_data(w,b,data_size):
x = torch.normal(0,1,(data_size,len(w)))
y = torch.matmul(x,w)+b
y += torch.normal(0,0.1,y.shape)
return x,y
这个函数的torch.normal是利用正态分布的方式来生成x,该正态分布的均值是0,方差是1,生成的x的维度是data_size行,每一行有len(w)个数据,w是参数张量,len(w)表示和参数的数量
torch.matmul表示矩阵乘法,是每一行的x和w相乘,这里不会报错的原因是torch在处理一维张量时会把他解读为列向量,得到的结果就是y张量,y张量的每一个数据都是x和w的点积+b,在加上正态分布的随机噪声,我们就得到了人工数据集
定义回归模型:
x是输入张量,w是参数张量
def linreg(x,w,b):
return torch.matmul(x,w)+b
返回值为x和w的点积+b。
然后我们来确定损失函数,在这个回归模型中我们采用均方损失:
y_hat是预测值,y是真实值
def loss(y_hat,y):
return (y_hat - y.reshape(y_hat.shape))2/2
利用当前模型的预测值和真实值做差再平方(/2是为了求导好看),得到一个损失值,这个损失值是一个向量,向量的shape是y的shape。
批量随机获取数据集:
x和y是数据集
def data_iter(batch_size,x,y):
num_examples = len(x)
index = list(range(num_examples))
random.shuffle(index)
for i in range(0,num_examples,batch_size):
j = torch.tensor(index[i:min(i+batch_size,num_examples)])
yield x[j],y[j]
这个函数可以一次性获取个数为batch_size数量的数据,利用random.shuffle来将索引打乱,然后创建一个tensor来保存index中的连续10个值,通过python的列表操作来返回x的10个数据,和每一个x对应的y的数据,yield是单次返回,每次用yield返回后,该函数会暂停,当调用next()这个函数将继续执行,本质是一个生成器,相比较return来说,优点是节省内存,每次返回一定数据,不需要存储全部的数据,可以批量多次处理。
学习函数:
parmenters是参数张量,batch_size是批量数据大小,lr是学习率(超参数)
def learning(parmeters,batch_size,lr):
with torch.no_grad():
for parmeter in parmeters:
parmeter -= lrparmeter.grad
parmeter.grad.zero_()
这个函数通过torch的自动求导来计算梯度,对每一个参数进行梯度下降,下降大小为损失函数学习率,以此来达到降低损失函数值的目的,每次计算完梯度需要调用grad.zero_()手动清除梯度,因为torch的梯度是可以积累的。
全部代码:
import torch
import random
import time
def generate_data(w,b,data_size):
x = torch.normal(0,1,(data_size,len(w)))
y = torch.matmul(x,w)+b
y += torch.normal(0,0.1,y.shape)
return x,y
def data_iter(batch_size,x,y):
num_examples = len(x)
index = list(range(num_examples))
random.shuffle(index)
for i in range(0,num_examples,batch_size):
j = torch.tensor(index[i:min(i+batch_size,num_examples)])
yield x[j],y[j]
def linreg(x,w,b):
return torch.matmul(x,w)+b
def loss(y_hat,y):
return (y_hat - y.reshape(y_hat.shape))2/2
def learning(parmeters,batch_size,lr):
with torch.no_grad():
for parmeter in parmeters:
parmeter -= lr*parmeter.grad
parmeter.grad.zero_()
if name == "main":
true_w = torch.tensor([3123.1543,-1245.2344141,13.42343252,645.12424534,-432.42352,25346546,-24234])
true_b = torch.tensor([123.23432])
batch_size = 10
data_size = 10000
epochs = 3
lr = 0.01
w = torch.randn(len(true_w), requires_grad=True)
b = torch.randn(len(true_b), requires_grad=True)
generated_x,generated_y = generate_data(true_w,true_b,data_size)
for epoch in range(epochs):
for x,y in data_iter(batch_size,generated_x,generated_y):
y_hat = linreg(x,w,b)
l = loss(y_hat,y)
l.sum().backward()
learning([w,b],batch_size,lr)
print([w,b],l.sum())
这是全部的训练代码,结果如下:
[tensor([ 3.1231e+03, -1.2456e+03, 1.3075e+01, 6.4524e+02, -4.3244e+02,
2.5347e+07, -2.4234e+04], requires_grad=True), tensor([123.2118], requires_grad=True)] tensor(17.1426, grad_fn=
与真实值的差距:
torch.tensor([3123.1543,-1245.2344141,13.42343252,645.12424534,-432.42352,25346546,-24234]
tensor([ 3123.1, -1245.6, 13.075, 645.24, -432.44,25347000, -24234]
最终的损失函数值为17.1426,每一个参数经过训练后,与真实值差距很小。

浙公网安备 33010602011771号