NLP算法面经
前一阵子为了宁德时代的算法实习生面试准备了一些NLP算法问题,但是完全没有用上。。权当记录了。
1. 宏平均和微平均是用来干什么的?是如何计算的?他俩的主要区别?
微平均(Micro-average),是计算数据集总体的TP、FP、TN、FN (类别1、2、3……对应的TP、FP、TN、FN样例个数都分别加起来, 建立全局混淆矩阵,然后计算相应指标
宏平均(Macro-average),是先对每一个类统计指标值P、R、F1,然后在对所有类求算术平均值。
2、batch normalization与 layer normalization区别
Batch 顾名思义是对一个batch进行操作。BN是针对每一列(特征)进行缩放,例如算出【身高】的均值与方差,再对身高这一列的10个数据进行缩放。这是一种“列缩放”。
而layer方向相反,它针对的是每一行进行缩放。即只看一笔数据,算出这笔所有特征的均值与方差再缩放。这是一种“行缩放”。
NLP领域中,LN更为合适。
如果我们将一批文本组成一个batch,那么BN的操作方向是,对每句话的第一个词进行操作。但语言文本的复杂性是很高的,任何一个词都有可能放在初始位置,且词序可能并不影响我们对句子的理解。而BN是针对每个位置进行缩放,这不符合NLP的规律。
而LN则是针对一句话进行缩放的,且LN一般用在第三维度,如[batchsize, seq_len, dims]中的dims,一般为词向量的维度,或者是RNN的输出维度等等,这一维度各个特征的量纲应该相同。因此也不会遇到上面因为特征的量纲不同而导致的缩放问题。
BN 是对样本内部特征的缩放,LN 是样本直接之间所有特征的缩放。为啥BN不适合NLP 是因为NLP模型训练里的每次输入的句子都是多个句子,并且长度不一,那么 针对每一句的缩放才更加合理,才能表达每个句子之间代表不同的语义表示,这样让模型更加能捕捉句子之间的上下语义关系。如果要用BN,它首先要面临的长度不一的问题。有时候batch size 越小的bn 效果更不好。
3、BERT的主要改进,包括结构的改进,预训练方式的改进
BERT(Bidirectional Encoder Representations from Transformers)是一种预训练模型,它在自然语言处理任务中取得了显著的突破。下面是BERT的主要改进,包括结构的改进和预训练方式的改进。
1、 结构改进:
a. Transformer结构:BERT使用了Transformer作为其基础结构。Transformer是一种基于自注意力机制的深度神经网络,通过自注意力机制可以同时考虑输入序列的上下文信息,有助于捕捉长距离依赖关系。
b. 双向性:与传统的语言模型不同,BERT采用了双向性(bidirectional)预训练,即在预训练阶段使用左右两个方向的上下文信息。这使得模型可以更好地理解每个词汇在不同上下文中的含义。
c. 掩码语言模型(Masked Language Model,MLM):BERT在预训练阶段引入了掩码语言模型任务。在输入序列中,一部分词汇会被随机掩盖,模型需要预测这些被掩盖的词汇。这使得模型能够学习到词汇之间的上下文相关性。
2、预训练方式改进:
a. 大规模语料库:BERT使用了大规模的未标记数据进行预训练,如维基百科、BookCorpus等。通过更多的数据进行预训练,模型可以学习到更丰富的语言知识。
b. 无监督预训练:BERT采用了无监督预训练的方式,即仅使用未标记的语料库进行预训练,不需要依赖特定的标注任务。这样可以在不同的下游任务上进行微调,提高模型的泛化能力。
c. 预训练阶段任务:除了掩码语言模型任务,BERT还引入了句子级别的预测任务。例如,Next Sentence Prediction(NSP)任务要求模型判断两个句子是否连续,这有助于模型学习到句子之间的关系。
4、lstm参数量计算,给出emb_size和hidden_size,求lstm参数量
参数数量 = 4 × [(emb_size + hidden_size) × hidden_size + hidden_size]
有 4 个非线性变换(3 个 门 + 1 个 tanh),每一个非线性变换说白了就是一个两层的全连接网络。重点来了,第一层是xi 和 hi的结合,维度就是 embedding_size + hidden_size
,第二层就是输出层,维度为 hidden_size
,所以该网络的参数量就是:
1 |
|
一个 cell 有 4 个这样结构相同的网络,那么一个 cell 的总参数量就是直接 × 4:
1 |
|
5、简单实现一个layer normalization类,只需要实现__init__和forward就行
1 |
|
在__init__
方法中,我们定义了两个可学习的参数weight
和bias
,它们用于对归一化后的结果进行缩放和平移。features
参数表示输入的特征维度。
在forward
方法中,我们首先计算输入张量x
沿着最后一个维度的均值和方差。然后,使用归一化公式将x
进行归一化处理。最后,将缩放和平移应用到归一化后的结果上,得到最终的输出。
6、self-attention为什么要用QKV三个矩阵,不用有什么问题?有没有哪个模型的Q和K矩阵是一样的?
在自注意力机制(Self-Attention)中使用Q(查询)、K(键)和V(值)三个矩阵的主要原因是为了引入不同的线性变换,以便在不同的表示空间中计算相关性。
- 使用不同的线性变换:
- 查询(Q)矩阵:将输入序列映射到查询空间,用于计算每个位置对其他位置的注意力权重。
- 键(K)矩阵:将输入序列映射到键空间,用于表示每个位置的特征。
- 值(V)矩阵:将输入序列映射到值空间,用于根据注意力权重加权聚合信息。
通过引入这三个不同的矩阵,自注意力机制能够在不同的表示空间中对输入进行不同的变换,以便更好地捕捉输入序列中的关系和重要信息。这种机制允许模型关注输入序列的不同方面,并计算不同位置之间的相关性。
- 模型的Q和K矩阵相同: 在某些模型中,例如Transformer的Decoder端,查询(Q)和键(K)矩阵可以是相同的。这是因为在解码过程中,模型通常希望查询位置与键位置之间的相关性。因此,可以共享相同的权重矩阵来计算注意力权重。
然而,值(V)矩阵仍然是单独的,因为值矩阵用于表示每个位置的特征,不同位置的值可能具有不同的重要性。
需要注意的是,虽然在某些特定情况下可以共享权重矩阵,但通常使用不同的Q、K和V矩阵可以提供更大的灵活性和表达能力,因为它们可以捕捉到不同维度和信息的关系。
7、nlp的数据增强方法,主要有哪几种?每一种举个例子?
同义词替换;随机插入;随机删除;随机交换;随机交换
8、分类的损失函数为什么是交叉熵而不是mse?
- 输出的概率分布: 在分类任务中,我们通常希望模型的输出是一个表示不同类别的概率分布。交叉熵损失函数通过衡量模型的输出分布与真实标签的差异来指导模型的学习,鼓励模型对正确类别分配更高的概率。相比之下,MSE损失函数主要用于回归任务,对于连续值的预测更合适。
- 梯度特性: 交叉熵损失函数在分类任务中的梯度特性更有优势。它的梯度对于预测概率的错误部分是敏感的,这样可以更快地进行参数更新和收敛。相比之下,MSE损失函数的梯度相对平缓,可能会导致训练过程较慢。
- 多分类问题的适应性: 交叉熵损失函数在多分类问题中更加适应,可以很容易地扩展到多个类别。它通过计算真实标签对应类别的预测概率的对数来衡量预测的准确性。相比之下,MSE损失函数通常用于回归问题,对于多分类问题的处理可能需要进行额外的扩展。
9、BERT对输入文本的长度有什么限制,为什么要限制长度呢?
BERT对输入文本的长度有一定的限制。原始的BERT模型有一个最大输入长度限制,通常为512个标记(tokens)。这包括输入文本中的所有单词、标点符号和特殊标记(如[CLS]和[SEP]),并且对超过该长度的文本进行截断或切分。
这种限制是出于以下原因:
- 内存和计算资源的限制:较长的文本序列会占用更多的内存和计算资源来进行预训练和推理。较长的序列长度会导致显存的需求增加,可能会超出GPU的容量。为了保持模型的可训练性和效率,需要限制输入长度。
- 注意力机制的复杂性:BERT模型使用自注意力机制(self-attention)来捕捉文本中不同位置之间的关系。较长的序列长度会导致注意力权重矩阵的尺寸增大,增加计算复杂度和存储需求,使模型训练和推理变得更加困难。
- 预训练效果的稳定性:BERT的预训练阶段使用了遮蔽语言模型(Masked Language Modeling)和下一句预测(Next Sentence Prediction)任务。较长的文本序列可能会导致遮蔽任务和预测任务的效果变差,因为对于更长的文本,模型需要更长的上下文来进行预测,而预训练任务的设计是基于相对较短的序列长度的。
需要注意的是,有些变种的BERT(如BERT-Large)对输入长度的限制可能会更大一些,但仍然存在长度限制的概念。为了处理较长的文本,可以采用截断、切分或其他技术来处理输入序列,并确保关键信息尽可能地保留在模型的输入中。
10、BERT参数量计算
1. Embedding层
该层包括三种Embedding,具体是Token Embedding, Segment Embedding, Position Embedding
Token Embedding 层参数: 30522 * 768
Segment Embedding层参数:2 * 768
Position Embedding层参数: 512 * 768
因此总的参数量为:(30522 + 512 +2)* 768
2. Multi-Head Attention层
该层主要是由Q、K、V三个矩阵运算组成,BERT模型中是Multi-head多头的Self-attention(记为SA)机制。先通过Q和K矩阵运算并通过softmax变换得到对应的权重矩阵,然后将权重矩阵与 V矩阵相乘,最后将12个头得到的结果进行concat,得到最终的SA层输出。
又因为BERT模型中包含12个Transformer Encoder层,因此改层的参数总量为:[768 * (768/12) * 3 * 12 + 768 * 768 ] * 12
3. LayerNorm层
LayerNorm层主要有weight和bias两个参数。而LN层在Embedding层、Self-attention层、Feed-Forward Network层三个层都有用到,因此LN层的参数总量为:768 * 2 + (768 * 2)* 12 + (768 * 2)* 12
4. Feed-Forward Network层
前馈网络FFN主要由两个全连接层组成,且W1和W2的形状分别是(768,3072),(3072,768),层数为12,因此该层的参数量为:
(768 * 3072 + 3072 * 768)* 12
11、如果BERT词表很大,比如vocab_size达到几百万,怎么办?
处理大词表的方法有以下几种:
- 分层词汇表(Subword Tokenization):可以使用分层词汇表技术(如Byte-Pair Encoding,BPE)将词汇表分解为更小的子词单元,以便更好地处理未登录词(Out-of-Vocabulary,OOV)和稀有词。这种方法可以将大词汇表的大小控制在可管理的范围内,并提高对稀有词的处理能力。
- 动态词汇表:可以根据数据集的特点和需求,在训练或推理阶段动态地构建词汇表。只保留出现频率较高的词汇或子词单元,而将其他词汇进行替换或合并,从而减少词汇表的大小。这可以在一定程度上缓解大词汇表带来的问题。
- 采样策略:可以使用采样策略来降低训练过程中对大词汇表的依赖。例如,可以使用Negative Sampling或其他采样方法来选取部分负样本,减少模型处理大词汇表的负担。
- 基于近似方法的压缩:可以尝试使用基于近似的方法来对大词汇表进行压缩。例如,可以使用哈希函数或近似算法来降低存储和计算的复杂性,而不牺牲太多性能。
12、transformer里面为什么要加add&norm模块?好处是什么?
在Transformer模型中引入"Add & Norm"模块是为了解决两个问题:梯度传播和模型训练中的内部协变量转移(internal covariate shift)。
- 梯度传播问题: 在深层神经网络中,梯度传播可能会受到困扰,导致深层网络的梯度变得很小或很大,使得训练过程变得困难。"Add & Norm"模块中的残差连接(residual connection)可以帮助缓解这个问题。通过将原始输入与模块的输出相加,梯度可以更容易地传播回较早的层级,避免梯度消失或爆炸的情况。
- 内部协变量转移问题: 在深层神经网络中,每一层的输入分布会随着网络参数的更新而发生变化,这被称为内部协变量转移。这可能会导致网络在训练过程中难以收敛。"Add & Norm"模块中的层归一化(layer normalization)可以帮助解决这个问题。层归一化通过在每一层对输入进行归一化,使得每个维度上的特征具有相似的分布,减少了内部协变量转移的影响,提升了模型的训练稳定性和收敛速度。
因此,"Add & Norm"模块的引入具有以下好处:
- 提升梯度传播:通过残差连接,梯度可以更容易地传播回较早的层级,减少梯度消失或爆炸的问题,使得深层网络的训练更加稳定和高效。
- 缓解内部协变量转移:通过层归一化,减少了内部协变量转移的影响,帮助网络更好地学习特征表示,提高模型的训练效果和泛化能力。
13、 transformer相比lstm的优势有哪些?
相比于LSTM,Transformer模型有以下几个优势:
- 并行计算:LSTM是序列模型,需要按顺序逐步计算,导致难以进行有效的并行计算。而Transformer模型中的自注意力机制(Self-Attention)可以并行计算,使得模型的训练和推理过程更加高效。
- 长依赖建模:传统的RNN模型如LSTM在处理长序列时容易遇到梯度消失或梯度爆炸的问题,导致难以建模长期依赖关系。而Transformer模型中的自注意力机制能够直接捕捉序列中不同位置之间的依赖关系,更容易建模长序列的上下文信息。
- 全局信息获取:LSTM是逐步处理输入序列的,每个时间步只能看到有限的上下文信息。相比之下,Transformer模型中的自注意力机制能够同时考虑整个输入序列的信息,从而更好地捕捉全局上下文关系,提高模型的表达能力和理解能力。
- 参数效率:相对于LSTM,Transformer模型具有较少的参数数量。LSTM模型的参数数量与序列长度相关,而Transformer模型的参数数量与序列长度无关,使得Transformer模型更加轻量化和高效。
- 推广能力:由于自注意力机制的引入,Transformer模型在处理不仅限于文本的序列数据上表现出色。它广泛应用于自然语言处理任务,如机器翻译、文本生成、文本分类等,同时也可用于其他序列数据的建模,如音频处理、时间序列分析等。
需要注意的是,LSTM在某些任务或数据集上仍然表现出很好的性能,特别是在较短的序列或对历史状态有强依赖的任务中。选择模型应根据具体问题的需求和数据特点进行评估和选择。
14、transformer优点那么多,是不是可以淘汰lstm了,以后全用transformer?
尽管Transformer在自然语言处理任务中取得了重大的突破和成功,但并不意味着它可以完全淘汰LSTM或在所有场景下都优于LSTM。以下是一些需要考虑的因素:
- 任务和数据特点:不同的任务和数据可能对模型的要求有所不同。在某些任务中,LSTM可能仍然表现出较好的性能,特别是对于序列中存在长期依赖关系的任务。Transformer对输入序列长度的限制以及对全局上下文的建模能力可能会导致在某些情况下表现不佳。
- 计算资源:Transformer模型通常比LSTM更为复杂,具有更多的参数和计算需求。在计算资源受限的环境下,使用LSTM可能更加实际和可行。
- 数据量和标注需求:对于某些任务,特别是在数据量较小且需要大量标注的情况下,LSTM可能会更好地泛化和适应数据。Transformer模型通常需要更大规模的预训练数据和计算资源来发挥其优势。
- 模型解释性和可解释性:LSTM模型在某些情况下可能更容易解释和理解,特别是对于其逐步处理序列的方式。相比之下,Transformer模型由于其全局性质和注意力机制的复杂性,可能较难解释其决策过程。
总的来说,Transformer模型在自然语言处理领域取得了显著的突破,并且在许多任务上表现出优异的性能。然而,LSTM仍然具有其自身的优势和适用场景。选择使用哪种模型应该根据具体的任务需求、数据特点、计算资源和解释性等因素进行评估和选择。同时,随着研究的不断发展,还可能会涌现出更多改进和变体的模型,进一步推动自然语言处理的发展。
15、BERT预训练有哪些问题?后面的模型怎么改进的?
BERT的预训练也存在一些问题,其中一些问题已经在后续的模型改进中得到了改善。以下是一些BERT预训练中存在的问题以及后续模型的改进:
- 无法处理长文本:原始的BERT模型对于长文本的处理存在限制,因为BERT采用的是固定长度的输入,即使使用了截断和填充操作,也可能导致信息丢失或冗余。为了解决这个问题,后续的模型如Longformer和XLNet引入了更灵活的机制来处理长文本,通过局部和全局的注意力机制来克服输入长度的限制。
- 上下文敏感性:BERT在预训练过程中采用了Masked Language Model(MLM)任务,其中一部分输入被遮蔽,模型需要预测被遮蔽的单词。然而,这种预训练方法忽略了上下文中其他单词的信息,导致模型在处理上下文敏感的任务时可能表现不佳。为了解决这个问题,后续的模型如ALBERT和RoBERTa采用了连续文本建模(Continual Text Masking)和动态掩码策略,更好地利用了上下文信息。
- 预训练与微调不一致:在BERT中,预训练和微调阶段使用了不同的目标函数和训练策略,这导致预训练和微调之间的不一致性。后续的模型如ERNIE和MT-DNN通过一致性训练和多任务学习等方法,试图减小预训练和微调之间的差距,提升模型在下游任务上的性能。
- 训练效率和参数量:BERT模型的参数量较大,预训练和微调的计算成本较高。为了提高训练效率和模型的可用性,后续的模型如DistilBERT和TinyBERT通过模型压缩和蒸馏等方法,减小了模型的规模,同时保持了较高的性能。
16、pytorch中,dataloader dataset和sampler的关系?
在PyTorch中,DataLoader
、Dataset
和sampler
是用于数据加载和处理的重要组件,它们之间有以下关系:
Dataset
:Dataset
是一个抽象类,表示一个数据集,提供对数据的访问和操作方法。为了使用自定义数据集,需要继承Dataset
类并实现__getitem__
和__len__
方法。Dataset
类提供了对数据样本的索引和获取的功能。Sampler
:Sampler
是一个抽象类,用于定义样本的采样策略。它决定了DataLoader
在每个epoch中以什么顺序访问数据集中的样本。PyTorch提供了几种内置的sampler
,如RandomSampler
、SequentialSampler
和SubsetRandomSampler
等。此外,用户还可以自定义sampler
来满足特定需求。DataLoader
:DataLoader
是一个迭代器,用于对数据进行批次化加载。它封装了Dataset
和sampler
,并提供了许多功能,如批次大小控制、数据并行加载、多线程加载等。通过DataLoader
,可以方便地对数据进行批次化处理,提供给模型进行训练或推理。
DataLoader
使用以下方式与Dataset
和sampler
进行关联:
- 在创建
DataLoader
对象时,需要传入一个Dataset
对象作为数据源,如data_loader = DataLoader(dataset, ...)
。 - 可以通过参数
batch_size
指定每个批次的样本数量。 - 可以通过参数
sampler
指定使用的sampler
对象,默认为None
。如果未提供sampler
,则会使用默认的SequentialSampler
,按顺序遍历数据集。 DataLoader
还可以接受其他参数,如shuffle
、num_workers
、pin_memory
等,用于控制数据加载的行为和性能。
综上所述,DataLoader
通过与Dataset
和sampler
进行关联,实现了对数据集的批次化加载,并提供了便捷的数据处理和加载功能。
17、word2vec与GloVe有什么区别
Word2Vec和GloVe是两种常见的词向量表示模型,它们在训练方法和目标函数上有一些区别。
Word2Vec是一种基于神经网络的词向量模型,提出了两种训练方法:Skip-gram和CBOW(Continuous Bag-of-Words)。这两种方法都基于一个假设,即一个词的上下文信息可以用来预测该词本身(Skip-gram)或者一个词的上下文可以用来预测该词(CBOW)。Word2Vec通过训练一个浅层的神经网络,使用上下文窗口来生成词向量。在训练过程中,模型学习到的词向量可以捕捉到词之间的语义关系。
GloVe(Global Vectors for Word Representation)是一种基于全局词频统计的词向量模型。GloVe的目标是通过最小化词对的共现矩阵的差异来学习词向量,即学习到的词向量可以准确地捕捉到词之间的共现关系。GloVe使用了整个语料库的全局统计信息,通过优化一个目标函数来学习词向量。相比于Word2Vec,GloVe在训练过程中考虑了全局的词频信息,因此可以更好地捕捉到词与词之间的共现关系。
总结一下,Word2Vec和GloVe都是用于学习词向量表示的模型,但在训练方法和目标函数上有所不同。Word2Vec基于神经网络模型,通过上下文窗口来预测词或上下文,而GloVe则通过最小化词对的共现矩阵的差异来学习词向量。
18、hierarchical softmax和negative sampling
Hierarchical Softmax和Negative Sampling是两种用于解决词向量训练中的输出层问题的方法。
- Hierarchical Softmax(分层Softmax): 在传统的语言模型中,使用softmax函数来计算每个词的概率分布作为输出层。然而,当词汇表很大时,计算softmax的时间和空间复杂度很高。为了解决这个问题,Hierarchical Softmax被提出。它使用了一颗二叉树(如霍夫曼树)来表示词汇表,每个词都对应着二叉树中的一个路径。通过在树上进行二进制的分类,可以减少计算复杂度。在训练过程中,只需要计算沿着二叉树路径的概率,而不需要计算所有词的概率。这样可以大大减少计算量。
- Negative Sampling(负采样): Negative Sampling是由Mikolov等人提出的一种词向量训练方法。传统的Skip-gram或CBOW模型需要对每个训练样本计算softmax概率,这在大规模词汇表上是计算上的挑战。Negative Sampling通过只对一小部分负样本进行计算来加速训练过程。具体而言,对于每个正样本,Negative Sampling从词汇表中随机采样一些负样本(通常是根据词频进行采样),然后使用二元逻辑回归(Logistic Regression)来训练模型以区分正样本和负样本。这样可以大大减少计算量,同时还能够学习到具有区分能力的词向量。
19、常见的激活函数
常见的激活函数包括:
- Sigmoid函数(Logistic函数):将输入映射到[0, 1]的区间,常用于二分类问题或需要将输出限制在一定范围内的情况。
- Tanh函数(双曲正切函数):将输入映射到[-1, 1]的区间,相比于Sigmoid函数,Tanh函数的输出范围更广,常用于中间层的非线性变换。
- ReLU函数(修正线性单元):将负值映射为0,正值保持不变,ReLU函数简单且计算高效,常用于深度神经网络的隐藏层。
- Leaky ReLU函数:在负值区域引入一个小的斜率,避免了ReLU函数负值区域的死亡神经元问题。
- Softmax函数:将向量映射为概率分布,常用于多分类问题,将输出转化为各类别的概率。
20、P、R、F1
- P(Precision):准确率,表示分类器预测为正例的样本中有多少是真正的正例。P = TP / (TP + FP),其中 TP 表示真正例数量,FP 表示假正例数量。
- R(Recall):召回率,表示真正的正例中有多少被分类器正确地预测为正例。R = TP / (TP + FN),其中 TP 表示真正例数量,FN 表示假负例数量。
- F1:综合评价指标,是 P 和 R 的调和平均值,F1 = 2 * P * R / (P + R)。
P 和 R 的取值范围均为 [0,1],值越大表示模型效果越好。F1 的取值范围也是 [0,1],综合了准确率和召回率,用于综合评价模型的性能。
chatgpt原理
ChatGPT是基于GPT(Generative Pre-trained Transformer)的聊天型语言模型,下面简要介绍ChatGPT的原理:
- Transformer模型:ChatGPT使用了Transformer模型作为其基础架构。Transformer模型是一种基于自注意力机制(Self-Attention)的深度神经网络模型,它能够处理输入序列的上下文信息,并捕捉序列中不同位置的依赖关系。
- 预训练和微调:ChatGPT首先通过大规模的无监督预训练来学习通用的语言表示。在预训练阶段,模型使用了大量的互联网文本数据来训练,并通过预测下一个词来建模语言的统计特征。预训练完成后,ChatGPT会在特定的任务上进行微调,例如生成回答问题的聊天对话。
- 上下文编码:ChatGPT使用特殊的编码方式来表示上下文信息。对于每个对话轮次,模型会将用户的输入和历史对话进行编码,并将其转化为向量表示。这些向量会传递给模型进行下一步的生成。
- 生成策略:ChatGPT使用基于概率的生成策略,通过预测下一个词来生成回复。模型会根据当前的上下文信息和已生成的部分回复来计算每个词的概率分布,然后根据概率进行采样或选择概率最高的词作为生成的输出。
- 重复和一致性处理:为了避免生成重复或不一致的回复,ChatGPT通常会使用一些技术进行处理,例如使用历史回复的缓存来防止重复,或引入特殊的指示性标记来控制生成的风格和内容。