【鼠鼠学AI代码合集#8和9】线性神经网络

深度学习中的矢量化加速

在深度学习模型的训练过程中,处理大量数据的效率对模型性能至关重要。为此,我们通常希望能够在一次操作中处理整个小批量的样本,而不是逐一处理每个样本。这种优化方式称为矢量化。通过矢量化,我们可以充分利用底层硬件的并行处理能力,从而极大地加速计算过程。相较于传统的逐元素计算,矢量化能够减少开销,并使代码更加简洁。

为什么矢量化如此重要?

在Python中使用for循环进行逐元素操作虽然直观,但效率往往不高,尤其是在处理大规模数据时。Python本身是解释型语言,每次执行一条指令时,Python解释器会带来较大的开销。如果我们能利用底层的线性代数库(例如深度学习框架的内置库),就可以将这些高开销的操作批量化,从而极大提高运行效率。

通过示例对比矢量化与逐元素操作

为了说明矢量化的优势,我们通过一个简单的向量相加示例进行对比。我们将在两个全为1的10000维向量上进行逐元素相加,并分别采用for循环和矢量化两种方式来计算。

首先,我们引入所需的库,并定义一个简单的计时器类来测量不同方法的运行时间。

import time
import torch
import numpy as np# 计时器类
class Timer:"""记录多次运行时间"""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()

接下来,我们定义两个大小为10000的全为1的张量向量,并分别通过for循环和矢量化进行相加计算。

n = 10000
a = torch.ones(n)
b = torch.ones(n)
方法一:使用for循环逐元素相加
c = torch.zeros(n)
timer = Timer()
for i in range(n):c[i] = a[i] + b[i]
print(f'For循环执行时间:{timer.stop():.5f} 秒')
方法二:使用矢量化操作
timer.start()
d = a + b
print(f'矢量化操作执行时间:{timer.stop():.5f} 秒')

性能对比

运行结果表明,矢量化操作比for循环快得多:

  • For循环执行时间:0.16749 秒
  • 矢量化执行时间:0.00042 秒

通过这组对比,可以看到矢量化代码的速度比for循环快了两个数量级。原因在于for循环只能逐元素进行加法操作,而矢量化操作则可以一次性批量处理整个向量的加法。深度学习框架(如PyTorch、MXNet、TensorFlow等)背后的线性代数库高度优化,通常会利用CPU或GPU的并行计算能力,这使得矢量化操作具有显著的速度优势。

矢量化的其他优势

  1. 并行计算:矢量化操作允许在现代CPU和GPU上进行高效的并行计算。与之相比,for循环只能串行处理元素。
  2. 减少解释器开销:for循环每次迭代都需要调用Python解释器,而矢量化操作将大量的计算交给底层优化的库完成,减少了解释器的频繁调用,进而提高效率。
  3. 简洁易读的代码:矢量化不仅加速了计算过程,还使代码更加简洁。复杂的循环逻辑可以被更简单的张量运算替代,代码可维护性和可读性均有所提升。
  4. 减少出错风险:矢量化代码减少了手动编写循环和逐元素操作的需求,从而降低了编写和调试代码时出错的几率。

总结

矢量化是一种通过批量处理数据来加速计算的技术,尤其在深度学习模型训练中至关重要。相比于逐元素的for循环,矢量化可以充分利用硬件的并行能力,大幅提高计算效率。在深度学习框架中(如PyTorch、MXNet、TensorFlow等),矢量化操作已经被广泛应用,以确保训练和推理的速度能够满足大规模数据的需求。

为了在日常开发中提升代码性能,务必养成使用矢量化操作的习惯。无论是矩阵运算、向量操作还是批量数据处理,矢量化都能带来显著的速度优势和代码质量提升。

参考代码

import time
import torch
import numpy as npclass Timer:"""记录多次运行时间"""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]n = 10000
a = torch.ones(n)
b = torch.ones(n)# For循环实现逐元素加法
c = torch.zeros(n)
timer = Timer()
for i in range(n):c[i] = a[i] + b[i]
print(f'For循环执行时间:{timer.stop():.5f} 秒')# 矢量化加法
timer.start()
d = a + b
print(f'矢量化操作执行时间:{timer.stop():.5f} 秒')

通过这一示例,希望您能更加直观地理解矢量化带来的巨大加速效果,并在实践中应用这一技术提升深度学习模型的训练效率。

正态分布

import math
import numpy as np
import matplotlib.pyplot as pltdef normal(x, mu, sigma):p = 1 / math.sqrt(2 * math.pi * sigma**2)return p * np.exp(-0.5 / sigma**2 * (x - mu)**2)x = np.arange(-7, 7, 0.01)
params = [(0, 1), (0, 2), (3, 1)]for mu, sigma in params:plt.plot(x, normal(x, mu, sigma), label=f'mean {mu}, std {sigma}')plt.xlabel('x')
plt.ylabel('p(x)')
plt.legend()
plt.show()

线性回归的从零开始实现

引言

线性回归是一种基础而重要的机器学习算法,通过建立特征与目标变量之间的线性关系进行预测。尽管现代深度学习框架可以简化实现过程,从零开始构建线性回归模型有助于深入理解其工作原理。

1. 生成数据集

为了测试我们的线性回归模型,我们首先需要生成一个带噪声的线性数据集。以下是生成数据集的函数:

import torchdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声w: 模型的权重参数b: 模型的偏置num_examples: 生成的样本数量"""# 生成特征矩阵X,服从标准正态分布X = torch.normal(0, 1, (num_examples, len(w)))# 计算标签y,添加线性噪声y = torch.matmul(X, w) + b  # 计算线性关系y += torch.normal(0, 0.01, y.shape)  # 添加噪声return X, y.reshape((-1, 1))  # 返回特征和标签

我们设置真实的权重和偏置,并生成1000个样本:

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

2. 可视化数据集

为了直观观察特征与标签之间的关系,我们可以绘制散点图:

import matplotlib.pyplot as pltplt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), s=1)
plt.xlabel('Feature 1')  # X轴标签
plt.ylabel('Label')  # Y轴标签
plt.title('Scatter plot of Features vs Labels')  # 图表标题
plt.show()  # 显示图表

3. 读取数据集

训练模型时,我们需要以小批量的方式读取数据。以下是实现这一功能的 data_iter 函数:

import randomdef data_iter(batch_size, features, labels):"""生成小批量数据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]  # 返回当前批量的特征和标签

4. 初始化模型参数

接下来,我们需要初始化模型的参数。权重从均值为0、标准差为0.01的正态分布中随机初始化,而偏置初始化为0:

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

5. 定义模型

线性回归模型的输出由输入特征与权重的矩阵乘法后加上偏置计算而来:

def linreg(X, w, b):"""线性回归模型X: 输入特征w: 权重参数b: 偏置参数"""return torch.matmul(X, w) + b  # 返回预测结果

6. 定义损失函数

我们使用均方损失函数来评估模型的预测能力:

def squared_loss(y_hat, y):"""均方损失y_hat: 预测值y: 真实值"""return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  # 计算损失

7. 定义优化算法

我们实现小批量随机梯度下降(SGD)来更新模型参数:

def sgd(params, lr, batch_size):"""小批量随机梯度下降params: 要更新的参数列表lr: 学习率batch_size: 批量大小"""with torch.no_grad():  # 不需要计算梯度for param in params:param -= lr * param.grad / batch_size  # 更新参数param.grad.zero_()  # 清除梯度

8. 训练模型

最后,我们将所有组件结合起来,进行模型训练。以下是主要的训练循环:

lr = 0.03  # 学习率
num_epochs = 3  # 训练轮数
batch_size = 10  # 设置批量大小
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}')  # 打印损失

9. 评估结果

通过比较真实参数与训练得到的参数,我们可以评估训练的效果:

print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')  # 打印权重误差
print(f'b的估计误差: {true_b - b}')  # 打印偏置误差

完整代码

import torch
import matplotlib.pyplot as pltdef synthetic_data(w, b, num_examples):"""生成y=Xw+b+噪声w: 模型的权重参数b: 模型的偏置num_examples: 生成的样本数量"""# 生成特征矩阵X,服从标准正态分布X = torch.normal(0, 1, (num_examples, len(w)))# 计算标签y,添加线性噪声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)  # 生成数据集plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), s=1)
plt.xlabel('Feature 1')  # X轴标签
plt.ylabel('Label')  # Y轴标签
plt.title('Scatter plot of Features vs Labels')  # 图表标题
plt.show()  # 显示图表import randomdef data_iter(batch_size, features, labels):"""生成小批量数据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]  # 返回当前批量的特征和标签w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)  # 权重参数
b = torch.zeros(1, requires_grad=True)  # 偏置参数def linreg(X, w, b):"""线性回归模型X: 输入特征w: 权重参数b: 偏置参数"""return torch.matmul(X, w) + b  # 返回预测结果def squared_loss(y_hat, y):"""均方损失y_hat: 预测值y: 真实值"""return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2  # 计算损失def sgd(params, lr, batch_size):"""小批量随机梯度下降params: 要更新的参数列表lr: 学习率batch_size: 批量大小"""with torch.no_grad():  # 不需要计算梯度for param in params:param -= lr * param.grad / batch_size  # 更新参数param.grad.zero_()  # 清除梯度lr = 0.03  # 学习率
num_epochs = 3  # 训练轮数
batch_size = 10  # 设置批量大小
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}')  # 打印损失print(f'w的估计误差: {true_w - w.reshape(true_w.shape)}')  # 打印权重误差
print(f'b的估计误差: {true_b - b}')  # 打印偏置误差

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

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

相关文章

【开源免费】基于SpringBoot+Vue.JS网上超市系统(JAVA毕业设计)

本文项目编号 T 037 ,文末自助获取源码 \color{red}{T037,文末自助获取源码} T037,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

C++学习笔记----9、发现继承的技巧(六)---- 有趣且令人迷惑的继承问题(2)

2、给继承类添加虚基类成员函数的重载 给继承类添加新的虚基类成员函数的重载是可能的。也就是说,可以用新的原型给继承类中的虚成员函数添加重载,但是继续继承基类版本。这个技术使用了using声明来显式包含了继承类中的成员函数的基类定义。下面为示例&…

研发运营一体化(DevOps)能力成熟度模型

目录 应用设计 安全风险管理 技术运 持续交付 敏捷开发管理 基于微服务的端到端持续交付流水线案例 应用设计 安全风险管理 技术运 持续交付

Spring-SpringMVC-SpringBoot理解

Spring是一个完整的框架,能够解决全栈的问题,核心是IOC控制反转和AOP面向切面。 SpringMVC只是Spring的一个模块module,属于Spring框架中WEB层的一部分。 即SpringMVC归属于Spring,不是一个独立的框架 由于SpringMVC配置繁杂使…

关于非中文或者url文本不换行的问题

我在一个写一个简单的url展示的时候,发现url一直溢出不换行,查了各种方法不管用,我请教了我大哥,他直接甩给我两个css放进去就好了 word-break:break-all; 按字符截断换行 /* 支持IE和chrome,FF不支持*/ word-w…

Android 判断手机放置的方向

#1024程序员节|征文# 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 需求 老板:我有个手持终端,不能让他倒了,当他倒或者倾斜的时候要发出报警; 程序猿:我这..... 老板…

机器学习4

第3章 线性模型 3.1 线性模型的基本形式 3.1.1 线性模型的核心公式 线性模型通过属性的线性组合进行预测,其核心公式为: [ f(x) \omega_1 X_1 \omega_2 X_2 … \omega_d X_d b ] 其中: ω 1 , ω 2 , . . . , ω d \omega_1, \omega_…

医疗实施-项目管理06-估算成本

估算成本 估算成本介绍作用注意事项 常见的估算方法自上而下估算数据分析-储备分析三点估算PERT 常见的估算分类根据产品进行估算根据实施计划估算 估算成本介绍 作用 估算成本是对完成项目所需资源成本进行类似估算的过程。 作用:确定项目所需资金 注意事项 注…

2024-09-28 地址空间与进程控制

一、进程地址空间 Pt.2 同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址 1. 页表 内存保护与页表标志位 在操作系统中,页表用于管理内存的访问权限。每个页表项通常包含一组标志位&…

SZTU数科导论实验_pandas知识点总结

Pandas nunique示例 value_counts主要功能参数示例输出示例 groupby主要功能常用操作基本语法示例输出示例常用聚合方法 这个函数参数中的as_index选择True或者False有什么影响呢参数 as_indexTrue(默认)参数 as_indexFalse适用场景 info示例代码输出解释…

Spring Boot技术在厨艺交流平台中的创新应用

摘 要 使用旧方法对厨艺交流信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在厨艺交流信息的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。 这次开发的厨艺交流平台功能…

二:Python学习笔记--基础知识(1) 变量,关键字,数据类型,赋值运算符,比较运算符

目录 1. 变量 2. python关键字 3. python数据类型 3.1 数字类型 整型 int 浮点型 float 内置函数-type 3.2 字符串类型 3.3 布尔类型 3.4 空类型 3.5 列表类型 3.6 元组类型 3.7 字典类型 4. python赋值运算 5. python比较运算符 1. 变量 组成:必须是数…

基于SSM的BBS社区论坛系统源码

运行环境:ideamysql5.7jdk8maven 使用技术:ssmmysqlshirolayui 功能模块:用户管理、模板管理、帖子管理、公告管理、权限管理等

yolov9目标检测/分割预测报错AttributeError: ‘list‘ object has no attribute ‘device‘常见汇总

这篇文章主要是对yolov9目标检测和目标分割预测测试时的报错,进行解决方案。 在说明解决方案前,严重投诉、吐槽一些博主发的一些文章,压根没用的解决方法,也不知道他们从哪里抄的,误人子弟、浪费时间。 我在解决前&…

Lampiao靶机入侵实战

07-Lampiao靶机入侵实战 一、扫描采集信息 1、获取IP地址 nmap -sn 192.168.81.0/24获得IP地址为:192.168.81.1282、获取端口信息 由于nmap默认情况下只扫描常用的1000个端口,覆盖面并不全,所以建议全端口扫描 nmap -p 1-65535 192.168.…

DiffusionDet: Diffusion Model for Object Detection—扩散模型检测论文解析

DiffusionDet: Diffusion Model for Object Detection—扩散模型检测论文解析 这是一篇发表在CVPR 2023的一篇论文,因为自己本身的研究方向是目标跟踪,之前看了一点使用扩散模型进行多跟踪的论文,里面提到了DiffusionDet因此学习一下。 论文…

读数据工程之道:设计和构建健壮的数据系统21数据获取

1. 数据获取 1.1. 数据获取是将数据从一个地方移动到另一个地方的过程 1.1.1. 数据获取与系统内部获取是不同的 1.2. 数据获取是数据工程生命周期中将数据从源系统移入存储的一个中间步骤 1.3. 数据集成则是将来自不同来源系统的数据组合到一个新的数据集 1.4. 数据获取的…

Java中如何实现对象的序列化与反序列化过程?

1、Java中如何实现对象的序列化与反序列化过程? 在Java中,对象序列化是一个过程,该过程可以将对象的状态(属性)转化为可以传输或者存储的形式,然后再将对象状态(属性)反序列化回对象…

数字后端零基础入门系列 | Innovus零基础LAB学习Day6

今天没有具体的数字IC后端lab实验。今天的重点是熟悉掌握静态时序分析STA中的几类timing path以及setup和hold检查机制(包含setup和hold计算公式)。 芯片流片失败的那些故事 数字后端零基础入门系列 | Innovus零基础LAB学习Day5 等大家把今天内容学习…

QT获取本机所有IP地址以及修改本机IP(注意区分Windows和Linux环境)

QT 获取本机所有 IP 地址 Chapter1 QT 获取本机所有 IP 地址获取本机所有 IP 地址,包括 IPV6的地址,需要引用 QNetworkInterface1.检索所有网络接口:2.获取接口的详细信息:3.获取接口的 IP 地址:4.用于网络诊断和监控&…