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

绝对位置编码

 旋转位置编码

 

 

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

对于“我”对应的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 = dim
        self.max_position_embeddings = max_position_embeddings
        self.base = base
        inv_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_len
        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)
        # Different from paper, but it uses a different permutation in order to obtain the same calculation
        emb = 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.outer

import 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 models
    key_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 length
        seq_len = torch.max(position_ids) + 1
        if 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 compilation

        cos, 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 ids
        position_ids = position_ids.float() / self.scaling_factor
        cos, 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。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全威胁2024年中报告

下载地址&#xff1a; 网络安全威胁2024年中报告-奇安信

Momentum Contrast for Unsupervised Visual Representation Learning论文笔记

文章目录 论文地址动量队列对比学习的infoNCE loss为什么需要动量编码器对比学习moco方法中的动量Encoder为什么不能与梯度Encoder完全相同为什么动量编码器和梯度编码器不能完全相同&#xff1f;总结&#xff1a; 我理解&#xff0c;正负样本应该经过同一个encoder&#xff0c…

Unity 使用UGUI制作卷轴开启关闭效果

视频效果 代码 using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options;public class JuanZhou : MonoBehaviour {[SerializeField]private …

plsql :用户system通过sysdba连接数据库--报错ora-01031

一、winR cmd通过命令窗口登录sys用户 sql sys/[password]//localhost:1521/[service_name] as sysdba二、输入用户名:sys as sysdba 三、输入密码:自己设的 四、执行grant sysdba to system; 再去PL/SQL连接就可以了

ubuntu 使用samba与windows共享文件[注意权限配置]

在Ubuntu上使用Samba服务与Windows系统共享文件&#xff0c;需要正确配置Samba服务以及相应的权限。以下是详细的步骤&#xff1a; 安装Samba 首先&#xff0c;确保你的Ubuntu系统上安装了Samba服务。 sudo apt update sudo apt install samba配置Samba 安装完成后&#xff0c…

Java - 日志体系_Apache Commons Logging(JCL)日志接口库_适配Log4j2 及 源码分析

文章目录 PreApache CommonsApache Commons ProperLogging &#xff08;Apache Commons Logging &#xff09; JCL 集成Log4j2添加 Maven 依赖配置 Log4j2验证集成 源码分析1. Log4j-jcl 的背景2. log4j-jcl 的工作原理2.1 替换默认的 LogFactoryImpl2.2 LogFactoryImpl 的实现…

仓颉编程语言:编程世界的 “文化瑰宝”

我的个人主页 在当今编程领域百花齐放的时代&#xff0c;各种编程语言争奇斗艳&#xff0c;服务于不同的应用场景和开发者群体。然而&#xff0c;有这样一种编程语言&#xff0c;它承载着独特的文化内涵&#xff0c;宛如编程世界里一颗熠熠生辉的“文化瑰宝”&#xff0c;那就…

Prompt工程--AI开发--可置顶粘贴小工具

PROMPT 1.背景要求&#xff1a;我需要开发一个简单的粘贴小工具&#xff0c;用于方便地粘贴和管理文本内容。该工具需要具备以下功能&#xff1a;粘贴功能&#xff1a;提供一个文本框&#xff0c;用户可以粘贴内容。窗口置顶&#xff1a;支持窗口置顶功能&#xff0c;确保窗口…

利用Abel_Cain软件实现ARP欺骗

ARP协议是“Address Resolution Protocol”&#xff08;地址解析协议&#xff09;的缩写。在局域网中&#xff0c;网络中实际传输的是“帧”&#xff0c;帧里面是有目标主机的MAC地址的。在以太网中&#xff0c;一个主机要和另一个主机进行直接通信&#xff0c;必须要知道目标主…

STM32学习之 按键/光敏电阻 控制 LED/蜂鸣器

STM32学习之 按键/光敏电阻 控制 LED/蜂鸣器 1、按键控制 LED 按键:常见的输入设备&#xff0c;按下导通&#xff0c;松手断开 按键抖动:由子按键内部使用的是机械式弹簧片来进行通断的、所以在按下和松手的瞬间会伴随有一连串的抖动 按键控制LED接线图&#xff1a; 要有工程…

深入解析MySQL索引结构:从数组到B+树的演变与优化

前言&#xff1a; 在数据库查询中&#xff0c;索引是一种关键的性能优化工具。然而&#xff0c;索引的失效可能导致查询效率大幅下降。为了更好地理解索引的工作原理及规避其失效&#xff0c;深入了解索引结构的演变过程尤为重要。 MySQL 的索引数据结构从简单到复杂&#xff0…

window如何将powershell以管理员身份添加到右键菜单?(按住Shift键显示)

window如何将powershell以管理员身份添加到右键菜单&#xff1f; 在 Windows 中&#xff0c;将 PowerShell 以管理员身份添加到右键菜单&#xff0c;可以让你在需要提升权限的情况下快速打开 PowerShell 窗口。以下是详细的步骤&#xff0c;包括手动编辑注册表和使用注册表脚本…

Redis--持久化策略(AOF与RDB)

持久化策略&#xff08;AOF与RDB&#xff09; 持久化Redis如何实现数据不丢失&#xff1f;RDB 快照是如何实现的呢&#xff1f;执行时机RDB原理执行快照时&#xff0c;数据能被修改吗&#xff1f; AOF持久化是怎么实现的&#xff1f;AOF原理三种写回策略AOF重写机制 RDB和AOF合…

uniapp-vue3(下)

关联链接&#xff1a;uniapp-vue3&#xff08;上&#xff09; 文章目录 七、咸虾米壁纸项目实战7.1.咸虾米壁纸项目概述7.2.项目初始化公共目录和设计稿尺寸测量工具7.3.banner海报swiper轮播器7.4.使用swiper的纵向轮播做公告区域7.5.每日推荐滑动scroll-view布局7.6.组件具名…

计算机网络 (16)数字链路层的几个共同问题

一、封装成帧 封装成帧是数据链路层的一个基本问题。数据链路层把网络层交下来的数据构成帧发送到链路上&#xff0c;以及把接收到的帧中的数据取出并上交给网络层。封装成帧就是在一段数据的前后分别添加首部和尾部&#xff0c;构成了一个帧。接收端在收到物理层上交的比特流后…

操作系统论文导读(八):Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个

Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个关键性规范的零星任务的可调度性分析 目录 一、论文核心思想 二、基本定义 2.1 关键性指标 2.2 任务及相关参数定义 2.3 几个基础定义 三、可调度性分析 3.1 调度算法分…

「教程」抖音短剧小程序源码开发后上架的教程及好处

上线抖音短剧小程序的步骤 注册账号与准备资料&#xff1a;首先需要在抖音开放平台官网注册一个抖音小程序账号&#xff0c;并完成相关认证&#xff0c;获取小程序开发权限。同时&#xff0c;要准备好短剧相关的素材&#xff0c;如视频、音频、剧本、封面图片等 开发或选择小程…

omi friend实战记录

一、简介 omi friend是国外githab上开源的一个“AI硬件”的制作教程&#xff0c;它的形状是个三角形&#xff0c;属于项链佩戴这类的。可以接入llm进行对话&#xff0c;他有麦克风、扬声器&#xff0c;还有电池。外形好看&#xff0c;功能实用。还有专属的一系列app可以供方便…

活动预告 |【Part2】 Azure 在线技术公开课:迁移和保护 Windows Server 和 SQL Server 工作负载

课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft 云技术的了解。参加我们举办的“迁移和保护 Windows Server 和 SQL Server 工作负载”活动&#xff0c;了解 Azure 如何为将工作负载…

hive-sql 连续登录五天的用户

with tmp as (select 梁牧泽 as uid, 2023-03-03 as dt union allselect 梁牧泽 as uid, 2023-03-04 as dt union allselect 梁牧泽 as uid, 2023-03-05 as dt union allselect 梁牧泽 as uid, 2023-03-07 as dt union allselect 梁牧泽 as uid, 2023-03-08 as dt union allsel…