线性回归与实现(三)


写在前面:
公式符号详见 论文数学公式编辑
参考书: 动手学深度学习

1 线性回归

回归是多(或单)个自变量与因变量之间关系建模的一类方法。 在机器学习中通常与预测有关。线性回归基于两个基本假设:

  • 1.自变量 x \mathbf{x} x和因变量 y y y之间的关系是线性的, 即 y y y可以表示为 x \mathbf{x} x中元素的加权和。
  • 2.噪声遵循正态分布。原因见文末第二节。

1.1 术语

 因变量 y i y^i yi称为:标签
 因变量 y i y^i yi对应的自变量 x i = [ x 1 i , x 2 i , ⋯   , x d i ] ⊤ \mathbf{x}^{i}=[x_1^{i},x_2^{i}, \cdots, x_d^i]^\top xi=[x1i,x2i,,xdi]称为:样本
 自变量 x i \mathbf{x}^{i} xi对应的每个元素 [ x 1 i , x 2 i , ⋯   , x d i ] ⊤ [x_1^{i},x_2^{i}, \cdots, x_d^i]^\top [x1i,x2i,,xdi]称为:特征

PS: 通常,我们使用 n n n来表示数据集中的样本数。 也就是说数据集表示为 X n × d \mathbf{X}_{n \times d} Xn×d,n为样本数,d为特征数。

1.2 模型表示

输入包含 d d d个特征时,我们将预测结果 y ^ \hat{y} y^表示为:
y ^ = w 1 x 1 + … + w d x d + b . (1) \hat{y}=w_1x_1+\ldots+w_dx_d+b. \tag{1} y^=w1x1++wdxd+b.(1)
PS: 通常使用“尖角”符号表示估计值

将所有特征放到向量 x ∈ R d \mathbf{x}\in\mathbb{R}^{d} xRd中, 并将所有权重放到向量 w ∈ R d \mathbf{w}\in\mathbb{R}^{d} wRd中得:
y ^ = w ⊤ x + b . (2) \hat{y}=\mathbf{w}^\top\mathbf{x}+b. \tag{2} y^=wx+b.(2)

在公式(2)中,向量 x \mathbf{x} x单个数据样本的特征。矩阵-向量乘法可以很方便地表示整个数据集n个样本模型计算为:

y ^ = X w + b (3) \hat{\mathbf{y}}=\mathbf{X}\mathbf{w}+b\tag{3} y^=Xw+b(3)
在这里插入图片描述
在这里插入图片描述

1.3 损失函数

损失函数量化目标的真实值与预测值之间的差距。我们希望差距越小越好。即损失函数值越小越好。回归问题中最常用的损失函数是平方误差函数

当样本的预测值为 y ^ ( i ) \hat{y}^{(i)} y^(i),其相应的真实标签为 y ( i ) y^{(i)} y(i)时, 平方误差可以定义为以下公式:

l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 . (4) l^{(i)}(\mathbf{w},b)=\frac{1}{2}\Big(\hat{y}^{(i)}-y^{(i)}\Big)^2. \tag{4} l(i)(w,b)=21(y^(i)y(i))2.(4)

度量模型在整个数据集上的质量,我们需计算在训练集n个样本上的损失均值
L ( w , b ) = 1 n ∑ i = 1 n l ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w ⊤ x ( i ) + b − y ( i ) ) 2 . (5) L(\mathbf{w},b)=\frac1n\sum_{i=1}^nl^{(i)}(\mathbf{w},b)=\frac1n\sum_{i=1}^n\frac12\left(\mathbf{w}^\top\mathbf{x}^{(i)}+b-y^{(i)}\right)^2.\tag{5} L(w,b)=n1i=1nl(i)(w,b)=n1i=1n21(wx(i)+by(i))2.(5)

在训练模型时,我们希望寻找一组参数 ( w ∗ , b ∗ ) (\mathbf{w}^*,b^*) (w,b) 最小化所有样本总损失 如下式:
w ∗ , b ∗ = argmin ⁡ w , b L ( w , b ) . (6) \mathbf{w}^*,b^*=\underset{\mathbf{w},b}{\operatorname*{argmin}} L(\mathbf{w},b). \tag{6} w,b=w,bargminL(w,b).(6)

1.4 随机梯度下降

梯度下降几乎可以优化所有深度学习模型。
本质使参数在损失函数递减的方向上更新来降低误差
我们目标是模型输出结果贴近真实值,即误差小,即用于衡量误差的损失函数值小。那就每次算一下当前的损失函数在哪个方向上会减小,按照这个方向更新参数就会使损失函数值减小。随机是为了防止停在极小值点而非最小值点。

我们用下面的数学公式来表示这一更新过程:

( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) . (7) (\mathbf{w},b)\leftarrow(\mathbf{w},b)-\frac\eta{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\partial_{(\mathbf{w},b)}l^{(i)}(\mathbf{w},b). \tag{7} (w,b)(w,b)BηiB(w,b)l(i)(w,b).(7)

η ∣ B ∣ \frac\eta{|\mathcal{B}|} Bη可以视为自定义系数,用于控制更新幅度。 B \mathcal{B} B是数据集的一个小批量。

对于平方损失,我们可以明确地写成如下形式:
w ← w − η ∣ B ∣ ∑ i ∈ B ∂ w l ( i ) ( w , b ) = w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w ⊤ x ( i ) + b − y ( i ) ) , b ← b − η ∣ B ∣ ∑ i ∈ B ∂ b l ( i ) ( w , b ) = b − η ∣ B ∣ ∑ i ∈ B ( w ⊤ x ( i ) + b − y ( i ) ) . (8) \begin{gathered} \mathbf{w}\leftarrow\mathbf{w}-{\frac{\eta}{|\mathcal{B}|}}\sum_{i\in\mathcal{B}}\partial_{\mathbf{w}}l^{(i)}(\mathbf{w},b)=\mathbf{w}-{\frac{\eta}{|\mathcal{B}|}}\sum_{i\in\mathcal{B}}\mathbf{x}^{(i)}\left(\mathbf{w}^{\top}\mathbf{x}^{(i)}+b-y^{(i)}\right), \\ b\leftarrow b-\frac\eta{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\partial_bl^{(i)}(\mathbf{w},b)=b-\frac\eta{|\mathcal{B}|}\sum_{i\in\mathcal{B}}\Big(\mathbf{w}^\top\mathbf{x}^{(i)}+b-y^{(i)}\Big). \end{gathered}\tag{8} wwBηiBwl(i)(w,b)=wBηiBx(i)(wx(i)+by(i)),bbBηiBbl(i)(w,b)=bBηiB(wx(i)+by(i)).(8)

2 pytorch实现

2.1 不借助框架组件

只运用:(1)通过张量来进行数据存储和线性代数; (2)通过自动微分来计算梯度。

import random
import torch
from d2l import torch as d2l
# 定义一个函数来生成合成数据集
def synthetic_data(w, b, num_examples):  
    """生成合成数据集,其中y = Xw + b + 噪声"""
    X = torch.normal(0, 1, (num_examples, len(w)))  # 生成特征矩阵,均值为0,标准差为1
    y = torch.matmul(X, w) + b  # 计算标签,为特征矩阵与权重向量的矩阵乘加偏置
    y += torch.normal(0, 0.01, y.shape)  # 在标签上添加均值为0,标准差为0.01的噪声
    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)
# 定义一个数据迭代器函数,用于批量生成数据
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 features[batch_indices], labels[batch_indices]  # 生成当前批次的数据
# 设置批次大小
batch_size = 10
# 初始化权重参数,并设置需要计算梯度
w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
# 初始化偏置参数,并设置需要计算梯度
b = torch.zeros(1, requires_grad=True) 
# 定义线性回归模型
def linreg(X, w, b):  #@save
    """线性回归模型,返回预测值"""
    return torch.matmul(X, w) + b  # 计算预测值

# 定义均方损失函数
def squared_loss(y_hat, y):  #@save
    """计算预测值和真实值之间的均方损失"""
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  # 计算均方损失

# 定义小批量随机梯度下降算法
def sgd(params, lr, batch_size):  #@save
    """使用小批量随机梯度下降更新参数"""
    with torch.no_grad():  # 在更新参数时不需要计算梯度
        for param in params:  # 遍历所有参数
            param -= lr * param.grad / batch_size  # 更新参数
            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.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}')  # 打印当前轮次的损失

2.2 简洁实现

import numpy as np
import torch
# 导入PyTorch的数据工具,用于数据加载和批处理
from torch.utils import data
from d2l import torch as d2l
# 定义真实的权重和偏置
true_w = torch.tensor([2, -3.4])
true_b = 4.2
# 使用d2l库中的函数生成合成数据集
features, labels = d2l.synthetic_data(true_w, true_b, 1000)
# 定义一个函数来构造PyTorch数据迭代器
def load_array(data_arrays, batch_size, is_train=True):  #@save
    """构造一个PyTorch数据迭代器"""
    dataset = data.TensorDataset(*data_arrays)
    # 返回一个DataLoader对象,用于批量加载数据
    return data.DataLoader(dataset, batch_size, shuffle=is_train)

# 设置批次大小
batch_size = 10
# 使用load_array函数创建数据迭代器
data_iter = load_array((features, labels), batch_size)
# 导入torch.nn模块,用于构建神经网络
from torch import nn

# 构建一个顺序模型,包含一个线性层
net = nn.Sequential(nn.Linear(2, 1))
# 初始化线性层的权重和偏置
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)
# 设置损失函数为均方误差损失
loss = nn.MSELoss()
# 设置优化器为随机梯度下降
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
# 设置训练轮数
num_epochs = 3

# 训练模型
for epoch in range(num_epochs):
    for X, y in data_iter:  # 遍历数据迭代器中的每个批次
        l = loss(net(X), y)  # 计算损失
        trainer.zero_grad()  # 清零梯度
        l.backward()  # 反向传播计算梯度
        trainer.step()  # 更新模型参数
    # 在每个epoch结束时计算并打印整个数据集上的损失
    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)

3 正态分布与平方损失

我们拿到的数据是有噪声的。文首所言线性模型的基本假设第二条为:噪声遵循正态分布。其原因为在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。
你可能会问不用平方损失就不是线性模型了?我用其他损失函数不也可以训练出来很好甚至更佳的效果吗?
个人见解:

  • 在线性模型初问世时,需要模型可解释。噪音正态分布假设+最大似然可以解释线性模型。
  • 当今AI领域许多模型其实没有很好的可解释性,因为我们更看重实际性能,而不在乎他是不是可解释的。
  • 我们当然可以用其他的损失函数。一个不恰当的例子:就像我们用牛顿力学解释世界肯定不如加上相对论更准确,但是能用就行了,我不一定要准确的解释世界,我只要有个不错的结果就行了。

3.1 证明

有兴趣可以看一下,不是很必要。

假设模型考虑噪声:
y = w ⊤ x + b + ϵ , (10) y=\mathbf{w}^\top\mathbf{x}+b+\epsilon, \tag{10} y=wx+b+ϵ,(10)
其中, ϵ ∼ N ( 0 , σ 2 ) \epsilon\sim\mathcal{N}(0,\sigma^2) ϵN(0,σ2)。正态分布概率密度函数如下:
p ( x ) = 1 2 π σ 2 exp ⁡ ( − 1 2 σ 2 ( x − μ ) 2 ) . (11) p(x)=\frac{1}{\sqrt{2\pi\sigma^2}}\exp\left(-\frac{1}{2\sigma^2}(x-\mu)^2\right). \tag{11} p(x)=2πσ2 1exp(2σ21(xμ)2).(11)

因此,我们现在可以写出通过给定的 x \mathbf{x} x观测到特定 y y y的似然(likelihood):

根据极大似然估计法,参数 w \mathbf{w} w b b b的最优值是使整个数据集的似然最大的值:

P ( y ∣ X ) = ∏ i = 1 n p ( y ( i ) ∣ x ( i ) ) . (12) P(\mathbf{y}\mid\mathbf{X})=\prod_{i=1}^np(y^{(i)}|\mathbf{x}^{(i)}). \tag{12} P(yX)=i=1np(y(i)x(i)).(12)

我们可以改为最小化负对数似然。 由此可以得到的数学公式是:
P ( y ∣ x ) = 1 2 π σ 2 exp ⁡ ( − 1 2 σ 2 ( y − w ⊤ x − b ) 2 ) . (13) P(y\mid\mathbf{x})=\frac{1}{\sqrt{2\pi\sigma^2}}\exp\left(-\frac{1}{2\sigma^2}(y-\mathbf{w}^\top\mathbf{x}-b)^2\right).\tag{13} P(yx)=2πσ2 1exp(2σ21(ywxb)2).(13)

σ \sigma σ是某个固定常数。 现在第二项除了常数外,其余部分和前面介绍的均方误差是一样的。上面式子的解并不依赖于 σ \sigma σ。 因此,在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rendy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值