当前位置: 首页 > news >正文

Datawhale------Tiny-universe学习笔记——Qwen

1. Qwen整体介绍

        对于一个完全没接触过大模型的小白来说,猛一听这个名字首先会一懵:Qwen是啥。这里首先解答一下这个问题。下面是官网给出介绍:Qwen是阿里巴巴集团Qwen团队研发的大语言模型和大型多模态模型系列。其实随着大模型领域的发展,这类产品已经有很多了例如:由百度开发的ERNIE,由清华大学开发的Zhuiyi等等。

        目前,Qwen已升级至Qwen2版本。无论是语言模型还是多模态模型,均在大规模多语言和多模态数据上进行预训练,并通过高质量数据进行后期微调以贴近人类偏好。Qwen具备自然语言理解、文本生成、视觉理解、音频理解、工具使用、角色扮演、作为AI Agent进行互动等多种能力。

       

        废话不多说,我们可以先看一下Qwen的整体架构。Qwen的整体架构与Llama2类似,如下图所示:742783c260624227847cc91f252ad49e.jpeg

 

        接下来我们顺着整体架构图学习,对于输入问题Text,首先会经过Tokenizer。在这里,对于没有了解过NLP的友友们又开始疑惑了:Tokenizer是啥?其实Tokenizer就是一个分词器,在这里的作用就是将问题中句子分成各个词,每一个词都对应着词表的索引,每个索引对应着一个词向量。

        接着之后生成一个input_ids,由此输入Qwen2的主干部分。

 

1.1 模型初始化

        第一部首先进行模型初始化:

class Qwen2Model(Qwen2PreTrainedModel):def __init__(self, config: Qwen2Config):super().__init__(config)self.padding_idx = config.pad_token_idself.vocab_size = config.vocab_sizeself.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)self.layers = nn.ModuleList([Qwen2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)])self.norm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)self.gradient_checkpointing = False# Initialize weights and apply final processingself.post_init()

        下面我们来解释一下这段代码:

     1.def __init__(self, config: Qwen2Config):
        super().__init__(config)

        Qwen2Model继承自Qwen2PreTrainedModelQwen2PreTrainedModel继承自PreTrainedModel。PretrainedConfig是transformers框架中所有配置类的基类。

        Qwen2PreTrainedModel是已经预训练好的模型,具体代码如下:

引自:transformers/src/transformers/models/qwen2/modeling_qwen2.py at main · huggingface/transformers · GitHub

class Qwen2PreTrainedModel(PreTrainedModel):config_class = Qwen2Configbase_model_prefix = "model"supports_gradient_checkpointing = True_no_split_modules = ["Qwen2DecoderLayer"]_skip_keys_device_placement = "past_key_values"_supports_flash_attn_2 = True_supports_sdpa = True_supports_cache_class = True_supports_quantized_cache = True_supports_static_cache = Truedef _init_weights(self, module):std = self.config.initializer_rangeif isinstance(module, nn.Linear):module.weight.data.normal_(mean=0.0, std=std)if module.bias is not None:module.bias.data.zero_()elif isinstance(module, nn.Embedding):module.weight.data.normal_(mean=0.0, std=std)if module.padding_idx is not None:module.weight.data[module.padding_idx].zero_()

 

   2.  self.padding_idx = config.pad_token_id
        self.vocab_size = config.vocab_size

        这里设置了模型的两个属性:padding_idx(用于指定填充标记的索引),vocab_size(词汇表的大小,即模型能够处理的不同token的数量)。

   

    3.  self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)

         self.layers = nn.ModuleList([Qwen2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)])
        self.norm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)

        初始化模型的嵌入层、解码器层、归一化层:

  • 嵌入层(nn.Embedding):模型使用嵌入层将输入的标记映射成密集的向量表示。config.vocab_size是词汇表的大小,config.hidden_size是嵌入向量的维度,self.padding_idx是padding token的索引。
  • 解码器层(nn.ModuleList()):模型包含多个解码器层,这些层都是由 `Qwen2DecoderLayer`` 定义。每个解码器层都是根据配置对象中的参数构建的,并且有一个索引layer_idx,它表示层在模型中的位置。
  • 归一化层 Qwen2RMSNorm:归一化层使用的是 Root Mean Square Layer Normalization

 

    4. self.gradient_checkpointing = False

        设置了是否使用 gradient_checkpoint 主要是用来节省显存。它用于控制是否使用梯度检查点技术。这是一种节省内存的技术,通过在正向传播中丢弃一些中间梯度来实现。

 

    5. self.post_init()

        调用 post_init() 完成一些初始化和准备检查的代码。post_init()代码。

 

def post_init(self):"""A method executed at the end of each Transformer model initialization, to execute code that needs the model'smodules properly initialized (such as weight initialization)."""self.init_weights()self._backward_compatibility_gradient_checkpointing()

 

1.2 forward方法

        第二步实现Qwen2Model的forward方法。在实现 Qwen2Model 的 forward 方法时,我们需要分成三个主要部分:Embedding、Hidden States 和 Decoder Layers。这一过程展示了模型的前向传播行为,即在接收输入数据后,如何计算输出结果。

        1. Embedding

        首先,对于输入的 input_ids,我们将使用 torch.nn.Embedding 进行嵌入处理。这一步负责将每个输入标识符映射到一个高维向量空间中,以便后续的处理。

        2. Hidden States

        接下来,经过嵌入处理后的向量将转化为 Hidden States。这些状态代表了输入数据的内部表示,将作为输入提供给模型的 Decoder Layers。

        3. Decoder Layers

        最后,经过前两步处理的 Hidden States 会传递到多层的 Decoder Layers 进行进一步的处理。Decoder Layers 是模型的核心部分,它们通过自注意力机制和前馈神经网络对输入进行深入处理,以生成最终的输出。

        代码如下:

引自:transformers/src/transformers/models/qwen2/modeling_qwen2.py at main · huggingface/transformers · GitHub

    @add_start_docstrings_to_model_forward(QWEN2_INPUTS_DOCSTRING)def forward(self,input_ids: torch.LongTensor = None,attention_mask: Optional[torch.Tensor] = None,position_ids: Optional[torch.LongTensor] = None,past_key_values: Optional[List[torch.FloatTensor]] = None,inputs_embeds: Optional[torch.FloatTensor] = None,use_cache: Optional[bool] = None,output_attentions: Optional[bool] = None,output_hidden_states: Optional[bool] = None,return_dict: Optional[bool] = None,cache_position: Optional[torch.LongTensor] = None,) -> Union[Tuple, BaseModelOutputWithPast]:output_attentions = output_attentions if output_attentions is not None else self.config.output_attentionsoutput_hidden_states = (output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states)use_cache = use_cache if use_cache is not None else self.config.use_cachereturn_dict = return_dict if return_dict is not None else self.config.use_return_dictif (input_ids is None) ^ (inputs_embeds is not None):raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time, and must specify either one")if self.gradient_checkpointing and self.training:if use_cache:logger.warning_once("`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`...")use_cache = Falseuse_legacy_cache = Falseif use_cache and not isinstance(past_key_values, Cache) and not self.training:use_legacy_cache = Truepast_key_values = DynamicCache.from_legacy_cache(past_key_values)logger.warning_once("We detected that you are passing `past_key_values` as a tuple and this is deprecated and will be removed in v4.46. ""Please use an appropriate `Cache` class (https://huggingface.co/docs/transformers/internal/generation_utils#transformers.Cache)")if inputs_embeds is None:inputs_embeds = self.embed_tokens(input_ids)if cache_position is None:past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0cache_position = torch.arange(past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device)if position_ids is None:position_ids = cache_position.unsqueeze(0)causal_mask = self._update_causal_mask(attention_mask, inputs_embeds, cache_position, past_key_values, output_attentions)hidden_states = inputs_embeds# create position embeddings to be shared across the decoder layersposition_embeddings = self.rotary_emb(hidden_states, position_ids)# decoder layersall_hidden_states = () if output_hidden_states else Noneall_self_attns = () if output_attentions else Nonenext_decoder_cache = Nonefor decoder_layer in self.layers:if output_hidden_states:all_hidden_states += (hidden_states,)if self.gradient_checkpointing and self.training:layer_outputs = self._gradient_checkpointing_func(decoder_layer.__call__,hidden_states,causal_mask,position_ids,past_key_values,output_attentions,use_cache,cache_position,position_embeddings,)else:layer_outputs = decoder_layer(hidden_states,attention_mask=causal_mask,position_ids=position_ids,past_key_value=past_key_values,output_attentions=output_attentions,use_cache=use_cache,cache_position=cache_position,position_embeddings=position_embeddings,)hidden_states = layer_outputs[0]if use_cache:next_decoder_cache = layer_outputs[2 if output_attentions else 1]if output_attentions:all_self_attns += (layer_outputs[1],)hidden_states = self.norm(hidden_states)# add hidden states from the last decoder layerif output_hidden_states:all_hidden_states += (hidden_states,)next_cache = Noneif use_cache:next_cache = next_decoder_cache.to_legacy_cache() if use_legacy_cache else next_decoder_cacheif not return_dict:return tuple(v for v in [hidden_states, next_cache, all_hidden_states, all_self_attns] if v is not None)return BaseModelOutputWithPast(last_hidden_state=hidden_states,past_key_values=next_cache,hidden_states=all_hidden_states,attentions=all_self_attns,)# Copied from transformers.models.llama.modeling_llama.LlamaModel._update_causal_mask

        这里内容有点多,我们看核心:

inputs_embeds = self.embed_tokens(input_ids)
# embed positions
hidden_states = inputs_embedsfor idx, decoder_layer in enumerate(self.layers):# 将所有的hidden_states保存成tupleif output_hidden_states:all_hidden_states += (hidden_states,)# 将hs送入每一层decoder_layerlayer_outputs = decoder_layer(hidden_states,attention_mask=attention_mask,position_ids=position_ids,past_key_value=past_key_value,output_attentions=output_attentions,use_cache=use_cache,)# 取出上一层decoder_输出的hs,再传入下一个layer# 只要第一个,第二个是cache的一个类,然后进入下一个layerhidden_states = layer_outputs[0]# 将最后layers输出后的hidden_states进行标准化  
hidden_states = self.norm(hidden_states)# 加上最后一层的hidden_states
if output_hidden_states:all_hidden_states += (hidden_states,)
  • 如果保存output_hidden_states的话,就是第一个为input_ids进行emb,然后保存到n-1层的decoder_layer的输出hs,再加上最后一层layer的输出hs进行过norm后的hs.
  • 最后是以BaseModelOutputWithPast的形式输出。

 

 

1.3 RMSNorm

        计算公式:

9040e8c3b3494235915b2a4352c13934.jpeg

        

其中:

  • x是层的输入的hidden_state
  • eq?w_%7Bi%7D表示的是hidden_state的最后一个维度的值
  • n 表示上面输入的最后一个维度的数量。
  • ϵ 表示是很小的数,防止除0。
class Qwen2RMSNorm(nn.Module):  # 标准化层def __init__(self, hidden_size, eps=1e-6):"""Qwen2RMSNorm is equivalent to T5LayerNorm"""super().__init__()self.weight = nn.Parameter(torch.ones(hidden_size))self.variance_epsilon = epsdef forward(self, hidden_states):input_dtype = hidden_states.dtypehidden_states = hidden_states.to(torch.float32)variance = hidden_states.pow(2).mean(-1, keepdim=True)hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)return self.weight * hidden_states.to(input_dtype)
  • torch.rsqrt表示输入的东西开根的导数。
  • .pow(2).mean(-1, keepdim=True)表示对最后一个维度平方并取均值。

 

2. Qwen2Attention 

        cf16aefd8f2f42f6a101bb5294182fb0.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 前端项目使用js将dom生成图片、PDF
  • 每日一题——第九十四题
  • Python:抓取 Bilibili(B站)评论、弹幕、字幕等
  • go 以太坊代币查余额
  • 408算法题leetcode--第六天
  • 【系统架构设计师-2015年真题】案例分析-答案及详解
  • k8s(kubernetes)的PV / PVC / StorageClass(理论+实践)
  • 梧桐数据库(WuTongDB):RBO(Rule-Based Optimizer)优化器简介
  • COTERRORSET—— LLM训练新基准让模型从自身错误中学习
  • leetcode - 分治思想
  • 前后端数据交互 笔记03(get和post方法)
  • hku-mars雷达相机时间同步方案-软件驱动(MID360与海康MV-CB060-10UMUC-S)
  • [Redis] Redis中的Hash类型和List类型
  • 【CTF Web】BUUCTF BUU UPLOAD COURSE 1 Writeup(文件上传+PHP+文件包含漏洞)
  • 泛微E10产品二开
  • C++入门教程(10):for 语句
  • CSS 提示工具(Tooltip)
  • idea + plantuml 画流程图
  • Iterator 和 for...of 循环
  • Linux下的乱码问题
  • passportjs 源码分析
  • PAT A1092
  • Protobuf3语言指南
  • python学习笔记 - ThreadLocal
  • 从0到1:PostCSS 插件开发最佳实践
  • 聊聊redis的数据结构的应用
  • 七牛云假注销小指南
  • 前端性能优化--懒加载和预加载
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 使用Swoole加速Laravel(正式环境中)
  • 函数计算新功能-----支持C#函数
  • 如何正确理解,内页权重高于首页?
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • #include<初见C语言之指针(5)>
  • (9)STL算法之逆转旋转
  • (function(){})()的分步解析
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (差分)胡桃爱原石
  • (回溯) LeetCode 78. 子集
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)Google的Objective-C编码规范
  • .mysql secret在哪_MYSQL基本操作(上)
  • .net dataexcel winform控件 更新 日志
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .Net 垃圾回收机制原理(二)
  • .NET 设计一套高性能的弱事件机制
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • @Documented注解的作用
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116