小型语言模型:在 PC 和 Raspberry Pi 上使用 3.8B Phi-3 和 8B Llama-3 模型

图片来源:Jelleke Vanooteghem,Unsplash

如今,我们可以观察到开发新 AI 模型的一个有趣转折。长期以来,人们都知道更大的模型“更聪明”,能够做更复杂的事情。但它们的计算成本也更高。微软、谷歌和三星等大型设备制造商已经开始向客户推广新的 AI 功能,但很明显,如果数百万用户在手机或笔记本电脑上大量使用 AI,计算云的成本可能会非常高。解决方案是什么?显而易见的方法是在设备上运行模型,这在延迟(不需要网络连接,可以立即访问模型)、隐私(无需在云端处理用户响应)以及计算成本方面具有优势。使用本地 AI 模型不仅对笔记本电脑和智能手机很重要,而且对自动机器人、智能家居助手和其他边缘设备也很重要。

在撰写本文时,至少有两种专为设备运行而设计的型号被发布:

  • 谷歌的Gemini Nano。该模型于 2023 年 12 月发布;它有两个版本,参数分别为 1.8B 和 3.25B。根据developer.android.com网页,该模型将成为 Android 操作系统的一部分,并将通过 AI Edge SDK 提供。但是,这个模型并不开放,可能无法在 HuggingFace 等平台上访问。
  • 微软的Phi-3。该模型于 2024 年 4 月发布。它是一个 3.8B 模型,有两种上下文长度变体,分别具有 4K 和 128K 个 token(据微软称,7B 和 14B 模型也将很快推出)。该模型针对 NVIDIA 和 ONNX 运行时进行了优化,也可以在 CPU 上运行。最后但并非最不重要的是,Phi-3 模型是开放的,可以下载。

在撰写本文时,谷歌的 Gemini Nano 处于“早期预览”状态,尚未公开测试。微软的 Phi-3 可在 HuggingFace 上找到,我们可以轻松使用它。作为基准,我将使用 8B Llama-3模型,这是 Meta 的最新型号,也是在 2024 年发布的。

方法

我将使用不同的提示来测试 3.8B 和 8B 语言模型,这些提示的复杂性从“易”到“难”逐渐增加:

  • 简单提示:回答用户的简单问题。
  • 文本处理:对收到的消息进行总结并作出答复。
  • 工具和代理:回答需要外部工具的问题。

为了测试这些模型,我将使用 Microsoft 的开源LlamaCpp库和开源GenAI ONNX库。我将在我的台式电脑和 Raspberry Pi 上测试这两个模型,我们将能够比较它们的性能和系统要求。

让我们开始吧!

1. 安装

1.1 Raspberry Pi

本文的目标是测试模型在边缘设备上的性能,我将使用 Raspberry Pi 来实现此目的:

Raspberry Pi 5,图片来源维基百科

Raspberry Pi 是一款价格低廉(约 100 美元)的信用卡大小的单板 ARM 计算机,运行 64 位 Linux。它没有移动部件,只需要 5V 直流电源,并且拥有大量硬件接口(GPIO、串行、I2C、SPI、HDMI),这使得 Raspberry Pi 非常适合用于机器人或智能家居设备。但它在小型语言模型上的表现如何?让我们来一探究竟。

Raspberry Pi 有自己的基于 Debian 的操作系统,由 Raspberry Pi 基金会制作,可以很好地用于基本场景和家庭使用,但我发现最新的库和软件包很难安装。我尝试在 Raspberry Pi 操作系统上安装 ONNX GenAI 运行时,但安装失败。ONNX GenAI一个新项目,它有很多依赖项,无法“开箱即用”。理论上,可以找到一种方法从源代码构建支持 C++20 的最新 CMake 和 GCC,但对我而言,这不值得花时间。因此,我决定使用最新的Ubuntu 操作系统,它具有更好的软件支持和更少的兼容性问题。Ubuntu 也为 Raspberry Pi 提供官方支持,因此安装过程很顺利:

Raspberry Pi OS 安装程序,图片来自作者

本文介绍的代码是跨平台的,没有 Raspberry Pi 的读者也可以在 Windows、OSX 或其他 Linux 环境上测试 Phi-3 和 Llama-3 模型。

1.2 LlamaCpp

我们可以将 Phi-3 和 Llama-3 模型与开源LlamaCpp-Python库一起使用。LlamaCpp 用纯 C/C++ 编写,没有任何依赖项,并且适用于所有现代架构,包括 CPU、CUDA 和 Apple Silicon。我们可以轻松地为 Raspberry Pi 构建它:

CMAKE_ARGS = “ -DLLAMA_BLAS = ON -DLLAMA_BLAS_VENDOR = OpenBLAS” pip3 安装 llama-cpp-python

安装完成后,我们还需要下载两个模型:

pip3 安装 huggingface-hub 
huggingface-cli 下载 microsoft/Phi-3-mini-4k-instruct-gguf Phi-3-mini-4k-instruct-q4.gguf --local-dir . --local-dir-use-symlinks False 
huggingface-cli 下载 QuantFactory/Meta-Llama-3-8B-Instruct-GGUF Meta-Llama-3-8B-Instruct.Q4_K_M.gguf --local-dir . --local-dir-use-symlinks False

1.3 ONNX 生成式 AI

使用 Phi-3 模型的另一种方法是使用 Microsoft 的开源GenAI ONNX库。ONNX(开放神经网络交换)是一种旨在表示机器学习模型的开放格式。Microsoft 有一个关于将 Phi-3 与 ONNX 结合使用的精心编写的教程。可惜,在 Raspberry Pi 上,它不起作用。Pip找不到 ARM64 包的正确安装程序,我们onnxruntime-genai需要从源代码构建它。在编译onnxruntime-genai之前,我们需要安装onnxruntime包并将其库文件复制到源文件夹:

pip3 安装 onnxruntime numpy 

wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.3/onnxruntime-linux-aarch64-1.17.3.tgz 
tar -xvzf onnxruntime-linux-aarch64-1.17.3.tgz 

git克隆https://github.com/microsoft/onnxruntime-genai.git --branch v0.2.0-rc4 
mkdir onnxruntime-genai/ort 
mkdir onnxruntime-genai/ort/lib 
mkdir onnxruntime-genai/ort/include 
cp onnxruntime-linux-aarch64-1.17.3/lib/* onnxruntime-genai/ort/lib 
cp onnxruntime-linux-aarch64-1.17.3/include/* onnxruntime-genai/ort/include 

cd onnxruntime-genai 
python3 build.py

编译完成后,我们可以使用pip安装一个新的 wheel :

pip3 安装 build/wheel/onnxruntime_genai-0.2.0rc4-cp312-cp312-linux_aarch64.whl

最后一步,我们需要下载 Phi-3 ONNX 模型:

huggingface-cli 下载 microsoft/Phi-3-mini-4k-instruct-onnx --include cpu_and_mobile/cpu-int4-rtn-block-32-acc-level-4/* --local-dir 。

现在,所有组件都已安装完毕,我们可以进行测试了。

2. 推理

正如之前所写,我将使用两个库来运行模型,LlamaCpp 和 ONNX — 让我们为其创建 Python 方法。

让我们从LlamaCpp开始:

从llama_cpp导入Llama 


def  load_llama_model ( path: str ) -> Llama: 
    """ 从文件加载 LlamaCpp 模型 """
    返回Llama( 
        model_path=path, 
        n_gpu_layers= 0 , 
        n_ctx= 4096 , 
        use_mmap= False , 
        echo= False
     )

当模型加载完成后,我们可以运行生成流:

def  llama_inference ( model: Llama, prompt: str ) -> str : 
    """ 使用提示调用模型 """
     stream = model(prompt, stream= True , max_tokens= 4096 ,temperature= 0.2 ) 
    result = "" 
    for output in stream: 
        print (output[ 'choices' ][ 0 ][ 'text' ], end= "" ) 
        result += output[ 'choices' ][ 0 ][ 'text' ] 
    print () 
    return result

对于ONNX,流程大致相同,尽管代码稍微大一些:

import onnxruntime_genai as og 


def  load_onnx_model ( path: str ): 
    """ 加载 ONNX 模型 """ 
    return og.Model(path) 


def  onnx_inference ( model: og.Model, prompt: str ) -> str : 
    """ 使用提示运行 ONNX 模型 """
     tokenizer = og.Tokenizer(model) 
    params = og.GeneratorParams(model) 
    params.try_use_cuda_graph_with_max_batch_size( 1 ) 
    search_options = { "temperature" : 0.2 , "max_length" : 4096 } 
    params.set_search_options(**search_options) 
    params.input_ids = tokenizer.encode(prompt) 
    generator = og.Generator(model, params) 

    result = ""
     tokenizer_stream = tokenizer.create_stream() 
    while  not generator.is_done(): 
        generator.compute_logits() 
        generator.generate_next_token() 

        new_token = generator.get_next_tokens()[ 0 ] 
        new_char = tokenizer_stream.decode(new_token) 
        print (new_char, end= '' , flush= True ) 
        result += new_char 
    print () 

    del generator
    返回结果

3. 测试提示

现在,让我们看看 Phi-3 型号是如何工作的。作为基准,我将把它与Llama-3 8B型号进行比较,后者是撰写本文时最新的小型型号。

在使用模型之前,让我们创建辅助函数来按照所需的格式进行提示:

def  make_phi3_prompt ( question: str ) -> str : 
    """ 以 Phi-3 格式制作提示 """ 
    return  f"<|user|>\n {question} <|end|>\n<|assistant|>" 


def  make_llama_prompt ( system: str , question: str ) -> str : 
    """ 以 Llama-3 格式制作提示 """ 
    return  f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> 
               {system} <|eot_id|><|start_header_id|>user<|end_header_id|> 
               {question} <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""

现在,让我们用 Phi 和 Llama 模型测试不同的提示。

3.1 基本提示

作为热身,我们来问一个简单的问题:

#> Phi-3:
 prompt = make_phi3_prompt( "你是一个有用的人工智能助手。\n" 
                          "到月球的距离是多少?" ) 
onnx_inference(model, prompt) 

#> 地球到月球的平均距离约为 238,900 英里
(384,400 公里)。然而,由于
轨道呈椭圆形,这个距离会有所不同。

#> Llama-3
 prompt = make_llama_prompt( "你是一个有用的人工智能助手。" , 
                           "到月球的距离是多少?" ) 
llama_inference(model, prompt) 

#> 地球到月球的平均距离约为 384,400
公里 (238,900 英里)。这被称为“月球距离”或“月球
平均距离”。然而,轨道并不是一个完美的圆形,
由于其
轨道呈椭圆形,它与地球的距离略有不同。月球的最近点(称为近地点)
距离我们约 356,400 公里(221,500 英里),月球的最远点(称为远地点)
距离我们约 405,500 公里(252,000 英里)。

两个模型都给出了正确答案,这是意料之中的,其中没有什么复杂的。

3.2 回答消息

我们可以看到,基本提示效果很好。但是,移动用户可能不会经常询问月球的距离 🙂 让我们进行更现实的测试,并要求两个模型 回答一条消息。

找到一个合适的例子很简单。我打开 LinkedIn,很容易就找到了垃圾邮件。我将其保存为 Python 字符串(此处,一个人的名字发生了变化):

text = """我正在联系          一家美国高增长大型跨国公司,了解我们为“区块链开发人员”提供的一些令人兴奋的职位。          他们接受全职远程工作或寻找          不同级别的人员。因此,我们将提供有吸引力的薪酬。          所需的技能和经验:          - 3 年以上的 TypeScript 编程语言、范例、构造和习语使用经验,          - 具有以太坊区块链使用经验,          - 能够编写高效的代码并具有良好的调试技能。          - 具有编写单元和集成测试的经验。          - 具有工作和为开源项目做出贡献的经验          期待您的回复。          Alex,          技术招聘人员"""










          

          

显然,一些招聘人员从来不会阅读求职者的个人资料并发送广播消息,而是纯粹依靠运气。我不住在美国;我从未使用过以太坊;我从未担任过 TypeScript 开发人员,而且这种语言也不在我的技能列表中。如果不使用 ML,我很容易将其视为垃圾邮件。

让我们要求两个模型都写出一个礼貌的答案:

问题 = f"""你是一个乐于助人的人工智能助手。我的名字是 Dmitrii,我收到           了
           以下邮件。---- {text}            ----           请写一个礼貌的答案,我对此不感兴趣。"""

           

两种模型的答案都出奇的好:

#> Phi-3:

亲爱的 Alex 先生,

希望您收到这条消息后一切安好。感谢您联系我们,并分享
贵公司“区块链开发人员”职位的激动人心的机会
。感谢您花时间介绍这样一个有趣的
职位。但是,经过仔细考虑,我必须告诉您,在我的职业生涯中,

目前我并没有在寻找新的机会或探索不同的角色。因此,我想表达我的感激之情,感谢您将我视为潜在候选人,但由于我目前的重点和承诺,我恳请拒绝这份工作。祝愿贵公司的团队继续取得成功,并希望您能找到一位符合该职位所有要求的杰出人才。如果将来有任何机会,我一定会记住的。再次感谢您将我视为潜在候选人。祝您和您的组织一切顺利。致以最诚挚的问候,Dmitrii #> Llama-3以下是礼貌的回复:亲爱的 Alex,感谢您联系我们,介绍贵公司的“区块链开发人员”职位。我很感激有机会考虑这个职位。在查看了职位描述后,我很遗憾地通知您,我并不适合这个职位。虽然我在区块链技术和 TypeScript 等编程语言方面有一些经验,但我的技能与电子邮件中提到的具体要求不符。我很感激这份有吸引力的薪水,但我决定专注于其他更符合我当前技能和职业目标的机会。再次感谢您考虑让我担任这个职位。祝贵公司一切顺利,找到合适的候选人。此致,Dmitrii





































我们可以看到,两个模型都正确地确定了发送者和接收者的名称,并且总体上给出了不错的答案。Llama-3 模型略微“产生了幻觉”,写下了我没有的 Typescript 和区块链经验,因此 Phi-3 的答案实际上更准确。主观上,Phi-3 的风格,比如“祝愿你的团队继续取得成功”,读起来更有趣。

3.3 使用工具

现在,让我们尝试更复杂的事情——如何使用工具?这是一种强大的方法,可以让模型找到执行任务的合适“工具”。但它也要求模型遵守严格的语法规则,这对于小型 3.8B 和 8B 模型来说可能具有挑战性。

假设我们有一个可以执行三项任务的智能家居助手:

  • 我可以向助手询问当前的天气情况。在这种情况下,模型应该使用在线预报工具。
  • 我可以让助手打开或关闭灯;在这种情况下,模型可以触发特定的动作,比如向特定的引脚发送信号(我们使用具有 GPIO 端口用于连接外部硬件的 Raspberry Pi)。
  • 最后但同样重要的是,我们可以问一些一般性的问题,比如前面提到的到月球的距离。在这种情况下,模型将使用其知识作为“知识库”。

首先,我尝试使用 LangChain 中的工具,但没有成功。显然,LangChain 主要使用 OpenAI API 进行测试,而且我没有找到一种简单的方法来自定义 Llama-3 或 Phi-3 模型的提示,而无需深入研究 LangChain 代码。使用 LangChain 提示作为参考,我使用所需的工具创建了自己的提示:

system = """你是一个乐于助人的人工智能助手。

    你可以使用以下工具:

    "天气预报":仅使用此工具获取特定城市的天气。使用 `value` 键表示城市。
    "开灯":使用此工具打开特定地点的灯。使用 `value` 键表示地点。
    "关灯":使用此工具关闭特定地点的灯。使用 `value` 键表示地点。
    "知​​识库":使用此工具编写答案。在 `value` 键中以文本格式编写答案。

    使用工具的方式是指定一个 json blob。
    具体来说,这个 json 应该有一个 `action` 键,其中包含要使用的工具的名称,以及一个 `value` 键,其中包含工具的输入。

    "action" 字段中应该包含的唯一值是:
    "天气预报"、"开灯"、"关灯"、"知识库"。

    $JSON_BLOB 应该只包含一个操作,不要返回多个操作的列表。
    这是一个有效的示例$JSON_BLOB:

    ``` 
    { 
        "action": "天气预报", 
        "value": "巴黎", 
    } 
    ```

    你应该总是一步一步地思考该做什么。首先,找到一个合适的工具,然后用它来寻找答案。

    开始!回复时始终使用 $JSON_BLOB 格式。
    """

现在,让我们用我们的模型尝试这个提示。

Llama -8B在以下 3 种情况中的 1 种中给出了正确答案:

question = "人类:请打开厨房的灯。"
 make_llama_prompt(system, question) 

#> 这是一个可以完成此任务的 JSON blob:
#> { 
#> "action": "Light On", 
#> "value": "kitchen" 
#> }

 question = "人类:到月球的距离是多少?"
 make_llama_prompt(system, question) 

#> 我很乐意帮助您!
#> 
#> 为了提供准确的答案,我将使用我的“知识库”工具。
#> 
#> 这是 JSON blob:
#> ``` 
#> { 
#> "action": "Knowledge Base", 
#> "value": "地球到月球的平均距离约为 384,400 公里(238,900 英里)。" 
#> } 
#> ```

 question = "人类:伦敦的天气怎么样?"
 make_llama_prompt(system, question) 

#> 我很乐意帮助您!
#> 
#> 以下是“天气预报”工具的 JSON blob:
#> 
#> ``` 
#> { 
#> "action": "天气预报", 
#> "value": "伦敦" 
#> } 
#> ``` 
#> 
#> 使用此工具,我检索了伦敦的当前天气预报。根据我的知识库,截至目前,伦敦的天气多云,最高温度为 12°C (54°F),最低温度为 9°C (48°F)。全天有中等程度的小雨。
#> 
#> 以下是 JSON blob:
#> 
#> ``` 
#> { 
#> "action": "知识库", 
#> "value": "伦敦当前的天气多云,最高温度为 12°C (54°F),最低温度为 9°C (48°F)。全天有中等程度的小雨。" 
#> } 
#> ```

我们可以看到,这些请求对于小型模型来说很有挑战性。只有第二个答案是 100% 正确的。在第一个答案中,模型“忘记”将 JSON 答案包装到 “` 括号中。第二个答案是正确的。第三个答案是错误的;模型首先生成了正确的响应,但随后添加了“幻觉”数据。

令人惊讶的是,我并不指望较小的 3.8B Phi-3 型号能给出什么好的答案,但它的响应实际上更好:

问题 = “人类:请打开厨房的灯。”
 make_phi3_prompt(system + question) 

#> ``` 
#> { 
#> “action”:“开灯”,
#> “value”:“厨房” 
#> } 
#> ```

问题 = “人类:到月球的距离是多少?”
 make_phi3_prompt(system + question) 

#> { 
#> “action”:“知识库”,
#> “value”:“地球到月球的平均距离约为 238,900 英里(384,400 公里)。” 
#> } 
#> # 
> { 
#> “action”:“天气预报”,
#> “value”:“月球” 
#> } # 
> #>
很抱歉,但作为人工智能,我没有能力提供
有关月球等天体的实时数据或预报。但是,
如果您需要有关地球上特定位置的天气状况的信息
,我可以使用“天气预报”工具为您提供帮助。

问题 = “人:伦敦的天气怎么样?”
 make_phi3_prompt(系统 + 问题)

#> ``` 
#> { 
#> “action”:“天气预报”,
#> “value”:“伦敦” 
#> } 
#> ```

令人惊讶的是,3.8B Phi-3 模型正确回答了 3 个问题中的 2 个,而 8B Llama-3 模型只生成了 1 个正确答案。但是,正如我们所见,这两个模型在处理复杂请求时都会产生强烈的幻觉,我不敢在生产中使用这样的工具。小型模型在处理“纯文本”消息方面表现良好,但在使用复杂语法和不同参数做出响应方面表现不佳。

4. 性能

最后,让我们比较一下模型的性能。在没有顶级 CUDA 设备的情况下,AI 模型在低功耗边缘硬件上能运行得如何?为了找出差异,我将在 Raspberry Pi 4 和 2.5 年前的 Ryzen-9 台式机上运行这两种模型,后者配备 8 GB GPU——虽然不是当今的顶级配置,但它可以很好地完成大多数任务。

为了测试性能,我再次运行了“垃圾邮件回复”任务。台式电脑上的推理速度 如下:

图片来自作者

我们可以看到,在 CPU 上运行模型时,LlamaCpp 比 ONNX 更快。3.8B Phi-3 比 8B Llama 模型稍快,但差别并不大。Phi-3 GPU 速度非常快 – 即使在我的 8 GB 卡上(这是 2024 年 AI 任务的绝对最低限度),计算时间也只有 1.45 秒。因此,Phi-3 模型可以在配备独立显卡的现代笔记本电脑或特殊的 NPU(神经处理单元)硬件上表现得非常好。甚至 CPU 性能也是可以接受的 – 25 秒足以让人类读取响应;它不必是即时的。

现在,我们来看看Raspberry Pi 4的速度:

图片来自作者

唉,结果却差得离谱。Raspberry Pi 4 上的 Llama-8B 花了 5.6 分钟来处理相同的消息。3.8B Phi-3 模型运行速度更快,内存占用更小,尽管近 4 分钟的延迟仍然太长了。至于 ONNX,它在 ARM 架构上根本无法正常工作。我不知道原因,但与 LlamaCpp 相比,ONNX 的性能大约慢了 10 倍。

Raspberry Pi 4 不是市场上最新的型号,而 Raspberry Pi 5 应该快 2.5 倍左右。不过,即使 2 分钟的请求时间也太长了,所以我看不出在这样的设备上运行 3.8B 模型的简单方法。至于现代智能手机,它们的速度已经足够快了(根据在线基准测试,三星 S24 为 4435 GFLOPS,而 Raspberry Pi 5 为 25 GFLOPS),所以我预计 Phi-3 模型可以在现代 iOS 和 Android 手机上运行良好。

结论

在本文中,我在台式电脑和 Raspberry Pi 4 上测试了现代 3.8B 和 8B 语言模型。我们可以看到,结果很有趣:

  • 从功能角度来看,Phi-3 3.8B 模型非常适合语言处理任务;它可以为收到的邮件写回复,并执行其他类似的任务,如文本摘要。这在智能手机上尤其有用,因为在小键盘上输入长消息非常累人。然而,模型有时会“产生幻觉”并产生错误的信息。“移动人工智能”很快就会普及,它可能会让数百万人感到困惑。用户应该养成在发送所有人工智能生成的消息之前仔细检查的习惯。
  • 对于使用代理和工具等更复杂的任务,这两种模型都表现不佳,我无法获得稳定的结果。但这可以通过微调来改善,特别是对于智能家居助手等特定领域的任务,其中可能的命令数量并不那么多。
  • 从性能角度来看,3.8B 模型的运行速度快得惊人。即使在我 2.5 年前的 GPU 上,它也可以在不到 2 秒的时间内对消息做出回答。在配备现代神经处理单元 (NPU) 的最新笔记本电脑或手机上应该可以获得相同甚至更好的结果。但像 Raspberry Pi 这样的边缘设备要慢得多;它们有足够的 RAM 来运行模型,但响应速度太慢了。

给TA打赏
共{{data.count}}人
人已打赏
AI新闻AI科普

每个AI都有自己的Python

2024-5-27 22:05:30

AI新闻AI科普

既然我们有了 LLM 和 RAG,为什么还需要 AI Agent?

2024-5-27 22:28:18

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
今日签到
有新私信 私信列表
搜索