[NLP]LLaMA与LLamMA2解读

news2024/11/25 23:42:16

摘要

Meta最近提出了LLaMA(开放和高效的基础语言模型)模型参数包括从7B到65B等多个版本。最值得注意的是,LLaMA-13B的性能优于GPT-3,而体积却小了10倍以上,LLaMA-65B与Chinchilla-70B和PaLM-540B具有竞争性。

一、引言

一般而言,模型越大,效果越好。然而有文献指出[1],当给定计算量的预算之后,最好的performance,并不是最大的模型,而是在一个小模型上用更多的数据进行训练。针对给定的计算量预算,scaling laws可以计算如何选择数据量的大小和模型的大小。然而这忽略了inference的预算,而这一点在模型推理时非常关键。当给定一个模型performance目标之后,最好的模型不是训练最快的模型,而是推理最快的模型。尽管在这种情况下,训练一个更大的模型成本会更低。

文献[2]中推荐,训练一个 10B 的模型,需要 200B 的 tokens,而本文的实验发现,一个7B的模型,经过 1T tokens 训练之后,performance 仍然在增加。本文的目标在于,通过在超大规模的数据上训练,给出一系列可能最好 performance 的 LLM。

二、预训练数据

2.1 数据集

训练语料是混合的开源语料,中文占比很低,几乎不支持中文。详细占比为:CommonCrawl 67%, C4 15%, GitHub 4.5%, Wikipedia 4.5%, Books 4.5%, ArXiv 2.5%, Stack Exchange 2%.

一共有1.4T的tokens,大部分的训练数据都只用了一次,除了Wikipedia 和 Books 使用了大概2个epochs。

2.2 Tokenizer

使用byte pair encoding (BPE) 算法,使用的是Sentence-Piece的实现。所有数字被拆分为单独的digit,所有未知的UTF-8 字符,回退到字节来进行分解。因此,LLaMA 可以通过byte 的方式,构造出很多不在 vocab 中的字符,从而也具有较好的多语言能力。

三、网络结构改进

优化器

论文的模型使用AdamW优化器(Loshchilov和Hutter,2017)进行训练,具有以下超参数:

使用余弦学习率计划,使得最终学习率等于最大学习率的10%。论文使用0.1的权重衰减和1.0的梯度剪裁。使用2000个预热步骤,并随着模型的大小而改变学习率和批次大小。

使用了基于transformer的架构,并做了如下3点改进:

3.1 Pre-normalization

为了提高训练的稳定性,对每个transformer层的输入进行归一化,而不是输出进行归一化。

同时,使用 RMS Norm 归一化函数。RMS Norm 的全称为 Root Mean Square layer normalization。与 layer Norm 相比,RMS Norm的主要区别在于去掉了减去均值的部分,计算公式为:

 RMS Norm 的作者认为这种模式在简化了Layer Norm 的计算,可以在减少约 7%∼64% 的计算时间[3]。

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))
        self.variance_epsilon = eps

    def forward(self, hidden_states):
        input_dtype = hidden_states.dtype
        variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True)
        hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)

        return (self.weight * hidden_states).to(input_dtype)

3.2 SwiGLU

使用SwiGLU替代了ReLU作为激活函数。和PaLM中不同,维度采用 234� 而不是 4� 。

SwiGLU 在论文[4] 中提出,相比于其他的激活函数变体,可以取得 log-perplexity 的最优值(和 GEGLU 并列)。

class LlamaMLP(nn.Module):
    def __init__(
        self,
        hidden_size: int,
        intermediate_size: int,
        hidden_act: str,
    ):
        super().__init__()
        self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
        self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
        self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
        # config 中 hidden_act = 'silu'
        # 'silu' 和 'swish' 对应的激活函数均为:SiLUActivation 
        # https://github.com/huggingface/transformers/blob/717dadc6f36be9f50abc66adfd918f9b0e6e3502/src/transformers/activations.py#L229
        self.act_fn = ACT2FN[hidden_act]

    def forward(self, x):
        # 对应上述公式的 SwiGLU
        return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))

从代码可以看到 LlamaMLP 中一共有 3 个 Linear 层,原因就在于 SwiGLU 激活函数比类似 ReLU 的激活函数,需要多一个 Linear 层进行门控。

3.3 RoPE

RoPE 的核心思想是“通过绝对位置编码的方式实现相对位置编码”,可以说是具备了绝对位置编码的方便性,同时可以表示不同 token 之间的相对位置关系。[5] 不同于原始 Transformers 论文中,将 pos embedding 和 token embedding 进行相加,RoPE 是将位置编码和 query (或者 key) 进行相乘。具体如下:

 

# 代码增加了注释,可以看到和原始公式的对应关系。
class LlamaRotaryEmbedding(torch.nn.Module):
    def __init__(self, dim, max_position_embeddings=2048, base=10000, device=None):
        super().__init__()
        # 此处 inv_freq 对应公式中的 theta
        inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float().to(device) / dim))
        self.register_buffer("inv_freq", inv_freq)

        self.max_seq_len_cached = max_position_embeddings
        t = torch.arange(self.max_seq_len_cached, device=self.inv_freq.device, dtype=self.inv_freq.dtype)
        # 此处 freqs 对应公式中的 m * theta, t 对应公式中的 m,表示位置
        freqs = torch.einsum("i,j->ij", t, self.inv_freq)
        # Different from paper, but it uses a different permutation in order to obtain the same calculation
        # 此处和原始公式不同,theta_0 和 theta_0 不再相邻
        # 而是分在向量的前半部分和后半部分
        emb = torch.cat((freqs, freqs), dim=-1)
        dtype = torch.get_default_dtype()
        self.register_buffer("cos_cached", emb.cos()[None, None, :, :].to(dtype), persistent=False)
        self.register_buffer("sin_cached", emb.sin()[None, None, :, :].to(dtype), persistent=False)

    def forward(self, x, seq_len=None):
        # x: [bs, num_attention_heads, seq_len, head_size]
        if seq_len > self.max_seq_len_cached:
            self.max_seq_len_cached = seq_len
            t = torch.arange(self.max_seq_len_cached, device=x.device, dtype=self.inv_freq.dtype)
            freqs = torch.einsum("i,j->ij", t, self.inv_freq)
            # Different from paper, but it uses a different permutation in order to obtain the same calculation
            emb = torch.cat((freqs, freqs), dim=-1).to(x.device)
            self.register_buffer("cos_cached", emb.cos()[None, None, :, :].to(x.dtype), persistent=False)
            self.register_buffer("sin_cached", emb.sin()[None, None, :, :].to(x.dtype), persistent=False)
        # 大部分情况下,直接从这里返回
        return (
            self.cos_cached[:, :, :seq_len, ...].to(dtype=x.dtype),
            self.sin_cached[:, :, :seq_len, ...].to(dtype=x.dtype),
        )


def rotate_half(x):
    """Rotates half the hidden dims of the input."""
    # 此次和原始推导中不同,正负号不是间隔的,而是分前半部分和后半部分。但对于结果没有影响
    x1 = x[..., : x.shape[-1] // 2]
    x2 = x[..., x.shape[-1] // 2 :]
    return torch.cat((-x2, x1), dim=-1)


def apply_rotary_pos_emb(q, k, cos, sin, position_ids):
    # The first two dimensions of cos and sin are always 1, so we can `squeeze` them.
    cos = cos.squeeze(1).squeeze(0)  # [seq_len, dim]
    sin = sin.squeeze(1).squeeze(0)  # [seq_len, dim]
    cos = cos[position_ids].unsqueeze(1)  # [bs, 1, seq_len, dim]
    sin = sin[position_ids].unsqueeze(1)  # [bs, 1, seq_len, dim]
    # 对应上图中 RoPE 的简化计算
    q_embed = (q * cos) + (rotate_half(q) * sin)
    k_embed = (k * cos) + (rotate_half(k) * sin)
    return q_embed, k_embed

四、高效实现

加速训练:

  • 使用 随机多头注意力机制(causal multi-head attention) 提高模型的训练速度。该机制的实现借用了xformers库,它的思路是不存储注意力权重,不计算其中注意力得分
  • 手动实现了Transformer的激活函数,而没有用pytorch库的autograd,以得到更优的训练速度。同时使用了并行化技术提高训练速度。
  • 减少了activation checkpointing 中,重新计算 activation 的计算量。手动实现 transformer 层的反向传递函数,保存了计算成本高的 activations,例如线性层的输出。
  • 通过使用 model parallelism 和 sequence parallelism 来减少显存的使用量。
  • 尽可能地将 activations 的计算和GPU之间的通讯进行并行。

加速效果:

  • 65B的模型,在2048个80G的A100 GPU上,可以达到380 tokens/sec/GPU的速度。训练1.4T tokens需要21天。

五、主要结果与结论

LLaMA-13B 优于 GPT-3,尽管只有1/10大小。 LLaMA-65B 是可以与 Chinchilla-70B 和 PaLM-540B 这种最佳的LLM相竞争的模型。经过微调之后,LLaMA的效果有显著的提升。

未来打算发布在更大的语料上预训练上的更大的模型,因为随着数据和模型的增大,可以看到 performance 的稳定提升。

五、高效实现

LLaMA2的开源地址:https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md

LLaMA2的下载地址:https://ai.meta.com/resources/models-and-libraries/llama-downloads/

LLaMA2的官方博客地址:https://ai.meta.com/resources/models-and-libraries/llama/

技术细节记录

  1. 模型尺寸:LLaMA 2提供了三种不同的模型尺寸:7B、13B和70B。其中,7B和13B的架构与LLaMA 1相同,可直接用于商业应用。
  2. 训练:LLaMA 2模型经过了2万亿个标记的训练,其上下文长度是LLaMA 1的两倍。此外,LLaMA-2-chat模型还接受了超过100万个新的人类注释的训练。LLaMA 2的训练语料比LLaMA 1多出40%,上下文长度从2048增加到4096,使其能够理解和生成更长的文本。
  3. 预训练:LLaMA 2使用公开的在线数据进行预训练,然后通过监督微调创建LLaMA-2-chat的初始版本。接下来,LLaMA-2-chat使用人类反馈强化学习(RLHF)进行迭代细化,其中包括拒绝采样和近端策略优化(PPO)。
  4. 模型架构:LLaMA 2采用了LLaMA 1的大部分预训练设置和模型架构,使用标准Transformer架构,使用RMSNorm应用预归一化、使用SwiGLU激活函数和旋转位置嵌入RoPE。与LLaMA 1的主要架构差异包括增加了上下文长度和分组查询注意力(GQA)。
  5. 分组查询注意力(GQA):这是一个新的注意力机制,可以提高大模型的推理可扩展性。它的工作原理是将键和值投影在多个头之间共享,而不会大幅降低性能。可以使用具有单个KV投影的原始多查询格式(MQA)或具有8KV投影的分组查询注意力变体(GQA)。
  6. 超参数:使用AdamW优化器进行训练,其中β1=0.9,β2=0.95,eps=10−5。使用余弦学习率计划,预热2000步,衰减最终学习率降至峰值学习率的10%。使用0.1的权重衰减和1.0的梯度裁剪。
  7. 分词器:LLaMA 2使用与LLaMA 1相同的分词器;它采用字节对编码(BPE)算法,使用SentencePiece实现。与LLaMA 1一样,将所有数字拆分为单独的数字,并使用字节来分解未知的UTF-8字符。总数词汇量为32k个token。
  8. 微调:LLaMA 2-Chat是数月实验研究和对齐技术迭代应用的结果,包括指令微调和RLHF,需要大量的计算和数据标注资源。有监督微调指令数据质量非常重要,包括多样性,注重隐私安全不包含任何元用户数据。
  9. 安全性:该研究使用三个常用基准评估了Llama 2的安全性,针对三个关键维度:真实性,指语言模型是否会产生错误信息,采用TruthfulQA基准;毒性,指语言模型是否会产生「有毒」、粗鲁、有害的内容,采用ToxiGen基准;偏见,指语言模型是否会产生存在偏见的内容,采用BOLD基准。

参考

  1. Training Compute-Optimal Large Language Models https://arxiv.org/abs/2203.15556
  2. ^Training Compute-Optimal Large Language Models https://arxiv.org/abs/2203.15556
  3. ^Root Mean Square Layer Normalization https://arxiv.org/pdf/1910.07467.pdf
  4. ^GLU Variants Improve Transformer https://arxiv.org/pdf/2002.05202.pdf
  5. ^Transformer升级之路:2、博采众长的旋转式位置编码 Transformer升级之路:2、博采众长的旋转式位置编码 - 科学空间|Scientific Spaces
  6. ^https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py#L91

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

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

相关文章

IT 资产管理功能

ServiceDesk Plus 支持ITIL流程,帮助管理员制定明智的业务决策,在整个生命周期中跟踪所有资产的硬件和软件。 ServiceDesk Plus 中的资产管理模块包含多种功能,例如:多种扫描资产的方法;基于代理和无代理的方法&#…

新老联手,火花四溅?大众汽车与小鹏汽车达成长期合作框架协议

7 月 26 日资讯,大众汽车宣布与小鹏汽车达成长期合作框架协议,并在官网中正式宣布,大众是老牌油车领军代表,小鹏则是新势力中的佼佼者,新老强强联手,又会碰撞出怎样的火花呢? 现阶段大众计划与…

凭借一份深入解析 Java 虚拟机 HotSpot 手册,让我卷成美团架构师

前言 Java 语言已经走过了 20 多个年头,在此期间虽然新语言层出不穷,但是都没有撼动 Java 的位置。可能是历史选择了 Java,也可能是 Java 改变了历史,总之,Java 无疑是一门成功的编程语言。这门语言之所以能如此成功&…

MODBUS RTU转 EtherNet/IP 网关连接森兰变频器与欧姆龙系统通讯配置案例

捷米特JM-EIP-RTU(Modbus转Ethernet/Ip)网关,用于将多个 MODBUS 从站设备接入 ETHERNET/IP 主站网络,实现 MODBUS 转 ETHERNET/IP 功能。配上 捷米特JM-EIP-RTU网关专用的 EDS 文件,实现 ETHERNET/IP 主 站对 MODBUS 从站设备的控…

Java多线程锁

多线程锁 本专栏学习内容又是来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 Synchronized Synchronized是Java中锁的一种实现方法,我们需要了解他锁在什么地方,锁的类型有哪些 阿里巴巴开发手册规定: 高并发时,同…

大语言模型LLM技术赋能软件项目管理和质量保障︱微软中国高级研发经理步绍鹏

微软中国高级研发经理步绍鹏先生受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾,演讲议题:大语言模型LLM技术赋能软件项目管理和质量保障。大会将于8月12-13日在北京举办,敬请关注! 议题内容简要: 本次分享将…

809 协议相关

809 协议 目录概述需求: 设计思路实现思路分析1.概念2.业务流程3.详细过程4.相关过程 参考资料 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,ch…

Windows上安装Docker Desktop

运行环境 Windows 10Docker Desktop 4.21.1 安装步骤 步骤1: 勾掉"Use WSL 2 instead of Hyper-V(recommended)"(原因见小插曲2章节) 步骤2: 安装完成 步骤3: 运行Docker Desktop 步骤4: …

面试了无数家公司整理的软件测试面试题【含答案】

1、自动化代码中,用到了哪些设计模式? 单例设计模式 工厂模式PO设计模式数据驱动模式面向接口编程设计模式 2、什么是断言( Assert) ? 断言Assert用于在代码中验证实际结果是不是符合预期结果,如果测试用例执行失败会抛出异常并提供断言日志 3、什么是web自动化测…

STM32 串口实验(学习一)

本章将实现如下功能:STM32通过串口和上位机对话,STM32在收到上位机发过来的字符串后,原原本本返回给上位机。 STM32 串口简介 串口作为MCU的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。现在基本…

centos7设置网桥网卡

安装bridge-utils yum install bridge-utils修改ens33 网卡 TYPEEthernet BOOTPROTOnone DEFROUTEyes IPV4_FAILURE_FATALno IPV6INITyes IPV6_AUTOCONFyes IPV6_DEFROUTEyes IPV6_FAILURE_FATALno NAMEens33 UUID04b97484-25c8-45c7-8c8c-e335e8080e10 DEVICEens33 ONBOOTye…

TEE GP(Global Platform)认证方案

TEE之GP(Global Platform)认证汇总 一、GP认证方案 二、GP认证方案分类 参考: GlobalPlatform Certification - GlobalPlatform

【读书笔记】《生命册》- 李佩甫 - 2012年出版

不停的阅读,然后形成自己的知识体系。 2023.07. 读 《生命册》是河南作家李佩甫于2012年发表的长篇小说,作家出版社发行,全书共12章约38万字,与之前发表的《羊的门》、《城的灯》组成“平原三部曲”,2015年获得第九届…

恶意软件已渗透商业环境,超40万个企业凭证被窃取

网络安全公司 Flare 与 BleepingComputer 分享的一份报告显示,在对暗网和 Telegram 渠道上出售的近 2000 万条泄密数据日志进行分析后,发现信息窃取恶意软件已实现了对商业环境的严重渗透。 信息窃取程序是一种恶意软件,可窃取存储在 Web 浏…

Jmeter 测试 JMS (Java Message Service)/ActiveMQ 性能

目录 前言 ActiveMQ 介绍 准备工作 编写jndi.properties添加到ApacheJMeter.jar 中 下载 ActiveMQ 配置 Jmeter 进行测试 点对点 (Queues 队列) 配置 Jmeter 进行测试 发布/订阅 (Topic 队列) 配置发布 Publisher 配置订阅 Subscriber 总结 前言 在进行性能测试时&a…

Java API文档工具:小白如何游刃有余编写Java中的API使用手册?

Java API文档工具:小白如何游刃有余编写Java中的API使用手册? 对于初学者来说,Java API文档是解决问题和学习语言的重要工具。本文将介绍Java API文档工具的使用方法,帮助小白们轻松编写出优秀的API使用手册,供日后的…

PaaS低代码平台源码:预置3000+应用集成插件,强大的建模引擎,快速构建自己的应用程序和流程

低代码PaaS平台是一款基于 Salesforce Platform 的开源替代方案,支持多种企业应用场景,包括但不限于CRM、ERP、OA、BI、IoT、大数据等。无论是传统企业还是新兴企业,都可以使用管理后台快速构建自己的应用程序和流程。 技术架构:微…

【软件测试】单元测试工具---Junit详解

1.junit 1.1 junit是什么 JUnit是一个Java语言的单元测试框架。 虽然我们已经学习了selenium测试框架,但是有的时候测试用例很多,我们需要一个测试工具来管理这些测试用例,Junit就是一个很好的管理工具,简单来说Junit是一个针对…

emacs打开git仓库下多个子工程的根目录问题解决案

emacs打开git仓库下多个子工程的根目录问题解决案 问题描述 如题所述,这个问题困扰我很久了,一直没搜到完整的解决方案。这次终于乘着空闲时间,研究了projectile.el源码找到了方案。 问题场景具体描述下: 我自己有一个私人git仓库&#x…

CISA学习笔记-第一章、信息系统审计过程

传统的审计三方关系理论指明,审计作为独立于会计记录之外的一项重要职能,是公司财务信息公允可靠的有力保障,制约着会计行为,制衡了会计权力。 1. IS审计和保障标准、指南、工具 职业道德规范 信息技术保证框架(ITAF&a…