大模型系列——旋转位置编码和长度外推

绝对位置编码

 旋转位置编码

 

 

论文中有个很直观的图片展示了旋转变换的过程: 

对于“我”对应的d维向量, 拆分成d/2组以后,每组对应一个角度\theta,若\theta1对应的向量为(x1,x2),应用旋转位置编码,相当于这个分量旋转了m\theta1角度。

结合transformer4.42.4版本,qwen2源码分析如下:

1、定义和缓存cos、sin

class Qwen2RotaryEmbedding(nn.Module):def __init__(self, dim, max_position_embeddings=2048, base=10000, device=None):super().__init__()self.dim = dimself.max_position_embeddings = max_position_embeddingsself.base = baseinv_freq = 1.0 / (self.base ** (torch.arange(0, self.dim, 2, dtype=torch.int64).float().to(device) / self.dim))self.register_buffer("inv_freq", inv_freq, persistent=False)# Build here to make `torch.jit.trace` work.self._set_cos_sin_cache(seq_len=max_position_embeddings, device=self.inv_freq.device, dtype=torch.get_default_dtype())def _set_cos_sin_cache(self, seq_len, device, dtype):self.max_seq_len_cached = seq_lent = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq)freqs = torch.outer(t, self.inv_freq)# Different from paper, but it uses a different permutation in order to obtain the same calculationemb = torch.cat((freqs, freqs), dim=-1)self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)def forward(self, x, seq_len=None):# x: [bs, num_attention_heads, seq_len, head_size]if seq_len > self.max_seq_len_cached:self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype)return (self.cos_cached[:seq_len].to(dtype=x.dtype),self.sin_cached[:seq_len].to(dtype=x.dtype),)

在上面这段代码中,inv_freq对应的是各分量的旋转角度,长度为d/2

        t = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq)freqs = torch.outer(t, self.inv_freq)

这里的t为提前把所有可能的位置id 都先取好,并与对应的角度相乘,对应公式中的m\theta,计算出来的矩阵freqs维度为(self.max_seq_len,d/2)。这里outer函数计算如下:

torch.outerimport torch
t = torch.tensor([1,2,3])
inv_freq = torch.tensor([0.1,0.2,0.3])
f = torch.outer(t, inv_freq)
tensor([[0.1000, 0.2000, 0.3000],[0.2000, 0.4000, 0.6000],[0.3000, 0.6000, 0.9000]])emb = torch.cat((f,f), dim=-1)
emb
tensor([[0.1000, 0.2000, 0.3000, 0.1000, 0.2000, 0.3000],[0.2000, 0.4000, 0.6000, 0.2000, 0.4000, 0.6000],[0.3000, 0.6000, 0.9000, 0.3000, 0.6000, 0.9000]])

这样取每一行,即对应这个id下的所有m\theta值。

通过cat,拼接出来的emb后半部分和前半部分是一致的,维度变成d

2、apply_rotary_pos_emb

def rotate_half(x):"""Rotates half the hidden dims of the input."""x1 = x[..., : x.shape[-1] // 2]x2 = x[..., x.shape[-1] // 2 :]return torch.cat((-x2, x1), dim=-1)def apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1):cos = cos[position_ids].unsqueeze(unsqueeze_dim)sin = sin[position_ids].unsqueeze(unsqueeze_dim)q_embed = (q * cos) + (rotate_half(q) * sin)k_embed = (k * cos) + (rotate_half(k) * sin)return q_embed, k_embed

再简单介绍下rotate_half这个函数,我们模拟下:

q = torch.tensor([0.1000, 0.2000, 0.3000, 0.4000, 0.5000, 0.6000])rotate_q = rotate_half(q) 
rotate_q 
tensor([-0.4000, -0.5000, -0.6000,  0.1000,  0.2000,  0.3000])

可以看出,q的最后一维后半部分取反后放到了前面,这里和论文中的公式是有区别的。问了下kimi解释如下:

原始论文中可能采用了不同的子空间划分方法,例如将维度0, 1, 2, 3划分为{0, 1}和{2, 3}两组。而在HuggingFace的实现中,可能采用了不同的划分方式,例如将维度0, 1, 2, 3划分为{0, 2}和{1, 3}两组。这两种划分方法都是合理的,只是子空间的划分不同,但最终都能达到相同的旋转编码效果。

因此,即使rotate_half函数的实现与论文中的公式看起来不一样,但由于其最终效果相同,这种实现差异是可以接受的。重要的是理解旋转位置编码的核心思想,即通过旋转操作将位置信息编码到模型中,而不是纠结于具体的实现细节。

3、attention forward

query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)if past_key_value is not None:cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}  # Specific to RoPE modelskey_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)# repeat k/v heads if n_kv_heads < n_heads
key_states = repeat_kv(key_states, self.num_key_value_groups)
value_states = repeat_kv(value_states, self.num_key_value_groups)attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim)

参考:

(1)十分钟读懂旋转编码(RoPE):https://zhuanlan.zhihu.com/p/647109286

(2)旋转位置编码RoPE最通俗易懂解释,https://zhuanlan.zhihu.com/p/701576694

ROPE优化——长度外推

本节来自:Transformer升级之路:16、“复盘”长度外推技术 - 科学空间|Scientific Spaces

顾名思义,免训练长度外推,就是不需要用长序列数据进行额外的训练,只用短序列语料对模型进行训练,就可以得到一个能够处理和预测长序列的模型,即“Train Short, Test Long”。那么如何判断一个模型能否用于长序列呢?最基本的指标就是模型的长序列Loss或者PPL不会爆炸,更加符合实践的评测则是输入足够长的Context,让模型去预测答案,然后跟真实答案做对比,算BLEU、ROUGE等,LongBench就是就属于这类榜单。

但要注意的是,长度外推应当不以牺牲远程依赖为代价——否则考虑长度外推就没有意义了,倒不如直接截断文本——这意味着通过显式地截断远程依赖的方案都需要谨慎选择,比如ALIBI以及《Transformer升级之路:7、长度外推性与局部注意力》所列举的大部分方案,还有带显式Decay的线性RNN,这些方案当序列长度足够大时都表现为局部注意力,即便有可能实现长度外推,也会有远程依赖不足的风险,需要根据自己的场景斟酌使用。

如何判断在长度外推的同时有没有损失远程依赖呢?比较严谨的是像《Transformer升级之路:12、无限外推的ReRoPE?》最后提出的评测方案,准备足够长的文本,但每个模型只算每个样本最后一段的指标,如下图所示:

 

比如,模型训练长度是4K,想要看外推到16K的效果,那么我们准备一个16K tokens的测试集,4K的模型输入每个样本最后4K tokens算指标,8K模型输入每个样本最后8K tokens但只算最后4K tokens算指标,12K模型输入每个样本最后12K tokens但只算最后4K tokens算指标;依此类推。这样一来,不同长度的模型算的都是同一段tokens的指标,不同的只是输入的Context不一样,如果远程依赖得以有效保留,那么应该能做到Context越长,指标越好。

问题:如果ABC和MNOP没有强关联关系呢? 如何评判优劣?

先说个题外话,为什么如今大部分LLM的位置编码都选择了RoPE呢?笔者认为主要有几点原因:

1、RoPE不带有显式的远程衰减,这对于旨在Long Context的模型至关重要;

2、RoPE是一种真正的位置编码,通过不同频率的三角函数有效区分了长程和短程,达到了类似层次位置编码的效果,这也是Long Context中比较关键的一环;

3、RoPE直接作用于Q、K,不改变Attention的形式,与Flash Attention更契合,更容易Scale Up。

相比之下,诸如ALIBI、KERPLE等,虽然有时也称为位置编码,但它们实际上只是一种Attention Bias,没有太多位置信息,且不适用于Encoder,能用于Decoder大体上是因为Decoder本身的下三角Mask就已经有较为充分的位置Bias了,额外的Attention Bias只是锦上添花。此外它们无法在单个头内有效区分长程和短程,而是要通过在不同头设置不同的Decay因子来实现,这也意味着它们用于单头注意力(比如GAU)的效果会欠佳。

说这么多优缺点的对比,看起来像是“王婆卖瓜,自卖自夸”,其实不然,这只是为了跟大家交换一下观点,因为之前也有读者提出过相同的问题。作为RoPE的提出者,笔者对RoPE的理解不见得一定比大家深刻,毕竟当时提出RoPE的初衷纯粹是好玩,当时的想法是有效就很不错了,能媲美Learnable的绝对位置编码就是非常好的消息了。所以,既然是“意料之外”,那么“作者本人也没多透彻的认识”这件事,也是“情理之中”了。

好像又把话题扯偏了。简单来说,其实上两节的内容主要是想表达的观点是:目前看来,RoPE对于Long Context来说是足够的,所以研究RoPE的长度外推是有价值的,以及我们在选择长度外推方案时,不应牺牲远程依赖的能力

1、窗口截断

在本站最早讨论长度外推的《Transformer升级之路:7、长度外推性与局部注意力》一文中,我们判断长度外推是一个预测阶段的OOD(Out Of Distribution)的问题,尽管用今天的视角看,这篇文章的一些评述已经显得有点过时,但这个根本判断是依然还算正确,放到RoPE中,就是推理阶段出现了没见过的相对距离。为此,一个看上去可行的方案是引入Sliding Window的Attention Mask,如下图左所示:

当然,由于强行截断了窗口外的注意力,所以这个方案并不满足“不牺牲远程依赖的能力”的原则,但我们可以只将它作为一个Baseline看待。很遗憾的是,即便做出了如此牺牲,这个方案却是不Work的——连最基本的PPL不爆炸都做不到!

答案可能让人意外:开头的几个Token很重要,不能扔掉。所以最后可用的Window Mask应该如上图右(LM-Infinite这篇论文管它叫“ΛΛ-Mask”)。

2、位置内插-PI

一位网名为“kaiokendev”的网友在他的博客《https://kaiokendev.github.io/til#extending-context-to-8k》中提出了一个非常朴素的解决办法——“位置内插”——将预测的长文本的位置编码乘上因子LtrainLtest�����������,缩放到训练长度范围内,如下式所示(式中的位置都是相对位置)。没过多久,Meta在论文《Extending Context Window of Large Language Models via Positional Interpolation》中也发布了同样的方法,命名为“Positional Interpolation(PI)”,并补充了较为充分的实验结果。

然而,位置内插并不算长度外推方案,至少不是免训练的长度外推方案,因为位置内插之后同样会有PPL爆炸的问题。原因也不难理解,尽管位置内插避免了远处的位置越界问题,但这同时压缩了邻近Token的距离,严重扰乱了模型的局部分辨率,而众所周知语言模型本身就是一个非常依赖于局部关系的任务,所以扰乱了局部自然就没法预测准了。

不过,这也并非说位置内插就没有价值了。我们知道,需要长度外推的读者,无外乎是两种情况:一种是没有资源去做长文本微调,希望能够从短文本模型直接得到一个可用的长文本模型,这种需求对长度外推的效果要求会比较高,位置内插就不适合他们了;另一种是有资源去做长文本微调,研究长度外推纯粹是为了得到一个更好的初始化模型,这种情况对模型修改带来的初始损失容忍度比较高,只要能够通过微调快速弥补回损失掉的效果即可,位置内插正好是属于此类方法。Meta的论文显示,经过PI之后,仅需1000步左右的长文本训练,就可以得到一个行之有效的长文本模型,这比不做任何修改直接微调的训练效率高出很多。

3、保近压远-ReRope 

直接外推的问题是远处越界,而位置内插的问题是局部失真,看上去两者是互补的,能不能集两者之长呢?这就是《Transformer升级之路:12、无限外推的ReRoPE?》所提出的Leaky ReRoPE,以及它的极限版本ReRoPE。

如果将内插的因子k�取到无穷大,这就得到极简的ReRoPE,它在窗口外的位置编码都变为w�,意味着对于任意长的序列都不会越界,即理论上具备无限外推的潜力!事实上,Leaky ReRoPE和ReRoPE的表现确实都非常好,从Loss来看,它们能做到几乎不损失训练长度内的效果,并且实现了长度外推,且Context越长,Loss越低,说明它们在外推的同时还确实保证了远程依赖。

Leaky ReRoPE和ReRoPE的主要问题在于它们的代码实现稍微有点麻烦。跟Attention Bias类的位置编码不同,RoPE没法通过先构造相对位置矩阵然后才计算相对位置编码的方式来实现(那样效率太低),只能通过绝对位置编码的方式来实现相对位置编码,这意味着它只能实现线性增长的相对位置,而Leaky ReRoPE和ReRoPE的相对位置是分段线性的,这意味着朴素地实现的话,需要算两次Attention矩阵(得到两段不同的线性)然后将它们拼接起来,这样效率无疑明显降低了。

不过,好消息是当前主流的Attention加速手段如Flash Attention都是将Attention分块计算的,比如每128长度为一块,这样当序列足够长时,分段线性的块占比非常少(只有窗口边界附近),如下式所示,只有红绿混色的块才需要重复计算Attention,剩下同色的块都只需要计算一次,所以结合分块计算Attention的话,Leaky ReRoPE和ReRoPE所增加的计算成本时几乎可以忽略的。此前读者 @chu-tianxiang 在评论区也分享了一个基于Triton的实现,大家有兴趣的可以参考一下。

月初Arxiv上提交了一篇论文《LLM Maybe LongLM: Self-Extend LLM Context Window Without Tuning》,其中提出了一种名为“Self-Extend”的免训练长度外推方法,它实际上就是在Leaky ReRoPE的基础上加了Round运算(四舍五入),使得每个相对位置都变回整数,进一步减轻相对位置的OOD问题。论文报告的效果也很好,这进一步肯定了Leaky ReRoPE的有效性。

4、转圈视角-YaRN

备注:i->0时为高频,转的越快。

结论:YaRN效果略逊于ReRope。我感觉是内插的时候过于随意,这种修改没有保证窗口内的局部注意力不变,也许YaRN可以和ReRope结合。

备注:这里的缩放因子,一会会提到

就像NTK-RoPE、YaRN的作者Bowen Peng曾经的观点,高频学习到的是局部的相对距离,低频学习到的是远程的绝对距离,两者都很重要,它们之间更像是一种层次的关系;

5、首个外推方案-NTK-ROPE

相比YaRN本身,YaRN的作者Bowen Peng的故事也许更加称得上“引人入胜”,他早前所提出的NTK-RoPE是RoPE的第一个免训练的长度外推方案,本系列的两篇博客《Transformer升级之路:10、RoPE是一种β进制编码》和《Transformer升级之路:11、将β进制位置进行到底》都直接受启发于它。虽然从目前来看,NTK-RoPE的效果不见得多好(相比YaRN、ReRoPE等),但它首次显示了免训练长度外推的可能性,具有里程碑式的意义,甚至可以说,后续的所有长度外推相关研究,都直接或者间接得益于NTK-RoPE打开了大家的想象力。

不过,尽管NTK-RoPE效果上不如YaRN,但对于前面提到的第二种有资源去做长文本微调的读者,可能会更喜欢NTK-RoPE,因为他们只是为了得到一个更好的初始化模型,反正都是要微调,NTK-RoPE与YaRN的初始效果差异他们并不会太在意,相比之下他们更乐意选择实现更简单的NTK-RoPE了,比如CodeLLAMA就是在LLAMA2的基础上将base改为10的6次方,然后继续训练的。此外,Meta在其论文《Effective Long-Context Scaling of Foundation Models》中,将NTK-RoPE改称为RoPE-ABF(Adjusted Base Frequency),相比神秘的NTK,ABF的名称能更直观体现出它的含义。

6、拒绝交税-Dynamic Scaling和CLEX

备注:从公式可以看出,核心思想就是Ltrain训练窗口长度内的位置不缩放,之外的缩放 

在llama的官方代码中,有一个DynamicNTKScalingRotary实现如下(结合以上公式就比较容易看懂了):

class LlamaDynamicNTKScalingRotaryEmbedding(LlamaRotaryEmbedding):"""LlamaRotaryEmbedding extended with Dynamic NTK scaling. Credits to the Reddit users /u/bloc97 and /u/emozilla"""def forward(self, x, position_ids):# difference to the original RoPE: inv_freq is recomputed when the sequence length > original lengthseq_len = torch.max(position_ids) + 1if seq_len > self.max_position_embeddings:base = self.base * ((self.scaling_factor * seq_len / self.max_position_embeddings) - (self.scaling_factor - 1)) ** (self.dim / (self.dim - 2))inv_freq = 1.0 / (base ** (torch.arange(0, self.dim, 2, dtype=torch.int64).float().to(x.device) / self.dim))self.register_buffer("inv_freq", inv_freq, persistent=False)  # TODO joao: this may break with compilationcos, sin = super().forward(x, position_ids)return cos, sin

 另外llama官方代码中还有一个线性scaling,也记录一下:

class LlamaLinearScalingRotaryEmbedding(LlamaRotaryEmbedding):"""LlamaRotaryEmbedding extended with linear scaling. Credits to the Reddit user /u/kaiokendev"""def forward(self, x, position_ids):# difference to the original RoPE: a scaling factor is aplied to the position idsposition_ids = position_ids.float() / self.scaling_factorcos, sin = super().forward(x, position_ids)return cos, sin

问题:窗口内的是否真的做到了拒绝交税,窗口外的是否没有丢失远程信息 ?

7、另起炉灶 HWFA和Key  Norm

除了Dynamic Scaling外,“拒绝交税”的另一个思路是“另起炉灶”,通过重新设计预训练时所用的模型架构,使得它具备训练完成后就可以不做任何修改实现长度外推的潜力,在这个系列的文章中,笔者有两篇相关的探讨,分别是在《Transformer升级之路:9、一种全局长度外推的新思路》所提到HWFA(Hybird Window-Full Attention),以及在《Transformer升级之路:15、Key归一化助力长度外推》所验证的Key Norm。

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

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

相关文章

路径规划 | 基于极光PLO优化算法的三维路径规划Matlab程序

效果一览 基本介绍 研究内容 极光优化算法&#xff08;PLO&#xff09;的深入理解&#xff1a; 研究极光优化算法的基本原理&#xff0c;包括模拟带电粒子在地球磁场中的旋转运动、极光椭圆区域内的行走以及粒子间的碰撞等。 分析PLO算法的全局搜索能力和局部开发能力&#xf…

MATLAB画柱状图

一、代码 clear; clc; figure(position,[150,100,900,550])%确定图片的位置和大小&#xff0c;[x y width height] %准备数据 Y1[0.53,7.9,8.3;0.52,6.8,9.2;0.52,5.9,8.6;2.8,5.8,7.9;3.9,5.2,7.8;1.8,5.8,8.4]; % withoutNHC X11:6; %画出4组柱状图&#xff0c;宽度1 h1…

[实用指南]如何将视频从iPhone传输到iPad

概括 将视频从 iPhone 传输到 iPad 时遇到问题&#xff1f;您可能知道一种方法&#xff0c;但不知道如何操作。此外&#xff0c;您要传输的视频越大&#xff0c;完成任务就越困难。那么如何将视频从 iPhone 传输到 iPad&#xff0c;特别是当您需要发送大视频文件时&#xff1f…

Git命令行的使用

目录 一、什么是Git 1、本地仓库 vs 远端仓库 本地仓库 远端仓库 2、.git vs .gitignore .git .gitignore 二、使用Git命令 1、安装git 2、git首次使用需要配置用户邮箱和用户名 3、上传目录/文件到远端仓库步骤 1&#xff09;创建放置文件的目录 2&#xff09;cd…

黑马JavaWeb开发跟学(十五).Maven高级

黑马JavaWeb开发跟学.十五.Maven高级 Maven高级1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承关系2.1.1.1 思路分析2.1.1.2 实现 2.1.2 版本锁定2.1.2.1 场景2.1.2.2 介绍2.1.2.3 实现2.1.2.4 属性配置 2.2 聚合2.2.1 介…

十二、Vue 路由

文章目录 一、简介二、安装与基本配置安装 Vue Router创建路由实例在应用中使用路由实例三、路由组件与视图路由组件的定义与使用四、动态路由动态路由参数的定义与获取动态路由的应用场景五、嵌套路由嵌套路由的概念与配置嵌套路由的应用场景六、路由导航<router - link>…

AE RFG 1251 Generator User Manual

AE RFG 1251 Generator User Manual

vue2、element的el-select 选项框的宽度设置、文本过长问题

<el-select v-model"value" placeholder"请选择"><el-optionv-for"item in cities":key"item.value":label"item.label":value"item.value"><el-tooltip class"item" :content"ite…

【Matlab算法】基于改进人工势场法的移动机器人路径规划研究(附MATLAB完整代码)

基于改进人工势场法的移动机器人路径规划研究 结果图摘要1. 引言2. 方法说明2.1 基本原理2.2 改进策略3. 核心函数解释3.1 改进的斥力计算函数3.2 路径规划主函数4. 实验设计4.1 实验环境设置4.2 关键参数选择5. 结果分析5.1 实验结果5.2 性能分析附录:完整代码参考文献结果图…

【MySQL】--- 内置函数

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL &#x1f3e0; 时间函数 约定&#xff1a;我们在MySQL中说的日期指的是年 月 日&#xff0c;时间指的是时 分 秒。 &#x1f9f7; now() select n…

springboot和vue项目前后端交互

java后端开发常用springboot框架&#xff0c;开发简单不繁琐&#xff0c;容易上手。简简单单配置好一些配置项&#xff0c;整个web项目就能运行起来了。vue前端也是比较流行的前端开发框架&#xff0c;写起来简单&#xff0c;组件也丰富&#xff0c;参考资料多。 这期就应薯薯…

酒店管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…

OkHttp接口自动化测试

文章目录 java环境搭建OkHttp之getOkHttp之POSTPOST发送From表单POST发送jsonPOST上传文件 OkHttp之deleteOkHttp之put java环境搭建 引入依赖 <!--okhttp3--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</art…

分数阶傅里叶变换代码 MATLAB实现

function Faf myfrft(f, a) %分数阶傅里叶变换函数 %输入参数&#xff1a; %f&#xff1a;原始信号 %a&#xff1a;阶数 %输出结果&#xff1a; %原始信号的a阶傅里叶变换N length(f);%总采样点数 shft rem((0:N-1)fix(N/2),N)1;%此项等同于fftshift(1:N)&#xff0c;起到翻…

【Rust练习】26.Package and Crate

练习题来自&#xff1a;https://practice-zh.course.rs/crate-module/crate.html 建议在命令行下操作完成本节内容&#xff0c;Windows 11/10 首选 Windows 终端&#xff0c;好看&#xff0c;支持渲染中文字体&#xff0c;缺点是功能太少了&#xff1b;其次推荐 mobaxterm&…

Python实现接口签名调用

目录: 1、第三方接口签名调用2、调用结果 1、第三方接口签名调用 import json import requests import hashlib import time import hmac access_key xxxxxxxxxxxxxxx secret_key xxxxxxxxxxxxxxx # 应用信息 def _wps4_sig(method, url, date, body): print(body)if bod…

df.replace({‘b‘: r‘\s*(\.)\s*‘}, {‘b‘: r‘\1ty‘}, regex=True)

这段代码 df.replace({b: r\s*(\.)\s*}, {b: r\1ty}, regexTrue) 用于在 DataFrame 中进行替换操作&#xff0c;具体来说是针对 b 列&#xff0c;匹配并替换符合正则表达式的值。 详细解析&#xff1a; df.replace()&#xff1a;这是 Pandas 中的 replace() 方法&#xff0c;用…

js的一些处理

1.翻转字符串 let str abcdef str str.split().reverse().join() console.log(str) 因此想到了我之前写的截取字符串获取参数跳转&#xff0c;在写一遍 let str nameJack&age18&gender男 let list str.split(&); let obj {} list.forEach((v)>{ …

单片机串口控制

1.使用微控制器输入串口指令控制LED灯亮灭 main.c #include "uart4.h"int main() {led_init(); //初始化LED相关寄存器char buf[128];while(1){gets(buf);if(mystrcmp(buf,"LED1_on") 0){led_ctl(1,1); //当在串口工具中输入"LED1_on"时控制L…

物联网开发利器:基于web的强大的可拖拽组态软件

随着互联网、物联网技术的快速发展&#xff0c;BY组态基于多年研发积累和私有部署实践打磨、以及对业务场景的深入理解&#xff0c;推出了适用于物联网应用场景的轻量型web组态软件。 该产品采用 B/S 架构&#xff0c;提供 web 管理界面&#xff0c;软件包大小仅 50MB&#xf…