当前位置: 首页 > news >正文

【机器学习】向量化使得简单线性回归性能提升

向量化使得简单线性回归性能提升

  • 一、摘要
  • 二、向量化运算概述
  • 三、向量化运算在简单线性回归中的应用
  • 四、性能测试与结果分析

一、摘要

本文主要讲述了向量化运算在简单线性回归算法中的应用。通过回顾传统for循环方式实现的简单线性回归算法,介绍了如何通过最小二乘法计算a的值。然而,这种方式在计算性能上存在效率较低的问题。为了提高性能,视频引入了向量化运算的概念,即将计算过程从循环方式转变为向量之间的计算。通过向量化运算,可以快速地计算出结果,相比传统的for循环方式,在性能上具有显著的优势。视频还强调了向量化运算需要基于推导的结果进行,对于入门级别的同学来说,可以先实现更清晰的程序版本,再基于这个版本进行向量化,以更好地理解算法的原理。

二、向量化运算概述

向量化概述

  1. 向量化运算是一种重要的概念,可以提高计算性能。
  2. 通过将计算转换为向量之间的运算,可以大大提升性能。

向量化运算性能高的原因
在计算机学科中,向量化运算通常比for循环等具有更好的计算性能,主要原因如下:

  1. 硬件层面
  • 利用SIMD指令集:现代计算机的CPU通常支持单指令多数据(SIMD)指令集,如Intel的SSE、AVX等。向量化运算能够直接利用这些指令集,在一条指令中同时对多个数据元素进行相同的操作,例如可以同时对4个或8个单精度浮点数进行加法运算。而for循环每次只能处理一个数据元素,需要多条指令来完成相同数量数据的操作,这使得向量化运算在数据处理效率上有天然的优势。
  • 提高缓存命中率:向量化运算通常会连续访问内存中的数据,这有利于提高CPU缓存的命中率。因为数据在内存中是连续存储的,当加载一个数据元素时,相邻的数据元素也很可能被加载到缓存中,后续对这些数据的访问就可以直接从缓存中获取,大大加快了访问速度。相比之下,for循环可能会以非连续的方式访问数据,导致缓存失效的情况更频繁,需要从内存中多次读取数据,增加了访问时间。
  1. 软件层面
  • 减少指令开销:for循环需要在每次迭代时执行循环控制指令,如比较、跳转等,这些指令会增加额外的开销。而向量化运算将多个数据的处理合并为一个操作,减少了指令的数量和执行时间,从而提高了整体性能。
  • 编译器优化:编译器对向量化运算的优化能力更强。编译器可以识别向量化的代码模式,并对其进行更高级的优化,如自动展开循环、调整指令顺序等,以充分利用硬件的特性。对于for循环,虽然编译器也能进行一些优化,但由于其灵活性较高,编译器很难像对向量化运算那样进行深度优化。
  • 并行执行能力:向量化运算更适合并行计算。在多核处理器或GPU等并行计算环境中,向量化运算可以很容易地将数据划分到不同的核心或线程中进行并行处理,从而进一步提高计算速度。for循环虽然也可以通过一些方式实现并行化,但需要更多的代码调整和同步操作,实现起来相对复杂,且可能存在数据竞争等问题,影响性能。

三、向量化运算在简单线性回归中的应用

  1. 在简单线性回归中,a斜率)的计算方式可以通过向量化运算来优化
  2. 通过将计算转换为向量点乘,可以避免使用for循环,提高效率
  3. 向量化运算的实现
    • 基于上一篇博文中的SimpleLinearRegressionModel类所在工程中文件改名成为SimplyLearnRegressionDemo.py,然后在其中新建一个SimpleLinearRegressionVectorModel类,使得fit函数通过向量化运算来计算a和b。
    • 通过使用numpy的dot方法,实现了向量点乘,提高了计算速度。
    • 具体SimpleLinearRegressionVectorModel代码如下:
      import numpy as npclass SimpleLinearRegressionModel:def __init__(self):# 初始化线性回归模型的参数a和b为Noneself.a_ = Noneself.b_ = Nonedef fit(self, x_train, y_train):"""根据训练数据集x_train,y_train训练Simple Linear Regression模型"""# 断言x_train的维度为1,确保是单特征训练数据assert x_train.ndim == 1, \"Simple Linear Regressor can only solve single feature training data."# 断言x_train和y_train的长度相等,确保数据匹配assert len(x_train) == len(y_train), \"the size of x_train must be equal to the size of y_train"# 先分别求出x和y的均值x_mean = np.mean(x_train)y_mean = np.mean(y_train)# 先求a的分子部分numerator = 0.0  # 分子denominator = 0.0  # 分母# 遍历训练数据,计算分子和分母for x_i, y_i in zip(x_train, y_train):numerator += (x_i - x_mean) * (y_i - y_mean)denominator += (x_i - x_mean) ** 2# 然后计算a的值self.a_ = numerator / denominator# 最后计算b的值self.b_ = y_mean - self.a_ * x_meanreturn selfdef predict(self, x_predict):"""给定待预测数据集x_predict,返回表示x_predict的结果向量"""# 断言x_predict的维度为1,确保是单特征数据assert x_predict.ndim == 1, \"Simple Linear Regressor can only solve single feature training data."# 断言模型已经训练过(a_和b_不为None)assert self.a_ is not None and self.b_ is not None, \"must fit before predict!"# 对每个待预测数据调用_predict方法,生成预测结果数组return np.array([self._predict(x) for x in x_predict])def _predict(self, x_single):"""给定单个待预测数据x_single,返回x_single的预测结果值"""# 根据训练得到的参数a_和b_进行预测计算return self.a_ * x_single + self.b_def __repr__(self):# 返回模型的字符串表示形式return "SimpleLinearRegressionModel()""""向量化的方式实现简单线性回归的算法"""class SimpleLinearRegressionVectorModel:def __init__(self):# 初始化线性回归模型的参数a和b为Noneself.a_ = Noneself.b_ = Nonedef fit(self, x_train, y_train):"""根据训练数据集x_train,y_train训练Simple Linear Regression模型"""# 断言x_train的维度为1,确保是单特征训练数据assert x_train.ndim == 1, \"Simple Linear Regressor can only solve single feature training data."# 断言x_train和y_train的长度相等,确保数据匹配assert len(x_train) == len(y_train), \"the size of x_train must be equal to the size of y_train"# 先分别求出x和y的均值x_mean = np.mean(x_train)y_mean = np.mean(y_train)# 先求a的分子部分# 向量化的方式实现numerator = (x_train - x_mean).dot(y_train - y_mean)denominator = (x_train - x_mean).dot(x_train - x_mean)# 然后计算a的值self.a_ = numerator / denominator# 最后计算b的值self.b_ = y_mean - self.a_ * x_meanreturn selfdef predict(self, x_predict):"""给定待预测数据集x_predict,返回表示x_predict的结果向量"""# 断言x_predict的维度为1,确保是单特征数据assert x_predict.ndim == 1, \"Simple Linear Regressor can only solve single feature training data."# 断言模型已经训练过(a_和b_不为None)assert self.a_ is not None and self.b_ is not None, \"must fit before predict!"# 对每个待预测数据调用_predict方法,生成预测结果数组return np.array([self._predict(x) for x in x_predict])def _predict(self, x_single):"""给定单个待预测数据x_single,返回x_single的预测结果值"""# 根据训练得到的参数a_和b_进行预测计算return self.a_ * x_single + self.b_def __repr__(self):# 返回模型的字符串表示形式return "SimpleLinearRegressionVectorModel()"
      

四、性能测试与结果分析

  1. 在jupyter中进行性能测试

    # 导入在PyCharm中封装好的工程项目
    import sys
    project_path = 'D:/PycharmProjects/pythonProject/'
    if project_path not in sys.path:sys.path.append(project_path)from SimpleLinearRegressionDemo import SimpleLinearRegressionModel
    from SimpleLinearRegressionDemo import SimpleLinearRegressionVectorModel# for循环实现的
    sreg = SimpleLinearRegressionModel()
    # 向量化实现的
    vreg = SimpleLinearRegressionVectorModel()# 定义一个随机的测试数据
    num = 100000
    # 自定义线性方程中的x,随机给定
    big_x = np.random.random(size=num)
    # 定义线性方程中的y,其中np.random.normal(size=num)是给定了一个噪声
    big_y = big_x * 2.0 + 3.0 + np.random.normal(size=num)# 使用魔法命令%timeit计算程序执行所花时间
    %timeit sreg.fit(big_x,big_y)
    %timeit vreg.fit(big_x,big_y)
    

    执行结果如下:

    51.9 ms ± 546 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    760 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
    

    下面为你详细解释其含义:
    第一行:51.9 ms ± 546 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

    • 51.9 ms:这是每次循环的平均执行时间,单位是毫秒(ms),也就是说该代码每次循环平均花费 51.9 毫秒来执行。
    • ± 546 µs:这表示测量结果的标准差,单位是微秒(µs)。标准差反映了多次测量结果的离散程度,这里说明每次循环执行时间在平均时间 51.9 毫秒左右波动,波动范围大约是正负 546 微秒。
    • mean ± std. dev. of 7 runs, 10 loops each:这描述了测量的具体方式。7 runs 表示进行了 7 次独立的测试运行;10 loops each 表示每次运行中代码循环执行了 10 次。最终的平均时间和标准差是基于这 7 次运行,每次 10 个循环的所有测量结果计算得出的。

    第二行:760 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

    • 760 µs:每次循环的平均执行时间,单位是微秒(µs),即该代码每次循环平均花费 760 微秒来执行。
    • ± 11.9 µs:测量结果的标准差,单位是微秒。说明每次循环执行时间在平均时间 760 微秒左右波动,波动范围大约是正负 11.9 微秒。
    • mean ± std. dev. of 7 runs, 1,000 loops each:同样描述了测量方式。进行了 7 次独立的测试运行,每次运行中代码循环执行了 1000 次,平均时间和标准差是基于这些测量结果计算的。

    对比分析

    • 从这两组数据可以看出,第二组代码的执行效率明显高于第一组。第二组每次循环平均耗时 760 微秒,而第一组每次循环平均耗时 51.9 毫秒(即 51900 微秒)。你可以根据这些性能数据来优化代码或者选择更高效的实现方式。

    在jupyter中执行过程:
    在这里插入图片描述

  2. 结果显示,向量化运算实现的SimpleLinearRegressionVectorModel性能大幅提升,达到了68倍的速度提升

相关文章:

【机器学习】向量化使得简单线性回归性能提升

向量化使得简单线性回归性能提升 一、摘要二、向量化运算概述三、向量化运算在简单线性回归中的应用四、性能测试与结果分析 一、摘要 本文主要讲述了向量化运算在简单线性回归算法中的应用。通过回顾传统for循环方式实现的简单线性回归算法,介绍了如何通过最小二乘…...

【kafka系列】消费者

目录 获取消息 1. 消费者获取消息的流程逻辑分析 阶段一:消费者初始化 阶段二:分区分配与重平衡(Rebalance) 阶段三:消息拉取与处理 阶段四:偏移量提交 核心设计思想 2. 流程 关键点总结 常见参数…...

HackerRank C++面试,中等难度题目 - Attribute Parser

去除字符串首尾的空白字符(包括空格、制表符、换行符和回车符) void trim(string &s) {size_t start s.find_first_not_of(" \t\n\r");size_t end s.find_last_not_of(" \t\n\r");if (start string::npos) {s ""…...

【ARM】解决ArmDS Fast Models 中部分内核无法上电的问题

1、 文档目标 解决ArmDS Fast Models 中部分内核无法上电的问题。 2、 问题场景 在调用ArmDS的Fast Models中的Cortex-A55的模型,只有Core 0是上电状态,而Core 1处于掉电状态,如图2-1所示: 图2-1 3、软硬件环境 1)…...

节目选择器安卓软件编写(针对老年人)

文章目录 需求来源软件界面演示效果源码获取 对爬虫、逆向感兴趣的同学可以查看文章,一对一小班教学:https://blog.csdn.net/weixin_35770067/article/details/142514698 需求来源 由于现在的视频软件过于复杂,某客户想开发一个针对老年人、…...

蓝桥杯之图

图&#xff1a; 对于图来说&#xff0c;重点在于之后的最短路径算法&#xff0c;这边简单做一下了解即可 代码&#xff1a; #include<iostream> #include<string> #include<vector> #include<list> #include<queue> using namespace std; clas…...

中兴光猫修改SN,MAC,修改地区,异地注册,改桥接,路由拨号

前言 请先阅读上一篇博客获取到光猫超级密码电信光猫获取超级密码 电信光猫天翼网关4.0获取超级密码教程 四川电信光猫 中兴 F1855V2 ZXHN F1855V2 telent权限 实战 实测_天翼4.0光猫超级密码-CSDN博客 修改SN-修改地区&#xff0c;光猫异地注册&#xff0c;设置桥接模式&#…...

【kafka系列】Kafka如何保证消息不丢失?

目录 1. 生产者端&#xff1a;确保消息成功发送到Broker 核心机制&#xff1a; 关键步骤&#xff1a; 2. Broker端&#xff1a;持久化与副本同步 核心机制&#xff1a; 关键源码逻辑&#xff1a; 3. 消费者端&#xff1a;可靠消费与Offset提交 核心机制&#xff1a; 关…...

AtCoder Beginner Contest 393 —— E - GCD of Subset 补题 + 题解 python

AtCoder Beginner Contest 393 E - GCD of Subset Problem Statement You are given a sequence A ( A 1 , A 2 , … , A N ) A (A_1, A_2, \dots, A_N) A(A1​,A2​,…,AN​) of length N N N and a positive integer K K K (at most N N N). For each i 1 , 2 , … …...

vue3响应式丢失解决办法(三)

vue3的响应式的理解&#xff0c;与普通对象的区别&#xff08;一&#xff09; vue3 分析总结响应式丢失问题原因&#xff08;二&#xff09; 经过前面2篇文章&#xff0c;知道了响应式为什么丢失了&#xff0c;但是还是碰到了丢失情况&#xff0c;并且通过之前的内容还不能解…...

BY组态:构建灵活、可扩展的自动化系统

引言 在现代工业自动化领域&#xff0c;BY组态&#xff08;Build Your Own Configuration&#xff09;作为一种灵活、可扩展的解决方案&#xff0c;正逐渐成为工程师和系统集成商的首选。BY组态允许用户根据具体需求自定义系统配置&#xff0c;从而优化生产效率、降低成本并提…...

2025 (ISC)²CCSP 回忆录

2025.1.20 广州&#xff0c;周一&#xff0c;我一次性通过了CCSP的考试。 为什么要考证&#xff1f; 个人成长所需 职业热情&#xff1a;做一行爱一行&#xff0c;既然我投入了美好的青春年华到网络安全行业当中&#xff0c;那么对于这个行业最有权威的认证&#xff0c;是肯定…...

强化学习笔记7——DDPG到TD3

前提&#xff1a;基于TD 的方法多少都会有高估问题&#xff0c;即Q值偏大。原因两个&#xff1a;一、TD目标是真实动作的高估。 二&#xff1a;自举法高估。 DDPG 属于AC方法&#xff1a;异策略&#xff0c;适合连续动作空间&#xff0c;因为他的策略网络直接输出的动作&#…...

win10 系统 自定义Ollama安装路径 及模型下载位置

win10 系统 自定义Ollama安装路径 及模型下载位置 由于Ollama的exe安装软件双击安装的时候默认是在C盘&#xff0c;以及后续的模型数据下载也在C盘&#xff0c;导致会占用C盘空间&#xff0c;所以这里单独写了一个自定义安装Ollama安装目录的教程。 Ollama官网地址&#xff1…...

-bash:/usr/bin/rm: Argument list too long 解决办法

问题概述 小文件日志太多导致无法使用rm命令&#xff0c;因为命令行参数列表的长度超过了系统允许的最大值。 需要删除/tmp目录下的所有文件&#xff0c;文件数量比较多。 ls -lt /tmp | wc -l 5682452 解决方法如下&#xff1a; 使用find -exec 遍历&#xff0c;然后执行删…...

内容中台重构企业内容管理流程驱动智能协作升级

内容概要 内容中台作为企业数字化转型的核心基础设施&#xff0c;通过技术架构革新与功能模块整合&#xff0c;重构了传统内容管理流程的底层逻辑。其核心价值在于构建动态化、智能化的内容生产与流转体系&#xff0c;将分散的创作、存储、审核及分发环节纳入统一平台管理。基…...

python实现YouTube关键词爬虫(2025/02/11)

在当今数字化时代&#xff0c;YouTube作为全球最大的视频分享平台之一&#xff0c;拥有海量的视频资源。无论是进行市场调研、内容创作还是学术研究&#xff0c;能够高效地获取YouTube上的相关视频信息都显得尤为重要。今天&#xff0c;我将为大家介绍一个基于Python实现的YouT…...

【效率技巧】怎么做思维导图||数学思维||费曼学习法

目录标题 常见问题&#xff1a;认知误区和建议&#xff1a;思维导图按照功能分类思维导图好处步骤&#xff08;拆解的步骤&#xff09; 常见问题&#xff1a; 1、做好的思维导图浪费时间 2、做简单的思维导图没有效果 认知误区和建议&#xff1a; 1、做思维导图工具&#xf…...

LabVIEW与USB设备开发

开发一台USB设备并使用LabVIEW进行上位机开发&#xff0c;涉及底层驱动的编写、USB通信协议的实现以及LabVIEW与设备的接口设计。本文将详细介绍如何开发USB设备驱动、实现LabVIEW与USB设备的通信以及优化数据传输&#xff0c;帮助用户顺利完成项目开发。下面是一个详细的说明&…...

动态规划LeetCode-416.分割等和子集

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] 和 [11] 。 示例 2&…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

ThreadLocal 源码

ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物&#xff0c;因为每个访问一个线程局部变量的线程&#xff08;通过其 get 或 set 方法&#xff09;都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段&#xff0c;这些类希望将…...