LLM大模型: llama源码要点解读(一)

news/2024/10/6 8:22:47
  transformer火了之后,基于transformer架构的llama也火了,可能的原因:
  • 来自meta,一线互联网大厂,质量有保证;自称70b参数的表现比chatGPT3还好(Llama 2:Open Foundation and Fine-Tuned Chat Models)!
  • 可能会成为大模型界的Android:各种基于llama的微调和应用会越来越多(llama的模型的参数量7B、13B、70B,凡是和这个参数量一样的的大模型,很有可能是基于llama二次改造的
  所以学习llama的源码是非常重要的(这不废话么?);整个transformer的源码在这: https://github.com/huggingface/transformers transformer里面收录所有的模型都在这: https://github.com/huggingface/transformers/tree/main/src/transformers/models 那些听说过的、没听说过的大模型在这里都能找到,当然也包括llama:https://github.com/huggingface/transformers/tree/main/src/transformers/models/llama
  llama源码不多,就这些,如下:从名字就能看出来这些文件的核心功能是啥!

       

  核心类不多,就这些:

     

     打开modeling_llama文件:

      1、第一个映入眼帘的就是归一化了:

class LlamaRMSNorm(nn.Module):def __init__(self, hidden_size, eps=1e-6):"""LlamaRMSNorm is equivalent to T5LayerNorm"""super().__init__()self.weight = nn.Parameter(torch.ones(hidden_size)) #初始化权重为1self.variance_epsilon = eps #防止分母为0def 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)

  用公式总结就是:

     

      那么问题来了:llama为啥要用RMSNorm,而不用batchNorm或layerNorm?

       3种norm方式综合对比:

  • 计算开销:RMSNorm > LayerNorm > BatchNorm。RMSNorm的计算开销最低,因为它不需要计算均值。
  • 对小批量数据的适用性:RMSNorm和LayerNorm均优于BatchNorm,适用于小批量甚至单个样本的数据。
  • 适用场景:RMSNorm和LayerNorm在序列建模、NLP以及需要处理变长输入的任务中表现更好,而BatchNorm更适合于图像处理和需要大批量数据训练的任务。
  • 训练稳定性:RMSNorm通过均方根归一化,在深层神经网络中提供了较为稳定的训练效果。

      2、(1)第二个重要的类就是MLP,有的地方也要FFN,就是常见的深度神经网络层:

class LlamaMLP(nn.Module):def __init__(self, config):super().__init__()self.config = configself.hidden_size = config.hidden_sizeself.intermediate_size = config.intermediate_size # 中间层大小self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias) #输入升维到中间层self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias) #输入升维到中间层self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=config.mlp_bias) #中间层到输出层self.act_fn = ACT2FN[config.hidden_act] #激活函数def forward(self, x):if self.config.pretraining_tp > 1:slice = self.intermediate_size // self.config.pretraining_tp  #切片gate_proj_slices = self.gate_proj.weight.split(slice, dim=0) #输入切片up_proj_slices = self.up_proj.weight.split(slice, dim=0)down_proj_slices = self.down_proj.weight.split(slice, dim=1) #输出切片gate_proj = torch.cat([F.linear(x, gate_proj_slices[i]) for i in range(self.config.pretraining_tp)], dim=-1  #每个切片并行执行线性变换后拼接)up_proj = torch.cat([F.linear(x, up_proj_slices[i]) for i in range(self.config.pretraining_tp)], dim=-1) #每个切片并行做线性变换后拼接intermediate_states = (self.act_fn(gate_proj) * up_proj).split(slice, dim=2)down_proj = [F.linear(intermediate_states[i], down_proj_slices[i]) for i in range(self.config.pretraining_tp)]down_proj = sum(down_proj)#结果相加else:down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))return down_proj

    和传统的FFN比,llama的MLP只有1点是一样的:输入通过线性变换升维到intermediate中间层,再从intermediate中间层降维到输出层!其他的差异较大,主要体现在:

  • 输入切片,并行处理
  • gate经过激活函数后继续和up相乘;整个过程图示如下:

      

     那么问题来了:为啥要把input分成gate和up,gate经过激活函数后再乘以up了?

   (2)记得10多年前大数据这个概念刚火热时,很多互联网公司利用用户的基础画像、行为数据等做搜广推。这些数据类从业人员最常用炫技的说辞之一:通过亿级的数据维度快速、精准地做推荐!当时我就纳闷了:用户画像一般有几百到几千维度,用户行为数据大概也这个量级,某些从业人员所谓的亿级别维度是哪来的?后来找了好多资料才发现,这么高维度数据的来源竟然是:特征组合!比如“女性”+“年龄” 两两组合成新维度,计算化妆品、服装等的ctr; “男性” + “运动” 两个原本独立的维度两两组合,计算体育用品、体育类视频的ctr;这只是基础特征维度的两两组合,还有三个、四个、五个、甚至更多特征维度的组合了?这么来看,基础特征组合成上亿个维度完全是有可能的!原本线性不可分的样本,经过维度组合后,产生了非线性特征,更容易区分样本,秒啊!顺着这个思路,从代数角度解释神经网络的一些特性就容易多了:

  • 为什么神经网络要用激活函数?这里的二阶到N阶,展开后不就是特征的2阶到N阶的组合么

      

  •  神经网络为什么要先维,再降维? 升维的核心是特征组合:维度提高了激活函数就多啦,组合的特征就多了,能捕捉到的非线性特征就多了!为什么又要降维了?去掉无用的特征组合

     回到llama这里来:输入为什么要分成gate和up?为什么gate经过激活函数后还要和up相乘了?

  • 激活函数:参考上述,激活函数经过tylor展开后,不就是特征的N阶组合么?
  • 和up相乘,不也是特征之间的两两组合么?

  说到底,干的这些事,最终都是做特征的各种花式组合,让线性不可分的数据产生非线性特征,为最终的分类或回归任务产生强特征

 

其他要点总结:

  1、做所有的重要操作前(包括但不限于attention、softmax等)前都要乘以一个矩阵做线性变换,所以这些操作都是在新的矩阵空间进行的,目的是和之前的旧空间隔开来,避免互相影响:每个矩阵空间只干一件事,如果要做其他事,继续通过矩阵乘法进入下一个空间操作,使得每个矩阵空间都是专用的,互不干扰(有点像每个厕所坑位只能蹲一个人,坑位之间严格隔开,避免互相影响拉便便)!

  2、特征组合让线性不可分变成线性可分举例:经典的XOR问题;整个思路很简单:现有的维度分不开了怎么办?那就生成新的能分开的维度呗!怎么生成新维度了?下面这个例子用的是旧维度两两相乘。实际生产环境,还可以N个维度互相相乘,或则N个旧维度之间线性组合(神经网络不就是这么干的嘛!)

参考:

1、https://blog.csdn.net/qq_35812205/article/details/136587013  LLM2模型

2、https://www.bilibili.com/video/BV1qj411y7kF/?spm_id_from=333.788&vd_source=241a5bcb1c13e6828e519dd1f78f35b2    transformers源码阅读——如何看懂模型代码(以llama为例)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/43062.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

[快速阅读七] Halcon里emphasize函数相关资料.

时不时有人问我我的SSE优化Demo里emphasize(边缘强调)的原理是啥,有没有写博客,其实不是我不愿意写博客,而是那个东西太过于简单,我不想写博客。但是耐不住问的人多了,我就干脆复制点资料放在博客里吧,省的每次我还要去找点资料复制给人家。时不时有人问我我的SSE优化D…

如何通过加密U盘 实现数据传输闭环管控?

加密U盘是用来保护存储在其中数据的安全的。通过加密技术,用户可以将其敏感文件和信息存储在U盘中,并设置密码或使用其他加密方法来防止未经授权的访问。这种安全措施可以防止数据泄露或盗窃,特别是在丢失或被盗的情况下,确保数据不会落入他人手中。许多不同类型的企业和组…

[Cloud Networking] Layer 2

目录1. 什么是Mac Address?2. 如何查找MAC地址?3. 二层数据交换 1. 什么是Mac Address? MAC 地址是计算机的唯一48位硬件编码,嵌入到网卡中。MAC地址也称为网络设备的物理地址,在IEEE 802中规定,数据链路层分为 逻辑链路控制(LLC)子层 和 媒体控制访问(MAC)子层。 MA…

跨国大文件传输需要哪些方面?怎么实现数据快速传输?

跨国大文件传输涉及到许多方面,包括网络速度、安全性、可靠性和法律合规性等。以下是跨国大文件传输时需要考虑的一些重要方面: 高速稳定的网络连接:确保有足够的带宽和稳定的网络连接以支持大文件的快速传输。这可能需要考虑到跨国网络的延迟和带宽限制。 1、数据加密:为了…

华为云短信服务教你用C++实现Smgp协议

本文简单对SGIP协议进行了介绍,并尝试用C++实现协议栈,但实际商用发送短信往往更加复杂,可以选择华为云消息&短信服务通过HTTP协议接入。本文分享自华为云社区《华为云短信服务教你用C++实现Smgp协议》,作者:张俭。 引言&协议概述 中国联合网络通信有限公司短消息…

老生常谈!程序员为什么要阅读源代码?

面试造航母,入职拧螺丝。相信大家对这句话的精髓都深有体会,大家好,我是码农先森。 阅读源码这是一个老生常谈的话题了,但又是很多人想做又没有付出行动的事情。前段时间我研究了 Swoole 的源代码,并且输出了系列的源码分析文章「感兴趣的朋友可以翻阅以前的文章」。虽然这…

新增汇率无法保存,提示存在生效期间重叠的记录

金蝶提示信息有误,程序中考虑了原币和目标币相反的情况,如下图。

零一科技Yi-VL 6B视觉大模型环境搭建推理

​引子 最近看新闻博客说零一科技的Yi-VL-Plus视觉大模型效果很不错,那就想着尝尝鲜。这是第四篇关于视觉大模型的博客。之前有写过一篇零一科技的chat大模型零一科技Yi-34B Chat大模型环境搭建&推理_python部署大模型yi-34b-chat-CSDN博客,感兴趣的童鞋可以移步。我个人…