深度学习笔记之Transformer(三)自注意力机制

news2024/11/24 1:10:48

深度学习笔记之Transformer——自注意力机制

引言

上一节对注意力分数 ( Attention Score ) (\text{Attention Score}) (Attention Score)这个概念进行了总结。本节将基于缩放点积注意力机制 ( Scaled Dot-Product Attention ) (\text{Scaled Dot-Product Attention}) (Scaled Dot-Product Attention)这种注意力分数的计算模式,介绍自注意力机制

回顾:缩放点积注意力机制

缩放点积注意力机制的核心思路在于:使用内积描述刻意信息无意信息之间的关联关系(相似性关系)
关于‘刻意信息’、‘无意信息’的概念详见注意力机制基本介绍

  • 已知包含 N N N个向量的查询矩阵 Q \mathcal Q Q(刻意信息)与无意信息 M \mathcal M M键值对 { ( K j , V j ) } j = 1 M \{(\mathcal K_j,\mathcal V_j)\}_{j=1}^{\mathcal M} {(Kj,Vj)}j=1M,并且各向量维数表示为:
    其中 K , V \mathcal K,\mathcal V K,V分别表示 Keys,Values \text{Keys,Values} Keys,Values组成的矩阵,它们的元素数量 ( M ) (\mathcal M) (M)相同;而 Q \mathcal Q Q中各元素的维数 ( d ) (d) (d)需要与 K \mathcal K K个元素维数大小相同,否则无法执行内积。
    { Q ∈ R N × d K j ∈ R 1 × d j = 1 , 2 , ⋯   , M ⇒ K ∈ R M × d V j ∈ R 1 × v j = 1 , 2 , ⋯   , M ⇒ V ∈ R M × v \begin{cases} \mathcal Q \in \mathbb R^{N \times d} \\ \mathcal K_j \in \mathbb R^{1 \times d} \quad j=1,2,\cdots,\mathcal M \Rightarrow \mathcal K \in \mathbb R^{\mathcal M \times d} \\ \mathcal V_j \in \mathbb R^{1 \times v} \quad j =1,2,\cdots,\mathcal M \Rightarrow \mathcal V \in \mathbb R^{\mathcal M \times v} \end{cases} QRN×dKjR1×dj=1,2,,MKRM×dVjR1×vj=1,2,,MVRM×v

  • 基于缩放点积注意力机制的注意力分数 a ( Q , K ) a(\mathcal Q,\mathcal K) a(Q,K)表示如下:
    a ( Q , K ) = [ Q K T d ] N × M a(\mathcal Q,\mathcal K) = \left[\frac{\mathcal Q\mathcal K^T}{\sqrt{d}}\right]_{N \times \mathcal M} a(Q,K)=[d QKT]N×M
    其中 a ( Q , K ) a(\mathcal Q,\mathcal K) a(Q,K)返回的 N × M N \times \mathcal M N×M矩阵中的每一个元素均描述:查询向量 Q i ( i = 1 , 2 , ⋯   , N ) ∈ R 1 × d \mathcal Q_i(i=1,2,\cdots,N) \in \mathbb R^{1 \times d} Qi(i=1,2,,N)R1×d与某个 K j ( j = 1 , 2 , ⋯   , M ) ∈ R 1 × d \mathcal K_j(j=1,2,\cdots,\mathcal M) \in \mathbb R^{1 \times d} Kj(j=1,2,,M)R1×d之间的内积结果;而 d \sqrt{d} d 的作用是约束内积结果的解空间,使注意力分数结果对参数的敏感度降低

  • 对注意力分数做归一化 ( Softmax ) (\text{Softmax}) (Softmax)处理,再与对应 V j ( j = 1 , 2 , ⋯   , M ) \mathcal V_j(j=1,2,\cdots,\mathcal M) Vj(j=1,2,,M)内积运算:
    f [ Q , ( K 1 , V 1 ) , ( K 2 , V 2 ) ⋯   , ( K M , V M ) ] = Softmax [ a ( Q , K ) ] ⋅ V M × v \begin{aligned} f [\mathcal Q,(\mathcal K_1,\mathcal V_1),(\mathcal K_2,\mathcal V_2)\cdots,(\mathcal K_{\mathcal M},\mathcal V_{\mathcal M})] & = \text{Softmax}[a(\mathcal Q,\mathcal K)] \cdot \mathcal V_{\mathcal M \times v} \end{aligned} f[Q,(K1,V1),(K2,V2),(KM,VM)]=Softmax[a(Q,K)]VM×v

自注意力机制

归纳一下之前出现的注意力机制

  • 关于 Seq2seq \text{Seq2seq} Seq2seq,它的注意力机制中查询向量 Query \text{Query} Query Keys \text{Keys} Keys分别来自于独立的循环神经网络 ( Decoder,Encoder ) (\text{Decoder,Encoder}) (Decoder,Encoder);并且 Keys,Values \text{Keys,Values} Keys,Values均来自于同一个事物
    Keys,Values ⇒ H B i = { [ h L ; j , h R ; T + 1 − j ] } j = 1 T \text{Keys,Values} \Rightarrow \mathcal H_{Bi} = \left\{[h_{\mathcal L;j},h_{\mathcal R;\mathcal T+1-j}]\right\}_{j=1}^{\mathcal T} Keys,ValuesHBi={[hL;j,hR;T+1j]}j=1T
  • 关于 Nadaraya-Watson \text{Nadaraya-Watson} Nadaraya-Watson核回归,它的注意力机制中查询向量指的是训练集 D \mathcal D D之外的陌生样本 x x x;而 Keys,Values \text{Keys,Values} Keys,Values分别描述训练集 D \mathcal D D中的特征与标签信息 x ( i ) , y ( i ) ( i = 1 , 2 , ⋯   , N ) x^{(i)},y^{(i)}(i=1,2,\cdots,N) x(i),y(i)(i=1,2,,N)。很明显, Keys,Values \text{Keys,Values} Keys,Values之间同样存在显式的关联关系。

关于 Keys,Values \text{Keys,Values} Keys,Values在各模型的注意力机制中关联性都很强;但作为执行相关性(相似性)计算的双方: Query,Keys \text{Query,Keys} Query,Keys,上述两种注意力机制似乎都有意地区分它们。

自注意力机制 ( Self-Attention ) (\text{Self-Attention}) (Self-Attention)核心在于:特征既作为 Query \text{Query} Query,也作为 Keys \text{Keys} Keys,也作为 Values \text{Values} Values进行运算,三者在内容上没有区别。通过这种方式对序列抽取特征。

给定一个长度为 T \mathcal T T序列 X = ( x 1 , x 2 , ⋯   , x T ) T \mathcal X = (x_1,x_2,\cdots,x_{\mathcal T})^T X=(x1,x2,,xT)T,并且序列中的每个元素 x t ( t = 1 , 2 , ⋯   , T ) x_t(t=1,2,\cdots,\mathcal T) xt(t=1,2,,T)均有 d d d维向量进行特征表示
{ x t ∈ R 1 × d t = 1 , 2 , ⋯   , T X ∈ R T × d \begin{cases} x_t \in \mathbb R^{1 \times d} \quad t=1,2,\cdots,\mathcal T \\ \mathcal X \in \mathbb R^{\mathcal T \times d} \end{cases} {xtR1×dt=1,2,,TXRT×d

关于 x t x_t xt注意力信息 y t y_t yt表示如下:
其中元素 x t x_t xt需要与序列中的所有元素 x 1 , x 2 , ⋯   , x T x_1,x_2,\cdots,x_{\mathcal T} x1,x2,,xT计算注意力分数。
y t ∈ R 1 × d = f [ Q = x t , ( K 1 = x 1 , V 1 = x 1 ) , ⋯   , ( K T = x T , V T = x T ) ] = Softmax { [ x t X T d ] 1 × T } ⋅ [ X ] T × d \begin{aligned} y_t \in \mathbb R^{1 \times d} & = f[\mathcal Q = x_t,(\mathcal K_1 = x_1,\mathcal V_1 = x_1),\cdots,(\mathcal K_{\mathcal T} = x_{\mathcal T},\mathcal V_{\mathcal T} = x_{\mathcal T})] \\ & = \text{Softmax} \left\{\left[\frac{x_t \mathcal X^T}{\sqrt{d}}\right]_{1 \times \mathcal T}\right\} \cdot [\mathcal X]_{\mathcal T \times d} \end{aligned} ytR1×d=f[Q=xt,(K1=x1,V1=x1),,(KT=xT,VT=xT)]=Softmax{[d xtXT]1×T}[X]T×d
同理,将完整序列 X ∈ R T × d \mathcal X \in \mathbb R^{\mathcal T \times d} XRT×d作为输入,它的注意力信息 Y \mathcal Y Y表示如下:
注意:这里的 Softmax \text{Softmax} Softmax对各行的 T \mathcal T T个元素做归一化,而不是对 [ X X T d ] T × T \begin{aligned}\left[\frac{\mathcal X \mathcal X^T}{\sqrt{d}}\right]_{\mathcal T \times \mathcal T}\end{aligned} [d XXT]T×T整体做归一化。
Y ∈ R T × d = Softmax { [ X X T d ] T × T } ⋅ [ X ] T × d \mathcal Y \in \mathbb R^{\mathcal T \times d} = \text{Softmax} \left\{\left[\frac{\mathcal X \mathcal X^T}{\sqrt{d}}\right]_{\mathcal T \times \mathcal T}\right\} \cdot [\mathcal X]_{\mathcal T \times d} YRT×d=Softmax{[d XXT]T×T}[X]T×d
这种操作与循环神经网络结构有些许相似:给定一个长度为 T \mathcal T T的序列,自注意力操作后同样返回一个长度为 T \mathcal T T的输出。在不额外添加 Query,Keys,Values \text{Query,Keys,Values} Query,Keys,Values的情况下,我们可以直接使用自注意力来处理序列

关于自注意力的流程图表示如下:
如果仅仅从‘自注意力’执行过程的角度观察,感觉自注意力的输出信息不像是一个序列信息。在循环神经网络系列中如 LSTM \text{LSTM} LSTM GRU \text{GRU} GRU,之所以认为它们各时刻的输出信息是‘序列信息’,是因为它们的各时刻输出中均包含上一时刻的信息
{ RNN :  h t + 1 = Tanh ( W h t ⇒ h t + 1 ⋅ h t + W x t ⇒ h t + 1 ⋅ x t + b h ) LSTM :  C t = f t ∗ C t − 1 + i t ∗ C ~ t \begin{cases} \text{RNN : } h_{t+1} = \text{Tanh} \left(\mathcal W_{h_t \Rightarrow h_{t+1}} \cdot h_t + \mathcal W_{x_t \Rightarrow h_{t+1}} \cdot x_t +b_{h}\right) \\ \quad \\ \text{LSTM : } \mathcal C_t = f_t * \mathcal C_{t-1} + i_t * \widetilde{\mathcal C}_t \end{cases} RNN : ht+1=Tanh(Whtht+1ht+Wxtht+1xt+bh)LSTM : Ct=ftCt1+itC t
在下面的‘位置编码’部分进行解答。
自注意力机制——图形描述

自注意力机制与 RNN,CNN \text{RNN,CNN} RNN,CNN的对比

简单介绍:卷积神经网络处理序列信息的原理

事先说明:卷积神经网络 ( Convolutional Neural Network,CNN ) (\text{Convolutional Neural Network,CNN}) (Convolutional Neural Network,CNN)同样可以执行序列运算。在卷积神经网络处理图像数据过程中,通常将图像数据描述为 [ Width,Height,Channels ] [\text{Width,Height,Channels}] [Width,Height,Channels]张量格式。
其中 Width,Height,Channel \text{Width,Height,Channel} Width,Height,Channel分别表示图像的宽、高、通道数。

而在处理序列数据中,可以将序列数据(例如文本序列)描述为 [ BatchSize , MaxLength , Embedding ] [\text{BatchSize},\text{MaxLength},\text{Embedding}] [BatchSize,MaxLength,Embedding]张量格式。在卷积核的选择过程中,由于 BatchSize \text{BatchSize} BatchSize不同文本序列之间相互独立,因而卷积核的格式被限制为 [ WindowSize , 1 ] [\text{WindowSize},1] [WindowSize,1]的大小格式。其中 WindowSize \text{WindowSize} WindowSize表示覆盖序列信息的窗口大小
其中 BatchSize,MaxLength,Embedding \text{BatchSize,MaxLength,Embedding} BatchSize,MaxLength,Embedding分别表示该批次中的序列数量、最大序列长度、序列中各元素的向量表示维数。

在算法八股系列——卷积函数中介绍过单层卷积神经网络的模型结构。其结构图表示如下:
该图左侧表示‘卷积核大小’为 3 3 3的卷积神经网络结构;右侧则表示相同输入大小 ( 5 ) (5) (5)的全连接神经网络结构。
卷积神经网络VS注意力机制
虽然右侧图描述的是全连接神经网络结构,但我们可以将其视作自注意力机制的网络结构。原因在于:在自注意力机制中,每个元素均要与序列中的所有元素计算注意力分数

同理,对应循环神经网络的网络结构表示如下:
该图看起来像‘隐马尔可夫模型’的概率图结构。这里简化了很多,需要注意的是,这里的这里的蓝色点既表示各时刻的序列信息,也表示输出信息
循环神经网络——网络结构

从计算复杂度的角度观察

三结构中计算复杂度最小的自然是循环神经网络结构。原因在于:序列中的每个元素仅需执行一次前馈计算,就可得到对应时刻的输出结果。因此它的计算复杂度为: O ( T ∗ d 2 ) \mathcal O(\mathcal T * d^2) O(Td2)
其中 T \mathcal T T表示序列长度; d d d表示序列各元素的维数信息。在循环神经网络中,共经历两个层:隐藏层 h t ( t = 1 , 2 , ⋯   , T ) h_t(t=1,2,\cdots,\mathcal T) ht(t=1,2,,T)和输出层 O t ( t = 1 , 2 , ⋯   , T ) \mathcal O_t(t=1,2,\cdots,\mathcal T) Ot(t=1,2,,T)。关于序列中的每个输入元素,每一层都是关于输入与对应权重矩阵的线性运算。因此是 T × d × d \mathcal T \times d \times d T×d×d

其次是卷积神经网络,它的计算复杂度表示为: O ( K ∗ T ∗ d 2 ) \mathcal O(\mathcal K*\mathcal T*d^2) O(KTd2)

  • 卷积神经网络与循环神经网络的差别在于:序列中的各元素可能不止执行了一次运算。这取决于‘窗口大小’ ( WindowSize ) (\text{WindowSize}) (WindowSize)与步长 Step \text{Step} Step之间的关系。
  • 其中 K \mathcal K K表示窗口大小。如果 K < Step \mathcal K < \text{Step} K<Step,这意味着序列中某些元素在不同的窗口中连续地重复出现。如果执行了 Padding \text{Padding} Padding操作,导致输出大小与输入大小相同,最终执行的序列长度是 K × T \mathcal K \times \mathcal T K×T
  • 其中卷积核的大小是 K × d \mathcal K \times d K×d,并且它的输出结果也包含 d d d个维度(通道数)(和自注意力机制相比,输出大小相同,为公平起见),这意味着包含 d d d个卷积核。因此最终的复杂度是 K ∗ T ∗ d 2 \mathcal K * \mathcal T * d^2 KTd2

最终最慢的是自注意力机制,它的计算复杂度表示为: O ( T 2 ∗ d ) \mathcal O(\mathcal T^{2}* d) O(T2d)
由于自注意力机制需要序列中每个元素之间均执行一次内积运算,因此是 T × T \mathcal T \times \mathcal T T×T次线性运算。而每次内积运算均包含 d d d次运算。因此是 T 2 ∗ d \mathcal T^2 * d T2d

位置编码

在上面介绍自注意力机制时,觉得它并不像一个序列信息。是因为:我们仅仅是记录了目标词与序列中各个词之间的关联关系(相似性关系),但并没有记录序列信息(序列中各元素的相对位置/上下文位置关系)
补充:卷积神经网络处理序列数据时,其生成的输出内包含‘序列信息’。其原因是:卷积核在移动过程中,遵循某一方向移动。而移动过程中卷积核内的参数会学习序列信息。

这会产生什么效果 ? ? ?依然拿序列 X = ( x 1 , x 2 , ⋯   , x T ) T \mathcal X = (x_1,x_2,\cdots,x_{\mathcal T})^T X=(x1,x2,,xT)T为例,这会导致:序列中某元素 x t x_t xt与序列中所有元素 x 1 , x 2 , ⋯   , x T x_1,x_2,\cdots,x_{\mathcal T} x1,x2,,xT之间的相似性关系 a ( x t , x j ) ( j = 1 , 2 , ⋯   , T ) a(x_t,x_j)(j=1,2,\cdots,\mathcal T) a(xt,xj)(j=1,2,,T)离散。也就是说,将序列中的元素打乱顺序 ⇒ \Rightarrow 不会影响其相似性结果
但相反,一个文本句子打乱顺序后,就可能不是一个正确的文本句子了。

位置编码 ( Position Encoding ) (\text{Position Encoding}) (Position Encoding)就是加入位置信息的一种方式。这种编码的特点在于:它并不作用在模型内部,而是单独计算出来,直接作用在输入内(让输入自身存在位置信息)。其具体做法表示如下:

已知输入数据 X ∈ R T × d \mathcal X \in \mathbb R^{\mathcal T \times d} XRT×d,对应的位置编码矩阵 P ∈ R T × d \mathcal P \in \mathbb R^{\mathcal T \times d} PRT×d(张量大小与 X \mathcal X X相同),并执行对应元素相加操作,并将该结果重新作为自注意力机制的输入;

P \mathcal P P内元素的计算方式表示如下:
{ P i , 2 j = sin ⁡ ( i 1000 0 2 j d ) P i , 2 j + 1 = cos ⁡ ( i 1000 0 2 j d ) \begin{cases} \begin{aligned} \mathcal P_{i,2j} & = \sin \left(\frac{i}{10000^{\frac{2j}{d}}}\right) \\ \mathcal P_{i,2j+1} & = \cos \left(\frac{i}{10000^{\frac{2j}{d}}}\right) \end{aligned} \end{cases} Pi,2jPi,2j+1=sin(10000d2ji)=cos(10000d2ji)
其中 P i , 2 j \mathcal P_{i,2j} Pi,2j表示编码矩阵 P \mathcal P P i i i行、第 2 j 2j 2j列的元素值 P i , 2 j + 1 \mathcal P_{i,2j+1} Pi,2j+1同理。这里选择若干个行、列作为例子,对应代码表示如下:

import math
import matplotlib.pyplot as plt

def PositionEncoding(i,j,d=64):
    if j % 2 == 0:
        return math.sin(i / (10000 ** ((2 * j) / d)))
    else:
        return math.cos(i / (10000 ** ((2 * j) / d)))

def DrawPicture():
    j = [6,7,8,9]
    LineStyleList = ["-","--","-.",":"]
    i = [k for k in range(60)]
    for Index,Elem in enumerate(j):
        print(Elem)
        Res = list()
        jList = [Elem for _ in range(len(i))]
        for _,(Elemi,Elemj) in enumerate(zip(i,jList)):
            Res.append(PositionEncoding(Elemi,Elemj))
        plt.plot(i,Res,label="Col "+ str(Elem),linestyle=LineStyleList[Index])
    plt.legend()
    plt.show()

if __name__ == '__main__':
    DrawPicture()

对应函数图像表示如下:
其中关于序列中各元素的'特征表示'维数 d d d设置为 64 64 64
位置编码示例
从该函数图像中可以看出:横坐标表示序列长度编号 1 , 2 , ⋯   , T 1,2,\cdots,\mathcal T 1,2,,T,纵坐标表示函数的映射区间
每一条函数图像表示同一维度的位置特征在序列 X \mathcal X X中的各元素 x 1 , x 2 , ⋯   , x T x_1,x_2,\cdots,x_{\mathcal T} x1,x2,,xT的映射信息。能够看出,即便是同一维度的信息在序列不同位置的映射结果也存在不同程度的差异

为什么要设计成这种形式呢 ? ? ?上面描述的是对向量特征表示 6 , 7 , 8 , 9 6,7,8,9 6,7,8,9维度的位置信息,发现各维度图像的周期总是会出现因错位而产生的少许差异,并且特征维度 d d d的数值越大,这个差异就越不明显(细致)
下图表示 d = 1024 d=1024 d=1024时的对应图像。
d=1024时的图像信息
当然,这里选择的是 6 , 7 , 8 , 9 6,7,8,9 6,7,8,9四个连续维数 d = 1024 d=1024 d=1024维度下的效果,如果将其设置为 32 , 64 , 128 , 256 32,64,128,256 32,64,128,256四个维数,各维数的周期差异会更加明显:
32,64,128,256的维数差异图像
而这些周期性差异并非是完全不重合的,而是存在一些重合的点。为了更方便理解,我们可以观察如下例子:关于 0 − 7 0-7 07二进制编码
关于十进制数 0 − 7 0-7 07的二进制编码表示如下:
0-7的二进制编码
二进制的特点很简单:逢二进一。如果将这里每一个十进制数看作是 3 3 3个特征表示的编码结果,来观察各特征(每一列)的变化情况:
对应图像从左到右进行表示。
各特征的周期表示
很明显,由于逢二进一的原因,导致位数越高的特征周期越长(变化速度更慢)。并且它们同样存在部分重合的情况(上图中的红色框部分示例)。

并且十进制数的二进制表示,其特征仅仅是 { 0 , 1 } \{0,1\} {0,1}内的离散特征,但这种特征可以保证每个十进制数均存在独一无二的位置编码;同理,可以将自注意力机制位置编码的错位现象想象成位数的进化,对应的重合现象也是表示序列中的各元素 x 1 , x 2 , ⋯   , x T x_1,x_2,\cdots,x_{\mathcal T} x1,x2,,xT d d d特征空间中独一无二的特征信息重要的组成部分。
相比于二进制的离散信息,各维度的位置编码信息是使用函数表示的连续信息,它描述的信息更加丰富,因为我们设置的数据特征维数可能是任意大小的。

相关参考:
67 自注意力【动手学深度学习v2】

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

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

相关文章

关于前端Vue脚手架的完整搭建

创建脚手架 在VSC中打开命令行&#xff0c;输入如下命令可以用于创建脚手架 Vue create <项目名称>会出现如下选项&#xff1a; 前面是选项的名称&#xff0c;括号中的是选项包含有&#xff1a; 1、Vue的版本 2、babel是用于将高版本的js转化成为低版本的js&#xff0…

SSM 整合案例

Ssm整合 注意事项 Spring mvcSpringMybatisMySQL项目结构&#xff0c;以web项目结构整合&#xff08;还有maven、gradle&#xff09;整合日志、事务一个项目中Idea 2019、JDK12、Tomcat9、MySQL 5.5 项目结构 D:\java\Idea\Idea_spacework\SSMhzy&#xff1a;不会就去找项目…

chatgpt赋能python:Python怎么筛选奇数

Python怎么筛选奇数 Python是一种高级编程语言&#xff0c;既具有面向对象编程的特点&#xff0c;又可以进行函数式编程。Python的语法简洁、清晰&#xff0c;非常适合初学者学习。在Python中&#xff0c;筛选奇数的方法非常简单&#xff0c;本文将介绍Python中筛选奇数的方法…

人机交互学习-5 交互式系统的需求

交互式系统的需求 需求是什么需求需求活动 产品特性用户特性体验水平差异新手用户专家用户中间用户 年龄差异老年人儿童 文化差异健康差异 用户建模人物角色人物角色的作用人物角色的构造错误观点人物角色基于问题举例注意事项 建模过程 需求获取、分析和验证观察场景人物角色场…

爬虫数据是如何收集和整理的?

爬虫数据的收集和整理通常包括以下步骤&#xff1a; 确定数据需求&#xff1a;确定要收集的信息类型、来源和范围。 网络爬取&#xff1a;使用编程工具&#xff08;如Python的Scrapy、BeautifulSoup等&#xff09;编写爬虫程序&#xff0c;通过HTTP请求获取网页内容&#xff…

网卡命名规则和网卡变动结论

net.ifnames0 biosdevname0 插卡前状态&#xff1a; 插卡后状态&#xff1a; 结论&#xff1a;明显eth0 MAC地址从00:0d:48:94:10:fc 变更为 c0:33:da:10:31:ff。该方法eth0实际对应的网口发生了变动。 net.ifname1 插卡前状态&#xff1a; 插卡后状态&#xff1a; 查看…

MEC | 条款2 最好使用C++转型操作符

条款2 最好使用C转型操作符 文章目录 条款2 最好使用C转型操作符c4个转型操作符static_castconst_castdynamic_castreinterpret_cast 宏模仿新转换语法欢迎关注公众号【三戒纪元】 c4个转型操作符 static_castconst_castdynamic_castreinterpret_cast 原因是 新式转型方法容…

chatgpt赋能python:Python在SEO中如何确定主语?

Python在SEO中如何确定主语&#xff1f; Python是一种高级编程语言&#xff0c;广泛应用于Web开发、数据分析和机器学习等领域。但是&#xff0c;Python编写的网页是否符合SEO标准&#xff0c;是一个需要重视的问题。在SEO中&#xff0c;主语是一个非常重要的因素。那么&#…

CLickhouse 物化视图--干货记录(亲验证)

1、普通视图VS物化视图 普通视图不保存数据&#xff0c;保存的仅仅是查询语句&#xff0c;查询的时候还是从原表读取数据&#xff0c;可以将普通视图理解为是个子查询。--中看不中用 物化视图则是把查询的结果根据相应的引擎存入到了磁盘或内存中&#xff0c;对数据重新进行了…

Duilib中禁止一个窗口双击最大化

1、Duilib中禁止一个窗口双击最大化 用duilib开发了一个窗口&#xff0c;比如是登录窗口&#xff0c;那么这个窗口的窗口的双击最大化就毫无意义&#xff0c;甚至带来灾难&#xff0c;我们就要明确禁止这样的行为。 我们应该明确&#xff0c;一个窗口创建的时候就赋予了它一些…

内核链表、JSON的序列化与反序列化

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除&#xff1b; 2) 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍&#xff0c;如有需要编译器会在成员之间加上填充字节(internal adding)&#xff1b; 3) 结构体的总大小为结构体最宽基本类型…

计算机组成原理(考研408)练习题#3

用于复习408或计算机组成原理期末考试。如有错误请在评论区指出。 So lets start studying with questions! それでは、問題の勉強を始めましょう&#xff01; 1. 定点整数原码编码[x]原1110100B 的真值为_________。 首先&#xff0c;1110100B是一个8位二进制数&#xff0c…

Spring Cloud Sleuth使用简介

Spring-Cloud Spring Cloud为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性Token、全局锁、决策竞选、分布式会话和集群状态)操作的开发工具。使用SpringCloud开发者可以快速实现上述这些模式。 SpringCloud Sleuth Distribu…

【0基础教程】Javascript 正则表达式里的分组捕捉 Capturing Groups 使用方法及原理

一、从最简单开始 现有一个字符串&#xff1a; “1-apple” 需要解析出 1 和 apple 来&#xff0c;对应的正则表达式很简单&#xff1a; ^(\d)-(.)$ 其中&#xff0c; ^ 表示字符串的开始&#xff0c;然后一个圆括号包裹的内容表示一个"组"&#xff1a;(\d) 表示一组…

【深度学习】2-1 神经网络 - 激活函数

激活函数 将输入信号的总和转换为输出信号&#xff0c;一般称为激活函数&#xff08;activation function&#xff09;。激活函数作用在于决定如何来激活输入信号的总和。 对激活函数&#xff0c;一般要求&#xff1a; 非线性&#xff1a;为提高模型的学习能力&#xff0c;如…

Nginx reuseport导致偶发性卡顿

背景 从2018年开始&#xff0c;我们有个业务陆续接到反馈 Nginx 线上集群经常出现不响应或者偶发性的“超慢”请求。这种卡顿每天都有少量出现。而只有多个集群中的一个出现&#xff0c;其他压力更大的集群皆未出现。 业务结构比较简单&#xff1a;LVS->Nginx->后端&…

Advanced-C.01.基础知识

C语言程序设计概述 一个简单句的C程序 #include <stdio.h> int main(){printf("This is a C program.\n");retrun 0; }C程序的执行过程 数据单位 bit&#xff1a;位&#xff0c;计算机中最小的数据单位Byte&#xff1a;字节&#xff0c;计算机中信息组织和存…

C++ 搜索二叉树

目录 C 搜索二叉树一. 介绍二.简单实现搜索二叉树1. 基本框架2. 插入节点a. 图示&#xff1a;b. 递归实现&#xff1a;c. 非递归&#xff1a; 3. 删除节点a. 图示&#xff1a;b. 递归实现&#xff1a;c. 非递归&#xff1a; 三. 小结 C 搜索二叉树 又名&#xff1a;二叉搜索树…

bean的三种实例化方式

实例化bean的三种方式&#xff0c;构造方法,静态工厂和实例工厂 构造方法实例化&#xff08;常用&#xff09; 步骤1&#xff1a;准备一个BookDao和BookDaoImpl类 public interface BookDao {public void save(); } ​ public class BookDaoImpl implements BookDao {public…

Vue中如何进行表单图片裁剪与预览

Vue中如何进行表单图片裁剪与预览 在前端开发中&#xff0c;表单提交是一个常见的操作。有时候&#xff0c;我们需要上传图片&#xff0c;但是上传的图片可能会非常大&#xff0c;这会增加服务器的负担&#xff0c;同时也会降低用户的体验。因此&#xff0c;我们通常需要对上传…