Gemma 与 Llama 与 Mistral:探索小型 AI 模型

原文:towardsdatascience.com/gemma-vs-llama-vs-mistral-exploring-smaller-ai-models-672a95f4b9b7

本文与 Rafael Guedes 共同撰写。

简介

大型语言模型(LLM)正在迅速发展。每个月,都会开发出新的模型来超越市场上当前的最高得分者。这种健康的竞争对创造新的方法、提高质量和速度有益。此外,公司还专注于开发更小的模型,以便让没有强大计算资源的个人或组织也能使用。

就在几周前,Apple 在其全球开发者大会上推出了 Apple Intelligence。这是一套多个经过微调的生成模型,旨在帮助用户撰写和改进文本、优先处理和总结通知、创建图像以及执行应用内操作。该套件中唯一由 Apple 开发的底层和专有模型也是在同一场会议上推出的。这是一个小型模型,旨在在设备上运行,其中硬件成为了一个重要的限制因素。在 Apple 的案例中,该模型是封闭源代码的。我们知道的是,它是一个具有约 30 亿参数的模型,与 Gemma、Mistral 和 Llama 3 的 70 亿版本相当(根据 Apple 分享的结果)。

虽然 Apple 的新型号令人兴奋,但我们无法对其进行测试或重用。因此,我们更感兴趣的是公开可用的模型,因为开发者和公司可以使用它们来构建新产品和服务。区分开放型 LLM 和开源 LLM 非常重要。从历史上看,开源软件指的是在特定许可证下发布的计算机程序,使得源代码可供公众使用或修改。对于 LLM 来说,还有额外的复杂性,包括训练数据和模型权重。因此,开放型 LLM 通常会公开模型权重和初始代码。另一方面,开源型 LLM 将分享训练过程的每一步,包括训练数据,以及一个许可协议。它应该允许他人使用、在此基础上构建并进一步分发模型。然而,目前发布的多数模型都属于开放型 LLM 的范畴,因为例如,它们没有发布用于训练目的的数据集。这是 Google 的 Gemma、Mistral AI 的 Mistral 和 Meta 的 Llama 的情况。

在本文中,我们更深入地分析了 Gemma,以了解这些小型模型之间的区别。Gemma 是 Google 最近发布的模型之一。它有两个版本,20 亿和 70 亿参数。因此,它可以在边缘设备上使用,并旨在超越 Mistral 和 Llama 3 这样的最先进模型。

此外,我们将 Gemma、Llama 3 和 Mistral 应用于名为 SQuAD 的阅读理解数据集。LLM 被要求根据给定上下文回答特定问题。我们使用诸如推理速度和平均答案长度等量化指标来评估其性能。我们还使用了由 [1] 提出的相对答案质量(RAQ)框架。RAQ 通过根据其相对于真实答案的准确性对答案进行排名,弥合了评估特定用例 LLM 的差距,为模型性能提供了更细致和实用的评估。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/806b6e23a2fea32ce527a664ca98d571.png

图 1:Gemma 与 Llama 与 Mistral 的比较(作者 DALL-E 制作)

如往常一样,代码可在我们的 GitHub 上找到。

Gemma:Gemini 的基础文本模型

Google 发布了基于其强大、闭源模型 Gemini [3] 开发的开源 LLM Gemma [2]。

Google 发布了预训练和微调的检查点,以促进对新用例中模型的研究,使其以两种不同的尺寸提供:

  • 7B 模型将被部署并在 GPU 或 TPU 上进一步开发。

  • 2B 模型旨在解决计算约束,并允许其在 CPU 或设备应用程序中使用。

与其他具有大致相同规模的开源模型(如 Llama 3 7B 或 Mistral 7B)相比,Gemma 承诺实现最先进的性能。这应该发生在不同的领域,例如问答、常识推理、数学/科学和编码。

Gemma:有什么新内容?

Gemma 的架构基于仅解码器 [4] Transformer [5],上下文长度为 8192 个标记。让我们探讨使其变小的方法。

多查询注意力

2B 模型利用多查询注意力(MQA)来显著减少加载所有查询、键和值头所需的内存资源,这与多头注意力(MHA)方法不同。MQA 通过在注意力层中使用单个键和值来为多个查询头实现内存减少,如图 3 所示。

虽然这种方法允许 Gemma 2B 在内存资源较小的设备上部署,但它可能导致质量下降和训练不稳定。因此,作者选择了在 7B 版本中使用 MHA,遵循与 Llama 3 相同的方法。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/14e34cd5cc6f99efbebadca99fd7fe7c.png

图 2:MHA 和 MQA 的区别(作者制作)

RoPE 嵌入

由于 Transformer 本质上是顺序不变的,因此需要位置嵌入。这意味着如果没有位置信息,Transformer 会以相同的方式表示具有相同单词但顺序和意义不同的句子。例如:

句子 1: Gemma 比 Llama 3 更好

句子 2: Llama 3 比 Gemma 更好

位置信息通常使用两个正弦函数(正弦和余弦)来表示。然后,根据其在序列中的位置、标记嵌入维度和模型维度,为序列中的每个位置创建一个独特的位置嵌入。

因此,添加位置信息对于使 Transformers 能够正确处理文本至关重要。原始 Transformer 架构使用了 绝对位置嵌入,其中将位置向量的表示添加到标记向量的表示中。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1247c09ef00227fe42af80c6e5b6f39a.png

图 3:绝对位置嵌入(作者图片)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c187f858d251cbb8ae1073344b1e5adb.png

方程式 1 和 2:正弦和余弦函数生成位置嵌入,其中 pos 是位置,i 是位置编码的维度,model 是向量的总维度。

绝对位置嵌入的挑战在于它们没有明确编码标记之间的相对距离。虽然它们使用正弦和余弦函数来捕捉位置信息,但这些嵌入是独立为每个位置计算的。这意味着模型本身并不理解序列中不同位置之间的邻近性或关系重要性。例如,位置 1 和 2 的嵌入可能由于正弦函数的性质而看起来相似,但模型并没有明确识别这些位置是相邻的。

因此,模型可能无法区分位置 1 和 2 的标记之间的关系与位置 1 和 500 的标记之间的关系。在自然语言处理中,句子中相邻的词通常共享更多的上下文或比相隔较远的词有更强的语义或句法关系。绝对位置嵌入可能无法完全捕捉这种细微差别。这可能导致在捕捉长距离依赖关系或语言的层次结构时存在局限性。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/442f6e1456dee42dcc5e1ab0c12a2b93.png

图 4:相对位置应包含在位置编码中(作者图片)

旋转位置嵌入(RoPE)[6] 通过对序列中标记嵌入进行旋转来建模标记的相对位置,从而解决这个问题。

让我们以前面的例子“Gemma is better than Llama”为例,并将每个词视为一个由 2D 向量表示的标记。单词 better 将根据其位置 m 和一个常数角度 θ 从原始向量旋转,如图 5 所示。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/68e02c663cf89aeb3a739d2d0f2e1ad5.png

图 5:基于位置(m=3)和常数θ将原始向量转换为新向量的旋转位置嵌入(作者图像)

这种方法保留了标记之间的相对距离,因为旋转变换保持了向量之间的相同相似性,无论它们在序列中的位置如何。例如,如果我们向原始句子中添加两个单词,使其变为“The LLM Gemma is better than Llama”,则betterthan的位置从(3 & 4)变为(5 & 6)。然而,由于旋转角度保持一致,这些向量之间的相似性(通过点积测量)保持不变,确保了相对位置的连续性。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4510b33281425444573118cfd76552a9.png

图 6:旋转嵌入保留标记之间相对距离的能力(作者图像)

GeGLU 激活函数

作者将传统的 ReLU 激活函数替换为门控线性单元(GLU)的变体 GeGLU,因为另一项研究[7]表明它可以提高 LLM 生成的输出质量。

ReLU 和 GeGLU 之间有两个区别:

  1. 激活函数 – GeGLU 使用高斯误差线性单元(GELU)[8]函数,与 ReLU 的不同之处在于它将神经元输入x乘以正态分布的累积分布函数。在这种情况下,x被丢弃的概率随着x的减小而增加。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/01d57db7138a332d1e5caf0102f678f4.png

图 7:GELU 和 ReLU 之间的差异(来源)

  1. Sigmoid 激活 – 简单的 ReLU 或 GELU 激活函数应用于隐藏表示x和由两个矩阵表示的两个线性变换之间。GeGLU 中的门控变体将门控机制(sigmoid)应用于其中一个组件,如方程 3 所示。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f0f90e3411e4aa00cebc4a5ea80b1e04.png

方程 3:GELU 和门控 GELU 之间的差异

正则化位置

最后对原始 Transformer 架构的修改如图 8 所示。作者将每个 transformer 子层的输入和输出都进行了正则化,以提高训练稳定性,这与原始论文相反,原始论文只对输出进行了正则化。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fefef48ffcce01ae452cc8436bf0a526.png

图 8:Gemma 架构中添加到 transformer 输入的正则化(作者图像)

他们还用 RMSNorm [8] 替换了传统的 LayerNorm 函数。它在保持训练稳定性改进的同时,计算效率更高,并有助于模型收敛。

RMSNorm 效率更高,因为其作者证明了 LayerNorm 的好处来自于重新缩放不变性,而不是重新居中不变性。重新缩放不变性意味着如果输入乘以一个常数因子,则归一化过程的输出保持不变。换句话说,将所有输入乘以一个常数不会影响归一化输出。重新居中不变性意味着如果向所有输入添加一个常数值,则归一化过程的输出保持不变。这意味着将所有输入移动一个常数量不会影响归一化输出。这一发现允许移除计算平均值的开销(你只需要计算标准差),使 RMSNorm 更简单、更高效。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/627a2833c736f2e3885306fdf37fa722.png

图 9:LayerNorm 和 RMSNorm 之间的方程差异(作者提供)

Mistral AI vs. Meta vs. Google:Gemma 7B vs. Llama 3 7B vs. Mistral 7B 的比较

在本节中,我们将 3 个 LLM——Gemma 7B、Mistral 7B 和 Llama 3 7B——进行测试。我们使用了一个名为 SQuAD 的问答数据集,该数据集在 CC BY-SA 4.0 许可下,可以在这里找到。这个数据集是一个阅读理解数据集,包含关于一组维基百科文章的问题。根据上下文,模型应该能够检索到问题的正确答案。对于我们用例来说,3 个更重要的字段是:

  • question – 模型应该回答的问题。

  • context – 模型需要从中提取答案的背景信息。

  • answers – 对问题的文本答案。

评估过程将包括两个定量指标:

  • words per second – 评估推理速度。

  • words – 评估答案的长度。

为了评估我们用例中模型的准确性,我们使用了 RAQ [1]。RAQ 使用一个独立的 LLM 对所有 LLM 的答案进行排名,基于它们与真实答案的接近程度。

我们首先以.gguf格式下载模型,以便在 CPU 上运行,并将它们放置在model/文件夹下。

我们使用了每个模型的指令版本,并对其进行了 4 位量化:

之后,我们导入所有库以及接收我们想要使用的模型的生成器。

import os

import seaborn as sns
import matplotlib.pyplot as plt
import scikit_posthocs as sp
import pandas as pd
import utils

from dotenv import load_dotenv
from datasets import load_dataset
from generator.generator import Generator

llama = Generator(model='llama')
mistral = Generator(model='mistral')
gemma = Generator(model='gemma')
load_dotenv('env/var.env')

这个类负责导入在 config.yaml 文件中定义的模型参数,其特征如下:context_length 为 1024,temperature 为 0.7,max_tokens 为 2000。

generator:
  llama:
    llm_path: "model/Meta-llama-3-8B-Instruct-Q4_K_M.gguf"
  mistral:
    llm_path: "model/mistral-7b-instruct-v0.1.Q4_K_M.gguf"
  gemma:
    llm_path: "model/gemma-7b-it-Q4_K_M.gguf"
  context_length: 1024
  temperature: 0.7
  max_tokens: 2000

它还创建了提示模板。这个模板有助于在将查询和上下文传递给 LLM 以获取响应之前对其进行格式化。

from langchain import PromptTemplate
from langchain.chains import LLMChain
from langchain.llms import LlamaCpp

from base.config import Config
class Generator(Config):
    """Generator, aka LLM, to provide an answer based on some question and context"""
    def __init__(self, model) -> None:
        super().__init__()
    # template
        self.template = """
            Use the following pieces of context to answer the question at the end.
            {context}
            Question: {question}
            Answer:
        """
   # load llm from local file
        self.llm = LlamaCpp(
            model_path=f"{self.parent_path}/{self.config['generator'][model]['llm_path']}",
            n_ctx=self.config["generator"]["context_length"],
            temperature=self.config["generator"]["temperature"],
        )
        # create prompt template
        self.prompt = PromptTemplate(
            template=self.template, input_variables=["context", "question"]
        )
    def get_answer(self, context: str, question: str) -> str:
        """
        Get the answer from llm based on context and user's question
        Args:
            context: most similar document retrieved
            question: user's question
        Returns:
            llm answer
        """
        query_llm = LLMChain(
            llm=self.llm,
            prompt=self.prompt,
            llm_kwargs={"max_tokens": self.config["generator"]["max_tokens"]},
        )
        return query_llm.run({"context": context, "question": question})

加载 LLM 后,我们从 HuggingFace 获取 SQuAD 数据集并进行洗牌,以确保问题主题的多样性足够。

squad = load_dataset("squad", split="train")
squad = squad.shuffle()

现在,我们可以遍历 60 个问题和上下文,并记录上述指标。

for i in range(60):
    context = squad[i]['context']
    query = squad[i]['question']
    answer = squad[i]['answers']['text'][0]

    # Llama
    answer_llama, words_per_second, words = utils.get_llm_response(llama, context, query)
    llama_metrics["words_per_second"].append(words_per_second)
    llama_metrics["words"].append(words)
    # mistral
    answer_mistral, words_per_second, words = utils.get_llm_response(mistral, context, query)
    mistral_metrics["words_per_second"].append(words_per_second)
    mistral_metrics["words"].append(words)
    # gemma
    answer_gemma, words_per_second, words = utils.get_llm_response(gemma, context, query)
    gemma_metrics["words_per_second"].append(words_per_second)
    gemma_metrics["words"].append(words)

    # GPT-3.5 rank
    llm_answers_dict = {'llama': answer_llama, 'mistral': answer_mistral, 'gemma': answer_gemma}
    rank = utils.get_gpt_rank(answer, llm_answers_dict, os.getenv("OPENAI_API_KEY"))
    llama_metrics["rank"].append(rank.index('1')+1)
    mistral_metrics["rank"].append(rank.index('2')+1)
    gemma_metrics["rank"].append(rank.index('3')+1)

函数 get_llm_response 负责接收加载的 LLM、上下文和问题,并返回 LLM 回答以及定量指标。

def get_llm_response(model: Generator, context: str, query: str) -> Tuple[str, int, int]:
    """
    Generates an answer from a given LLM based on context and query
    returns the answer and the number of words per second and the total number of words
    Args:
        model: LLM
        context: context data
        query: question
    Returns:
        answer, words_per_second, words
    """
    init_time = time.time()
    answer_llm = model.get_answer(context, query)
    total_time = time.time()-init_time
    words_per_second = len(re.sub("[^a-zA-Z']+", ' ', answer_llm).split())/total_time
    words = len(re.sub("[^a-zA-Z']+", ' ', answer_llm).split())
    return answer_llm, words_per_second, words

我们可以看到,Llama 3 通过平均每秒产生 ~0.7 个单词的速度比 Mistral 和 Gemma 快,而 Mistral 的速度为 ~0.26 个单词,Gemma 为 ~0.4 个单词。在回答长度方面,Llama 3 也比 Mistral 和 Gemma 产生更长的回答,平均回答长度为 148 个单词,而 Mistral 为 20 个单词,Gemma 为 50 个单词。最后,基于 RAQ,Mistral 的平均排名最好,约为 1.81,其次是 Gemma,平均排名为 2.05,而 Llama 3 的表现较差,平均排名约为 2.1。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f8f96fbea6d022ef33acc1f2ee536978.png

图 10:所有 LLM 的指标比较(图片由作者提供)

RAQ 框架还包括一个统计测试,以了解观察到的差异是否显著。表 1 显示了 Dunn 后续检验的结果,比较了不同语言模型的性能。每个单元格表示相应模型之间性能差异在 5% 显著性水平下是否具有统计学意义。 “显著” 表示具有统计学意义的差异(p 值 ≤ 0.05),而 “不显著” 表示没有统计学意义的差异(p 值 > 0.05)。对于选定的显著性水平,Dunn 测试结果表明模型之间的性能差异不显著。

p_values = sp.posthoc_dunn([Llama_metrics['rank'], mistral_metrics['rank'], gemma_metrics['rank']], p_adjust='holm')
p_values > 0.05

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bcdc14db4e9086b67a4ee50224fd0869.png

表 1:LLM 集合中排名差异的重要性

总是评估一些示例的定性方面非常重要。下面,我们展示了基于以下上下文对问题“Power House Day 在 New Haven 是哪一天庆祝?”的 3 个模型的回答:

背景:“一个多世纪以来,纽黑文市民一直与正规英国军队并肩作战,参与殖民民兵,就像在法国和印第安人战争中一样。随着美国革命的临近,大卫·伍斯特将军和其他有影响力的人士希望与英国政府的冲突能够在叛乱之前得到解决。1775 年 4 月 23 日,这一天在纽黑文仍然被庆祝为火药库日,纽黑文的第二公司,州长卫队加入了与英国议会的斗争。在贝奈迪克特·阿诺德的带领下,他们闯入火药库武装自己,并开始向马萨诸塞州的剑桥的三天行军。其他纽黑文民兵成员也在场,护送乔治·华盛顿从他在纽黑文的过夜停留前往剑桥。”当代报道,来自双方,都称赞了纽黑文志愿者的专业军事素养,包括制服。”

所有 3 个模型都给出了正确的答案。虽然 Llama 3 和 Gemma 提供了更完整的答案,但 Mistral 更加简洁。

Llama 3 答案:“纽黑文的火药库日是在 4 月 23 日庆祝的。”

Gemma 答案:“当然!文本中说明了火药库日是在哪一天庆祝的:火药库日在纽黑文庆祝于 23 April。”

Mistral 答案:‘23 April’

结论

设备上的模型通过使计算资源较低的设备能够访问强大的 LLM 来提供增强用户体验的巨大机会。苹果和谷歌都在积极开发更小、更高效的模型以满足这一需求,使更多人能够从他们日常生活中的高级人工智能中受益。

在这篇文章中,我们探讨了由 Google 开发的开源 LLM——Gemma,它为传统的 Transformer 架构引入了四个新颖的特性:2B 版本的 Multi-Query Attention,用于位置编码的 RoPE 嵌入,GeGLU 作为激活函数,以及输入归一化。

我们还比较了 Gemma 在阅读理解数据集上的性能与 Llama 3 和 Mistral 的表现。我们观察到 Gemma 每秒产生的单词数比 Mistral 多,且答案更长,但在这些指标上并未超越 Llama 3。使用 RAQ 框架,我们评估了三个模型的准确性。虽然数据显示 Mistral 的结果更好,其次是 Gemma,但差异并不具有统计学意义。因此,我们可以认为这三种模型在应用于我们的阅读理解用例时表现相似。

关于我

人工智能领域的连续创业者和领导者。我为商业开发人工智能产品,并投资于专注于人工智能的初创企业。

ZAAI 创始人 | LinkedIn | X/Twitter

参考文献

[1] 路易斯·罗克,拉斐尔·格德斯. 从研究到生产:相对答案质量(RAQ)和 NVIDIA NIM。medium.com/@luisroque/research-to-production-relative-answer-quality-raq-and-nvidia-nim-15ce0c45b3b6,2024.

[2] 吉玛团队,谷歌 DeepMind. 吉玛:基于双子星研究和技术的开源模型,2023.

[3] 双子星团队. 双子星:一套高度多模态的模型,2023.

[4] 诺亚姆·沙泽尔. 快速 Transformer 解码:只需一个写头。arXiv:1911.02150,2019.

[5] 阿希什·瓦桑尼,诺亚姆·沙泽尔,尼基·帕尔马尔,雅各布·乌斯克雷伊特,利昂·琼斯,艾丹·N·戈麦斯,卢卡斯·凯泽,伊利亚·波洛苏欣. 注意力即一切。arXiv:1706.03762,2017.

[6] 孙建林,吕宇,潘胜锋,阿赫迈德·穆尔塔达,文博,刘云峰. RoFormer:带有旋转位置嵌入的增强 Transformer。arXiv:2104.09864,2021.

[7] 诺亚姆·沙泽尔. GLU 变体改进 Transformer。arXiv:2002.05202,2020.

[8] 丹·亨德里克斯,凯文·吉姆佩尔. 高斯误差线性单元(GELUs)。arXiv:1606.08415,2016.

[9] 张标,里科·森尼奇. 根均方层归一化。arXiv:1910.07467,2019.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值