动手学PyTorch(李沐)1 ---- 线性回归(附实现代码)

线性回归

线性模型

此处箭头即权重

衡量预估质量

训练数据

参数学习

预测损失计算:每个实际y减去每个预测y(<x,w>-b)插值的平方求和除以2n算出预测损失。

利用最小化损失学习参数:找到最合适的向量w和b使得损失最小。

显示解

线性模型的损失是一个凸函数,通常有最优解,最优解需满足单数为0即可

​ 将变量向量X设为X = [ X ,1 ],参数向量W设为 W = [ W , b ],

线性回归总结


基础优化算法

​ η为学习率(步长,是一个超参,需要人为指定的值),乘以变化梯度,表示延梯度方向将增加的损失函数值,η表示沿梯度方向每次都多远。

梯度:就是沿函数值增加最大的方向,负梯度是下降最大的方向

不能太小:因为计算梯度是一件代价很大的操作,如果η太小,想要达到最好效果计算梯度的次数就会显著增加,付出极大的计算资源。

不能太大:如果η太大,可能会一步迈过最佳参数值,会使得一直震荡,不能得到很好的结果。

​ 用整个样本b的平均来近似整个数据的损失,样本b越大,近似越好。

总结


QA:

  1. 之所以使用平方损失而不用绝对差值,是因为绝对差值又是不可导。

  2. 损失要求平均,是损失太大,如果损失不除以n,那么求梯度的时候就要除以n

  3. 线性回归损失函数通常都是MSE

  4. batch_size越小对收敛越好,因为随机梯度下降实际是带来了噪音,采样样本越小,噪音越多,但是噪音对当前的神经网络是有益的。

  5. 理论上学习率和批量大小对收敛的影响不大

  6. 每个参数更新时减去的梯度是batch_size中每个样本对应参数梯度求和后的均值

  7. 随机梯度下降,采样是随机的,批量大小是一样的

  8. 真实的损失函数是一个很复杂的曲面

  9. detach()就是把数据从计算梯度的计算图中拿出来,不参与计算梯度

  10. SGD收敛的话,学习率η需要逐步衰减

  11. 每个batch计算的时候,需要把梯度清零,如果不清零的话,PyTorch会在之前的梯度上做累加


编写实现线性回归

%matplotlib inline
import torch
import random  #要随机梯度下降和初始化权重
from d2l import torch as d2l
import numpy

# 数据张量生成
def synthetic_data(w,b,num_examples):
    #生成y = wx + b 
    #生成x是均值为0方差为1的张量,(num_examples,len(w))指的是张量的形状
    x = torch.normal(0,1,(num_examples,len(w)))
    #设计y,matmul是矩阵乘法
    y = torch.matmul(x,w) + b
    #添加噪声
    y += torch.normal(0,0.01,y.shape)
    return x , y.reshape((-1,1))
 
#设计构造数据
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features,labels = synthetic_data(true_w,true_b,1000)
print("features:",features[0],'\nlabels:',labels[0])
#该函数接受 批量大小,特征矩阵和标签向量作为输入,生成大小为batch_size的小批量

def data_iter(batch_size,features,labels):
    # 特征样本数
    num_examples = len(features)
    #生成一个与样本数量同大小的顺序表
    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)])
        
        #yield会返回一个x,y      batch_indices是一个随机标号
        yield features[batch_indices],labels[batch_indices]
    '''带有yield的函数在Python中被称之为generator(生成器),也就是说,
        当你调用这个函数的时候,函数内部的代码并不立即执行 ,
        这个函数只是返回一个生成器(Generator Iterator)。'''
        
        
batch_size = 10

# data_iter是一个生成器,每次调用会在上一个状态的基础上再次调用
for x,y in data_iter(batch_size,features,labels):
    print(x,'\n',y)
#     break是因为只取了一个小批量
    break
# 定义初始化模型参数
w = torch.normal(0,0.01,size = (2,1),requires_grad = True)
b = torch.zeros(1,requires_grad = True)
#定义线性回归模型  linear regression
def linreg(X,w,b):
#     线性回归模型
    return torch.matmul(X,w)+b
#定义损失函数  y_hat 预测值, y 真实值
def squared_loss(y_hat,y):
    '''均方损失,统一 y 的形状'''
    return (y_hat - y.reshape(y_hat.shape))**2 / 2
#定义优化算法
'''params里面包含了w,b          lr为学习率'''
def  sgd(params,lr,batch_size):
    '''小批量梯度下降'''
    with torch.no_grad():
        for param in params:
#       之前求损失函数没有计算均值,所以这里除以batch_size,   w,b都需要计算梯度
            param -= lr*param.grad/batch_size
#       梯度手动置为0
            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)  #预测和实际的小批量损失
        #因为 l 的形状是(batch_size,1),是一个长为批量大小的向量,而不是一个标量。 
        #并以此计算关于 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}')

在这里插入图片描述

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

在这里插入图片描述

PyTorch实现线性回归

%matplotlib inline
import torch
import random  #要随机梯度下降和初始化权重
from d2l import torch as d2l
import numpy
from torch.utils import data
# 数据生成
def synthetic_data(w,b,num_examples):
    #生成y = wx + b 
    #生成x是均值为0方差为1的张量,(num_examples,len(w))指的是张量的形状
    x = torch.normal(0,1,(num_examples,len(w)))
    #设计y,matmul是矩阵乘法
    y = torch.matmul(x,w) + b
    #添加噪声
    y += torch.normal(0,0.01,y.shape)
    return x , y.reshape((-1,1))
#设计真实参数
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features,labels = synthetic_data(true_w,true_b,1000)
print("features:",features[0],'\nlabels:',labels[0])
# 调用框架的API读取数据 
def load_array(data_arrays,batch_size,is_train=True):
    """构造一个PyTorch数据迭代器"""
    
    """
    TensorDataset 可以用来对 tensor 进行打包,包装成dataset。
    就好像 python 中的 zip 功能。
    该类通过每一个 tensor 的第一个维度进行索引。
    TensorDataset 中的参数必须是 tensor。
    """
#     dataset = torch.utils.data.TensorDataset(*data_arrays)
    """ 
        * 表示解包操作,表示将一个包含多个元素的元组、列表、集合等数据结构
    解压为多个独立的元素。接受任意多个参数并将其放在一个元组中。
    """
    dataset = data.TensorDataset(*data_arrays)
    
#     return torch.utils.data.DataLoader(dataset,batch_size,shuffle=is_train)
    """
        使用DataLoader函数每次从dataset中随机挑选batch_size个样本,
    shuffle指是否随机打乱顺序
    """
    return data.DataLoader(dataset,batch_size,shuffle=is_train)


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

#把函数调用转成一个迭代器
next(iter(data_iter))
# 使用框架预定义好的层
from torch import nn

# Sequential 可以理解为将一个一个的层按顺序放在一起,初始化模型
net = nn.Sequential(nn.Linear(2,1))
"""
net通过第1层访问线性模型,weight访问w,
data就是真是的数据,narmal指的是用正态分布替代data的值
"""
net[0].weight.data.normal_(0,0.01)

"""bias值得是偏差"""
net[0].bias.data.fill_(0)
# 计算均方误差使用 MSELoss 类,也称平方L2范数
loss = nn.MSELoss()
# 实例化SGD实例,  net.parameters 里面包含了所有参数
trainer = torch.optim.SGD(net.parameters(),lr=0.03)
# 训练模块
num_epochs = 3
for epoch in range(num_epochs):
    #拿出小批量进行训练
    for x,y in data_iter:
#         net本身带有模型参数,就不需要  w,b
        l = loss(net(x),y)
#         trainer是优化器,先把梯度清零
        trainer.zero_grad()
#         梯度清零过后进行梯度的前向传播
        l.backward()
#         有梯度之后,调用setp函数对模型进行更新
        trainer.step()
#     把整个data放入模型计算损失
    l = loss(net(features),labels)
    print(f'epoch{epoch+1},loss:{l:f}')

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值