李沐《动手学深度学习》线性神经网络 线性回归

这篇具有很好参考价值的文章主要介绍了李沐《动手学深度学习》线性神经网络 线性回归。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章

李沐《动手学深度学习》预备知识 张量操作及数据处理
李沐《动手学深度学习》预备知识 线性代数及微积分


教材:李沐《动手学深度学习》

一、线性回归

(一)线性回归的基本元素

  1. 线性回归基于的假设
    • 假设自变量和因变量之间的关系是线性的,这里通常允许包含观测值的一些噪声;
    • 假设任何噪声都比较正常,如噪声遵循正态分布。
  2. 线性回归的矩阵向量表示:(这个过程中的求和将使用广播机制 )
    y ^ = X w + b \hat{y}=Xw+b y^=Xw+b
  3. 线性回归的损失函数:(回归问题中最常用的损失函数是平方误差函数)
    平方误差的定义为:
    l ( i ) ( w , b ) = 1 2 ( y ^ ( i ) − y ( i ) ) 2 l^{(i)}(w,b)=\frac{1}{2}(\hat{y}^{(i)}-y^{(i)})^2 l(i)(w,b)=21(y^(i)y(i))2
    训练集n个样本上的损失均值:
    L ( w , b ) = 1 n ∑ i = 1 n l ( i ) ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w T x ( i ) + b − y ( i ) ) 2 L(w,b)=\frac{1}{n}\sum_{i=1}^nl^{(i)}(w,b)=\frac{1}{n}\sum_{i=1}^n\frac{1}{2}(w^Tx^{(i)}+b-y^{(i)})^2 L(w,b)=n1i=1nl(i)(w,b)=n1i=1n21(wTx(i)+by(i))2
    训练模型时,希望找到一组参数最小化所有训练样本的损失,即:
    w ∗ , b ∗ = argmin ⁡ w , b   L ( w , b ) w^*,b^*={ \underset {w,b} { \operatorname {argmin} } \,L(w,b)} w,b=w,bargminL(w,b)
  4. 解析解
    线性回归的解可以用一个公式简单的表达出来,这类解成为解析解。不是所有的问题都存在解析解。
    w ∗ = ( X T X ) − 1 X T y w^*=(X^TX)^{-1}X^Ty w=(XTX)1XTy
  5. 正态分布与平方损失
    在高斯噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。

(二)随机梯度下降

  1. 随机梯度下降方法几乎可以优化所有深度学习模型,它通过不断地在损失函数递减的方向上更新参数来降低误差;
  2. 梯度下降的用法是计算损失函数关于模型参数的导数;
  3. 由于每次更新参数之前都必须遍历整个数据集,梯度下降法的执行可能会非常慢。因此我们通常会采用每次需要计算更新时随机抽取一小批样本的方法,即小批量随机梯度下降法。

随机梯度下降的公式表示:
( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) (w,b)\leftarrow(w,b)-\frac{\eta}{|B|}\sum_{i\in B}\partial_{(w,b)}l^{(i)}(w,b) (w,b)(w,b)BηiB(w,b)l(i)(w,b)

在每次迭代中,先随机抽样一个小批量 B B B(由固定数量的训练样本组成),然后计算小批量的平均损失的导数(梯度),最后将梯度乘以一个预定的正数 η \eta η(学习率),并从当前参数的值中减掉。

批量大小和学习率的值通常是手动预先指定,而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数调参(hyperparameter tuning)是选择超参数的过程。 超参数通常是我们根据训练迭代结果来调整的, 而训练迭代结果是在独立的验证数据集(validation dataset)上评估得到的。

(三)矢量化加速(实例化说明)

在训练模型时,会利用线性代数库对计算进行矢量化,从而实现整个小批量样本的同时处理。
对比矢量化和for循环两种计算方法,会发现矢量化方法的计算时间短很多,代码实现如下:

相关库的准备:

%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l

d2l的安装

定义一个计时器:

class Timer:  #@save
    """记录多次运行时间"""
    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """启动计时器"""
        self.tik = time.time()

    def stop(self):
        """停止计时器并将时间记录在列表中"""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """返回平均时间"""
        return sum(self.times) / len(self.times)

    def sum(self):
        """返回时间总和"""
        return sum(self.times)

    def cumsum(self):
        """返回累计时间"""
        return np.array(self.times).cumsum().tolist()

数据准备:

n=10000
a=torch.ones([n])
b=torch.ones([n])

用python for循环进行计算:
该方法花费的时间为’0.16749 sec’

c=torch.zeros(n)
timer=Timer()
for i in range(n):
    c[i]=a[i]+b[i]
f'{timer.stop():.5f} sec'

用矢量化进行计算:
该方法花费的时间为’0.00042 sec’

timer.start()
d=a+b
f'{timer.stop():.5f} sec'

结果很明显,第二种方法比第一种方法快得多。 矢量化代码通常会带来数量级的加速。 另外,可以将更多的数学运算放到库中,而无须自己编写那么多的计算,从而减少了出错的可能性。

(四)从线性回归到神经网络

我们可以将线性回归模型视为仅由单个人工神经元组成的神经网络,或称为单层神经网络:
李沐《动手学深度学习》线性神经网络 线性回归,李沐《动手学深度学习》学习笔记,深度学习,神经网络,线性回归,pytorch

  • 输入为 x 1 , … , x d x_1,\ldots,x_d x1,,xd, 因此输入层中的输入数为d;
  • 输出为 o 1 o_1 o1,因此输出层中的输出数是1;
  • 由于模型重点在发生计算的地方,所以通常我们在计算层数时不考虑输入层。 也就是说, 图中神经网络的层数为1。

对于线性回归,每个输入都与每个输出(在本例中只有一个输出)相连, 我们将这种变换( 图中的输出层) 称为全连接层(fully-connected layer)。

二、线性回归的从零开始实现

(一)生成数据集

根据带有噪声的线性模型构造一个人造数据集:

  • 包含1000个样本
  • 线性模型参数: w = [ 2 , − 3.4 ] T w=[2,-3.4]^T w=[2,3.4]T b = 4.2 b=4.2 b=4.2
  • 噪声项服从均值为0,标准差为0.01的正态分布
def synthetic_data(w,b,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)

(二)读取数据集

定义一个函数data_iter, 该函数能打乱数据集中的样本并以小批量方式获取数据

  • 输入:批量大小、特征矩阵和标签向量
  • 输出:大小为batch_size的小批量
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]

通常,我们利用GPU并行运算的优势,处理合理大小的“小批量”。 每个样本都可以并行地进行模型计算,且每个样本损失函数的梯度也可以被并行计算。 GPU可以在处理几百个样本时,所花费的时间不比处理一个样本时多太多。

(三)初始化模型参数

从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0:

w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)

(四)定义模型

def linreg(X,w,b):
    return torch.matmul(X,w)+b

(五)定义损失函数

使用 平方损失函数。 在实现中,我们需要将真实值y的形状转换为和预测值y_hat的形状相同。

def squared_loss(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_()

(七)训练

在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。 最后,我们调用优化算法sgd来更新模型参数。

在每个迭代周期(epoch)中,使用data_iter函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数num_epochs和学习率lr都是超参数,分别设为3和0.03。 设置超参数很棘手,需要通过反复试验进行调整。文章来源地址https://www.toymoban.com/news/detail-810010.html

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

三、线性回归的简洁实现

(一)生成数据集

根据带有噪声的线性模型构造一个人造数据集:

  • 包含1000个样本
  • 线性模型参数: w = [ 2 , − 3.4 ] T w=[2,-3.4]^T w=[2,3.4]T b = 4.2 b=4.2 b=4.2
  • 噪声项服从均值为0,标准差为0.01的正态分布
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)

(二)读取数据集

调用框架中现有的API来读取数据:

  • 将features和labels作为API的参数传递
  • 通过数据迭代器指定batch_size
  • 布尔值is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据。
def load_array(data_arrays,batch_size,is_train=True):
    #构造一个数据迭代器
    # TensorDataset 将输入的特征数据和标签数据打包成一个数据集
    dataset=data.TensorDataset(*data_arrays)
    # DataLoader 用于批量加载数据,可以选择是否在每个 epoch 时随机打乱数据
    return data.DataLoader(dataset,batch_size,shuffle=is_train)


batch_size=10
data_iter=load_array((features,labels),batch_size)

(三)定义模型

对于标准深度学习模型,我们可以使用框架的预定义好的层。这使我们只需关注使用哪些层来构造模型,而不必关注层的实现细节。

torch.nn.Sequential 是一个容器模块,它按顺序包含了其他模块(layers)。这个容器允许将一系列的神经网络层按照顺序组合在一起,形成一个更大的网络模型。Sequential 类提供了一种简单的方式来构建和组织神经网络模型,尤其适用于顺序堆叠的层结构。

将两个参数传递到nn.Linear中。 第一个指定输入特征形状,即2,第二个指定输出特征形状,输出特征形状为单个标量,因此为1。

from torch import nn
net=nn.Sequential(nn.Linear(2,1))

(四)初始化模型参数

在使用net之前,我们需要初始化模型参数。 如在线性回归模型中的权重和偏置。 深度学习框架通常有预定义的方法来初始化参数。 在这里,我们指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样, 偏置参数将初始化为零。

通过net[0]选择网络中的第一个图层, 然后使用weight.data和bias.data方法访问参数。 我们还可以使用替换方法normal_和fill_来重写参数值。

net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)

(五)定义损失函数

使用 平方损失函数。 在实现中,我们需要将真实值y的形状转换为和预测值y_hat的形状相同。

loss=nn.MSELoss()

(六)定义优化算法

使用小批量随机梯度下降法进行优化。

trainer = torch.optim.SGD(net.parameters(), lr=0.03)

(七)训练

在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。 最后,我们调用优化算法sgd来更新模型参数。

在每个迭代周期(epoch)中,使用data_iter函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数num_epochs和学习率lr都是超参数,分别设为3和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()
    l=loss(net(features),labels)
    print(f'epoch {epoch+1}, loss {l:f}')

到了这里,关于李沐《动手学深度学习》线性神经网络 线性回归的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动手学深度学习-pytorch版本(二):线性神经网络

    参考引用 动手学深度学习 神经网络的整个训练过程,包括: 定义简单的神经网络架构、数据处理、指定损失函数和如何训练模型 。经典统计学习技术中的 线性回归 和 softmax 回归 可以视为线性神经网络 1.1 线性回归 回归 (regression) 是能为一个或多个自变量与因变量之间关系建

    2024年02月12日
    浏览(47)
  • 1、动手学深度学习——线性神经网络:线性回归的实现(从零实现+内置函数实现)

    回归(regression)是能为一个或多个自变量与因变量之间关系建模的一类方法。 在自然科学和社会科学领域, 回归经常用来表示输入和输出之间的关系 。 给定一个数据集,我们的目标是 寻找模型的权重和偏置 , 使得根据模型做出的预测大体符合数据里的真实价格。 输出的

    2024年02月11日
    浏览(49)
  • 【动手学深度学习】现代卷积神经网络汇总

    本文为作者阅读学习李沐老师《动手学深度学习》一书的阶段性读书总结,原书地址为:Dive into Deep Learning。 网络结构 实现代码 网络特征 最早发布的卷积神经网络之一。 每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均汇聚层。 网络结构 实现代码 网络特

    2024年02月07日
    浏览(47)
  • 自己动手实现一个深度学习算法——三、神经网络的学习

    这里所说的“学习”是指从训练数据中自动获取最优权重参数的过程 。为了使神经网络能进行学习,将导入 损失函数 这一指标。而学习的目的就是以该损失函数为基准,找出能使它的值达到最小的权重参数。为了找出尽可能小的损失函数的值,利用了 函数斜率的梯度法 。

    2024年02月05日
    浏览(48)
  • 动手学深度学习—卷积神经网络(原理解释+代码详解)

    多层感知机对图像处理是百万维度,模型不可实现。 如果要在图片中找到某个物体,寻找方法应该和物体位置无关。 适合 计算机视觉 的神经网络架构: 平移不变性 :不管检测对象出现在图像中的哪个位置,神经网络前几层应该对相同图像区域有相似的反应。 局部性 :神

    2024年02月14日
    浏览(50)
  • 《动手学深度学习》学习笔记 第9章 现代循环神经网络

    书籍链接: 动手学深度学习 笔记是从第四章开始,前面三章为基础知识,有需要的可以自己去看看 关于本系列笔记: 书里为了让读者更好的理解,有大篇幅的描述性的文字,内容很多,笔记只保留主要内容,同时也是对之前知识的查漏补缺 《动手学深度学习》学习笔记 第

    2024年01月18日
    浏览(51)
  • 《动手学深度学习 Pytorch版》 9.4 双向循环神经网络

    之前的序列学习中假设的目标是在给定观测的情况下对下一个输出进行建模,然而也存在需要后文预测前文的情况。 数学推导太复杂了,略。 双向循环神经网络(bidirectional RNNs)添加了反向传递信息的隐藏层,以便更灵活地处理此类信息。 前向和反向隐状态的更新如下:

    2024年02月07日
    浏览(43)
  • 深度学习——第7章 项目实战:自己动手写一个神经网络模型

    7.1 导入数据集 7.2 定义神经网络输入层、隐藏层、输出层神经元个数 7.3 网络参数W和b初始化 7.4 正向传播过程 7.5 损失函数 7.6 反向传播过程 7.7 网络参数更新 7.8 搭建整个神经网络模型 7.9 模型训练 7.10 模型预测 7.11 隐藏层神经元个数对分类效果的影响 上一课主要介绍了最简

    2024年01月16日
    浏览(36)
  • 【AI】《动手学-深度学习-PyTorch版》笔记(十七):卷积神经网络入门

    我们在前面学习的多层感知机中,已经认识了全链接层,缺点很明显,在稍微大点的网络模型中,参数成指数级别增长。参数量很快就达到数十亿,这样的量级几乎无法计算。为此科学家们想出一个减少参数的方法:卷积。 从全链接层到卷积的推论,使用如下两个原则: 平

    2024年02月13日
    浏览(59)
  • 十 动手学深度学习v2 ——卷积神经网络之NiN + GoogLeNet

    NiN块使用卷积层加两个1x1卷积层 后者对每个像素增加了非线性性 NiN使用全局平均池化层来替代VGG和AlexNet中的全连接层 不容易过拟合,更少的参数个数 Inception块由四条并行路径组成。 前三条路径使用窗口大小为1x1、3x3和5x5的卷积层,从不同空间大小中提取信息。 中间的两条

    2024年02月09日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包