来源:投稿 作者:寒武纪
编辑:学姐
首先简单摸个底:
(1)自我介绍
(2)项目介绍,问的很细,过程中不停打断提问
(3)算法竞赛项目,整体数据处理流程、模型效果评估方法、心得体会
接着问了一些八股文:
简单介绍一下 BERT 和 Transformer
-
-
BERT
是一种基于Transformer架构的预训练语言模型,由Google在2018年提出。BERT通过双向编码器来学习词汇和句子的表示,从而在各种自然语言处理任务中取得了显著的成功。
-
-
Transformer
是一种基于注意力机制的深度学习模型,由Google提出并广泛应用于自然语言处理任务。它摒弃了传统的循环神经网络(RNN)和长短时记忆网络(LSTM),采用自注意力机制实现序列建模,使得模型能够并行计算,有效地捕捉长距离依赖关系,从而提高了模型训练的效率和准确性。Transformer已经成为许多自然语言处理任务中的基础模型架构。
Attention 和 self-attention 有什么区别?
-
-
Attention
是一种机制,用于在深度学习模型中指导模型在处理序列数据时关注输入序列中的不同部分。在自然语言处理和其他序列建模任务中,Attention机制允许模型动态地分配不同权重给输入序列中的不同位置,以便模型可以集中精力处理最相关的部分。
-
-
Self-attention
(自注意力)是一种特殊形式的Attention机制,它允许模型在输入序列内部进行关注和权重分配。具体来说,对于给定的输入序列,Self-attention机制会计算序列中每个位置与其他位置之间的关联程度,然后使用这些关联程度来调整每个位置的表示。这样,每个位置的表示将受到整个序列的影响,而不仅仅是局部的上下文信息。Transformer模型中的Encoder和Decoder都使用了Self-attention机制来建模输入和输出序列之间的关系。
Transformer 的复杂度
-
-
时间复杂度:
在 Transformer 模型中,自注意力机制(self-attention)是最耗时的部分。对于长度为 N 的序列,计算自注意力需要 O(N^2) 的复杂度,因为每个位置都要考虑与其他位置的关联程度。此外,Transformer 中的位置编码、前馈神经网络等部分也会增加计算复杂度。因此,整体来说,Transformer 模型的时间复杂度通常是 O(N^2)。
-
-
空间复杂度:
Transformer 模型的空间复杂度也是比较大的,因为在计算自注意力时需要维护一个 N×N 的注意力矩阵作为中间结果,这会占用大量内存。另外,由于需要存储每个位置的表示和参数,模型的空间占用也相对较高。
Bert 用的什么位置编码,为什么要用正弦余弦来做位置编码?还知道其他哪些位置编码?
BERT使用的位置编码是正弦和余弦函数的组合,也被称为正弦余弦位置编码(Sine-Cosine Positional Encoding)。
位置编码的作用是为输入序列中的每个位置赋予一个特定的编码,以便模型能够区分不同位置的词汇。正弦和余弦函数的组合被用来做位置编码的原因有两点:
-
-
周期性:
正弦和余弦函数具有周期性,可以为不同位置产生不同的编码,并且在超出已知序列长度的位置上也能产生合理的编码。
-
-
连续性:
正弦和余弦函数的连续性使得它们能够提供平滑的位置表示,有利于模型学习长距离依赖关系。
除了正弦余弦位置编码之外,还存在其他一些位置编码的方法,例如:
-
-
绝对位置编码
(Absolute Positional Encoding):直接使用固定的向量表示每个位置的绝对位置信息。
-
-
相对位置编码
(Relative Positional Encoding):根据位置之间的相对关系来编码每个位置的位置信息,适用于序列中存在一定结构的情况。
不同的位置编码方式适用于不同的场景,选择合适的位置编码方式可以帮助模型更好地理解输入序列中不同位置的信息。
除了 bert 还做过哪些模型的微调?
SFT 监督微调、LoRA 微调方法、P-tuning v2 微调方法和Freeze 监督微调方法。
-
-
SFT
(Self-training Fine-tuning)是一项引人注目的微调方法,特别适用于解决低资源语言或领域的挑战。它采用了自监督学习的思想,可以显著减少对大量标记数据的依赖。
-
-
LoRA
(Language-oriented Data Augmentation)是一种针对自然语言处理任务的微调方法,它引入了一种语言导向的数据增强技术,以改进模型的性能。
-
-
P-tuning
是一种适用于多语言和跨语言任务的微调方法,它的目标是使模型能够在不同语言之间进行迁移学习。P-tuning v2是其改进版本,增强了模型的通用性。
-
-
Freeze
监督微调方法通常用于计算机视觉领域,不同于文本微调方法。这种方法的核心思想是冻结部分模型层,以保留模型在预训练任务中学到的特征。
为什么现在的大模型大多是 decoder-only 的架构?
目前的大型模型大多采用decoder-only架构的主要原因有几个:
-
-
自回归生成:
Decoder-only架构通常用于自回归生成任务,如机器翻译和文本生成。在这些任务中,模型需要逐步生成输出序列,而不需要同时考虑输入和输出序列的关系,因此decoder-only架构非常适合。
-
-
预训练语言模型:
近年来,预训练语言模型如GPT、GPT-2和GPT-3等都采用了decoder-only架构。这些模型通常通过自回归方式进行预训练,然后在特定任务上进行微调,取得了非常好的效果。
-
-
大规模生成任务:
在一些需要处理大规模生成任务的场景中,decoder-only架构能够更好地应对。例如,生成长篇文章、对话系统、以及代码生成等任务,decoder-only架构有助于模型更好地理解和生成复杂的输出序列。
总的来说,decoder-only架构在自回归生成任务和大规模生成任务中展现出了优秀的性能,因此在当前的大型模型中得到了广泛的应用。同时,随着自注意力机制和Transformer架构的发展,decoder-only架构也更容易实现并且易于扩展,因此受到了研究和工程领域的青睐。
讲一下生成式语言模型的工作机理
生成式语言模型是一类用于生成文本的模型,其工作机理主要涉及以下几个方面:
-
-
学习上下文信息:
生成式语言模型通过学习大量文本数据中的上下文信息,尝试捕捉词汇之间的关联性和语法结构。这通常通过使用循环神经网络(RNN)、Transformer等结构来实现。
-
-
建模概率分布:
模型学习单词序列的条件概率分布,即给定前面的单词序列,预测下一个单词的概率分布。通过学习这种概率分布,模型可以在生成文本时做出合理的选择。
-
-
采样生成文本:
在生成文本时,模型可以使用不同的策略,如贪婪搜索、束搜索(beam search)或者采样(sampling)来选择下一个单词。采样是一种常见的方法,可以根据模型预测的概率分布随机地生成下一个单词,从而增加文本的多样性。
-
-
对抗训练:
为了提高生成式语言模型的生成能力和语言流畅度,通常会使用对抗训练的方法,即通过与对抗样本进行交互,使得模型能够对输入数据进行更好的建模,从而提高生成文本的质量。
总的来说,生成式语言模型通过学习语言的概率分布和上下文信息,以及采用合适的生成策略,可以生成具有一定语义和语法正确性的文本片段。这些模型在自然语言生成、对话系统、机器翻译等任务中发挥着重要作用。
用过 LoRA 吗?讲一下原理?
LoRa(Long Range)是一种用于低功耗广域网络(LPWAN)的调制技术,它允许长距离的通信,同时具有低功耗的特点。下面是 LoRa 技术的主要原理:
-
-
调制方式:
LoRa 使用了一种称为“正交频分复用”(OFDM)的调制方式,通过在频率和时间上的正交性来实现多个子载波之间的互不干扰。这种调制方式允许在相同的频谱带宽内传输多个数据流,从而提高了通信效率。
-
-
扩频技术:
LoRa 还使用了扩频技术,即在发送数据之前对信号进行扩频,使信号在频谱上更加宽广,从而提高了信号的抗干扰能力和传输距离。LoRa 中采用的扩频因子可以根据需求进行调整,以平衡数据传输速率和通信距离之间的关系。
-
-
码率与距离:
LoRa 的调制方式和扩频技术使得它在低信噪比环境下依然能够实现较高的传输速率和长距离的通信。同时,LoRa 还可以通过调整参数来适应不同的通信距离需求,从几百米到几十公里不等。
-
-
信道管理:
LoRa 使用了自适应数据速率(ADR)和自适应扩频因子(AS)等技术来动态管理通信参数,以适应不同的通信环境和要求。这样可以在保证通信质量的同时最大程度地减少功耗。
总的来说,LoRa 技术通过采用正交频分复用调制方式、扩频技术以及灵活的参数配置,实现了低功耗、长距离的无线通信,适用于物联网、智能城市、农业监测等领域的应用。
然后,还问了一些算法题:
最大子段
最大子段(Maximum Subarray)问题是一个经典的算法问题,其目标是在一个给定的整数数组中找到一个连续的子数组,使得该子数组的元素之和最大。这个问题可以通过动态规划算法来解决,以下是一个常见的动态规划解法:
假设给定的整数数组为 nums,我们可以使用动态规划来解决最大子段问题。定义两个变量 maxEndingHere 和 maxSoFar,它们分别表示以当前元素为结尾的子数组的最大和,以及数组中任意子数组的最大和。
动态规划的状态转移方程如下:
-
-
maxEndingHere
表示以第 i 个元素结尾的子数组的最大和,可以根据前一个元素的 maxEndingHere 和当前元素的大小进行更新:maxEndingHere = max(maxEndingHere + nums[i], nums[i])
-
-
maxSoFar
表示数组中任意子数组的最大和,可以通过比较 maxEndingHere 和 maxSoFar 的大小来更新:maxSoFar = max(maxSoFar, maxEndingHere)
通过遍历整个数组并应用上述状态转移方程,最终可以得到整个数组的最大子段和 maxSoFar。
下面是一个基于动态规划的最大子段和问题的 Python 代码示例:
def maxSubArray(nums):
maxEndingHere = maxSoFar = nums[0]
for i in range(1, len(nums)):
maxEndingHere = max(maxEndingHere + nums[i], nums[i])
maxSoFar = max(maxSoFar, maxEndingHere)
return maxSoFar
通过这样的动态规划算法,我们可以在 O(n) 的时间复杂度内解决最大子段和问题,其中 n 表示数组 nums 的长度。
跳台阶
跳台阶问题是一个经典的递归和动态规划问题,在每次跳跃时可以选择跳一级台阶或者跳两级台阶,目标是计算跳上 n 级台阶有多少种不同的跳法。
这个问题可以通过递归、递推或者动态规划等多种方法来解决。下面我将分别介绍这几种方法:
-
-
递归方法:
这种方法简单直观,但是效率较低,因为存在大量的重复计算。
def jump(n):
if n == 1:
return 1
elif n == 2:
return 2
else:
return jump(n-1) + jump(n-2)
-
-
递推方法:
这种方法通过递推计算每一级台阶的跳法,避免了递归中的重复计算,效率较高。
def jump(n):
if n == 1:
return 1
elif n == 2:
return