本文与Rafael Guedes共同撰写。
介绍2022年ChatGPT的成功发布让人们意识到,生成式AI不仅对那些希望自动化手动且耗时任务的个人有许多优势,也对那些希望提升客户体验和优化运营的公司有很多好处。
随着对生成式AI解决方案需求的增加,多家公司开始投资于开源解决方案的研究和开发,例如Mistral AI的Mixtral或Meta的LLaMA 3。对GenAI的大量投资使得这些模型广泛向公众开放,这使得大多数公司的重点从内部开发大型语言模型(LLMs)转向部署这些开源版本。
关于这些模型的产品化,有两个问题值得思考:应该使用哪个模型,以及如何能够大规模且安全地部署这些模型?本文旨在回答这些问题。我们提出了一种名为RAQ(相对答案质量)的方法,通过使用独立的LLM来比较和排名不同LLM的答案,从而评估这些模型。我们方法的关键优势在于它可以轻松地集成到任何工作流程中,并且可以评估任何一组LLM在任何领域/主题/用例上的表现。RAQ可以用于拥有特定主题的问题和正确答案的数据集的组织,但也可以在没有此类数据集的情况下应用。我们提出的方法的另一个优点是可以量化数据集的大小。我们使用统计测试来确定排名差异是否显著,从而让机器学习从业者能够自信地判断一个LLM是否优于另一个。排名本质上是基于它们与真实答案的接近程度,无论评估的数据属于哪个领域/主题/用例。
为了回答第二个问题,我们展示了使用 NVIDIA 的新 NIM 微服务从研究过渡到生产级解决方案是多么容易。NIM 允许在大规模部署 LLM,首先使用 NVIDIA 提供的服务进行快速原型设计,而在生产环境中,则可以在任何私有云或物理硬件上进行自托管部署。加速硬件设置和领先开源模型的推理引擎已经预先优化,因此我们可以轻松地设置基础设施。此外,它还提供了使用 LoRA 对模型进行微调的灵活性。
图1:从研究到生产的相对答案质量(RAQ)(使用NVIDIA NIM,图片由作者使用DALL-E生成)
一如既往,代码可在我们的 GitHub 上获取。
RAQ:相对答案质量如前所述,在ChatGPT发布之后,对开源大语言模型(LLM)的研究和开发进行了巨大的投资。事实上,几乎每周都会有一个新的模型或模型的变种被发布。面对如此多的选择,如何选择最适合自己的模型呢?
定量指标如推理时间很重要,在选择您的大语言模型时应予以考虑。然而,推理速度快但响应质量低的大语言模型可能不是一个好选择。
在特定用例上定性评估大型语言模型(LLM)是一项手动且耗时的任务,因为需要根据数百个问题来评估模型。这具有高度主观性,并且需要阅读数百个答案并与真实答案进行比较。因此,为了克服这个问题并减少评估响应质量所需的手动工作,我们提出了相对答案质量(RAQ)。
RAQ 框架依赖于一个独立的大语言模型(LLM),该模型接收问题、真实答案以及一组 LLM 的答案。它使用独立的 LLM 根据与真实答案的比较来对它们进行排名。当不存在包含问题和答案的数据集时,可以开发 RAQ 的扩展。在这种情况下,我们可以使用另一个独立的 LLM 来为我们生成这些问题和答案。还有一种混合设置,即存在一个小数据集但不足以运行 RAQ。在这种情况下,我们可以利用这个小数据集作为种子,使用独立的 LLM 生成类似的示例,采用半合成的方法。
独立的大规模语言模型(LLM)可能包含偏见和其他潜在问题。为了解决这些问题,我们提出了两个选项:i) 选择最佳的开源或闭源模型,或者 ii) 选择一组最佳模型,并对每个独立的LLM运行相对答案质量(RAQ)评估。后者需要在应用通用RAQ框架之前增加一个额外步骤。结果需要在计算排名的中位数和标准差之前进行汇总。对于RAQ的一个关键点是确保独立的LLM或LLM集合不在我们评估的LLM集合中。否则,我们将对该特定模型或模型集合引入强烈偏见。
最后,RAQ 还可以包含其他指标以提供对一系列大语言模型的完整比较。例如,我们可以计算每秒单词数和平均回答长度。这些指标可以提供更多关于模型性能和详细程度的数据点。
RAQ 实际应用我们首先创建以下提示:我们要求独立的大规模语言模型(LLM)根据答案质量对LLM ID进行比较和排名。
根据正确答案:{Ground Truth Answer},将以下答案的ID从最正确的到最不正确的进行排序:
ID: 1 答案:{LLM 1 Answer}
ID: 2 答案:{LLM 2 Answer}
ID: 3 答案:{LLM 3 Answer}
...
我们多次运行此过程并记录所有排名。在收集了所有问题的排名后,我们执行Dunn的多重比较检验[2]。这有助于我们了解所有大型语言模型(LLM)的排名是否存在显著差异,或者它们的表现是否相似。该检验在预定义的显著性水平(通常为5%)下进行成对比较,并告诉我们哪些组在统计上存在显著差异。
图2:RAQ处理机制(作者供图)
NVIDIA NIM 是什么?NVIDIA NIMs [1] 是提供现成推理 API 的容器,用于 AI 模型。它是一种云原生微服务解决方案,旨在使部署过程更加简单且节省时间。它消除了将 AI 模型连接到现有企业基础设施的复杂性。
公司通常以三种方式部署大型语言模型(LLMs):在自己的物理硬件上、在云端、或通过第三方托管的API。前两种选项提供了诸如数据隐私、安全性和模型灵活性等优势。然而,它们需要非常专业的资源以避免效率低下,例如硬件利用率低或应用程序性能问题。另一方面,后一种方式解决了性能问题,但不能确保数据隐私、安全性和模型灵活性。它也会成为核心依赖项,给部署带来额外的风险。
NIM 通过两种方式填补了这些空白。首先,它们提供了自己的第三方API,你可以使用这些API。主要的区别在于,它们提供了社区支持的模型,并确保数据隐私和安全。它们只提供运行这些模型的微服务,因此没有使用任何数据进行训练的动机,这与OpenAI、Anthropic、Google等公司的情况不同。第二种选择是使用NIM在你的专用基础设施上部署模型。在这种情况下,NIM为每个模型和硬件配置提供了优化的推理引擎。这意味着NVIDIA团队已经在基础设施方面完成了关键工作,以确保低延迟和高吞吐量。此外,它还提供了灵活性,可以自由选择其目录中的任何模型并进行最小更改部署。最后,这些模型也可以使用LoRA进行微调。
以下我们介绍如何在您自己的基础设施上从 NIM 目录中获取并运行大型语言模型 (LLM) 的过程:
- 安装 Docker (https://docs.docker.com/engine/install/)
- 安装 NVIDIA Container Toolkit (https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)
- 登录 NVIDIA
docker login [nvcr.io](https://medium.com/<http:/nvcr.io/>)
- 设置你的 NVIDIA NGC API 密钥
export NGC_API_KEY=<你的 api 密钥>
- 定义容器名称、镜像名称和下载模型的本地路径。如果你想部署另一个模型,例如 LLaMA 3 70B,你只需要将
IMG_NAME
更改为nvcr.io/nim/meta/meta-llama3-70b-instruct:<版本>
# 选择一个容器名称用于记录
export CONTAINER_NAME=meta-llama3-8b-instruct
# 从NGC选择一个LLM NIM镜像
export IMG_NAME="nvcr.io/nim/meta/${CONTAINER_NAME}:1.0.0"
# 选择系统上的一个路径来缓存下载的模型
export LOCAL_NIM_CACHE=~/.cache/nim
mkdir -p "$LOCAL_NIM_CACHE"
6. 运行以下 docker 命令。
# 启动 LLM NIM
docker run -it --rm --name=$CONTAINER_NAME \\
--runtime=nvidia \\
--gpus all \\
--shm-size=16GB \\
-e NGC_API_KEY \\
-v "$LOCAL_NIM_CACHE:/opt/nim/.cache" \\
-u $(id -u) \\
-p 8000:8000 \\
$IMG_NAME
表1:启动NIM容器的docker命令解释。
我们已经准备好了。我们现在可以向刚刚部署的 LLaMA 3 8B 发送请求了。
import requests
from pprint import pp
endpoint = '<http://0.0.0.0:8000/v1/chat/completions>'
headers = {
'accept': 'application/json',
'Content-Type': 'application/json'
}
messages = [
{"role": "user",
"content": "写一篇简短的文章,解释为什么AI很重要。"}
]
data = {
'model': 'meta/llama3-8b-instruct',
'messages': messages,
'max_tokens': 100,
'temperature': 1,
'n': 1,
'stream': False,
'stop': 'string',
'frequency_penalty': 0.0
}
response = requests.post(endpoint, headers=headers, json=data)
pp(response.json())
行业标准APIs人工智能(AI)正在改变世界,并有可能显著影响我们的日常生活。通过处理大量数据,AI 可以自动化重复性任务,改进决策过程,并提供个性化的体验。它还可以通过分析模式和识别解决方案来帮助我们应对气候变化、医疗保健和教育等复杂挑战。此外,AI 可以在从客户服务到交通运输的各种行业中提高生产率、效率和准确性。
另一个有趣的方面是 NIM 与流行的 LLM 包(如 LangChain 和 LlamaIndex)的集成。此外,任何与 OpenAI 的 API 兼容的包都可以通过更改基础 URL 轻松地与 NIM 集成。
以下示例使用 LangChain 和 OpenAI 来询问与之前相同的问题。请注意,我们提供了本地主机 URL,因为我们正在查询刚刚部署的 LLaMA 3 8B 模型。在这种情况下,我们创建了一个 LLMChain,它使用一个简单的模板接收一个问题并将其传递给 LLaMA。
from langchain import PromptTemplate
from langchain.chains import LLMChain
from langchain_openai import ChatOpenAI
template = """
问题: {question}
回答:
"""
prompt = PromptTemplate(
template=template, input_variables=["context", "question"]
)
llm = ChatOpenAI(base_url="<http://localhost:8000/v1>",
model="meta/llama3-8b-instruct",
api_key="not-used",
temperature=0.1,
max_tokens=100,
top_p=1.0)
query_llm = LLMChain(
llm=llm,
prompt=prompt,
)
answer = query_llm.invoke(
{"question": "写一段简短的信息,解释为什么AI很重要。"}
)
领域特定模型人工智能(AI)在当今世界中至关重要,因为它有可能彻底改变我们生活、工作和相互交流的方式。AI 可以自动化重复性和繁琐的任务,释放人力资源,使其能够专注于更具创意和战略性的任务。它还可以改善医疗保健成果,增强客户服务,并优化企业运营。此外,AI 可以通过提供数据驱动的见解和解决方案来帮助我们应对气候变化、贫困和不平等这些复杂的全球性挑战。
像 HuggingFace 一样,NVIDIA API 目录 非常全面,包含了解决不同领域问题的模型,例如语言、语音、视觉和游戏。
在本文中,我们重点关注四种可用的语言模型:
- mistralai /mistral-7b-instruct-v0.3
- mistralai /mixtral-8x22b-instruct-v0.1
- meta/llama3–70b-instruct
- meta/llama3–8b-instruct
本节测试四个模型在许可证为 CC BY-SA 4.0 的问题回答数据集 SQuAD 中的表现。该阅读理解数据集包含关于一组维基百科文章的问题。根据上下文,模型应该能够回答正确的问题。对我们用例来说,三个更重要的字段是:
-
question
- 模型需要回答的问题。 -
context
- 模型需要从中提取答案的背景信息。 answers
- 问题的文字答案。
为了进行评估,我们使用上述描述的相对答案质量(RAQ)。在这个实例中,我们使用GPT-3.5作为独立的大规模语言模型(LLM),对感兴趣的LLM集合进行排名。它根据真实答案从最好(rank=1
)到最差(rank=4
)对它们的答案进行排序。
RAQ 使用一种名为 Dunn’s 多重比较检验的统计检验来评估这些大型语言模型(LLMs)的排名之间是否存在统计学上的显著差异。
最后,RAQ 还比较了每秒单词数和平均答案长度,这为模型性能和冗长程度提供了额外的数据点。
我们首先在 env/
目录下设置一个 env 文件,包含 OpenAI 和 NCG API 密钥:
- var.env 文件
OPENAI_KEY=<YOUR_OPENAI_KEY>
NGC_API_KEY=YOUR_NGC_API_KEY
然后,我们导入所有库,加载API密钥,并定义要从NVIDIA目录中使用的模型。
import os
import matplotlib.pyplot as plt
import pandas as pd
import scikit_posthocs as sp
import seaborn as sns
import utils
from datasets import load_dataset
from dotenv import load_dotenv
from generator import Generator
load_dotenv('env/var.env')
# 模型
llama8b = Generator(model='meta/llama3-8b-instruct', ngc_key=os.getenv("NGC_API_KEY"))
mistral7b = Generator(model="mistralai/mistral-7b-instruct-v0.3", ngc_key=os.getenv("NGC_API_KEY"))
llama70b = Generator(model="meta/llama3-70b-instruct", ngc_key=os.getenv("NGC_API_KEY"))
mixtral = Generator(model="mistralai/mixtral-8x22b-instruct-v0.1", ngc_key=os.getenv("NGC_API_KEY"))
Generator 类负责加载模型并创建由 LangChain 提供支持的 Prompt 模板。它在将查询和上下文传递给大语言模型以获取响应之前进行格式化。
from langchain import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
class Generator:
"""生成器,即LLM,根据问题和上下文提供答案"""
def __init__(self, model: str, ngc_key: str) -> None:
# 模板
self.template = """
使用以下上下文来简洁清晰地回答问题:
{context}
问题:{question}
回答:
"""
# LLM
self.llm = ChatOpenAI(
base_url="<https://integrate.api.nvidia.com/v1>",
api_key=ngc_key,
model=model,
temperature=0.1)
# 创建提示模板
self.prompt = PromptTemplate(
template=self.template, input_variables=["context", "question"]
)
def generate_answer(self, context: str, question: str) -> str:
"""
根据上下文和用户的问题从LLM获取答案
Args:
context (str): 最相似的文档
question (str): 用户的问题
Returns:
str: LLM的回答
"""
query_llm = LLMChain(
llm=self.llm,
prompt=self.prompt,
llm_kwargs={"max_tokens": 2000},
)
answer = query_llm.invoke(
{"context": context, "question": question}
)
return answer['text']
加载了大语言模型后,我们从HuggingFace获取SQuAD数据集并打乱顺序,以确保问题主题的多样性。
squad = load_dataset("squad", split="train")
squad = squad.shuffle()
现在,我们可以将 RAQ 循环应用于 100 个问题和上下文中,并记录上述指标。
for i in range(100):
context = squad[i]['context']
query = squad[i]['question']
answer = squad[i]['answers']['text'][0]
# Llama 8B
answer_llama, words_per_second, words = utils.get_llm_response(llama8b, context, query)
llama8b_metrics["words_per_second"].append(words_per_second)
llama8b_metrics["words"].append(words)
# Mistral 7B
answer_mistral, words_per_second, words = utils.get_llm_response(mistral7b, context, query)
mistral7b_metrics["words_per_second"].append(words_per_second)
mistral7b_metrics["words"].append(words)
# Llama 70B
answer_llama70b, words_per_second, words = utils.get_llm_response(llama70b, context, query)
llama70b_metrics["words_per_second"].append(words_per_second)
llama70b_metrics["words"].append(words)
# Mixtral
answer_mixtral, words_per_second, words = utils.get_llm_response(mixtral, context, query)
mixtral_metrics["words_per_second"].append(words_per_second)
mixtral_metrics["words"].append(words)
# GPT-3.5 排序
llm_answers_dict = {'llama8b': answer_llama, 'mistral7b': answer_mistral, 'llama70b': answer_llama70b, 'mixtral': answer_mixtral}
rank = utils.get_gpt_rank(answer, llm_answers_dict, os.getenv("OPENAI_API_KEY"))
llama8b_metrics["rank"].append(rank.index('1')+1)
mistral7b_metrics["rank"].append(rank.index('2')+1)
llama70b_metrics["rank"].append(rank.index('3')+1)
mixtral_metrics["rank"].append(rank.index('4')+1)
函数 get_llm_response
接收加载的 LLM、上下文和问题,并返回 LLM 的回答以及量化指标。
def 获取_llm_response(model: Generator, context: str, query: str) -> Tuple[str, int, int]:
"""
根据上下文和查询从给定的LLM生成答案
返回答案、每秒单词数和总单词数
Args:
model (Generator): LLM
context (str): 上下文数据
query (str): 查询
Returns:
Tuple[str, int, int]: 答案, 每秒单词数, 单词总数
"""
初始化时间 = time.time()
llm答案 = model.get_answer(context, query)
总时间 = time.time()-初始化时间
每秒单词数 = len(re.sub("[^a-zA-Z']+", ' ', llm答案).split())/总时间
单词总数 = len(re.sub("[^a-zA-Z']+", ' ', llm答案).split())
return llm答案, 每秒单词数, 单词总数
另一方面,get_gpt_rank
函数实现了 RAQ 核心逻辑。它负责接收真实答案和每个大语言模型(LLM)的答案,并向 GPT-3.5 发送请求,根据正确性对它们进行排名。
def get_gpt_rank(true_answer: str, llm_answers: dict, openai_key: str) -> list:
"""
实现RAQ核心:根据正确答案,使用GPT-3.5对LLM的答案进行排名
Args:
true_answer (str): 正确答案
llm_answers (dict): LLM答案
openai_key (str): OpenAI密钥
Returns:
list: LLM ID的排名
"""
# 从OpenAI获取格式化的输出
functions = define_open_ai_function()
gpt_query = f"""基于正确答案:{true_answer},对以下四个答案的ID从最正确到最不正确的顺序进行排名:
ID: 1 答案:{re.sub("[^a-zA-Z0-9']+", ' ', llm_answers['llama8b'])}
ID: 2 答案:{re.sub("[^a-zA-Z0-9']+", ' ', llm_answers['mistral7b'])}
ID: 3 答案:{re.sub("[^a-zA-Z0-9']+", ' ', llm_answers['llama70b'])}
ID: 4 答案:{re.sub("[^a-zA-Z0-9']+", ' ', llm_answers['mixtral'])}"""
completion = OpenAI(api_key=openai_key).chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": gpt_query}],
functions=functions,
function_call={"name": "return_rank"},
)
response_message = completion.choices[0].message.function_call.arguments
rank = ast.literal_eval(response_message)["rank"].split(",")
if len(rank) == 1:
rank = list(rank[0])
return rank
从图3可以看出,LLaMA 3 8B是最快速的大型语言模型,平均每秒生成约43个单词。在回答长度方面,Mistral 7B生成的回答更长,平均长度为24个单词,远超过LLaMA 70B的8个单词。最后,根据独立的大型语言模型排名,Mistral 7B的平均排名约为2.25,而LLaMA 3 8B的平均排名约为2.8,表现最差。
图3:所有大语言模型(LLM)之间的指标比较(作者提供)
表2展示了Dunn事后检验的结果,比较了不同语言模型的性能。每个单元格表示相应模型之间在5%显著性水平下的性能差异是否具有统计学意义。“显著”表示具有统计学意义的差异(p值≤0.05),而“不显著”表示没有统计学意义的差异(p值>0.05)。
对于选定的显著性水平,邓恩检验的结果表明,Mistral 7B 的表现与 LLaMA 3 8B 显著不同,但与其他大语言模型(LLMs)没有显著差异。为了增加在剩余比较中检测到显著差异的可能性,可以增加测试的样本量(用于排名模型的示例数量)。样本量增大后,如果确实存在排名差异,我们可能会获得更小的 p 值。
p_values = sp.posthoc_dunn([mistral7b_metrics['rank'], llama8b_metrics['rank'], llama70b_metrics['rank'], mixtral_metrics['rank']], p_adjust='holm')
p_values < 0.05
表2:各组大型语言模型(LLMs)排名差异的显著性
如前所述,RAQ 的好处在于它可以用于评估任何一组大语言模型(LLM)在任何领域/主题/使用案例上,而无需依赖传统的基准测试。这意味着,根据使用的数据集不同,在这种评估中不同的模型会脱颖而出。
结论在开发更强大的大型语言模型(LLMs)并使其易于每个人访问方面取得的快速进展带来了新的采用挑战。公司正在寻找将这些模型集成到内部和外部工具中的新方法。然而,目前选择和部署这些模型的方法在控制、隐私、灵活性和安全性之间存在很大的权衡。
在本文中,我们介绍了RAQ,这是一个用于评估和比较一组大型语言模型(LLMs)答案质量的新框架。它使得为新的应用场景选择一个LLM变得客观、可扩展和灵活。灵活性来源于这样一个事实:当一个组织有以前的私人示例并希望用这些示例测试这组LLMs时,可以应用该框架。即使在没有这些数据集的情况下,该框架仍然可以正常工作。
选择了大语言模型后,我们探索了NIM作为部署模型的解决方案。NIM确保了隐私、安全性和可扩展性,无论模型是部署在物理硬件、私有云还是作为托管服务。
我们应用了相对答案质量(RAQ)并使用NVIDIA NIM来比较Mistral和Meta模型(小版本和大版本)的性能。我们使用了一个阅读理解数据集来展示如何使用RAQ。在我们的设置中,Mistral 7B表现最佳,生成的答案明显优于LLaMA 3 8B。而LLaMA 3 8B实际上是最快的模型,每秒生成的单词更多。这表明选择模型通常需要在质量和速度之间进行权衡。
关于我连续的创业者,也是人工智能领域的领导者。我为企业开发人工智能产品,并投资专注于人工智能的初创公司。
创始人 @ ZAAI | 领英 | X/Twitter
参考资料[1] https://developer.nvidia.com/blog/nvidia-nim-offers-optimized-inference-microservices-for-deploying-ai-models-at-scale/ NVIDIA NIM 提供了优化的推理微服务,用于大规模部署 AI 模型。
[2] Dunn, O. J. (1964) 使用秩和进行多重比较. 技术计量学. 6, 241–252. doi:10.1080/00401706.1964.10490181.
共同学习,写下你的评论
评论加载中...
作者其他优质文章