为了提高性能,大型语言模型(llm)通常会通过增加模型大小的方法来实现这个目标,但是模型大小的增加也增加了计算成本和推理延迟,增加了在实际场景中部署和使用llm的障碍。
Mistral AI是一家总部位于巴黎的欧洲公司,一直在研究如何提高模型性能,同时减少为实际用例部署llm所需的计算资源。Mistral 7B是他们创建的最小的LLM,它为传统的Transformer架构带来了两个新概念,Group-Query Attention(GQA)和Sliding Window Attention(SWA)。这些组件加快了推理速度,减少了解码过程中的内存需求,从而实现了更高的吞吐量和处理更长的令牌序列的能力。
此外他们还创造了混合8x7B,通过使用稀疏混合专家(SMoEs)。为每个令牌激活8个可用专家中的2个来减少推理时间,将处理令牌所需的参数数量从47B减少到13B。
在本文中,我们将详细地解释了Mistral AI添加到传统Transformer架构中的每个新概念,并对Mistral 7B和Llama 27b之间的推理时间进行了比较。除此以外还对Mixtral 8x7B和Llama 270b之间的内存、推理时间和响应质量进行了比较。
GQA:分组查询注意力
自回归解码器推理是transformer的瓶颈,因为需要在多头注意层(MHA)中加载所有查询、键和值需要大量内存资源。为了克服这个问题,Multi-Query Attention(MQA)被开发出来,它通过在注意层中只使用一个键和值但是使用多个查询头来减少所需的内存。但是这种解决方案可能会导致质量下降和训练不稳定,这使得开源llm(如T5和Llama)选择不使用这种方法。
GQA通过将查询值划分为G组(GQA-G)在MHA和MQA之间取得了平衡,这些组共享一个键和值头。GQA-1意味着所有查询都分配在一个组中,因此与MQA相同,而GQA-H (H = head的数量)相当于MHA,其中每个查询都被视为一个组。
这种方法减少了每个查询组中进入单个键和值的键和值头的数量,减少了缓存的键-值的大小,从而减少了需要加载的数据量。这种比MQA更适度的减少加速了推理速度,并减少了解码过程中的内存需求,其质量更接近MHA,但是速度却几乎与MQA相同。
Mistral有32个查询头和8个键值头,查询被分成4组。
SWA:滑动窗口注意力
大多数Transformers 使用传统的注意力机制,其中序列中的每个标记都可以对自己和过去的所有标记进行处理。它使内存随着令牌的数量线性增加。这种方法在推理时带来了问题,因为由于缓存可用性降低,它具有更高的延迟时间和更小的吞吐量。
SWA的设计可以缓解这些问题,它利用堆叠的注意力层来关注超窗口大小w的信息。k层中位置i的每个隐藏状态h可以关注位置在i- w和i之间的前一层的所有隐藏状态。隐藏状态可以从输入层访问距离为W x k个令牌的令牌。该模型有32层,窗口大小为4096,其注意力广度为131k个令牌。
为了更好地理解SWA是如何工作的,想象一下下面的场景,我们的输入提示是:
Mixtral 8x7B is a Large Language Model designed to deliver high performance while maintaining efficiency at inference time …
如果窗口大小为3 (W=3),位于第6层(k=6),位置为16 (i=16),我们访问令牌“at”和第5层的最后3个令牌,由于是递归过程,第6层也可以访问W=3以外的信息,因为第5层可以访问第4层的最后3个令牌,第4层可以访问第3层的最后3个令牌。所以滑动窗口外的标记仍然会影响下一个单词的预测。
由于Mistral具有131k令牌的固定注意力广度,因此缓存大小也限制在固定大小的W,所以作者使用滚动缓冲缓存来覆盖过去的值并停止对缓存大小的线性增长需求。时间步长i的键和值存储在cache的i mod W位置,当位置i高于W时,第一个值将被新的令牌覆盖(可以理解为FIFO)。
考虑前面的例子,我们有一个窗口大小为3。当模型生成第四个令牌时,第一个令牌将被替换,如下图在Timestep i+1所示。
SWA中的最后一个内存优化依赖于预填充和分块,作者将非常大的提示块分成与W大小相同的小块,并预填充键值缓存以限制内存使用。当涉及到处理大小为3 (W=3)的块时,模型可以使用滑动窗口访问当前块和缓存中的块,但它不能访问过去的令牌,因为它们在滑动窗口之外。
SMoE:稀疏混合专家
混合专家(moe)通过引入专家网络(通常是前馈神经网络)的概念,打破了通过连续层进行线性数据处理的传统观念,每个专家网络都是专门处理特定任务或数据类型的。
这种架构提高了训练效率,因为FFN层被视为单独的专家,而剩下的模型参数是共享的。例如,Mixtral 8x7B没有56B参数,只有47B参数,这使得模型可以用比具有56B的密集模型更少的计算资源进行预训练。它在推理时也带来了好处:只有2个专家被激活因此只使用了13B个参数,所以比密集模型更快。
moe有两个主要组件:
使用稀疏混合专家层代FFN层:Mixtral 8x7B有8个SMoE层,即8个专家,每个专家专门负责一组令牌。例如,一个人可以是标点符号专家、视觉描述专家或数字专家,但是他并不是全能的。
Gate或路由网络:决定哪些令牌被发送给哪些专家,这个网络与网络的其余部分同时进行预训练,学习如何将令牌分配给能够最好地处理它的专家。
对于路由网络,仅使用softmax函数可能导致专家之间的负载平衡不均衡,所以作者提出了一个有噪声的top-k门控[7]函数,在softmax门控之前加入可调高斯噪声和稀疏度。
我们简单的解释以下top-k门控是如何工作的:如果我们希望每个令牌分配给前2名专家(k=2),如下图中的等式所示。会进行一个转换,其中保留前2个值,其余的值设置为-∞。这种稀疏性允许节省计算能力,因为相应的-∞的softmax值为0,所以专家不会被激活。最后softmax函数计算每个专家对输入令牌的权重。这些权重将定义专家对最终输出的贡献。
比如我们上面的文本,第一个令牌“Mixtral”通过路由网络,只激活2个专家而不是所有专家可以节省推理时的时间和训练时的计算资源,这是因为一个特定的令牌只由2个较小的FFN处理,而不是一个密集的FFN。
Mistral AI vs Meta: Mistral 7B vs Llama 27b和midtral 8x7B vs Llama 270b的比较
介绍完Mistral的改进,我们将开始进行比较。我们将创建四个RAG系统,系统之间的区别将是生成模型,其中我们将使用Mistral 7B, Llama 2 7B, Mixtral 8x7B, and Llama 2 70B。比较Mistral 7B与Llama 27b在推理时间方面的性能,以及Mixtral 8x7B与Llama 2 70b在推理时间、内存和响应质量方面的性能。
我们首先建立一个PGVector数据库来支持上下文检索的语义搜索。
postgres.env
POSTGRES_DB=postgres
POSTGRES_USER=admin
POSTGRES_PASSWORD=root
docker-compose.yaml
version: '3.8'
services:
postgres:
container_name: container-pg
image: ankane/pgvector
hostname: localhost
ports:
- "5432:5432"
env_file:
- ./env/postgres.env
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres-data:
我们运行命令docker-compose up -d, PGVector数据库就准备好了。
数据库以下方式填充数据集的前10个产品的客户评论:
使用sentence-transformers/multi-qa-mpnet-base-dot-v1 来进行embedding并使用LangChain将它们存储在PGVector中。然后创建一个新的列full_review,它将客户的标题和评论连接起来,循环10个不同的产品id,将它们转换为Documents (LangChain期望的格式),并将它们存储在PGVector中。
from encoder.encoder import Encoder
from retriever.vector_db import VectorDatabase
from langchain.docstore.document import Document
import pandas as pd
encoder = Encoder()
vectordb = VectorDatabase(encoder.encoder)
df = pd.read_csv('data/data.csv')
# create new column that concatenates title and review
df['full_review'] = df[['reviews.title', 'reviews.text']].apply(
lambda row: ". ".join(row.values.astype(str)), axis=1
)
for product_id in df['asins'].unique()[:10]:
# create documents to store in Postgres
docs = [
Document(page_content=item)
for item in df[df['asins'] == product_id]["full_review"].tolist()
]
passages = vectordb.create_passages_from_documents(docs)
vectordb.store_passages_db(passages, product_id)
与PGVector的连接设置必须在一个连接中。使用以下变量创建Env /下的Env文件:
DRIVER=psycopg2
HOST=localhost
PORT=5432
DATABASE=postgres
USERNAME=admin
PASSWORD=root
现在我们将创建20个查询,每个产品2个,要求LLM告诉我们,“What do people like about the product?”以及“What do people dislike about the product?”在将问题发送给LLM之前,我们从向量数据库中检索上下文以帮助指导答案。
为了检索每个产品的正确上下文,我们需要将查询和product ID一起发送,这样可以从表中获取正确的数据。通过事先检索上下文,我们可以确保两个模型接收到相同的信息,这样比较更加公平。
# generate 2 questions for each product id (20 questions in total)
like_questions = [f"{product_id}|What people like about the product?" for product_id in df["asins"].unique()[:10]]
dislike_questions = [f"{product_id}|What people dislike about the product?" for product_id in df["asins"].unique()[:10]]
# retrieve query and context to give to llama and mistral
QUERIES = []
CONTEXTS = []
for q in like_questions+dislike_questions:
id = q.split("|")[0]
query = q.split("|")[1]
context = vectordb.retrieve_most_similar_document(query, k=2, id=id)
QUERIES.append(query)
CONTEXTS.append(context)
我们已经有了问题和上下文,溴铵在可以把它们传递给LLM,记录他们每秒产生多少单词和答案的平均长度。
我们以.gguf格式下载所有模型,这样可以在cpu中运行它们。
mistral-7b-v0.1.Q4_K_M和nous-hermes-llama-2-7b.Q4_K_M。使用4位量化,Mistral 7B需要6.87 GB RAM, Llama 2需要6.58 GB RAM。
mixtral-8x7b-v0.1.Q4_K_M和llama-2-70b-chat.Q4_K_M也是使用4位量化,其中Mixtral 8x7B需要28.94 GB RAM, Llama 2需要43.92 GB GB RAM。
然后我们导入类Generator,它接收我们想要使用的模型作为参数。
from generator.generator import Generator
llama = Generator(model='llama')
mistral = Generator(model='mistral')
llama70b = Generator(model='llama70b')
mixtral8x7b = Generator(model='mixtral8x7b')
这个类负责导入配置中定义的模型参数。具有以下特征的Yaml文件:context_length为1024,temperature为0.7,max_tokens为2000。
generator:
llama:
llm_path: "model/nous-hermes-llama-2-7b.Q4_K_M.gguf"
mistral:
llm_path: "model/mistral-7b-v0.1.Q4_K_M.gguf"
llama70b:
llm_path: "model/llama-2-70b.Q4_K_M.gguf"
mixtral8x7b:
llm_path: "model/mixtral-8x7b-v0.1.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 (str): most similar document retrieved
question (str): user's question
Returns:
str: 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})
现在遍历问题和上下文,并记录上面提到的指标。
结束后通过指标图可以看到Mistral 7B比Llama 2 7b快得多,平均每秒产生约1.5个单词,而Llama 27b仅产生约0.8个单词。Mistral 7B生成的答案更完整,平均答案长度为248,而Llama 27b仅生成75个单词的句子。
对于时间,其中Mixtral 8x7B需要大概3分钟,Llama 2 70b需要大概10分钟。
对于内存利用率,Mixtral 8x7B有47B个参数,而Llama 2有70B个参数,因此我们可以预期,Mixtral的内存利用率是Llama 2所使用内存的67%,但由于smoe及其专家之间共享的参数,它的内存利用率仅为62.5%。
总结
LLM在过去两年中有了巨大的发展,这使得获得高质量的回复成为可能,而且很难区分是谁写了这些回复,是人还是机器。目前的研究的重点正在从生成高质量的响应转向创建尽可能小的LLM,以便能够在资源较少的设备上运行,以节省成本并使其更容易获得。
Mistral是积极研究这一领域的公司之一,正如我们所看到的他们取得了非常好的成果。对于他们最小的模型Mistral 7B能够在训练期间提高内存效率,并将推理时间减少近一半。
对于Mixtral 8x7B,除了增加GQA和SWA,他们还引入了第三个概念,稀疏混合专家,这进一步提高了训练和推理效率。这种方法保证在推理时不使用47B参数来处理每个令牌,而只使用13B参数。当我们比较Mistral 8x7B和LLama 270b的答案时,可以看到它产生的答案与LLama 2一样好,但是时间减少了约70%,内存减少了62.5%。
可以想象在2024年会LLM有更好的发展。
引用
[1] Albert Q. Jiang, Alexandre Sablayrolles, Antoine Roux, Arthur Mensch, Blanche Savary, Chris Bamford, Devendra Singh Chaplot, Diego de las Casas, Emma Bou Hanna, Florian Bressand, Gianna Lengyel, Guillaume Bour, Guillaume Lample, Lélio Renard Lavaud, Lucile Saulnier, Marie-Anne Lachaux, Pierre Stock, Sandeep Subramanian, Sophia Yang, Szymon Antoniak, Teven Le Scao, Théophile Gervet, Thibaut Lavril, Thomas Wang, Timothée Lacroix, William El Sayed. Mixtral of Experts. arXiv:2401.04088, 2024.
[2] Albert Q. Jiang, Alexandre Sablayrolles, Arthur Mensch, Chris Bamford, Devendra Singh Chaplot, Diego de las Casas, Florian Bressand, Gianna Lengyel, Guillaume Lample, Lucile Saulnier, Lélio Renard Lavaud, Marie-Anne Lachaux, Pierre Stock, Teven Le Scao, Thibaut Lavril, Thomas Wang, Timothée Lacroix, William El Sayed. Mistral 7B. arXiv:2310.06825, 2023.
[3] Joshua Ainslie, James Lee-Thorp, Michiel de Jong, Yury Zemlyanskiy, Federico Lebrón, and Sumit Sanghai. Gqa: Training generalized multi-query transformer models from multi-head checkpoints. arXiv:2305.13245, 2023.
[4] Iz Beltagy, Matthew E Peters, and Arman Cohan. Longformer: The long-document transformer. arXiv:2004.05150, 2020.
[5] Bo Li, Yifei Shen, Jingkang Yang, Yezhen Wang, Jiawei Ren, Tong Che, Jun Zhang, Ziwei Liu. Sparse Mixture-of-Experts are Domain Generalizable Learners. arXiv:2206.04046, 2023.
[6] Noam Shazeer. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150, 2019.
[7] Noam Shazeer, Azalia Mirhoseini, Krzysztof Maziarz, Andy Davis, Quoc Le, Geoffrey Hinton, Jeff Dean. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538, 2017.
作者:Luís Roque
https://avoid.overfit.cn/post/1924fd9d2c174feba6495eb90e85e301
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。