李沐动手深度学习(pycharm中运行条记)——08.线性回归+从零实现+简便实现

[复制链接]
发表于 2025-9-18 04:33:10 | 显示全部楼层 |阅读模式
08.线性回归+从零实现+简便实现(与课程对应)

目录
08.线性回归+从零实现+简便实现(与课程对应)

一、基础算法
二、从零实现
三、简便实现


一、基础算法

1、线性回归

2、买房竞价应用


  • 买房流程:在美国买房需先看房了解信息,看中后加入竞价,给定时间窗内浩繁买家出价,价高者得房。
  • 代价参考:卖房经纪人列价和 Redfin 网站估价仅供参考,终极成交价需买家自行出价竞争。
  • 实例阐明:以某房为例,列价 550 万美金,有 7 个寝室、5 个卫生间,居住面积 460 平米左右,Redfin 估价 540 万美金。
  • 购房差价:展示两套房子成交价与系统估价情况,有买家因不懂规矩多花 10 万美金,系统估价在一年后仍低于其出价。
​​​​​​​3、线性回归模型构建


  • 简化假设:假设影响房价的关键因素为寝室个数、卫生间个数和居住面积,分别记为 X1、X2、X3;成交价 y 是关键因素的加权和,即 y = W1*X1 + W2*X2 + W3*X3 + b ,此中权重 W1、W2、W3 和弊端 b 值后续确定。



  • 一样平常化模型:给定 n 维输入 x(包罗 x1 到 xn 项),线性模型有 n 维权重 w(含 w1 到 wn)和标量弊端 b,输出为输入的加权和加弊端,写成向量版本为输入 x 向量与权重 w 累积再加弊端 b。



  • 与神经网络关系:线性模型可看作单层神经网络,输入层有 n 个输入元素,输出层维度为 1,每箭头代表权重,此神经网络因带权重层仅一层而被称为单层神经系统,神经网络概念源于神经科学,虽如今发展超出其范畴,但部门模型仍有神经科学配景。
​​​​​​​4、模型评估与参数学习



  • 损失函数界说:用平方损失权衡猜测值y^与真实值y差异,即 1/2*(真实值 - 估计值)² ,此中 1/2 是为求导方便消去系数。



  • 练习数据预备:基于数据学习模型参数,如收罗过去 6 个月卖房信息及成交价作为练习数据,数据通常越多越好,但受多种因素限定,数据不敷时有干系处理技能。

 



  • 损失函数盘算:假设有 n 个样本,将样天职列成矩阵情势,大 X 每行为一个样本,y 为列向量代表真实值,评估模型在每个数据上损失求均值得到损失函数,目标是找到使损失函数最小的权重 w 和弊端 b 。
二、从零实现

线性回归的从零实现(倒霉用任何的深度学习框架提供的盘算,只利用最简单的在tensor上的盘算):我们将从零开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度降落优化器。
1、导入库
  1. import random
  2. import torch
  3. from d2l import torch as d2l
复制代码
 2、根据带有噪声的线性模型构造一个 人造数据集,我们利用线性模型参数 w = [2, -3.4]T、b = 4.2 和噪声项 ϵ,天生数据集及标签 y = Xw + b + ϵ
  1. def synthetic_data(w, b, num_examples):
  2.     """生成 y = Xw + b + 噪声"""
  3.     X = torch.normal(0, 1, (num_examples, len(w)))  # 创建x,均值为0、方差为1的随机正态分布数,大小尺寸为(n个样本, w的长度)
  4.     y = torch.matmul(X, w) + b  # y = Xw + b
  5.     y += torch.normal(0, 0.01, y.shape)  # 加入随机噪音(均值为0,方差为0.01,形状与y相同):y = Xw + b + 噪声
  6.     return X, y.reshape((-1, 1))
  7. true_w = torch.tensor([2, -3.4])  # 真实的 w
  8. true_b = 4.2  # 真实的 b
  9. features, labels = synthetic_data(true_w, true_b, 1000)  # 特征,标签
  10. print("features:", features[0], "\nlabels:", labels[0])  # 打印第0个数据
  11. # 对样本数据集进行可视化
  12. d2l.set_figsize()
  13. d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)
  14. # d2l.plt.scatter(features[:, 1], labels, 1)  # 这么写也行
  15. d2l.plt.show()  # 在线展示
复制代码

 

 3、每次读取小批量
  1. def data_iter(batch_size, features, labels):  # 批量大小,特征,标号
  2.     num_examples = len(features)  # 样本数n
  3.     indices = list(range(num_examples))  # 0到n-1下标转成一个list
  4.     # 这些样本是随机读取的,没有特定的顺序
  5.     random.shuffle(indices)  # 用random.shuffle()将下标完全打乱;这样就可以随机顺序去访问每个样本
  6.     for i in range(0, num_examples, batch_size):  # 每一次从0开始,到n-1,每一次跳batch_size大小
  7.         batch_indices = torch.tensor(indices[i:min(i + batch_size, num_examples)])  # 前边没有到最后,那就取最小值;最后一次如果没有拿满会取个最小值
  8.         yield features[batch_indices], labels[batch_indices]  # yield就是每次返回两组值,可以一直返回
  9. batch_size = 10
  10. # 打印一个批量的数据示例
  11. for X, y in data_iter(batch_size, features, labels):
  12.     print('X:', X, '\n', 'y:', y)
  13.     break
复制代码


 4、界说初始化模型参数
  1. w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)  # 因为输入维度是2,所以w是一个长为2的向量,随机初始化为均值为0、方差为1 的随机的正太分布
  2. b = torch.zeros(1, requires_grad=True)  # 需要计算梯度
复制代码
5、 界说模型
  1. def linreg(X, w, b):  # 给定输入X(就是批量大小);以及w, b
  2.     """线性回归模型"""
  3.     return torch.matmul(X, w) + b  # y = Xw + b
复制代码
6、 界说损失函数
  1. def squqred_loss(y_hat, y):  # y_hat预测值;y真实值
  2.     """均方损失"""
  3.     return (y_hat - y.reshape(y_hat.shape))**2 / 2
复制代码
7、 界说优化算法
  1. def sgd(params, lr, batch_size):  # params所有参数,包含w、b;lr学习率;batch_size批量大小
  2.     """小批量随机梯度下降"""
  3.     with torch.no_grad():  # 不需要计算梯度,更新的时候不要采用梯度计算
  4.         for param in params:  # 对参数里面的每一个参数w、b
  5.             param -= lr * param.grad / batch_size  # 自动求导时,导数存在.grad里面
  6.             param.grad.zero_()  # 梯度设置为0,下一次计算梯度的时候,就不会跟上次的有关联了
复制代码
 8、练习过程
  1. # (1)超参数设置
  2. lr = 0.03  # 学习率
  3. num_epochs = 3  # 整个数据扫三遍
  4. net = linreg  # network 模型
  5. loss = squqred_loss  # 损失函数,均方损失
  6. # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
  7. for epoch in range(num_epochs):
  8.     for X, y in data_iter(batch_size, features, labels):
  9.         l = loss(net(X, w, b), y)  # 把 X, w, b 放到模型里面做预测;把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
  10.         l.sum().backward()  # 对loss求和(因为上一步得到的loss是批量大小的向量),求和之后算梯度
  11.         sgd([w, b], lr, batch_size)  # 使用sgd()函数,来对w、b进行更新;此处的batch_size不够严谨,因为本次示例有100个样本,批量大小为10,所以可以整除,当遇到最后剩余的数据少于batch_size时,这么写会多出一部分,所以要进行特殊处理
  12.     # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
  13.     with torch.no_grad():
  14.         train_l = loss(net(features, w, b), labels)  # features, w, 传入到模型中,与真实的labels进行损失计算
  15.         print(f"epoch {epoch + 1}, loss {float(train_l.mean()):f}") # 打印评估的结果
复制代码

9、 由于本次用的时人工数据集,可以看到真实的w、b;比力真实参数和通过练习学到的参数来评估练习的乐成程度
  1. print(f"w的估计误差:{true_w - w.reshape(true_w.shape)}")
  2. print(f"b的估计误差:{true_b - b}")
复制代码

10、完备代码:
  1. import random
  2. import torch
  3. from d2l import torch as d2l# 线性回归的从零实现(倒霉用任何的深度学习框架提供的盘算,只利用最简单的在tensor上的盘算):我们将从零开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度降落优化器# 1、根据带有噪声的线性模型构造一个 人造数据集,我们利用线性模型参数 w = [2, -3.4]T、b = 4.2 和噪声项 ϵ,天生数据集及标签 y = Xw + b + ϵdef synthetic_data(w, b, num_examples):    """天生 y = Xw + b + 噪声"""    X = torch.normal(0, 1, (num_examples, len(w)))  # 创建x,均值为0、方差为1的随机正态分布数,巨细尺寸为(n个样本, w的长度)    y = torch.matmul(X, w) + b  # y = Xw + b    y += torch.normal(0, 0.01, y.shape)  # 加入随机噪音(均值为0,方差为0.01,形状与y相同):y = Xw + b + 噪声    return X, y.reshape((-1, 1))true_w = torch.tensor([2, -3.4])  # 真实的 wtrue_b = 4.2  # 真实的 bfeatures, labels = synthetic_data(true_w, true_b, 1000)  # 特性,标签print("features:", features[0], "\nlabels:", labels[0])  # 打印第0个数据# 对样本数据集举行可视化d2l.set_figsize()d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)# d2l.plt.scatter(features[:, 1], labels, 1)  # 这么写也行# d2l.plt.show()  # 在线展示# 2、每次读取小批量def data_iter(batch_size, features, labels):  # 批量巨细,特性,标号    num_examples = len(features)  # 样本数n    indices = list(range(num_examples))  # 0到n-1下标转成一个list    # 这些样本是随机读取的,没有特定的顺序    random.shuffle(indices)  # 用random.shuffle()将下标完全打乱;如许就可以随机顺序去访问每个样本    for i in range(0, num_examples, batch_size):  # 每一次从0开始,到n-1,每一次跳batch_size巨细        batch_indices = torch.tensor(indices[i:min(i + batch_size, num_examples)])  # 前边没有到最后,那就取最小值;最后一次如果没有拿满会取个最小值        yield features[batch_indices], labels[batch_indices]  # yield就是每次返回两组值,可以不停返回batch_size = 10# 打印一个批量的数据示例for X, y in data_iter(batch_size, features, labels):    print(X, '\n', y)    break# 3、界说初始化模型参数w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)  # 因为输入维度是2,所以w是一个长为2的向量,随机初始化为均值为0、方差为1 的随机的正太分布
  4. b = torch.zeros(1, requires_grad=True)  # 需要计算梯度
  5. # 4、界说模型def linreg(X, w, b):  # 给定输入X(就是批量大小);以及w, b
  6.     """线性回归模型"""
  7.     return torch.matmul(X, w) + b  # y = Xw + b# 5、界说损失函数def squqred_loss(y_hat, y):  # y_hat预测值;y真实值
  8.     """均方损失"""
  9.     return (y_hat - y.reshape(y_hat.shape))**2 / 2# 6、界说优化算法def sgd(params, lr, batch_size):  # params所有参数,包含w、b;lr学习率;batch_size批量大小
  10.     """小批量随机梯度下降"""
  11.     with torch.no_grad():  # 不需要计算梯度,更新的时候不要采用梯度计算
  12.         for param in params:  # 对参数里面的每一个参数w、b
  13.             param -= lr * param.grad / batch_size  # 自动求导时,导数存在.grad里面
  14.             param.grad.zero_()  # 梯度设置为0,下一次计算梯度的时候,就不会跟上次的有关联了# 7、练习过程# (1)超参数设置
  15. lr = 0.03  # 学习率
  16. num_epochs = 3  # 整个数据扫三遍
  17. net = linreg  # network 模型
  18. loss = squqred_loss  # 损失函数,均方损失
  19. # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
  20. for epoch in range(num_epochs):
  21.     for X, y in data_iter(batch_size, features, labels):
  22.         l = loss(net(X, w, b), y)  # 把 X, w, b 放到模型里面做预测;把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
  23.         l.sum().backward()  # 对loss求和(因为上一步得到的loss是批量大小的向量),求和之后算梯度
  24.         sgd([w, b], lr, batch_size)  # 使用sgd()函数,来对w、b进行更新;此处的batch_size不够严谨,因为本次示例有100个样本,批量大小为10,所以可以整除,当遇到最后剩余的数据少于batch_size时,这么写会多出一部分,所以要进行特殊处理
  25.     # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
  26.     with torch.no_grad():
  27.         train_l = loss(net(features, w, b), labels)  # features, w, 传入到模型中,与真实的labels进行损失计算
  28.         print(f"epoch {epoch + 1}, loss {float(train_l.mean()):f}") # 打印评估的结果# 8、由于本次用的时人工数据集,可以看到真实的w、b;比力真实参数和通过练习学到的参数来评估练习的乐成程度print(f"w的估计误差:{true_w - w.reshape(true_w.shape)}")
  29. print(f"b的估计误差:{true_b - b}")
复制代码
三、简便实现

线性回归的简便实现(利用深度学习框架提供的盘算);包括数据流水线、模型、损失函数和小批量随机梯度降落优化器
1、导入库
  1. import numpy as np
  2. import torch
  3. from torch.utils import data
  4. from d2l import torch as d2l
  5. from torch import nn
复制代码
 2、人造数据集,利用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labels
  1. true_w = torch.tensor([2, -3.4])
  2. true_b = 4.2
  3. features, labels = d2l.synthetic_data(true_w, true_b, 1000)
  4. def load_array(data_arrays, batch_size, is_train=True):
  5.     """构造一个Pytorch数据迭代"""
  6.     dataset = data.TensorDataset(*data_arrays)  # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包
  7.     return data.DataLoader(dataset, batch_size, shuffle=is_train)  # 加载数据集,shuffle表示是否随机打乱
  8. batch_size = 10
  9. data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size)  # 把features, labels做成一个list传入到data.TensorDataset,得到数据集dataset
  10. print(next(iter(data_iter)))
复制代码
3、 模型界说;'nn'是神经网络的缩写
  1. # (1)使用框架的预定义好的层
  2. net = nn.Sequential(nn.Linear(2, 1))  # 指定输入维度为2,输出维度为1
  3. # (2)初始化模型参数
  4. net[0].weight.data.normal_(0, 0.01)  # 就是对w初始化化为均值为0,方差为0.01的正态分布
  5. net[0].bias.data.fill_(0)  # 就是对b初始化为0
复制代码
4、盘算均方偏差利用的是MSELoss类,也称为 平方范数
  1. loss = nn.MSELoss()
复制代码
5、实例化SGD实例,优化器
  1. trainer = torch.optim.SGD(net.parameters(), lr=0.03)  # 传入参数、学习率
复制代码
6、练习过程
  1. # (1)超参数设置
  2. num_epochs = 3  # 整个数据扫三遍
  3. # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
  4. for epoch in range(num_epochs):
  5.     for X, y in data_iter:
  6.         l = loss(net(X), y)  # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
  7.         trainer.zero_grad()  # 优化器梯度清0
  8.         l.backward()  # 求梯度,此处不用求sum,因为已经自动求完sum了
  9.         trainer.step()  # 调用step()函数,进行一次模型参数的更新
  10.     # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
  11.     l = loss(net(features), labels)
  12.     print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果
复制代码
7、完备代码:

  1. import numpy as np
  2. import torch
  3. from torch.utils import data
  4. from d2l import torch as d2l
  5. from torch import nn
  6. # 线性回归的简便实现(利用深度学习框架提供的盘算);包括数据流水线、模型、损失函数和小批量随机梯度降落优化器# 1、人造数据集,利用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labelstrue_w = torch.tensor([2, -3.4])
  7. true_b = 4.2
  8. features, labels = d2l.synthetic_data(true_w, true_b, 1000)
  9. def load_array(data_arrays, batch_size, is_train=True):
  10.     """构造一个Pytorch数据迭代"""
  11.     dataset = data.TensorDataset(*data_arrays)  # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包
  12.     return data.DataLoader(dataset, batch_size, shuffle=is_train)  # 加载数据集,shuffle表示是否随机打乱
  13. batch_size = 10
  14. data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size)  # 把features, labels做成一个list传入到data.TensorDataset,得到数据集dataset
  15. print(next(iter(data_iter)))
  16. # 2、模型界说;'nn'是神经网络的缩写# (1)使用框架的预定义好的层
  17. net = nn.Sequential(nn.Linear(2, 1))  # 指定输入维度为2,输出维度为1
  18. # (2)初始化模型参数
  19. net[0].weight.data.normal_(0, 0.01)  # 就是对w初始化化为均值为0,方差为0.01的正态分布
  20. net[0].bias.data.fill_(0)  # 就是对b初始化为0# 3、盘算均方偏差利用的是MSELoss类,也称为 平方范数loss = nn.MSELoss()# 4、实例化SGD实例,优化器trainer = torch.optim.SGD(net.parameters(), lr=0.03)  # 传入参数、学习率# 5、练习过程# (1)超参数设置
  21. num_epochs = 3  # 整个数据扫三遍
  22. # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
  23. for epoch in range(num_epochs):
  24.     for X, y in data_iter:
  25.         l = loss(net(X), y)  # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
  26.         trainer.zero_grad()  # 优化器梯度清0
  27.         l.backward()  # 求梯度,此处不用求sum,因为已经自动求完sum了
  28.         trainer.step()  # 调用step()函数,进行一次模型参数的更新
  29.     # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
  30.     l = loss(net(features), labels)
  31.     print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果
复制代码
如果此文章对您有所资助,那就请点个赞吧,收藏+关注 那就更棒啦,非常感谢!!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表