【拜读】Tensor Product Attention Is All You Need姚期智团队开源兼容RoPE位置编码

姚期智团队开源新型注意力:张量积注意力(Tensor Product Attention,TPA)。有点像一种「动态的LoRA」,核心思路在于利用张量分解来压缩注意力机制中的 Q、K、V 表示,同时保留上下文信息,减少内存开销。另外巧妙地兼容了RoPE,论文中还证明了流行的MHA、MQA、GQA都是TPA的特殊情况,用一个框架统一了现代注意力设计,解决MLA压缩了KV缓存但与RoPE位置编码不兼容的问题。
张量积注意力(Tensor Product Attention, TPA),用于解决语言模型在处理长序列时的内存开销问题。通过上下文张量分解来表示查询、键和值,从而在推理时显著减少了KV缓存的大小。实验结果表明,TPA在保持模型性能的同时,显著降低了内存开销,能够处理更长的序列上下文。此外,TPA与旋转位置嵌入(RoPE)兼容,便于在现代大型语言模型架构中应用。总体而言,TPA提供了一种灵活且内存高效的替代方案,推动了现代语言模型的可扩展性。
核心机制总结
具体来说,
-
张量分解:首先,TPA使用张量分解来表示查询(Q)、键(K)和值(V),从而在推理时显著减少KV缓存的大小。通过将表示分解为上下文低秩分量(contextual factorization),TPA实现了比标准多头注意力(MHA)低一个数量级的内存开销,同时降低了预训练验证损失(困惑度)并提高了下游性能。
- 张量积投影:通过两组线性层(A 投影和 B 投影)对输入进行变换,这是张量积注意力的核心操作之一。
- 缓存机制:使用缓存来存储 K 和 V 的值,以便在后续计算中使用,这有助于提高计算效率。
- 旋转位置嵌入:应用旋转位置嵌入来处理序列中的位置信息。
- 注意力计算:通过矩阵乘法计算注意力分数,并使用 softmax 进行归一化,最后得到输出。

-
与RoPE的兼容性:TPA与旋转位置嵌入(RoPE)天然兼容,可以直接替代多头注意力(MHA)层,便于在现代大型语言模型架构(如LLaMA和Gemma)中应用。
-
公式描述:具体来说,TPA的查询、键和值的分解公式如下:
Q t = 1 R Q ∑ r = 1 R Q a r Q ( x t ) ⊗ b r Q ( x t ) Q_{t}=\frac{1}{R_{Q}}\sum_{r=1}^{R_{Q}} a_{r}^{Q}\left(x_{t}\right)\otimes b_{r}^{Q}\left(x_{t}\right) Qt=RQ1r=1∑RQarQ(xt)⊗brQ(xt)
K t = 1 R K ∑ r = 1 R K a r K ( x t ) ⊗ b r K ( x t ) K_{t}=\frac{1}{R_{K}}\sum_{r=1}^{R_{K}} a_{r}^{K}\left(x_{t}\right)\otimes b_{r}^{K}\left(x_{t}\right) Kt=RK1r=1∑RKarK(xt)⊗brK(xt)
V t = 1 R V ∑ r = 1 R V a r V ( x t ) ⊗ b r V ( x t ) V_{t}=\frac{1}{R_{V}}\sum_{r=1}^{R_{V}} a_{r}^{V}\left(x_{t}\right)\otimes b_{r}^{V}\left(x_{t}\right) Vt=RV1r=1∑RVarV(xt)⊗brV(xt)
其中, a r Q ( x t ) a_{r}^{Q}(x_{t}) arQ(xt), b r Q ( x t ) b_{r}^{Q}(x_{t}) brQ(xt)是查询的因子, a r K ( x t ) a_{r}^{K}(x_{t}) arK(xt) 和 b r K ( x t ) b_{r}^{K}(x_{t}) brK(xt) 是键的因子, a r V ( x t ) a_{r}^{V}(x_{t}) arV(xt) 和 b r V ( x t ) b_{r}^{V}(x_{t}) brV(xt) 是值的因子。
实验设计
- 数据集:实验在FineWeb-Edu 100B数据集上进行,该数据集包含1000亿个训练令牌和10亿个验证令牌。
- 模型对比:实验中将T6与基线Llama架构(使用SwiGLU激活和RoPE嵌入)以及Llama变体(将多头注意力替换为多查询注意力MQA、分组查询注意力GQA或多头潜在注意力MLA)进行对比。
- 训练设置:实验采用nanoGPT训练配置,使用AdamW优化器,学习率由余弦退火调度器管理,训练阶段分别为2000步预热和全局批量大小为480。
结果与分析
-
训练和验证曲线:中等规模(353M)、大规模(773M)和超大规模(1.5B)模型的训练和验证损失曲线显示,TPA及其简化变体TPA-KVonly的收敛速度与基线MHA、MQA、GQA和MLA相当或更快,并且在整个训练过程中保持了较低的验证损失。


-
验证困惑度:中等规模和大规模模型的验证困惑度曲线显示,TPA和TPA-KVonly在大多数配置下在整个训练过程中保持了较低的困惑度。预训练结束时,TPA基线的困惑度最低。

-
下游评估:在标准基准上的零样本和两样本评估结果显示,中等规模模型中,TPA的平均准确率为51.41%,高于MHA的50.11%、MQA的50.44%和MLA的50.13%。大规模模型中,TPA-KVonly的平均准确率为53.52%,而超大规模模型中,TPA-KVonly的平均准确率为55.03%。
优点与创新
- 显著的内存效率提升:通过张量分解表示查询、键和值,显著减少了推理时的KV缓存大小,相比标准多头注意力机制(MHA)提升了10倍以上。
- 模型性能提升:在预训练验证损失(困惑度)和下游评估性能方面均优于现有的多头注意力、多查询注意力、分组查询注意力和多头潜在注意力等方法。
- 与RoPE的兼容性:TPA天然兼容旋转位置嵌入(RoPE),可以直接替代多头注意力层,便于在现代大型语言模型架构(如LLaMA和Gemma)中应用。
- 统一的注意力机制框架:揭示了多头注意力、多查询注意力和分组查询注意力都可以作为非上下文变体的TPA自然出现。
- 灵活的变体:TPA的变体包括仅分解键/值或跨标记共享基向量,展示了在平衡内存成本、计算开销和表示能力方面的多样性。
关键问题及回答
问题1:张量积注意力(TPA)是如何通过张量分解来表示查询(Q)、键(K)和值(V)的?
张量积注意力(TPA)通过将查询(Q)、键(K)和值(V)分解为多个低秩张量的和来表示。具体来说,每个头的查询、键和值被分解为多个低秩张量的和:
Q t = 1 R Q ∑ r = 1 R Q a r Q ( x t ) ⊗ b r Q ( x t ) Q_{t}=\frac{1}{R_{Q}}\sum_{r=1}^{R_{Q}} a_{r}^{Q}\left(x_{t}\right)\otimes b_{r}^{Q}\left(x_{t}\right) Qt=RQ1r=1∑RQarQ(xt)⊗brQ(xt)
K t = 1 R K ∑ r = 1 R K a r K ( x t ) ⊗ b r K ( x t ) K_{t}=\frac{1}{R_{K}}\sum_{r=1}^{R_{K}} a_{r}^{K}\left(x_{t}\right)\otimes b_{r}^{K}\left(x_{t}\right) Kt=RK1r=1∑RKarK(xt)⊗brK(xt)
V t = 1 R V ∑ r = 1 R V a r V ( x t ) ⊗ b r V ( x t ) V_{t}=\frac{1}{R_{V}}\sum_{r=1}^{R_{V}} a_{r}^{V}\left(x_{t}\right)\otimes b_{r}^{V}\left(x_{t}\right) Vt=RV1r=1∑RVarV(xt)⊗brV(xt)
其中, a r Q a_{r}^{Q} arQ, a r K a_{r}^{K} arK, a r V a_{r}^{V} arV 和 b r Q b_{r}^{Q} brQ, b r K b_{r}^{K} brK, b r V b_{r}^{V} brV 是可学习的参数矩阵, x t x_{t} xt 是第t个标记的隐藏状态向量。通过这种张量分解,TPA能够显著减少KV缓存的大小,同时提高表示能力。
问题2:张量积注意力(TPA)与旋转位置嵌入(RoPE)的兼容性如何?
张量积注意力(TPA)与旋转位置嵌入(RoPE)天然兼容。RoPE是一种用于编码位置信息的编码方式,能够在保持相对位置关系的同时进行旋转。TPA可以直接替换多头注意力(MHA)层,便于在现代大型语言模型(如LLaMA和Gemma)中应用。具体来说,RoPE可以通过以下公式进行预旋转:
B ~ K ( x t ) ⟵ RoPE t ( B K ( x t ) ) \widetilde{B}_{K}\left(x_{t}\right)\longleftarrow\operatorname{RoPE}_{t}\left(B_{K}\left(x_{t}\right)\right) B K(xt)⟵RoPEt(BK(xt))
这样,每个键在缓存之前就已经旋转,从而避免了在解码时显式进行旋转操作,加速了自回归推理过程。
问题3:张量积注意力(TPA)在实验中的性能如何?
张量积注意力(TPA)在实验中表现出色。具体来说,在FineWeb-Edu 100B数据集上的中型(353M)、大型(773M)和XL(1.5B)模型的训练和验证损失曲线显示,TPA及其简化变体TPA-KVonly收敛速度与基线MHA、MQA、GQA和MLA相当或更快,且最终损失更低。验证困惑度曲线也表明,TPA和TPA-KVonly在训练过程中始终优于MHA、MQA、GQA和MLA,并在预训练结束时达到最低的困惑度。
在下游评估中,TPA和TPA-KVonly在中型和大型模型上均表现出色。例如,中型模型在零样本情况下的平均准确率达到51.41%,在两样本情况下的平均准确率达到53.12%。这些结果表明,TPA在各种基准测试中均优于现有的多头注意力、多查询注意力和分组查询注意力机制,解决了语言模型在处理长序列时的内存开销问题。
代码
张量积注意力(TPA)机制的核心代码主要实现在TPA类中,下面对其核心代码进行详细解读。
类定义与初始化
class TPA(nn.Module):def __init__(self, args: ModelArgs):super().__init__()# 若未指定 n_kv_heads,则使用 n_heads 的值self.n_kv_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_headsself.n_heads = args.n_heads# 若 head_dim 大于 0 则使用其值,否则通过计算得到self.head_dim = args.head_dim if args.head_dim > 0 else args.dim // args.n_headsself.n_head = args.n_headsself.q_rank = args.q_rankself.rank = args.rankself.dim = args.dimself.using_groupnorm = args.using_groupnorm# 定义 A 投影的线性层,用于 Q、K、Vself.W_A_q = nn.Linear(args.dim, self.n_head * self.q_rank, bias=False)self.W_A_k = nn.Linear(args.dim, self.n_head * self.rank, bias=False)self.W_A_v = nn.Linear(args.dim, self.n_head * self.rank, bias=False)# 定义 B 投影的线性层,用于 Q、K、Vself.W_B_q = nn.Linear(args.dim, self.q_rank * self.head_dim, bias=False)self.W_B_k = nn.Linear(args.dim, self.rank * self.head_dim, bias=False)self.W_B_v = nn.Linear(args.dim, self.rank * self.head_dim, bias=False)# 初始化缓存,用于存储 K 和 V 的值self.cache_kA = torch.zeros((args.max_batch_size, args.max_seq_len, self.n_heads, self.rank,)).cuda()self.cache_vA = torch.zeros((args.max_batch_size, args.max_seq_len, self.n_heads, self.rank,)).cuda()self.cache_kB = torch.zeros((args.max_batch_size, args.max_seq_len, self.rank, self.head_dim,)).cuda()self.cache_vB = torch.zeros((args.max_batch_size, args.max_seq_len, self.rank, self.head_dim,)).cuda()self.reset_parameters()if self.using_groupnorm:self.subln = T6GroupNorm(self.head_dim, eps=1e-5, elementwise_affine=True)
在初始化函数中,首先接收一个ModelArgs类型的参数args,然后设置一些必要的超参数,如头的数量、秩等。接着定义了两组线性层,分别用于 A 投影和 B 投影。同时,还初始化了缓存用于存储 K 和 V 的值,以便在后续计算中使用。最后,调用reset_parameters方法对权重进行初始化,并根据using_groupnorm参数决定是否使用组归一化。
权重初始化
def reset_parameters(self, args):# 将 W_A_q 的权重进行变形,然后使用 Xavier 均匀初始化W_A_q_tensor = self.W_A_q.weight.view(self.dim, self.n_head, self.q_rank)nn.init.xavier_uniform_(W_A_q_tensor)self.W_A_q.weight.data = W_A_q_tensor.view_as(self.W_A_q.weight)# 对 W_A_k 和 W_A_v 做同样的操作W_A_k_tensor = self.W_A_k.weight.view(self.dim, self.n_head, self.rank)nn.init.xavier_uniform_(W_A_k_tensor)self.W_A_k.weight.data = W_A_k_tensor.view_as(self.W_A_k.weight)W_A_v_tensor = self.W_A_v.weight.view(self.dim, self.n_head, self.rank)nn.init.xavier_uniform_(W_A_v_tensor)self.W_A_v.weight.data = W_A_v_tensor.view_as(self.W_A_v.weight)# 对 B 投影的权重做同样的操作W_B_q_tensor = self.W_B_q.weight.view(self.dim, self.q_rank, self.head_dim)nn.init.xavier_uniform_(W_B_q_tensor)self.W_B_q.weight.data = W_B_q_tensor.view_as(self.W_B_q.weight)W_B_k_tensor = self.W_B_k.weight.view(self.dim, self.rank, self.head_dim)nn.init.xavier_uniform_(W_B_k_tensor)self.W_B_k.weight.data = W_B_k_tensor.view_as(self.W_B_k.weight)W_B_v_tensor = self.W_B_v.weight.view(self.dim, self.rank, self.head_dim)nn.init.xavier_uniform_(W_B_v_tensor)self.W_B_v.weight.data = W_B_v_tensor.view_as(self.W_B_v.weight)
reset_parameters方法用于对线性层的权重进行初始化,采用 Xavier 均匀初始化方法,这有助于提高模型的训练稳定性。
前向传播
def forward(self,x: torch.Tensor,start_pos: int,freqs_cis: torch.Tensor,mask: Optional[torch.Tensor],):bsz, seqlen, _ = x.shape# 计算 A 投影的 Q、K、VA_q = self.W_A_q(x).view(bsz, seqlen, self.n_head, self.q_rank)A_k = self.W_A_k(x).view(bsz, seqlen, self.n_head, self.rank)A_v = self.W_A_v(x).view(bsz, seqlen, self.n_head, self.rank)# 计算 B 投影的 Q、K、VB_q = self.W_B_q(x).view(bsz, seqlen, self.q_rank, self.head_dim)B_k = self.W_B_k(x).view(bsz, seqlen, self.rank, self.head_dim)B_v = self.W_B_v(x).view(bsz, seqlen, self.rank, self.head_dim)# 缓存 A_k 和 A_vself.cache_kA = self.cache_kA.to(A_k)self.cache_vA = self.cache_vA.to(A_v)self.cache_kA[:bsz, start_pos : start_pos + seqlen] = A_kself.cache_vA[:bsz, start_pos : start_pos + seqlen] = A_vA_k = self.cache_kA[:bsz, : start_pos + seqlen]A_v = self.cache_vA[:bsz, : start_pos + seqlen]# 缓存 B_k 和 B_vself.cache_kB = self.cache_kB.to(B_k)self.cache_vB = self.cache_vB.to(B_v)self.cache_kB[:bsz, start_pos : start_pos + seqlen] = B_kself.cache_vB[:bsz, start_pos : start_pos + seqlen] = B_vB_k = self.cache_kB[:bsz, : start_pos + seqlen]B_v = self.cache_vB[:bsz, : start_pos + seqlen]# 重塑 A_q、A_k、A_vA_q = A_q.view(bsz * seqlen, self.n_head, self.q_rank)A_k = A_k.view(bsz * seqlen, self.n_head, self.rank)A_v = A_v.view(bsz * seqlen, self.n_head, self.rank)# 重塑 B_q、B_k、B_vB_q = B_q.view(bsz * seqlen, self.q_rank, self.head_dim)B_k = B_k.view(bsz * seqlen, self.rank, self.head_dim)B_v = B_v.view(bsz * seqlen, self.rank, self.head_dim)# 计算 q、k、vq = torch.bmm(A_q, B_q).div_(self.q_rank).view(bsz, seqlen, self.n_head, self.head_dim)k = torch.bmm(A_k, B_k).div_(self.rank).view(bsz, seqlen, self.n_head, self.head_dim)v = torch.bmm(A_v, B_v).div_(self.rank).view(bsz, seqlen, self.n_head, self.head_dim)# 应用旋转位置嵌入q, k = apply_rotary_emb(q, k, freqs_cis=freqs_cis)# 计算注意力分数k = k.transpose(1, 2) scores = torch.matmul(q.transpose(1, 2), k.transpose(2, 3)) / math.sqrt(self.head_dim)if mask is not None:scores = scores + mask scores = F.softmax(scores.float(), dim=-1).type_as(q)# 计算输出output = torch.matmul(scores, v.transpose(1, 2)) output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1)return self.wo(output)
在前向传播函数中,首先获取输入的形状。然后分别计算 A 投影和 B 投影的 Q、K、V,并对其进行缓存。接着对 A 和 B 投影的结果进行重塑,通过矩阵乘法计算最终的 q、k、v。之后应用旋转位置嵌入,计算注意力分数并进行归一化,最后通过矩阵乘法得到输出。
相关文章:
【拜读】Tensor Product Attention Is All You Need姚期智团队开源兼容RoPE位置编码
姚期智团队开源新型注意力:张量积注意力(Tensor Product Attention,TPA)。有点像一种「动态的LoRA」,核心思路在于利用张量分解来压缩注意力机制中的 Q、K、V 表示,同时保留上下文信息,减少内存…...
Docker-技术架构演进之路
目录 一、概述 常见概念 二、架构演进 1.单机架构 2.应用数据分离架构 3.应用服务集群架构 4.读写分离 / 主从分离架构 5.引入缓存 —— 冷热分离架构 6.垂直分库 7.业务拆分 —— 微服务 8.容器化引入——容器编排架构 三、尾声 一、概述 在进行技术学习过程中&am…...
用Chrome Recorder轻松完成自动化测试脚本录制
前言 入门自动化测试,录制回放通常是小白测试首先用到的功能。而录制回放工具也一直是各大Web自动化测试必然会着重提供的一块功能。 早期WinRunner、QTP这样的工具,自动化测试可以说是围绕录制回放开展的。近年像Selenium也提供有录制工具 Selenium IDE,Playwright也包含…...
python中的异常-模块-包
文章目录 异常异常的定义异常捕获语法捕获常规异常捕获指定异常捕获多个异常捕获所有异常异常else异常finally 异常传递总结 模块概念导入自定义模块及导入main方法all变量 总结 包自定义包定义pycharm中建包的基本步骤导入方式 第三方包 异常 异常的定义 当检测到一个错误时…...
【GPU驱动】OpenGLES图形管线渲染机制
OpenGLES图形管线渲染机制 OpenGL/ES 的渲染管线也是一个典型的图形流水线(Graphics Pipeline),包括多个阶段,每个阶段都负责对图形数据进行处理。管线的核心目标是将图形数据转换为最终的图像,这些图像可以显示在屏幕…...
ssm-day06 ssm整合
从springMVC总结再回顾一下 60节 整合就是应用框架,并且把这个框架放到IOC容器中 web容器:装springMVC和controller相关的web组件 root容器:装业务和持久层相关的组件 子容器可以引用父容器中的组件,父容器不能调子容器 一个容器…...
AI 编程助手 cursor的系统提示词 prompt
# Role 你是一名极其优秀具有10年经验的产品经理和精通java编程语言的架构师。与你交流的用户是不懂代码的初中生,不善于表达产品和代码需求。你的工作对用户来说非常重要,完成后将获得10000美元奖励。 # Goal 你的目标是帮助用户以他容易理解的…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_process_options
ngx_process_options 声明在 src\core\nginx.c static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); 定义在 src\core\nginx.c static ngx_int_t ngx_process_options(ngx_cycle_t *cycle) {u_char *p;size_t len;if (ngx_prefix) {len ngx_strlen(ngx_prefix);p …...
ollama如何安全卸载,解决Ollama unins000.msg is missing
春节后在本地电脑安装了Ollama的客户端,每次开机自启,影响开机速度,而且本地的模型不如联网的回答效果好,果断选择了卸载,但是今天卸载发现提示下方的错误。根据此文章可以解决当前的问题。 根据此文章可以解决当前的…...
网络安全设备防护原理 网络安全防护装置
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 防火墙 简介 网络层的防护设备,依照特殊的规则允许或者限制传输的数据通过 是由软件和硬件设备组合而成,在内部网和外部网之间、专用网…...
Python的那些事第二十八篇:数据分析与操作的利器Pandas
Pandas:数据分析与操作的利器 摘要 Pandas是基于Python的开源数据分析库,广泛应用于数据科学、机器学习和商业智能等领域。它提供了高效的数据结构和丰富的分析工具,能够处理结构化数据、时间序列数据以及复杂的数据转换任务。本文从Pandas的基础概念入手,深入探讨其核心…...
学习threejs,使用MeshBasicMaterial基本网格材质
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.MeshBasicMaterial 二…...
【git-hub项目:YOLOs-CPP】本地实现05:项目移植
ok,经过前3个博客,我们实现了项目的跑通。 但是,通常情况下,我们的项目都是需要在其他电脑上也跑通,才对。 然而,经过测试,目前出现了2 个bug。 项目一键下载【⬇️⬇️⬇️】: 精…...
Html5学习教程,从入门到精通,HTML5 元素语法知识点及案例代码(2)
HTML5 元素语法知识点及案例代码 一、HTML5 元素概述 HTML5 元素是构成网页的基本单位,每个元素都有特定的语义和功能。HTML5 元素由开始标签、内容和结束标签组成,例如: <p>这是一个段落。</p><p> 是开始标签这是一个段…...
【python】协程(coroutine)
协程(coroutine)可以理解为一个可以中途暂停保存当前执行状态信息并可以从此处恢复执行的函数,多个协程共用一个线程执行,适合执行需要“等待”的任务。 所以严格意义上,多个协程同一时刻也只有一个在真正的执行&#…...
【编译器】-LLVMIR
概述 LLVM 是一种基于静态单赋值 (SSA) 的表示形式,提供类型安全、低级操作、灵活性以及干净地表示“所有”高级语言的能力。 LLVM IR 是一门低级语言,语法类似于汇编任何高级编程语言(如C)都可以用LLVM IR表示基于LLVM IR可以很…...
java面试场景问题
还在补充,这几天工作忙,闲了会把答案附上去,也欢迎各位大佬评论区讨论 1.不用分布式锁如何防重复提交 方法 1:基于唯一请求 ID(幂等 Token) 思路:前端生成 一个唯一的 requestId(…...
算法菜鸡备战3月2日传智杯省赛----0221
2209. 用地毯覆盖后的最少白色砖块 - 力扣(LeetCode) 力扣每日一题 class Solution { public:// 白色最少 黑色最多int minimumWhiteTiles(string floor, int numCarpets, int carpetLen) {int n floor.size();// 记忆化搜索vector memo(n 1, vector&…...
python pandas下载
pandas pandas:就是一个可以处理数据的 python 库 核心功能: 数据的清洗:处理丢失值,重复值数据分析:计算和统计信息,或分组汇总数据可视化:结合 图标库(Matplotlib)完成数据可视化…...
高斯牛顿法(GN)与列文伯格-马夸尔特方法在ORB-SLAM3中的应用
问题背景 高斯牛顿法(Gauss-Newton, GN)和列文伯格-马夸尔特方法(Levenburg-Marquadt, LM)是两种最常用的非线性优化方法,这两种方法在ORB-SLAM3系统中均有使用。 在ORB-SLAM3前端跟踪线程(Tracking)中,局…...
Python+Selenium+Pytest+POM自动化测试框架封装
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 1、测试框架简介 1)测试框架的优点 代码复用率高,如果不使用框架的话,代码会显得很冗余。可以组装日志、报告、邮件等一些高…...
猿大师中间件:网页直接内嵌本机EXE、OCX控件、ActiveX控件或桌面应用程序神器
猿大师中间件自从2019年发布以来,迄今为止不断迭代升级,给第三方提供了将自己的桌面程序和OCX控件支持直接内嵌到浏览器网页运行的赋能SDK开发包。 目前针对不同需求发布了三个成熟且商用的产品: 猿大师播放器:浏览器中直接原生…...
【Python】03-Python语法入门
文章目录 1、基本概念1.1、表达式1.2、语句1.3、程序(program)1.4、函数(function) 2、基本语法3、字面量与变量4、变量与标识符 1、基本概念 1.1、表达式 表达式就是一个类似于数学公式的东西,表达式一般仅用来计算一…...
C++,设计模式,【工厂方法模式】
文章目录 如何用汽车生产线理解工厂方法模式?一、传统生产方式的困境二、工厂方法模式解决方案三、模式应用场景四、模式优势分析五、现实应用启示✅C++,设计模式,【目录篇】 如何用汽车生产线理解工厂方法模式? 某个早晨,某车企CEO看着会议室里堆积如面的新车订单皱起眉…...
跟着 Lua 5.1 官方参考文档学习 Lua (5)
文章目录 2.10 – Garbage Collection2.10.1 – Garbage-Collection Metamethods2.10.2 – Weak Tables 2.10 – Garbage Collection Lua performs automatic memory management. This means that you have to worry neither about allocating memory for new objects nor abo…...
9.PG数据库层权限管理(pg系列课程)第2遍
一、PostgreSQL数据库属主 Postgres中的数据库属主属于创建者,只要有createdb的权限就可以创建数据库,数据库属主不一定拥有存放在该数据库中其它用户创建的对象的访问权限。数据库在创建后,允许public角色连接,即允许任何人连接…...
鸿蒙-canvas-画时钟
文章目录 前言准备分析组成部分数值计算过程 开始第一步 画圆环第二步 画格子第三步 画数字第四、五步 画指针&定时更新最后一步 前言 你在 Android 上能画出来的东西,在鸿蒙上画不出来? 画个时钟嘛,有啥难的? 你行你上&…...
【AI实践】阿里百炼文本对话Agent安卓版搭建
环境:安卓手机运行环境;WinsurfAI编程工具;阿里百炼提前创建Agent应用; 耗时:2小时; 1,新建安卓项目 完成文本输入,并将输入的文字显示出来。 2,安装SDK 参考文档 安…...
算法很美笔记(Java)——动态规划
解重叠子问题(当前解用到了以前求过的解) 形式:记忆型递归或递推(dp) 动态规划本质是递推,核心是找到状态转移的方式,也就是填excel表时的逻辑(填的方式),而…...
Jest单元测试
由于格式和图片解析问题,可前往 阅读原文 前端自动化测试在提高代码质量、减少错误、提高团队协作和加速交付流程方面发挥着重要作用。它是现代软件开发中不可或缺的一部分,可以帮助开发团队构建可靠、高质量的应用程序 单元测试(Unit Testi…...
