NLP算法岗八股秋招自用----不定时更新中

NLP算法岗八股

介绍一下BERT和GPT

区别1、模型基础和架构
BERT是基于Transformer的编码器部分进行堆叠构建,通过预训练和微调两个阶段来生成深度的双向语言表征。
GPT是基于Transformer的解码器部分,通过自回归语言模型预训练来学习生成连贯文本的能力。
区别2:训练方式和任务
BERT:BERT使用了双向语言模型的训练策略。在输入序列中,BERT随机掩盖一些词语,并让模型预测这些被掩盖的词语。这种方式使BERT能够从上下文中学习词语的语义和语境信息。
GPT:GPT使用了自回归语言模型的训练方式。它通过让模型预测当前位置的词语来学习生成文本的能力。在预训练过程中,GPT逐步生成下一个词语,并优化参数以最大化下一个词语的概率。
区别3:上下文理解能力和应用场景
BERT:由于BERT采用双向模型,通过预测被掩盖的词语和判断句子之间的关系。它可以从上下文中获取更丰富的信息,并具有较强的上下文理解能力。这使得BERT在词语级别的任务中表现出色,如命名实体识别、问答等。
GPT:GPT是一个单向模型,它只能依赖已生成的上文来预测下一个词语。在预训练过程中,GPT使用自回归语言模型进行训练,通过逐步生成下一个词语来学习生成连贯的文本。由于单向模型的限制,GPT在生成式任务中表现较好,如对话生成、文本生成等。GPT能够生成具有上下文连贯性和逻辑性的文本,因为它在生成每个词语时都能考虑之前已生成的上文。

了解哪些深度学习模型(MLP、CNN、RNN、Transformer),说一下各自的优缺点;

多层感知器(Multi-Layer Perceptron,MLP)是一种基本的人工神经网络模型。它由多个神经元组成多个层次,其中输入层接收外部输入信号,输出层产生输出结果,中间的隐藏层通过非线性变换对输入进行处理,从而学习数据的复杂特征。不适用于处理序列数据或图像数据,因为它不具备处理输入之间时间或空间关系的能力。
卷积神经网络(CNN):通常用于计算机视觉中,可以用来图像识别和图像分类。CNN 用于提取图像的空间特征,通过不断的卷积和池化操作实现特征提取和降维卷积层提取图像的局部特征,通过卷积核的过滤提取出图片中局部的特征,类似初级视觉皮层进行初步特征提取。池化层用来大幅降低参数量级,实现数据降维。下采样实现数据降维,大大减少运算量,避免过拟合。输入层(Input layer)卷积层(CONV layer,包含激活函数,比如 ReLU、sigmoid、tanh 等)池化层(Pooling layer)全连接层(FC layer)输出层(Ouput layer)
循环神经网络(RNN):通常用于自然语言处理和语音识别中,可以用来处理时间序列数据。RNN 的主要思想是把前面的信息传递到后面,这样网络就可以利用之前的信息做出预测,能够处理序列中每个时间步的数据。但难以捕捉长序列中的依赖关系。
Transformer是基于自注意力机制编码器-解码器架构。在处理序列数据任务(尤其是NLP任务如机器翻译)中表现优异。能够并行处理序列数据,有效捕捉长距离依赖关系。一种基于自注意力机制的神经网络结构,通过并行计算多层特征抽取有效解决了长序列依赖问题,实现了在自然语言处理等领域的突破。
在这里插入图片描述

Transformer 模型的基本结构包括哪些部分?

Transformer 模型的基本结构主要包括输入嵌入层、位置编码、编码器(Encoder)、解码器(Decoder)以及最终的线性层和softmax层。
输入嵌入层:字的embedding,可以通过Word2Vec、Glove 等算法预训练得到,也可以在 Transformer 中训练得到。
位置编码:在Attention is all you need这篇论文中提到的,位置编码采用的是正余弦函数编码。
P E ( p o s , 2 i ) = s i n ( p o s 1000 0 2 i / d ) PE_{(pos,2i)}=sin(\frac{pos}{10000^{2i/d}}) PE(pos,2i)=sin(100002i/dpos)
P E ( p o s , 2 i + 1 ) = c o s ( p o s 1000 0 2 i / d ) PE_{(pos,2i+1)}=cos(\frac{pos}{10000^{2i/d}}) PE(pos,2i+1)=cos(100002i/dpos)
其中pos表示字在句子中的位置,d 表示 PE的维度 (与字的embedding一样),2i 表示偶数的维度,2i+1 表示奇数维度 (即 2i≤d, 2i+1≤d)。
编码器:6个相同的block块堆叠而成,每个block块都有两个重要的组成部分,分别是多头注意力机制和前馈神经网络,它们后面都紧跟着残差连接和Layernorm层。
解码器:6个相同的block块堆叠而成,每个block块的重要的组成部分,分别是掩码多头注意力机制和多头注意力机制和前馈神经网络,它们后面都紧跟着Add残差连接和Layernorm层。Add 表示残差连接 (Residual Connection) 用于防止网络退化,Norm 表示 Layer Normalization,用于对每一层的激活值进行归一化。
最终的线性层和softmax层。

Transformer模型中的位置编码是用来解决什么问题的?

词语的位置和顺序对句子意思表达都是至关重要的,而transformer模型不像RNN模型根据时间步处理文本信息。句子中的词语都是同时进入网络进行处理,所以没有明确的关于单词在源句子中位置的相对或绝对的信息。为了让模型理解序列中每个单词的位置(顺序),Transformer论文中提出了使用一种叫做 Positional Encoding(位置编码) 的技术来解决这个问题。

Transformer中注意力的作用是什么?

self-attention: s o f t m a x ( q ∗ k T d k ) v softmax(\frac{q*k^T}{\sqrt{d_k}})v softmax(dk qkT)v
Transformer采用自注意力机制,能够在处理一个序列时考虑序列中的每个元素与其他所有元素之间的关系。在 Transformer 中,它帮助模型捕捉序列内部的长距离依赖。

Transformer模型中自注意力机制的数学表达式是什么?

Self-Attention公式:[ S o f t m a x ( q ∗ k T d k ) v Softmax(\frac{q*k^T}{\sqrt{d_k}})v Softmax(dk qkT)v],其中,q、k和v分别代表查询(query)、键(key)和值(value)矩阵, d k d_k dk是键向量的维度。此表达式通过将查询和键的点积除以 d k \sqrt d_k d k进行缩放,然后应用 softmax 函数来获取权重,最后这些权重用于值向量的加权求和。

为什么自注意力机制在计算时需要对点积结果进行 d k \sqrt d_k d k的缩放?

为什么在进行softmax之前需要对attention进行scaled(为什么除以dk的平方根),并使用公式推导进行讲解

学习链接:链接讲的很详细
https://blog.csdn.net/qq_37430422/article/details/105042303

d k d_k dk过大的时候, q T k q^Tk qTk 的方差较大,也就是说不同的 key 与同一个 query 算出的对齐分数可能会相差很大,有的远大于 0,有的则远小于 0. softmax 函数梯度过低(趋于零),使得模型误差反向传播(back-propagation)经过softmax 函数后无法继续传播到模型前面部分的参数上,造成这些参数无法得到更新,最终影响模型的训练效率。缩放后,score(q,k) 的方差由原来的 d k d_k dk缩小到了1. 这就消除了 dot-product attention 在 d k d_k dk较大时遇到的问题。这时,softmax 函数的梯度就不容易趋近于零了。

Transformer为何使用多头注意力机制?(为什么不使用一个头)

学习链接:https://blog.csdn.net/zgpeace/article/details/126635650

在这里插入图片描述
self-attention只是使用了一组 W Q W_Q WQ W K W_K WK W V W_V WV来进行变换得到查询、键、值矩阵,而Multi-Head Attention使用多组 W Q W_Q WQ W K W_K WK W V W_V WV得到多组查询、键、值矩阵.分别计算。
1、并行计算。多头注意力机制允许模型同时关注输入序列的不同部分,每个注意力头可以独立计算,从而实现更高效的并行计算。这样能够加快模型的训练速度。
2、提升表征能力:通过引入多个注意力头,模型可以学习到不同类型的注意力权重,从而捕捉输入序列中不同层次、不同方面的语义信息。这有助于提升模型对输入序列的表征能力。
3、降低过拟合风险:多头注意力机制使得模型可以综合不同角度的信息,从而提高泛化能力,降低过拟合的风险。
增强模型解释性:每个注意力头可以关注输入序列的不同部分,因此可以更好地理解模型对于不同输入信息的关注程度,使得模型的决策更具解释性。

Transformer为什么Q和K使用不同的权重矩阵生成,为何不能使用同一个值进行自身的点乘?

学习链接:https://zhuanlan.zhihu.com/p/360144789
https://www.cnblogs.com/jins-note/p/14508523.html

首先就是为什么要进行QK点乘,是因为想要得到attention score,也就是想得到每个key对query的重要程度。之后作为权值与value相乘,得到一个加权后的结果。
但如果query和key使用相同的权重矩阵,就相当于 q q T qq^T qqT,得到的是一个对称矩阵,这样A对B的重要程度等于B对A的重要程度,这显然是有问题的,一句话中A字对B字的重要程度不一定与B字对A字的重要程度相同。
如果K和Q使用不同的值的话, A对B的重要程度是Key(A) * Query(B), 而B对A的重要程度是Key(B) * Query(A). 可以看出, A对B的重要程度与B对A的重要程度是不同的. 然而, 如果K和Q是一样的, 那么A对B的重要程度和B对A的重要程度是一样的.

Q(查询)和K(键)使用不同的权重矩阵生成,是为了在计算注意力得分时能够捕捉到输入序列中不同的特征。如果使用同一个值进行自身的点乘,模型无法有效区分查询向量和键向量的不同特征,导致注意力机制失去灵活性和区分能力。因此,通过不同的权重矩阵生成Q和K,可以增强模型的表达能力,确保注意力机制能够更好地识别和利用输入序列中的信息。

Transformer计算attention的时候为何选择点乘而不是加法?两者计算复杂度和效果上有什么区别?

在计算attention score的时候如何对padding做mask操作?

学习链接https://www.cnblogs.com/sherrlock/p/17629223.html

在训练的过程中,自然语言数据往往都是以Batch的形式输入进的模型,而一个batch中的每一句话不能保证长度都是一样的,所以需要使用PADDING的方式将所有的句子都补全到最长的长度,比如拿0进行填充,但是我们知道这种用0填充的位置的信息是完全没有意义的,因此我们希望这个位置不参与后期的反向传播过程。以此避免最后影响模型自身的效果,因此提出了在训练时将补全的位置给Mask掉的做法。而在Self-attention的计算当中,我们自然也不希望有效词的注意力集中在这些没有意义的位置上,因此使用了PADDING MASK的方式.
假设我们有一个长度为4的序列:[A, B, C, ],其中是填充标记。对应的padding mask是:[0, 0, 0, 1]。
在计算注意力分数后,我们可以使用以下方法应用padding mask:

attention_scores = attention_scores.masked_fill(mask == 1, -1e9)

这里,masked_fill是一个PyTorch函数,它会将mask中值为1的位置替换为-1e9
看图,这里的attention_scores就是Q×K的矩阵,把尾部多余的部分变成-inf,再过SoftMax,这样就是0了。这样,即使V的后半部分有padding的部分,也会因为乘0而变回0。这样被padding掉的部分就从计算图上被剥离了,由此不会影响模型的训练。

为什么在进行多头注意力的时候需要对每个head进行降维?(可以参考上面一个问题)

学习链接:https://www.zhihu.com/question/350369171/answers/updated

将原有的高维空间转化为多个低维空间并再最后进行拼接,形成同样维度的输出,借此丰富特性信息。
回答:在进行多头注意力时,需要对每个头进行降维,以保证每个头的计算复杂度不会过高,同时能够并行计算。将输入的维度分成多个头,可以让每个头处理更小维度的数据,从而降低单头的计算复杂度,减小参数量,提高计算效率。并且通过多个头的组合,增强模型的表达能力和鲁棒性。

详细讲解:

降低计算复杂度
假设输入的维度是d,每个头的输出维度也是d。如果不进行降维,每个头的输出维度仍然是d,那么在拼接多个头的输出时,最终的维度将是d * num_heads(num_heads表示头的数量)。这样维度会变得非常大,计算复杂度和内存需求都大大增加。
通过对每个头进行降维,每个头的输出维度变为d / num_heads。这样,即使拼接多个头的输出,最终的维度也仍然是d,保持了与输入相同的维度,避免了计算复杂度和内存需求的急剧增长。

保持模型的参数数量可控
模型的参数数量直接影响训练的难度和时间。如果每个头都不进行降维,那么模型的参数数量会大大增加,训练起来会非常困难。而对每个头进行降维,可以控制每个头的参数数量,从而使得整个模型的参数数量保持在一个可控范围内。

维持信息的多样性
通过对每个头进行降维,可以确保每个头在一个更小的子空间中进行注意力计算。这意味着每个头可以在不同的子空间中学习到不同的特征,增加了模型的多样性和鲁棒性。最终的拼接结果融合了不同子空间的信息,使得模型能够更全面地理解输入数据。

大概讲一下Transformer的Encoder模块?

Transformer 模型中的 Encoder 层主要负责将输入序列进行编码,将输入序列中的每个词或标记转换为其对应的向量表示,并且捕获输入序列中的语义和关系。
Encoder模块由多个相同的block块组成,每个block块有两个重要的部分,多头注意力机制和前馈神经网络。并且他们之后都紧跟残差连接+归一化层。
多头注意力机制: s o f t m a x ( q k T d k ) v softmax(\frac{qk^T}{\sqrt{d_k}})v softmax(dk qkT)v
首先将输入矩阵X分别乘 W q W_q Wq, W k W_k Wk, W v W_v Wv得到q,k和v,然后q和k的转置相乘,除以 d k \sqrt{d_k} dk 防止梯度消失,经过softmax函数得到关注度分数矩阵,也就是获得每个词之间的关联程度。当作权重矩阵与V向量矩阵相乘。得到加权后的词向量。
Add:X+selfattention(X),防止网络退化造成的梯度消失。残差连接允许模型直接学习到输入序列的增量变换,而不是完全替代原始输入。通常用于解决多层网络训练的问题,可以让网络只关注当前差异的部分
norm:LayerNorm(X+selfattention(X)),Norm指 LayerNormalization,通常用于 RNN 结构,Layer Normalization 会将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛。
FeedForword:前馈神经网络,包含两层全连接层,第一层全连接层+激活函数Relu。实现将该层的输入投放到高维空间,学习更多特征。第二层只有全连接层,实现从高维空间再回归原维度。
norm+LayerNormalization
在这里插入图片描述

为何在获取输入词向量之后需要对矩阵乘以embedding size的开方?意义是什么?

在获取输入词向量之后,需要对矩阵乘以embedding size的平方根,是为了保持向量的尺度稳定。Embedding的值通常是随机初始化的,乘以开方后的结果能保证在后续的点乘计算中,值的尺度不会过大或过小,从而有利于模型的训练稳定性。

简单介绍一下Transformer的位置编码?有什么意义和优缺点?

学习链接:https://blog.csdn.net/m0_37605642/article/details/132866365
介绍的很详细

词语的位置和顺序对句子意思表达都是至关重要的,而transformer模型不像RNN模型根据时间步处理文本信息。句子中的词语都是同时进入网络进行处理,所以没有明确的关于单词在源句子中位置的相对或绝对的信息。为了让模型理解序列中每个单词的位置(顺序),Transformer论文中提出了使用一种叫做 Positional Encoding(位置编码) 的技术。
在这里插入图片描述
Transformer论文中,使用正余弦函数表示绝对位置,通过两者乘积得到相对位置。因为正余弦函数具有周期性,可以很好地表示序列中单词的相对位置。
优点是能够显式地提供位置信息,易于计算,缺点是位置编码固定,不能根据上下文动态调整。

你还了解哪些关于位置编码的技术,各自的优缺点是什么?

ROPE、可学习位置编码、sincos位置编码、相对位置编码

简单讲一下Transformer中的残差结构以及意义。

学习链接:https://zhuanlan.zhihu.com/p/42833949
https://developer.volcengine.com/articles/7389519960881496075
https://blog.csdn.net/liaomin416100569/article/details/138789156

残差连接(Residual Connection)是一种在深度神经网络中用于解决梯度消失和梯度爆炸问题的技术。它通过将输入直接添加到神经网络的某些层的输出中,从而允许梯度直接通过残差路径传播,减轻了梯度消失的问题,加速了训练过程
具体来说,假设我们有一个包含多个层的神经网络,每个层都由输入x经过一些变换F(x)得到输出H(x)。传统的神经网络会直接将 H(x) 作为下一层的输入,而残差连接则是将x与H(x) 相加,即 x H(x),然后再输入到下一层。这样做可以使得网络学习到的变换是相对于输入的增量,而不是完全替代原始输入
残差连接的作用包括:
**缓解梯度消失:**通过保留原始输入的信息,使得梯度可以更容易地传播到较浅层,从而减轻了梯度消失问题。
**加速训练:**残差连接可以使得神经网络更快地收敛,因为它减少了训练过程中的信息丢失。
**提高模型性能:**残差连接使得神经网络可以更深,更复杂,从而能够更好地捕捉输入数据的特征和模式。
举个例子,考虑一个包含残差连接的深度残差网络(Residual Network,ResNet)。在这个网络中,每个残差块都由两个或多个卷积层组成,其中第一个卷积层产生特征图 H(x),而第二个卷积层则对H(x) 进行进一步变换。然后,原始输入x 被添加到 H(x) 上,得到 F(x)=H(x)+x。这样,输出F(x) 就包含了相对于输入x 的增量,网络可以更轻松地学习到残差部分,从而更有效地优化模型。
Transformer中的残差结构(Residual Connection)是在每个子层输出后,加入输入的原始信息,通过直接相加实现。这有助于缓解深层网络中的梯度消失问题,保证信息流的顺畅,促进训练过程的稳定和快速收敛。

prenorm和postnorm

在transformer中,Add&Norm操作可以分为两种:PreNorm和PostNorm。PreNorm是先执行LayerNorm操作,然后传入下一层,同时在下一层只把 X t X_t Xt X t + 1 X_{t+1} Xt+1相加。
PostNorm是先将上一层的输出和当前层的输出相加之后,再进行的LayerNorm。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PostNorm在残差之后做归一化,对参数正则化的效果更强,进而模型的鲁棒性也会更好。PreNorm相对于PostNorm,因为有一部分参数直接加在了后面,不需要对这部分参数进行正则化,正好可以防止模型的梯度爆炸或者梯度消失。

batch norm和layer norm

在这里插入图片描述
batch norm是对所有批次的某个特征做标准化
layer norm是对一个样本的所有特征进行标准化
比如有三句话:“郑明去吃饭了”“小花长大了”“胖达死了”
batch norm是分次对这三句话的同一指定位置进行归一化。
layer norm是分次对每句话所有位置的字进行归一化

为什么transformer块使用LayerNorm而不是BatchNorm?LayerNorm 在Transformer的位置是哪里?

git上:DA-southampton/NLP_ability

Transformer模型中的注意力机制会使不同位置的特征之间存在依赖关系。
Batchnorm是对一个batch中的所有样本的每个特征进行归一化,这会破坏注意力机制所学习到的位置信息。
而LayerNorm是对每个样本的每个特征进行归一化,这样可以保留位置信息。
此外,Batchnorm在训练过程中需要计算每个batch的均值和方差,这在Transformer模型中会带来很大的计算开销。而LayerNorm只需要计算每个样本的均值和方差,计算开销更小。
LayerNorm的优点:能够缓解梯度饱和问题、能够保留注意力机制所学习到的位置信息、计算开销更小

简答讲一下BatchNorm技术,以及它的优缺点。

https://www.zhihu.com/column/p/153183322

简单描述一下Transformer中的前馈神经网络?使用了什么激活函数?

学习链接:https://blog.csdn.net/2401_85377976/article/details/141422784

在这里插入图片描述
所以FeedForward的作用是:通过线性变换,先将数据映射到高纬度的空间再映射到低纬度的空间,提取了更深层次的特征
在这里插入图片描述
使用的是ReLU激活函数。
Transformer前馈神经网络两层结构: 包括两个线性变换,并在它们之间使用ReLU激活函数。 两个线性层的差异主要体现在它们的作用和维度变化上。

第一层线性变换负责将输入映射到更高维度的空间,并引入非线性;而第二层线性变换则负责将输出映射回与输入相同的维度(或兼容的维度),通常不引入额外的非线性。
第一层线性变换:这是一个全连接层,它接收自注意力层的输出作为输入,并将其映射到一个更高维度的空间。这个步骤有助于模型学习更复杂的特征表示。
激活函数:在第一层全连接层之后,通常会应用一个非线性激活函数,如ReLU(Rectified Linear Unit)。ReLU函数帮助模型捕获非线性关系,提高模型的表达能力。
第二层线性变换:这也是一个全连接层,它将前一层的输出映射回与输入相同的维度(或与模型其他部分兼容的维度)。这一层通常没有非线性激活函数。
Relu优点是增加模型的非线性表达能力,结构简单高效。缺点是ReLU可能导致部分神经元输出恒为零(死神经元),需要慎重选择超参数。

Encoder端和Decoder端是如何进行交互的?(在这里可以问一下关于seq2seq的attention知识)

学习链接:https://blog.csdn.net/liaomin416100569/article/details/138843009
https://blog.csdn.net/qq_44722174/article/details/118978582

在这里插入图片描述
decoder的交互层,Q矩阵来自本身,K/V矩阵来自整个Encoder层输出。
Cross Self-Attention,Decoder提供Q,Encoder提供K,V
每个大的模块分为三部分:掩码多头注意力层,交互层,前馈神经层;每个层内部尾端都含有 Add&Norm。

Decoder阶段的多头自注意力和encoder的多头自注意力有什么区别?(为什么需要decoder自注意力需要进行 sequence mask)

Decoder的多头注意力是Masked 多头注意力机制, q k T d k \frac{qk^T}{\sqrt{d_k}} dk qkT之后,softmax之前乘Mask矩阵,只保留当前字与前面字的重要程度。当前字与后面字的重要程度=0,这样得到的权重矩阵就是下三角矩阵,只让模型知道当前字与其前面的字重要程度,来预测当前字。
numpy.triu()函数的基本用法相对简单,它接受一个二维数组(即矩阵)作为输入,并返回该矩阵的上三角部分。函数的原型如下:

numpy.triu(m, k=0)

当k=0时,函数返回主对角线及其上方的元素;当k为正数时,返回主对角线上方第k条对角线及其上方的元素;当k为负数时,返回主对角线下方第|k|条对角线及其上方的元素。

numpy.triu(m, k)同理,只不过是取下三角
def subsequent_mask(size):
    "Mask out subsequent positions."
    attn_shape = (1, size, size)
    subsequent_mask = np.triu(np.ones(attn_shape), k=1).astype('uint8')
    return torch.from_numpy(subsequent_mask) == 0
###输出###

在这里插入图片描述

Transformer的并行化提现在哪个地方?Decoder端可以做并行化吗?

体现在使用多头注意力机制上,可以并行处理整个序列,但是rnn只能从前到后的执行。
Decode引入sequence mask就是为了并行化训练,Decoder推理过程没有并行,只能一个一个的解码,很类似于RNN,这个时刻的输入依赖于上一个时刻的输出。

Transformer在哪里做了权重共享,为什么可以做权重共享?好处是什么?

权重共享是指在模型的不同层之间复用相同的参数。这可以减少模型的总体参数数量,并使得模型在训练时更容易学习。
Transformer在两个地方进行了权重共享:
(1)Encoder和Decoder间的Embedding层权重共享;
对于(1),《Attention is all you need》中Transformer被应用在机器翻译任务中,源语言和目标语言是不一样的,但它们可以共用一张大词表,对于两种语言中共同出现的词(比如:数字,标点等等)可以得到更好的表示,而且对于Encoder和Decoder,嵌入时都只有对应语言的embedding会被激活,因此是可以共用一张词表做权重共享的。
论文中,Transformer词表用了bpe来处理,所以最小的单元是subword。英语和德语同属日耳曼语族,有很多相同的subword,可以共享类似的语义。而像中英这样相差较大的语系,语义共享作用可能不会很大。
但是,共用词表会使得词表数量增大,增加softmax的计算时间,因此实际使用中是否共享可能要根据情况权衡。
(2)Decoder中Embedding层和FC层权重共享。
对于(2),Embedding层可以说是通过onehot去取到对应的embedding向量,FC层可以说是相反的,通过向量(定义为 x)去得到它可能是某个词的softmax概率,取概率最大(贪婪情况下)的作为预测值。
那哪一个会是概率最大的呢?在FC层的每一行量级相同的前提下,理论上和 x 相同的那一行对应的点积和softmax概率会是最大的(可类比本文问题1)。
因此,Embedding层和FC层权重共享,Embedding层中和向量 x 最接近的那一行对应的词,会获得更大的预测概率。实际上,Decoder中的Embedding层和FC层有点像互为逆过程。
通过这样的权重共享可以减少参数的数量,加快收敛。
但开始我有一个困惑是:Embedding层参数维度是:(v,d),FC层参数维度是:(d,v),可以直接共享嘛,还是要转置?其中v是词表大小,d是embedding维度。

简单描述一下wordpiece model 和 byte pair encoding,有实际应用过吗?

Transformer训练的时候学习率是如何设定的?Dropout是如何设定的,位置在哪里?Dropout 在测试的需要有什么需要注意的吗?

引申一个关于bert问题,bert的mask为何不学习transformer在attention处进行屏蔽score的技巧?

为什么BERT在第一句前会加一个[CLS]标志?

BERT在第一句前会加一个**[CLS]标志,最后一层该位对应向量可以作为整句话语义表示**,从而用于下游的分类任务等。
为什么选它表示整句话语义?
因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。
而**[CLS]位本身没有语义**,经过12层,得到的是attention后所有词加权平均,相比其他正常词,可以更好的表征句子语义。当然,也可以通过对最后一层所有词的embedding做pooling去表征句子语义。
这里补充一下bert的输出,有两种,在BERT TF源码中对应:
一种是get_pooled_out(),就是上述**[CLS]的表示**,输出shape是[batch size,hidden size]。
一种是get_sequence_out(),获取的是整个句子每一个token的向量表示,输出shape是[batch_size, seq_length,hidden_size],这里也包括[CLS],因此在做token级别的任务时要注意它。

BERT的三个Embedding直接相加会对语义有影响吗?

在BERT中,token分3种情况做mask,分别的作用是什么?

BERT预训练模型会对输入数据进行“mask策略”的修改。具体为:保留85%的token不进行“mask策略”的修改(也就是单词还是其本身对15%的token进行“mask策略”的修改)
对于被选中15%的token需要进行**“mask策略”**的token:
以80%的概率替换为[MASK]标记;
以10%的概率替换为词表中的任意一个随机的词;
以10%的概率保持原词不变,即不替换。(也就是单词还是其本身。
这么做的原因是如果句子中的某个Token100%都会被mask掉,那么在fine-tuning的时候模型就会有一些没有见过的单词。加入随机Token的原因是因为Transformer要保持对每个输入token的分布式表征,否则模型就会记住这个[mask]是token ’hairy‘。至于单词带来的负面影响,因为一个单词被随机替换掉的概率只有15%*10% =1.5%,这个负面影响其实是可以忽略不计的。

为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?

BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的。

BERT用的是transformer里面的encoder还是decoder?

BERT只使用了Transformer中的Encoder部分。并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。原论文中,作者分别用12层和24层Transformer Encoder组装了两套BERT模型,分别是:
在这里插入图片描述
其中层的数量(即,Transformer Encoder块的数量)为 L ,隐藏层的维度为 H,自注意头的个数为 A ​。在所有例子中,我们将前馈/过滤器(Transformer Encoder端的feed-forward层)的维度设置为 4H,即当 ​H=768时,是 ​3072;当 ​H=1024时,是4096.
需要注意的是,与Transformer本身的Encoder端相比,BERT的Transformer Encoder端输入的向量表示,多了Segment Embeddings。 ​

针对句子语义相似度/多标签分类的任务,利用BERT结构怎么做fine-tuning?

1、针对句子语义相似度的任务:
在这里插入图片描述
[cls]句1[sep]句2[sep],上述最后一句话之后还会加一个[SEP] token,语义相似度任务将两个句子按照上述方式输入即可,之后与论文中的分类任务一样,将**[CLS] token位置对应的输出**,接上softmax做分类即可(实际上GLUE任务中就有很多语义相似度的数据集)。
2、针对多标签分类的任务
多标签分类任务,即MultiLabel,指的是一个样本可能同时属于多个类,即有多个标签。以商品为例,一件L尺寸的棉服,则该样本就有至少两个标签——型号:L,类型:冬装。
利用BERT模型解决多标签分类问题时,其输入与普通单标签分类问题一致,得到其embedding表示之后(也就是BERT输出层的embedding),有几个label就连接到几个全连接层(也可以称为projection layer),然后再分别接上softmax分类层,这样的话会得到​ loss1,loss2,loss3,…,lossn,最后再将所有的loss相加起来即可。这种做法就相当于将n个分类模型的特征提取层参数共享,得到一个共享的表示(其维度可以视任务而定,由于是多标签分类任务,因此其维度可以适当增大一些),最后再做多标签分类任务。

使用BERT预训练模型为什么最多只能输入512个词,最多只能两个句子合成一句?

BERT非线性的来源在哪里?multi head attention 是线性的嘛?

主要来自两个地方:前馈层的gelu激活函数和self-attention
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attention layer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。

BERT 是如何区分一词多义的?

BERT 的核心是 Self-Attention,而 Self-Attention 的核心是用文本中的其它词来增强目标词的语义表示
对于一个句子,每经过一层 Self-Attention,每个词的embedding 都会是这句话中所有词 embedding 的加权平均,也就会融合这句话中所有词的信息。因此,对于同一个词,不同的上下文会让这个词融合不同的语义信息,使得同一个词在不同的上下文中有不同的embedding,去表征不同的语义,从而区分一词多义。

Bert在预训练任务中有MLM任务。通过随机掩码15%的token,并采取三种策略对选中的token进行掩码。让模型去预测[Mask]的token是哪个字,从而让模型学习上下文信息,理解句子中每个单词与上下文之间的关系。通过预测被掩盖的单词,BERT可以学习到句子中单词之间的依赖关系,从而更好地理解语言的内在结构。

BERT的输入是什么,哪些是必须的,为什么position id不用给,type_id 和 attention_mask没有给定的时候,默认会是什么

首先将输入改造成[CLS]+句子A(+[SEP]+句子B+[SEP]) 其中[cls]表示句子的开始,[sep]表示分隔符或句子的结束。
而模型能理解的是数字,所以需要将文本转化为向量表示,在BERT中,输入的向量是由三种不同的embedding求和而成,分别是token embedding+position embedding+segment embedding.
在这里插入图片描述
position_id不用给,我看过源代码,通过torch.arrange(seqlen)生成0-(seqlen-1)的长度,unsqueeze()的作用是用来增加给定tensor的维度的,unsqueeze(dim)就是在维度序号为dim的地方给tensor增加一维。因为position的维度要跟tokenizer的维度一样。
token_type_id:如果不给,默认None,然后模型里面有判断,如果token_type_idNone,会生成全0的mask矩阵。代表只有1句话.
attention_mask:如果不给,默认None,然后模型里面有判断,如果attention_mask
None,会生成全1的mask矩阵。代表没有填充值.
在这里插入图片描述

BERT训练时使用的学习率 warm-up 策略是怎样的?为什么要这么做?

之前遇到一个这样的问题:

在做一个数据量很大的训练(千万至亿级别),在一个epoch内,看到训练误差先减小后上升,然后通过观察测试集变化,排除了模型和数据出错的可能。

最后把问题目标锁定在学习率过大,导致模型提前过拟合,结果对于新的训练数据loss变大。

那么有人可能会问,这跟warmup有什么关系?

先看warmup的实现:

if warmup:
warmup_steps = int(batches_per_epoch * 5)
warmup_lr = (initial_learning_rate * tf.cast(global_step, tf.float32) / tf.cast(warmup_steps, tf.float32))
return tf.cond(global_step < warmup_steps, lambda: warmup_lr, lambda: lr)
1
2
3
4
(ps:粘贴一段网上代码 tf 不知道哪个版本的代码)

可以看到 warmup_lr 的初始值是跟训练预料的大小成反比的,也就是说训练预料越大,那么warmup_lr 初值越小,随后增长到预设的超参 initial_learning_rate相同的量级,再接下来又通过 decay_rates 逐步下降。

这样做有什么好处?

1)这样可以使得学习率可以适应不同的训练集合size

实验的时候经常需要先使用小的数据集训练验证模型,然后换大的数据集做生成环境模型训练。

2)即使不幸学习率设置得很大,那么也能通过warmup机制看到合适的学习率区间(即训练误差先降后升的关键位置附近),以便后续验证。

Bert 采用哪种Normalization结构,LayerNorm和BatchNorm区别,LayerNorm结构有参数吗,参数的作用?

Bert采用LayerNormLayerNorm是对每个样本的所有位置的字进行归一化。BatchNorm是对同一个批次的所有样本同个位置的字进行归一化。选择LayerNorm是为了不破坏位置信息。
BN就是在每个维度上统计所有样本的值,计算均值和方差;LN就是在每个样本上统计所有维度的值,计算均值和方差(注意,这里都是指的简单的MLP情况,输入特征是(bsz,hidden_dim))。所以BN在每个维度上分布是稳定的,LN是每个样本的分布是稳定的。
注意,和Batch Normalization一样,同样会施以线性映射的。区别就是操作的维度不同而已!公式都是统一的:减去均值除以标准差,施以线性映射。同时LN也有BN的那些个好处!

为什么说ELMO是伪双向,BERT是真双向?产生这种差异的原因是什么?

BERT和Transformer Encoder的差异有哪些?做出这些差异化的目的是什么?

学习链接:https://zhuanlan.zhihu.com/p/360343071

首先,Transformer共6个block,Bert有12个block.
位置编码也不同,Transformers采用的正余弦函数,Bert采用的是可学习的位置编码。
主要是位置编码和输入参数的不同
以中文为例,「BERT 模型通过查询字向量表将文本中的每个字转换为一维向量,作为模型输入(还有 position embedding 和 segment embedding);模型输出则是输入各字对应的融合全文语义信息后的向量表示。」而对于输入的 token embedding、segment embedding、position embedding 都是随机生成的,需要注意的是在 Transformer 论文中的 position embedding 由 sin/cos 函数生成的固定的值,而在这里代码实现中是跟普通 word embedding 一样随机生成的,可以训练的。作者这里这样选择的原因可能是 BERT 训练的数据比 Transformer 那篇大很多,完全可以让模型自己去学习。

self-attention 的本质是什么?包括哪几个步骤?和普通 Attention 的差别在哪里?

自注意力机制(Self-Attention),也称为内部注意力,是一种允许模型在序列内部的不同位置间直接建立关系的机制。自注意力机制通过计算序列中每个元素对于其他元素注意力分数来工作,这允许模型在不同位置间直接捕捉到相关性。这种机制特别适合处理那些输入和输出之间关系复杂或者序列很长的任务。

步骤一:第一步根据 W q , W k , W v W_q,W_k,W_v Wq,Wk,Wv生成Q,K,V
步骤二:Q,K矩阵相乘除 d k \sqrt{d_k} dk ,经过softmax函数得到注意力关注矩阵,即每个字之间的重要程度。
步骤三:将关注度矩阵与V相乘得到加权后的结果。
和普通的Attention差别在,Self-Attention也称为内部注意力,解决的是序列内部不同位置的重要程度。
如果是普通的attention的话,Q来自于句A,K, V来自于句B.

不考虑多头的原因,self-attention中词向量不乘QKV参数矩阵,会有什么问题?

self-attention的核心是用文本中的其它词增强目标词的语义表示,从而更好的利用上下文的信息。
self-attention中,sequence中的每个词都会和sequence中的每个词做点积计算相似度,也包括这个词本身。
对于self-attention,一般会说它的q=k=v,这里的相等实际上是指它们来自同一个基础向量。但是在实际计算时,它们是不一样的。因为这三者都是乘了 W Q W_Q WQ, W K W_K WK, W V W_V WV 矩阵的。如果不乘,每个词对应的q,k,v就是完全一样的。那在softmax后的加权平均中,该词本身所占的比重将会是最大的,使得其他词的比重很少,无法有效利用上下文信息来增强当前词的语义表示。​而且softmax后的关注度矩阵是对称矩阵,没有体现位置相反重要程度可能不同的现象。
而乘以 W q W_q Wq, W k W_k Wk, W v W_v Wv 矩阵,会使得每个词的q,k,v都不一样,能很大程度上减轻上述的影响。
当然, W q W_q Wq, W k W_k Wk, W v W_v Wv 矩阵也使得多头(类似于CNN中的多核)去捕捉更丰富的特征信息成为可能。

在普通 attention 中,一般有 k=v,那 self-attention 可以嘛?

self-attention实际只是attention中的一种特殊情况,因此k=v是没有问题的,也即K,V参数矩阵相同。
扩展到Multi-Head Attention中,乘以QK参数矩阵之后,其实就已经保证了多头之间的差异性了,在q和k点积+softmax得到相似度之后,从常规attention的角度,觉得再去乘以和k相等的v会更合理一些。在Transformer/BERT中,完全独立的QKV参数矩阵,可以扩大模型的容量和表达能力。
但采用Q,K=V这样的参数模式,我认为也是没有问题的,也能减少模型的参数又不影响多头的实现
当然,上述想法并没有做过实验,为个人观点,仅供参考。

self-attention 在计算的过程中,如何对padding位做mask?

1、padding位一般是设置特殊的数字表示。
2、在scaled之后,softmax之前,通过atten_score.masked_fill指定padding位的用 − ∞ -\infty 替换。这样在softmax的时候,该位置的值就会变成0.说明该位置无实际意义,即在attention score矩阵中该位置的词对目标词没有什么关系。

bert的mask为何不学习transformer在attention处进行屏蔽score的技巧?

BERT训练过程中的损失函数是什么?

BERT模型的训练使用的是两个主要任务:Masked Language Model(MLM)和下一句预测(Next Sentence Prediction, NSP)。这两个任务的损失在训练时被同时优化。
Masked Language Model (MLM) 损失:
在MLM任务中,输入文本的一部分被随机地遮蔽(例如,被替换为特殊的"[MASK]"标记)。模型的目标是预测这些被遮蔽的单词。对于每个被遮蔽的位置,模型输出一个概率分布,表示每个可能的词汇在该位置的可能性。MLM损失使用交叉熵损失函数,将模型的预测与真实标签进行比较,计算损失。具体来说,对于每个被遮蔽的位置,用交叉熵损失计算预测分布和实际分布之间的差异。最小化这些差异是模型的目标。
Next Sentence Prediction (NSP) 损失:
NSP任务是为了让模型学会理解两个句子之间的关系。对于输入的一对句子,模型需要判断第二个句子是否是第一个句子的下一句。NSP损失使用二元交叉熵损失函数,将模型的预测(下一句或非下一句)与实际标签进行比较,计算损失。NSP损失的目标是帮助模型学会一些语言推理任务,例如理解句子之间的逻辑关系。
总的来说,在BERT的训练过程中,MLM损失和NSP损失被加权相加,然后通过反向传播和优化算法(通常是梯度下降法)来更新模型的参数,使得模型能够更好地捕捉文本中的语言表示和关系。

BERT 的两个任务 Masked LM 任务和 Next Sentence Prediction 任务是先后训练的还是交替训练的

Masked Language Model任务是BERT预训练的核心。在这个任务中,模型需要预测被掩盖(或掩码)的单词。具体来说,在输入的句子中,随机选择15%的单词进行掩盖,然后让模型去预测这些被掩盖的单词。这是一个多分类问题,因为模型需要从给定的选项中选择最可能的单词。这个任务的损失函数是基于预测的单词与实际单词之间的交叉熵损失。这个任务的目的是让模型学习上下文信息,理解句子中每个单词与上下文之间的关系。通过预测被掩盖的单词,BERT可以学习到句子中单词之间的依赖关系,从而更好地理解语言的内在结构。
Next Sentence Prediction是BERT预训练的另一个关键任务。在这个任务中,模型需要判断给定的两个句子是否为连续句子。具体来说,输入为一个句子对**[CLS]a[SEP]b[SEP],其中a和b是两个独立的句子。模型需要判断b是否是a的下一句。这是一个二分类问题,其损失函数也是基于交叉熵损失**。这个任务的目的是让模型学习句子间的关系,理解文本中的连贯性和逻辑性。通过判断两个句子是否为连续句子,BERT可以学习到句子间的语义关系,从而更好地理解文本的整体结构和意义。
在预训练过程中,BERT将MLM和NSP两个任务结合起来,同时进行训练。对于每个batch的数据,BERT首先随机遮盖一部分词,然后使用这些被遮盖的词进行MLM任务的训练。同时,它还会进行NSP任务的训练,以学习句子间的关系。在每个训练步骤中,BERT会计算两个任务的损失,并将它们相加以获得总损失。然后,模型会使用梯度下降等方法更新其参数,以最小化总损失。通过这种预训练方法,BERT能够学习到丰富的词表示和句子关系,这为其在各种NLP任务中取得优异表现奠定了基础。

RNN、CNN和Transformer的比较(复杂度,特点,适用范围etc)

CNN是一种基于卷积层的特征提取网络结构,主要用于图像处理领域。卷积层可以提取出图像中的空间特征,例如边缘、角点等。在卷积层后添加池化层可以进一步减小特征图的大小降低计算量。CNN还可以通过多层卷积层和全连接层组合,实现对复杂图像的分类和识别。

循环神经网络(Recurrent Neural Networks, RNNs)是一种用于处理序列数据神经网络,例如处理例如自然语言文本和时间序列数据等。其特点是循环层可以将前一个时间步的隐藏状态传递到下一个时间步,从而实现对序列数据的建模。RNN的模型结构可以有多种变体,RNN中的门控循环单元(GRU)和长短时记忆网络(LSTM)可以有效地解决梯度消失和梯度爆炸问题,提高训练效率和模型泛化能力。

Transformer是一种基于自注意力机制的特征提取网络结构,主要用于自然语言处理领域。自注意力机制可以对输入序列中的每个位置进行注意力计算,从而获取全局上下文信息。Transformer中的编码器和解码器可以实现机器翻译、文本生成等任务。

Transformer:

deepspeed框架介绍

学习链接:https://blog.csdn.net/myTomorrow_better/article/details/138945584

DeepSpeed是一个开源的深度学习优化库,它由微软开发并维护,旨在提高大规模模型训练的效率和可扩展性。通过创新的算法和技术,DeepSpeed能够降低训练超大规模模型的复杂性和资源需求,让深度学习训练变得更快、更高效。
DeepSpeed的核心就在于,GPU显存不够,CPU内存来凑。具体点说,DeepSpeed将当前时刻,训练模型用不到的参数,缓存到CPU中,等到要用到了,再从CPU挪到GPU。这里的“参数”,不仅指的是模型参数,还指optimizer、梯度等。
越多的参数挪到CPU上,GPU的负担就越小;但随之的代价就是,更为频繁的CPU,GPU交互,极大增加了训练推理的时间开销。因此,DeepSpeed使用的一个核心要义是,时间开销和显存占用的权衡。
DeepSpeed的主要特点和优势
1、高效的并行化策略:DeepSpeed支持多种并行化方法,包括数据并行、模型并行和流水线并行。这些方法可以灵活组合,以适应不同规模和复杂度的深度学习模型。通过并行化,DeepSpeed能够显著提高训练速度和可扩展性。
2、内存优化技术:为了降低内存占用提高训练效率,DeepSpeed引入了ZeRO(Zero Redundancy Optimizer)技术。ZeRO通过将优化器的状态、梯度和参数在分布式环境中进行分割,从而减少了冗余的内存占用。这使得在有限的内存资源下训练更大的模型成为可能。
3、混合精度训练支持:DeepSpeed 支持混合精度训练,即同时使用单精度和半精度浮点数进行训练。这种方法可以在保持模型性能的同时,减少内存占用和计算时间,降低能耗。
4、易用性和兼容性:DeepSpeed与PyTorch等主流深度学习框架紧密集成,提供了易用的API和丰富的文档支持。这使得用户能够轻松地将DeepSpeed集成到他们的项目中,并充分利用其提供的优化功能。此外,DeepSpeed还提供了高度优化的数据加载和网络通信工具,以减少通信量并提高多GPU和多节点环境下的训练效率。

用语言介绍一下Transformer的整体流程

1.输入嵌入 (input Embedding):将输入的文本序列转换为向量表示。通常使用词嵌入 (Word Embedding)技术,如Word2Vec或GloVe,将每个单词映射为一个固定长度的向量。
2.位置编码(positional Encoding):为了捕捉输入序列中单词的位置信息,Transformer引|入了位置编码。位置编码是一种特殊的向量,用于表示单词在序列中的位置关系。
3.自注意力机制(Self-Atention): Transformer的核心是自注意力机制。它通过计算每个单词与其他单词之间的相关性得分,来捕捉输入序列中的上下文信息。自注意力机制能够同时考虑所有单词之间的关系,而不仅仅是局部窗口。
4.编码器(Encoder): Transfommer由多个相同结构的编码器堆叠而成。每个编码器包含多个自注意力层和前馈神经网络层。自注意力层用于捕捉输入序列中的上下文信息,前馈神经网络层用于对每个位置的向量进行非线性变换。
5.解码器 (Decoder):在机器翻译等任务中,Transformer还包含一个解码器。解码器与编码器的结构类似,但在自注意力机制中加入了额外的注意力机制,用于对编码器输出进行加权求和。
6.输出层 (OutputLaver):最后一个解码器的输出经过一个线性变换和softmax函数,得到最终的预测结果。在机器翻译任务中,输出层通常是一个词汇表大小的向量,表示每个单词的概率分布。

分布式训练一共有哪些并行方式,请全部列举出

深度学习的三种并行方式:数据并行(DP),模型并行(MP),流水线并行(PP)

学习链接:https://www.cnblogs.com/rossiXYZ/p/15840803.html#13-%E6%A8%A1%E5%9E%8B%E5%B9%B6%E8%A1%8C
https://blog.csdn.net/sinat_37574187/article/details/140247471#:~:text=%E6%B5%81%E6%B0%B4%E7%BA%BF%E5%B9%B6%E8%A1%8C:%20%E5%B0%86%E6%A8%A1%E5%9E%8B
https://blog.csdn.net/Neleuska/article/details/136645597

如今的大模型训练,离不开各种分布式的训练框架,一般来说,并行策略包含:数据并行模型并行流水线并行
数据并行
数据集分成多个子集,每个子集分配给不同的计算节点(GPU),每个节点上都有完整的模型副本,分别基于每个GPU中的数据去进行梯度求导。然后,AllReduce每个GPU中的梯度进行累加,最后,AllReduce再将聚合后的结果广播其他GPU节点
数据并行分为了两种模式:Data Parallel(DP)和 Distributed Data Parallel(DDP)。
DP是一种单进程多线程的并行策略,只能在单机上进行训练,步骤如下:

1、首先将模型加载到主 GPU 上,再复制到各个指定从 GPU;
2、将输入数据按照 Batch 维度进行拆分,各个 GPU 独立进行 forward 计算;
3、将结果同步给主 GPU 完成梯度计算和参数更新,将更新后的参数复制到各个 GPU。
4、由于其是单进程控制多个GPU,故会存在GPU之间负载不均衡的问题,主GPU负载较大。

DDP采用 AllReduce 架构,多进程的方式,突破锁的束缚。在单机和多机上都可以使用。
负载分散在每个 GPU 节点上,通信成本(时间)是恒定的,与 GPU 数量无关,等于V/B(参数量/带宽)。
DDP不需要通过主GPU分发全模型的参数到每个GPU上。
使用ring-all-reduce的方式进行通讯,随着 GPU 数量 N 增加,总传输量恒定。也就是理论上,随着GPU数量的增加,ring all-reduce有线性加速能力。

模型并行
将模型切分到不同的GPU上,将模型的层或模型的参数分到不同的GPU上,每一个GPU上的参数量大大减小,这样可以容纳更大的模型进行训练。但是需要频繁的设备间通信来传递中间结果。
模型并行分为两种:流水线并行和张量并行,就是把模型切分的方式。
流水线并行(pipeline model paralel)是把模型不同的层放到不同设备之上,比如前面几层放到一个设备之上,中间几层放到另外一个设备上,最后几层放到第三个设备之上。
在这里插入图片描述

张量并行则是层内分割,把某一个层做切分,放置到不同设备之上,也可以理解为把矩阵运算分配到不同的设备之上,比如把某个矩阵乘法切分成为多个炬阵乘法放到不同设备之上。
具体如下图,上面是层间并行(流水线并行),纵向切一刀,前面三层给第一个GPU,后面三层给第二个GPU,下面是层内并行(tens!并行),横向切一刀,每个张量分成两块分到不同GPU之上。
在这里插入图片描述
在这里插入图片描述

Deepspeed分布式训练的了解,zero 0-3的了解。

ZeRO学习链接:https://blog.csdn.net/qq_38563206/article/details/133792668

在数据并行、张量并行、流水线并行三种并行方式中,数据并行因其易用性,得到了最为广泛的应用。然而,数据并行会产生大量冗余 Model States 的空间占用。ZeRO 的本质,是在数据并行的基础上,对冗余空间占用进行深度优化
我们介绍了大规模训练中的显存占用可以分为 Model StatesActivation 两部分,而 ZeRO 就是为了解决 Model States 而诞生的一项技术。
Model States 是由什么组成的:1. Optimizer States: Optimizer States 是 Optimizer 在进行梯度更新时所需要用到的数据,例如 SGD 中的Momentum以及使用混合精度训练时的Float32 Master Parameters。2. Gradient:在反向传播后所产生的梯度信息,其决定了参数的更新方向。3. Model Parameter: 模型参数,也就是我们在整个过程中通过数据“学习”的信息。
在传统数据并行下,每个GPU都使用同样参数来进行训练。每个GPU也会持有对Optimizer States的完整拷贝,同样占用了大量显存。在混合精度场景下,以参数量为Ψ的模型和Adam optimzier为例,Adam需要保存:- Float16的参数和梯度的备份。这两项分别消耗了2Ψ和2Ψ Bytes内存;(1 Float16 = 2 Bytes) - Float32的参数,Momentum,Variance备份,对应到 3 份4Ψ的内存占用。(1 Float32 = 4 Bytes)
最终需要2Ψ + 2Ψ + KΨ = 16Ψ bytes的显存。一个7.5B参数量的模型,就需要至少 120 GB 的显存空间才能装下这些Model States。当数据并行时,这些重复的Model States会在N个GPU上复制N份[1]。
ZeRO 则在数据并行的基础上,引入了对冗余Model States的优化。使用 ZeRO 后,各个GPU之后只保存完整状态的1/GPUs,互不重叠,不再存在冗余。在本文中,我们就以这个 7.5B 参数量的模型为例,量化各个级别的 ZeRO 对于内存的优化表现。
在这里插入图片描述

深度学习中常用的优化器有哪些?

学习链接:https://blog.csdn.net/qq_42109740/article/details/105401197

梯度下降变形形式:
1、批量归一化(BGD):每次经过完整一轮训练后更新一次参数,这使得梯度下降过程变得比较慢,并且需要很大内存保存中间结果。
2、随机梯度下降(SGD):随机梯度下降是对每个训练样本就更新一次网络参数,这样使得网络更新参数速度很快,但是问题就是由于训练数据多样,容易朝偏离网络最优点方向训练,网络训练不稳定。
3、小批量梯度下降(MBGD):小批量梯度下降是批量梯度下降与随机梯度下降之间的一个折中,即经过一个小批量的训练数据更新一次参数,可以保证网络训练速度不太慢,也能使训练方向不至于偏离太多,具有一定稳定性。当使用小批量梯度下降时,通常也使用SGD这个术语。

SimCSE的了解

经典的词向量模型有哪些?

Word2Vec glove ELMo Bert
Word2Vec:它的核心思想是通过词的上下文得到词的向量化表示,有两种方法:CBOW(通过附近词预测中心词)、Skip-gram(通过中心词预测附近的词);
在这里插入图片描述

产生梯度消失问题的原因有哪些?

首先解释一下什么是梯度消失和梯度爆炸,
梯度消失:梯度趋近于零,网络权重无法更新或更新的很微小,网络训练再久也不会有效果;
梯度爆炸:梯度呈指数级增长,变的非常大,然后导致网络权重的大幅更新,使网络变得不稳定。
其实不管是梯度消失还是梯度爆炸本质上都是由于——深度神经网络的反向传播造成的
可以通过两个角度去解释:一是在深层网络中,二是采用的激活函数导致的。即隐藏层的层数过多,采用了不合适的激活函数(更容易产生梯度消失,但是也有可能产生梯度爆炸)

Recall、Precision、F1-Score

TP(True Positive):实际是正例,预测的也是正例,所以TP。先看是T还是F,判断是否预测正确,后看是P还是N,这个表示是预测的结果,TP表示前面是T表明预测正例是正确,说明原来就是正例。如果前面是F,说明预测正例是错误的,因为原来是负例。
TN(True Negativate):实际是负例,预测的也是负例。
FP:实际是负例,预测的是正例。
FN:实际是正例,预测的是负例。
准确率(Accuracy)表示分类正确的样本占总样本个数的比例。总样本个数即为TP, FP, TN, FN之和。
故计算公式如下: T P T P + F P + T N + F N \frac{TP}{TP+FP+TN+FN} TP+FP+TN+FNTP
召回率(Recall)又被称为查全率,表示预测与实际的一样都是正样本
实际正样本
的比率。
Recall: T P T P + F N \frac{TP}{TP+FN} TP+FNTP
召回率:表示预测正确的正例/实际是正样本。命名实体识别任务中也就是,recall:正确被识别出的实体数目/实际实体数目
精确率 (Precision):表示预测与实际的一样都是正样本预测结果为正样本的比率。
Precision: T P T P + F P \frac{TP}{TP+FP} TP+FPTP
TP:正确被识别的实体数目;
FN:原本是实体,却没被预测出来,即没有被识别出来的实体数目
FP:原本是非实体,却被预测为实体,即没有被正确识别出的非实体数目。
F1-Score:F1 score是精确率和召回率的一个加权平均。
F1 score的计算公式如下: 2 ∗ p ∗ r p + r \frac{2*p*r}{p+r} p+r2pr
Precision体现了模型对负样本的区分能力,Precision越高,模型对负样本的区分能力越强;Recall体现了模型对正样本的识别能力,Recall越高,模型对正样本的识别能力越强。F1 score是两者的综合,F1 score越高,说明模型越稳健。

Dropout 有什么作用?类似于 Bagging 。在 Transformer 模型中 dropout 主要用在哪里?dropout 在每个子层之间,设置为 0.1。看过源码吗?看过源码,看的哈佛实现的那一版本。(面试官应该也看过这个版本,说写的很好)

学习链接:https://blog.csdn.net/qq_42346574/article/details/119895908
https://blog.csdn.net/Magical_Bubble/article/details/89083225
https://blog.csdn.net/Magical_Bubble/article/details/89083225(Transformer源码)

dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。dropout是CNN中防止过拟合提高效果的一个大杀器。在Transformorers模型中,dropout用在各个子层之间。 P d r o p = 0.1 P_{drop}=0.1 Pdrop=0.1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Dropout训练和测试的区别,Dropout的原理

Dropout原理:dropout训练减少了神经网络结点之间的共适应性,当隐藏层节点被随机删除后,是的网络具有了一定的稀疏性,从而有效的减轻了不同特征间的协同效应。也就是说,某些特征可能会依赖于固定关系的隐藏节点的共同作用,而通过dropout,迫使一个网络节点和随机挑选出来的其他节点共同工作,达到更好的网络泛化能力。
Dropout训练和测试的区别:训练时以一定的概率p(通常是50%)关闭隐藏层神经元的输出,也就是输出为0。这种策略可以从不同角度理解:首先这使得每次训练的模型并不是相同的结构,可以认为是原网络的子集,最终的输出是这些不同模型不同结构共同作用的结果(类似于集成学习中Bagging的策略);另外Dropout方法可以让神经元之间减小依赖性,因为随机的关闭可以使得神经元之间不会总是同时作用。
测试时,全部神经元都使用,但是他们的输出乘上了系数(1-p)。

RNN

简单说一下什么是RNN?

链接:https://blog.csdn.net/jump882/article/details/123717798#:~:text=%E9%98%90%E8%BF%B0%E4%BA%86RNN%E5%AD%98%E5%9C%A8%E7%9A%84%E6%A2%AF

RNN也叫循环神经网络,RNN的核心思想是使用循环,使得网络能够将信息从一个步骤传递到下一个步骤。这种循环结构使得网络能够保留某种状态,即网络在处理当前输入时,同时考虑之前的输入。在RNN中,每个序列元素都会更新网络的隐藏状态。这个隐藏状态是网络记忆之前信息的关键,它可以被视为网络的“记忆”。
在这里插入图片描述

RNN为什么会存在梯度消失的问题?

学习链接:https://blog.csdn.net/zhaojc1995/article/details/114649486#:~:text=LSTM%E7%BC%93%E8%A7%A3%E6%A2%AF%E5%BA%A6%E6%B6%88%E5%A4%B1

目前优化神经网络的方法都是基于反向传播的思想,即根据损失函数计算的误差通过梯度反向传播的方式,指导深度网络权值的更新优化。在神经网络中,根据链式法则,如果每一层神经元对上一层的输出的偏导乘上权重结果都小于1的话,那么即使这个结果是0.99,在经过足够多层传播之后,误差对输入层的偏导会趋于0。同理,如果每一层神经元对上一层的输出的偏导乘上权重结果都大于1的话,在经过足够多层传播之后,误差对输入层的偏导会趋于无穷大。

RNN有哪些问题(梯度消失、梯度爆炸),如何缓解(使用LSTM结构,引入门控机制);

学习链接:https://blog.csdn.net/qq_24178985/article/details/118381013
https://blog.csdn.net/jump882/article/details/123717798(RNN为什么会梯度消失,解释的很详细)
https://blog.csdn.net/zhaojc1995/article/details/114649486#:~:text=LSTM%E7%BC%93%E8%A7%A3%E6%A2%AF%E5%BA%A6%E6%B6%88%E5%A4%B1

RNN:梯度消失、梯度爆炸
缓解:使用LSTM引入门结构。遗忘门,输入门,输出门
在这里插入图片描述

遗忘门根据当前节点的输入和上一个节点的输出决定丢弃细胞状态中哪些信息。 f t = s i g m o d ( w f [ h t − 1 , x t ] ) + b f , f_t=sigmod(w_f[h_{t-1},x_t])+b_f, ft=sigmod(wf[ht1,xt])+bf输出 f t f_t ft 是一个与细胞 C t − 1 C_{t-1} Ct1大小相同且每个元素均在0到1之间的向量, f t f_t ft C t − 1 C_{t-1} Ct1对位点乘,丢弃 C t − 1 C_{t-1} Ct1中不重要的信息。
在这里插入图片描述

输入门根据当前节点的输入和上一个节点的输出决定哪些信息加入细胞状态中。 i t = s i g m o d ( w i [ h t − 1 , x t ] ) + b i i_t=sigmod(w_i[h_{t-1},x_t])+b_i it=sigmod(wi[ht1,xt])+bi C t ′ = t a n h ( w c [ h t − 1 , x t ] ) + b c C'_t=tanh(w_c[h_{t-1},x_t])+b_c Ct=tanh(wc[ht1,xt])+bc之后将 i t i_t it C t ′ C'_t Ct按位相乘,之后将乘积新矩阵与 C t − 1 C_{t-1} Ct1相加,得到该节点的细胞状态 C t C_t Ct
在这里插入图片描述
输出门:输出门决定输入下一节点的h_t, o t = s i g m o d ( w t [ h t − 1 , x t ] ) + b o o_t=sigmod(w_t[h_{t-1},x_t])+b_o ot=sigmod(wt[ht1,xt])+bo,之后将o_t与 t a n h ( C t ) tanh(C_t) tanh(Ct)按位相乘得到 h t h_t ht
在这里插入图片描述

说一下RNN、LSTM、GRU它们是联系?

RNN(循环神经网络): RNN是一种经典的循环结构神经网络。它的主要特点是将前一个时间步的输出作为当前时间步的输入,从而在处理序列数据时引入了时间上的依赖关系。然而,传统的RNN存在梯度消失或梯度爆炸的问题,导致长期依赖关系难以捕捉。

LSTM(长短期记忆网络): LSTM是为了解决传统RNN中的梯度问题而提出的改进型网络。它引入了门控机制,通过遗忘门、输入门和输出门来控制信息的流动,从而有效地捕捉长期依赖关系。LSTM能够在序列数据中保留长期的记忆,适用于处理较长的文本序列和时间序列。

GRU(门控循环单元): GRU是对LSTM的另一种改进型循环神经网络。它简化了LSTM的结构,仅使用了更新门和重置门,使得模型参数较少,计算复杂度较低。GRU在解决长期依赖问题的同时,也表现出较好的性能。

为什么LSTM模型中既存在sigmoid又存在tanh两种激活函数,而不是选择统一一种sigmoid或者tanh?这样做的目的是什么?

sigmoid函数被用作各个门上,产生0~1之间的值,来判断是对信息进行记住还是遗忘。tanh用在了状态和输出上,是对数据的处理,可以替换成其他激活函数。

GRU和LSTM的区别?

GRU和LSTM都是用于解决长期依赖问题的改进型循环神经网络(RNN)结构。它们在解决长期依赖问题上有相似之处,但也有一些不同点。以下是它们之间的主要区别:
门控结构不同:
LSTM具有三个门控:输入门(Input Gate)、遗忘门(Forget Gate)和输出门(Output Gate)。这三个门控通过sigmoid激活函数来控制信息的流动和细胞状态的更新。
GRU具有两个门控:重置门(Reset Gate)和更新门(Update Gate)。重置门决定了过去信息在当前时间步的输入中有多少保留,而更新门决定了过去和当前信息在当前时间步的更新中所占的比例。
参数数量不同:
GRU的参数较少,因为它合并了LSTM的细胞状态和隐藏状态,并减少了一个门控。这使得GRU在计算上相对更轻量级。
LSTM的参数较多,因为它有三个门控,每个门控都有自己的权重和偏置。
细胞状态更新不同:
LSTM的细胞状态由遗忘门、输入门和输出门三个门控决定,分别控制了细胞状态的遗忘、增益和输出。
GRU的细胞状态由重置门和更新门两个门控决定,重置门控制了过去信息的保留,更新门控制了过去和当前信息的更新。
计算效率不同:
由于参数较少,GRU的计算效率通常高于LSTM,特别是在较大规模的模型或者大规模数据上。
表现情况不同:
在一些任务上,LSTM和GRU的表现可能会有所不同。在某些序列建模任务中,LSTM可能更适合处理长期依赖问题,而在另一些任务中,GRU可能表现得更好。
总的来说,LSTM和GRU都是强大的RNN变种,用于处理序列数据和解决长期依赖问题。

RNN input具体计算

在这里插入图片描述

为什么LSTM一定程度上解决RNN问题

链接:https://blog.csdn.net/zhaojc1995/article/details/114649486#:~:text=LSTM%E7%BC%93%E8%A7%A3%E6%A2%AF%E5%BA%A6%E6%B6%88%E5%A4%B1

CNN、RNN、LSTM和Transformer各自的优点

CNN优点:局部权值共享,平移不变性可以更好提取特征以及处理高维数据;**缺点:**网络过深时其梯度回传变化相对于输入往往很小,出现梯度消失或爆炸的情况;解释性一般
RNN优点:相比于CNN,RNN结合序列上的时序上下文来提取特征,但是在处理序列数据时没有进行信息的过滤,在稍长序列中就会出现梯度消失、爆炸的情况
LSTM优点:LSTM经过使用全连接层设计遗忘门、输出门、输入门来过滤信息,使得在长序列数据中表现较好。但是在时间跨度非常大的序列数据中,会出现计算复杂和耗时偏多的问题 **Transformer优点:**相比于RNN,可以直接并行计算序列数据,计算的Attention也更有解释性,可以为不同的头分配不同的任务。虽然全局信息可以捕捉,但是不如CNN捕捉局部信息来的好,而且其位置编码的语义问题也很困扰,最后在Transformer内部堆叠残差层和BN层过多时,顶部会出现梯度消失的问题

Pytorch

pytorch如何使用多gpu。

1、
可见设置,环境变量使得指定设备对CUDA应用可见
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
//选择第一块显卡开始载入数据
device = torch.device("cuda: 0")
model.to(device)
//显卡大于1块时,device_ids选择模型载入数据对应的显卡
if torch.cuda.device_count() > 1:
	model= nn.DataParallel(model,device_ids=[0,1])
2、使用accelerate库,加载模型的时候设置device_map="auto"

Linux

Linux查看各类资源的命令,通常看哪些字段

Linux启动需要经过什么过程

GPT

Roberta

RoFormer

大模型问题

大模型推理加速的方法

大模型训练的超参数设置

LoRA的作用和原理

CoT的作用

大模型思维链 (CoT):
神经网络经典的激活函数以及它们的优缺点
softmax函数求导的推导
BERT的参数量如何计算?
AUC和ROC

prompt tuning, instruct tuning, fine tuning差别

说说大模型生成采样的几种方式,它们的特点和优缺点比较

llama中per norm,rmsnorm的介绍,优劣,position embedding构造方法

prompt构造经验,怎样的prompt更好

lora介绍,了解什么其他高效微调方法

LLaMA 2的创新/ChatGLM的创新点/Qwen的创新点/Baichuan的创新点

LLM的评估方式有哪些?特点是什么?(中文的呢?)

文本生成模型中生成参数的作用(temperature,top p, top k,num beams)

temperature:控制生成结果的随机性,temperature越偏向于0,结果就越死板,没有创新性;越偏向于1,最终生成的结果就越新颖
top_k:根据K值挑选生成结果,选取前k个作为结果。
top_p:给定一个概率值,挑选和>=top_p的值作为结果
num_beams:

InstructGPT三个阶段的训练过程,用语言描述出来(过程,损失函数)

大模型的幻觉问题

大模型训练数据处理

RLHF的计算细节

RoPE和ALiBi

询问对生成模型的了解,发展情况,询问项目中的难点,回答解码策略,谈到了 Beam Search 和 Random Sample 策略。

Python问题

贪心(greedy algorithm,GA)和 DP (动态规划)(dynamic programming,DP)区别?

相同点:DP和GA都利用了历史信息进行求解。但是二者利用历史信息的方式有所区别。
不同点:
GA:贪心算法的每一步最优解都包含上一步的最优解,通过上一步的结果和当前的信息进行求解。也就是其利用的历史信息只有上一步的最优解。上一步之前的解则不做保留。从树的角度理解,GA从根节点出发,向下遍历最优子树,这样的话,只按照一条路径向下寻找,所以无法构成完整的遍历树。时间复杂度低。
DP:由于重叠子问题和最优子结构的形式,DP可以利用所有的局部最优解信息进行求解,不一定包含上一步的最优解。所以DP要纪录所有的局部最优解,也就是纪录所有的子问题最优解。从树的角度来讲,DP子底向上构建树,从叶子节点开始,每个节点都是一个局部最优解,直到最后的解利用树的所有信息构成,组成一颗完成的树。时间复杂度高。

GA 的一般做法流程?

贪心算法一般按如下步骤进行:
①建立数学模型来描述问题。
②把求解的问题分成若干个子问题。
③对每个子问题求解,得到子问题的局部最优解。
④把子问题的解局部最优解合成原来解问题的一个解。
经典算法中的贪心:哈夫曼编码,单源路径中的Djikstra算法,最小生成树Prim算法

DP 的一般做法流程?

1.分析最优子结构性质(递推关系)
2.递归定义最优值(动态规划核心)
3.自底向上的方式计算出最优值(动态规划的执行过程)
4.根据计算最优值时得到的信息,构造最优解

一个文件的大小超过了主存容量,如何对这个文件进行排序?应该使用什么算法?

Python中的线程、进程和协程

**进程:**指在系统中正在运行的一个应用程序;程序一旦运行就是进程;或者更专业化来说:进程是指程序执行时的一个实例,从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
**线程:**系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。进程——资源分配的最小单位,线程——程序执行的最小单位。
**协程(coroutine)**是一种程序运行的方式,即在单线程里多个函数并发地执行。有了协程,我们在函数的执行过程中,如果遇到了I/O密集型任务,函数可以临时让出控制权,让 CPU 执行其他函数,等 I/O 操作执行完毕以后再收回其他函数的控制权.

python中的生成器和迭代器

迭代器:迭代器是一个可以记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。迭代器有两个基本的方法:iter() 和 next()。字符串,列表或元组对象都可用于创建迭代器。

>>> list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")
#输出结果:1 2 3 4
import sys         # 引入 sys 模块
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()
#输出结果:
1
2
3
4

在 Python 中,使用了 yield 的函数被称为生成器(generator)。yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。当在生成器函数中**使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。**然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。调用一个生成器函数,返回的是一个迭代器对象。

def countdown(n):
    while n > 0:
        yield n
        n -= 1
#创建生成器对象
generator = countdown(5)
#通过迭代生成器获取值
print(next(generator))  # 输出: 5
print(next(generator))  # 输出: 4
print(next(generator))  # 输出: 3
#使用 for 循环迭代生成器
for value in generator:
    print(value)  # 输出: 2 1

Python、C++、Java 哪个用的多一点?值传递和引用传递区别。

值传递是指在调用方式时,将实参的值拷贝一份给形参,对形参的修改不影响实参。引用传递也叫地址传递,指在调用方法时将实参的地址传递给形参,对形参的修改将影响实参的值,即传递的是实参的内存地址。

Python 垃圾回收了解吗?

进程和线程区别

1、进程资源分配的最小单位线程是程序执行的最小单位(资源调度的最小单位
2、进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
3、线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
4、但是多进程程序更健壮多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

Linux 多个进程如何通信的?socket 和管道

开放问题,海量商家和海量语料,语料不平衡,语料对商家 group by 后按照时间排序,怎么解决。先扯了下哈希分桶,不平衡用归并排序。

算法题:最长公共子串

机器学习问题

损失函数和目标函数的区别与联系

损失函数(Loss Function)用于评估预测结果与真实值之间的差异。通常用于有监督学习中,值越小,表示模型的预测结果越接近真实值。
目标函数(Objective Function)是在优化模型的过程中所要最小化或最大化的函数。通常情况下,目标函数就是损失函数,因为我们的目标是最小化模型的预测误差。但是,在某些情况下,目标函数可能不仅仅是损失函数。例如,当我们在训练带有正则化的模型时,目标函数可能包括两部分:损失函数和正则化项。在这种情况下,我们的目标是同时最小化损失函数和正则化项的值。
总之,损失函数和目标函数是机器学习和深度学习中非常重要的概念,
它们帮助我们评估和优化模型的性能,提高预测的准确度。

介绍一下LR回归、XGBoost、GBDT,以及他们的优缺点;

LR回归(逻辑回归):解决分类问题的算法。通过使用sigmoid函数实现将输入的线性组合映射到[0,1]之间的概率值,用于预测二分类问题 1 1 + e − x \frac{1}{1+e^{-x}} 1+ex1,LR回归的损失函数:,优点:对线性关系的拟合效果特别好,计算速度快。缺点:对于非线性特征的处理能力有限、容易欠拟合。
优点:
(1)训练速度较快,分类的时候,计算量仅仅只和特征的数目相关;
(2)简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;
(3)适合二分类问题,不需要缩放输入特征;
(4)内存资源占用小,因为只需要存储各个维度的特征值;
缺点:
(1)不能用Logistic回归去解决非线性问题,因为Logistic的决策面试线性的;
(2)对多重共线性数据较为敏感;
(3)很难处理数据不平衡的问题;
(4)准确率并不是很高,因为形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布;
(5)逻辑回归本身无法筛选特征,有时会用gbdt来筛选特征,然后再上逻辑回归
GBDT:是基于boosting融合思想,
XGBoost:

传统机器学习会哪些?决策树和 GBDT、Adaboost 区别说下。

决策树决策树是一种机器学习的方法,就是将决策规则指定成树,根据属性特征分裂,分支代表做出的决策,叶子节点代表一种分类结果。
GBDT是基于boosting融合思想的算法,经历多个迭代,每一轮都更关注上一轮错判的样例,增加错误判别样例的权重.
Adaboost优缺点:优点,很好的利用了弱分类器进行级联。可以将不同的分类算法作为弱分类器。AdaBoost具有很高的精度,不容易过拟合。
相对于bagging/Random Forest算法,AdaBoost充分考虑的每个分类器的权重。缺点,AdaBoost迭代次数也就是弱分类器数目不太好设定。训练比较长,预测效果依赖于弱分类器的选择(Adaboost只是一个算法框架)

激活函数的作用,你知道的都有哪些激活函数?

原文链接:去看原链接,写的非常好https://blog.csdn.net/weixin_44115575/article/details/139835864

激活函数的作用:激活函数人工神经网络中一个关键的组成部分,它被设计用来引入非线性特性到神经网络模型中。在神经网络的基本结构中,每个神经元接收输入信号,对其进行加权求和后加上偏置项,然后将这个结果通过激活函数进行转换,得到神经元的输出。如果没有激活函数,无论神经网络有多少层,其输出都将仅仅是一个线性组合,这样的模型表达能力非常有限,无法解决复杂的非线性问题。
**激活函数的作用可以总结为以下几点:**1、引入非线性特征;2、控制神经元输出范围;3、缓解梯度消失/爆炸问题;
常见的激活函数:
s i g m o d : 1 1 + e − x sigmod:\frac{1}{1+e^{-x}} sigmod:1+ex1 输出结果:0~1
t a n h : e x − e − x e x + e − x = 2 s i g m o d ( 2 x ) − 1 tanh:\frac{e^x-e^{-x}}{e^x+e^{-x}}=2sigmod(2x)-1 tanh:ex+exexex=2sigmod(2x)1 输出结果:-1~1
R e l u : f ( x ) = m a x ( 0 , x ) Relu:f(x)=max(0,x) Reluf(x)=max(0,x)
L e a k y R e l u : f ( x ) = m a x ( α x , x ) Leaky Relu:f(x)=max(\alpha x,x) LeakyRelu:f(x)=max(αx,x)
S o f t m a x : y i = e z i ∑ t = 1 m e z t Softmax:y_i=\frac{e^{z_i}}{\sum^{m}_{t=1}{e^{z_t}}} Softmax:yi=t=1meztezi

Sigmoid 和 ReLU 区别,ReLU 解决了什么问题。

sigmod和relu都是激活函数Sigmoid函数将输入值映射到0到1之间的连续输出,适用于二分类问题或者用于表示置信度。。而Relu函数则将输入值映射到大于0的输出,适用于多分类和回归问题
在这里插入图片描述
sigmod的优点:输出范围明确。Sigmoid函数的输出范围在0到1之间,非常适合作为模型的输出函数。用于输出一个0到1范围内的概率值,表示二分类的类别或者用于表示置信度。便于求导:梯度平滑,便于求导,防止模型训练过程中出现突变的梯度。
在这里插入图片描述

缺点:sigmod的导数范围是0~0.25,梯度相乘容易为0,导致梯度消失。而且sigmod函数输出是0-1范围的,中心值是0.5,输出总是正值,可能会导致权重更新更偏向于某一边。sigmod的计算基于指数计算,计算耗时过大。

而Relu的函数保证当值为负数时输出0,正数时输出x.当输入值为正数时解决了梯度消失问题,计算复杂度降低。但是它也不是以0为中心输出的,可能会导致权重更新更偏向于某一方。
在这里插入图片描述

CNN 模型中池化层的作用,Max Pooling 是如何反向传递梯度的。

学习链接:
什么是卷积和池化?https://developer.volcengine.com/articles/7392417164059213863
池化的反向传播:https://blog.csdn.net/Jason_yyz/article/details/80003271

CNN模型:卷积和池化。卷积层提取图像的空间特征,通过卷积核在输入数据上滑动计算加权和池化用于特征降维 ,通过聚合统计池化窗口内的元素来减少数据空间大小 。
卷积是一种数学运算,在CNN中,它通过滑动窗口(也称为卷积核或滤波器)在输入图像或特征图上滑动,并计算窗口内元素与对应卷积核元素的加权和(包括偏置项),从而生成输出特征图。池化是卷积神经网络中的一种下采样操作。它通过定义一个空间邻域(通常为矩形区域),并对该邻域内的特征进行统计处理(如取最大值、平均值等),从而生成新的特征图。 池化操作通常紧随卷积层之后。
在这里插入图片描述
Maxpoolong是选择池化窗口内最大的元素作为池化结果输出。
Average Pooling是计算池化窗口内的平均值作为池化结果输出。
Pooling池化操作的反向梯度传播:需要保证传递的loss(或者梯度)总和不变
在这里插入图片描述
在这里插入图片描述

机器学习中正则化做什么的?正则化有 L1 和 L2 正则化,区别是什么?

学习链接:https://blog.csdn.net/a910247/article/details/137604232

正则化通过在模型的损失函数引入额外的惩罚项,来对模型的参数进行约束,从而降低模型的复杂度。这个额外的惩罚通常与模型参数的大小或者数量相关,旨在鼓励模型学习简单的规律,而不是过度拟合训练数据。
约束模型参数,防止过拟合。有L1和L2正则化,L1正则化使用Lasso算法(套索回归),L2使用Ridge算法(岭回归)。L1 正则会使很多参数为0,得到的参数矩阵是稀疏矩阵,可以用于特征选择,一定程度上L1正则也可以防止模型过拟合。
L2正则主要用来防止模型过拟合,直观上理解就是L2正则化是对于大数值的权重向量进行严厉惩罚。

贝叶斯学派和概率学派的区别

ROPE 原理

Docker

对docker的了解

docker与虚拟机的区别

学习链接:https://developer.aliyun.com/article/1489277

VMware是属于完全虚拟机化,而docker则是轻量级虚拟化(只虚拟出来容器所需要的资源)
虚拟机是一种完全虚拟化技术,它在物理硬件上运行一个完整的操作系统(称为宿主操作系统),并在该操作系统上运行一个或多个客户操作系统(称为虚拟机实例)。每个虚拟机实例都有自己的内核、用户空间和系统资源,因此它们能够完全独立地运行应用程序。虚拟机提供了更高的隔离性安全性,但是启动和运行虚拟机实例需要较多的系统资源(如内存、CPU等)。
Docker容器是一种轻量级虚拟化技术,它利用操作系统的容器化功能,在宿主操作系统上创建一个隔离运行环境容器共享宿主操作系统的内核,但是每个容器都有自己的文件系统、网络空间和进程空间,因此它们能够提供较高的性能和资源利用率。与虚拟机相比,容器更加轻量级,启动和运行速度更快,但是隔离性相对较弱。

docker是怎样实现资源隔离和资源限制的

学习链接:https://blog.csdn.net/qq_39241682/article/details/142033943#:~:text=%E5%9C%A8%E5%AE%B9%E5%99%A8%E6%8A%80%E6%9C%AF%E4%B8%AD%EF%BC%8C%E8%B5%84%E6%BA%90%E9%9A%94

Docker作为主流的容器平台,其核心的资源隔离机制依赖于Linux的namespace。Docker在启动容器时,会为每个容器创建一套独立的namespace,确保容器内的资源与宿主机及其他容器隔离。Docker通过调用Linux内核中的系统调用 unshare() 和 clone(),创建并分配这些namespace。在这两个系统调用的帮助下,每个容器内的进程、网络、文件系统等资源视图都是隔离的。

docker如何实现相互通信

1、使用Docker网络

1、创建网络
docker network create pangda
2、查看网络
docker network ls
3、启动容器一并将其加入该网络中
docker run -di --name 容器名1 --network pangda 镜像名1
4、启动容器二并将其加入该网络中
docker run -di --name 容器名2 --network pangda 镜像名2
5、实现通信
docker exec -it 容器名1 ping 容器名2

2、使用Docker Compose

#在这个示例中,web容器和app容器通过Docker Compose链接在一起。
version: '3'
services:
  web:
    image: nginx
  app:
    image: myapp
    links:
      - web

docker file了解吗

了解。Dockerfile是用于构建 Docker 容器镜像文本文件,它包含了一系列 指令和配置 ,用于描述 如何组装 一个Docker容器的环境通过Dockerfile,你可以自动化地构建镜像,确保在不同的环境中都可以复现相同的容器。Dockerfile中的指令可以指定从哪个基础镜像开始构建、复制文件到镜像中、安装软件包、设置环境变量、暴露端口、运行命令等等。每个指令都会在镜像的构建过程中创建一个新的镜像层,这些层构成了最终镜像的结构。这种分层结构让镜像的构建更加高效,同时也方便了镜像的复用和共享。以下是一个简单的Dockerfile示例:

# 使用官方的 Python 3 基础镜像
FROM python:3
# 将当前目录下的文件复制到镜像中的 /app 目录
COPY . /app
# 设置工作目录
WORKDIR /app
# 安装依赖包
RUN pip install -r requirements.txt
# 暴露容器监听的端口
EXPOSE 80
# 定义容器启动时运行的命令
CMD ["python", "app.py"]

Dockerfile指令详解

Dockerfile指令说明
FROM指定基础镜像,用于后续的指令构建。
MAINTAINER指定Dockerfile的作者/维护者。
LABEL添加镜像的元数据,使用键值对的形式。
RUN在构建过程中在镜像中执行命令。
CMD指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT设置容器创建时的主要命令。(不可被覆盖)
EXPOSE声明容器运行时监听的特定网络端口。
ENV在容器内部设置环境变量。
ADD将文件、目录或远程URL复制到镜像中。
COPY将文件或目录复制到镜像中。
VOLUME为容器创建挂载点或声明卷。
WORKDIR设置后续指令的工作目录。
USER指定后续指令的用户上下文。
ARG定义在构建过程中传递给构建器的变量,可使用 “docker build” 命令设置。
ONBUILD当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL设置发送给容器以退出的系统调用信号。
HEALTHCHECK定义周期性检查容器健康状态的命令。
SHELL覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

docker网络

学习链接:https://cloud.tencent.com/developer/article/2302649

Docker网络是Docker容器之间和容器与外部网络之间的通信和连接的一种机制。在Docker中,每个容器都可以有自己的网络栈,包括网络接口、IP地址和网络配置。Docker网络提供了一种灵活且可定制的方式,使得容器之间可以相互通信,并与主机或其他网络资源进行交互。
Docker网络作用:容器之间的互联以及端口映射,容器IP变动的时候可以通过服务名直接网络通信而不受影响。

网络模式简介
Bridge(默认)此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
Host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
Container创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。
None该模式关闭了容器的网络功能,与宿主机、与其他容器都不连通的.
在使用docker run创建Docker容器时,可以用 --net 选项指定容器的网络模式,Docker可以有以下4种网络模式:
• bridge模式:使用 --net=bridge 指定,默认设置。
• host模式:使用 --net=host 指定。
• none模式:使用 --net=none 指定。
• container模式:使用 --net=container:NAME_or_ID 指定。

docker相关命令

链接:https://blog.csdn.net/Pan_peter/article/details/128860771

docker build

docker build命令用于从 Dockerfile 构建 Docker 镜像。
docker build命令通过读取 Dockerfile 中定义的指令,逐步构建镜像,并将最终结果保存到本地镜像库中。
在这里插入图片描述

docker上传到阿里云

链接:https://blog.csdn.net/YL3126/article/details/122184386#:~:text=%E4%B8%80%E3%80%81docker%20%E6%89%93

1、docker 将容器打包成镜像
docker commit -a “作者” -m “简要说明” 容器ID 想要打包成的镜像名称:版本号
或者使用Dockerfile进行打包镜像
2、上传镜像到阿里云
#username后面就是你的阿里云账号,然后 输入密码时 是你 刚才申请镜像仓库设置的密码docker login --username=6643*****@qq.com registry.cn-hangzhou.aliyuncs.com
3、推送镜像
#给镜像打标签,格式必须为 “registry.cn-hangzhou.aliyuncs.com” 这个开头, “yl_hmbb” 换成你自己的 阿里云命名空间名称 即可,后面的 “yl-nginx:v1” 镜像名称和版本号 自行取名即可
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/yl_hmbb/yl-nginx:v1
#推送本地镜像上去
docker push registry.cn-hangzhou.aliyuncs.com/yl_hmbb/yl-nginx:v1
4、拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/yl_hmbb/yl-nginx:v1

JAVA

Redis

redis的使用场景有哪些

热点key问题,怎么发现热点key

为什么点赞用Redis?

redis 数据结构

讲讲Redis中Big Key和Hot Key是什么,解决方案?

如果我有一个Hot Key,它的QPS差不多有十万甚至百万,怎么解决这个Hot Key问题?

集群?读写分离?怎么做?

Mysql 数据库

数据库的三大范式

链接:https://zhuanlan.zhihu.com/p/590135927

第一范式:原子不可再分性。即表中字段的数据,不可以再拆分。
第二范式(2NF):在第一范式基础上,遵循唯一性 ,消除部分依赖。即非主键列要完全依赖于主键。(主要是说在联合主键的情况下,非主键列不能只依赖于主键的一部分)
比如表一:学号,课程名,课程分数
(学号,课程名)----->课程分数
表二:学号,课程名,课程id,课程分数
(学号,课程名)----->课程分数
(学号,课程id)----->课程分数
所以就不符合第二范式
第三范式(3NF):在第二范式的基础上,消除传递依赖问题(A -> B, B -> C, A->C),即在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取某非主键字段 B。

不遵循第二范式会造成什么样的后果呢?

链接:https://zhuanlan.zhihu.com/p/590135927

  1. 造成整表的数据冗余。
  2. 更新数据不方便。
  3. 插入数据不方便或产生异常。

什么样的表越容易符合3NF?

非主键列越少的表。(1NF强调列不可再分;2NF和3NF强调非主属性列和主属性列之间的关系)

连表查询有内连接,左外连接,右外连接,全外连接。

链接:https://www.cnblogs.com/yyjie/p/7788413.html#:~:text=%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3SQL%E7%9A%84%E5%9B%9B%E7%A7%8D

连接查询是从多个表中选择数据的方式,通常使用外键关联表。常见的连接方式有 INNER JOIN(内连接)、LEFT JOIN(左外连接)、RIGHT JOIN(右外连接) 和 FULL OUTER JOIN(全连接)。
INNER JOIN 返回两个表中满足连接条件的所有行。如果没有匹配的行,则不会返回结果。

SELECT employees.name, departments.name 
FROM employees INNER JOIN departments 
ON employees.department_id = departments.id;

LEFT JOIN 返回左表中的所有行,即使右表中没有匹配的记录。如果右表中没有匹配的记录,会以 NULL 值表示。

#该查询返回所有员工及其对应的部门,如果某个员工没有部门,则部门名称会显示为 NULL。
SELECT employees.name, departments.name 
FROM employees LEFT JOIN departments 
ON employees.department_id = departments.id;

RIGHT JOIN 返回右表中的所有行,即使左表中没有匹配的记录。如果左表中没有匹配的记录,会以 NULL 值表示。

#这个查询返回所有部门及其对应的员工,如果某个部门没有员工,则员工名称会显示为 NULL。
SELECT employees.name, departments.name 
FROM employees RIGHT JOIN departments 
ON employees.department_id = departments.id;

FULL OUTER JOIN 返回两个表中的所有行,不论是否有匹配记录。如果没有匹配的记录,会以 NULL 值表示。

该查询返回所有员工及所有部门,即使没有匹配的记录。
SELECT employees.name, departments.name 
FROM employees FULL OUTER JOIN departments 
ON employees.department_id = departments.id;

子查询

子查询是嵌套在其它查询中的查询,分为嵌套查询相关子查询。
嵌套查询:将一个查询的结果作为另一个查询的条件,子查询作为外部查询的一部分并先于外部查询执行

#上述查询选择所有在"Sales"部门工作的员工。
SELECT name FROM employees WHERE department_id IN (
    SELECT id 
    FROM departments 
    WHERE name = 'Sales'
);

**相关子查询:**相关子查询依赖于外部查询,每次执行外部查询时都会执行一次子查询。

#这条查询选择所有薪资高于其部门平均薪资的员工。
SELECT name, salary FROM employees e WHERE salary > (
    SELECT AVG(salary) 
    FROM employees 
    WHERE department_id = e.department_id
);

子查询的优化
使用适当的索引:确保在相关列上有适当的索引。
简化子查询:将复杂的子查询简化为视图或临时表。
避免SELECT:只选择必须的列以减少数据传输量。

聚合函数

聚合函数用于对结果集中的值进行计算,如 COUNT、SUM、AVG、MAX 和 MIN。
COUNT 函数返回结果集中的行数。

#这条查询返回员工表中的总行数。
SELECT COUNT(*)  FROM employees;

SUM 函数返回数值列的总和。

#这条查询返回所有员工薪资的总和。
SELECT SUM(salary) FROM employees;

AVG 函数返回数值列的平均值。

#这条查询返回所有员工薪资的平均值。
SELECT AVG(salary) FROM employees;

MAX 函数返回数值列的最大值。

这条查询返回员工中的最高薪资。
SELECT MAX(salary) FROM employees;

MIN 函数返回数值列的最小值。

这条查询返回员工中的最低薪资。
SELECT MIN(salary) FROM employees;

GROUP BY 语句用于根据一个或多个列对结果集进行分组,并对每个分组应用聚合函数。

#这条查询返回每个部门的员工人数。
SELECT department_id, COUNT(*) FROM employees 
GROUP BY department_id;

mysql如何避免重复插入数据

mysql事务是什么,原子性怎么实现的

链接:https://blog.csdn.net/Baisitao_/article/details/104723795#::text=MySQL%E4%BA%8B%E5%8A%A1%E7%9A%84%20%E5%8E%9F#::text=MySQL%E4%BA%8B%E5%8A%A1%E7%9A%84%20%E5%8E%9F

事务具有以下四个重要特性,即 ACID 特性
原子性 (Atomicity):事务中包含的操作要么都执行,要么都不执行。
一致性 (Consistency):事务执行完成后,数据库必须从一个一致的状态转换到另一个一致的状态。
隔离性 (Isolation):多个事务并发执行时,一个事务的执行不应受其他事务的干扰。
持久性 (Durability):事务一旦提交,对数据库的改变是永久性的,即使在系统崩溃情况下也不会丢失。
MySQL事务的原子性是通过
undo log
来实现的。undo log是
InnoDB存储引擎
特有的。具体的实现方式是:将所有对数据的修改(增、删、改)都写入日志(undo log)。如果一个事务中的一部分操作已经成功,但另一部分操作,由于断电/系统崩溃/其它的软硬件错误而无法成功执行,则通过回溯日志,将已经执行成功的操作撤销,从而达到全部操作失败的目的。
undo log是逻辑日志,可以理解为:记录和事务操作
相反
的SQL语句,事务执行insert语句,undo log就记录delete语句。它以追加写的方式记录日志,不会覆盖之前的日志。除此之外undo log还用来实现数据库多版本并发控制(Multiversion Concurrency Control,简称MVCC)
MySQL事务的持久性是通过
redo log
来实现的。redo log也是InnoDB存储引擎特有的。具体实现方式是:当发生数据修改(增、删、改)的时候,InnoDB引擎会先将记录写到redo log中,并更新内存,此时更新就算完成了。同时InnoDB引擎会在合适的时机将记录刷到磁盘中。
redo log是物理日志,记录的是在某个数据页做了什么修改,而不是SQL语句的形式。它有固定大小,是循环写的方式记录日志,空间用完后会覆盖之前的日志。
undo log和redo log并不是直接写到磁盘上的,而是先写入log buffer。再等待合适的时机同步到OS buffer,再由操作系统决定何时刷到磁盘。

隔离如何实现,数据库的隔离机制与原理

第一类丢失更新、脏读和幻读、第二类丢失更新,及解决方案

如果没有隔离性,会遇到哪些问题及其解决方案

链接:https://blog.csdn.net/Baisitao_/article/details/104723795#::text=MySQL%E4%BA%8B%E5%8A%A1%E7%9A%84%20%E5%8E%9F#::text=MySQL%E4%BA%8B%E5%8A%A1%E7%9A%84%20%E5%8E%9F

第一类丢失更新是指:一个事务在撤销的时候,覆盖了另一个事务已提交的更新数据
**脏读:**一个事务读到了另一个事务未提交的更新数据
**不可重复读:**一个事务读到了另一个事务已提交的更新数据
**第二类丢失更新是指:**一个事务在提交的时候,覆盖了另一个事务已提交的更新数据
为了解决这五类问题,MySQL提供了四种隔离级别:
Serializable(串行化):事务之间以一种串行的方式执行,安全性非常高,效率低
Repeatable Read(可重复读):是MySQL默认的隔离级别,同一个事务中相同的查询会看到同样的数据行,安全性较高,效率较好
Read Commited(读已提交):一个事务可以读到另一个事务已经提交的数据,安全性较低,效率较高
Read Uncommited(读未提交):一个事务可以读到另一个事务未提交的数据,安全性低,效率高

隔离级别是否出现第一类丢失更新是否出现脏读是否出现虚读是否出现不可重复读是否出现第二类丢失更新
Serializable
Repeatable Read
Read Commited
Read Uncommited

事务的生命周期

一个事务的生命周期主要包括以下几个阶段:
1、开始事务 (BEGIN 或 START TRANSACTION)
2、执行事务操作 (各种 DML 语句,如 INSERT、UPDATE、DELETE)
3、提交事务 (COMMIT) 或 回滚事务 (ROLLBACK)

#一个简单的事务过程如下:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
#在这个例子中,如果任意一个 UPDATE 操作失败,
#那么整个事务都会回滚,保证数据的一致性。

mysql锁机制

MySQL 中的锁大体分为两类:表级锁行级锁InnoDB 支持行级锁,这是实现高并发的重要特性。
行级锁有以下几种类型:
**共享锁 (S):**允许事务读取一行记录,多个事务可以同时加共享锁。
排他锁 (X):允许事务删除或更新一行记录,只有加锁的事务能操作这行记录。
意向共享锁(IS)意向排他锁 (IX):用于表级锁与行级锁的兼容性,确保行级锁不会与表级锁冲突。
死锁检测
在高并发情况下,可能会发生死锁。InnoDB 具有死锁检测机制,能自动检测并解决死锁情况:检测到死锁时,InnoDB 会回滚其中一个事务,从而释放锁。

B树介绍

学习链接:https://www.cnblogs.com/lianzhilei/p/11250589.html
一颗m阶的B树满足如下条件:
1、每个节点最多只有m个子节点。
2、除根节点外,每个非叶子节点具有至少有⌈ m/2⌉个子节点。
3、非叶子节点的根节点至少有两个子节点。(意思就是如果这棵树不是只有根节点的话,根节点至少要有两个子节点)
4、有k颗子树的非叶节点有k-1个键,键按照递增顺序排列。
5、叶节点都在同一层中。

根节点的子节点数目为M,根节点中关键字为X,则要满足的关系:2=<M<=m,1=<X<=m-1
内部节点的子节点数目为M,内部节点中关键字为X,则要满足的关系:(⌈ m/2⌉)=<M<=m,(⌈ m/2⌉)-1=<X<=m-1
在这里插入图片描述

针对m阶高度h的B树,插入一个元素时,首先在B树中是否存在,如果不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素。
若该节点元素个数小于m-1,直接插入
若该节点元素个数等于m-1,引起节点分裂;以该节点中间元素为分界,取中间元素(偶数个数,中间两个随机选取)插入到父节点中;
重复上面动作,直到所有节点符合B树的规则;最坏的情况一直分裂到根节点,生成新的根节点,高度增加1;

B+树介绍

学习链接:https://www.cnblogs.com/lianzhilei/p/11250589.html

B+树的特征:
有m个子树的中间节点包含有m个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引
所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息);
所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息);

索引的底层结构是什么,为什么要采用B+树?

为什么说B+树比B树更适合数据库索引?

B树与B+树的区别

1)B+树的磁盘读写代价更低
B+树的内部结点并没有指向关键字具体信息指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了;
2)B+树查询效率更加稳定
  由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当;
3)B+树便于范围查询(最重要的原因,范围查找是数据库的常态)
  B树在提高了IO性能的同时并没有解决元素遍历效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低;不懂可以看看这篇解读-》https://zhuanlan.zhihu.com/p/54102723
补充:B树的范围查找用的是中序遍历,而B+树用的是在链表上遍历;

mysql存储引擎

存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。
MySQL - 常见的三种数据库存储引擎
1.InnoDB存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),其它存储引擎都是非事务安全表,支持行锁定和外键,MySQL5.5以后默认使用InnoDB存储引擎。
2.MyISAM存储引擎
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务,不支持外键。
3.MEMORY存储引擎
MEMORY存储引擎将表中的数据存储到内存中,为查询和引用其他表数据提供快速访问。

mysql分片

mysql索性和结构

链接:https://blog.csdn.net/Pireley/article/details/133931413#::text=MySQL%E7%B4%A2%E5%BC%95%E5%B8%B8%E8%A7%81%E7%9A%84#::text=MySQL%E7%B4%A2%E5%BC%95%E5%B8%B8%E8%A7%81%E7%9A%84

索引是存储引擎用于快速查找数据纪录的一种数据结构。
最典型的例子就是查新华字典,通过查找目录快速定位到要查找的字。
数据是存储在磁盘上的,查询数据时,如果没有索引,会加载所有的数据到内存,依次进行检索,读取磁盘次数较多使用索引,就不需要加载所有数据,MySQL是以B+数的数据结构存储索引,B+树的高度一般在2-4层,最多只需要读取2-4次磁盘,查询速度大大提升。
2、索引的优缺点
(1)优点:1、避免进行数据库全表的扫描,大多数情况,只需要扫描较少的索引页和数据页,提升查询语句的执行效率
2、在使用分组和排序语句进行数据检索时,可以显著减少查询中分组和排序的时间
3、多表连接查询,提高从其他表检测行数据的性能
4、如果表具有多列索引,则优化器可以使用索引的最左匹配前缀来查找,提升数据检索的性能
(2)缺点:会降低表的增删改的效率,因为每次对表记录进行增删改,需要进行动态维护索引。

数据库连接池的参数怎么配

mysql 日志

原文链接:https://javaguide.cn/database/mysql/mysql-logs.html

MySQL三大日志(binlog、redo log和undo log),binlog(归档日志)和事务日志 redo log(重做日志)和 undo log(回滚日志)
redo log(重做日志)是 InnoDB 存储引擎独有的,它让 MySQL 拥有了崩溃恢复能力。比如 MySQL 实例挂了或宕机了,重启时,InnoDB 存储引擎会使用 redo log 恢复数据,保证数据的持久性与完整性。
Redo Log 记录的是物理日志,也就是磁盘数据页的修改。
作用: 用来保证服务崩溃后,仍能把事务中变更的数据持久化到磁盘上。
MySQL事务中持久性就是使用Redo Log实现的。
Undo Log的内容与作用:Undo Log记录的是逻辑日志,也就是SQL语句。
比如:当我们执行一条insert语句时,Undo Log就记录一条相反的delete语句。
作用:回滚事务时,恢复到修改前的数据。
实现 MVCC(多版本并发控制,Multi-Version Concurrency Control) 。
MySQL事务中原子性就是使用Undo Log实现的。
**Bin Log(备份日志)**Bin Log记录的是逻辑日志,即原始的SQL语句,是MySQL自带的。作用: 数据备份和主从同步。
Bin Log共有三种日志格式,可以binlog_format配置参数指定。

参数值含义
Statement记录原始SQL语句,会导致更新时间与原库不一致。
比如 update_time=now()
Row记录每行数据的变化,保证了数据与原库一致,缺点是数据量较大。
MixedStatement和Row的混合模式,默认采用Statement模式,涉及日期、函数相关的时候采用Row模式,既减少了数据量,又保证了数据一致性。

Mysql的索引介绍一下

索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,可以大大加快查询的速度,使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据。索引的作用类似于书的目录,可以根据目录中的页码快速找到所需的内容。
索引的分类
普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。
功能逻辑 上说,索引主要有 4 种,分别是普通索引、唯一索引、主键索引、全文索引。
按照 物理实现方式 ,索引可以分为 2 种:聚簇索引和非聚簇索引。
按照 作用字段个数 进行划分,分成单列索引和联合索引。
普通索引是最基本的索引,它没有任何限制,也是大多数情况下用到的索引。

直接创建索引的方式
mysql>CREATE INDEX index_name ON table_name (column(length));
column 是指定要创建索引的列名
length 是可选项
修改表结构的方式添加索引
mysql>ALTER TABLE table_name ADD INDEX index_name (column(length));
在创建一个表结构时,就创建索引
mysql> create table num (id int(3),index id_index(id));
Query OK, 0 rows affected (0.01 sec)
mysql> describe num;
+-------+--------+------+-----+---------+-------+
| Field | Type   | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| id    | int(3) | YES  | MUL | NULL    |       |
+-------+--------+------+-----+---------+-------+
1 row in set (0.00 sec)

唯一索引与普通索引类似,不同的就是:唯一索引的索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一。唯一索引创建方法和普通索引类似。

mysql>CREATE UNIQUE INDEX index_name ON table_name(column(length));
或
mysql>ALTER TABLE table_name ADD UNIQUE index_name(column(length));
或
CREA TETABLE `table`( 
...
UNIQUE index Name (title(length)) );

主键索引:主键索引是一种特殊的唯一索引,一个表只能有一个主键不允许有空值。一般是在建表的时候同时创建主键索引。

第一种:在字段外创建
mysql> create table info2 (id int(4) not null,name varchar(10) not null,address varchar(50) default '未知',primary key(id));
第二种:在字段内创建
mysql> create table info2 (id int(4) not null primary key,name varchar(10) not null,address varchar(50) default '未知');

全文索引:对于较大的数据集,将资料输入一个没有 FULLTEXT 索引的表中,然后创建索引,其速度比把资料输入现有 FULLTEXT 索引的速度更快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间、非常消耗硬盘空间的做法。

mysql> alter table info2 add fulltext index addr_index(address);    ##创建全文索引

联合索引(最左前缀):平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。在组合索引的创建中,有两种场景,即为单列索引和多列索
引。特点:遵从最左原则,从左往右依次执行;

查看索引:

查看索引的两种方法
mysql>show index from tablename;
mysql>show keys from tablename;

删除索引

 删除索引的两种方式
DROP INDEX 索引名 ON 表名; 
ALTER TABLE 表名 DROP INDEX 索引名;

如何建立索引?或者说建立索引的原则有哪些?

1、建立唯一索引。
2、为经常需要查询的字段建立索引。
3、对经常需要排序、分组以及联合操作的字段建立索引。
4、考虑索引的最左匹配原则。
5、不要建立过多的索引。

为什么要打破三范式、冗余数据的时候有哪些原则

数据库三范式,为什么要打破三范式

学习链接:https://blog.csdn.net/qq_21891743/article/details/132516886#:~:text=%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%89%E5%A4%A7%E8%8C%83%E5%BC%8F%E6%98%AF%E6%8C%87%E5%85%B3
https://blog.csdn.net/qq_42799459/article/details/92424480#:~:text=%E4%B8%89%E8%8C%83%E5%BC%8F.%20%E8%AE%BE%E8%AE%A1%20%E5%85%B3%E7%B3%BB

(1NF):原子性,每个字段都不可再分
(2NF):唯一性,在1NF基础上,所有非主键字段必须完全依赖于主键,不能依赖部分主键
(3NF):消除传递性,在2NF基础上,要求所有非主键字段之间不能存在传递依赖关系。
在数据库设计领域,冗余字段是一个经常被讨论的话题。冗余字段指的是在数据库表中存储了可以从其他数据派生或计算得到的信息。
反范式
实际使用过程中,需要注意以下几个问题:
数据冗余,范式化的数据库设计,可以尽可能地减少数据冗余,避免了数据的不一致和更新异常。但范式化的设计也可能导致查询时需要进行多表连接,影响查询性能。
性能问题,范式化的数据库设计可能导致复杂的查询语句,对于大量数据的查询和处理可能性能较差。在实际应用中,需要根据具体情况进行性能优化,可以考虑使用反范式化来提高查询性能。
设计复杂度,范式化的数据库设计可能会增加数据表的数量,使数据库结构变得复杂。在设计过程中需要权衡范式化的好处和复杂性,并根据实际需求做出适当的选择。
为了解决上述问题,有时候需要采用反范式化的设计方法。反范式化是指有意地将数据冗余存储在数据库中,以提高查询性能或简化数据模型。
常用的反规范技术有增加冗余列、增加派生列、重新组表 和分割表。

增加冗余列:指在多个表中具有相同的列,它常用来在查询时避免连接操作。
增加派生列:指增加的列来自其他表中的数据,由其他表中的数据经过计算生成。增 加的派生列其作用是在查询时减少连接操作,避免使用集函数。
重新组表:指如果许多用户需要查看两个表连接出来的结果数据,则把这两个表重新 组成一个表来减少连接而提高性能.

对于冗余的数据,怎么保证数据的一致性

什么是索引,你都知道什么索引

在MySQL中,B+树索引按照存储方式的不同分为聚集索引非聚集索引
1、聚集索引(聚簇索引)
以innodb作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。这是因为innodb是把数据存放在B+树中的,而B+树的键值就是主键,在B+树的叶子节点中存储了行数据,可以直接在聚集索引中查找到想要的数据。这种以主键作为B+树索引的键值而构建的B+树索引,我们称之为聚集索引。
2、非聚集索引(非聚簇索引)
(1)以主键以外的列值作为键值构建的B+树索引,我们称之为非聚集索引。
(2)非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。
(3)如果使用了覆盖索引,则不需要回表,直接通过辅助索引就可以查找到想要的数据。覆盖索引就是指select查询的数据只需要在索引中就能取得,而不必读取数据行,换句话说就是,查询列要被所建的索引覆盖。

为什么索引快

建立了索引的数据,就是通过事先排好序,从而在查找时可以应用二分查找来提高查询效率。这也解释了为什么索引应当尽可能的建立在主键这样的字段上,因为主键必须是唯一的,根据这样的字段生成的二叉查找树的效率无疑是最高的。

为什么索引不能建立的太多?

如果一个表中所有字段的索引很大,也会导致性能下降。想象一下,如果一个索引和一个表一样长,那么它将再次成为一个需要检查的开销。这就好比字典的目录非常详细,但是其长度已经和所有的文字一样长,这个时候目录本身的效率就大大下降了。

讲讲二叉树,b树,b+树的区别

链接:https://blog.csdn.net/Pireley/article/details/133931413#::text=MySQL%E7%B4%A2%E5%BC%95%E5%B8%B8%E8%A7%81%E7%9A%84#::text=MySQL%E7%B4%A2%E5%BC%95%E5%B8%B8%E8%A7%81%E7%9A%84

MySQL索引常见的数据存储结构有哈希结构,B+树结构,R树结构。其中R树结构用于空间索引,不常见。要介绍B+树索引,就不得不提二叉查找树,平衡二叉树和B树这三种数据结构。B+树就是在此基础上演化而来的。
二叉查找树的特点就是任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值。 顶端的节点我们称为根节点,没有子节点的节点我们称之为叶节点。
平衡二叉树又称AVL树,在满足二叉查找树特性的基础上,要求每个节点的左右子树的高度差不能超过1
平衡二叉树保证了树的构造是平衡的,当我们插入或删除数据导致不满足平衡二叉树不平衡时,平衡二叉树会进行调整树上的节点来保持平衡。
B树
因为内存的易失性。一般情况下,我们都会选择将user表中的数据和索引存储在磁盘这种外围设备中。如果我们采用平衡二叉树这种数据结构作为索引的数据结构,每查找一次数据就需要从磁盘中读取一个节点,即我们说的一个磁盘块。平衡二叉树每个节点只存储一个键值和数据,也就是说每个磁盘块仅仅存储一个键值和数据。如果要存储海量的数据,二叉树的节点将会非常多,高度也会很高,查找数据时就会进行很多次磁盘IO,查找数据的效率降低。
(2)为了解决平衡二叉树的这个弊端,我们应该寻找一种单个节点可以存储多个键值和数据的平衡树。也就是我们接下来要说的B树。
B+树是对B树的进一步优化。B+树非叶子节点上是不存储数据的,仅存储键值,这么做是因为在数据库中页的大小是固定的,innodb中页的默认大小是16KB。如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少。
(2)B+树的阶数是等于键值的数量,如果我们的B+树一个节点可以存储1000个键值,那么3层B+树可以存储1000×1000×1000=10亿个数据。一般根节点是常驻内存的,所以一般我们查找10亿数据,只需要2次磁盘IO。
(3)因为B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得非常简单。
(4)B+树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。上图中的B+树索引就是innodb中B+树索引的实现方式,准确的说应该是聚集索引,在MyISAM中,B+树索引的叶子节点并不存储数据,而是存储数据的文件地址。

知道回表么, 二级索引都需要回表么

如果查询的列本身就存在于索引中,那么即使使用二级索引,一样也是不需要回表的。

MySQL如何处理多并发

大量请求MySQL该怎么办

Elasticsearch

学习链接:https://zhuanlan.zhihu.com/p/429104939

什么是Elasticsearch

Elasticsearch 的基本概念

你了解Elasticsearch,为什么用它?

Elasticsearch是基于Lucene的一款开源的搜索、聚合分析和存储引擎。同时它也可以称作是一种非关系型文档数据库简化了 lucene的那些复杂API,它天然支持集群,开箱即用。性能也得到了大幅度提升。
elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。kibana做可视化界面,elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。
在这里插入图片描述

什么是倒排索引

学习链接:https://www.cnblogs.com/buchizicai/p/17093719.html

倒排索引的概念是基于MySQL这样的正向索引而言的。那么什么是正向索引呢?例如给下表(tb_goods)中的id创建索引:
在这里插入图片描述
如果是根据id查询,那么直接走索引,查询速度非常快。
但如果是基于title做模糊查询,只能是逐行扫描数据,流程如下:
1)用户搜索数据,条件是title符合"%手机%"
2)逐行获取数据,比如id为1的数据
3)判断数据中的title是否符合用户搜索条件
4)如果符合则放入结果集,不符合则丢弃。回到步骤1
逐行扫描,也就是全表扫描,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。
倒排索引中有两个非常重要的概念:
文档(Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息
词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条
创建倒排索引是对正向索引的一种特殊处理,流程如下:
将每一个文档的数据利用算法分词,得到一个个词条
创建表,每行数据包括词条、词条所在文档id、位置等信息
因为词条唯一性,可以给词条创建索引,例如hash表结构索引

正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。
倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程。

DocValues的作用

doc_values和fieldd源于Elasticsearch(后面简称ES)除了强大的搜索功能外,还可以支持排序,聚合之类的操作。搜索需要用到倒排索引,而排序和聚合则需要使用 “正排索引”。说白了就是一句话,倒排索引的优势在于查找包含某个项的文档,而反过来确定哪些项在单个文档里并不高效。
doc_values和fielddata就是用来给文档建立正排索引的。他俩一个很显著的区别是,前者的工作地盘主要在磁盘,而后者的工作地盘在内存

维度doc_valuesfielddata
创建时间index时创建使用时动态创建
创建位置磁盘内存(jvm heap)
优点不占用内存空间不占用磁盘空间
缺点索引速度稍低文档很多时,动态创建开销比较大,而且占内存

text 和 keyword类型的区别

keyword类型的字段中的数据都是不可分的,比如时间:2024-09-14
text类型的字段中的数据是可分的,比如:“今天的饭真好吃”, 邮箱内容、地址、代码块、博客文章内容等。text类型的数据不能用来过滤、排序和聚合等操作。
keyword 类型的数据可以满足电子邮箱地址、主机名、状态码、邮政编码和标签等数据的要求,不进行分词,常常被用来过滤、排序和聚合

什么是停顿词过滤

停顿词可以看成是没有意义的词,比如“的”、“而”,这类词没有必要建立索引

import nltk
from nltk.corpus import stopwords
sw_nltk = stopwords.words('english')
print(sw_nltk)
text = "When I first met her she was very quiet. She remained quiet during the entire two hour long journey from Stony Brook to New York."
words = [word for word in text.split() if word.lower() not in sw_nltk]
new_text = " ".join(words)
print(new_text)
print("Old length: ", len(text))
print("New length: ", len(new_text))
把我自己的停用词加到列表上
sw_nltk.extend(['first', 'second', 'third', 'me'])
print(len(sw_nltk)) 
# 从预先制作的列表中删除停用词
sw_nltk.remove('not')

ES的写入流程

es 写数据的过程

写数据的底层原理

ES的更新和删除流程

ES的搜索流程

搜索被执行成一个两阶段过程,我们称之为Query Then Fetch;

Query阶段

当一个search请求发出的时候,这个query会被广播到索引里面的每一个shard(主shard或副本shard),每个shard会在本地执行查询请求后会生成一个命中文档的优先级队列。
这个队列是一个排序好的top N数据的列表,它的size等于from+size的和,也就是说如果你的from是10,size是10,那么这个队列的size就是20,所以这也是为什么深度分页不能用from+size这种方式,因为from越大,性能就越低。
Elasticsearch query流程

客户端发送一个search请求到NODE 3上,然后NODE 3会创建一个优先级队列它的大小=from+size;
接着NODE 3转发这个search请求到索引里面每一个主shard或者副本shard上,每个shard会在本地查询,然后添加结果到本地的排序好的优先级队列里面;
每个shard返回docId和所有参与排序字段的值例如_score到优先级队列里面,然后再返回给coordinating node(协调节点,这里面是NODE 3,即请求第一个打到的节点),然后NODE 3负责将所有shard里面的数据给合并到一个全局的排序的列表。
上面提到一个术语叫coordinating node,这个节点是当search请求随机负载的发送到一个节点上,然后这个节点就会成为一个coordinating node,它的职责是广播search请求到所有相关的shard上,然后合并他们的响应结果到一个全局的排序列表中然后进行第二个fetch阶段,注意这个结果集仅仅包含docId和所有排序的字段值,search请求可以被主shard或者副本shard处理,这也是为什么我们说增加副本的个数就能增加搜索吞吐量的原因,coordinating节点将会通过round-robin的方式自动负载均衡。

Fetch阶段

Fetch(读取阶段)
query阶段标识了哪些文档满足了该次的search请求,但是我们仍然需要检索回document整条数据,这个阶段称为fetch阶段。
Elasticsearch fetch流程:
coordinating node(协调节点,上图中是NODE 3)标识了哪些document需要被拉取出来,并发送一个批量的multi get请求到相关的shard上;
每个shard加载相关的document,如果需要它们将会被返回到coordinating node上;一旦所有的document被拉取回来,coordinating node将会返回结果集到客户端上。
这里需要注意,coordinating节点拉取的时候只拉取需要被拉取的数据,比如from=90,size=10,那么fetch只会读取需要被读取的10条数据,这10条数据可能在一个shard上,也可能在多个shard上所以 coordinating节点会构建一个multi-get请求并发送到每一个shard上,每个shard会根据需要从_source字段里面获取数据,一旦所有的数据返回,coordinating节点会组装数据进入单个response里面然后将其返回给最终的client。

ES在高并发下如何保证读写一致性?

Elasticsearch 的分布式原理

Elasticsearch 如何 选举 Master

ES的深度分页与滚动搜索scroll

Elasticsearch是如何避免脑裂现象

elasticsearch索引

elasticsearch索引是倒排索引,正向索引的话是根据索引去数据库中搜索文档。而倒排索引的概念是根据查询内容分片,去索引库中搜索分片后的查询对应的文档id(也就是mysql中对应的索引),然后再根据文档id搜索文档

为啥模糊查询ElasticSearch?MySQL不行?

Mysql采用的是正向索引,如果是模糊查询的话就不能使用索引了,这样会一条一条的去匹配,如果数据库中数据量特别大的话,效率特低
而ElasticSearch是倒排索引,如果是模糊查询,会根据查询切分成词条,根据词条去索引库中搜索对应的文档id(也就是mysql中对应的索引),然后再根据文档id搜索文档.相较于一条条匹配效率会提升很多。

query 和 filter 的区别?

Query context 查询上下文 这种语句在执行时既要计算文档是否匹配,还要计算文档相对于其他文档的匹配度有多高,匹配度越高,_score 分数就越高
并且没有cache功能.
Filter context 过滤上下文 过滤上下文中的语句在执行时只关心文档是否和查询匹配,不会计算匹配度,也就是得分。同时可以cache。

GET /_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
 }

对上面的例子分析下:
query 参数表示整个语句是处于 query context 中
bool 和 match 语句被用在 query context 中,也就是说它们会计算每个文档的匹配度(_score)
filter 参数则表示这个子查询处于 filter context 中
filter 语句中的 term 和 range 语句用在 filter context 中,它们只起到过滤的作用,并不会计算文档的得分。

Elasticsearch支持事务吗?

Elasticsearch 结构 索引 集群分片

讲讲ElasticSearch,你为什么用ElasticSearch?ElasticSearch相对于其他的数据库来讲有什么优势吗?

讲一下elasticsearch和mysql 的区别

1、es文档格式存储,mysql行存储
2、es倒排索引,mysq正向索引
3、

如何确保ElasticSearch和数据库中数据的一致性

elasticsearch怎么实现的全文搜索

学习 链接:https://www.cnblogs.com/buchizicai/p/17093719.html

非结构化数据/结构化数剧建立(索引)再对索引进行搜索文档数据 的过程就叫做 全文检索 (full text search)
全文检索查询的基本流程如下:
对用户搜索的内容做分词,得到词条
根据词条去倒排索引库中匹配,得到文档id
根据文档id找到文档,返回给用户

1、对于全文搜索,文本分析是关键步骤。Elasticsearch 会对查询文本进行分析,包括:
分词:将输入的字符串分解为单独的词项(tokens)。
过滤:应用分析器(如去除停用词大小写转换词干提取等),以
处理文本并生成标准化
搜索词项
在这里插入图片描述
2、在每个目标分片中,Elasticsearch 会执行查询操作。主要过程包括:
倒排索引查找:使用倒排索引根据分析后的查询词项查找相关文档。
评分:对于匹配的文档,计算其相关性得分(score),常用的方法有 BM25 算法。
3、如果
查询中
包含
聚合请求
,Elasticsearch 会在匹配的文档上执行聚合操作(如计数、平均值等)。最终,根据相关性得分和排序条件对结果进行排序
4、从所有目标分片中收集结果,并将其合并为最终结果。

常见的全文检索查询包括:
match查询:单字段查询
multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件

说说ElasticSearch的相关功能

ES如何进行索引创建

在kibana可视化工具中创建索引:

PUT /pretty

注意:默认情况下,创建的索引分片数量是 5 个,副本数量是 1 个。也可以通过如下参数来指定分片数、副本数量:

{
	"settings": {
		"number_of_shards": 3,
		"number_of_replicas": 2
	}
}

实战:

PUT /my_index
{
    "settings": { ... any settings ... },  // ES配置,如分片
    // 映射关系
    "mappings": {
        "type_one": { ... any mappings ... },
        "type_two": { ... any mappings ... },
        ...
    }
}

在这里插入图片描述

你知道ES搜索数据、从磁盘加载数据的原理吗?

如果文章很多,像快手可能有几亿篇,存ES有什么问题?

Elasticsearch存的什么数据?文章所有字段都存es里吗?

BM25

什么是BM25,介绍下BM25 算法基本思想

BM25是信息索引领域用来计算query与文档相似度得分的经典算法。 基于TF-IDF(Term Frequency-Inverse Document Frequency)的思想,但对其进行了改进以考虑文档的长度等因素。
TF-IDF 的改进: BM25 通过对文档中的每个词项引入饱和函数(saturation function)和文档长度因子,改进了 TF-IDF 的计算。
饱和函数: 在 BM25 中,对于词项的出现次数(TF),引入了一个饱和函数来调整其权重。这是为了防止某个词项在文档中出现次数过多导致权重过大。
文档长度因子: BM25 考虑了文档的长度,引入了文档长度因子,使得文档长度对权重的影响不是线性的。这样可以更好地适应不同长度的文档。

介绍下BM25公式

不同于TF-IDF,BM25的公式主要由三个部分组成:
1.query中每个单词t与文档d之间的相关性(对tf部分的优化,并考虑了文档的长度)
2.单词t与query之间的相似性(该部分只有在当query很长时才会使用)
3.每个单词的权重(可以理解为idf部分)

BM25的一般公式:
S c o r e ( Q , d ) = ∑ i n R ( q i , d ) Score(Q,d)=\sum^{n}_{i}{R(q_i,d)} Score(Q,d)=inR(qi,d)
其中Q表示一条query, q i q_i qi表示query中的单词。d表示某个搜索文档。 W i W_i Wi表示单词权重
这里其实就是IDF:
I D F ( q i ) = l o g N − d f i + 0.5 d f i + 0.5 IDF(q_i)=log{\frac{N-df_i+0.5}{df_i+0.5}} IDF(qi)=logdfi+0.5Ndfi+0.5
其中N表示索引中全部文档数, d f i df_i dfi为包含了 q i q_i qi的文档的个数。依据IDF的作用,对于某个 q i q_i qi,包含 q i q_i qi的文档数越多,说明 q i q_i qi重要性越小,或者区分度越低,IDF越小,因此IDF可以用来刻画 q i q_i qi与文档的相似性。
单词与文档之间的相关性
单词与文档之间相关性的刻画依赖一个重要发现:词频和相关性之间的关系是非线性的。即每个词和文档的相关性分数不会超过某个阈值,当词出现的次数达到一个阈值之后,其影响就不再线性增长,而这个阈值和文档本身相关。因此在刻画单词与文档的相关性时,BM25时这么设计的:
S ( q i , d ) = ( k 1 + 1 ) t f q i d K + t f q i d S(q_i,d)=\frac{(k_1+1)tf_{{q_i}d}}{K+tf_{{q_i}d}} S(qi,d)=K+tfqid(k1+1)tfqid
K = k 1 ( 1 − b + b ∗ L d L a v g ) K=k_1(1-b+b*\frac{L_d}{L_{avg}}) K=k1(1b+bLavgLd)
其中 t f q i d tf_{q_i}d tfqid 表示单词 q i q_i qi 在文档d中的词频, L d L_d Ld表示文档d的长度, L a v e L_{ave} Lave表示所有文档的平均长度,变量 k 1 k_1 k1表示为正的参数,用来标准化文章词频的范围。b是另一个参数且0<b<1,b表示使用文档长度来表示信息量的程度。当b=1,是完全使用文档长度来衡量词的权重,当b为0时,表示不使用文档长度来衡量词的权重。
单词与query之间的相关性
只有当query很长时,才需要刻画单词与query之间的相关性。公式为:
S ( q i , Q ) = k 3 + 1 ∗ t f q i q k 3 ∗ t f q i q S(q_i,Q)=\frac{k_3+1*tf_{{q_i}q}}{k_3*tf_{{q_i}q}} S(qi,Q)=k3tfqiqk3+1tfqiq
其中 q i q_i qi表示query中的单词, t f q i q tf_{{q_i}q} tfqiq表示单词 q i q_i qi在query中出现的频数。 k 3 k_3 k3是一个可调节的正参数,用来矫正query中的词频范围.
整体公式
S c o r e ( Q , d ) = ∑ i n l o g N − d f i + 0.5 d f i + 0.5 ∗ ( k 1 + 1 ) t f q i d K + t f q i d ∗ k 3 + 1 ∗ t f q i q k 3 ∗ t f q i q Score(Q,d)=\sum^{n}_{i}{log{\frac{N-df_i+0.5}{df_i+0.5}}*\frac{(k_1+1)tf_{{q_i}d}}{K+tf_{{q_i}d}}*\frac{k_3+1*tf_{{q_i}q}}{k_3*tf_{{q_i}q}}} Score(Q,d)=inlogdfi+0.5Ndfi+0.5K+tfqid(k1+1)tfqidk3tfqiqk3+1tfqiq = ∑ i n l o g N − d f i + 0.5 d f i + 0.5 ∗ ( k 1 + 1 ) t f q i d t f q i d + k 1 ∗ ( 1 − b + b ∗ L d L a v g ) ∗ k 3 + 1 ∗ t f q i q k 3 ∗ t f q i q =\sum^{n}_{i}{log{\frac{N-df_i+0.5}{df_i+0.5}}*\frac{(k_1+1)tf_{{q_i}d}}{tf_{{q_i}d}+k_1*(1-b+b*\frac{L_d}{L_{avg}})}*\frac{k_3+1*tf_{{q_i}q}}{k_3*tf_{{q_i}q}}} =inlogdfi+0.5Ndfi+0.5tfqid+k1(1b+bLavgLd)(k1+1)tfqidk3tfqiqk3+1tfqiq
参数经验值
根据实验, k 1 k_1 k1 k 3 k_3 k3一般取值1.2~2。b取值0.75。

tf-idf

介绍下TF-IDF公式

TF(term frequency): 术语频率。用于衡量一个词在一个文档中的出现频率。因为每个文档的长度的差别可以很大,因而一个词在某个文档中出现的次数可能远远大于另一个文档,所以词频通常就是一个词出现的次数除以文档的总长度,相当于是做了一次归一化。
公式: T F ( t ) = 词 t 在某个文档中出现的总次数 文档的总词数 TF(t)=\frac{词t在某个文档中出现的总次数}{文档的总词数} TF(t)=文档的总词数t在某个文档中出现的总次数
IDF(inverse document frequency):逆向文件频率。用于衡量一个词的重要性/区分度。计算词频TF的时候,所有的词语都被当做一样重要的,但是某些词,比如"is","of ","that"很可能出现很多次,但是可能根本并不重要,因此我们需要减轻在多个文档中都频繁出现的词的权重。
公式: I D F = l o g e ( 语料库的总文档数 包含该词的文档数 + 1 ) IDF=log_e(\frac{语料库的总文档数}{包含该词的文档数+1}) IDF=loge(包含该词的文档数+1语料库的总文档数)
IDF越大,则说明词条具有很好的类别区分能力。
公式: T F − I D F = T F ∗ I D F TF-IDF=TF*IDF TFIDF=TFIDF

介绍下TF-IDF 的主要思想

如果某个单词在一篇文章中出现的频率 TF 高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF应用:(1)搜索引擎;(2)关键词提取;(3)文本相似性;(4)文本摘要

TF-IDF算法的不足

TF-IDF 采用文本逆频率 IDF对TF值加权,取权值大的作为关键词,但 IDF 的简单结构并不能有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能,所以 TF-IDF 算法的精度并不是很高,尤其是当文本集已经分类的情况下。
在本质上 IDF 是一种试图抑制噪音的加权,并且单纯地认为文本频率小的单词就越重要,文本频率大的单词就越无用。这对于大部分文本信息,并不是完全正确的。IDF 的简单结构并不能使提取的关键词, 十分有效地反映单词的重要程度和特征词的分布情 况,使其无法很好地完成对权值调整的功能。尤其是在同类语料库中,这一方法有很大弊端,往往一些同类文本的关键词被盖。
TF-IDF算法实现简单快速,但是仍有许多不足之处:
(1)没有考虑特征词的位置因素对文本的区分度,词条出现在文档的不同位置时,对区分度的贡献大小是不一样的。
(2)按照传统TF-IDF,往往一些生僻词的IDF(反文档频率)会比较高、因此这些生僻词常会被误认为是文档关键词。
(3)传统TF-IDF中的IDF部分只考虑了特征词与它出现的文本数之间的关系,而忽略了特征项在一个类别中不同的类别间的分布情况。
(4)对于文档中出现次数较少的重要人名、地名信息提取效果不佳。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值