设计一套针对熟悉ChatGLM、Llama2、Qwen等大型语言模型及其微调技术(如Prompt Engineering、P-Tuning v2、LoRA)的面试题目,旨在评估应聘者对这些模型架构的理解、微调方法的掌握程度以及在实际应用中的问题解决能力。以下是一套综合性的面试题设计方案:
模型架构概述:
描述ChatGLM、Llama2和Qwen的基本架构特点,它们各自的主要创新点是什么? 这个部分一直没找到比较好的材料 所以 只能从各个模型的代码中寻找一定的蛛丝马迹。 chatglm 提到chatglm就必须要提到glm,glm具备以下特性。
讲完了glm我们来看看chatglm是如何实现的
首先拆解ChatGLMModel
类,它是基于ChatGLMPreTrainedModel
的一个子类,主要负责实现ChatGLM模型的架构和前向传播逻辑。ChatGLM模型是一个强大的语言模型,特别设计用于中文自然语言处理任务,它支持作为编码器或解码器使用,并且能够通过添加交叉注意力层来扩展至序列到序列(Seq2Seq)模型架构。
__init__
)config
设定模型的基本结构,如隐藏层大小、注意力头数、词汇表大小等,并依据empty_init
参数选择是否采用预设的初始化方法初始化模型参数。word_embeddings
)层,用于将输入的词汇索引映射到连续的向量空间。pre_seq_len
),则会初始化一个前缀编码器,用于处理指令或提示相关的先验知识,并在训练时冻结其他参数以减少计算负担。forward
)input_ids
)或预先嵌入的向量(inputs_embeds
),同时处理位置ID(position_ids
)、注意力掩码(attention_mask
)和过去的键值对(past_key_values
)等,这些是用于实现自回归生成的关键元素。GLMBlock
组成,每个块包含多头自注意力机制和一个前馈网络,这些块按顺序处理输入序列,每一层都可以选择性地输出自注意力权重和隐藏状态。BaseModelOutputWithPastAndCrossAttentions
对象。总结来说,ChatGLMModel
类定义了ChatGLM模型的结构和行为,支持多种输入格式和配置选项,旨在适应不同的自然语言处理任务需求,特别是针对中文场景的对话和生成任务。通过精细控制注意力机制、位置编码和前缀编码等组件,模型能够在长序列上保持高效和准确的预测能力。
其次拆解chatglm的tokenizer特征分割器
用于ChatGLM模型的分词器类ChatGLMTokenizer
,继承自Hugging Face的PreTrainedTokenizer
基类,它结合了自定义的文本分词器TextTokenizer
和特定于图像的分词逻辑。下面是对主要组成部分的解析:
encode(text)
: 将文本转换为ID序列。decode(ids)
: 将ID序列转换回文本。tokenize(text)
: 返回文本的分词片段列表。num_image_tokens
。PreTrainedTokenizer
,针对ChatGLM模型进行了定制化设计。vocab_file
:SentencePiece模型的文件路径。num_image_tokens
:预留的图像令牌数量。bos_token
)、结束(eos_token
)、遮罩(mask_token
)等的定义。_tokenize(text)
:实现文本到token的转换,使用SPTokenizer
进行实际的分词工作。convert_tokens_to_string(tokens)
:将token序列转换回原始文本。_decode(token_ids)
:将ID序列解码为文本,处理填充等特殊情况。_convert_token_to_id(token)
和 _convert_id_to_token(index)
:分别将token和ID相互转换。_encode_whitespaces
和get_blank_token
方法处理文本中的多空格和制表符,使其适应模型的输入要求。综上所述,ChatGLMTokenizer
旨在提供一套完整的文本处理流程,从基础的分词到复杂的文本预处理逻辑,确保ChatGLM模型能有效理解并生成高质量的中文文本,同时也保留了处理潜在图像输入的能力(尽管这部分的具体实现细节需要进一步完善)。
网络结构
超参数
分词器(Tokenizer)
qwen观察QWenModel
的类,它是基于预训练模型QWenPreTrainedModel
的一个扩展,主要用于实现Qwen(一种大规模语言模型)的前向传播逻辑。这个模型设计用于自然语言处理任务,特别是生成式语言任务,如文本生成、对话系统等。以下是代码的关键部分解析:
__init__
)config
对象中读取并设置模型的基本参数,如词汇表大小(vocab_size
)、隐藏层数量(num_hidden_layers
)、嵌入维度(embed_dim
)等。rotary_pct
和kv_channels
计算rotary_ndims
,并初始化RotaryEmbedding
用于旋转注意力机制,这是提高长序列处理能力的一种技术。wte
)。drop
)。QWenBlock
作为变换器层(h
)。ln_f
)。use_cache_quantization
)、动态NTK(use_dynamic_ntk
)、以及序列长度限制等。forward
方法)input_ids
、inputs_embeds
、attention_mask
等,确保它们适合模型处理。QWenBlock
,执行多头自注意力和前馈网络的计算,可选地使用梯度检查点以节省内存。get_ntk_alpha
方法根据实际序列长度动态调整旋转位置嵌入的缩放因子,这有助于控制模型的复杂度和泛化能力。RotaryEmbedding
实现,这种机制在长序列上特别有效,因为它能减少注意力矩阵的复杂性,同时保留序列信息的位置敏感性。QWenBlock
类,它继承自PyTorch的nn.Module
,代表了Qwen模型中的一个基本transformer块。每个QWenBlock
包含层归一化(RMSNorm)、自注意力层(QWenAttention
)、另一个层归一化以及多层感知机(MLP,通过QWenMLP
实现)。下面是详细的解释:
__init__
方法)config
对象接收模型配置,如隐藏尺寸(hidden_size
)和层归一化epsilon值。ln_1
和 ln_2
:两个RMSNorm层,用于对输入和自注意力/MLP输出进行归一化。attn
:QWenAttention
实例,处理自注意力机制。mlp
:QWenMLP
实例,负责前馈网络部分的计算。forward
方法)hidden_states
应用第一层RMSNorm(ln_1
)。self.attn
,传入归一化后的隐藏状态、旋转位置嵌入列表(用于动态位置编码)、过去的键值对(如果缓存被启用)、注意力掩码、头部掩码等参数。hidden_states
残差连接,准备进入下一个LN层。ln_2
)。mlp
),结果与该层的输入残差连接,更新hidden_states
。use_cache=True
,则把当前层的隐藏状态和自注意力层产生的缓存(如果有)一起返回。否则,只返回更新后的隐藏状态和注意力权重(如果output_attentions=True
)。rotary_pos_emb_list
参数,支持动态的位置编码,这对于长序列理解尤其重要。综上所述,QWenBlock
类实现了transformer架构中的核心逻辑,即自注意力机制和前馈网络的组合,并通过旋转位置嵌入和特定的归一化策略进行了优化,以适应大规模语言模型的需求。
RMSNorm的类,它是PyTorch中的一个自定义层,实现了Root Mean Square (RMS) 归一化,这是一种替代Layer Normalization的归一化方法,尤其是在Transformer模型中被广泛应用。以下是代码的详细解析:
__init__
方法)dim
表示要归一化的特征维度(例如,在一个形状为(batch_size, sequence_length, hidden_size)
的张量中,dim
通常为hidden_size
),eps
是一个很小的正值,用于数值稳定性,防止除以零。weight
,形状为(dim,)
,用于在归一化后重新缩放输出。_norm
私有方法x
在指定维度(默认是最后一个维度)上的均方根,然后对每个样本除以这个值的平方根加上eps
,实现归一化。forward
方法rms_norm
函数(可能是某个C++扩展或其他优化实现)以及输入张量x
是否位于CUDA设备上。如果满足这两个条件,则直接调用该优化的rms_norm
函数执行归一化,并传入x
、权重self.weight
和eps
。_norm
方法进行归一化,然后再将结果转换回原始数据类型(通过type_as(x)
保证类型一致性),最后乘以权重self.weight
得到最终输出。RMSNorm与LayerNorm的主要区别在于,RMSNorm是在所有元素上计算均方根,而不是分别计算均值和标准差,这使得它在处理稀疏更新(如Recurrent Neural Network中的梯度计算)或非常长的序列时更加高效和稳定。此外,RMSNorm中的缩放因子是一个可学习参数,这为模型提供了一定程度的灵活性,有助于学习更复杂的表示。此自定义层的设计意图在于提升模型训练的效率和效果,尤其是在大规模语言模型中。
实现了Qwen模型中的自注意力机制。这个类设计得相当复杂,包含了多种特性,如Flash Attention加速、动态NTK(Neural Tangent Kernel)、日志尺度注意力、以及缓存量化等,以优化模型的性能和效率。下面是对关键部分的解析:
__init__
方法)config
对象中读取模型配置,如隐藏尺寸、注意力头数、投影尺寸等。c_attn
和c_proj
,分别用于从隐藏状态到查询、键、值的映射以及注意力输出到后续层的映射。_attn
方法_split_heads
和 _merge_heads
:分别用于将隐藏状态按头数分割和合并,这是多头注意力机制的基础操作。forward
方法:整合了所有步骤,包括线性变换、头分割、旋转位置嵌入(如果适用)、注意力计算、以及最终的线性变换输出。此方法还处理了过去键值对(layer_past
)的使用,以及输出注意力权重(如果output_attentions=True
)。总之,QWenAttention
类展示了Qwen模型如何在保持高度可配置性和灵活性的同时,集成了一系列创新技术来提升性能,特别是在处理大规模语言模型的场景下。
这个代码定义了一个名为 RotaryEmbedding
的类,它是一个PyTorch模块,用于在序列到序列(Seq2Seq)模型中生成旋转位置嵌入(rotary position embeddings)。旋转位置嵌入是一种用于Transformer模型中的位置编码,它通过对序列中的位置信息进行旋转处理,以提高模型的性能。
class RotaryEmbedding(torch.nn.Module):
def __init__(self, dim, base=10000):
super().__init__()
self.dim = dim
self.base = base
...
这个类继承自 torch.nn.Module
,这意味着它将继承一些基础的PyTorch功能,如参数管理、前向传播等。
def __init__(self, dim, base=10000):
super().__init__()
self.dim = dim
self.base = base
...
在初始化方法中,类首先调用父类的初始化方法,然后根据配置参数初始化模型的一些关键属性,如维度、基数等。基数用于生成旋转位置嵌入的频率。
self.dim = dim
self.base = base
self.inv_freq = ...
这里定义了模型的一些关键属性,如维度、基数、逆频率等。
def update_rotary_pos_emb_cache(self, seqlen, ntk_alpha=1.0):
if seqlen > self._seq_len_cached or ntk_alpha != self._ntk_alpha_cached:
...
这个方法用于更新旋转位置嵌入的缓存。它根据序列长度和NTK(Neural Tangent Kernel)的alpha值来更新缓存。NTK的alpha值用于调整旋转位置嵌入的频率。
def forward(self, max_seq_len, ntk_alpha=1.0):
self.update_rotary_pos_emb_cache(max_seq_len, ntk_alpha)
cos, sin = self._rotary_pos_emb_cache
return [cos[:, :max_seq_len], sin[:, :max_seq_len]]
这是模型的前向传播方法,它接受最大序列长度和NTK的alpha值作为输入,并返回旋转位置嵌入的余弦和正弦分量。这些分量将被添加到Transformer模型的输入中,以提供位置信息。
微调方法概念:
微调方案设计:
在进行微调时,我会考虑以下微调方法:Prompt Engineering、P-Tuning v2、LoRA或它们的组合。
当然我们很清楚清楚这份答案是无法满足我们的
chatglm/ptuning/deepspeed.json
{
"train_micro_batch_size_per_gpu": "auto",
"zero_allow_untested_optimizer": true,
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"initial_scale_power": 16,
"loss_scale_window": 1000,
"hysteresis": 2,
"min_loss_scale": 1
},
"zero_optimization": {
"stage": 2,
"allgather_partitions": true,
"allgather_bucket_size": 5e8,
"overlap_comm": false,
"reduce_scatter": true,
"reduce_bucket_size": 5e8,
"contiguous_gradients" : true
}
}
ptuning/deepspeed.json 配置文件的详细介绍:
train_micro_batch_size_per_gpu
:auto
表示 DeepSpeed 会自动选择一个适合当前 GPU 资源的小批量大小。zero_allow_untested_optimizer
:true
表示允许使用未经测试的优化器,这可能会带来潜在的风险。fp16
:enabled
设置为 auto
表示 DeepSpeed 会自动选择是否使用 FP16,这取决于您的 GPU 是否支持 >FP16 训练。loss_scale
, initial_scale_power
, loss_scale_window
, hysteresis
, >min_loss_scale
用于控制 FP16 训练中的损失缩放和稳定性。zero_optimization
:stage
设置为 2 表示使用 ZeRO 优化器的第二阶段,这是目前推荐的优化器。allgather_partitions
, allgather_bucket_size
, overlap_comm
, reduce_scatter
, reduce_bucket_size
, contiguous_gradients
用于控制 ZeRO 优化器的行为,如是否启用 AllGather 分区、AllGather 桶大小、是否重叠通信、是否启用 Reduce Scatter、Reduce 桶大小以及是否使用连续梯度。 LLaMA-Factory examples/deepspeed/ds_z0_config.json{
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"zero_allow_untested_optimizer": true,
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16,
"hysteresis": 2,
"min_loss_scale": 1
},
"bf16": {
"enabled": "auto"
},
"zero_optimization": {
"stage": 0,
"allgather_partitions": true,
"allgather_bucket_size": 5e8,
"overlap_comm": true,
"reduce_scatter": true,
"reduce_bucket_size": 5e8,
"contiguous_gradients": true,
"round_robin_gradients": true
}
}
配置文件的每个选项的解释:
train_batch_size
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的总批大小。train_micro_batch_size_per_gpu
:auto
表示 DeepSpeed 会自动选择一个适合当前 GPU 资源的小批量大小。gradient_accumulation_steps
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的累积步数。gradient_clipping
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的阈值。zero_allow_untested_optimizer
:true
表示允许使用未经测试的优化器,这可能会带来潜在的风险。fp16
:enabled
设置为 auto
表示 DeepSpeed 会自动选择是否使用 FP16,这取决于您的 GPU 是否支持 FP16 训练。loss_scale
, loss_scale_window
, initial_scale_power
, hysteresis
, min_loss_scale
用于控制 FP16 训练中的损失缩放和稳定性。bf16
:enabled
设置为 auto
表示 DeepSpeed 会自动选择是否使用 BF16,这取决于您的 GPU 是否支持 BF16 训练。zero_optimization
:stage
设置为 0 表示不使用 ZeRO 优化器。allgather_partitions
, allgather_bucket_size
, overlap_comm
, reduce_scatter
, reduce_bucket_size
, contiguous_gradients
, round_robin_gradients
用于控制 ZeRO 优化器的行为,如是否启用 AllGather 分区、AllGather 桶大小、是否重叠通信、是否启用 Reduce Scatter、Reduce 桶大小以及是否使用连续梯度和轮询梯度。examples/deepspeed/ds_z2_config.json
{
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"zero_allow_untested_optimizer": true,
"fp16": {
"enabled": "auto",
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16,
"hysteresis": 2,
"min_loss_scale": 1
},
"bf16": {
"enabled": "auto"
},
"zero_optimization": {
"stage": 2,
"allgather_partitions": true,
"allgather_bucket_size": 5e8,
"overlap_comm": true,
"reduce_scatter": true,
"reduce_bucket_size": 5e8,
"contiguous_gradients": true,
"round_robin_gradients": true
}
}
以下是配置文件的每个选项的解释:
train_batch_size
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的总批大小。train_micro_batch_size_per_gpu
:auto
表示 DeepSpeed 会自动选择一个适合当前 GPU 资源的小批量大小。gradient_accumulation_steps
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的累积步数。gradient_clipping
:auto
表示 DeepSpeed 会自动选择一个适合当前计算资源的阈值。zero_allow_untested_optimizer
:true
表示允许使用未经测试的优化器,这可能会带来潜在的风险。fp16
:enabled
设置为 auto
表示 DeepSpeed 会自动选择是否使用 FP16,这取决于您的 GPU 是否支持 FP16 训练。loss_scale
, loss_scale_window
, initial_scale_power
, hysteresis
, min_loss_scale
用于控制 FP16 训练中的损失缩放和稳定性。bf16
:enabled
设置为 auto
表示 DeepSpeed 会自动选择是否使用 BF16,这取决于您的 GPU 是否支持 BF16 训练。zero_optimization
:stage
设置为 2 表示使用 ZeRO 优化器的第二阶段,这是目前推荐的优化器。allgather_partitions
, allgather_bucket_size
, overlap_comm
, reduce_scatter
, reduce_bucket_size
, contiguous_gradients
, round_robin_gradients
用于控制 ZeRO 优化器的行为,如是否启用 AllGather 分区、AllGather 桶大小、是否重叠通信、是否启用 Reduce Scatter、Reduce 桶大小以及是否使用连续梯度和轮询梯度。故障诊断与优化:
P-Tuning v2 是一种用于微调语言模型的方法,它通过调整模型的参数来适应特定的下游任务。如果您在使用 P-Tuning v2 对 Qwen 进行新闻摘要任务微调时发现模型过拟合,可以采取以下措施来缓解这一问题:
请记住,缓解过拟合问题的方法可能需要根据您的具体情况和数据集进行调整。在实施任何更改之前,建议仔细分析您的数据和模型,以确定过拟合的具体原因,并针对性地采取措施。
在应用 LoRA 微调 ChatGLM 模型时,如果发现模型生成的文本相关性高但创意性不足,可以考虑以下几种策略来提升模型的创造性:
请注意,这些策略需要根据您的具体情况和数据集进行调整,并且可能需要多次尝试和优化才能找到最佳解决方案。在实施任何更改之前,建议仔细分析您的数据和模型,以确定提升创造性文本生成的具体策略。
创新应用探索:
伦理与社会影响:
这些问题不仅测试了应聘者的理论知识,还涵盖了实际操作、问题解决能力和对未来趋势的洞察力,有助于全面评估其在该领域的专业技能和潜力。