大数跨境
0
0

一夜之间改变大模型格局?详解LLaMa 2的技术细节:开源微调的聊天大语言模型

一夜之间改变大模型格局?详解LLaMa 2的技术细节:开源微调的聊天大语言模型 极市平台
2023-07-25
2
↑ 点击蓝字 关注极市平台
作者丨科技猛兽
编辑丨极市平台
本文首发于极市平台,转载须经授权并注明来源插入公众号名片。

极市导读

 

Llama 2-Chat 在大多数基准测试中都优于开源聊天模型,而且在帮助性和安全性上面优化得不错。值得一提的是,LLaMa 2 对其微调的方法和安全性提升的方法都做了完整的描述和介绍,有助于社区的复现并开发更多大语言模型。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

详聊LLaMa技术细节:LLaMA大模型是如何炼成的?

本文目录

1 LLaMa 2:开源微调的聊天大语言模型
(来自 Meta AI)
1.1 背景:已有的开源大语言模型还缺一步
1.2 LLaMa 2 做到了什么
LLaMa 2 预训练模型
1.3 LLaMa 2 预训练数据
1.4 LLaMa 2 模型架构
1.5 LLaMa 2 的优化
1.6 LLaMa 2 预训练模型的评测
LLaMa 2-CHAT 微调模型
1.7 LLaMa 2-CHAT 的有监督微调过程
1.8 LLaMa 2-CHAT 的人类反馈强化学习:数据收集
1.9 LLaMa 2-CHAT 的人类反馈强化学习:奖励模型
1.10 LLaMa 2-CHAT 的人类反馈强化学习:迭代微调
1.11 LLaMa 2-CHAT 模型评测

太长不看版

本文介绍来自 Meta AI 的 LLaMa 2 模型,类似于 OPT 和 LLaMa,也是一种完全开源的大语言模型。LLaMa 2 的参数量级从 7B 到 70B 大小不等。微调之后的 LLaMa 2 模型,称之为 Llama 2-Chat,针对了对话用例进行了优化。Llama 2-Chat 在大多数基准测试中都优于开源聊天模型,而且在帮助性和安全性上面优化得不错。值得一提的是,LLaMa 2 对其微调的方法和安全性提升的方法都做了完整的描述和介绍,有助于社区的复现并开发更多大语言模型。

1 LLaMa 2:开源微调的聊天大语言模型

论文名称:LLAMA 2: Open Foundation and Fine-Tuned Chat Models

论文地址:

https://ai.meta.com/research/publications/llama-2-open-foundation-and-fine-tuned-chat-models/

代码链接:

https://github.com/facebookresearch/llama

1.1 背景:已有的开源大语言模型还缺一步

大语言模型 (Large Language Models, LLM) 作为 AI 助手,显示出巨大的应用前景。作为 AI 助手,LLM 擅长复杂的推理任务 (需要领域专家的知识),同时擅长编程和创造性写作等等专业领域。AI 助手还可以通过聊天界面同人类交互,获得广泛的公众应用。

大语言模型的训练也比较繁杂,LLM 先在巨大的自监督语料库上做预训练,然后通过带有人类反馈的强化学习 (Reinforcement Learning with Human Feedback , RLHF) 技术进行微调,与人类偏好对齐。这里详细的方法介绍可以参考这里:

详解让ChatGPT听话的「魔法」!InstructGPT:训练语言模型以遵从人类指令

尽管这套训练方法看上去简单,但是实际执行起来不但需要标注大量的有监督数据,标注模型的结果排序,还需要极高的训练代价需求,将 LLM 的开发限制在少数玩家中。

反观已经开源的,可以直接使用的 LLM,比如 BLOOM[1],LLaMa[2],这些模型的性能可以做到和 GPT-3[3] 媲美,但是这些模型都不适合替代闭源的 LLM,像 ChatGPT、BARD 和 Claude。因为这些闭源的模型经历了人类指令微调的过程,与人类偏好对齐得更好,同时也可以大大提高它们的可用性和安全性。这一步在计算和人工注释中需要大量的成本,并且通常是不透明,也不易复现。这个问题限制了社区的进步,和 LLM 的相关研究。

已经开源的 LLM 其实就差这最后一步:人类指令微调的过程以对齐人类的偏好

1.2 LLaMa 2 做到了什么

LLaMa 2 其实是两种模型:LLaMa 2LLaMa 2-CHAT,分别是仅仅预训练过的模型,和预训练过之后再经过人类指令微调的模型。在一系列有用性和安全性的评测基准上,Llama 2-Chat 模型比现有的开源模型表现得更好,与一些闭源模型表现相当。

作者还对 LLaMa 2 的微调方法和提高安全性的方法进行了全面的描述,希望这种开放性能够使社区复现更多 LLM 模型,并继续提高这些模型的安全性。

LLaMa 2 开放了下面的模型,用于研究和商业用途:

  1. LLaMa 2 预训练模型:分为 7B、13B 和 70B 三种,是 LLaMa 的升级版。
  2. LLaMa 2-CHAT 微调模型:分为 7B、13B 和 70B 三种,是 LLaMa 2 微调之后的版本,主要用于对话。

LLaMa 2 预训练模型

1.3 LLaMa 2 预训练数据

LLaMa 预训练遵循 GPT-3 的自回归的范式,和 LLaMa 相比的主要变化如下图1所示。

图1:LLaMa 2 和 LLaMa 相比的主要变化

LLaMa 2 和 LLaMa 模型的参数规模基本一样,LLaMa 2 的输入度由 LLaMa 的 2k 增加到 4k,训练数据由 1.4T tokens 增加到 2.0T tokens。

预训练数据的 2.0T tokens 也都来自开源的混合数据,作者团队努力从已知包含大量关于私人个人的个人信息的某些站点中删除数据。

Tokenizer 的做法和 LLaMa 一样,是基于 SentencePieceProcessor[4],使用 bytepair encoding (BPE) 算法。

LLaMa 的 PyTorch 代码如下,用到了 sentencepiece 这个库。

class Tokenizer:
    def __init__(self, model_path: str):
        # reload tokenizer
        assert os.path.isfile(model_path), model_path
        self.sp_model = SentencePieceProcessor(model_file=model_path)
        logger.info(f"Reloaded SentencePiece model from {model_path}")

        # BOS / EOS token IDs
        self.n_words: int = self.sp_model.vocab_size()
        self.bos_id: int = self.sp_model.bos_id()
        self.eos_id: int = self.sp_model.eos_id()
        self.pad_id: int = self.sp_model.pad_id()
        logger.info(
            f"#words: {self.n_words} - BOS ID: {self.bos_id} - EOS ID: {self.eos_id}"
        )
        assert self.sp_model.vocab_size() == self.sp_model.get_piece_size()

    def encode(self, s: str, bos: bool, eos: bool) -> List[int]:
        assert type(s) is str
        t = self.sp_model.encode(s)
        if bos:
            t = [self.bos_id] + t
        if eos:
            t = t + [self.eos_id]
        return t

    def decode(self, t: List[int]) -> str:
        return self.sp_model.decode(t)

1.4 LLaMa 2 模型架构

Context Length:

LLaMa 2 的上下文窗口从 2048 个 tokens 扩展到了 4096 个 tokens。较长的上下文窗口使模型能够处理更多信息,这对于支持聊天应用程序、各种摘要任务和理解更长的文档中的较长历史特别有用。

Pre-normalization [受 GPT3 的启发,和 LLaMa 保持一致]:

为了提高训练稳定性,LLaMa 对每个 Transformer 的子层的输入进行归一化,而不是对输出进行归一化。使用 RMSNorm[5] 归一化函数。

SwiGLU 激活函数 [受 PaLM 的启发,和 LLaMa 保持一致]:

LLaMa 使用 SwiGLU 激活函数[6]替换 ReLU 非线性以提高性能,维度从 变为

Rotary Embeddings [受 GPTNeo 的启发,和 LLaMa 保持一致]:

LLaMa 去掉了绝对位置编码,使用旋转位置编码 (Rotary Positional Embeddings, RoPE)[7],这里的 RoPE 来自苏剑林老师,其原理略微复杂,感兴趣的读者可以参考苏神的原始论文和官方博客介绍:https://spaces.ac.cn/archives/8265

分组查询的注意力机制 (Grouped-Query Attention, GQA)

LLaMa 2 与 LLaMa 1 的主要架构差异包括分组查询的注意力机制 (grouped-query attention, GQA[8]),以增加输入长度。

这里就不得不提到自回归解码的标准做法,即:缓存 (Cache) 序列中先前标记的键 (K) 和值 (V) 对,以加快注意力计算。但是,随着上下文窗口或 Batch Size 大小的增加,多头注意力 (MHA) 模型中与 KV 缓存 (cache_k, cache_v) 相关的内存成本显着增加。对于更大的模型,其中 KV 缓存大小成为一个瓶颈。

之前有一些工作[9][10]研究:Key 和 Value 的投影可以跨多个 head 共享,同时不会大大降低性能。如图2所示是 Attention 架构的消融实验结果,可以观察到 GQA 变体在大多数评估任务上的表现与 MHA 基线相当,并且平均而言优于 MQA 变体。

图2:Attention 架构的消融实验结果
def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor:
    """torch.repeat_interleave(x, dim=2, repeats=n_rep)"""
    bs, slen, n_kv_heads, head_dim = x.shape
    if n_rep == 1:
        return x
    return (
        x[:, :, :, None, :]
        .expand(bs, slen, n_kv_heads, n_rep, head_dim)
        .reshape(bs, slen, n_kv_heads * n_rep, head_dim)
    )


class Attention(nn.Module):
    def __init__(self, args: ModelArgs):
        super().__init__()
        self.n_kv_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_heads
        model_parallel_size = fs_init.get_model_parallel_world_size()
        self.n_local_heads = args.n_heads // model_parallel_size
        self.n_local_kv_heads = self.n_kv_heads // model_parallel_size
        self.n_rep = self.n_local_heads // self.n_local_kv_heads
        self.head_dim = args.dim // args.n_heads

        self.wq = ColumnParallelLinear(
            args.dim,
            args.n_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wk = ColumnParallelLinear(
            args.dim,
            self.n_kv_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wv = ColumnParallelLinear(
            args.dim,
            self.n_kv_heads * self.head_dim,
            bias=False,
            gather_output=False,
            init_method=lambda x: x,
        )
        self.wo = RowParallelLinear(
            args.n_heads * self.head_dim,
            args.dim,
            bias=False,
            input_is_parallel=True,
            init_method=lambda x: x,
        )

        self.cache_k = torch.zeros(
            (
                args.max_batch_size,
                args.max_seq_len,
                self.n_local_kv_heads,
                self.head_dim,
            )
        ).cuda()
        self.cache_v = torch.zeros(
            (
                args.max_batch_size,
                args.max_seq_len,
                self.n_local_kv_heads,
                self.head_dim,
            )
        ).cuda()

    def forward(
        self,
        x: torch.Tensor,
        start_pos: int,
        freqs_cis: torch.Tensor,
        mask: Optional[torch.Tensor],
    )
:

        bsz, seqlen, _ = x.shape
        xq, xk, xv = self.wq(x), self.wk(x), self.wv(x)

        xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim)
        xk = xk.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim)
        xv = xv.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim)

        xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)

        self.cache_k = self.cache_k.to(xq)
        self.cache_v = self.cache_v.to(xq)

        self.cache_k[:bsz, start_pos : start_pos + seqlen] = xk
        self.cache_v[:bsz, start_pos : start_pos + seqlen] = xv

        keys = self.cache_k[:bsz, : start_pos + seqlen]
        values = self.cache_v[:bsz, : start_pos + seqlen]

        # repeat k/v heads if n_kv_heads < n_heads
        keys = repeat_kv(keys, self.n_rep)  # (bs, seqlen, n_local_heads, head_dim)
        values = repeat_kv(values, self.n_rep)  # (bs, seqlen, n_local_heads, head_dim)

        xq = xq.transpose(12)  # (bs, n_local_heads, seqlen, head_dim)
        keys = keys.transpose(12)
        values = values.transpose(12)
        scores = torch.matmul(xq, keys.transpose(23)) / math.sqrt(self.head_dim)
        if mask is not None:
            scores = scores + mask  # (bs, n_local_heads, seqlen, cache_len + seqlen)
        scores = F.softmax(scores.float(), dim=-1).type_as(xq)
        output = torch.matmul(scores, values)  # (bs, n_local_heads, seqlen, head_dim)
        output = output.transpose(12).contiguous().view(bsz, seqlen, -1)
        return self.wo(output)

这里 LLaMa 2 的 cache_k 和 cache_v 和 V1 相比有所不同。 

在 LLaMa 1 中,是这么写的: 

self.cache_k = torch.zeros((args.max_batch_size, args.max_seq_len, self.n_local_heads, 

self.head_dim)).cuda() 

self.cache_v = torch.zeros( (args.max_batch_size, args.max_seq_len, self.n_local_heads, 

self.head_dim)).cuda() 

维度是:(args.max_batch_size, args.max_seq_len, self.n_local_heads, self.head_dim)


在 LLaMa 2 中,是这么写的: 

self.cache_k = torch.zeros(( 

args.max_batch_size, 

args.max_seq_len, 

self.n_local_kv_heads, 

self.head_dim, 

)).cuda() 

self.cache_v = torch.zeros(( 

args.max_batch_size, 

args.max_seq_len, 

self.n_local_kv_heads, 

self.head_dim, 

)).cuda() 

维度是:(args.max_batch_size, args.max_seq_len, self.n_local_kv_heads, self.head_dim) 

注意一个是 n_local_heads,一个是 n_local_kv_heads。

1.5 LLaMa 2 的优化

优化器使用 AdamW, ,使用 cosine 学习率衰减策略,2000 步的 warm-up,最终学习率等于最大学习率的 10%,使用 0.1 的权重衰减和 1.0 的梯度裁剪。如下图3所示是以上设置下的 LLaMa 2 训练损失曲线。

图3:LLaMa 2 训练损失曲线

1.6 LLaMa 2 预训练模型的评测

评测的各种 benchmarks 可以大体归结为下面的几类:

Code: 报告在 HumanEval 和 MBPP 上的平均 pass@1 得分。

Commonsense Reasoning: 报告在 CommonsenseQA 上的 7-shot 得分,在 PIQA, SIQA, HellaSwag, WinoGrande, ARC easy and challenge , OpenBookQA 上的 0-shot 得分。

World Knowledge: 报告在 NaturalQuestions 和 TriviaQA 上的 5-shot 得分。

Reading Comprehension: 报告在 SQuAD, QuAC 和 BoolQ 上的 0-shot 得分。

MATH: 报告在 GSM8K上的 8-shot 得分,在 MATH 上的 4-shot 得分。

Popular Aggregated Benchmarks: 报告在 MMLU 上的 5-shot 得分,在 Big Bench Hard (BBH) 上的 3-shot 得分,AGI Eval 上的 3-5 shot 得分,取平均。

图4:LLaMa 2 预训练模型的评测结果

如图4所示是 LLaMa 2 预训练模型的评测结果。可以看到,LLaMa 2 模型优于 LLaMa 1 模型。特别是,与 LLaMa 1 65B 相比,LLaMa 2 70B 将 MMLU 和 BBH 的结果分别提高了大约 5 个和 8 个点。LLaMa 2-7B 和 30B 模型在除代码基准之外的所有类别上都优于相应大小的 MPT 模型。对于 Falcon 模型,LLaMa 2-7B 和 34B 在所有基准类别上都优于 Falcon-7B 和 40B 模型。此外,LLaMa 2-70B 模型优于所有开源模型。

图5:LLaMa 2 预训练模型与闭源模型相比的评测结果

除了开源模型外,作者还将 LLaMa 2-70B 结果与封闭源模型进行了比较,如图5所示。LLaMa 2-70B 在 MMLU 和 GSM8K 上接近 GPT-3.5 (OpenAI, 2023),但在编码基准上存在显着差距。LLaMa 2-70B 结果在几乎所有基准测试中都比 PaLM (540B) 相当或更好。Llama 2-70B 和 GPT-4 和 PaLM-2-L 的性能仍有很大差距。

LLaMa 2-CHAT 微调模型

LLaMa 2-CHAT 的微调过程和 InstructGPT 类似,如图5所示,大致也分为:

  • 有监督微调:Supervised Fine-Tuning (SFT)
  • 人类反馈强化学习:Reinforcement Learning with Human Feedback (RLHF)
图6:LLaMa 2-CHAT 的微调过程

Supervised Fine-Tuning (SFT) 需要注意2点:

  1. LLaMa 2 和 LLaMa 一样,也是根据[8]论文中的数据进行有监督指令微调。
  2. 微调数据的质量很关键。

Reinforcement Learning with Human Feedback (RLHF) 需要注意3点:

  1. 注重帮助性和安全性的人类偏好数据收集
  2. 注重帮助性和安全性两个奖励模型
  3. 迭代微调 (Iterative Fine-Tuning)

1.7 LLaMa 2-CHAT 的有监督微调过程

作者首先专注于收集数千个高质量的 SFT 数据,注意这里虽然只有几千条数据 (InstructGPT 13k 条),但是每一条的质量都是相当高的,作者发现这样做反而能够使得性能取得显著的提升。数据举两个例子,如图6所示。

图7:LLaMa 2 使用的高质量的 SFT 数据

1.8 LLaMa 2-CHAT 的人类反馈强化学习:数据收集

RLHF 是一种模型训练过程,应用于微调的语言模型,以进一步将模型行为与人类偏好和指令对齐。在人类偏好数据收集的过程中,标注工首先给一个 Prompt,然后从不同模型的两个回复中选择一个好的 (chosen),另一个标记为 (reject),同时记录一个比另一个好的程度:significantly better,better,slightly better,negligibly better,unsure。同时在标注数据的过程中很注重帮助性 (Helpfulness,指 Llama 2-Chat 的答复满足了用户请求的程度) 和安全性 (Safety,指Llama 2-Chat的响应是否不安全)。像 "提供有关制造炸弹的详细说明" 这种 Prompt 的标注可能会有 Helpfulness,但不满足 Safety。所以这两个目标之间可能也会有一定的矛盾点。

这一步的数据集如下图7所示,图7里面将这个数据与多个开源的数据集进行对比。Meta (Safety and Helpfulness) 代表 LLaMa 2 的 RLHF 这一步新采集的数据集,这个数据集包含大约 1.4M 个 binary comparisons。整个数据集一共包含大约 2.9M 个 binary comparisons。

与现有的开源数据集相比,LLaMa 2 的 RLHF 偏好数据具有更多的对话轮次,平均而言更长。

图8:LLaMa 2 的人类偏好数据

1.9 LLaMa 2-CHAT 的人类反馈强化学习:奖励模型

奖励模型 (Reward Model) 在 RLHF 里面也叫打分模型,它输入喂给 LLM 的 Prompt 和 LLM 的输出文本,输出一个标量的分数作为模型生成结果的质量 (一般是考虑有用性和安全性)。LLaMa 2-CHAT 的 RLHF 优化过程也使用了奖励模型,以实现更好的人类偏好对齐并提高有用性和安全性。

两个独立的奖励模型: LLaMa 2-CHAT 作者团队觉得单个奖励模型有时候难以同时满足有用性和安全性,为了解决这个问题,他们训练了两个独立的奖励模型,一个针对有用性 (称为 Helpfulness RM) 进行了优化,另一个针对安全性 (称为 Safety RM)。

两个独立的奖励模型的训练数据: Helpfulness RM 的训练数据:所有的 Meta Helpfulness 数据 + 均匀采样的 Meta Safty data,二者比例 1:1。Safety RM 的训练数据:所有的 Meta Safety 和 Anthropic Harmless 数据 + 均匀采样的 Meta Helpfulness 数据和 Open-Source Helpfulness 数据,二者比例 9:1。作者发现混入一些 Helpfulness 数据对于提升安全结果的准确性有帮助。

奖励模型的架构: LLaMa 2-CHAT 奖励模型的另一个特点是 Reward Model 和 Chat Model 有着相同的结构和超参数,只是把用于 next token prediction 的分类头替换为回归头,输出标量的奖励值。

奖励模型训练的目标函数: 采用 InstructGPT 的二元排序目标函数 (Binary Ranking Loss)

其中, 是给定的 Prompt, 是标注工 chosen 的语言模型的输出结果, 是标注工 reject 的语言模型的输出结果, 是奖励模型的输出打分。这个二元排序目标函数的意思是希望优化奖励模型的参数 , 使得它对于 chosen 的结果的打分相对于 reject 结果的打分之差越大越好。

除此之外,LLaMa 2-CHAT 奖励模型训练的目标函数还额外地加了一个 margin 的先验项,使得目标函数变成了下式:

其中, 就是对于奖励函数增加的先验项,意思是希望 chosen 比 reject 好,而且要好的多一点,多多少取决于 margin 的取值。 是一个离散函数,对于 chosen 比 reject 好的程度不同时,它取值也不同,具体如下图8所示:

图9:奖励函数增加的先验项的取值范围

比如,当 chosen 和 reject 的回复相比是 Significantly Better 时, 取值3或者1 (取决于使用大 margin 还是小 margin)。作者发现加入了 margin 之后可以进一步提升奖励模型的准确性。

奖励模型的训练策略: 奖励模型训练了 1 个 Epoch,因为作者发现训练更长会导致过拟合。使用 cosine 学习率衰减策略,3% 总步数的 warm-up,最终学习率等于最大学习率的 10%,Batch Size 为 512 个 (Prompt 和 Response 的 Pair)。

奖励模型实验结果1:测试集实验结果

评估奖励模型训练的好不好应该看它打分的准确率。作者在每个数据集上面分别 held out 1000 个数据组成测试集。测试集实验结果如下图9所示,上面的 SteamSHP-XL,Open Assistant,GPT4 是 Baseline 模型,下面的 Safety RM 和 Helpfulness RM 是本文的两个模型。

结果显示,Helpfulness 奖励模型在 Meta Helpfulness 数据集上的表现最佳,类似地 Safety 奖励模型在 Safety Helpfulness 数据集上的表现最佳。而且,LLaMa 2-CHAT 的奖励模型优于所有基线,包括 GPT-4。GPT-4 尽管没有直接训练奖励建模的任务,但是其性能仍然优于其他模型。

图10:奖励模型的测试集实验结果

还有一个结果是下面的图11,作者把测试集的数据按照 chosen 比 reject 好的多少进行了统计。比如,Safety RM 奖励模型在 Meta Safety 测试集上面,对于 chosen 比 reject "Significantly Better" 的测试集数据的精度达到了 94.3,但是同样在 Meta Safety 测试集上面,对于 chosen 比 reject "Negligibly Better/Unsure" 的测试集数据的精度只有 55.3。作者觉得这其实也很符合我们的直觉。chosen 比 reject "Significantly Better" 的测试集数据人就更容易区分优劣,所以对于打分模型而言更好学,chosen 比 reject "Significantly Better" 的测试集数据人就难以区分优劣,所以对于打分模型而言更难学。

图11:更细粒度的奖励模型的测试集实验结果

奖励模型实验结果2:缩放奖励模型和训练数据的结果

如下图12所示是缩放奖励模型和训练数据的结果,更多的数据和更大的模型通常会提高奖励模型的精度。作者也认为奖励模型的精度是 Llama 2-CHAT 最终性能的重要代理之一,其性能的改进可以直接转化为 Llama 2-CHAT 的改进。

图12:缩放奖励模型和训练数据的结果

1.10 LLaMa 2-CHAT 的人类反馈强化学习:迭代微调

LLaMa 2-CHAT 模型在经过了 1.7 小节的有监督微调 SFT 之后 (得到的模型用 SFT Policy 表示),再结合 1.8 和 1.9 小节介绍的奖励模型,做最后一步的迭代微调过程。

这个迭代过程中间经历了 RLHF-V1-RLHF-V5 这5个版本,具体可以表述为 (这里参考 郝晓田:【LLM】Meta Llama-2中RLHF的技术细节):

1) SFT Policy → 采样模型输出,标注更新奖励模型 → Rejection Sampling fine-tuning → RLHF-V1
2) RLHF-V2 → 采样模型输出,标注更新奖励模型 → Rejection Sampling fine-tuning → RLHF-V2
3) RLHF-V2 → 采样模型输出,标注更新奖励模型 → Rejection Sampling fine-tuning → RLHF-V1
4) RLHF-V3 → 采样模型输出,标注更新奖励模型 → Rejection Sampling fine-tuning → RLHF-V4
5) RLHF-V4 → 采样模型输出,标注更新奖励模型 → Rejection Sampling fine-tuning → RLHF-V5 (w/o PPO) → Proximal Policy Optimization (PPO) → RLHF-V5 (w/ PPO)

这里就涉及到了 Rejection Sampling fine-tuning 和 PPO 这俩优化算法。

Rejection Sampling fine-tuning

Rejection Sampling fine-tuning 的做法是在每一次迭代中,从上一次迭代得到的语言模型里面采样 个结果出来,使用当前时刻最好的奖励模型去给这 个结果打分,找到最好的一个结果。拿着最好的结果作为训练数据,做有监督训练 (Supervised Fine-Tuning),得到下一轮的模型。

这里作者对 KK 的影响做了一个实验: 如图13所示是对训练集中的所有 Prompts,采样 个模型输出的结果,得到奖励值的最大值和中位数。那么每个 Prompts 就可以获得一个最大值和中位数。对于所有的 Prompts 取平均,获得训练集上的平均最大值和平均中位数,画在下面。得到了不同采样数 下的训练集上的平均最大值和平均中位数。可以看到,随着采样数的上升,平均最大值和平均中位数的差距越来越大,如图12中橘黄色的阴影部分所示,这部分就可以看成是当前的模型潜在的提升空间。

图13:不同采样数下的训练集上的平均最大值和平均中位数

这里作者对语言模型 Softmax 中的 temperature 的影响做了一个实验: 如图14所示左图的曲线是: 模型使用 Llama 2-Chat-SFT, 在各种温度 个采样结果的 RM 给分最大值在整个训练集上的平均。右图的曲线是: 模型使用 Llama 2-Chat-RLHF, 在各种温度 个采样结果的 给分最大值在整个训练集上的平均。

图14:(左) 模型使用 Llama 2-Chat-SFT,在各种温度 T 的 N 个采样结果的 RM 给分最大值在整个训练集上的平均。(右) 模型使用 Llama 2-Chat-RLHF,在各种温度 T 的 N 个采样结果的 RM 给分最大值在整个训练集上的平均

可以观察到,RLHF 之后模型的最优温度和之前相比有所不同。对于 Llama 2-Chat-RLHF,在 10 到 100 个输出之间采样时的最佳温度为

Proximal Policy Optimization (PPO)

PPO 也是优化语言模型的一种目标函数,它使用奖励模型的输出作为真实奖励函数 (人类偏好) 的估计,优化以下目标:

式中, 是从数据集 里面采样的 Prompt, 是语言模型 (在 RL 里面一般称之为 Policy ) 的输出结果, 希望最大化奖励模型的输出

按照 PPO 算法的定义,最后的目标函数是:

这个式子的意思是:对于 中的每一个 Prompt , 通过语言模型 (RL 算法中的 Policy) 生成一个 回复 , 把 喂给打分模型得到分数 。通过优化语言模型的参数使得打分模型的分数越大越好。

如果给定的 Prompt者之前训练好了两个奖励模型, 分别是 Helpfulness 奖励模型 和 Safety 奖励模型 。奖励模型的定义如下式5所示:

上式的意思是:用于训练的 Prompt 里面有一些是引发潜在的不安全反应的,因此对于这些 Prompt,应该直接使用 Safety 奖励模型。或者说,如果 Safety 奖励模型的打分低于 0.15,表面当前 Prompt 也不太安全,也应该使用 Safety 奖励模型。其他情况使用 Helpfulness 奖励模型。

第2项的意思是:RL 阶段初始的模型是 , 实时更新的模型是 , 那么 PPO 算法其实是不希望这俩模型之前差距太大, 所以就给目标函数减去了一项 KL 散度, 以减轻过度优化。当 完全一样时,

优化器使用 AdamW, , 使用 constant 学习率衰减策略, 使用 0.1 的权重衰减和 1.0 的梯度裁剪。对于 7B 和 13B 的模型, , 对于 34B 和 70B 的模型,

1.11 LLaMa 2-CHAT 模型评测

评估 LLM 是一个具有挑战性的问题。人工评估虽然较准确,但是成本高,流程也相对复杂。为了节省成本和提高迭代速度,LLaMa 2-CHAT 的评测采用基于奖励模型的评测 + 人工评测方法。从 RLHF-V1 到 V5 的每次迭代过程中,首先基于最新的奖励模型的打分选择性能最佳的模型,再通过人工评估验证了主要模型版本。

基于奖励模型的评测 (Model-Based Evaluation)

为了衡量奖励模型结果和人工评测结果的一致性,作者团队搞了一个提示集,并要求三位标注工按照7分制的原则来判断答案的质量。如下图15所示是奖励模型的打分和三位标注工按照7分制的打分的关系,阴影区域代表±1标准差。图15的横轴代表三位标注工按照7分制的打分值,纵轴代表奖励模型的打分,可以看到,这二者之间大致呈正相关关系。尽管奖励模型是使用 Binary Ranking Loss 训练得到的,但它仍与人类偏好注释之间有很好的校准性。

图15:奖励模型的打分和三位标注工按照7分制的打分的关系,阴影区域代表±1标准差

如下图16所示是 LLaMa 2 的 SFT 和不同 RLHF 版本在 Safety 和 Helpfulness 这两个方面的评测结果,或者说 LLaMa 2-CHAT 模型对 ChatGPT 的胜率在多次迭代微调之后的演变结果。提示集中分别包含 1586 和 584 条 Safety 和 Helpfulness 相关的提示。左图中的法官是 LLaMa 2 的奖励模型,可能有利于 LLaMa 2。右图中的法官是 GPT-4,应该更加中性。在这组评估中,RLHF-V3 之后的两个轴上都优于 ChatGPT (Safety 和 Helpfulness 的胜率均超过了 50%)

图16:LLaMa 2 的 SFT 和不同 RLHF 版本在 Safety 和 Helpfulness 这两个方面的评测结果 (左):法官是 LLaMa 2 的奖励模型,可能有利于 LLaMa 2。(右):法官是 GPT-4,应该更加中性

人工评测 (Human Evaluation)

人工评测通常被认为是判断自然语言生成模型的黄金标准,包括对话模型。为了评估主要模型版本的质量,作者要求人工评估员在有用性和安全性上对它们进行评分。

对比的模型:开源模型有 Falcon-40B, MPT-7B, Vicuna-13B。闭源模型有:ChatGPT (gpt-3.5-turbo-0301),PaLM (chat-bison-001)。如下图17是每个模型的人工评估的最终 Prompt 数。

图17:每个模型的人工评估的最终 Prompt 数

如图18所示是大约 4,000 个 Helpfulness Prompt 下的 LLaMa 2-CHAT 模型的评估结果。LLaMa 2-CHAT 模型在单轮和多轮提示上都优于开源模型。LLaMa 2-CHAT 7B 模型在 60% 的提示上优于 MPT-7B-CHAT。LLaMa 2-CHAT 34B 与同等大小的 Vicuna-33B 和 Falcon 40B 模型的总体胜率超过 75%。最大的 LLaMa 2-CHAT 模型与 ChatGPT 相比也具有竞争力。LLaMa 2-CHAT 70B 模型胜率为 36%,与 ChatGPT 相比平局率为 31.5%。

图18:大约 4,000 个 Helpfulness Prompt 下的 LLaMa 2-CHAT 模型的评估结果

人工评测的局限性:

  • 测试集只包括 4k 个 Prompt,并没有涵盖这些模型所有的真实世界用法。
  • Prompt 的多样性可能会影响最终结果。测试集里不包含任何编码或推理相关的 Prompt。
  • 只评估多轮对话的生成结果,一种更有趣的评估方法是让模型完成一项任务,多次对模型的整体经验评分。
  • 对生成模型而言,人工评估本质上就主观且嘈杂。对不同的 Prompt 或 Instruction 的评估结果可能会不同。

参考

https://zhuanlan.zhihu.com/p/644697081

  1. BLOOM: A 176B-Parameter Open-Access Multilingual Language Model
  2. LLaMA: Open and Efficient Foundation Language Models
  3. Language models are few-shot learners
  4. Neural machine translation of rare words with subword units
  5. Root Mean Square Layer Normalization
  6. Glu variants improve transformer
  7. RoFormer: Enhanced Transformer with Rotary Position Embedding
  8. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
  9. Palm: Scaling language modeling with pathways
  10. Fast Transformer Decoding: One Write-Head is All You Need
  11. Scaling instruction-finetuned language models

公众号后台回复“极市直播”获取100+期极市技术直播回放+PPT

极市干货

极视角动态2023GCVC全球人工智能视觉产业与技术生态伙伴大会在青岛圆满落幕!极视角助力构建城市大脑中枢,芜湖市湾沚区智慧城市运行管理中心上线!
数据集:面部表情识别相关开源数据集资源汇总打架识别相关开源数据集资源汇总(附下载链接)口罩识别检测开源数据集汇总
经典解读:多模态大模型超详细解读专栏

极市平台签约作者#


科技猛兽

知乎:科技猛兽


清华大学自动化系19级硕士

研究领域:AI边缘计算 (Efficient AI with Tiny Resource):专注模型压缩,搜索,量化,加速,加法网络,以及它们与其他任务的结合,更好地服务于端侧设备。


作品精选

搞懂 Vision Transformer 原理和代码,看这篇技术综述就够了
用Pytorch轻松实现28个视觉Transformer,开源库 timm 了解一下!(附代码解读)
轻量高效!清华智能计算实验室开源基于PyTorch的视频 (图片) 去模糊框架SimDeblur



投稿方式:
添加小编微信Fengcall(微信号:fengcall19),备注:姓名-投稿
△长按添加极市平台小编

觉得有用麻烦给个在看啦~  

【声明】内容源于网络
0
0
极市平台
为计算机视觉开发者提供全流程算法开发训练平台,以及大咖技术分享、社区交流、竞赛实践等丰富的内容与服务。
内容 8155
粉丝 0
极市平台 为计算机视觉开发者提供全流程算法开发训练平台,以及大咖技术分享、社区交流、竞赛实践等丰富的内容与服务。
总阅读919
粉丝0
内容8.2k