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

深度学习中的矢量化加速

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

为什么矢量化如此重要?

在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.rhkb.cn/news/455190.html

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

相关文章

Linux笔记之文件查找和搜索命令which,find,locate,whereis总结

Linux笔记之文件查找和搜索命令which,find,locate,whereis总结 code review! 文章目录 Linux笔记之文件查找和搜索命令which,find,locate,whereis总结1.对比2.whereis 和 which 命令区别3.locate 和 find 命令区别 1.对比 命令功能说明备注which常用于查找可直接执行的命令。…

【状态机DP】【记忆化搜索1:1翻译递归空间优化】力扣2771. 构造最长非递减子数组

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度均为 n 。 让我们定义另一个下标从 0 开始、长度为 n 的整数数组,nums3 。对于范围 [0, n - 1] 的每个下标 i ,你可以将 nums1[i] 或 nums2[i] 的值赋给 nums3[i] 。 你的任务是使用最…

【MySQL】表的增删改查(CRUD)

目录 1.前言 2.增加(Create) 3.查询(Retrieve) 3.1全列查询 3.2指定列查询 3.3查询字段为表达式 3.4别名 3.5去重:DISTINCT 3.6排序:ORDER BY 3.7条件查询:WHERE 3.8分页查询&#x…

【LLM之Agent】《Tool Learning with Large Language Models: A Survey》论文阅读笔记

概述 背景信息 近年来,基于大型语言模型(LLMs)的工具学习成为增强LLMs应对复杂任务能力的有力范式。尽管这一领域快速发展,现有文献的碎片化以及缺乏系统组织,给新入门者带来了阻碍。因此,本论文旨在对现…

stable-zero123模型构建指南

一、介绍 stabilityai出品,能够对有简单背景的物体进行三维视角图片的生成,简单来说也就是通过调整变换观察的视角生成对应视角的图片。 本项目通过comfyui实现。 二、容器构建说明 1. 部署ComfyUI (1)使用命令克隆ComfyUI g…

【设计模式系列】命令模式

目录 一、什么是命令模式 二、命令模式的角色 三、命令模式的典型应用场景 四、命令模式在Runnable中的应用 一、什么是命令模式 命令模式(Command Pattern)是一种行为设计模式,它将一个请求或简单操作封装为一个对象。这个模式提供了一种…

Axure垂直菜单展开与折叠

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:Axure垂直菜单展开与折叠 主要内容:垂直菜单单击实现展开/折叠,点击各菜单项显示选中效果 应用场景:后台菜单设…

Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题

作者:彦鸿 背景 随着 LLM(大语言模型)技术的不断成熟和应用场景的不断拓展,越来越多的企业开始将 LLM 技术纳入自己的产品和服务中。LLM 在自然语言处理方面表现出令人印象深刻的能力。然而,其内部机制仍然不明确&am…

Apache Seata 新版本集成了 RocketMQ 事务消息

大家好,我是君哥。 Apache Seata 是一款高性能、简单易用的分布式事务中间件,它包含 AT、TCC、SAGA 和 XA 四种模式。 在最近发布的新版本中,Apache Seata 引入了 RocketMQ 中间件,并且跟 RocketMQ 的事务消息配合使用。今天我们…

界面控件DevExtreme中文教程 - 如何与Amazon S3和Azure Blob存储集成?

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NET Core,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac&#xff0c…

顺序表(一)(数据结构)

一. 线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列 。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,是人为想象出来的数…

1024程序员节 | QT进阶学习——如何通过QT连接云服务器的MySQL数据库并进行数据库操作 和 数据表的增删改查

目录 引出连接本地MySQL1.首先下载MySQL的ODBC驱动2.启动运行,创建用户数据源补充:ANSI 版和 Unicode 版 3.qt代码连接 如何连接华为云服务器中的MySQL1.在Centos中安装Linux版本的ODBC驱动2.在ODBC连接管理器中建立和华为云的链接3.qt代码通过ODBC连接华…

【微软商店平台】如何将exe打包上传微软商店

打开微软合作者中心:https://partner.microsoft.com/en-us/dashboard/home点击App and Games板块可以创建项目。 3. 重新生成包含私钥的自签名证书 运行以下命令,确保生成的证书包含私钥: New-SelfSignedCertificate -Type CodeSigning -Su…

【Java设计模式】1-15章

第1章 内容介绍 1.1 Java设计模式内容介绍 1.1.1 先看几个经典的面试题 1.1.2 设计模式的重要性 1.2 课程亮点和授课方式 第2章 设计模式七大原则 2.1 设计模式的目的 2.2 设计模式七大原则 2.3 ①单一职责原则 方案1 package com.atguigu.principle.singleresponsibili…

【Nuvoton干货分享】开发应用篇 4 -- 8bit MCU Flash 操作

我们在进行实际开发设计中,难免需要进行数据存储,早期很多都是外接EEPROM来进行设计,但是需要增加成本。其实芯片内部的Flash也是可以当成数据存储空间的。本章节主要介绍新唐的8位机如何进行常量数据的存储操作。 一、存储空间划分 我这边…

力扣hot100--DFS/BFS

DFS/BFS 1. 79. 单词搜索 中等 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相…

2024 睿抗机器人开发者大赛(RAICOM)-【网络安全】CTF 部分WP

文章目录 一、前言二、MICS你是黑客么循环的压缩包Goodtime 三、WEBpy 四、Crypto变异凯撒RSAcrypto3 一、前言 WP不完整,仅供参考! 除WEB,RE,PWN外,其余附件均已打包完毕 也是一个对MISC比较友好的一个比赛~ 123网…

鲸鱼优化算法(Whale Optimization Algorithm, WOA)原理与MATLAB例程

鲸鱼优化算法(Whale Optimization Algorithm, WOA)是一种基于鲸鱼捕食行为的智能优化算法。它模拟了座头鲸在狩猎时的“气泡网”捕食策略。 文章目录 1.适应度函数2. 更新公式2.1 突袭行为2.2 螺旋更新3.线性递减参数4. 边界处理 MATLAB 实现示例代码说明…

C语言程序设计:现代设计方法习题笔记《chapter3》

第一题 ​ 代码示例&#xff1a; #include<stdio.h>int main() {printf("Enter a date&#xff08;mm/dd/yyyy&#xff09;: ");int day, month, year;scanf_s("%d/%d/%d", &month, &day, &year);printf("%04d%02d%02d", yea…

一款好用的搜索软件——everthing(搜索比文件资源管理器快)

everthing官网链接 在官网选择下载 1.下载后双击打开 2.点击OK&#xff08;需要其他语言自己选择&#xff09; 3.选择安装位置&#xff08;路径最好别带中文和空格&#xff09; 继续点击下一步 4. 点击下一步 5.继续点击安装 6.然后就完成了 7.点击打开然后就可以搜索了