FlashAttention v1 论文解读
论文标题:FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness
论文地址:https://arxiv.org/pdf/2205.14135
FlashAttention 是一种重新排序注意力计算的算法,它无需任何近似即可加速注意力计算并减少内存占用。所以作为目前LLM的模型加速它是一个非常好的解决方案,本文介绍经典的V1版本。
目前FlashAttention已经推出了V1~V3版本,遗憾的是,FlashAttention V3目前只支持Nvidia Hopper架构的GPU。目前transformers库已经集成了FlashAttention。
【注】穷人玩不起系列。
FlashAttention是用于在训练或推理时加速注意力计算的方法,参考其官方仓库可以看到对于训练精度和显卡还是有较大限制的:
https://github.com/Dao-AILab/flash-attention
带有 CUDA 的 FlashAttention-2 目前支持:
GPU架构 Ampere, Ada, or Hopper GPUs(例如 A100、RTX 3090、RTX 4090、H100)。对Turing GPU(T4、RTX 2080)的支持即将推出,目前请为Turing GPU 使用 FlashAttention 1.x。
数据类型 fp16 和 bf16(bf16 需要Ampere, Ada, or Hopper GPUs)。
标准注意力机制
在介绍FlashAttention前,一定要深入了解标准注意力机制计算原理。
在 Transformer 架构当中,Attention 是整个模型中最重要的运算,而这个 Attention 的运算示意图如下:
首先我们把 Q Q Q和 K K K做矩阵相乘,接下来就是除以隐藏层维度的开根号 d \sqrt{d} d,然后我们会把运算出来的结果 S(Score)丢进 Softmax 函数得到 P,最后 P 再和 V V V做矩阵相乘就会得到 Attention 的输出 O O O。
但实际上我们会发现这一连串的运算非常的耗时间,且会使用到非常大量的内存。
在我们的 GPU 架构中,可以把内存简单地分成 HBM(高带宽内存)和 SRAM(静态随机存取存储器)两个部分。
HBM 的内存空间虽然很大,但是它的带宽比较低。
SRAM 的内存空间虽然很小,但是它的带宽非常高。
所以我们常常看到 GPU 的参数,像是 Nvidia RTX 4090 24GB,就是这张 GPU 有大约 24GB 大小的 HBM。而 SRAM 这块又贵又小的内存,就是拿来做运算的。
因此我们可以看到今天你在GPU 上运行 标准Attention 的流程如下(N:序列长度、d 是 隐藏层维度):
首先我们会把 Q Q Q和 K K K从 HBM 拉到 SRAM 运算,接下来把算出来的结果 S S S写回 HBM,然后 GPU 又把 S S S拉到 SRAM 计算 S o f t m a x Softmax Softmax,算出来的 P P P又写回 HBM,最后 P P P和 V V V从 HBM 写到 SRAM 做矩阵运算,最后输出 O O O写回 HBM。
而实际情况当然没那么简单,我们知道 SRAM 这块内存又贵又小,所以当然不可能直接把整个 Q Q Q或是 K K K加载进 SRAM,而是一小块一小块地加载。所以这样大量的读写导致 Attention 运算速度很慢,而且会有内存碎片化问题。
【注】有了上面的背景之后,我们来看看FlashAttention V1是如何优化的,下面为大家带来FlashAttention V1论文精读。
Abstract
针对Transformer在处理长序列时速度慢、内存消耗大的问题,论文提出了FlashAttention,一种IO感知的精确注意力算法。该算法通过使用平铺(tiling)技术减少GPU内存(HBM)与SRAM之间的内存读写次数,从而降低计算复杂性。
分析显示,FlashAttention减少了HBM访问次数,并优化了SRAM使用。此外,本研究将FlashAttention扩展至块稀疏注意力,实现了比现有近似注意力方法更快的近似注意力算法,为长序列处理提供了高效解决方案。
【注】标准自注意力机制的时间复杂度是 O ( n 2 ∗ d ) O(n^2*d) O(n2∗d),其中 n n n是序列长度, d d d是隐藏层维度。多头注意力只是把 d d d进行了多头拆分,单头的时间复杂度是 O ( n 2 ∗ d h ) O(n^2*d_h) O(n2∗dh),其中 d h d_h dh是单头的隐藏层维度,虽然多头之间可以并行计算,但是仍然没有解决平方量的复杂度。
Introduction
目前许多优化 attention 的方法旨在降低 attention 的计算和内存需求。这些方法专注于减少 FLOP,并且倾向于忽略内存访问 (IO) 的开销。
但是本文认为attention的一个优化方向是使算法具有 IO 感知能力。
【注】也就是说,让求注意力的操作尽可能放在SRAM里,而不是频繁的让SRAM与HBM通信。
现代的GPU,计算速度超过了内存IO速度,当读取和写入数据可能占据运行时间的很大一部分时,IO 感知算法对于加速与降内存就变得很重要了。并且深度学习的常见 Python 库(如 PyTorch 和 Tensorflow)目前还不允许对内存访问进行精细控制。
因此,FlashAttention应运而生。
论文提到,为了实现计算注意力时多使用SRAM而少与HBM交换数据,需要克服两点:
- 在输入不完整的情况下,计算 S o f t m a x Softmax Softmax;
- 不存储用于反向传播的中间结果;
FlashAttention
第一招:内核融合(Kernel Fusion)
相信聪明的朋友立刻就能明白,何必这样反复加载和卸载,一次性在SRAM中完成所有计算不就好了?没错,这就是FlashAttention的精髓之一。
FlashAttention就是直接将 Q K V QKV QKV一次性加载到SRAM中完成所有计算,然后再将 O O O写回HBM。
这样大大减少了读写次数,这种一次性完成所有计算的流程被称为内核融合(Kernel Fusion)。
第二招:反向重计算(Backward Recomputation)
但是等一下,我们是不是忘了什么?我们直接计算出了 O O O,那么 P P P和 S S S难道就直接丢弃不存回HBM吗?在进行反向传播时,我们需要从 O O O推回 P P P,再从 P P P推回 S S S,它们都被我们丢弃了,怎么进行反向传播?没错,这就是FlashAttention的第二招,反向重计算(Backward Recomputation)。
因为 P P P和 S S S这两者实在太占用空间了,所以
在前向传播时, P P P和 S S S都不会被存储起来。当进行反向传播时,我们就会重新计算一次前向传播,重新计算出 P P P和 S S S,以便执行反向传播。
所以说:我们执行了2次前向传播和1次反向传播。
这里大家可能又会问:啊这样计算量不是更多了吗,怎么可能会更快?事实上,虽然我们重新计算了一次前向传播,但它不仅帮我们省下了存储P和S的内存空间,还省下了 P P P和 S S S在HBM和SRAM之间搬运的时间,让我们可以开启更大的batch size,所以总的来说,GPU每秒能处理的数据量依然是大幅增加的。
第三招:Softmax分块(Softmax Tiling)
最后是FlashAttention的最后一招分块(Tiling)。首先我们需要知道注意力机制中的最难搞的就是 S o f t m a x Softmax Softmax函数:
s o f t m a x ( { x 1 , . . . , x N } ) = { e x i ∑ j = 1 N e x j } i = 1 N (1) softmax(\{x_1, ..., x_N\}) = \left\{\frac{e^{x_i}}{\sum_{j=1}^N e^{x_j}}\right\}_{i=1}^N \tag1 softmax({x1,...,xN})={∑j=1Nexjexi}i=1N(1)
主要原因是在计算分母时,我们需要将所有位的exp值加总。但由于SRAM的大小限制,我们不可能一次性计算出所有数值的 S o f t m a x Softmax Softmax,一定是需要一块一块地丢进SRAM进行计算,所以需要将所有中间计算的数值存储在HBM中。
在FP16精度下,最大可以表示65536,而
e 12 = 162754 e^{12} = 162754 e12=162754
为了防止在计算 S o f t m a x Softmax Softmax产生数值溢出,引入了 S a f e − s o f t m a x Safe-softmax Safe−softmax概念,其公式如下:
S a f e − s o f t m a x ( { x 1 , . . . , x N } ) = { e x i − m ∑ j = 1 N e x j − m } i = 1 N (2) Safe-softmax(\{x_1, ..., x_N\}) = \left\{\frac{e^{x_i-m}}{\sum_{j=1}^N e^{x_j-m}}\right\}_{i=1}^N \tag2 Safe−softmax({x1,...,xN})={∑j=1Nexj−mexi−m}i=1N(2)
在公式(2)中,有如下定义:
x = [ x 1 , . . . , x N ] (3) x=[x_1,...,x_N] \tag3 x=[x1,...,xN](3)
m ( x ) : = m a x ( x ) (4) m(x):=max(x) \tag4 m(x):=max(x)(4)
p ( x ) : = [ e x 1 − m ( x ) , . . . , e x N − m ( x ) ] (5) p(x):=[e^{x_1-m(x)},...,e^{x_N-m(x)}] \tag5 p(x):=[ex1−m(x),...,exN−m(x)](5)
l ( x ) : = ∑ i p ( x ) i (6) l(x):=\sum_ip(x)_i \tag6 l(x):=i∑p(x)i(6)
s o f t m a x ( x ) : = p ( x ) l ( x ) (7) softmax(x):=\frac{p(x)}{l(x)} \tag7 softmax(x):=l(x)p(x)(7)
其原理就是,从 x x x中找出最大值 m m m,在计算 S o f t m a x Softmax Softmax时,分子分母同除以 e m e^m em,这样既可以防止数据溢出,也能保证 S o f t m a x Softmax Softmax值保持不变。
【注】类似于归一化。
x = [ x 1 , … , x N , … , x 2 N ] x 1 = [ x 1 , … , x N ] x 2 = [ x N + 1 , … , x 2 N ] m ( x 1 ) p ( x 1 ) l ( x 1 ) m ( x 2 ) p ( x 2 ) l ( x 2 ) m ( x ) : = max ( m ( x 1 ) , m ( x 2 ) ) p ( x ) : = [ e m ( x 1 ) − m ( x ) p ( x 1 ) , e m ( x 2 ) − m ( x ) p ( x 2 ) ] l ( x ) : = e m ( x 1 ) − m ( x ) l ( x 1 ) + e m ( x 2 ) − m ( x ) l ( x 2 ) s o f t m a x ( x ) : = p ( x ) l ( x ) (8) \begin{align*} & x = [x_1, \ldots, x_N, \ldots, x_{2N}] \\ & x^1 = [x_1, \ldots, x_N] \\ & x^2 = [x_{N+1}, \ldots, x_{2N}] \\ & m(x^1) \ p(x^1) \ l(x^1) \ m(x^2) \ p(x^2) \ l(x^2) \\ & m(x) := \max(m(x^1), m(x^2)) \\ & p(x) := [e^{m(x^1)-m(x)} p(x^1), e^{m(x^2)-m(x)} p(x^2)] \\ & l(x) := e^{m(x^1)-m(x)} l(x^1) + e^{m(x^2)-m(x)} l(x^2) \\ & softmax(x) := \frac{p(x)}{l(x)} \end{align*}\tag8 x=[x1,…,xN,…,x2N]x1=[x1,…,xN]x2=[xN+1,…,x2N]m(x1) p(x1) l(x1) m(x2) p(x2) l(x2)m(x):=max(m(x1),m(x2))p(x):=[em(x1)−m(x)p(x1),em(x2)−m(x)p(x2)]l(x):=em(x1)−m(x)l(x1)+em(x2)−m(x)l(x2)softmax(x):=l(x)p(x)(8)
而本文softmax分块的做法如公式(8)所示。
我们首先将一块数据 x x x中的第一块 x 1 x_1 x1丢进去计算出softmax,这里的 m 1 m_1 m1代表的是这一块加载到SRAM的最大值,所以我们称之为局部最大值。接下来,我们可以根据 m 1 m_1 m1计算出局部softmax。
接下来第二块数据进来时,我们将第一块的最大值 m 1 m_1 m1和第二块的最大值 m 2 m_2 m2取最大值,就可以得到这两块数据的最大值 m ( x ) m(x) m(x)。这个时候定义 p ( x ) : = [ e m ( x 1 ) − m ( x ) p ( x 1 ) , e m ( x 2 ) − m ( x ) p ( x 2 ) ] p(x) := [e^{m(x^1)-m(x)} p(x^1), e^{m(x^2)-m(x)} p(x^2)] p(x):=[em(x1)−m(x)p(x1),em(x2)−m(x)p(x2)],再与公式(5)结合,只会出现两种情况:
- 当 m ( x 1 ) m(x^1) m(x1)最大,最后可化简为 p ( x ) : = [ e x 1 − m ( x 1 ) , . . . , e x N − m ( x 1 ) ] p(x) := [e^{x_1-m(x^1)},...,e^{x_N-m(x^1)}] p(x):=[ex1−m(x1),...,exN−m(x1)]
- 当 m ( x 2 ) m(x^2) m(x2)最大,最后可化简为 p ( x ) : = [ e x 1 − m ( x 2 ) , . . . , e x N − m ( x 2 ) ] p(x) := [e^{x_1-m(x^2)},...,e^{x_N-m(x^2)}] p(x):=[ex1−m(x2),...,exN−m(x2)]
l ( x ) l(x) l(x)的计算化简也同理,所以我们只需要将第一块的局部softmax乘上这次更新的数值。如此一来,我们就得到了这两块的局部softmax。
没错!接下来依此类推,我们就可以将整个softmax计算完。而通过这种方式:
我们就不需要将每块计算出来的数值存储在HBM中,我们只需要存储当前的最大值 m ( x ) m(x) m(x)和分母加总值 l ( x ) l(x) l(x)就可以了。
而这两者都非常小,所以可以进一步帮我们节省更多内存空间。
另外,这里还有一个小细节,就是由于softmax计算出来后需要与value state进行矩阵相乘,但同样由于SRAM有限,我们一次只能加载一块进行内核融合运算,所以第一块QKV进去后,它计算出来的O是不准确的。但由于矩阵相乘就是数字相乘,所以同样道理,我们只要在计算到下一块时,使用l和m更新O就可以了。
我们可以看到实际的流程就是这样,蓝色的区域就是HBM,橙色虚线的区域就是SRAM。每次运算时,由于SRAM大小有限,所以我们只加载一部分的Key和Value。红色的字就是我们的第一个block的计算,蓝色的字就是我们的第二个block的计算。
这边我们可以更深入探讨算法和实现部分。静态随机存取存储器(SRAM)容量较小,当序列长度很长时,根本不可能一次性将如此庞大的查询(query)、键(key)、值(value)状态全部塞进SRAM。
一开始我们会把查询状态(Query State)切成 T r T_r Tr块,键/值状态(Key/Value State)切成 T c T_c Tc块,查询状态块的大小为 ( B r , d ) (B_r, d) (Br,d),键/值状态块的大小为 ( B c , d ) (B_c, d) (Bc,d)。切好的这些块再放入SRAM进行Flash Attention运算。 你可能会好奇 B r B_r Br和 B c B_c Bc是什么神奇的数字,其实非常简单, M M M是我们SRAM的大小,并且查询(Q)、键(K)、值(V)、输出(O)这四个矩阵大小完全相同,所以当然是 M / 4 d M/4d M/4d啦,这样Q、K、V、O四个矩阵的块加起来不就刚好是 M M M嘛,也就是说刚好填满SRAM。
比如说,假设M = 1000, d = 5。那么块大小为(1000/4*5)= 50。所以一次加载50个q, k, v, o个向量的块,这样可以减少HBM/SRAM之间的读/写次数。
性能
我们可以看到 FlashAttention 大大地加速了运算,达到 3 倍以上。
相关文章:
FlashAttention v1 论文解读
论文标题:FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 论文地址:https://arxiv.org/pdf/2205.14135 FlashAttention 是一种重新排序注意力计算的算法,它无需任何近似即可加速注意力计算并减少内存占用。…...
Kafka 副本机制(包含AR、ISR、OSR、HW 和 LEO 介绍)
文章目录 Kafka 副本机制(包含AR、ISR、OSR、HW 和 LEO 介绍)1. 副本的基本概念2. 副本同步和一致性2.1 AR(Assigned Replicas)2.2 ISR(In-Sync Replicas)2.3 OSR(Out-of-Sync Replicas…...
QtCreator在配置Compilers时,有一个叫ABI的选项,那么什么是ABI?
问题提出 QtCreator在配置Compilers时,有一个叫ABI的选项,那么什么是ABI? ABI(Application Binary Interface)介绍 ABI(Application Binary Interface,应用二进制接口)是指应用程序与操作系统或其他程序…...
ResNet--深度学习中的革命性网络架构
一、引言 在深度学习的研究和应用中,网络架构的设计始终是一个关键话题。随着计算能力和大数据的不断提升,深度神经网络逐渐成为解决复杂任务的主流方法。然而,随着网络层数的增加,训练深度神经网络往往面临梯度消失或梯度爆炸的…...
【 软件测试项目实战】 以淘宝网购物车管理功能为例
一、测试功能模块分析 选择淘宝网购物车管理功能进行测试,核心子功能包含: 单商品添加/删除购物车商品数量修改多商品勾选与批量删除失效商品识别与处理 二、测试用例设计方法论应用 1. 等价类划分法(商品添加操作) 分析&…...
Go 中 defer 的机制
文章目录 Go 语言中 defer 的底层机制与实战解析一、defer 的执行顺序:后进先出(LIFO)示例 :多个 defer 的执行顺序 二、defer 的参数预计算:值拷贝的陷阱示例 :参数预计算的影响 三、defer 与闭包…...
智能小区物业管理系统推动数字化转型与提升用户居住体验
内容概要 在当今快速发展的社会中,智能小区物业管理系统的出现正在改变传统的物业管理方式。这种系统不仅仅是一种工具,更是一种推动数字化转型的重要力量。它通过高效的技术手段,将物业管理与用户居住体验紧密结合,无疑为社区带…...
【memgpt】letta 课程4:基于latta框架构建MemGpt代理并与之交互
Lab 3: Building Agents with memory 基于latta框架构建MemGpt代理并与之交互理解代理状态,例如作为系统提示符、工具和agent的内存查看和编辑代理存档内存MemGPT 代理是有状态的 agents的设计思路 每个步骤都要定义代理行为 Letta agents persist information over time and…...
HTML DOM 对象
HTML DOM 对象 引言 HTML DOM(文档对象模型)是现代网页开发的核心技术之一。DOM 将 HTML 或 XML 文档结构化,使其成为可编程的对象。通过 DOM,开发者可以轻松地操作网页内容、样式和结构。本文将详细介绍 HTML DOM 对象的相关知识,包括其概念、结构、操作方法以及在实际…...
高温环境对电机性能的影响与LabVIEW应用
电机在高温环境下的性能可能受到多种因素的影响,尤其是对于持续工作和高负荷条件下的电机。高温会影响电机的效率、寿命以及可靠性,导致设备出现过热、绝缘损坏等问题。因此,在设计电机控制系统时,特别是在高温环境下,…...
【09-电源线布线与覆铜 GND与转孔】
走线 从接触点处走线 TYPEC画线-加铜皮 1.关闭不需要的层(锡膏层和阻焊层和机械层) 紫色阻焊层 L: 顶层锡膏 底层锡膏 顶层阻焊 底层阻焊 2.修改线框或者贴铜 3.顶层走不过去:打四个孔 核心:走线-打孔-贴铜皮 设置孔的参数:大小和人为盖有 挨一下其他才会有网络 4个孔也要贴…...
算法题(48):反转链表
审题: 需要我们将链表反转并返回头结点地址 思路: 一般在面试中,涉及链表的题会主要考察链表的指向改变,所以一般不会允许我们改变节点val值。 这里是单向链表,如果要把指向反过来则需要同时知道前中后三个节点&#x…...
C++ 泛型编程指南02 (模板参数的类型推导)
文章目录 一 深入了解C中的函数模板类型推断什么是类型推断?使用Boost TypeIndex库进行类型推断分析示例代码关键点解析 2. 理解函数模板类型推断2.1 指针或引用类型2.1.1 忽略引用2.1.2 保持const属性2.1.3 处理指针类型 2.2 万能引用类型2.3 传值方式2.4 传值方式…...
穷举vs暴搜vs深搜vs回溯vs剪枝系列一>单词搜索
题解如下 题目:解析决策树:代码设计: 代码: 题目: 解析 决策树: 代码设计: 代码: class Solution {private boolean[][] visit;//标记使用过的数据int m,n;//行,列char…...
9 点结构模块(point.rs)
一、point.rs源码 use super::UnknownUnit; use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; use crate::num::*; use crate::scale::Scale; use crate::size::{Size2D, Size3D}; use crate::vector::{vec2, vec3, Vector2D, V…...
基于vue船运物流管理系统设计与实现(源码+数据库+文档)
船运物流管理系统目录 目录 基于springboot船运物流管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员登录 2、货运单管理 3、公告管理 4、公告类型管理 5、新闻管理 6、新闻类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考…...
海思ISP开发说明
1、概述 ISP(Image Signal Processor)图像信号处理器是专门用于处理图像信号的硬件或处理单元,广泛应用于图像传感器(如 CMOS 或 CCD 传感器)与显示设备之间的信号转换过程中。ISP通过一系列数字图像处理算法完成对数字…...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?
2.12 连续数组:为什么contiguous这么重要? 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…...
Chromium132 编译指南 - Android 篇(一):编译前准备
1. 引言 欢迎来到《Chromium 132 编译指南 - Android 篇》系列的第一部分。本系列指南将引导您逐步完成在 Android 平台上编译 Chromium 132 版本的全过程。Chromium 作为一款由 Google 主导开发的开源浏览器引擎,为众多现代浏览器提供了核心驱动力。而 Android 作…...
Jenkins未在第一次登录后设置用户名,第二次登录不进去怎么办?
Jenkins在第一次进行登录的时候,只需要输入Jenkins\secrets\initialAdminPassword中的密码,登录成功后,本次我们没有修改密码,就会导致后面第二次登录,Jenkins需要进行用户名和密码的验证,但是我们根本就没…...
#define,源文件与头文件,赋值表达式
1.#define 1.1定义 #define 是一个预处理指令,用于定义宏 宏,是预处理阶段(在编译之前)由预处理器处理的代码片段 1.2使用 1.2.1 #define 可以定义常量 #define PI 3.14159 1.2.2 #define 可以定义宏函数 #define SQUARE(x) ((…...
wordpress外贸独立站常用询盘软件
LiveChat LiveChat是一家提供实时聊天软件的公司,帮助企业通过其平台与客户进行即时通讯,提高客户满意度和忠诚度。他们的产品允许企业在网站、应用程序或电子邮件等多个渠道与客户互动,从而提升客户体验并促进销售增长。 LiveChat的软件特…...
网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开。
一、前言 我从24年11月份开始学习网络爬虫应用开发,经过2个来月的努力,于1月下旬完成了开发一款网络爬虫软件的学习目标。这里对本次学习及应用开发进行一下回顾总结。 前几天我已经发了一篇日志(网络爬虫学习:应用selenium从搜…...
Zookeeper入门部署(单点与集群)
本篇文章基于docker方式部署zookeeper集群,请先安装docker 目录 1. docker初期准备 2.启动zookeeper 2.1 单点部署 2.2 集群部署 3. Linux脚本实现快速切换启动关闭 1. docker初期准备 拉取zookeeper镜像 docker pull zookeeper:3.5.6 如果拉取时间过长…...
2025最新在线模型转换工具onnx转换ncnn,mnn,tengine等
文章目录 引言最新网址地点一、模型转换1. 框架转换全景图2. 安全的模型转换3. 网站全景图 二、转换说明三、模型转换流程图四、感谢 引言 在yolov5,yolov8,yolov11等等模型转换的领域中,时间成本常常是开发者头疼的问题。最近发现一个超棒的…...
文件读写操作
写入文本文件 #include <iostream> #include <fstream>//ofstream类需要包含的头文件 using namespace std;void test01() {//1、包含头文件 fstream//2、创建流对象ofstream fout;/*3、指定打开方式:1.ios::out、ios::trunc 清除文件内容后打开2.ios:…...
AJAX XML
AJAX XML 引言 随着互联网技术的不断发展,Web应用对用户交互性和实时性的要求越来越高。AJAX(Asynchronous JavaScript and XML)技术的出现,为Web应用开发提供了强大的支持。AJAX技术允许Web应用在不重新加载整个页面的情况下,与服务器进行异步通信。XML作为数据传输格式…...
Linux文件原生操作
Linux 中一切皆文件,那么 Linux 文件是什么? 在 Linux 中的文件 可以是:传统意义上的有序数据集合,即:文件系统中的物理文件 也可以是:设备,管道,内存。。。(Linux 管理的一切对象…...
JavaScript常用的内置构造函数
JavaScript作为一种广泛应用的编程语言,提供了丰富的内置构造函数,帮助开发者处理不同类型的数据和操作。这些内置构造函数在创建和操作对象时非常有用。本文将详细介绍JavaScript中常用的内置构造函数及其用途。 常用内置构造函数概述 1. Object Obj…...
Shell篇-字符串处理
目录 1.变量引用 2.获取字符串长度 3.字符串截取 4.删除子字符串 5.字符串替换 总结: Bash(Shell 脚本)中的字符串处理语法。以下是对其的介绍和总结:Bash 变量可以使用不同的语法来获取、修改和删除字符串的内容。图片中列…...
Arduino大师练成手册 -- 控制 AS608 指纹识别模块
要在 Arduino 上控制 AS608 指纹识别模块,你可以按照以下步骤进行: 硬件连接 连接指纹模块:将 AS608 指纹模块与 Arduino 连接。通常,AS608 使用 UART 接口进行通信。你需要将 AS608 的 TX、RX、VCC 和 GND 引脚分别连接到 Ardu…...
C++ Primer 命名空间的using声明
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
C#,入门教程(12)——数组及数组使用的基础知识
上一篇: C#,入门教程(11)——枚举(Enum)的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合,是一组…...
深入浅出并查集(不相交集合实现思路)
引言 并查集(Disjoint Set Union,简称DSU)是一种用于处理一些不交集的合并及查询问题。它主要支持两种操作:查找(Find)和合并(Union)。 查找:确定某个元素属于哪一个子…...
M|哪吒之魔童闹海
rating: 8.5 豆瓣: 8.5 上映时间: “2025” 类型: M动画 导演: 饺子 主演: 国家/地区: 中国大陆 片长/分钟: 144分钟 M|哪吒之魔童闹海 制作精良,除了剧情逻辑有一点瑕疵,各方面都很到位。总体瑕不掩瑜。 上映时间: &…...
【c++】类与对象详解
目录 面向过程思想和面向对象思想类的定义引入类的关键字类定义的两种方式类的访问限定符类的作用域类大小的计算封装 this指针类的6个默认成员函数构造函数初步理解构造函数深入理解构造函数初始化列表单参数构造函数引发的隐式类型转换 析构函数拷贝构造函数赋值运算符重载运…...
LabVIEW如何有效地进行数据采集?
数据采集(DAQ)是许多工程项目中的核心环节,无论是测试、监控还是控制系统,准确、高效的数据采集都是至关重要的。LabVIEW作为一个图形化编程环境,提供了丰富的功能来实现数据采集,确保数据的实时性与可靠性…...
Golang 并发机制-4:用Mutex管理共享资源
并发性是Go的强大功能之一,它允许多个线程(并发线程)同时执行。然而,权力越大,责任越大。当多个例程并发地访问和修改共享资源时,可能会导致数据损坏、竞争条件和不可预测的程序行为。为了解决这些问题&…...
如何用微信小程序写春联
生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production 2、修改 app.json …...
从零开始:用Qt开发一个功能强大的文本编辑器——WPS项目全解析
文章目录 引言项目功能介绍1. **文件操作**2. **文本编辑功能**3. **撤销与重做**4. **剪切、复制与粘贴**5. **文本查找与替换**6. **打印功能**7. **打印预览**8. **设置字体颜色**9. **设置字号**10. **设置字体**11. **左对齐**12. **右对齐**13. **居中对齐**14. **两侧对…...
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略
LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之o3:《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读 LLMs之OpenAI o系列:OpenAI o3-mini的简介、安…...
DeepSeek-R1 低成本训练的根本原因是?
在人工智能领域,大语言模型(LLM)正以前所未有的速度发展,驱动着自然语言处理、内容生成、智能客服等众多应用的革新。然而,高性能的背后往往是高昂的训练成本,动辄数百万美元的投入让许多企业和研究机构望而…...
C语言:结构体
一,结构体 C语⾔已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。 描述⼀个学⽣需…...
java练习(5)
ps:题目来自力扣 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这…...
【高等数学】贝塞尔函数
贝塞尔函数(Bessel functions)是数学中一类重要的特殊函数,通常用于解决涉及圆对称或球对称的微分方程。它们在物理学、工程学、天文学等多个领域都有广泛的应用,例如在波动方程、热传导方程、电磁波传播等问题中。 贝塞尔函数的…...
贪吃蛇实现
1.资料来源 https://learn.microsoft.com/zh-cn/windows/console/getstdhandle 2.前言 简介 贪吃蛇是久负盛名的游戏,和俄罗斯方块、扫雷等游戏位列于经典游戏的行列。 《贪食蛇》中玩家控制一条不断移动的蛇,在屏幕上吃掉出现的食物。每吃掉一个食物…...
Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)
文章目录 一、环境准备二、安装Ollama2.1 访问Ollama官方网站2.2 下载适用于Windows的安装包2.3 安装Ollama安装包2.4 指定Ollama安装目录2.5 指定Ollama的大模型的存储目录 三、选择DeepSeek R1模型四、下载并运行DeepSeek R1模型五、使用Chatbox进行交互5.1 下载Chatbox安装包…...
在C++中,成员变量必须在对象构造完成前初始化,但初始化的方式有多种...
在C中,成员变量必须在对象构造完成前初始化,但初始化的方式可以有多种,具体取决于成员变量的类型和设计需求。以下是C中成员变量初始化的规则和相关机制: 1. 成员变量必须初始化 如果成员变量是基本类型(如 int、doub…...
maven mysql jdk nvm node npm 环境安装
安装JDK 1.8 11 环境 maven环境安装 打开网站 下载 下载zip格式 解压 自己创建一个maven库 以后在idea 使用maven时候重新设置一下 这三个地方分别设置 这时候maven才算设置好 nvm 管理 npm nodejs nvm下载 安装 Releases coreybutler/nvm-windows GitHub 一键安装且若有…...
算法随笔_37: 交替合并字符串
上一篇:算法随笔_36: 复写零-CSDN博客 题目描述如下: 给你两个字符串 word1 和 word2 。请你从 word1 开始,通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 示例…...