动手学深度学习——线性回归(原理解释+代码详解)

news2024/11/25 0:29:00

目录

  • 1、线性回归
  • 2、线性回归模型
    • 2.1 线性模型
    • 2.2 损失函数
      • 2.2.1 平方差损失函数
      • 2.2.2 整个数据集上的损失函数
    • 2.3 随机梯度下降
    • 2.4 用模型进行预测
  • 3、线性回归的简单实现
    • 3.1 生成数据集
    • 3.2 读取数据集
    • 3.3 初始化模型参数
    • 3.4 定义模型
    • 3.5 定义损失函数
    • 3.6 定义优化算法
    • 3.7 训练
  • 4、线性回归的简洁实现
    • 4.1 生成数据集
    • 4.2 读取数据集
    • 4.3 定义模型
    • 4.4 初始化模型参数
    • 4.5 定义损失函数
    • 4.6 定义优化算法
    • 4.7 训练
    • 4.8 小结

1、线性回归

回归是能够为一个或多个自变量与因变量之间关系建模的一类方法。

当函数为未知参数的线性函数时,称为线性回归模型。

机器学习领域中大多数任务通常都与预测有关,当我们预测一个数值时,就会涉及到回归问题。常见的例子有:预测价格,预测需求等。

2、线性回归模型

假设自变量x与因变量y满足线性关系,数学中一般的线性方程为:y=ax+b
我们将y可以表示为x中元素的加权和,并且允许包含观测值的一些噪声,可以将式子设为:
在这里插入图片描述

在机器学习中,线性回归模型建立的步骤一般是:
先假设一个线性模型——>计算该模型预测值与实际值的差距loss(损失函数)——>通过优化算法(如随机梯度下降)来更新参数如w,b来降低误差

2.1 线性模型

一般我们将线性假设可以表示为特征的加权和:

x表示元素的特征。
w称为权重,权重决定了每个特征对我们预测值的影响。
b称为偏置或者偏移量,偏移量指当所有特征值为0时,预测值应该为多少。(对于偏置的加入可以帮助模型有更好的泛化能力,即该模型在未见过的数据也有较好的表现)

如果是房屋的价格可以表示为:

2.2 损失函数

对于我们假设的线性模型,预测值可能离实际值还有差距,为了表示这一差距,我们引入损失函数这一概念。

损失函数能够量化目标的实际值与预测值之间的差距,通常选择非负数作为损失,且数值越小表示损失越小。

2.2.1 平方差损失函数

回归问题中最常用的损失函数是平方误差函数。在这里插入图片描述
常数1/2便于我们在对损失函数(平方项)求导时,能够将系数化为1

2.2.2 整个数据集上的损失函数

为了度量模型能够在整个数据集上的质量,我们需计算训练集n个样本的损失均值。
即上式求和再除以n(含参数w,b的为展开式)
在这里插入图片描述
我们的目标则是为了寻得一组参数w*,b*,使最小化训练样本的总损失
在这里插入图片描述

2.3 随机梯度下降

如上文所说,我们为了使总损失最小,我们需要对参数w和b进行更新。
而更新方法则是使用到一种叫做梯度下降的方法,它不断在损失函数递减的方向上更新参数。

梯度下降的简单用法是计算损失函数关于模型参数的导数(可以称为梯度),损失函数为数据集中所有样本的损失均值。

实际过程中由于数据集较大,每次更新参数会遍历整个数据集,执行会非常缓慢。我们通常会在每次更新的时候抽取一小批量样本,这种变体叫做小批量随机梯度下降。

每次迭代中,该过程为:
1、首先随机抽取一个小批量β,它是由固定数量的训练样本组成
2、计算小批量的平均损失关于模型参数的导数
3、将梯度乘以一个预先确定的正数η,并从当前参数的值中减掉
在这里插入图片描述
其中∂表示偏导数,η表示学习率,批量大小和学习率的值通常是手动预先设定的,这些可以调整但不在训练过程中更新的参数称为超参数。

2.4 用模型进行预测

给定“已学习”的线性回归模型在这里插入图片描述
我们现在可以通过房屋面积x1和房龄x2来估计一个(未包含在训练数据中的)新房屋价格。
给定特征估计目标的过程通常称为预测或推断。

3、线性回归的简单实现

了解到关键思路后,我们可以通过代码来实现线性回归。
下面的代码有些是调用或者定义的函数,刚开始学习的时候不必纠结代码,主要了解代码的整体实现过程。

步骤函数
生成数据集在这里插入图片描述
读取数据集在这里插入图片描述
初始化模型参数在这里插入图片描述
定义模型在这里插入图片描述
定义损失函数在这里插入图片描述
定义优化算法在这里插入图片描述
训练在这里插入图片描述

3.1 生成数据集

生成一个包含1000个样本的数据集,每个样本包含从标准正态分布中采用的2个特征。

线性模型参数
在这里插入图片描述
生成的数据集及标签:
在这里插入图片描述
噪声项ε可以视为模型预测和标签时的潜在观测误差,它服从均值为0的正态分布,标准差为0.01。

#matplotlib包用于作图,且设置成嵌入显示
%matplotlib inline
import random
import torch
from d2l import torch as d2l
def synthetic_data(w, b, num_examples):  #@save
    """生成y=Xw+b+噪声"""
    # normal:返回一个张量,包含从指定均值means和标准差std的离散正态分布抽取的一组随机数
    X = torch.normal(0, 1, (num_examples, len(w))) #均值为0,方差为1

	# matmul:矩阵乘法
    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)

注意,features中的每一行都包含一个二维数据样本,labels中的每一行都包含一维标签值(一个标量)。
在这里插入图片描述

3.2 读取数据集

训练模型要对数据集进行遍历,每次抽取一小批量,并使用它们来更新模型。

data_iter函数,该函数接收批量大小、特征矩阵和标签向量作为输入,生成大小为batch_size的小批量。每个小批量包含一组特征和标签。
在这里插入图片描述

random.shuffle()——打乱顺序
indices[i: min(i + batch_size, num_examples)])——按batch_size进行切片,得到小批量

# features:特征矩阵,labels:标签向量
def data_iter(batch_size, features, labels):
	# len():求矩阵时长度相当于输出行的数目
    num_examples = len(features)
    # 生成标号,列表形式储存
    indices = list(range(num_examples))
    # 这些样本是随机读取的,没有特定的顺序
    random.shuffle(indices)

	# 构造随机样本,打乱样本,等间隔访问,达到随机
	# 从0开始,到num_exampls结束,每次间隔batc_size
    for i in range(0, num_examples, batch_size):
        batch_indices = torch.tensor(
            indices[i: min(i + batch_size, num_examples)])
        # yield:返回一个值,并且记住这个返回的位置,下次迭代从这个位置开始
        yield features[batch_indices], labels[batch_indices]

3.3 初始化模型参数

我们通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重, 并将偏置初始化为0。
初始化参数后,我们的任务是更新这些参数,直到这些参数足够拟合我们的数据。

每次更新都需要计算损失函数关于模型参数的梯度。 有了这个梯度,我们就可以向减小损失的方向更新每个参数。

torch.normal(means, std, out=None)均值,标准差,可选的输出张量

# 此时size定义两行一列
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)

#  requires_grad用于说明当前向量是否需要在计算中保留对应的梯度信息
b = torch.zeros(1, requires_grad=True)

3.4 定义模型

线性回归模型:y=wx+b

def linreg(X, w, b):  #@save
    """线性回归模型"""
    return torch.matmul(X, w) + b

3.5 定义损失函数

采取平方损失函数
在这里插入图片描述
y.reshape(y_hat.shape)将y的形状统一为y_hat

# y_hat是预测值, y是真实值
def squared_loss(y_hat, y):  #@save
    """均方损失"""
    # 返回平方误差
    return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

3.6 定义优化算法

小批量随机梯度下降:在每一步中,使用从数据集中抽取的一个小批量,然后根据参数计算损失的梯度。接下来,朝着减少损失的方向更新我们的参数。

每一步更新的大小由学习速率lr决定这里是引用

with torch.no_grad()
强制之后的内容不计算梯度。
在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的。


def sgd(params, lr, batch_size):  #@save
    """小批量随机梯度下降"""
    with torch.no_grad():
        for param in params:
        	# param.grad是求梯度
            param -= lr * param.grad / batch_size
            
            # 因为pytorch不会自动将梯度设置为0,设置为零后下次计算就不会与上次相关了
            param.grad.zero_()

3.7 训练

训练过程可以概括为:

  1. 在每次迭代中,读取一小批量训练样本,并通过模型来获得一组预测。
  2. 计算完损失后,开始反向传播,存储每个参数的梯度。
  3. 调用优化算法sgd来更新模型参数。
    这里是引用
lr = 0.03 #学习率(超参数)
num_epochs = 3 #把整个数据扫3遍
net = linreg #模型生成函数
loss = squared_loss #均方损失函数

for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):
    	# 'X'和'y'的小批量损失
    	# 因为'l'形状是('batch_size',1),而不是一个标量。l中的所有元素被加到一起,
        # 并以此计算关于[w,b]的梯度
        l = loss(net(X, w, b), y)  # X和y的小批量损失
 
 		# 求和之后算梯度,这里backward()会对w和b进行求导
        l.sum().backward()
        sgd([w, b], lr, batch_size)  # 使用参数的梯度更新参数

	# net(features, w, b):预测值
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels) 
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {true_b - b}')

输出:损失与估计误差
在这里插入图片描述
在这里插入图片描述

4、线性回归的简洁实现

这里采用深度学习框架来简洁实现线性回归模型,我们不必单独分配参数、不必定义我们的损失函数,也不必手动实现小批量随机梯度下降。,可以直接调用API来进行训练。

API(Application Programming Interface)应用程序接口。

4.1 生成数据集

d2l包:由李沐老师等人开发的《动手学深度学习》配套的包,提供一些数学运算工具。
synthetic_data():合成数据函数。

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)

next(iter(data_iter))使用iter构造Python迭代器,并使用next从迭代器中获取第一项。

4.2 读取数据集

TensorDataset 将张量的第一个维度视为数据集大小的维度,数据集在传入 DataLoader 后,该维度也是 batch_size 所在的维度。
shuffle表示对数据打乱顺序。

def load_array(data_arrays, batch_size, is_train=True):  #@save
    """构造一个PyTorch数据迭代器"""
    # 将传入的特征和标签作为list传到TensorDataset,里面得到一个pytorch的数据集
    dataset = data.TensorDataset(*data_arrays)
    # 调用Dataloader每次从dataset里面挑选batch_size个样本出来
    return data.DataLoader(dataset, batch_size, shuffle=is_train)

batch_size = 10
# 将特征和标签传入load_array
data_iter = load_array((features, labels), batch_size)

4.3 定义模型

对于标准深度学习模型,我们可以使用框架的预定义好的层。
首先定义一个模型变量net,它是一个Sequential类的实例。 Sequential类将多个层串联在一起。 当给定输入数据时,Sequential实例将数据传入到第一层, 然后将第一层的输出作为第二层的输入,以此类推。

Sequential类可以看成一个容器包装各层,当一个模型较简单的时候,我们可以使用torch.nn.Sequential类来实现简单的顺序连接模型。

# nn是神经网络的缩写
from torch import nn

# 第一个指定输入特征形状为2,第二个指定输出特征形状为单个标量为1
net = nn.Sequential(nn.Linear(2, 1))

4.4 初始化模型参数

在使用net之前,我们需要初始化模型参数。在这里,我们指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样, 偏置参数将初始化为零。

# net[0] 表示第0层,.weight访问w,data就是w的值,下划线的意思是,使用正态分布,替换掉权重data的值
net[0].weight.data.normal_(0, 0.01)
# 使用填充0,data是偏置b,替换掉偏差data的值
net[0].bias.data.fill_(0)

4.5 定义损失函数

计算均方误差使用的是MSELoss类,也称为平方L2范数。 默认情况下,它返回所有样本损失的平均值。

loss = nn.MSELoss()

4.6 定义优化算法

这里使用小批量随机梯度下降算法,该算法在PyTorch在optim模块中。
当我们实例化一个SGD实例时,我们要指定优化的参数 (可通过net.parameters()从我们的模型中获得)以及优化算法所需的超参数字典。 小批量随机梯度下降只需要设置lr值,这里设置为0.03。

net.parameters()是一个生成器,用于生成模型中的参数。其中,第一个参数是生成器的第一个元素,第二个参数是该元素的具体参数值。该函数用循环获取所有参数,并将其作为参数传递。

# net.parameters():net里面的所有参数,包括w,b,然后指定学习率lr
trainer = torch.optim.SGD(net.parameters(), lr=0.03)

4.7 训练

在每个迭代周期里,我们将完整遍历一次数据集(train_data), 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量,我们会进行以下步骤:

  1. 通过调用net(X)生成预测并计算损失l(前向传播)。
  2. 通过进行反向传播来计算梯度。
  3. 通过调用优化器来更新模型参数。
num_epochs = 3 #迭代3次
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y) #因为net自带参数,所以和之前不同的是不需要再传进去w和b
        trainer.zero_grad() #梯度清零
        l.backward()  #计算梯度
        trainer.step() #调用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)

输出:损失和w、b的估计误差
在这里插入图片描述
在这里插入图片描述

4.8 小结

  • 可以使用PyTorch的高级API更简洁地实现模型。
  • 在PyTorch中,data模块提供了数据处理工具,nn模块定义了大量的神经网络层和常见损失函数。

参考资料:
[1]动手学深度学习:http://zh-v2.d2l.ai/index.html
[2]跟李沐学AI:https://space.bilibili.com/1567748478

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/754209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

H3C-Cloud Lab实验-OSPF配置实验

一、实验拓扑图 实验需求: 1、按照图示配置 IP 地址 2、按照图示分区域配置 OSPF ,实现全网互通 3、为了路由结构稳定,要求路由器使用环回口作为 Router-id,ABR 的环回口宣告进骨干区域 4、掌握OSPF初始化流程、路由表学习的过…

基于linux下的高并发服务器开发(第一章)- GDB调试(2)1.14

(1)执行 gcc test.c -o test -g ,生成test文件 (2)gdb test (3)list 查看当前文件代码 list/l (从默认位置显示) (4)l 20 list/l 行号 &#xf…

kafka(一)

一:kafka架构介绍 1. Brokers kafka集群包括一个或者多个服务器,服务器的节点叫做broker。 2. Topic 类似于数据库中的table。物理上不通的topic会分开存储。一个topic的消息会存储在多个broker上。但是在读取的时候,只要选择好topic&…

Centos Stream9安装Neovim的详细过程

Centos Stream9下的Neovim的安装步骤: 安装neovim Index of /pub/epelhttps://dl.fedoraproject.org/pub/epel/ yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm yum install -y neovim python3-neovim yum install -y …

【MySQL】不允许你不会全文本搜索

🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正&#xff0…

【ShenYu系列】ShenYu网关条件匹配的设计及原理分析

ShenYu网关中用到了很多有趣的设计,我对其中的条件匹配的实现尤其感兴趣,所以研究一下具体实现的原理。我这边用到的shenyu版本是2.6.0-SNAPSHOT。 应用入口 原理拆解 AbstractShenyuPlugin#execute,获取到SelectorData集合,进行…

Inkscape扩展脚本入门

Inkscape官网 https://inkscape.org/ 建议下载1.3版本 官方插件脚本文档 https://inkscape-extensions-guide.readthedocs.io/en/latest/index.html 但这个文档似乎和当前版本不符合,直接按照其内的方法写脚本会有问题 Inkscape插件加载目录 默认情况下&…

LVGL开发:配置模拟器学习LVGL V8.3

文章目录 模拟器配置常用控件学习基本知识WidgetEvents 输入设备ImagesScreen 参考 模拟器配置 LVGL支持多种IDE下配置模拟器: 在WINDOWS下面,大家最常使用的是VS2019,为了和大家保持一致,这里也使用VS2019进行配置。 首先&…

Matlab export_fig 输出高清图片和部分运行错误问题

Matlab export_fig 输出占空间较小的矢量高清图和部分运行错误问题 Matlab export_fig 的安装与运行错误export_fig 配置:安装后一直提示加载Ghostscript运行错误export_fig输出pdf的本质过程export_fig介绍几种生成图片的大小 Matlab export_fig 的安装与运行错误 …

mysql数据库备份与还原、索引、视图

一、备份与还原 /***************************样例表***************************/ CREATE DATABASE booksDB; use booksDB; CREATE TABLE books ( bk_id INT NOT NULL PRIMARY KEY, bk_title VARCHAR(50) NOT NULL, copyright YEAR NOT NULL …

Transaction事务使用了解

1.功能概述 ​ 在wiki的解释中,事务是一组单元化的操作,这组操作可以保证要么全部成功,要么全部失败(只要有一个失败的操作,就会把其他已经成功的操作回滚)。 ​ 这样的解释还是不够直观,看下…

利用BP网络输电线路故障诊断(Python代码,压缩包带有数据集和代码,解压缩可直接运行)

1.数据集介绍 将故障区分为具体的不同类型:单相短路故障、两相接地短路故障、两相相间故障、三相相间短路故障。这里随意举出每种类别的两个样本进行展示。 GCBAIaIbIcVaVbVc1001-151.2918124-9.67745156385.800162260.400749853-0.132934945-0.2678149071001-336…

git下载源码及环境搭建之前端(三)

学习目标: vue 新项目的 前端环境搭建 vue 项目在 使用 Visual Studio Code 开发前端项目环境的搭建及 相关文件的配置 操作步骤: 前端: 下图所示为开发时前端所用的编辑器 注意:在配置时 有时候 localhost 可能 不太好用&…

小程序源码开发带司机入驻搬家拉货线上接单多端合一

1.注册与登录: 用户可以注册账号并登录到小程序,以便进行后续操作和管理。 2.货物管理: 用户可以添加、编辑和删除货物信息。 货物信息包括货物名称、数量、重量、尺寸、装载方式等。 3.车辆管理: 用户可以添加、编辑和删除…

8.postgresql--Update join 和 Delete using

Update join Update join用于基于另一张表更新表数据,语法如下: UPDATE t1 SET t1.c1 new_value FROM t2 WHERE t1.c2 t2.c2;CREATE TABLE product_segment (id SERIAL PRIMARY KEY,segment VARCHAR NOT NULL,discount NUMERIC (4, 2) );INSERT INTO…

【数学建模】——拟合算法

【数学建模】——拟合算法 拟合算法定义:与插值问题不同,在拟合问题中不需要曲线一定经过给定的点。拟合问题的目标是寻求一个函数(曲线),使得该曲线在某种准则下与所有的数据点最为接近,即曲线拟合的最好&…

【微信小程序-uniapp】CustomPickerMul 自定义多选选择器组件

1. 效果图 2. 组件完整代码 <template><view class="custom-picker-mul"><view :class&#

MFC学习之2048小游戏程序源码

2048游戏的开发原理相对简单&#xff0c;它基于一个4x4的方格&#xff0c;通过控制数字方块的移动来合成相同的数字方块&#xff0c;并生成新的数字方块。 具体实现过程如下&#xff1a; 确定需求&#xff1a;首先需要明确游戏的功能需求&#xff0c;如产生随机数字方块、控制…

PostgreSQL的进程架构和内存架构

文章首发地址 PostgreSQL的进程架构 PostgreSQL的进程架构是由多个进程组成的&#xff0c;每个进程都有不同的作用和职责。下面是PostgreSQL的进程架构的详细说明&#xff1a; 后台进程(Postmaster) 后台进程是PostgreSQL启动时创建的第一个进程&#xff0c;它负责管理和控…

Android oom_adj 详细解读

源码基于&#xff1a;Android R 0. 前言 在博文《oom_adj 内存水位算法剖析》一文中详细的分析了lmkd 中针对 oom_adj 内存水位的计算、使用方法&#xff0c;在博文《oom_adj 更新原理(1)》、《oom_adj 更新原理(2)》中对Android 系统中 oom_adj 的更新原理进行了详细的剖析。…