Llama1-3 🦙:从一道美团大模型面试题讲起

从 LLaMA1 到 LLaMA3:这风云激荡的 2023 到 2024 年

这篇博客应当是我在 2025 年的首篇博客。24 年底,在我身上发生了很多意想不到的事情,总使我灰心丧气。忽然间,发觉自己除开写了十几个月的日记,并没有更多新的更新。前不久,在 B 站上看到名为 美团大模型面试真题:LLaMA怎么优化注意力机制计算? 的视频,我才惊觉时光飞逝。

于是想着,似乎应当写一篇详解 LLaMA 的博客出来。等到调查资料的时候,发现 LLaMA 原来早在 2023 年就已发布,且已到第三代。估计第四代就将在 2025 年发布吧?看来这篇博客实在是拖延不得了!

又:长久以来我总计划开设“NLP 经典论文”专区,整理自 2017 年以来“重点文”,不妨就以此篇作始吧!

2023 到 2024 年:从无到有,由弱及强

2023 到 2024 年,metaAI 先后发布 LLaMA1 到 LLaMA3 的论文。LLaMA 系列从无到有、由弱及强,成功跻身大语言模型先锋军之中。2023 也由此可以称作 LLaMA 元年

版本模型结构训练数据
规范化激活函数位置编码GQATokens上下文长度Vocab Size
LLaMA1RMSNormSwiGLURoPE1.4T2K32K
LLaMA2RMSNormSwiGLURoPE2.0T4K32K
LLaMA3RMSNormSiLURoPE15.0T8K128K

在模型结构上,LLaMA 自 1 代至 3 代总体改动较小,其中比较关键的技术是:RMSNormRoPEGQALLaMA 的迭代更新主要得力于 metaAI 不断扩充的优质语料库:

  • 自 1 代到 3 代,语料库的总 Token 量从 1.4T 上升至 15T;
  • 词汇表大小也从最初的 32K 扩充至 128K;
  • 预训练的上下文长度从 2K 增加到 4K,再到现在的 8K。

在模型参数量上,三代 LLaMA 总体呈现上升趋势:

  • LLaMA1 分别具有 7B、13B、33B、65B 等版本;
  • LLaMA2 与 1 代比差距不大,包括 7B、13B、34B、70B 等;
  • LLaMA3 的参数量则显著提升,主要是 8B、70B 甚至 405B 等。

LLaMA 是如何优化注意力机制的?

回到我们的话题上来:LLaMA 是如何优化注意力机制的? 事实上,LLaMA 在模型架构上大体仍沿用 (Vanilla,2017) 提出的 Transformer,而进行了许多微小的改动。我根据自身对原论文的理解,认为其中比较重要的三个技术是:RMSNormRoPEGQA。这些技术是什么意思?它们为什么能优化注意力机制?接下来对其进行详细讲解。

RMSNorm:在不牺牲模型稳定性的同时降低计算复杂度

原始的 Transformer 使用的是 层规范化 (LayerNorm) 。之所以引入规范化,是希望模型中间层的输入分布始终保持稳定。具体来说,它对输入 (假设 是长度为 的序列,每个词向量取第 个维度)进行如下操作:

而 RMSNorm,或称 均方根规范化 就是 LayerNorm 的变体,RMSNorm 省去了求均值的过程,也没有了偏置

首先,在计算上:RMSNorm 相比 LayerNorm 更为简便。其次,在效果上:容易看出 RMSNorm 具有对输入缩放的不变性(),一定程度上也能够稳定输入分布。最后,RMSNorm 并不保证输出的均值为 0。实验证明,该性质对模型的训练影响较小。

RoPE:以简便方式有效捕捉相对位置信息

LLaMA 在每个 Attention 层中分别对 进行 旋转位置编码 (RoPE, Rotary Postion Embedding) 具体来说,是在 点积之前对 分别编码。以下是部分 metaAI 官方给出的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Attention(nn.Module):
def forward(self, x, ...):
bsz, seqlen, hidden_dim = 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)

# 对 Q 和 K 施用旋转位置编码
xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)

... # 此处省略部分代码

# 对 Q 和 K 求点积并缩放
scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim)
PYTHON

那么,什么是 旋转位置编码 ?RoPE 原论文的说法是:“在RoPE中,我们的出发点就是 通过绝对位置编码的方式实现相对位置编码 。”也即,我们考虑:

  • 假设我们有编码操作 ,分别对 的第 维向量 的第 维向量 进行位置编码:
  • 那么在 Attention 中对 求点积时,我们希望 的内积结果将带入 这个 相对位置信息 (m-n 将影响内积结果)
  • 原论文经过复实变换得到了操作 的解:
    • . 其中 为虚数单位, 为给定超参。
    • 根据复数乘法的几何意义,该变换实际上对应着向量的旋转(我们可以想象二维向量)。
  • 最后,我们可以将 的完整形式表现如下(假设 维向量):
    • 其中,,这带来一定的远程衰减性。
    • 是逐位对应相乘,即Numpy、Tensorflow等计算框架中的 运算。
    • 从这个实现也可以看到,RoPE可以视为是乘性位置编码的变体。

最后在这里贴一份 metaAI 官方写的代码,以便更加直观地看到 RoPE 操作是如何实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0):
freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
t = torch.arange(end, device=freqs.device) # type: ignore
freqs = torch.outer(t, freqs).float() # type: ignore
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
return freqs_cis

def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
ndim = x.ndim
assert 0 <= 1 < ndim
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
return freqs_cis.view(*shape)

def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
freqs_cis = reshape_for_broadcast(freqs_cis, xq_)
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
PYTHON

GQA:减少 KV-Cache 大小以提升模型推理速度

引入 GQA 前先简单介绍下 KV-Cache

提高大模型推理速度的常用关键技术是 KV-Cache。大模型以 自回归 (auto regressive) 的方式推理,预测下个 token 时,总是基于之前已经生成的序列。从代码的角度来理解是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
inputs = "这是初始的输入序列"

while not stop:
# 根据之前的序列预测下个 token
next_token = model(inputs)

# 如果下个 token 是休止符,退出
# 否则,将 token 加入序列进行下次预测
if next_token == '[SEP]':
stop = True
else:
inputs += next_token

outputs = inputs
PYTHON

显然,随着输入序列越来越长,每次都重新计算所有 token 注意力值的传统方法显得非常低效。针对该问题,KV-Cache 采用 空间换时间 的方法:在自回归过程中,开辟空间将每次计算的 缓存起来,这样在处理新序列时只需从缓存中读取之前的 ,无需重复计算。LLaMA 中的代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Attention(nn.Module):
def __init__(self, ...):
super().__init__()
... # 此处省略部分代码

# 开辟 cache_k 用于缓存 k
self.cache_k = torch.zeros(
(
args.max_batch_size,
args.max_seq_len,
self.n_local_kv_heads,
self.head_dim,
)
).cuda()
# 开辟 cache_v 用于缓存 v
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, ...):
... # 此处省略部分代码

# 将缓存置于 xq 所在的计算单元(CPU 或 CUDA)
self.cache_k = self.cache_k.to(xq)
self.cache_v = self.cache_v.to(xq)

# 将当前计算出的 K 与 V 缓存起来
# 缓存位置是从 start_pos 到 start_pos + seqlen
# start_pos 是上次缓存后的序列长度
# seqlen 是此次新增的子序列长度,KV-Cache 并非逐字缓存的
self.cache_k[:bsz, start_pos : start_pos + seqlen] = xk
self.cache_v[:bsz, start_pos : start_pos + seqlen] = xv

# 获取缓存的 K 与 V,用于之后的计算
keys = self.cache_k[:bsz, : start_pos + seqlen]
values = self.cache_v[:bsz, : start_pos + seqlen]
PYTHON

在了解了 KV-Cache 后,我们不禁会反思:既然 能够缓存,那为什么不缓存 呢?答案是:不需要!与 BERT 不同,LLaMA、GPT 等大语言模型都是 Decoder-Only 架构,采用 单向注意力机制。由于使用了注意力掩码,位置靠后 token 的 值将无法与位置靠前 token 的 值求内积。因此,缓存历史 token 的 值是完全没有必要的。

GQA:用分组的方式减少 KV 对的数量

然而,引入 KV-Cahe 意味着需要开辟大量的缓存空间。在 多头注意力 (MHA) 中,所需开辟的缓存空间大小可按照如下公式计算:

  • 指 Transformer 块的数量。以 LLaMA2 为例,它共包含 32 个。
  • 指输入数据的批量大小。这里我们假设是 16。
  • 为输入句子的长度。为便于计算,我们取最大长度为 1024。
  • 是注意力头的个数。假设是 32,与原论文保持一致。
  • 是隐藏层的维度数。它在 LLaMA-7B 中被设为 4096。

根据公式,我们得出为了缓存 KV 所需的空间大小为 份浮点数所需的空间。若我们使用半精度浮点数 float16 类型存储,就需要 大小的存储空间!参照 LLaMA1 论文中给出的硬件设置,这远远地超出了他们所提供的 RAM 80GB 的容量。

为解决这一问题,我们必须优化算法。由此,便引出了 LLaMA 自 2 代开始所使用的 GQA (Group Query Attention) 。以下摘自 GQA 的原论文的图片简单明了地说明了什么是 GQA。

如图所示:在 多头注意力机制(左,MHA) 中,每个注意力查询 Q 都有各自对应的 KV 对,这导致缓存 KV 所需的空间极大。最极端的情况下,如 多查询注意力机制(右,MQA),所有的查询 Q 共享唯一的 KV 对,虽最大程度地减少了所需的缓存空间,但带来了精度的下降。而 分组查询注意力机制(中间,GQA),在精度和计算之间折中:将各查询 Q 分组,同组查询共享一个 KV 对,在保证精度的同时一定程度地减少缓存空间。

我们可以稍做计算:若我们将原有的 32 个注意力头分成 8 组,每组 4 个查询。那么就仅会有 8 个 KV 对,所需的缓存空间就变为了原来的四分之一(128GB -> 32GB)。由此,模型推理性能得到提升,我们就可以喂给模型更多和更长的句子,或者搭建更深的网络和设置更大的隐藏层维度。

metaAI 在代码中的具体实现方式为:限制 KV 头的数目小于 Q 头的数目,在计算的时候复制 KV 头以使其能够与 Q 的头对应,在缓存的时候仅缓存不重复的 KV 对。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 重复 KV:x 是要重复的对象(K 或 V)
# n_rep 是重复的次数,它等于 Q 的头除以 KV 的头
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 # 规定重复 1 次等于不重复
return (
x[:, :, :, None, :] # 重复后第 3 个维度变成 n_rep * KV 的头数
.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 forward(self, x, ...):
... # 此处省略部分代码

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

# 重复 KV 的头以使之与 Q 的头对应
keys = repeat_kv(keys, self.n_rep)
values = repeat_kv(values, self.n_rep)

## 以下代码是注意力机制的具体计算过程
# B 批量大小 L 序列长度
# H 注意力头数 D 隐藏层维度数
# C 已缓存的序列长度
xq = xq.transpose(1, 2) # [B, L, H, D] -> [B, H, L, D]
keys = keys.transpose(1, 2) # [B, C + L, H, D] -> [B, H, C + L, D]
values = values.transpose(1, 2) # [B, C + L, H, D] -> [B, H, C + L, D]
scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim)
if mask is not None:
scores = scores + mask # [B, H, L, C + L]
scores = F.softmax(scores.float(), dim=-1).type_as(xq)
output = torch.matmul(scores, values) # [B, H, L, D]
output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1)
return self.wo(output)
PYTHON

CodeWork:回顾与总结,尝试阅读完整代码

在之前对 RoPE、KV-Cache、GQA 的介绍中,我们事实上已经将 LLaMA 中 Attention 模块的 forward() 函数部分的全部代码展示出来了。现在贴一份完整的代码在这里,可以试着在无注释的条件下理解代码做了什么。如果想看源码,也可以访问 metaAI 官方的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Attention(nn.Module):
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]

keys = repeat_kv(keys, self.n_rep)
values = repeat_kv(values, self.n_rep)

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

训练一个对话机器人:LLaMA2 是如何做的?

自从 ChatGPT 火出圈以后,使用强化学习来提升 LLM 的对话能力 成为了一个很通用的方法。现如今的 LLM 在表现效果方面的提升主要关注 有用性 (helpfulness)安全性 (safety) 两个方面,它们对优化人机交互的体验非常关键。 在 LLaMA2 中,这一点通过强化学习来搞定。

简单地看一下预训练和 SFT 微调部分

预训练和微调过程都以自回归 (auto-regressive) 为训练目标。最大的不同之处在于:预训练过程的输入是独立的一句话,计算损失时考虑整个句子;微调过程的输入则是由 prompt 和 answer 组成的句子对,计算损失时仅考虑 answer 部分。自回归损失可用如下公式表示:

在预训练阶段,自回归赋予模型说话的能力,使模型的输出分布于 人类可接受 (Human Acceptable) 的域内。而在 SFT 微调阶段,通过 指令微调 (Instruction Fine-tuning) ,模型被要求以“提问-回答”的方式生成内容,从而使输出落在 人类可用 (Human Usable) 的域内。

至于具体的训练细节,如 使用 Adawm 优化器学习率呈 Cosine 式递减 等,限于篇幅,不再具体指出。感兴趣的小伙伴们可以通过原论文自行查阅。

重点!带人类反馈的强化学习 (RLHF)

LLaMA 引入强化学习,目的在于使模型的输出尽可能分布在 人类偏好 (Human Preference) 的域内。具体来说,metaAI 希望 LLaMA 是 有用的、无害的 (Helpful, Safe)。LLaMA 使用了与 ChatGPT 相同的 RLHF 算法,该算法分为三步:1) 定义并搜集人类偏好数据;2) 训练奖励模型(Reward Model);3) 确定所使用的强化学习算法,并不断迭代。下图反映了经过强化学习后模型输出的分布变化。

收集人类偏好数据

metaAI 从 helpfulness 和 safety 两个维度衡量人类对机器回答的偏好程度。标注者首先编写 prompt 喂给两个不同 Temperature 参数的模型变体,并按给定的 guidelince 给得到的两个回答打分。

  • 考察 helpfulness 时,标注员将回答标注为 sigificantly better, better, slightly better 或者 negligibly better / unsure。
  • 考察 safety 时,再额外收集一个安全标签,将模型回答分为三类:偏好回答安全而另一个回答不安全、两个回答都安全或者两个回答都不安全。

metaAI 按周分批收集标注,并在每次调优下个 Llama 2-Chat 前,使用最新一次迭代收集的偏好数据训练 RM (Reward Model,奖励模型),以保持 RM 的准确性和适应性。如上图所示,迭代将使 Llama 2-Chat 的输出尽可能分布到 RM 得分高的域内。这其中,RM 也在不断迭代升级。

在数据质量方面,metaAI 将其收集到的人类偏好数据与一些开源数据集,如 Anthropic Helpful & Harmless, OpenAI Summarize, OpenAI WebGPT, StackExchange, Stanford Human Preferences, 和 Synthetic GPT-J 做了对比。想详细了解的小伙伴可以到原论文查看,这里不再赘述。

训练一个奖励模型 (RM, Reward Model)

奖励模型接受模型的回答及其对应的提示作为输入,并返回一个实数(不一定介于 (0,1))表示模型输出的质量。如果将 Llama 2-Chat 看作一个 agent,那么 RM 的输出即是这个 agent 获得的 reward。metaAI 独立地训练两个 RM:一个用于评估 helpfulness,另一个用于评估 safety。

为了使 RM 和对话模型 (LLaMA2-Chat) “具备相同的知识”,metaAI 将两个 RM 初始化成经过预训练的 llama2 的一个 checkpoint。也就是说,RM 采用与 llama2 完全相同的架构和训练参数,而仅 将模型输出头从预测 next-token 头替换为回归头(就如下面公式展示的)。

这样,RM 将会输出一个实数值,作为该“提示+回答”对的质量评估。metaAI 并不要求将质量评估回归到精确的数值上,而采用了 排序损失函数。该损失函数适用于希望模型输出更加关注值的大小关系,而非具体数值的情况。同时,metaAI 引入了 margin 来衡量输出值间的大小差异程度,即“如大,有多大?如小,有多小?”。训练 RM 所使用的损失如下:

其中, 是 sigmoid 函数,用于将最终数值压缩到 (0,1) 之间。 即给定参数 的 RM。 是提示词,而 则分别是标注员选择 (chosen) 和拒绝 (reject) 的回答。 是一个离散函数,它由标注员给出的标签而唯一确定,如下表。

Significantly Better Better Slightly Better Negligibly Better/Unsure
Margin Small 1 2/3 1/3 0
Margin Large 3 2 1 0

该损失函数将会引导 RM 给标注员 chosen 的回答相对更高的分数,而给标注员 reject 的回答相对更低的分数。并且由于 margin 的引入,RM 会倾向于给获得更高级别标签的回答以更高分数。训练好的 RM 就相当于一个导师,它将告诉对话模型“如何说话才能更被人类偏爱”。metaAI 对其训练的 RM 的评估已在原论文给出,这里不再详述。

所使用的强化学习算法

metaAI 执行 RLHF 时主要用了两个算法: Proximal Policy Optimization(PPO)Rejection Sampling fine-tuning (RSF) 。前者是一个通用的 RLHF 的范式。后者则是在 RLHF 迭代早期时,模型尚未成熟所使用的方法。

Rejection Sampling fine-tuning 亦即 拒绝采样微调 。给定 prompt,它经由具有不同 Tempurature 参数的 LLaMA2-chat 得到一组可能的回答。RSF 从这些回答中选取 RM 得分最高的前 N 个样本,并用这些样本对 LLaMA2-Chat 做一次小规模的 SFT (这种方法有点像遗传算法) 。在 RLHF 的前三次迭代 (v1 to v3) 中,LLaMA2-Chat 只通过 RSF 学习,直到 v4 才引入 PPO 算法。

PPO,又称 临近策略优化 算法,是一种 Actor-Critic 算法。如果你不清楚什么是 PPO,你可以查看这篇博客。LLaMA2-Chat 所采用的 PPO 方法如下公式所示:

    • 在数据集 上采样提示 ,并让模型生成一定数量的内容
    • 表示对于提示 ,回答为 的 reward。
    • 目的是使 最大,其中唯一可变的策略 的参数
    • 是优势函数,它的计算在之后解释。
    • 是惩罚因子,用于控制对 的重视程度。
    • 及 KL 散度,用于衡量两个分布的差异程度。
    • KL 散度的存在限制了参数更新的“力度”,使新参数尽量不迥异于原始参数。
    • 经过 logit 变化和白化处理得到。
    • 是分段函数:若提示词安全或其安全得分 小于 0.15,则为安全得分。
    • 否则, 就是有用性得分

最终,我们应当对 求其梯度 ,并通过梯度下降的方法优化。进行梯度下降时所使用的优化器、学习率,设置的迭代次数、轮次、采样数目等在此处略去不提。想要深入了解的童鞋可以自行到原论文去看!

通过 GAtt 保持对话过程的一致性

GAtt 又称 “幽灵注意力” (Ghost Attention) 👻,它的引入主要是为了使模型在对话过程中保持前后话题的一致性。下图解释了什么是多轮对话的一致性:左图中,robot 在新的对话中“忘记了”要用 emoji 作答,而在右图中则始终遵循这一规则。

幽灵注意力的实现,是通过 采样那些保持对话过程一致的样例 来对模型进行微调。为了得到这些样例,在采样时,给多轮对话中用户输入的所有提示语句都加上前缀 instruction,保证模型每次对话时都能知道它应当遵循什么规则。而在微调时,则将这些前缀剔除。然而,这样做无法保证模型的输出和采样时一致,因而在计算损失的时候,需要掩盖当前句子之前的损失。

多模态?来看看 LLaMA3 的表现!

最后的最后,我们来看一下 LLaMA3 在多模态的表现,包括:图像识别 (Image Recognition)视频识别 (Video Recognition)语音理解和生成领域 (Speech Understanding & Generation)

图像识别 (Image Recognition)

主要关注 LLaMA3 在 自然图像理解文本理解图表理解多模态推理 等任务中的图像理解能力。用到的数据集包括:MMMU、VQAv2、AI2 Diagram、ChartQA、TextVQA、DocVQA。取得的成绩如下表所示:

Llama 3-V 8B Llama 3-V 70B Llama 3-V 405B GPT-4V GPT-4o Gemini 1.5 Pro Claude 3.5
MMMU (val, CoT) 49.6 60.6 64.5 56.4 69.1 62.2 68.3
VQAv2 (test-dev) 78.0 79.1 80.2 77.2 -- 80.2 --
AI2 Diagram (test) 84.4 93.0 94.1 78.2 94.2 94.4 94.7
ChartQA (test, CoT) 78.7 83.2 85.8 78.4 85.7 87.2 90.8
TextVQA (val) 78.2 83.4 84.8 78.0 -- 78.7 --
DocVQA (test) 84.4 92.2 92.6 88.4 92.8 93.1 95.2

视频识别 (Video Recognition)

在视频识别方面,metaAI 使用了如下的数据集:1) PerceptionTest,评估模型 时间推理 (temporal reasoning) 的能力,关注于模型的记忆、抽象等技能,有包括描述、预测、解释等不同推理类型;2) NExt-QA,与前一个类似但更关注开放领域的问题;3) TVQA,评估模型 复合推理 (composition reasoning) 的能力;4) ActivityNet-QA,评估模型对长视频总结、理解的能力。

Llama 3-V 8B Llama 3-V 70B Gemini 1.0 Pro Gemini 1.0 Ultra Gemini 1.5 Pro GPT-4V GPT-4o
PerceptionTest (test) 53.8 60.8 51.1 54.7 -- -- --
TVQA (val) 82.5 87.9 -- -- -- 87.3 --
NExT-QA (test) 27.3 30.3 28.0 29.9 -- -- --
ActivityNet-QA (test) 52.7 56.3 49.8 52.2 57.5 -- 61.9

语音理解与生成 (Speech Understanding & Generation)

在语音理解方面,关注 语音识别 (speech recognition)语音翻译 (speech translate)语音问答 (spoken question answer) 。在语音生成方面,主要评估使用 LLaMA3 嵌入向量的 逐字流输入模型 (token-wise input streaming model) 在规范化文本和写韵文这两个任务上的表现。

语音识别 (Speech Recogniton)

Llama 3 8B Llama 3 70B Whisper SeamlessM4T v2 Gemini 1.0 Ultra Gemini 1.5 Pro
MLS (English) 4.9 4.4 6.2 (v2) 6.5 4.4 4.2
LibriSpeech (test-other) 3.4 3.1 4.9 (v2) 6.2 -- --
VoxPopuli (English) 6.2 5.7 7.0 (v2) 7.0 -- --
FLEURS (34 languages) 9.6 8.2 14.4 (v3) 11.7 -- --

语音翻译 (Speech Translate)

Llama 3 8B Llama 3 70B Whisper v2 SeamlessM4T v2
FLEURS (33 lang. → English) 29.5 33.7 21.9 28.6
Covost 2 (15 lang. → English) 34.4 38.8 33.8 37.9

语音问答 (Spoken Question Answer)

规范化文本和写韵文 (TN & PM)

Model Context Accuracy
Without Llama 38B 3 73.6%
Without Llama 38B 88.0%
With Llama 38B 3 90.7%

规范化文本 (TN) 的准确率: 比较了使用/不使用 LLaMA 嵌入的模型,并使用不同的 right-context 值。

Model Perference
PM for Llama 38B 60.0%
Streaming phone-only baseline    40.0%
Model Perference
PM for Llama 38B 63.6%
Non-streaming phone-only baseline 36.4%

写韵文 (PM) 评估: 上例为带 llama38B 嵌入的 PM 与流式模型的对比;下例为与非流式模型的对比。

最后的最后:让我们简单总结下 metaAI 的技术路线

自 OpenAI 的 ChatGPT 诞生以来,大模型领域的更新换代愈发频繁。这一趋势不仅得益于各种技术的蓬勃涌现,更重要的是,开发大语言模型的路径已逐渐清晰并趋于成熟。若一家公司有意打造专属的大模型,很可能也能遵循这一明确路径迅速推出自己的产品。具体而言,该路径包含以下几个关键步骤:

  1. 通过各种手段优化注意力机制,核心有两方面:增强模型的 推理能力推理速度
  2. 利用强化学习或其他先进技术,进一步提升模型的对话交互能力,如 安全性有用性上下文一致性
  3. 实现模型的多模态融合,以拓宽其应用场景和增强功能多样性,包括 图像视频语音 的。

LLaMA 系列模型从一代到三代的演进,便大致遵循了上述发展路径。 可以预见,在未来的一段时间内,该路线是通用且火热 🔥🔥🔥 的。


Llama1-3 🦙:从一道美团大模型面试题讲起
http://example.com/2025/01/09/llama123/
Author
LazyPool
Posted on
January 9, 2025
Licensed under