跟李沐学AI -08 线性回归+基础优化算法

1、美国买房

1、什么是线性模型

 

2、衡量预估质量

对比预测值和 真实值之间的距离差,目标当然使越小越好。。也成为损失函数

3、训练数据

用已有的样本数据和目标值为已有信息,模型根据这些信息进行学习。使其逐渐成为具有对房价有预测能力的模型。

4、参数学习:

针对已有样本和目标值的数据,学习到合适的w和b 使尽量多的数据x 可以拟合到y 

5、线性回归的显式解

这是唯一有最优解的模型

2、基础优化算法 

梯度下降

学习率

小批量随机梯度下降

批量大小

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])
'''

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值