iOS Swift SDK

MLC LLM iOS 应用程序可以通过两种方式安装:通过预构建的包或从源代码构建。如果您是希望尝试模型的 iOS 用户,推荐使用预构建的包。如果您是开发者,希望将新功能集成到包中,则需要从源代码构建 iOS 包。

使用预构建的 iOS 应用程序

MLC Chat 应用程序现已免费登陆 App Store。您只需点击下方按钮即可下载并探索其功能:

从源代码构建 iOS 应用程序

本节展示了如何从源代码构建应用程序。

第一步:安装构建依赖项

首先,请克隆 MLC LLM GitHub 仓库。克隆完成后,进入 ios/ 目录。

git clone https://github.com/mlc-ai/mlc-llm.git
cd mlc-llm
git submodule update --init --recursive
cd ./ios

请按照 安装 MLC LLM Python 包 的说明获取 mlc_llm 包的二进制构建版本。请注意,这与用于 iOS 包构建的上述源代码是独立的。您无需为主机环境构建 mlc_llm,我们可以直接使用预构建的包来实现这一目的。

还需要具备以下构建依赖项:

  • CMake >= 3.24,

  • Git and Git-LFS,

  • Rust 和 Cargo,这是 Hugging Face 分词器所必需的。

第二步:构建运行时和模型库

为 iOS 应用程序构建的模型在 MLCChat/mlc-package-config.json 文件中指定,具体位于 model_list 部分:

  • model 指向包含预转换模型权重的 Hugging Face 仓库。iOS 应用程序将从该 Hugging Face URL 下载模型权重。

  • model_id 是模型的唯一标识符。

  • estimated_vram_bytes 是对模型在运行时占用的 vRAM 的估计。

  • "bundle_weight": true 表示在构建时,模型的权重将被捆绑到应用程序中。

  • overrides 指定了一些模型配置参数的覆盖值。

有一行命令可以构建并准备所有模型库:

cd /path/to/MLCChat  # e.g., "ios/MLCChat"
export MLC_LLM_SOURCE_DIR=/path/to/mlc-llm  # e.g., "../.."
mlc_llm package

该命令主要执行以下两个步骤:

  1. 编译模型。MLCChat/mlc-package-config.jsonmodel_list 的每个模型编译成二进制模型库。

  2. 构建运行时和分词器。 除了模型本身外,还需要轻量级的运行时和分词器来实际运行大语言模型。

该命令会创建包含运行时和模型构建输出的 ./dist/ 目录。请确保 dist/ 遵循以下结构(除可选的模型权重外):

dist
├── bundle                   # The directory for mlc-app-config.json (and optionally model weights)
│   │                        # that will be bundled into the iOS app.
│   ├── mlc-app-config.json  # The app config JSON file.
│   └── [optional model weights]
└── lib
   ├── libmlc_llm.a          # A lightweight interface to interact with LLM, tokenizer, and TVM Unity runtime.
   ├── libmodel_iphone.a     # The compiled model lib.
   ├── libsentencepiece.a    # SentencePiece tokenizer
   ├── libtokenizers_cpp.a   # Huggingface tokenizer.
   └── libtvm_runtime.a      # TVM Unity runtime.

备注

利用本地 JIT 缓存来避免重复编译相同的输入。然而,有时当我们有新的编译器更新或缓存库出现问题时,强制重新构建是有帮助的。您可以通过设置环境变量 MLC_JIT_POLICY=REDO 来实现这一点。

MLC_JIT_POLICY=REDO mlc_llm package

步骤 3. (可选)将模型权重打包到应用程序中

默认情况下,在运行应用程序时会从 Hugging Face 下载模型权重。作为可选方案,可以将模型权重打包到应用程序中:在 MLCChat/mlc-package-config.json 中,为您希望打包权重的模型设置 "bundle_weight": true,然后再次运行 mlc_llm package。以下是示例:

{
   "device": "iphone",
   "model_list": [
      {
         "model": "HF://mlc-ai/gemma-2b-it-q4f16_1-MLC",
         "model_id": "gemma-2b-q4f16_1",
         "estimated_vram_bytes": 3000000000,
         "overrides": {
            "prefill_chunk_size": 128
         },
         "bundle_weight": true
      }
   ]
}

运行 mlc_llm package 的结果应如下所示:

dist
├── bundle
│   ├── gemma-2b-q4f16_1   # The model weights that will be bundled into the app.
│   └── mlc-app-config.json
└── ...

步骤 4. 构建 iOS 应用程序

使用 Xcode 打开 ./ios/MLCChat/MLCChat.xcodeproj。请注意,您需要 Apple 开发者账户才能使用 Xcode,系统可能会提示您使用自己的开发者团队凭证和产品包标识符。

确保 Xcode 项目中所有必要的依赖项和配置均已正确设置。

完成必要的更改后,使用 Xcode 构建 iOS 应用程序。如果您使用的是 Apple Silicon Mac,可以选择目标“我的 Mac(专为 iPad 设计)”以在 Mac 上运行。您也可以直接在 iPad 或 iPhone 上运行。

https://raw.githubusercontent.com/mlc-ai/web-data/main/images/mlc-llm/tutorials/xcode-build.jpg

自定义 App

可以通过自定义 MLCChat/mlc-package-config.json 来定制 iOS 应用程序中构建的模型。以下我们将介绍该 JSON 文件的每个字段。

JSON 文件的 "model_list" 中的每个条目包含以下字段:

model

(必填)要构建到应用程序中的 MLC 转换模型的路径。

它可以是 Hugging Face URL(例如 "model": "HF://mlc-ai/phi-2-q4f16_1-MLC"),也可以是包含转换后模型权重的本地模型目录路径(例如 "model": "../dist/gemma-2b-q4f16_1")。如果您希望将本地模型构建到应用程序中,请查看 转换模型权重

注意:本地路径(如果是相对路径)是相对于 ios/ 目录的。

model_id

(必需)用于标识模型的唯一本地标识符。它可以是任意值。

estimated_vram_bytes

(必需)运行模型所需的 vRAM 估计值。

bundle_weight

(可选)布尔标志,指示是否将模型权重打包到应用程序中。请参阅 步骤 3. (可选)将模型权重打包到应用程序中

overrides

(可选)字典,用于覆盖默认的模型上下文窗口大小(以限制 KV 缓存大小)和预填充块大小(以限制模型的临时执行内存)。例如:

{
   "device": "iphone",
   "model_list": [
      {
            "model": "HF://mlc-ai/RedPajama-INCITE-Chat-3B-v1-q4f16_1-MLC",
            "model_id": "RedPajama-INCITE-Chat-3B-v1-q4f16_1",
            "estimated_vram_bytes": 2960000000,
            "overrides": {
               "context_window_size": 512,
               "prefill_chunk_size": 128
            }
      }
   ]
}
model_lib

(可选)字符串,指定用于模型的系统库前缀。通常,当您希望将具有相同架构的多个模型变体构建到应用程序中时,会使用此字段。此字段不会影响任何应用程序功能。 下面介绍的 "model_lib_path_for_prepare_libs" 也与此相关。例如:

{
   "device": "iphone",
   "model_list": [
      {
            "model": "HF://mlc-ai/RedPajama-INCITE-Chat-3B-v1-q4f16_1-MLC",
            "model_id": "RedPajama-INCITE-Chat-3B-v1-q4f16_1",
            "estimated_vram_bytes": 2960000000,
            "model_lib": "gpt_neox_q4f16_1"
      }
   ]
}

除了 MLCChat/mlc-package-config.json 中的 model_list 外,您还可以 选择性地 指定 "model_lib_path_for_prepare_libs" 字典,如果您希望使用手动编译的模型库。此字典的键应为模型列表中指定的 model_lib,而字典的值是手动编译的模型库的路径(绝对路径或相对路径)。在运行 mlc_llm package 时,"model_lib_path_for_prepare_libs" 中指定的模型库将被构建到应用程序中。例如:

{
   "device": "iphone",
   "model_list": [
      {
            "model": "HF://mlc-ai/RedPajama-INCITE-Chat-3B-v1-q4f16_1-MLC",
            "model_id": "RedPajama-INCITE-Chat-3B-v1-q4f16_1",
            "estimated_vram_bytes": 2960000000,
            "model_lib": "gpt_neox_q4f16_1"
      }
   ],
   "model_lib_path_for_prepare_libs": {
      "gpt_neox_q4f16_1": "../../dist/lib/RedPajama-INCITE-Chat-3B-v1-q4f16_1-iphone.tar"
   }
}

引入您自己的模型

本节介绍如何将您自己的模型构建到 iOS 应用程序中。以 NeuralHermes 模型为例,它是 Mistral 模型的变体。

备注

本节大部分内容复制自 转换模型权重。请参阅该页面以获取更多详细信息。请注意,权重在 MLC 中跨所有平台共享。

第一步:从 HF 克隆并转换权重

您可以在 mlc-llm 仓库下,或您自己的工作目录中。请注意,所有平台可以共享相同的编译/量化权重。有关 convert_weight 的规范,请参阅 编译命令规范

# Create directory
mkdir -p dist/models && cd dist/models
# Clone HF weights
git lfs install
git clone https://huggingface.co/mlabonne/NeuralHermes-2.5-Mistral-7B
cd ../..
# Convert weight
mlc_llm convert_weight ./dist/models/NeuralHermes-2.5-Mistral-7B/ \
    --quantization q4f16_1 \
    -o dist/NeuralHermes-2.5-Mistral-7B-q3f16_1-MLC

步骤 2. 生成 MLC Chat 配置文件

使用 mlc_llm gen_config 生成 mlc-chat-config.json 并处理分词器。有关 gen_config 的规范,请参阅 编译命令规范

mlc_llm gen_config ./dist/models/NeuralHermes-2.5-Mistral-7B/ \
    --quantization q3f16_1 --conv-template neural_hermes_mistral \
    -o dist/NeuralHermes-2.5-Mistral-7B-q3f16_1-MLC

对于 conv-templateconversation_template.py 包含了 MLC 提供的完整对话模板列表。

如果您添加的模型需要新的对话模板,您需要自行添加。请参考 此 PR 作为示例。通过 mlc-chat-config.json 中的 conv_template 字段查找要使用的模板。

更多详情,请参阅 自定义 MLC Chat 配置

步骤 3. 将权重上传至 HF

# First, please create a repository on Hugging Face.
# With the repository created, run
git lfs install
git clone https://huggingface.co/my-huggingface-account/my-mistral-weight-huggingface-repo
cd my-mistral-weight-huggingface-repo
cp path/to/mlc-llm/dist/NeuralHermes-2.5-Mistral-7B-q3f16_1-MLC/* .
git add . && git commit -m "Add mistral model weights"
git push origin main

成功完成所有步骤后,您应该会得到类似于 NeuralHermes-2.5-Mistral-7B-q3f16_1-MLC 的 Huggingface 仓库,其中包含转换/量化后的权重、mlc-chat-config.json 配置文件以及分词器文件。

步骤 4. 在模型列表中注册

最后,将模型添加到 MLCChat/mlc-package-config.jsonmodel_list 中,通过指定 Hugging Face 链接作为 model

{
   "device": "iphone",
   "model_list": [
      {
            "model": "HF://mlc-ai/NeuralHermes-2.5-Mistral-7B-q3f16_1-MLC",
            "model_id": "Mistral-7B-Instruct-v0.2-q3f16_1",
            "estimated_vram_bytes": 3316000000,
      }
   ]
}

现在,再次按照 第二步:构建运行时和模型库步骤 4. 构建 iOS 应用程序 的步骤操作。应用程序将使用您刚刚添加的 NeuralHermes-Mistral 模型。

使用 MLC Swift API 构建应用程序

还提供了 Swift 包,您可以使用它来构建自己的应用程序。该包位于 ios/MLCSwift 目录下。

  • 首先,在您的项目文件夹中创建 mlc-package-config.json。您可以通过复制 MLCChat 文件夹中的文件来完成此操作。然后运行 mlc_llm package。这将在 /path/to/project/dist 下生成必要的库。

  • 在“构建阶段”下,添加 /path/to/project/dist/bundle,这将把此文件夹复制到您的应用程序中,以包含捆绑的权重和配置。

  • 在 Xcode 中,将 ios/MLCSwift 包添加到您的应用程序中。在“框架、库和嵌入内容”下,点击添加包依赖项,并添加指向 ios/MLCSwift 的本地包。

  • 最后,需要添加库依赖项。在构建设置下:

    • 添加库搜索路径 /path/to/project/dist/lib

    • 将以下项目添加到“其他链接器标志”中。

    -Wl,-all_load
    -lmodel_iphone
    -lmlc_llm -ltvm_runtime
    -ltokenizers_cpp
    -lsentencepiece
    -ltokenizers_c
    

然后,您可以将 MLCSwift 包导入到您的应用程序中。以下代码展示了如何使用聊天模块的示例。

import MLCSwift

func runExample() async {
   let engine = MLCEngine()
   let modelPath = "/path/to/model/weights"
   let modelLib = "model-lib-name"

   await engine.reload(modelPath: modelPath, modelLib: modelLib)

   // run chat completion as in OpenAI API style
   for await res in await engine.chat.completions.create(
         messages: [
            ChatCompletionMessage(
               role: .user,
               content: "What is the meaning of life?"
            )
         ]
   ) {
      print(res.choices[0].delta.content!.asText())
   }
}

查看 MLCEngineExample 以获取最小的入门示例。