1、美国买房
1、什么是线性模型
2、衡量预估质量
对比预测值和 真实值之间的距离差,目标当然使越小越好。。也成为损失函数
3、训练数据
用已有的样本数据和目标值为已有信息,模型根据这些信息进行学习。使其逐渐成为具有对房价有预测能力的模型。
4、参数学习:
针对已有样本和目标值的数据,学习到合适的w和b 使尽量多的数据x 可以拟合到y
5、线性回归的显式解
这是唯一有最优解的模型
2、基础优化算法
梯度下降![](https://i-blog.csdnimg.cn/blog_migrate/010171fa41fb65fb30822ec8837f697c.png)
学习率![](https://i-blog.csdnimg.cn/blog_migrate/0aea449786313d8a29c7d35663cb30d8.png)
小批量随机梯度下降![](https://i-blog.csdnimg.cn/blog_migrate/a976761cb9fac45b75253fb638ae2554.png)
批量大小![](https://i-blog.csdnimg.cn/blog_migrate/33a84fad996dcaba912acdb0b6de2097.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7ab770483e3ae3c9442382b47ca64400.png)
3、线性回归的从0 开始实现
虽然现代的深度学习框架几乎可以自动化地进行所有这些工作,但从零开始实现可以确保我们真正知道自己在做什么。 同时,了解更细致的工作原理将方便我们自定义模型、自定义层或自定义损失函数。 在这一节中,我们将只使用张量和自动求导。
1、产生样本数据
import torch
import random
import matplotlib.pyplot as plt
# 我们将从零开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度下降优化器
# 根据带有噪声的线性模型构造一个人造数据集。---好处:我们可以知道真实的w和b
# 我们使用线性模型参数 w = [2,-3.4] b = 4.2 和噪声项e生成数据集及其标签:y = xw+b+e
def synthetic_data(w,b,num_examples):
'''生成 y = w*x +b+噪声 '''
#均值为0 ,方差为1 的随机数 列数是w的长度 。num_examples 个样本
X = torch.normal(0, 1, (num_examples, len(w)))
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], '\nlabel:', labels[0])
'''
features: tensor([0.9521, 1.5334])
label: tensor([0.9076])
'''
# 画图
# 设置大小
plt.figure(figsize=(3, 4))
# 给数据
plt.scatter(features[:,1].detach().numpy(), labels.detach().numpy(), 1)
# 展示图
plt.show()
生成的数据展示如片如下:
2、读取数据集
回想一下,训练模型时要对数据集进行遍历,每次抽取一小批量样本,并使用它们来更新我们的模型。 由于这个过程是训练机器学习算法的基础,所以有必要定义一个函数, 该函数能打乱数据集中的样本并以小批量方式获取数据。
在下面的代码中,我们定义一个data_iter
函数, 该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size
的小批量。 每个小批量包含一组特征和标签。
# ======================
# 定义一个 data_iter 函数,该函数接收批量大小、特征矩阵和标签尚量作为输入,生成大小为batch size的小批量
def data_iter(batch_size,features,labels):
num_examples = len(features) #样本个数
indices = list(range(num_examples)) #0-n-1
# 这些样本是随机读取的,没有特定的顺序
random.shuffle(indices) #把下标打乱
# 从 0 至num_examples ,每次跳batch_size大小
for i in range(0,num_examples,batch_size):
# min(i+batch_size, num_examples 超过样本个数就取最小值
batch_indices = torch.tensor(indices[i:min(i+batch_size, num_examples)])
# yield 是 python中的一个迭代器.
yield features[batch_indices],labels[batch_indices] #产生随机顺序对应的特征和编号
batch_size = 10
# data_iter 返回一个迭代器
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y) #y 是(10,1)
break
# tensor([[-0.9456, 0.4487],
# [-0.3866, 1.4375],
# [ 0.0700, -0.5329],
# [-1.5265, -1.1378],
# [ 0.7764, 0.5391],
# [ 0.8798, 0.0224],
# [-0.3990, 0.0811],
# [-1.3746, -0.4506],
# [ 1.1126, -0.1899],
# [-1.5335, -1.3193]])
# tensor([[ 0.7733],
# [-1.4451],
# [ 6.1603],
# [ 5.0287],
# [ 3.9116],
# [ 5.8815],
# [ 3.1339],
# [ 2.9816],
# [ 7.0710],
# [ 5.6272]])
当我们运行迭代时,我们会连续地获得不同的小批量,直至遍历完整个数据集。 上面实现的迭代对教学来说很好,但它的执行效率很低,可能会在实际问题上陷入麻烦。 例如,它要求我们将所有数据加载到内存中,并执行大量的随机内存访问。 在深度学习框架中实现的内置迭代器效率要高得多, 它可以处理存储在文件中的数据和数据流提供的数据。
3、定义初始化模型参数
#==================
# 定义初始化模型参数
# w 均值为0 方差为0.01 shape 为(2,1)
w = torch.normal(0, 0.01,size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True) #b 默认设置为0 标量
# 定义线性回归模型
def linreg(X,w,b,):
return torch.matmul(X,w)+b
# 定义损失函数--均方损失
def squared_loss(y_hat, y):
# reshape 统一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_() #清零
4、训练过程
#===============
# 训练过程
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):
# net(X,w,b) 预测值 和真实值之间的损失值
l = loss(net(X,w,b),y) #x和y 的小批量损失
# l的形状是(batch_size,1) 而不是一个标量 l中的所有元素被加到一起,
# 并以此计算关于w 和b 的梯度
l.sum().backward()
sgd([w,b],lr,batch_size) #使用参数的梯度更新
with torch.no_grad():
train_1 = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_1.mean()):f}')
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')
'''
epoch 1, loss 0.031740
epoch 2, loss 0.000122
epoch 3, loss 0.000053
w的估计误差: tensor([0.0007, 0.0007], grad_fn=<SubBackward0>)
b的估计误差: tensor([0.0009], grad_fn=<RsubBackward1>)
'''
4、简洁实现线性回归---用已经封装好的类
import numpy as np
import torch
from torch.utils import data
import 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): #@save
"""构造一个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size)
# next(iter(data_iter))
#定义模型
# nn是神经网络的缩写
from torch import nn
# Sequential 相当与list of layers
net = nn.Sequential(nn.Linear(2, 1)) #定义输入、输出的维度
#初始化模型参数
# net[0] 指的是哪个layer weight就是w data指真实data normal_使用正太分布替换data的指 相当于做了归一化
net[0].weight.data.normal_(0, 0.01)
# 偏差设置成0 了
net[0].bias.data.fill_(0)
# 计算均方误差使用的是MSELoss类,也称为平方范数
loss = nn.MSELoss() #定义损失函数
# SGD 梯度下降算法
# net.parameters() 包括了 w 和b
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.zero_grad() #梯度清零
l.backward()
trainer.step() #进行模型更新
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')
# 比较看效果
w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)
'''
epoch 1, loss 0.000293
epoch 2, loss 0.000099
epoch 3, loss 0.000099
w的估计误差: tensor([5.4145e-04, 6.2466e-05])
b的估计误差: tensor([0.0005])
'''