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、导入库
- import random
- import torch
- from d2l import torch as d2l
复制代码 2、根据带有噪声的线性模型构造一个 人造数据集,我们利用线性模型参数 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]) # 真实的 w
- true_b = 4.2 # 真实的 b
- features, 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() # 在线展示
复制代码

3、每次读取小批量
- 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:', X, '\n', 'y:', y)
- break
复制代码
4、界说初始化模型参数
- w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True) # 因为输入维度是2,所以w是一个长为2的向量,随机初始化为均值为0、方差为1 的随机的正太分布
- b = torch.zeros(1, requires_grad=True) # 需要计算梯度
复制代码 5、 界说模型
- def linreg(X, w, b): # 给定输入X(就是批量大小);以及w, b
- """线性回归模型"""
- return torch.matmul(X, w) + b # y = Xw + b
复制代码 6、 界说损失函数
- def squqred_loss(y_hat, y): # y_hat预测值;y真实值
- """均方损失"""
- return (y_hat - y.reshape(y_hat.shape))**2 / 2
复制代码 7、 界说优化算法
- def sgd(params, lr, batch_size): # params所有参数,包含w、b;lr学习率;batch_size批量大小
- """小批量随机梯度下降"""
- with torch.no_grad(): # 不需要计算梯度,更新的时候不要采用梯度计算
- for param in params: # 对参数里面的每一个参数w、b
- param -= lr * param.grad / batch_size # 自动求导时,导数存在.grad里面
- param.grad.zero_() # 梯度设置为0,下一次计算梯度的时候,就不会跟上次的有关联了
复制代码 8、练习过程
- # (1)超参数设置
- lr = 0.03 # 学习率
- num_epochs = 3 # 整个数据扫三遍
- net = linreg # network 模型
- loss = squqred_loss # 损失函数,均方损失
- # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
- for epoch in range(num_epochs):
- for X, y in data_iter(batch_size, features, labels):
- l = loss(net(X, w, b), y) # 把 X, w, b 放到模型里面做预测;把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
- l.sum().backward() # 对loss求和(因为上一步得到的loss是批量大小的向量),求和之后算梯度
- sgd([w, b], lr, batch_size) # 使用sgd()函数,来对w、b进行更新;此处的batch_size不够严谨,因为本次示例有100个样本,批量大小为10,所以可以整除,当遇到最后剩余的数据少于batch_size时,这么写会多出一部分,所以要进行特殊处理
- # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
- with torch.no_grad():
- train_l = loss(net(features, w, b), labels) # features, w, 传入到模型中,与真实的labels进行损失计算
- print(f"epoch {epoch + 1}, loss {float(train_l.mean()):f}") # 打印评估的结果
复制代码
9、 由于本次用的时人工数据集,可以看到真实的w、b;比力真实参数和通过练习学到的参数来评估练习的乐成程度
- print(f"w的估计误差:{true_w - w.reshape(true_w.shape)}")
- print(f"b的估计误差:{true_b - b}")
复制代码
10、完备代码:
- import random
- import torch
- 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 的随机的正太分布
- b = torch.zeros(1, requires_grad=True) # 需要计算梯度
- # 4、界说模型def linreg(X, w, b): # 给定输入X(就是批量大小);以及w, b
- """线性回归模型"""
- return torch.matmul(X, w) + b # y = Xw + b# 5、界说损失函数def squqred_loss(y_hat, y): # y_hat预测值;y真实值
- """均方损失"""
- return (y_hat - y.reshape(y_hat.shape))**2 / 2# 6、界说优化算法def sgd(params, lr, batch_size): # params所有参数,包含w、b;lr学习率;batch_size批量大小
- """小批量随机梯度下降"""
- with torch.no_grad(): # 不需要计算梯度,更新的时候不要采用梯度计算
- for param in params: # 对参数里面的每一个参数w、b
- param -= lr * param.grad / batch_size # 自动求导时,导数存在.grad里面
- param.grad.zero_() # 梯度设置为0,下一次计算梯度的时候,就不会跟上次的有关联了# 7、练习过程# (1)超参数设置
- lr = 0.03 # 学习率
- num_epochs = 3 # 整个数据扫三遍
- net = linreg # network 模型
- loss = squqred_loss # 损失函数,均方损失
- # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
- for epoch in range(num_epochs):
- for X, y in data_iter(batch_size, features, labels):
- l = loss(net(X, w, b), y) # 把 X, w, b 放到模型里面做预测;把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
- l.sum().backward() # 对loss求和(因为上一步得到的loss是批量大小的向量),求和之后算梯度
- sgd([w, b], lr, batch_size) # 使用sgd()函数,来对w、b进行更新;此处的batch_size不够严谨,因为本次示例有100个样本,批量大小为10,所以可以整除,当遇到最后剩余的数据少于batch_size时,这么写会多出一部分,所以要进行特殊处理
- # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
- with torch.no_grad():
- train_l = loss(net(features, w, b), labels) # features, w, 传入到模型中,与真实的labels进行损失计算
- print(f"epoch {epoch + 1}, loss {float(train_l.mean()):f}") # 打印评估的结果# 8、由于本次用的时人工数据集,可以看到真实的w、b;比力真实参数和通过练习学到的参数来评估练习的乐成程度print(f"w的估计误差:{true_w - w.reshape(true_w.shape)}")
- print(f"b的估计误差:{true_b - b}")
复制代码 三、简便实现
线性回归的简便实现(利用深度学习框架提供的盘算);包括数据流水线、模型、损失函数和小批量随机梯度降落优化器
1、导入库
- import numpy as np
- import torch
- from torch.utils import data
- from d2l import torch as d2l
- from torch import nn
复制代码 2、人造数据集,利用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labels
- 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) # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包
- return data.DataLoader(dataset, batch_size, shuffle=is_train) # 加载数据集,shuffle表示是否随机打乱
- batch_size = 10
- data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size) # 把features, labels做成一个list传入到data.TensorDataset,得到数据集dataset
- print(next(iter(data_iter)))
复制代码 3、 模型界说;'nn'是神经网络的缩写
- # (1)使用框架的预定义好的层
- net = nn.Sequential(nn.Linear(2, 1)) # 指定输入维度为2,输出维度为1
- # (2)初始化模型参数
- net[0].weight.data.normal_(0, 0.01) # 就是对w初始化化为均值为0,方差为0.01的正态分布
- net[0].bias.data.fill_(0) # 就是对b初始化为0
复制代码 4、盘算均方偏差利用的是MSELoss类,也称为 平方范数
5、实例化SGD实例,优化器
- trainer = torch.optim.SGD(net.parameters(), lr=0.03) # 传入参数、学习率
复制代码 6、练习过程
- # (1)超参数设置
- num_epochs = 3 # 整个数据扫三遍
- # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
- for epoch in range(num_epochs):
- for X, y in data_iter:
- l = loss(net(X), y) # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
- trainer.zero_grad() # 优化器梯度清0
- l.backward() # 求梯度,此处不用求sum,因为已经自动求完sum了
- trainer.step() # 调用step()函数,进行一次模型参数的更新
- # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
- l = loss(net(features), labels)
- print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果
复制代码 7、完备代码:
- import numpy as np
- import torch
- from torch.utils import data
- from d2l import torch as d2l
- from torch import nn
- # 线性回归的简便实现(利用深度学习框架提供的盘算);包括数据流水线、模型、损失函数和小批量随机梯度降落优化器# 1、人造数据集,利用线性模型参数 w = [2, -3.4]T、b = 4.2;得到features, labelstrue_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) # 得到数据集,*表示接受任意多个参数并将其放在一个元组中,拆包
- return data.DataLoader(dataset, batch_size, shuffle=is_train) # 加载数据集,shuffle表示是否随机打乱
- batch_size = 10
- data_iter = load_array(data_arrays=(features, labels), batch_size=batch_size) # 把features, labels做成一个list传入到data.TensorDataset,得到数据集dataset
- print(next(iter(data_iter)))
- # 2、模型界说;'nn'是神经网络的缩写# (1)使用框架的预定义好的层
- net = nn.Sequential(nn.Linear(2, 1)) # 指定输入维度为2,输出维度为1
- # (2)初始化模型参数
- net[0].weight.data.normal_(0, 0.01) # 就是对w初始化化为均值为0,方差为0.01的正态分布
- 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)超参数设置
- num_epochs = 3 # 整个数据扫三遍
- # (2)训练的实现大同小异,一般就是两层for循环:第一层是每一次对数据扫一遍;第二层是对于每一次拿出一个批量大小的X、y
- for epoch in range(num_epochs):
- for X, y in data_iter:
- l = loss(net(X), y) # 把 X 放到模型里面做预测(net本身自己带了模型参数,所以不需要w、b再传入了);把 预测的y 与 真实的y 做损失;得到的损失就是 一个批量大小的向量
- trainer.zero_grad() # 优化器梯度清0
- l.backward() # 求梯度,此处不用求sum,因为已经自动求完sum了
- trainer.step() # 调用step()函数,进行一次模型参数的更新
- # 对数据扫完一边之后,评价一下进度,此时是不需要梯度的,
- l = loss(net(features), labels)
- print(f"epoch {epoch + 1}, loss {l:f}") # 打印评估的结果
复制代码 如果此文章对您有所资助,那就请点个赞吧,收藏+关注 那就更棒啦,非常感谢!!!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |