transformer原理-Attention Is All You Need

news2024/12/23 6:41:53

文章目录

    • 前言
    • 动机
      • NLP任务特点
      • 循环神经网络
        • 循环神经网络流行原因
        • 循环神经网络缺点
    • transformer架构
      • 整体架构(编码器-解码器)
      • 自注意力(self-attention)
        • 传统NLP解决方案
        • 改进思路
      • 多头注意力(Multi-Head Attention)
      • Encoder部分
      • Decoder部分
    • 数据输入
      • token的embedding编码
      • 绝对位置编码
        • 原理
        • 绝对位置编码优点
    • 模型训练
      • 训练数据集
      • 硬件
      • 训练参数
    • 总结
    • transformer的缺点

前言

还是惯例来感慨一下,transforemr是google公司在2017年7月发表的【Attention Is All You Need】这篇文章中被提出来的。而在大模型得到了蓬勃发展的今天,不管是哪一类大模型(视频、图像、文本),基本上模型的基础架构都是采用了transformer或者是transformer的变体。这一定程度上奠定了transformer的铁王座地位。
惊讶的是这个时代红利的最大受益者不是那些开发LLM的公司,而是英伟达,老黄都笑嘻了,为此老黄还特意在2024年的GTC大会上邀请了transformer的7位创作者。以表transformer给他带来这破天富贵。
好的,闲话就吹到这,下面开始进入正题。

动机

因为transformer最开始主要是为了解决NLP相关的问题,所以我们首先得了解一下NLP任务大概有啥特点。

NLP任务特点

在NLP领域有不同的任务:诸如情感分类、多项选择、机器翻译等,但是不管什么任务,他们都是和文本打交道,所以最重要的基础工作就是要充分学习到文本中每一个词的信息。而文本的特点就在于词语与词之间是有关联的。举一个例子吧:

你真的很狗阿

这里的“”其实是需要结合着最开始的“”来进行分析的。而不能独立分析。
ok了,总结一下NLP任务的特点在于:文本中词与词之间是有关联的

循环神经网络

循环神经网络流行原因

上一小节我们知道了NLP任务特点在于:文本中词与词之间是有很大关联的,这就意味着你如果要想解决好NLP任务,在学习每一个词的信息的时候,就要充分考虑其周边的其他词(上下文),因为他们之间会有似有若无的联系。而就是因为这一个特点,给传统的神经网络下了死刑,因为传统神经网络输入的特征与特征之间是没有联系,模型在输入的时候一般都是独立的去考虑问题。自然就不能充分捕获每一个词的信息了,自然对于上层的情感分类等任务自然效果就不会那么好了。而这也就是RNN系列(LSTM、GRU等)兴起的原因,因为RNN网络结构的特殊性,导致在学习某个词的信息的时候,就会充分考虑过去时刻出现的词的信息。这不就契合了NLP任务的特点了嘛。所以在Transformer没出现之前,RNN系列算是统治了NLP领域了。关于RNN的详细内容,我在之前还写过一片博客,感兴趣可以去看看:从RNN到LSTM

循环神经网络缺点

虽然RNN系列在学习词的信息的时候也充分考虑到了过去时刻的每一个词的信息,但是因为它计算原理的特点,导致它出现了一些难以处理的缺点:

  1. 处理长序列文本很困难,很难充分捕获长文本的信息,例如句尾的词很难充分考虑到句头出现词的信息;
  2. 无法并行计算,因为后一个时刻是依赖前一时刻的结果,自然就无法并行计算了;
  3. 训练时间长,且训练难以收敛,这是因为rnn在学习下一个时刻出现的词的信息的时候是需要考虑前一时刻出现的词的信息的,而前一个时刻出现的词又依赖前前时刻的信息了,这就成了一个递归了。而递归你可以简单的理解为它就类似一个深度的神经网络,而网络加深,自然训练时间就会变长,同时在反向梯度计算的时候,容易出现梯度弥散,自然难以收敛。

所以这就给了Transformer来革命的机会,Transformer也会一一的解决RNN系列的这些缺点。

transformer架构

整体架构(编码器-解码器)

上一节介绍了,截止Transformer之前,RNN系列基本上已经统治了NLP领域了,基本上NLP的任务都会基于循环神经网络或者它的变体去做,但是又不单纯的用循环神经网络,而是基于循环神经网络去架构一个encoder-decoder模型,尤其是在机器翻译领域。而过往的事实证明这个encoder-decoder架构在文本翻译、摘要总结等的任务上都实现了sota。所以Transformer也秉承了这一点,整体上采用encoder-decoder结构。只是这个encoder-decoder结构下的原子结构不是rnn,而是self-attention(自注意力)+前馈神经网络。下面是原论文的模型结构,左侧是编码器、右侧是解码器,后面我们会逐个来讲解这个架构内容。
在这里插入图片描述

自注意力(self-attention)

因为transformer是基于自注意力机制架构的,所以就要先了解自注意力。下面我们一步步引出这个结构。我们还是以句子:你真的很狗阿,这句话的学习为例。

传统NLP解决方案

在传统的神经网络中,大致的解决方案如下图所示:
在这里插入图片描述

首先对于上面的网络,可以看作两大部分:

  1. 阴影部分可以看作是对token的embedding学习和构建;
  2. 阴影部分之上的可以认为是具体的网络设计。

对整个网络的运行步骤进行总结一下:

  1. 将利用tokenrizer分词器将“你真的很狗阿”这句话切分为token级别,同时将切分后的每一个token映射到一个具体的id。
  2. 构建一个可学习的embedding矩阵,这个矩阵大小取决于我们总的词库切分出来的总的token数,并不只是这句话仅有的这几个词切出来的token数。总之每一个token对应一个可学习的embedding向量。
  3. 将“你真的很狗”这句话对应的embedding向量取出来,进行拼接,当然也可以是对应位置的加和,或者是其他操作,最常用的是横向拼接。
  4. 将concat拼接后的向量送入到MLP网络进行学习。

缺点

首先我们还是强调一下,每一个对应的embedding向量就是表示具体token的信息,那上面的这种传统解决方案来说,每一个embedding是独立的。这就和我们最开始强调的“NLP任务特点”不契合了。所以在图中的阴影部分(用于学习token的embedding)就是我们首先要考虑改进的地方。

改进思路

NLP任务特点的章节表明,每一个词都似有若无的和它前后的词(也称为上下文)是有联系的,那要完成好NLP任务,就不能像传统方法一样独立的考虑每一个词或者token的信息。而是要综合考虑上下文的信息,那如何考虑呢?最直觉的方法就是将上下文的信息叠加到当前token上,叠加方法中最简单的就是加和了。大致如下图所示:
在这里插入图片描述

绿色的地方就是我们改进的地方,但是这就有一个非常大的问题,那就是融合上下文之后的每一个token的新embedding信息都一样了,这显然是不对的,因为不具有区分性了,那又该如何改呢?

首先我们分析一下,这种简单加和的本质是因为我们将上下文的token对当前token的影响程度都看成是一样的,且影响权重都是1。我简单给一个公式:

n e w e m b 你 = w 0 ∗ e m b 你 + w 1 ∗ e m b 真 + w 2 ∗ e m b 的 + w 3 ∗ e m b 很 + w 4 ∗ e m b 狗 + w 5 ∗ e m b 阿 newemb_{你} =w_0*emb_你+w_1*emb_真+w_2*emb_的+w_3*emb_很+w_4*emb_狗+w_5*emb_阿 newemb=w0emb+w1emb+w2emb+w3emb+w4emb+w5emb
其他的词的的emb的计算类似。而简单加和的本质就是将所有的w参数都看作是1,这个w可以看作是上下文的每一个token对当前token的影响程度。但是,上下文的token对当前token的影响程度显然是不一样的
在这里插入图片描述
就拿这句话来说,如果要把握住“”这个词的具体含义,“”这个词对他的影响程度是大于其他词对他的影响程度的。所以原始公式中的权重 w w w 应该不能同等的看作是1,那具体是多少呢?按照以往神经网络的处理习惯上,这个 w w w 的权重我们可以让模型自己去学习。到这里或许我们可以回想一下word2vec的原理,之前我写过的一篇:word2vec的原理和难点介绍(skip-gram,负采样、层次softmax)的博客中讲到,模型训练完之后得到了词的embedding矩阵,而词与词的embeding向量的点积计算的结果可以间接性的表示词与词之间的相似度。那放到我们现在的问题中,我们同样可以将token与token对应的embedding的向量点积看作是token与token之间的影响程度,同时这里embedding是不断学习的,那自然点积结果就是不断变化学习的,这也就实现了我们的愿望:动态学习 w w w权重。我们可以稍微绘制一个图看一下:
在这里插入图片描述

这里的三个emb的输入都是一样的,source-emb(左)和source-emb(下)用于计算出权重 w w w,结合着我最初的给公式来看这个图,就很清晰了。其实到这里,看似是已经实现了我们的诉求了,但是你细看这个结构,你会发现并没有可训练的参数,当然你可能会说,输入的三个embding都是可以学习的参数,确实在这个场景下这三个emb是可学习,但是你想一下,如果你输入的特征本身就是数值型特征,那也就不会有emb了,这样整个网络就没有可学习的参数了,所以为了解决这个问题,分别在三个emb矩阵输入的地方都加入了linear层:
在这里插入图片描述
这样加入了三个linear层之后,就有可学习的参数了,这三个层我们分别叫它query(Q),key(K)和value(V)。其中涂色的地方就是self-attention的雏形。为了看懂这个图,下面举例子讲解一下:

计算“你”的新embedding时:

  1. 计算其他词对“你”的影响权重(向量点积)
你(key)真(key)的(key)很(key)狗(key)阿(key)
你(query)w00w01w02w03w04w05
真(query)
  1. 将计算得到的权重与对应的token的value向量进行相乘,然后加和得到新的embedding向量

e n d e m b 你 = w 00 ∗ e m b 你 + w 01 ∗ e m b 真 + w 02 ∗ e m b 的 + w 03 ∗ e m b 很 + w 04 ∗ e m b 狗 + w 05 ∗ e m b 阿 endemb_你 = w00*emb_你+w01*emb_真+w02*emb_的+w03*emb_很+w04*emb_狗+w05*emb_阿 endemb=w00emb+w01emb+w02emb+w03emb+w04emb+w05emb

计算“真”的新embedding时:

  1. 计算其他词对“真”的影响权重(向量点积)
你(key)真(key)的(key)很(key)狗(key)阿(key)
你(query)
真(query)w10w11w12w13w14w15
  1. 将计算得到的权重与value向量进行相乘,然后加和得到新的embedding向量

e n d e m b 真 = w 10 ∗ e m b 你 + w 11 ∗ e m b 真 + w 12 ∗ e m b 的 + w 13 ∗ e m b 很 + w 14 ∗ e m b 狗 + w 15 ∗ e m b 阿 endemb_真 = w10*emb_你+w11*emb_真+w12*emb_的+w13*emb_很+w14*emb_狗+w15*emb_阿 endemb=w10emb+w11emb+w12emb+w13emb+w14emb+w15emb

以上就是self-attenion的大致原理,但是还是和原文给出的self-attenion的结构是不一样的:
在这里插入图片描述
对比一下发现,多了Scale、Mask、和SoftMax,首先Mask忽略掉,后边讲解码器的时候我会讲。

那么这个Attention的公式呢就可以归结为下面的这个了:
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k} } )V Attention(Q,K,V)=softmax(dk QKT)V

SoftMax是很好理解的,做一个归一化的处理,问题就在于这个Scale,Scale的做法呢就是在QK点积后除以QKV(他们三个的维度是一样的)的维度的根号,为什么要除以这个维度,这就要说到注意力的种类,根据注意力的计算形式,会把注意力分为加性注意力和乘性注意力,而我们这里呢就属于乘性注意力,而因为当下的很多矩阵计算框架中,对乘积的计算速度优化更好,所以作者呢就选择了用乘性注意力,在使用过程中他们发现,如果qkv的维度较小的时候,这两种注意力的最终效果都是差不多的,但是当维度变大之后,乘性注意力效果就变差了。他们猜测是因为维度变大之后,乘积的结果也跟着变大,导致最后梯度计算的时候出现了问题,所以就除以一个维度的根号值,这就是Scale。最终的效果如下,大家可以和上面的原文中的图对比来看。
在这里插入图片描述

多头注意力(Multi-Head Attention)

上面已经讲明白了self-attention,而Multi-Head Attention就是横向的多个self-attention叠加,这么做的出发点是在于:希望模型从多个维度和层面去学习token的信息,比如说“你真的很狗阿”,这个“”字,我们希望从多个维度去把握,好比你可以理解为,有一个self-attention是纯从动物维度去学习这个token的信息的,而另一个self-attention则是从人类角度去学习的。这就是多头注意力的出发点。最后将每一个self-attention执行结果进行concat送入到一个linear层就ok了。
在这里插入图片描述
:结合着上图来看,以及按照我讲解的原理来说,有多少个头,就代表着有多少套(QKV),也就是表示应该有多少套Linear层,但是实际的实现中,这样做参数会非常大,难以训练,我们只会创建一套QKV层,然后均分出几份作为不同的注意力头的QKV。
在这里插入图片描述
要实现均分,也就产生了一个严格的要求:

  1. 也就是QKV的维度d_model要能够整除多头注意力的头数h

这一点要牢记,这是代码实现时候的细节点。在transformer这篇文字中,头数h=8

Encoder部分

还是老样子,我们先不看论文中的结构,我们看看最开始那个网络:
在这里插入图片描述
我们前面花了很大力气讲的self-attention和Multi-Head Attention其实就是在改造灰色阴影部分,这部分其实你可以认为只是在处理embedding问题,思考如何得到一个包含上下文的token的新的embedding而已,而蓝色的部分才是真正要送入的网络。这个网络就可以五花八门了,你可以是传统的MLP,也可以是CNN等,而transformer也就是用了一个传统的两层MLP而已:
在这里插入图片描述
ok,transformer的整体结构就这么出来了,下面放一下原文中的结构图:
在这里插入图片描述
可以看得出来,我们已经把核心的骨干结构都讲出来了,而考虑到网络的收敛速度和平稳性,整体结构上利用了残差连接,同时呢多头注意力的输出和前馈神经网络的输出都用了一个LaryNorm进行了归一化处理。这就是图中的Add&Norm。

那就结束了,总结一下encoder部分的操作步骤:

  1. 输入经过一个Multi-Head Attention得到新的融合了上下文的embedding,这个多头注意力整体利用残差网络结构连接。
  2. 新的embedding经过LayerNorm进行归一化处理
  3. 继续将LayerNorm结果送入到前馈神经网络(两层MLP),整体结构同样采用残差连接
  4. MLP的结果送入到LayerNorm进行归一化处理。

大概的一个encoder的原子结构就是这样子了。transformer就是复制了6个这样的结构,作为encoder。

:通过上面的分析,我觉得需要注意的点在于:

  1. 整体结构是先残差计算,然后LayerNorm,这个别搞反了。
  2. 整体分析下来,其实网络可调的超参并不多,在多头注意力部分,可调的就是QKV的维度,在前馈神经网络可调的就是隐藏层的维度(这里考虑的是不更改网络的任何结构,包括MLP的层数)。在transformer原始实现中,QKV的维度d_model被设置为了512,前馈神经网络的隐层维度d_ff被设置为了2048

Decoder部分

decoder的结构其实和encoder部分的结构是很类似的,只是在最底部多了一个Masked Multi-Head Attention。
在这里插入图片描述
提出这篇文章的时候,作者们主要是在关注机器翻译问题,所以我们也就拿翻译来举个例子:

源语言目标语言
你真的很狗阿You’re such a jerk

对于这个任务,我们会将源语言丢到编码器学习,然后翻译出目标语言,而目标语言的翻译就是一个词语接龙的过程,翻译出的token会重新输入到解码器中,用于后面的token的生成。这也就表明,我们在训练transformer的时候,解码器部分,我们不希望让token看到未来的信息。比如在预测such的时候,我只希望它看到you are两个词,在预测a的时候,只希望看到you are such这几个词。对于未来的token,我们不需要加入这部分上下文的信息。那该如何做呢?首先我们self-attentionl的qk来计算出注意力分数:

You(key)are(key)such(key)a(key)jerk(key)
You(query)w00w01w02w03w04
are(query)w10w11w12w13w14
such(query)w20w21w22w23w24
a(query)w30w31w32w33w34
jerk(query)w40w41w42w43w44

接下来要根据公式和注意力分数计算出新的embedding了,为了说明例子,我直接从are举例:

n e w e m b a r e = w 10 ∗ e m b y o u + w 11 ∗ e m b a r e + w 12 ∗ e m b s u c h + w 13 ∗ e m b a + w 14 ∗ e m b j e r k newemb_{are} = w10*emb_{you}+w11*emb_{are}+w12*emb_{such}+w13*emb_{a}+w14*emb_{jerk} newembare=w10embyou+w11embare+w12embsuch+w13emba+w14embjerk

在这个计算公式中,为了不融入未来token的信息(such、a、jerk)。我们的做法就是将对应的权重变为0,那如何变为0呢,这个就要了解softmax的公式了,因为这个qk计算得到的权重分数w最终是要经过softmax计算的。
S o f t m a x ( x ) = e x i ∑ i e x i Softmax(x) = \frac{e^{x_i}}{ {\textstyle \sum_{i}^{}}e^{x_i} } Softmax(x)=iexiexi

你可以认为 x i x_i xi是qk计算后再scale的分数,最后再经过softmax进行计算,为了让最终的softmax值为0,那输入的 x i x_i xi就应该为负无穷,因为e的负无穷次方约等于0。所以我们只需要在前面qk点积计算的时候将未来的token的分数变为负无穷就ok了。

You(key)are(key)such(key)a(key)jerk(key)
You(query)-inf-inf-inf-inf-inf
are(query)w10-inf-inf-inf-inf
such(query)w20w21-inf-inf-inf
a(query)w30w31w32-inf-inf
jerk(query)w40w41w42w43-inf

上面就是我们要实现的效果,而为了实现这个效果,通常我们会建立一个同等维度的矩阵,叫Mask矩阵

00000
10000
11000
11100
11110

到时候是根据qk计算生成一个分数矩阵,然后再建立一个同等维度的Mask矩阵,这个矩阵的上三角都是0,然后我们会根据Mask矩阵的0和1情况,在分数矩阵中将0对应的位置更改为负无穷,这就是Mask的由来。最后进行softmax的时候,这些位置的权重就会变为0了。ok关于decoder的核心就这么点了。

:大体结构差不多都讲完了,同样decoder需要注意1点:

  1. 第二个多头注意力的KV是来自encoder的输出的。Q是来自上一个Masked Multi-Head Attention的输出。
  2. 整体的decoder也是6层。

数据输入

搞定了整体的模型结构,接下来我们就讲解一下输入了,而输入部分就是token的embedding编码和token的位置编码之和。
在这里插入图片描述

token的embedding编码

在讲解self-attention的时候,我们就已经提到了embedding作为输入了,这里简单讲讲这个embedding吧。
我们在做NLP任务的时候,最原始的信息肯定就是文本,但是输入到模型计算的时候一定得是一组数字或者是一组向量,所以通常会利用tokenizer分词器把长文本切分为多个token,并把每个token映射到一个对应的id,然后每一个id再映射到一组向量上。而这组向量就作为这个token的表示,它是可学习的。这就是embedding。结合下图来理解理解吧:
在这里插入图片描述

绝对位置编码

原理

前面讲到了self-attention的特点就在于可以并行的加载token,这样会带来一个不好的地方在于它无法区分每一个token的位置了,就好比把所有的token都放到一个篮子里,根本没有顺序可言,但是文本的位置信息是很重要的,就好比你在做词性分析的时候,动词后面大概率名词。所以位置信息不能丢。在transformer论文中,利用了正余弦函数来表示位置编码,具体公式如下:
在这里插入图片描述
对变量进行必要的说明:

  1. pos:token在句子中的位置
  2. i:向量中的每一个值的位置
  3. d_model:向量维度

因为token的位置编码是要和token的embedding编码相加的,所以位置编码的整体维度要和token的embedding的维度一样,这就是d_model:
在这里插入图片描述

而这个向量中的i则表示具体的空格的数字了,偶数位(2i)的计算则就利用第一个公式,奇数位(2i+1)的计算则利用第二个公式。

ok,这样位置编码向量就被计算出来了,而这种计算方法我们也称之为绝对位置编码,最终的模型输入就是一整句话的token向量,而每一个token的向量表示都是token的embedding编码和对应位置编码的和。

绝对位置编码优点

最后我想强调一下就是,在绝对位置编码上主要是为了引入位置信息,也就是公式中的pos,按理来说用什么公式都可以,只要有关于pos的计算就可以,但是为什么整体要用sin和cos呢?

因为sin和cos是可以互相转换的,那么我就讲讲sin。首先我们来看一个关于sin四则运算的公式:

s i n ( p o s + k ) = s i n ( p o s ) c o s ( k ) + c o s ( p o s ) s i n ( k ) sin(pos+k) = sin(pos)cos(k)+cos(pos)sin(k) sin(pos+k)=sin(pos)cos(k)+cos(pos)sin(k)

这里的 p o s + k pos+k pos+k表示的是一个位置, p o s pos pos也是一个位置,那 k k k就是他们之间的相对位置距离。通过展开来看,我们是可以计算得到cos(k)和sin(k)的值,也就是说利用sin的这种方式,是可以学习到一些相对位置的信息的,而相对位置的学习一定程度上决定了模型的外推能力。这就是选择sin的原因。同时还有一个好处在于,这些位置编码是一次性计算出来的,根本不需要学习,这就给模型学习减少了很多的压力。

同时呢,transformer作者们也试过像token的embedding编码这样将位置也进行embedding编码,让他们变得可学习,但是他们发现最终效果和sin这种差不多。既然效果差不多,而embedding的形式要引入很多学习的压力,所以他们选择了第一种。但是OpenAI在GPT1和GPT2中,他们却用了这种可学习的embedding形式,这就是我想不明白的地方。

模型训练

训练数据集

在原论文中,选择了WMT2014的英德数据和英法数据,主要是做翻译任务。

硬件

原文用了8卡P100的GPU机器

训练参数

  1. 优化器采用Adam,其中参数β1 = 0.9,,β2 = 0.98 , ε = 10−9.
  2. 学习率动态变化,具体公式如下,step_num是训练步数,warmup_steps=4000:
    在这里插入图片描述

总结

最后我们对这篇文章进行一下总结

  1. transformer整体采用encoder-decoder结构
  2. encoder结构采用Multi-Head Attention+两层前馈神经网络结构,两个结构整体上采用残差连接形式。总共有6个这样的块组成encoder
  3. decoder结构采用Masked Multi-Head Attention+Multi-Head Attention++两层前馈神经网络结构,三个结构整体上采用残差连接形式。总共有6个这样的块组成decoder
  4. d_ff维度为2048,d_model=512,h=8
  5. 输入采用embedding编码+绝对位置编码
  6. 优化器采用Adam,其中参数β1 = 0.9,,β2 = 0.98 , ε = 10−9.
  7. 学习率动态可调

从整体的结构来看,self-attention的结构并不需要多深,就可以实现对上下文信息的深度融合,这也就表明它可以比RNN训练得快,同时它可以并行的加载数据,而RNN是不可以的,这样速度更快。等于说transformer就是解决了RNN系列的一些弊端,也就从此刻开始,transformer取代RNN系列,占据NLP的铁王座地位。

transformer的缺点

以上把所有的transformer知识都讲解了一下,但是凡事总会有优缺点,而transformer最大的缺点就在于它的位置编码,它采用绝对位置编码的形式来引入位置信息,以假设的形式猜测sin这种模式可以引入相对位置信息。但是整体的外推能力并不强,这就是早期的大模型为啥生成的最长文本都很短,后来的大佬们发力点就在位置编码上,诸如现在的RoPE,连transformer作者们也意识到这一点,所以他们在后一年(2018-07)也改进了位置编码,接下来我就会读一下这篇文章,尽情期待。

ok,整体分析就到这,也推荐大家阅读阅读原文:Attention Is All You Need

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Fundamentals of Power Electronics》——反激变换器

反激转换器基于升降压转换器,接下去介绍它的演变过程。下图中的a描述了基本升降压型转换器电路,用一个MOSFET和二极管实现开关。 在图b中,电感绕组由两根导线构成,匝数比为1:1。电感的基础作用未改变,并联绕组可以等效…

在 Windows 系统上安装 TeamViewer 13

在 Windows 系统上安装 TeamViewer 13 References 默认安装到所有用户 同意协议 安装目录 勾选内容 打开文件位置 打开 rClientID.exe Extras -> Options -> Advanced Show advanced options -> Display language 重新启动TeamViewer 语言可修改为中文简体 …

Web 渗透测试神器:HackBar 保姆级教程

一、介绍 HackBar 是一个用于浏览器的扩展插件,主要用于进行网络渗透测试和安全评估。它提供了一系列方便的工具和功能,可以帮助用户执行各种网络攻击和测试,包括 XSS、SQL 注入、CSRF、路径穿越等。以下是 HackBar 插件的一些主要特点和功能…

Transformer - Layer Normalization

Transformer - Layer Normalization flyfish y x − E [ x ] V a r [ x ] ϵ ∗ γ β y \frac{x - \mathrm{E}[x]}{ \sqrt{\mathrm{Var}[x] \epsilon}} * \gamma \beta yVar[x]ϵ ​x−E[x]​∗γβ 论文 Layer Normalization import numpy as np import torch import…

【Jenkins】持续集成与交付 (一):深入理解什么是持续集成?

🟣【Jenkins】持续集成与交付 (一):深入理解什么是持续集成? 1、软件开发生命周期与持续集成2、 持续集成的流程3、持续集成的好处4、Jenkins的应用实践5、结语💖The Begin💖点点关注,收藏不迷路💖 1、软件开发生命周期与持续集成 软件开发生命周期(SDLC)是指软…

Redis缓存介绍以及常见缓存问题:穿透、雪崩和击穿

概念 缓存就是数据交换的缓冲区(Cache),是存贮数据的临时地方,一般读写性能较高。 作用: 降低后端负载 提高读写效率,降低相应时间 成本: 数据一致性成本 代码维护成本 运维成本 缓存更…

使用pyqt编写的页面导航框架

使用pyqt编写的页面导航框架 效果 介绍代码 效果 介绍 使用pyqt多种控件编写的导航框架,左边是菜单栏,点击不同的菜单选项可以切换到不同的页面。 代码 import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QP…

微服务之分布式理论zookeeper概述

一、分布式技术相关的理论 CAP理论 CAP定理(CAP theorem),⼜被称作布鲁尔定理(Eric Brewer),1998年第⼀次提出. 最初提出是指分布式数据存储不可能同时提供以下三种保证中的两种以上: (1) ⼀致性(Consistency): 每次读取收到的信息都是最新的; (2) …

Leetcode—1329. 将矩阵按对角线排序【中等】(unordered_map、priority_queue)

2024每日刷题&#xff08;121&#xff09; Leetcode—1329. 将矩阵按对角线排序 实现代码 class Solution { public:vector<vector<int>> diagonalSort(vector<vector<int>>& mat) {const int m mat.size();const int n mat[0].size();unorder…

(51单片机)第十三章-STC系列51单片机功能介绍

13.1 单片机空闲与掉电模式的应用 1. 空闲模式 当单片机进入空闲模式时&#xff0c;除CPU处于休眠状态外&#xff0c;其余硬件全部处于活动状态&#xff0c;芯片中程序未涉及的数据存储器和特殊功能寄存器中的数据在空闲模式期间都将保持原值。假若定时器正在运行&#xff0c;…

【tcl脚本实践Demo 1】文本生成、匹配、修改、读写

引言 在芯片设计的流程中,各种EDA工具在设计、综合、布局布线、验证、时序分析等等环节都会产出大量的文件信息。这些信息是海量的,如果单纯靠程序员自己查看信息效率很低并且很容易纰漏。所以脚本语言可以很好的解决这个问题,可以利用脚本语言匹配到敏感的信息,完成对信息…

C++ 如何实现原子性

1.操作系统如何实现原子性 在单处理器,单核,运行多线程的情况下,我们不使用线程同步工具, 我们会出现,线程之间会互相抢夺,临界区的资源,造成数据不符合我们预期的结果, 后面再说解决办法,那么我们怎么帮助实现原子性 1 屏蔽中断,不让线程之间切换,让它完成再切换 2 底层硬…

算法设计与分析 3.2 牛顿法及改进、迭代法、矩阵谱半径、雅可比迭代、高斯迭代

思考题1 改进cosx&#xff1f;优化算法 关键点在于cos计算过于麻烦&#xff0c;而每次都要求sinx的值 故直接简化为cosx的导数 -sinx 即&#xff1a; 原&#xff1a;//double daoshu(double x) { // return 18 * x - cos(x); //} 改&#xff1a;double daoshu(double x) {retu…

基于ssm+vue开放式教学评价管理系统【ppt·代码·文档报告】

项目演示视频 项目名称&#xff1a;开放式教学评价管理系统 系统介绍&#xff1a;本系统是通过java的SSM框架来实现的&#xff0c;前端采用vue框架进行实现 管理员通过登录进入到系统操作界面&#xff0c;结合需求可以对个人信息进行在线修改维护&#xff0c;也可结合需求进行…

深入剖析Redis哨兵模式的原理和应用

【更多精彩内容,欢迎关注小米的微信公众号“软件求生”】 大家好,我是小米!今天我们来聊一聊Redis中一个非常重要的话题——哨兵模式。相信大家在使用Redis时一定遇到过一些分布式系统的问题,而哨兵模式正是解决这些问题的关键之一。让我们一起来深入了解一下哨兵模式的原…

Notion是什么,Notion软件下载,Notion官方网站在哪里?国内用户Notion怎么订阅升级会员?

Notion是什么 Notion&#xff0c;一款强大的多功能工具&#xff0c;可用于组织笔记、任务、项目、数据库和文档等。 Notion软件下载 这个到Notion官方网站下载就可以了。 怎么订阅Notion会员 注册好了Notion的账号&#xff0c;来到首页&#xff0c;点击设置&#xff0c;左边…

13.Blender 界面介绍(下) 雕刻、纹理绘制及属性

界面介绍 1. 布局 物体的移动旋转和缩放等操作 2. 建模 里面就是有一些建模常用的功能 里面的功能对于做MMD来说不是必备的操作 3. 雕刻 使用里面的工具可以对物体本身进行修改 4. UV编辑 如果想要编辑UV贴图 将编辑模式改为纹理绘制 再点击右边的工具 如果进行编…

WordPress缓存插件有哪些?好用的缓存插件分享

目前WordPress缓存插件有&#xff1a;WP Rocket、WP Super Cache、W3 Total Cache、Sucuri、NitroPack、SiteGround Optimizer、LiteSpeed Cache、WP-Optimize、Hummingbird、Cache Enabler、Comet Cache。 在当今的数字世界中&#xff0c;拥有一个高效的网站对于吸引和留住用…

刷机维修进阶教程-----红米note7 修复基带 更改参数 nv损坏故障 实例步骤操作解析

在前面的博文中我有说过。不管刷更改参数还是修复基带,尽可能的情况下备份一些主要分区,上期讲了小米6x 小米5 小米6这些机型更改参数的具体步骤。今天的教程以红米note7为例解析下改参数和修复nv损坏的具体步骤,两者操作实际没有什么冲突。有兴趣的友友建议多看下我关于…

10GMAC层设计系列-(1)10G Ethernet PCS/PMA

一、引言 对于10G以太网MAC层的实现&#xff0c;Xilinx提供了 3种IP核&#xff0c;分别是 10G Ethernet MAC、10G Ethernet PCS/PMA、10G Ethernet Subsystem。 10G Ethernet MAC只包含MAC层&#xff0c;外部需要提供一个PHY芯片进行数据对齐&#xff0c;10G Ethernet MAC与P…