• 李沐深度学习记录1:零碎知识记录、08线性回归


    简要记录,以便查阅~

    一、零碎知识

    x.numel():看向量或矩阵里元素个数
    A.sum():向量或矩阵求和,axis参数可对某维度求和,keepdims参数设置是否保持维度不变
    A.cumsum:axis参数设置沿某一维度计算矩阵累计和
    
    x*y:向量的按元素乘法
    torch.dot(x,y):向量的点乘(点积or内积),结果是标量。公式,向量a点积向量b=|a||b|cos两向量夹角。向量点积即x的转置与向量y相乘,即对应元素相乘相加得数值
    torch.sum(x*y):计算向量点积的另一方式,执行向量的按元素乘法得向量,再对向量求和。
    
    torch.mv(A,X):矩阵向量积,矩阵乘以向量
    
    A*B:矩阵的按元素乘法,称为Hadamard积。
    torch.mm(A,B):矩阵乘法。但是注意,高维矩阵(二维以上)不可以使用mm(),应当使用matmul().
    
    torch.abs(x).sum():计算向量的L1范数,即先计算各项绝对值,再求和。
    torch.norm(x):计算向量的L2范数。L2范数是向量元素平方和的平方根
    torch.norm(A):类似于向量的L2范数,矩阵A的Frobenius范数是矩阵元素平方和的平方根。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    二、线性回归从零开始实现

    %matplotlib inline
    import random
    import torch
    from d2l import torch as d2l
    
    #生成数据集
    #构建synthetic_data函数,给定w、b和数据样本个数num_examples,给出随机合成的数据集,返回数据样本X和数据标签y
    def synthetic_data(w,b,num_examples):#@save
        #生成y=Xw+b+噪声
        X=torch.normal(0,1,(num_examples,len(w)))#随机生成样本值服从均值为0标准差为1的正态分布。样本数据矩阵为(样本量,样本特征维度)
    #     print('X:',X,'\nX的形状:',X.shape)  #torch.Size([1000, 2])
        y=torch.matmul(X,w)+b #矩阵乘法。得到数据X在权重w和偏差值b下的对应y值
    #     print('y:',y,'\ny的形状:',y.shape)  #torch.Size([1000])
        y+=torch.normal(0,0.01,y.shape) #随机为y添加服从均值0标准差0.01的正态分布的噪声值,噪声值形状与y相同
    #     print('y:',y,'\ny的形状:',y.shape)  #torch.Size([1000])
    #     print('reshape后y的形状:',y.reshape((-1,1)).shape,'\ny:',y)  #reshape后y的形状: torch.Size([1000, 1]) 
        return X,y.reshape((-1,1))  #返回数据X和标签y
    
    true_w=torch.tensor([2,-3.4]) #权重w
    true_b=4.2
    features,labels=synthetic_data(true_w,true_b,1000)  #feature即返回的X数据,指的二维数据样本;labels即标签值
    print('features:',features[0],'\nlabel:',labels[0])
    print('features:',features[0:5],'\nlabel:',labels[0:5])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    #直观观察数据样本features和labels的线性关系
    d2l.set_figsize()
    d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1);#利用数据样本X的第1维特征和数据标签y作散点图。最后的1表示标记点的大小
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    #如果使用X的第0维特征
    d2l.set_figsize()
    d2l.plt.scatter(features[:,0].detach().numpy(),labels.detach().numpy(),1);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    #读取数据集   
    #定义data_iter函数,该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size的小批量。
    def data_iter(batch_size,features,labels):
        num_examples=len(features)
        indices=list(range(num_examples)) #将0-总样本数间的所有数字保存在一个list中
        random.shuffle(indices) #将list中的数值随机打乱,也即做到之后随机取数据
        for i in range(0,num_examples,batch_size):  #从0开始到最后样本总数,每次跳batch_size的大小来取i,即每批数据的第一个数据的下标值
            batch_indices=torch.tensor( indices[i:min(i+batch_size,num_examples)] ) #从数据i开始,连着取batchsize大小的数据。min(,)是防止最后数据不足batchsize时,将最后的数据取为一个batch即可
            yield features[batch_indices],labels[batch_indices]  #根据前面所得的indices来取对应的features和labels
            #yield是返回两部分features,labels
    
    batch_size=10
    for X,y in data_iter(batch_size,features,labels):
        print(X,'\n',y) 
        break  #只输出一次X,y便跳出了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    #初始化模型参数
    w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
    b=torch.zeros(1,requires_grad=True)
    
    #定义模型
    def linreg(X,w,b):  #@save
        #线性回归模型
        return torch.matmul(X,w)+b
    
    #定义损失函数
    def squared_loss(y_hat,y):#@save
        #均方损失
        return (y_hat-y.reshape(y_hat.shape))**2/2
        
    #定义优化算法
    def sgd(params,lr,batch_size):#@save  #params是一个list,里面包含w和b
        #小批量随机梯度下降
        with torch.no_grad():
            for param in params:
                param-= lr * param.grad / batch_size  #除以batch_size是因为上面计算损失时没有除以batchsize计算均值
                param.grad.zero_()  #每次更新完后,要将梯度置0,这样下次计算梯度时不会在上次计算的梯度上累加
    
    #训练
    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)  #计算y预测值和y之间的损失,返回l向量的形状是(batch_size,1)
            l.sum().backward() #将l中所有样本损失求和,再反向传播计算梯度
            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}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述

    print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
    print(f'b的估计误差: {true_b - b}')
    
    • 1
    • 2

    在这里插入图片描述

    三、线性回归的简洁实现

    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)
    
    #读取数据集
    def load_array(data_arrays,batch_size,is_train=True):
        #构造一个pytorch数据迭代器
        dataset=data.TensorDataset(*data_arrays) 
        #将数据数组转换为TensorDataset对象。data_arrays是包含数据的数据元组。*符号表示解压缩元组,使其成为函数参数
        return data.DataLoader(dataset,batch_size,shuffle=is_train) #每次随机从中挑选batchsize大小的数据,随机打乱
    
    batch_size=10
    data_iter=load_array((features,labels),batch_size) #这里的data_iter和之前手动创建的data_iter一样
    
    next(iter(data_iter))
    #iter()函数是将可迭代对象转换成迭代器。next()是python内置的函数,用于获取迭代器中的下一元素。
    
    
    #next(iter(data_iter))这一行代码等价于下面的代码
    #for X,y in data_iter:
    #    print(X,'\n',y) 
    #    break  #只输出一次X,y便跳出了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    #定义模型
    #nn是神经网络的缩写
    from torch import nn
    net=nn.Sequential(nn.Linear(2,1)) #制定输入输出维度,分别是2和1。Sequential可理解为存放layer的list
    
    #初始化参数
    #net[0]访问网络层layer,weight即访问它的权重w,data即权重的值,normal_表示用均值为0标准差为0.01的数替换掉data的值
    net[0].weight.data.normal_(0,0.01)
    net[0].bias.data.fill_(0)  #同理将偏差值设置为0
    
    #定义损失函数
    loss=nn.MSELoss()  #MSELoss()也称平方L2范数,返回所有样本损失的平均值
    
    #定义优化算法
    trainer=torch.optim.SGD(net.parameters(),lr=0.03) #需要指定优化的参数以及优化算法所需的超参数字典
    
    #训练
    num_epochs=3
    for epoch in range(num_epochs):
        for X,y in data_iter:
            l=loss(net(X),y) #调用net(X)前向计算预测值,将其与y真实值传入loss计算损失
            trainer.zero_grad()  #计算梯度前,现将优化器梯度清零
            l.backward()#反向传播计算梯度
            trainer.step()#进行模型更新
        l=loss(net(features),labels) #与之前一样,扫完一遍数据后计算一下loss
        print(f'epoch {epoch+1},loss {l:f}')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

  • 相关阅读:
    .NET 中使用 OpenTelemetry Traces 追踪应用程序
    volatile原理及happens-before规则
    【开源】基于JAVA的校园失物招领管理系统
    多端统一开发框架Taro、UniApp和WeApp这三个应用各自在前端开发领域有着独特的定位和功能
    IntelliJ 平台彻底停用 Log4j 组件
    阿里规范说MySQL单表行数不要超过2000w,为啥?
    react setState异步操作数据的问题
    app小程序手机端Python爬虫实战06UiSelector文本、className定位方式
    TSINGSEE智慧加油站可视化监管与风险预警方案
    k8s之ConfigMap和Secret
  • 原文地址:https://blog.csdn.net/qq_46238275/article/details/133144804