Pytorch 3.3 后续 线性回归的简单实现(基于Pytorch框架实现)
线性回归的简单实现(基于Pytorch框架实现)
先来简单复习下线性回归的步骤吧
step.1导入库函数
%matplotlib inline
import random #用于随机化生成的数据
import torch #框架
from d2l import torch as d2l #我们引入的包
step2.随机生成数据并且测试
def synthetic_data(w ,b ,num_examples):
'y = wX+ b+ 噪音项'
X = torch.normal(mean=0,std=1,size=(num_examples,len(w))) # 生成一个(样本数,特征数)
y = torch.matmul(X,w) +b
y+=torch.normal(mean=0,std=0.01,size=(y.shape))
return X,y.reshape((-1,1))
true_w = torch.tensor([1,3.8])
true_b = 4.2
features,labels = synthetic_data(w = true_w,b=true_b,num_examples=1000)
# 我们将数据可视化,以查看数据是否生成正确
d2l.set_figsize((4,4 ))
d2l.plt.scatter(x=features[:, 1].numpy(),y=labels.numpy(),s=1,c='r') # s → 散点的面积
我们就绘制w[1]=3.8时候的数据 ,这时候我们的x的数据就为features[:,1] , matplotlib只支持numpy的数组
数据分析 x=0的时候 b≈4 (-2,-5)(0,4) 斜率约等于4.2 ≈ 3.8 数据生成正确
step3.读取数据
#读取数据 调用框架中现有的API来读取数据
def data_iter(batch_size , features , labels):
num_examples = len(features) # len(features) -》1000 返回的是 行的数量
indexes = list(range(num_examples))
#shuffle my Data
random.shuffle(indexes)
for i in range(0, num_examples, batch_size):
batch_indexes = torch.tensor(
indexes[i: min(i + batch_size, num_examples)])
yield features[batch_indexes],labels[batch_indexes]
next(data_iter(10,features,labels)) # 只取第一次的数据 表明我的data迭代器没有任何问题,接下来就可以设置一个梯度下降了
step4.定义模型和算法
#定义模型
def linerRegression(X,w,b):
'''定义线性回归'''
return torch.matmul(X,w)+b
def squared_loss(y_hat,y):
'''均方误差'''
return (y_hat-y.reshape(y_hat.shape))**2/2
def sgd(params,lr,batch_size):
'''小批量梯度下降'''
with torch.no_grad():
for param in params:
param -= lr*param.grad / batch_size
param.grad.zero_()
step5.算法实现
#初始化模型参数
w = torch.normal(mean=0,std=1,size=(2,1),requires_grad=True)
b = torch.tensor(4.2,requires_grad=True)
lr = 0.03
num_epochs = 3
batch_size = 10
net = linerRegression
loss = squared_loss
for epoch in range(num_epochs):
for X,y in data_iter(batch_size=batch_size,features=features,labels=labels):
l = loss(y_hat=net(X=X,w=w,b=b),y=y) # 一个样本的均方误差
l.sum().backward() # loss function
sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
Output:
epoch 1, loss 0.012969
epoch 2, loss 0.000071
epoch 3, loss 0.000047
接下来就是超级简单的实现了,基于上面代码的原理,只不过换另外一种方式表达罢了。
step1.导入库函数
# 简单实现
import torch
import numpy as np
from torch.utils import data
from d2l import torch as d2l
step2.生成数据和简便测试(同上面步骤)
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
# 用两个问号查询函数相关信息 发现这个函数是来自我们本地的函数
这里不知道你们有没有注意到,我没有写上synthetic_data这个生成数据的函数,但是我运行的时候却没有报错,这个是为何呢?我们在jupyter notebook输入:synthetic_data??
中一探究竟,最后竟然发现这个函数来自于我们之前编译过的文件,但是d2l这个库函数的具体功能我暂时不得而知,先学着先,到时候在窥视他的真容!!
step3.读取数据并且分割成批量大小返回
def load_array(data_arrays,batch_size,is_train=True):
'''构造一个Python的迭代器类似于我们之前的data_iter+'''
dataset = data.TensorDataset(*data_arrays) # (1)创建数据集,或者说封装数据集,可以传入多个参数
return data.DataLoader(dataset=dataset,batch_size=batch_size,shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size) # 传入(features,labels)
# next(iter(data_iter))
step4.定义模型
import torch.nn
net = torch.nn.Sequential(torch.nn.Linear(2, 1))# Sequential 连续的
# 在PyTorch中,全连接层在Linear类中定义。值得注意的是,我们将两个参数传递到nn.Linear中。
#第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1。
#定义损失函数
loss = torch.nn.MSELoss()# 均方误差是MSE
#定义优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
step5.算法实现
num_epochs = 3 # 迭代的次数
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y) # 我们之前定义的在optim模块中的MSEloss()算法
trainer.zero_grad() # 每次调用SGD之后都要清空 ,因为我们进行的是小批量梯度下降
l.backward() # 在前面我们进行了前向传播,现在进行反向传播更新我们的参数
trainer.step()
l = loss(net(features), labels) # 完成一次迭代之后查看我们的损失函数的值
print(f'epoch {epoch + 1}, loss {l:f}')
输出:
epoch 1, loss 0.000299
epoch 2, loss 0.000106
epoch 3, loss 0.000106
杂碎的知识点(如果你愿意继续看下去的话)
torch.utils.data主要包括以下三个类:
class torch.utils.data.Dataset
作用:(1)创建数据集,有__getitem__(self, index)函数来根据索引序号获取图片和标签,有__len__(self)函数来获取数据集的长度class torch.utils.data.sampler.Sampler(data_source)
参数: data_source (Dataset) – dataset to sample from
作用: 创建一个采样器, class torch.utils.data.sampler.Sampler是所有的Sampler的基类, 其中,iter(self)函数来获取一个迭代器,
对数据集中元素的索引进行迭代,len(self)方法返回迭代器中包含元素的长度.class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, num_workers=0, collate_fn=, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None)
* dataset (Dataset): 加载数据的数据集
* batch_size (int, optional): 每批加载多少个样本
* shuffle (bool, optional): 设置为“真”时,在每个epoch对数据打乱.(默认:False)
* sampler (Sampler, optional): 定义从数据集中提取样本的策略,返回一个样本
* batch_sampler (Sampler, optional): like sampler, but returns a batch of indices at a time 返回一批样本. 与atch_size, shuffle, sampler和 drop_last互斥.
* num_workers (int, optional): 用于加载数据的子进程数。0表示数据将在主进程中加载。(默认:0)
* collate_fn (callable, optional): 合并样本列表以形成一个 mini-batch. # callable可调用对象
* pin_memory (bool, optional): 如果为 True, 数据加载器会将张量复制到 CUDA 固定内存中,然后再返回它们.
* drop_last (bool, optional): 设定为 True 如果数据集大小不能被批量大小整除的时候, 将丢掉最后一个不完整的batch,(默认:False).
* timeout (numeric, optional): 如果为正值,则为从工作人员收集批次的超时值。应始终是非负的。(默认:0)
* worker_init_fn (callable, optional): If not None, this will be called on each worker subprocess with the worker id (an int in ``[0, num_workers - 1]``) as input, after seeding and before data loading. (default: None).
import torch,torch.utils.data as data
a = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = torch.tensor([44, 55, 66, 44, 55, 66, 44, 55, 66, 44, 55, 66])
# TensorDataset对tensor进行打包 将样本和labels对应起来
train_ids = data.TensorDataset(a, b)
# for x_train, y_label in train_ids:
# print(x_train, y_label)
# dataloader进行数据封装
train_loader = data.DataLoader(dataset=train_ids, batch_size=4, shuffle=True)
for i, data in enumerate(train_loader,1):
# 注意enumerate返回值有两个,一个是序号,一个是数据(包含训练数据和标签)
x_data, label = data
print(' batch:{0} x_data:{1} label: {2}'.format(i, x_data, label))
这样就可以少写很多函数了
输出:
batch:1 x_data:tensor([[7, 8, 9],
[4, 5, 6],
[1, 2, 3],
[1, 2, 3]]) label: tensor([66, 55, 44, 44])
batch:2 x_data:tensor([[7, 8, 9],
[4, 5, 6],
[4, 5, 6],
[7, 8, 9]]) label: tensor([66, 55, 55, 66])
batch:3 x_data:tensor([[7, 8, 9],
[4, 5, 6],
[1, 2, 3],
[1, 2, 3]]) label: tensor([66, 55, 44, 44])
posted on 2021-12-21 00:48 YangShusen' 阅读(617) 评论(0) 编辑 收藏 举报