Transformer模型详解03-Self-Attention(自注意力机制)

news2024/11/18 8:37:35

文章目录

  • 简介
  • 基础知识
  • 什么是Attention
  • Self Attention
    • 原理
      • 通俗易懂理解
      • 矩阵计算
        • Q,K,V计算
        • Self-Attention 的输出
    • 优势
  • Multi-head self-attention
    • 原理
      • 通俗易懂理解
      • 矩阵计算
      • 代码实现

简介

下图是论文中 Transformer 的内部结构图,左侧为 Encoder block,右侧为 Decoder block。红色圈中的部分为 Multi-Head Attention,是由多个 Self-Attention组成的,可以看到 Encoder block 包含一个 Multi-Head Attention,而 Decoder block 包含两个 Multi-Head Attention (其中有一个用到 Masked)。Multi-Head Attention 上方还包括一个 Add & Norm 层,Add 表示残差连接 (Residual Connection) 用于防止网络退化,Norm 表示 Layer Normalization,用于对每一层的激活值进行归一化。

因为 Self-Attention是 Transformer 的重点,所以我们重点关注 Multi-Head Attention 以及 Self-Attention,首先详细了解一下 Self-Attention 的内部逻辑。
在这里插入图片描述

基础知识

向量的内积是什么,如何计算,最重要的,其几何意义是什么?

内积的计算方法是将两个向量对应分量相乘,然后将结果相加。
内积的几何意义是非常重要的。在二维空间中,两个向量的内积等于两个向量的模(长度)之积乘以它们之间的夹角的余弦值。具体来说,如果
θ 是两个向量之间的夹角,则它们的内积为:
a ⋅ b = ∣ a ∣ ∣ b ∣ cos ⁡ ( θ ) \mathbf{a} \cdot \mathbf{b} = |\mathbf{a}| |\mathbf{b}| \cos(\theta) ab=a∣∣bcos(θ)
这个公式表明,内积可以用来衡量两个向量的相似程度。当两个向量的夹角为 0时(cos0=1),它们的内积取得最大值,表示它们的方向相同;当夹角为 90时(cos90=0),内积为 0,表示它们的方向垂直;当夹角为180(cos180=-1) 时,内积取得最小值,表示它们的方向相反。

一个矩阵 与其自身的转置相乘,得到的结果有什么意义?
矩阵的对称性指的是矩阵在某种变换下保持不变的性质。对称矩阵是一种特殊的矩阵,它满足以下性质:矩阵的转置等于它自身。
具体来说,对称矩阵 A 满足以下条件:
A = A ⊺ \mathbf{A} = \mathbf{A}^\intercal A=A
这意味着矩阵的主对角线上的元素保持不变,而其他元素关于主对角线对称。

例如,如果一个矩阵 A 的元素为:
A = ( a b c b d e c e f ) \mathbf{A} = \begin{pmatrix} a & b & c \\ b & d & e \\ c & e & f \end{pmatrix} A= abcbdecef
矩阵中的元素对称于主对角线。
对称矩阵在数学和工程领域中非常重要,因为它们具有许多有用的性质,比如特征值都是实数、可以通过正交变换对角化等。在应用中,对称矩阵广泛用于描述对称系统、表示物理现象等。

当一个矩阵与其自身的转置相乘时,得到的结果矩阵具有重要的性质,其中最显著的是结果矩阵是一个对称矩阵。这个性质在许多领域中都有重要的应用,比如在统计学中用于协方差矩阵的计算,以及在机器学习中用于特征提取和数据降维。

让我们用一个具体的矩阵示例来演示这个性质。考虑一个 3 × 2 3 \times 2 3×2的矩阵
的矩阵 A \mathbf{A} A
A = ( 1 2 3 4 5 6 ) \mathbf{A} = \begin{pmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{pmatrix} A= 135246
首先,我们计算 A 的转置 A ⊺ \mathbf{A}^\intercal A
A ⊺ = ( 1 3 5 2 4 6 ) \mathbf{A}^\intercal = \begin{pmatrix} 1 & 3 & 5 \\ 2 & 4 & 6 \end{pmatrix} A=(123456)
然后,我们将 𝐴 相乘 A ⊺ \mathbf{A}^\intercal A,得到结果矩阵 A A ⊺ \mathbf{A} \mathbf{A}^\intercal AA
A A ⊺ = ( 1 2 3 4 5 6 ) ( 1 3 5 2 4 6 ) = ( 5 11 17 11 25 39 17 39 61 ) \mathbf{A} \mathbf{A}^\intercal = \begin{pmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{pmatrix} \begin{pmatrix} 1 & 3 & 5 \\ 2 & 4 & 6 \end{pmatrix} = \begin{pmatrix} 5 & 11 & 17 \\ 11 & 25 & 39 \\ 17 & 39 & 61 \end{pmatrix} AA= 135246 (123456)= 51117112539173961

可以观察到,结果矩阵 A A ⊺ \mathbf{A} \mathbf{A}^\intercal AA是一个对称矩阵。

什么是Attention

所谓Attention,顾名思义:注意力,意思是处理一个问题的时候把"注意力"放到重要的地方上。Attention思想其实是从人类的习惯中提取出来的。人们在第一次看一张照片的时候,第一眼一定落到这张照片的某个位置上,可能是个显著的建筑物,或者是一个有特点的人等等,总之,人们通常并没有看清图片的全部内容,而是将注意力集中在了图片的焦点上。

2017年的某一天,Google 机器翻译团队发表了《Attention is All You Need》这篇论文,犹如一道惊雷,Attention横空出世了!(有一说一,这标题也太他喵嚣张了,不过人家有这个资本(o゚▽゚)o )

Attention 机制最早是在计算机视觉里应用的,随后在NLP领域也开始应用了,真正发扬光大是在NLP领域,由于2018年GPT模型的效果显著,Transformer和Attention这些核心才开始被大家重点关注。

下面举个例子上说明一下注意力和自注意力,可能不够严谨,但足以说明注意力和自注意力是什么了。
 首先我们不去考虑得到注意力分数的细节,而是把这个操作认为是一个封装好的函数。比如定义为attention_score(a,b),表示词a和b的注意力分数。现在有两个句子A=“you are beautiful”和B=“你很漂亮”,我们想让B句子中的词“你”更加关注A句子中的词“you”,该怎么做呢?答案是对于每一个A句子中的词,计算一下它与“you”的注意力分数。也就是把

attention_score(“you”,“你”)
attention_score(“are”,“你”)
attention_score(“beautiful”,“你”)

都计算一遍,在实现attention_score这个函数的时候,底层的运算会让相似度比较大的两个词分数更高,因此attention_score(“you”,“你”)的分数最高,也相当于告诉了计算机,在对B句子中“你”进行某些操作的时候,你应该更加关注A句子中的“you”,而不是“are”或者“beautiful”。
 以上这种方式就是注意力机制,两个不同的句子去进行注意力的计算。而当句子只有一个的时候,只能去计算自己与自己的注意力,这种方式就是自注意力机制。比如只看A句子,去计算

attention_score(“you”,“you”)
attention_score(“are”,“you”)
attention_score(“beautiful”,“you”)

这种方式可以把注意力放在句子内部各个单词之间的联系,非常适合寻找一个句子内部的语义关系。

再举个例子比如这句话“这只蝴蝶真漂亮,停在花朵上,我很喜欢它”,我们怎么知道这个“它”指的是“蝴蝶”还是“花朵”呢?答案是用自注意力机制计算出这个“它”和其他所有输入词的“分数”,这个“分数”一定程度上决定了其他单词与这个联系。可以理解成越相似的,分就越高(通过权重来控制)。通过计算,发现对于“它”这个字,“蝴蝶”比“花朵”打的分高。所以对于“它”来说,“蝴蝶”更重要,我们可以认为这个“它”指的就是蝴蝶。

Self Attention

原理

通俗易懂理解

在人类的理解中,对待问题是有明显的侧重。具体举个例子来说:“我喜欢踢足球,更喜欢打篮球。”,对于人类来说,显然知道这个人更喜欢打篮球。但对于深度学习来说,在不知道”更“这个字的含义前,是没办法知道这个结果的。所以在训练模型的时候,我们会加大“更”字的权重,让它在句子中的重要性获得更大的占比。比如:
C ( s e q ) = F ( 0.1 ∗ d ( 我 ) , 0.1 ∗ d ( 喜 ) , . . . , 0.8 ∗ d ( 更 ) , 0.2 ∗ d ( 喜 ) , . . . ) C(seq) = F(0.1*d(我),0.1*d(喜),...,0.8*d(更),0.2*d(喜),...) C(seq)=F(0.1d()0.1d()...0.8d()0.2d()...)
在知道了attention在机器学习中的含义之后(下文都称之为注意力机制)。人为设计的注意力机制,是非常主观的,而且没有一个准则来评定,这个权重设置为多少才好。所以,如何让模型自己对变量的权重进行自赋值成了一个问题,这个权重自赋值的过程也就是self-attention。

定义:假设有四个输入变量 a 1 a^1 a1 a 2 a^2 a2 a 3 a^3 a3 a 4 a^4 a4,希望它们经过一个self-attention layer之后变为 b 1 b^1 b1 b 2 b^2 b2 b 3 b^3 b3 b 4 b^4 b4
在这里插入图片描述
a 1 a^1 a1 b 1 b^1 b1做例子, b 1 b^1 b1这个结果是综合了 a 1 a^1 a1 a 2 a^2 a2 a 3 a^3 a3 a 4 a^4 a4而得出来的一个结果。既然得到一个b 是要综合所有的a才行,那么最直接的做法就是 a 1 a^1 a1 a 2 a^2 a2 a 3 a^3 a3 a 4 a^4 a4
都做一次运算,得到的结果就代表了这个变量的注意力系数。直接做乘法太暴力了,所以选择一个更柔和的方法:引入三个变量 W q W^q Wq, W k W^k Wk, W v W^v Wv这三个变量与 a 1 a^1 a1相乘得到 q 1 q^1 q1, k 1 k^1 k1, v 1 v^1 v1
同样的方法对 a 2 a^2 a2 a 3 a^3 a3 a 4 a^4 a4都做一次,至于这里的q , k , v具体代表什么,下面就慢慢展开讲解。
在这里插入图片描述
然后拿自己的q与别人的k相乘就可以得到一个系数 α \alpha α。这里 q 1 q^1 q1在和其他的k做内积时,可近似的看成是在做相似度计算(前面基础向量的内积)。比如:
α 1 , 1 = q 1 ⋅ k 1 α 1 , 2 = q 1 ⋅ k 2 α 1 , 3 = q 1 ⋅ k 3 α 1 , 4 = q 1 ⋅ k 4 \alpha_{1,1} =q^1\cdot k^1\\ \alpha_{1,2} =q^1\cdot k^2\\ \alpha_{1,3} =q^1\cdot k^3\\ \alpha_{1,4} =q^1\cdot k^4\\ α1,1=q1k1α1,2=q1k2α1,3=q1k3α1,4=q1k4

在实际的神经网络计算过程中,还得除于一个缩放系数 d \sqrt{d} d 这个d是指q和k的维度,因为q和k会做内积,所以维度是一样的。之所以要除 d \sqrt{d} d ​,是因为做完内积之后,, α \alpha α会随着它们的维度增大而增大,除 d \sqrt{d} d 相当于标准化。
在这里插入图片描述
得到了四个 α \alpha α之后,我们分别对其进行softmax,得到四个 α ^ 1 \hat{\alpha}_1 α^1,增加模型的非线性。
在这里插入图片描述
四个 α \alpha α分别是 α ^ 1 \hat{\alpha}_1 α^1, α ^ 2 \hat{\alpha}_2 α^2, α ^ 3 \hat{\alpha}_3 α^3, α ^ 4 \hat{\alpha}_4 α^4,别忘了还有我们一开始计算出来的 v 1 {v}^1 v1, v 2 {v}^2 v2, v 3 {v}^3 v3, v 4 {v}^4 v4,直接把各个 α ^ 1 \hat{\alpha}_1 α^1直接与各个a 相乘不就得出了最后的结果了吗?虽然这么说也没错,但为了增加网络深度,将a变成v也可以减少原始的a对最终注意力计算的影响。
那么距离最后计算出 b 1 b^1 b1只剩最后一步,我们将所有的 α ^ 1 \hat{\alpha}_1 α^1
与所有的v分别相乘,然后求和,就得出 b 1 b^1 b1啦!具体计算如下:
b 1 = α ^ 1 , 1 ∗ v 1 + α ^ 1 , 2 ∗ v 2 + α ^ 1 , 3 ∗ v 3 + α ^ 1 , 4 ∗ v 4 b^1=\hat{\alpha}_{1,1}*v^1+\hat{\alpha}_{1,2}*v^2+\hat{\alpha}_{1,3}*v^3+\hat{\alpha}_{1,4}*v^4 b1=α^1,1v1+α^1,2v2+α^1,3v3+α^1,4v4
公式简化为:
b 1 = ∑ i α ^ 1 , i ∗ v i b^1=\sum_i\hat{\alpha}_{1,i}*v^i b1=iα^1,ivi
在这里插入图片描述
同样的计算过程,我们对剩下的a都进行一次,就可以得到 b 2 b^2 b2, b 3 b^3 b3, b 4 b^4 b4,每个b都是综合了每个a之间的相关性计算出来的,这个相关性就是我们所说的注意力机制,。那么我们将这样的计算层称为self-attention layer。
在这里插入图片描述
我们把一个句子中的每个字代入上图的 x 1 x^1 x1 x 2 x^2 x2 , x 3 x^3 x3 x 4 x^4 x4

矩阵计算

在这里插入图片描述
上图是 Self-Attention 的结构,在计算的时候需要用到矩阵Q(查询),K(键值),V(值)。在实际中,Self-Attention 接收的是输入(单词的表示向量x组成的矩阵X) 或者上一个 Encoder block 的输出。而Q,K,V正是通过 Self-Attention 的输入进行线性变换得到的。

Q,K,V计算

输入矩阵X=position encoding+word embedding,其中维度d_model,行为句子中单词的个数。
需要知道x的格式参考:Word2Vec实例

Self-Attention 的输入用矩阵X进行表示,则可以使用线性变阵矩阵WQ,WK,WV计算得到Q,K,V。计算
如下图所示,注意 X, Q, K, V 的每一行都表示一个单词,WQ,WK,WV是一个d_model(输入矩阵的列)行的线性变阵参数,X的每一行都会都会有自己的QKV,比如 X 1 X_1 X1对应 Q 1 , K 1 , V 1 Q_1,K_1,V_1 Q1,K1,V1,即 X n X_n Xn对应 Q n , K n , V n Q_n,K_n,V_n Qn,Kn,Vn,所以 X, Q, K, V 的每一行都表示一个单词。
在这里插入图片描述

Self-Attention 的输出

得到矩阵 Q, K, V之后就可以计算出 Self-Attention 的输出了,计算的公式如下:
在这里插入图片描述
公式中计算矩阵Q和K每一行向量的内积,为了防止内积过大,因此除以 d k d_k dk的平方根,缩放注意力,以使得注意力分布的方差在不同维度上保持一致,从而更好地控制梯度的稳定性。。Q乘以K的转置后,得到的矩阵行列数都为 n,n 为句子单词数,这个矩阵可以表示单词之间的 attention 强度。下图为Q乘以 K T K^T KT, 1234 表示的是句子中的单词。
在这里插入图片描述
得到 Q K T QK^T QKT之后,使用 Softmax 计算每一个单词对于其他单词的 attention 系数,公式中的 Softmax 是对矩阵的每一行进行 Softmax,即每一行的和都变为 1.
在这里插入图片描述
得到 Softmax 矩阵之后可以和V相乘,得到最终的输出Z。
在这里插入图片描述
上图中 Softmax 矩阵的第 1 行表示单词 1 与其他所有单词的 attention 系数,最终单词 1 的输出 Z 1 Z_1 Z1等于所有单词 i 的值 V i V_i Vi根据 attention 系数的比例加在一起得到,如下图所示:
在这里插入图片描述

优势

在这里插入图片描述
从self-attention的原理中可以看出,这一层需要学习的参数只有 W q W^q Wq , W k W^k Wk, W v W^v Wv,大部分变量来自于内部计算得出来的,所以它的参数量少但每个参数所涵盖的信息多,这是它的第一个优点。
每个b的计算都是独立的,这一点相比之前的RNN来说很不一样,RNN是需要等前面的 a 1 a^1 a1算完了才能算 a 2 a^2 a2,是串行的。所以RNN无论是训练还是推理,都会因为不能计算并行而变慢,这是它的的第二个优点。
RNN的一个最大的问题是:前面的变量在经过多次RNN计算后,已经失去了原有的特征。越到后面,最前面的变量占比就越小,这是一个很反人类的设计。而self-attention在每次计算中都能保证每个输入变量 a的初始占比是一样的,这样才能保证经过self-attention layer计算后他的注意力系数是可信的。
所以总结下来,它的三个优点分别是:

  • 需要学习的参数量少
  • 可以并行计算
  • 能够保证每个变量初始占比是一样的

Multi-head self-attention

原理

通俗易懂理解

multi-head self-attention,所谓head也就是指一个a 衍生出几个q , k , v 。上述所讲解的self-attention是基于single-head的。以2 head为例:
首先, a i a^i ai先生成 q 1 q^1 q1, k 1 k^1 k1, v 1 v^1 v1,然后,接下来就和single-head不一样了, q i q^i qi生成 q i , 1 , q i , 2 q^{i,1},q^{i,2} qi,1,qi,2生成的方式有两种:

  1. q i q^i qi乘上一个 W q , 1 W^{q,1} Wq,1得到 q i , 2 q^{i,2} qi,2,这个和single-head的生成是差不多的;
  2. q i q^i qi直接从通道维,平均拆分成两个,得到 q i , 1 , q i , 2 q^{i,1},q^{i,2} qi,1,qi,2

这两种方式,在最后结果上都差不多。至于为啥,后面会讲一下原因。
那么这里的图解使用第1个方式,先得到 q i , 1 q^{i,1} qi,1, k i , 1 k^{i,1} ki,1, v i , 1 v^{i,1} vi,1。对 a j a^j aj做同样的操作得到
,对 a j a^j aj做同样的操作得到 q j , 1 q^{j,1} qj,1, k j , 1 k^{j,1} kj,1, v j , 1 v^{j,1} vj,1。这边需要注意的一点, q i , 1 q^{i,1} qi,1是要和 k j , 1 k^{j,1} kj,1做矩阵乘法,而非 k j , 2 k^{j,2} kj,2,一一对应。后面计算就和single-head一样了,最后得到 b i , 1 b^{i,1} bi,1
在这里插入图片描述
第二步,对 q i , 2 q^{i,2} qi,2, k i , 2 k^{i,2} ki,2, v i , 2 v^{i,2} vi,2做一样的操作,得到 b i , 2 b^{i,2} bi,2
在这里插入图片描述
这里我们算出的 b i , 1 b^{i,1} bi,1, b i , 2 b^{i,2} bi,2是同维度的,我们可以将其concat在一起,再通过一个 W 0 W^0 W0把他转成想要的维度。这也就不难理解,为什么说multi-head的两种生成方式是一样的,因为最终决定是输出维度的是 W o W^o Wo。我们可以将multi-head的过程看成是cnn中的隐藏层,multi-head的数量也就对应着Conv2D的filter数量,每一个head各司其职,提取不同的特征。
在这里插入图片描述

矩阵计算

我们已经知道怎么通过 Self-Attention 计算得到输出矩阵 Z,而 Multi-Head Attention 是由多个 Self-Attention 组合形成的,下图是论文中 Multi-Head Attention 的结构图。
在这里插入图片描述
从上图可以看到 Multi-Head Attention 包含多个 Self-Attention 层,首先将输入X分别传递到 h 个不同的 Self-Attention 中,计算得到 h 个输出矩阵Z。下图是 h=8 时候的情况,此时会得到 8 个输出矩阵Z。
在这里插入图片描述
得到 8 个输出矩阵 Z 1 Z_1 Z1 Z 8 Z_8 Z8之后,Multi-Head Attention 将它们拼接在一起 (Concat),然后传入一个Linear层,得到 Multi-Head Attention 最终的输出Z。
在这里插入图片描述
可以看到 Multi-Head Attention 输出的矩阵Z与其输入的矩阵X的维度是一样的。

代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F

class SelfAttention(nn.Module):
    def __init__(self, embed_size, num_heads):
        """
        初始化 SelfAttention 层
        
        参数:
            embed_size (int): 输入特征的维度
            num_heads (int): 注意力头的数量
        """
        super(SelfAttention, self).__init__()
        self.embed_size = embed_size
        self.num_heads = num_heads
        self.head_dim = embed_size // num_heads
        
        # 确保 embed_size 能被 num_heads 整除
        assert (
            self.head_dim * num_heads == embed_size
        ), "Embedding size needs to be divisible by heads"
        
        # 初始化线性层
        self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.fc_out = nn.Linear(num_heads * self.head_dim, embed_size)

    def forward(self, values, keys, query):
        """
        前向传播函数
        
        参数:
            values (Tensor): 值的张量,形状为 (batch_size, value_len, embed_size)
            keys (Tensor): 键的张量,形状为 (batch_size, key_len, embed_size)
            query (Tensor): 查询的张量,形状为 (batch_size, query_len, embed_size)
        
        返回:
            out (Tensor): 输出张量,形状为 (batch_size, query_len, embed_size)
        """
        # 获取张量的大小
        N = query.shape[0]
        value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]
        
        # 将输入张量按头数和头维度进行切分
        values = values.reshape(N, value_len, self.num_heads, self.head_dim)
        keys = keys.reshape(N, key_len, self.num_heads, self.head_dim)
        queries = query.reshape(N, query_len, self.num_heads, self.head_dim)
        
        # 通过线性层进行变换
        values = self.values(values)
        keys = self.keys(keys)
        queries = self.queries(queries)
        
        # 计算点积注意力
        energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys]) # batch_size, num_heads, query_len, key_len
        
        # 计算注意力权重
        attention = torch.nn.functional.softmax(energy / (self.embed_size ** (1/2)), dim=3)
        
        # 将注意力权重应用到值上
        out = torch.einsum("nhql,nlhd->nqhd", [attention, values]).reshape(
            N, query_len, self.num_heads * self.head_dim
        )
        
        # 合并多个头并通过线性层进行变换
        out = self.fc_out(out)
        return out

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

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

相关文章

十、Redis内存回收策略和机制

1、Redis的内存回收 在Redis中可以设置key的过期时间,以期可以让Redis回收内存,循环使用。在Redis中有4个命令可以设置Key的过期时间。分别为 expire、pexpire、expireat、pexpireat。 1.1、expire expire key ttl:将key的过期时间设置为tt…

SpringBoot自定义初始化sql文件 支持多类型数据库

我在resources目录下有init.sql初始化sql语句 指定sql文件的地址 sql内容如下: /*角色表*/ INSERT INTO #{schema}ccc_base_role (id, create_time, create_user_id, is_delete, role_name, status, update_time, update_user_id) VALUES(b89e30d81acb88448d412…

谷粒商城实战(023 业务-订单模块-页面和幂等性等校验)

Java项目《谷粒商城》架构师级Java项目实战,对标阿里P6-P7,全网最强 总时长 104:45:00 共408P 此文章包含第270p-第p283的内容 简介 远程调用的服务已经注册到了注册中心 校验 幂等性校验 拿令牌 读令牌 删令牌 要实现 原子性 在一个事务中 添加令牌…

小红书·电商运营课:小红书开店流程,小红书电商如何运营(18节视频课)

课程目录 第1节课:学习流程以及后续实操流程注意事项 第2节课:小红书店铺类型解析以及开店细节 第3节课:小红书电商运营两种玩法之多品店铺解析 第4节课:小红书电商运营两种玩法之单品店铺解析 第5节课:选品课(多品类类目推荐) 第6节课:选品课(多品类类目推荐) 第7节课:…

以C++为核心语言的高频交易系统是如何做到低延迟的?

在开始前我有一些资料,是我根据网友给的问题精心整理了一份「 c的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!! 问题中限定语言是C,可…

自动驾驶中的神经辐射场:综述

24年4月清华大学论文“Neural Radiance Field in Autonomous Driving: A Survey”。 神经辐射场(NeRF)由于其固有的优势,特别是其隐式表示和新视图合成能力,引起了学术界和工业界的广泛关注。 随着深度学习的快速发展&#xff0c…

最少数量线段覆盖-华为OD

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、java代码五、测试用例 前言 本人最近再练习算法,所以会发布一些解题思路,希望大家多指教 一、题目描述 给定坐标轴上的一组线段,线段的起点和终点均为整数…

ICode国际青少年编程竞赛- Python-4级训练场-列表综合练习

ICode国际青少年编程竞赛- Python-4级训练场-列表综合练习 1、 Flyer[3].step(1) Flyer[7].step(2) Flyer[11].step(1) for i in range(4):Flyer[i * 2].step(1) Flyer[8].step(3)for i in range(3):Dev.turnRight()Dev.step(-5)2、 for i in range(5):Flyer[i5].step(Flyer[…

如何通过AI技术实现员工培训的革命性变革

AI个性化培训:开启员工潜力的新篇章 在当今这个信息爆炸的时代,人工智能(AI)技术的影响力已经渗透到社会的各个层面,包括教育与培训行业。AI技术正在彻底改变我们获取知识与技能的方式,特别是在员工培训领域…

upload组件封装,支持拖拽文件上传

一、组件封装需要注意什么? 组件化思想:组件应该是独立的、可复用的部件,应该遵循单一职责原则,将组件的功能划分得尽可能细致。 API 设计:组件的 API 设计要合理,要考虑到组件的可定制性和易用性。应该尽可能的提供必要的配置项和事件回调,同时避免提供过多的 API,导…

Python Supervisor助力代码后台运行

大家好,Supervisor 是一个 C/S 架构的进程监控与管理工具,本文将主要介绍其基本用法和部分高级特性,用于解决部署持久化进程的稳定性问题。 1.问题场景 在实际的工作中,往往会有部署持久化进程的需求,比如接口服务进…

BOOT程序与APP程序的RAM共享问题与栈顶地址判断合法

一、我们在进行BOOT程序和APP程序,会想到这里面的RAM他们之间是怎么分配的,会不会有冲突? 答案是:从BOOT程序跳转到APP程序后,相当于执行了新的程序,所以BOOT里边的内存是全部释放了。所以是相互不影响的 …

硬件 - TL431计算

文章目录 1 . 概要2 . TL431内部3 . TL431应用电路4 . TL431计算5 . 小结 【全文大纲】 : https://blog.csdn.net/Engineer_LU/article/details/135149485 1 . 概要 1 . TL431常用于通过外围电阻R1,R2设置输出一个目标电压 2 . TL431内部 3 . TL431应用电路 1 . R1 1K&#xf…

web前端之sass中的颜色函数、active按钮激活、hover鼠标悬浮、disabled禁用、scss循环、css

MENU 效果图htmlsassscss编译后的css页面css 效果图 注意查看蓝色按钮。 html <div class"box"><button class"btn type_1">按钮</button><button class"btn type_2">按钮</button><button class"btn ty…

修改表空间对应数据文件的大小

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 表空间与数据文件紧密相连&#xff0c;相互依存&#xff0c;创建表空间的时候需设置数据文件大小。 在后期实际应用中&#xff0c;如果实际存储的数据量超出事先设置的数据…

Threejs Shader动态修改Merge合并几何体中单个Mesh的颜色

目录 Merge合并 现象 思路 实现 为单个geometry添加映射 通过id检索Merge后的Geometry映射属性&#xff0c;获取顶点坐标 onBeforeCompile修改编译前材质的着色代码 编译前材质的顶点着色代码 编译前材质的片元着色代码 着色器代码 注意 效果 Merge合并 mergeBuf…

Postgresql中JIT函数能否inline的依据function_inlinable

相关 《Postgresql源码&#xff08;128&#xff09;深入分析JIT中的函数内联llvm_inline》 《LLVM的ThinLTO编译优化技术在Postgresql中的应用》 前置阅读&#xff1a;《Postgresql源码&#xff08;128&#xff09;深入分析JIT中的函数内联llvm_inline》 在JIT inline函数的过…

2024高安全个人密码本程序源码,贴身密码管家-随机密码备忘录二代密码

项目概述&#xff1a; 在这个网络高度发展的时代&#xff0c;每个人都需要上网&#xff0c;而上网就不可避免地需要使用账号和密码。 在众多账号的情况下&#xff0c;你是否还在为复杂难记的密码感到烦恼&#xff1f;现在只需要记录一次&#xff0c; 就可以随时查看你的密码…

用websocket实现一个简单的im聊天功能

WebSocket前后端建立以及使用-CSDN博客 经过我上一篇的基本理解websocket的建立以及使用后&#xff0c;这篇就写一个简单的demo 实现im聊天 首先就是后端代码&#xff0c;详细解释我都放到了每一句的代码解析了&#xff0c;文章最后我会说怎么运行流程 放置后端代码 packa…

半小时搞懂STM32面经知识点——系统架构与启动流程

1.Cortex-M系统 1.1系统结构 1.处理器核心&#xff1a; Cortex-M3 2.存储器系统&#xff1a; Flash&#xff0c;SRAM&#xff0c;FSMC等 3.总线接口&#xff1a; 核心通过总线接口与外设设备和存储器进行通信。 总线矩阵&#xff1a;总线矩阵是一种硬件结构&#xff0c;用于连…