返回顶部

请叫我杨先生

导航

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主要包括以下三个类:

  1. class torch.utils.data.Dataset
    作用:(1)创建数据集,有__getitem__(self, index)函数来根据索引序号获取图片和标签,有__len__(self)函数来获取数据集的长度
  2. 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)方法返回迭代器中包含元素的长度.
  3. 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编辑  收藏  举报