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

news2024/11/8 14:24:11

机器学习与深度学习-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>)

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

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

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

相关文章

如何选择适合的AWS EC2实例类型

在云计算的世界中&#xff0c;Amazon Web Services&#xff08;AWS&#xff09;提供了丰富的服务&#xff0c;其中Elastic Compute Cloud&#xff08;EC2&#xff09;是最受欢迎的服务之一。选择合适的EC2实例类型对于确保应用程序的性能和成本效益至关重要。我们九河云通过本文…

(蓝桥杯C/C++)——基础算法(下)

目录 一、时空复杂度 1.时间复杂度 2.空间复杂度 3.分析技巧 4.代码示例 二、递归 1.递归的介绍 2.递归如何实现 3.递归和循环的比较 4.代码示例 三、差分 1.差分的原理和特点 2.差分的实现 3.例题讲解 四、枚举 1.枚举算法介绍 2.解空间的类型 3. 循环枚举解…

7.5 inch电力线载波通信技术

7.5寸电子桌牌 产品型号 PE75R_D_W 尺寸 176.2*137.15*80mm 屏幕尺寸 7.5 inch 显示区域(mm) 163.2(H) * 97.92(V) 分辨率 800*480 显示技术 电子墨水屏双面显示 显示颜色 黑/白/红 外观颜色 银色 工作温度 0-40℃ 视角 180 支持内容格式 文本/图片/二维码…

Linux下的ADC

ADC ADC简介 ADC是 Analog Digital Converter 的缩写&#xff0c;翻译过来为模数转换器&#xff0c;ADC可以将模拟值转换成数字值。模拟值是什么呢?比如我们日常生活中的温度&#xff0c;速度&#xff0c;湿度等等都是模拟值。所以如果我们想测量这些模拟值的值是多少&#x…

星空天文 2.0.1| 完全免费的观星软件,无注册登录,天文爱好者必备。

星空天文是一款完全免费且功能强大的观星软件&#xff0c;适用于安卓平台。无需注册登录即可使用&#xff0c;界面设计精美且操作简单。软件支持AR实景模式&#xff0c;可以将实景与星空结合&#xff0c;增强观星体验。用户可以设定任意日期和时间来观察不同时段的天空&#xf…

书生大模型实战营第四期-入门岛-1. Linux前置基础

入门岛-Linux前置基础 书生大模型实战营-第四期-Linux前置基础&#xff1a; 任务&#xff1a;https://github.com/InternLM/Tutorial/blob/camp4/docs/L0/linux/task.md 文档&#xff1a;https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/linux 任务描述完成所需时…

JavaEE初阶--servlet篇(三)HttpServlet/response/request对应方法使用

文章目录 1.总括说明2.httpservlet父类2.1方法介绍2.2dopost方法的演示2.3doput方法的演示 3.HttpServletRequest类3.1方法说明3.2方法使用演示3.3getparameter方法使用3.4使用form表单的方式3.5jackson获取参数 4.HttpResponse类4.1设置状态码4.2自动进行刷新4.3重定向跳转4.3…

前后端分离,Jackson,Long精度丢失

案例:后端接口放回一个Long数据 GetMapping("/testForLong")public Map<String, Object> testForLong() {Map<String, Object> map new HashMap<>();map.put("aaa", 1234567890123456789L);return map;}实际前端接收的数据 前后端数据…

记某单位众测项目漏洞挖掘中的一些手法

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 一个想当文人的黑客 &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【edusrc漏洞挖掘】 【VulnHub靶场复现】【面试分析】 &#x1f389;欢迎…

用 Python 写了一个天天酷跑(附源码)

Hello&#xff0c;大家好&#xff0c;给大家说一下&#xff0c;我要开始装逼了 这期写个天天酷跑玩一下叭&#xff01; 制作一个完整的“天天酷跑”游戏涉及很多方面&#xff0c;包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言&#xff0c;…

芯片设计公司ERP系统如何实现一体化管理

在当今高科技迅猛发展的时代&#xff0c;芯片设计行业作为信息技术的核心&#xff0c;正面临着日益激烈的市场竞争和复杂多变的市场需求。为了提升企业的运营效率和市场竞争力&#xff0c;芯片设计公司纷纷引入ERP(企业资源计划)系统&#xff0c;以实现一体化管理。接下来我们跟…

50岁+人群月活超1亿,短剧迎来新对手,小程序游戏“收割”中老年

抢夺中老年流量&#xff1a;微短剧向左&#xff0c;小游戏向右 作者&#xff5c;AgeClub 干货抢先看 1.《黑神话&#xff1a;悟空》走红&#xff0c;吸引大量玩家入坑单机市场。与硬核单机游戏不同&#xff0c;在渗透率更高的小游戏领域&#xff0c;聚集了更多“网瘾”中老年…

手机如何打开chm文件

chm文件一般是帮助文档&#xff0c;手机一般不能直接打开&#xff0c;我们可以通过下载阅读器来打开 以荣耀手机为例 首先下载掌阅iReaderAPP 下载完成后打开掌阅 点击书架&#xff0c;右上角本机导入 搜索你下载的chm文件的名字 勾选&#xff0c;加入书架(应该保留目录) 在书…

《重学Java设计模式》之 工厂方法模式

《重学Java设计模式》之 建造者模式 《重学Java设计模式》之 原型模式 《重学Java设计模式》之 单例模式 模拟发奖多种商品 工程结构 奖品发放接口 package com.yys.mes.design.factory.store;public interface ICommodity {/*** Author Sherry* Date 14:20 2024/11/6**/voi…

【算法与数据结构】【链表篇】【题1-题5】

题1.从尾到头打印链表 题目&#xff1a;输入一个链表的头结点&#xff0c;从尾到头反过来打印出每个节点的值。链表的定义如下&#xff1a; struct ListNode {int mValue;ListNode *mNext;ListNode *mPrev; }; 1.1 方法一&#xff1a;栈 思路&#xff1a;要反过来打印&…

28.医院管理系统(基于springboot和vue)

目录 1.系统的受众说明 2. 相关技术和开发环境 2.1 相关技术 2.1.1 Java语言 2.1.2 HTML、CSS、JavaScript 2.1.3 Redis 2.1.4 MySQL 2.1.5 SSM框架 2.1.6 Vue.js 2.1.7 SpringBoot 2.2 开发环境 3. 系统分析 3.1 可行性分析 3.1.1 经济可行性 3.1.2 技术…

Mysql基础 01 数据与sql

文章目录 一、基本概念二、mysql的常用命令三、sql规范四、数据类型五、SQL语句 一、基本概念 数据库(database,DB)&#xff1a;存储数据的仓库。 数据库管理系统软件(Database Management System,DBMS)&#xff1a;是一种操作和管理数据库的大型软件。常见的DBMS有oracle、s…

爬虫-------字体反爬

目录 一、了解什么是字体加密 二. 定位字体位置 三. python处理字体 1. 工具库 2. 字体读取 3. 处理字体 案例1:起点 案例2:字符偏移: 5请求数据 - 发现偏移量 5.4 多套字体替换 套用模板 版本1 版本2 四.项目实战 1. 采集目标 2. 逆向结果 一、了解什么是…

数据分析:宏基因组DESeq2差异分析筛选差异物种

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理:计算步骤:结果:加载R包准备画图主题数据链接导入数据Differential abundance (No BP vs 2BP TA)构建`countData`矩阵过滤低丰度物种构建DESeq数据对象DESeq2差异分析画图Di…

【手撕排序2】快速排序

&#x1f343; 如果觉得本系列文章内容还不错&#xff0c;欢迎订阅&#x1f6a9; &#x1f38a;个人主页:小编的个人主页 &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 ✌️ &#x1f91e; &#x1f91f; &#x1f918; &#x1f919; &#x1f448; &…