李沐_线性回归的从零开始实现_代码

 线性回归的从零开始实现

import random
import torch
from d2l import torch as d2l

"""生成数据集"""
def synthetic_data(w,b,num_examples):
    X=torch.normal(0,1,(num_examples,len(w)))
    #x是n*2的矩阵
    y=torch.matmul(X,w)+b
    #y是n*2的形状,因为 X(n*2)*w(1*2)=n*2
    y+=torch.normal(0,0.01,y.shape)
    return X,y.reshape(-1,1)
    #把y变形成列向量
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=synthetic_data(true_w,true_b,1000)
#synthetic_data函数返回X(n*2),y为列向量

print('features:',features[0],'\nlabels:',labels[0])

d2l.set_figsize()
d2l.plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1)
#1为点的直径大小

"""读取数据集"""
def data_iter(batch_size,features,labels):
    num_examples=len(features)
    #features为二维矩阵len拿到的是第0维n
    indices=list(range(num_examples))
    #样本随机读取
    random.shuffle(indices)
    for i in range(0,num_examples,batch_size):
        batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)])
        #用min函数防止取数据超过边界
        yield features[batch_indices],labels[batch_indices]
        #yield类似于return,在函数中返回值给调用者
        #使用了yield的函数是有状态的函数,后面的调用会基于前面的调用状态继续执行
        
batch_size=10
for X,y in data_iter(batch_size,features,labels):
    print(X,'\n',y)
    break

"""初始化模型参数"""
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)

"""定义模型"""
def linreg(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_()
            
"""训练"""
lr=0.03
num_epochs=3
net=linreg
loss=squared_loss

for epoch in range(num_epochs):
    for X,y in data_iter(batch_size,features,labels):
        l=loss(net(X,w,b),y) #x和y的小批量损失
        #计算关于[w,b]的梯度
        l.sum().backward()
        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}')#:f表示控制精度,表示小数部分输出的位数
        
print(f'w的估计误差:{true_w-w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b-b}')

结果展示:

线性回归的简洁实现

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l


"""生成数据集"""
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=d2l.synthetic_data(true_w,true_b,1000)
#synthetic_data函数为实现的功能为根据相关参数,生成随机数据集,函数输入参数为真实
#的w,b以及所需要的样本数,通过该函数以及定义的w,b,可以按照y=2∗x1+(−3.4)∗x2+4.2
#生成相关数据,样本总数为1000。X按照离散正态分布生成,它的每一行为一个样本,每一列为一个
#特征值。y根据X的值进行生成,为使数据集贴近真实情况,对其利用离散正态分布加上小扰动。


"""读取数据集"""
def load_array(data_arrays,batch_size,is_train=True):
    """构造一个pytorch数据迭代器"""
    dataset=data.TensorDataset(*data_arrays)
    #pytorch中TensorDateset是处理数据的工具包,其作用是将数据进行打包,例如训练数据X
    #和数据对应的Label,将两者打包为一一对应的关系,即X中的一个数据对应Label中的一个值
    #(X的一行数据对应Label中的一行数据)。在输入参数前添加星号 * 可以对参数执行提取
    #操作,比如对列表、元组、字符串等迭代类型的输入参数做提取之后,迭代类型的数据元素
    #会被逐个取出。在dataset中,每一个对象元组由一张图片对象img和一个标签target组成
    return data.DataLoader(dataset,batch_size,shuffle=is_train)
    #DataLoader是一个可迭代的数据装载器,组合了数据集和采样器,并在给定数据集上提供
    #可迭代对象。可以完成对数据集中多个对象的集成。dataloader分别对一个批次中的图片
    #和标签进行打包,因此dataloader中,每一个对象由元组由batchsize张图片对象imgs和
    #batchsize个标签targets组成。

batch_size=10
data_iter=load_array((features,labels),batch_size)

#假设我们已经有features和labels了,我们把他做成一个List传到tensor的dataset里面
#,把我们的X和y传进去,得到pytorch的一个dataset,(也就是说dataset里面是由两部分
#组成,features和labels)dataset里面拿到数据集之后我们可以调用dataloader函数
#每次从里面随机挑选batch_size个样本出来,shuffle是指是否需要随机去打乱顺序,如果
#是train则是需要的构造了一个data_iter(可迭代对象)之后,然后用iter()转成python的
#一个迭代器,再通过next()函数得到一个X和y

# DataLoader:构建可迭代的数据装载器
# enumerate:返回值有两个,一个是序号,一个是数据(包含训练数据和标签)

next(iter(data_iter))
#在Python 中,iter 函数是一个内置函数,用于创建一个迭代器对象。迭代器是种特殊的对象,
#可以通过调用 next()函数来逐个访问其中的元素。iter 函数接受一个可迭代对象作为参数,
#并返回一个迭代器对象。


"""定义模型"""
# nn是神经网络的缩写,里面有大量定义好的层
from torch import nn

net=nn.Sequential(nn.Linear(2,1))


#线性回归用的是nn里面的线性层(或者说是全连接层),它唯一要指定的是输入和输出的维度
#是多少,此处的输入维度是2,输出维度是1,线性回归就是简单的单层神经网络,为了以后的
#方便,放进一个Sequential的容器里面,可以理解为一个list of layers把层按顺序一个一个
#放在一起

#Sequential是一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图
#中执行,同时以神经网络模块为元素的有序字典也可以作为传入参数,Sequential 是一个容器,
#里面可以放置任何层,不一定是线性层"""

"""初始化模型参数"""
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)

#上面定义的net就是只有一个layer,可以通过索引[0]访问到layer,然后用.weight访问到他的w,
#用.data访问真实data,normal_表示使用正态分布来替换到data的值,使用的是均值为0方差为
#0.01来替换偏差直接设置为0

"""定义损失函数"""
loss=nn.MSELoss()

"""定义优化算法"""
trainer=torch.optim.SGD(net.parameters(),lr=0.03)
#parameters用于管理神经网络中的参数。在深度学习中,参数是指用于调整模型的权重和偏置项的变量。
#这些参数在训练过程中会自动更新,以使模型能够适应输入数据。在PyTorch中,一个神经网络
#模型是由多个层组成的,每个层都包含一些参数。这些参数可以通过在模型中定义nn.Parameter
#对象来创建。当我们将模型传递给优化器时,它会自动识别并更新这些参数。在PyTorch中,
#net.parameter是模型中所有可学习参数的一个迭代器。通过遍历这个迭代器,我们可以访问
#和操作每个参数的值。

#optim.SGD()是pytorch中的随机梯度下降优化器,它可以调整神经网络中的参数以最小化损失函数。
#它是一种梯度下降优化算法,通过迭代每个参数,以最小化损失函数。它的基本思想是,在每
#次迭代中,每个参数都会沿着梯度的反方向移动一小步,以期望最小化损失函数。

# SGD至少传入两个参数。net.parameters里面就包括了所有的参数,w和b;指定学习率0.03

"""训练"""
num_epochs=3
for epoch in range(num_epochs):
    for X,y in data_iter: # 在data_iter里面一次一次的把minibatch(小批量)拿出来放进net里面
        l=loss(net(X),y)  
        #net(X)是预测值,y是真实值,拿到预测值和真实值做Loss
        trainer.zero_grad()   
        l.backward() 
        # 计算反向传播,这里pytorch已经做了sum就不需要在做sum了(loss是一个张量,
        #求sum之后是标量)
        trainer.step()   
        #有了梯度之后调用step()函数来进行一次模型的更新。调用step函数,从而分别更
        #新权重和偏差
    l=loss(net(features),labels)  
    #当扫完一遍数据之后,把所有的feature放进network中,和所有的Label作一次Loss
    print(f'epoch {epoch+1},loss{l:f}')    # {l:f} 是指打印l,格式是浮点型

结果展示:

参考:

pytorch初学笔记(六):DataLoader的使用 - 电脑学习网

Python 中星号(*)的用法_python的*-CSDN博客

李沐动手学深度学习:08 线性回归(代码逐行理解)_李沐线性回归-CSDN博客动手学深度学习3.2线性回归的从零开始实现-笔记&练习(PyTorch) - 知乎

动手学深度学习3.3线性回归的从零开始实现-笔记&练习(PyTorch) - 知乎

动手学深度学习pytorch版练习解答——3-2线性回归的从零开始实现-CSDN博客

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值