机器学习与深度学习-1-线性回归从零开始实现

机器学习与深度学习-1-线性回归从零开始实现

1 前言

​ 内容来源于沐神的《动手学习深度学习》课程,本篇博客对线性回归从零开始实现(即不调用封装好的库,如SGD优化器、MSE损失函数等)进行重述,并且修改了沐神的课堂示例代码以符合PEP8代码编写规范(如内参、外参等)。我先发布代码实现的文章,过后会把线性回归的数学推导发布。

2 问题背景–以房价预测为例

​ 通常,我们希望通过过去的房价历史数据去预测未来的房价走向。但实际上,房价与很多因素有关。因此为了以房价预测为例子引出线性回归问题,我们做以下假设:

  • 房价只与房屋的面积与房屋年限有关;
  • 房价与两个因素是线性关系

​ 基于以上假设,有如下式子:

p r i c e = ω a r e a ⋅ a r e a   +   ω a g e ⋅ a g e   +   b price = \omega_{area}\cdot area ~+~\omega_{age} \cdot age~+~b price=ωareaarea + ωageage + b
其中, p r i c e price price为回归模型预测的房价; ω a r e a \omega_{area} ωarea ω a g e \omega_{age} ωage为房屋面积与房屋年限的权重,也为模型训练的目标; b b b为偏置项。

3 编程实现

​ 首先,我们先调用一些基本的库:

import random  # 用于生成随机数
import torch  # 导入Pytorch库
from d2l import torch as d2l  # 可视化数据结果

其中,前两个库是基本库。random用于生成随机数,而torch是深度学习的基本框架–Pytorch的库。d2l这个库需要用pip或者conda自行下载。笔者的环境:Python版本:3.10;CUDA版本:11.8;torch版本:2.5.0;GPU:RTX 4060;CPU:i9-14900HX

​ 接着,我们生成数据集:

def create_dataset(input_W, input_b, num_examples):
    """
    生成 y = xw + b + 噪声
    
    :param input_w:权重参数
    :param input_b:偏差参数
    :param num_examples:样本数
    """
    input_x = torch.normal(0, 1, (num_examples, len(input_w)))  # 随机生成输入数据,服从正态分布
    output_y = torch,matmul(input_x, input_w) + input_b  # 计算输出数据
    output_y += torch.normal(0, 0.01, oytput_y.shape)  # 加入噪声
    
    """
    返回数据集,其中通过reshape这个函数去重塑output_y的形状。
    :param -1:自动推断该向量的维度
    :param  1:将output_y变成一列
    
    所以input_x与output_y均为列向量
    """
    return input_x, output_y.reshape((-1, 1))

沐神的代码中,内参与外参用的是同一个变量符号。为了防止因为内参与外参的优先级而导致的变量覆盖,本文将内参的变量符号修改以区别于外参。

​ 定义实际的权重向量与偏差量,并调用刚刚定义好的函数create_dataset生成一个示例数据集:

true_w = torch.tensor([2, -3.4])  # 定义真实的权重
true_b = 4.2  # 定义真实的偏差
features, labels = create_dataset(true_w, true_b, 1000)  # 生成数据集

​ 在控制台打印数据集并输出数据的散点图:

print("features", features[0], "\n label", label[0])  # 在控制台展示生成的数据序列

d2l.set_figsize()  # 设置图窗的尺寸,自动调整一个舒适的尺寸
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)  # 
d2l.plt.show()

有几个函数用法要说明一下:

  • .detach():用于返回一个新的张量,与原张量共享相同的数据,但与计算题目无关联(计算梯度是一个很”贵“的事情);
  • .numpy():将张量格式转换为NumPy数组格式;
  • 1为散点的大小。

​ 接着我们需要根据批量的大小生成批量数据:

def data_iter(input_batch_size, input_features, input_labels):
    """
    生成批量数据
    :param input_batch_size:批量大小
    :param input_features:输入数据
    :param input_labels:输出数据
    :return:返回批量数据
    """
    num_examples = len(input_features)  # 样本数
    indices = list(range(num_examples))  # 样本的索引列表
    random.shuffle(indices)  # 样本的读取顺序随机
    
    for i in range(0, num_examples, input_batch_size):  # 按批量分割样本
        batch_indices = torch.tensor(
            indices[i + min(input_batch_size, num_examples)])  # 生成批量的索引,后面的min()保证索引值不会超出样本
        yield input_features[batch_indices], input_labels[batch_indices]  # 批量的输入输出数据,以迭代器的形式输出(可以节省内存)
    

​ 定义批量大小,并读取批量数据:

batch_size = 32  # 批量大小


for x, y in data_iter(batch_size, features, labels):  # 读取批量大小
    print(x, "\n", y)  # 打印结果
    break
    

​ 实际上这个批量大小的设置是有讲究的,沐神在他的教学案例设置的是10,往后我会结合我的课题出一个深度学习模型设计的一般步骤,在那里会提到。

​ 接着我们要探索出回归效果最好的权重向量,首先进行一个初始化:

w = torch.normal(0, 0.01, size(2, 1), requires_grad=True)  # 初始化权重参数
b = torch.zeros(1, requires_grad=True)  # 初始化偏置

requires_grad这一项的意思是计算其梯度,这一步是优化过程的重要一步。

​ 定义线性回归模型:

def linreg(input_x, input_w, input_b):
    return torch.matmul(input_x, input_w) + input_b

​ 定义损失函数:

def squared_loss(y_hat, output_y):
    return (y_hat - output_y.reshape(y_hat.reshape)) ** 2 / 2

​ 定义小批量随机梯度下降优化算法:

def sgd(params, learning_rate, input_batch_size):
    with torch.no_grad():  # 不跟踪梯度
        for param in params:  # 遍历参数
            param -= learning_rate * param.grad / input_batch_size  # 更新参数
            param.grad.zeros_()  # 清空梯度,减少计算负担

​ 接下来是最重要的训练过程:

lr = 0.03  # 学习率
num_epochs = 50  # 迭代次数
net = linreg  # 线性模型
loss = squared_loss  # MSE损失

for epoch in range(num_epochs):  # 训练模型
    for x, y in data_iter(batch_size, features, labels):  # 读取批量数据
        batch_loss = loss(net(x, w, b), y)  # 计算损失
        batch_loss.sum().backward()  # 反向传播
        sgd([w, b], lr, batch_size)  # 使用小批量随机梯度下降算法更新参数
    with torch.no_grad():  # 不跟踪梯度
        train_l = loss(new(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 结果分析

​ 代码结果:

epoch 1, loss 2.518388
epoch 2, loss 0.396580
epoch 3, loss 0.062917
epoch 4, loss 0.010110
epoch 5, loss 0.001669
epoch 6, loss 0.000314
epoch 7, loss 0.000095
epoch 8, loss 0.000059
epoch 9, loss 0.000054
epoch 10, loss 0.000053
epoch 11, loss 0.000052
epoch 12, loss 0.000052
epoch 13, loss 0.000052
epoch 14, loss 0.000052
epoch 15, loss 0.000052
epoch 16, loss 0.000052
epoch 17, loss 0.000052
epoch 18, loss 0.000052
epoch 19, loss 0.000052
epoch 20, loss 0.000052
epoch 21, loss 0.000052
epoch 22, loss 0.000052
epoch 23, loss 0.000052
epoch 24, loss 0.000052
epoch 25, loss 0.000052
epoch 26, loss 0.000052
epoch 27, loss 0.000052
epoch 28, loss 0.000052
epoch 29, loss 0.000052
epoch 30, loss 0.000052
epoch 31, loss 0.000052
epoch 32, loss 0.000052
epoch 33, loss 0.000052
epoch 34, loss 0.000052
epoch 35, loss 0.000052
epoch 36, loss 0.000052
epoch 37, loss 0.000052
epoch 38, loss 0.000052
epoch 39, loss 0.000052
epoch 40, loss 0.000052
epoch 41, loss 0.000052
epoch 42, loss 0.000052
epoch 43, loss 0.000052
epoch 44, loss 0.000052
epoch 45, loss 0.000052
epoch 46, loss 0.000052
epoch 47, loss 0.000052
epoch 48, loss 0.000052
epoch 49, loss 0.000052
epoch 50, loss 0.000052
w的估计误差为:tensor([0.0001, 0.0002], grad_fn=<SubBackward0>)
b的估计误差为:tensor([0.0004], grad_fn=<RsubBackward1>)

从结果可以看出,模型训练到第十轮左右就收敛了,且训练误差很小,证明训练的效果很好。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】解锁操作系统潜能,高效线程管理的实战技巧

目录 1. 线程的概念2. 线程的理解3. 地址空间和页表4. 线程的控制4.1. POSIX线程库4.2 线程创建 — pthread_create4.3. 获取线程ID — pthread_self4.4. 线程终止4.5. 线程等待 — pthread_join4.6. 线程分离 — pthread_detach 5. 线程的特点5.1. 优点5.2. 缺点5.3. 线程异常…

WPF+MVVM案例实战(二十二)- 制作一个侧边弹窗栏(CD类)

文章目录 1、案例效果1、侧边栏分类2、CD类侧边弹窗实现1、样式代码实现2、功能代码实现3 运行效果4、源代码获取1、案例效果 1、侧边栏分类 A类 :左侧弹出侧边栏B类 :右侧弹出侧边栏C类 :顶部弹出侧边栏D类 :底部弹出侧边栏2、CD类侧边弹窗实现 1、样式代码实现 在原有的…

如何对LabVIEW软件进行性能评估?

对LabVIEW软件进行性能评估&#xff0c;可以从以下几个方面着手&#xff0c;通过定量与定性分析&#xff0c;全面了解软件在实际应用中的表现。这些评估方法适用于确保LabVIEW程序的运行效率、稳定性和可维护性。 一、响应时间和执行效率 时间戳测量&#xff1a;使用LabVIEW的时…

stm32使用串口DMA实现数据的收发

前言 DMA的作用就是帮助CPU来传输数据&#xff0c;从而使CPU去完成更重要的任务&#xff0c;不浪费CPU的时间。 一、配置stm32cubeMX 这两个全添加上。参数配置一般默认即可 代码部分 只需要把上期文章里的HAL_UART_Transmit_IT(&huart2,DATE,2); 全都改为HAL_UART_Tra…

论文1—《基于卷积神经网络的手术机器人控制系统设计》文献阅读分析报告

论文报告&#xff1a;基于卷积神经网络的手术机器人控制系统设计 摘要 本研究针对传统手术机器人控制系统精准度不足的问题&#xff0c;提出了一种基于卷积神经网络的手术机器人控制系统设计。研究设计了控制系统的总体结构&#xff0c;并选用PCI插槽上直接内插CAN适配卡作为上…

「C/C++」C/C++ 之 变量作用域详解

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

JSP ft06 问题几个求解思路整理

刷到这篇文章使用Q-learning去求接JSP ft06 问题用基本Q-learning解决作业车间调度问题(JSP)&#xff0c;以FT06案例为例_q-learning算法在车间调度-CSDN博客 本着贼不走空的原则打算全部copy到本地试下&#xff0c;文章作者使用的tf06.txt在这里获取 https://web.cecs.pdx.e…

Uniapp安装Pinia并持久化(Vue3)

安装pinia 在uni-app的Vue3版本中&#xff0c;Pinia已被内置&#xff0c;无需额外安装即可直接使用&#xff08;Vue2版本则内置了Vuex&#xff09;。 HBuilder X项目&#xff1a;直接使用&#xff0c;无需安装。CLI项目&#xff1a;需手动安装&#xff0c;执行yarn add pinia…

Template Method(模板方法)

1)意图 定义一个操作中的算法骨架&#xff0c;而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 2)结构 模板方法模式的结构图如图7-47 所示。 其中: AbstractClass(抽象类) 定义抽象的原语操作&#xff0c;具体…

无人机场景数据集大全「包含数据标注+划分脚本+训练脚本」 (持续原地更新)

一、作者介绍&#xff1a;六年算法开发经验、AI 算法经理、阿里云专家博主。擅长&#xff1a;检测、分割、理解、AIGC 等算法训练与推理部署任务。 二、数据集介绍&#xff1a; 质量高&#xff1a;高质量图片、高质量标注数据&#xff0c;使用 labelimg 软件吐血标注、整理&…

安当ASP系统:适合中小企业的轻量级Radius认证服务器

安当ASP&#xff08;Authentication Service Platform&#xff09;身份认证系统是一款功能强大的身份认证服务平台&#xff0c;特别适用于中小企业。其中&#xff0c;简约型Radius认证服务器是安当ASP系统中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、主要…

跨域及解决跨域

什么是跨域 前端与后端不在同一个域名下&#xff1a; 解决 import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component;import java.io.IOException…

关于解决DICOM文件中中文乱码问题的解决方案

目录 问题背景 常见字符集和编码 DICOM标准中的字符集支持 解决方案 示例代码 处理不同字符集的示例 关键点 注意事项 结论 在解析DICOM文件时,如果字符集处理不当,可能会出现中文乱码的问题。本文将介绍如何正确处理DICOM文件中的字符集,以避免乱码问题。DICOM文件…

6.机器学习--PCA主成分分析(降维)

目录 1.问题的引入 为什么要降维&#xff1f; 降维的好处 降维的本质 2.降维的主要方法&#xff1a; 2.1 特征选择 2.2 特征抽取 3.主成分分析&#xff08;PCA&#xff09;推导 3.1.向量的表示及基变换 3.2.协方差矩阵及优化目标 3.3.算法及实例 3.4.实例 3.5.代…

我们来学mysql -- 同时使用 AND 和 OR 查询错误(填坑篇)

AND 和 OR 一同使用问题 现象分析处理扩展 现象 业务上在“锁定”当前零件所在出口国的所有零件时&#xff0c;出现其他国家零件 问题定位 分析 or 切断了操作符之间的连续性&#xff0c;从union角度分析 where k1 Td621 and k1 Vda96 or k3 P00009等同 select * fr…

基于Zynq FPGA的雷龙SD NAND存储芯片性能测试

文章目录 前言一、SD NAND特征1.1 SD卡简介1.2 SD卡Block图 二、SD卡样片三、Zynq测试平台搭建3.1 测试流程3.2 SOC搭建 四、软件搭建五、测试结果六、总结 前言 随着嵌入式系统和物联网设备的快速发展&#xff0c;高效可靠的存储解决方案变得越来越重要。雷龙发展推出的SD NA…

vscode翻译插件

vscode翻译插件 需求 &#xff1a; 在编写代码的时候&#xff0c; 打印或者定义变量的时候总是想不起来英文名称&#xff0c; 所有就开发了一款中文转换为英文的插件。 功能 1、目前支持选中中文&#xff0c;右键选择打印或者变量进行转换。 2、目前支持选中中文&#xff0…

信息安全工程师(81)网络安全测评质量管理与标准

一、网络安全测评质量管理 遵循标准和流程 网络安全测评应严格遵循国家相关标准和流程&#xff0c;确保测评工作的规范性和一致性。这些标准和流程通常包括测评方法、测评步骤、测评指标等&#xff0c;为测评工作提供明确的指导和依据。 选择合格的测评团队 测评团队应具备相关…

【C++】lambda表达式的理解与运用(C++11新特性)

&#x1f308; 个人主页&#xff1a;谁在夜里看海. &#x1f525; 个人专栏&#xff1a;《C系列》《Linux系列》 ⛰️ 天高地阔&#xff0c;欲往观之。 目录 前言 C11之前的例子 一、lambda的语法 lambda函数示例&#xff1a; 二、lambda的捕获列表 1.传值捕获 mutable修饰 2.…

K8s资源对象监控之kube-state-metrics详解(Detailed Explanation of Kube State Metrics)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…