自动完成

在 TensorFlow.org 上查看 在 Google Colab 中运行

简介

大型语言模型 (LLM) 是一类机器学习模型,经过训练可以根据大型数据集生成文本。它们可用于自然语言处理 (NLP) 任务,包括文本生成、问答和机器翻译。它们基于 Transformer 架构,并使用大量文本数据进行训练,通常涉及数十亿个单词。即使是规模较小的 LLM,例如 GPT-2,也能表现出色。将 TensorFlow 模型转换为更轻、更快、低功耗的模型,使我们能够在设备上运行生成式 AI 模型,并带来更好的用户安全性,因为数据永远不会离开您的设备。

本运行手册向您展示如何使用 TensorFlow Lite 构建 Android 应用程序以运行 Keras LLM,并提供使用量化技术优化模型的建议,否则需要更大的内存量和更高的计算能力才能运行。

我们已经开源了我们的 Android 应用程序框架,任何兼容的 TFLite LLM 都可以插入其中。以下是两个演示

  • 在图 1 中,我们使用 Keras GPT-2 模型在设备上执行文本完成任务。
  • 在图 2 中,我们将一个经过指令微调的 PaLM 模型(15 亿个参数)版本转换为 TFLite,并通过 TFLite 运行时执行。

Autocomplete with PaLM
图 1:在设备上运行 Keras GPT-2 模型(从 Codelab 转换而来)以在 Pixel 7 上执行文本完成的示例。演示显示了没有加速的真实延迟。

Autocomplete with PaLM

图 2:运行具有 15 亿个参数的 PaLM 模型 版本的示例。演示是在 Pixel 7 Pro 上录制,没有回放加速。

指南

模型创作

在本演示中,我们将使用 KerasNLP 获取 GPT-2 模型。KerasNLP 是一个包含用于自然语言处理任务的最先进预训练模型的库,可以支持用户完成整个开发周期。您可以在 KerasNLP 代码库 中查看可用的模型列表。工作流程由模块化组件构建,这些组件在开箱即用时具有最先进的预设权重和架构,并且在需要更多控制时易于定制。创建 GPT-2 模型可以通过以下步骤完成

gpt2_tokenizer = keras_nlp.models.GPT2Tokenizer.from_preset("gpt2_base_en")

gpt2_preprocessor = keras_nlp.models.GPT2CausalLMPreprocessor.from_preset(
    "gpt2_base_en",
    sequence_length=256,
    add_end_token=True,
)

gpt2_lm =
keras_nlp.models.GPT2CausalLM.from_preset(
"gpt2_base_en",
preprocessor=gpt2_preprocessor
)

这三行代码的一个共同点是 from_preset() 方法,该方法将从预设架构和/或权重实例化 Keras API 的一部分,从而加载预训练模型。从这段代码片段中,您还会注意到三个模块化组件

  1. 分词器:将原始字符串输入转换为适合 Keras Embedding 层的整数标记 ID。GPT-2 特别使用字节对编码 (BPE) 分词器。

  2. 预处理器:用于分词和打包输入以馈送到 Keras 模型的层。在这里,预处理器将在分词后将标记 ID 张量填充到指定长度(256)。

  3. 主干:遵循 SoTA 变形器主干架构并具有预设权重的 Keras 模型。

此外,您可以在 GitHub 上查看完整的 GPT-2 模型实现。

模型转换

TensorFlow Lite 是一个移动库,用于在移动设备、微控制器和其他边缘设备上部署方法。第一步是使用 TensorFlow Lite 转换器将 Keras 模型转换为更紧凑的 TensorFlow Lite 格式,然后使用 TensorFlow Lite 解释器(针对移动设备进行了高度优化)来运行转换后的模型。

GPT2CausalLM 中的 generate() 函数开始,该函数执行转换。包装 generate() 函数以创建具体的 TensorFlow 函数

@tf.function
def generate(prompt, max_length):
    """
    Args:
        prompt: input prompt to the LLM in string format
        max_length: the max length of the generated tokens
    """
    return gpt2_lm.generate(prompt, max_length)

concrete_func = generate.get_concrete_function(tf.TensorSpec([], tf.string), 100)

请注意,您也可以使用 TFLiteConverter 中的 from_keras_model() 来执行转换。

现在定义一个辅助函数,该函数将使用输入和 TFLite 模型运行推理。TensorFlow 文本操作不是 TFLite 运行时中的内置操作,因此您需要添加这些自定义操作,以便解释器能够对该模型进行推理。此辅助函数接受一个输入和一个执行转换的函数,即上面定义的 generator() 函数。

def run_inference(input, generate_tflite):
    interp = interpreter.InterpreterWithCustomOps(
        model_content=generate_tflite,
        custom_op_registerers=
            tf_text.tflite_registrar.SELECT_TFTEXT_OPS
    )

    interp.get_signature_list()

    generator = interp.get_signature_runner('serving_default')
    output = generator(prompt=np.array([input]))

您现在可以转换模型

gpt2_lm.jit_compile = False
converter = tf.lite.TFLiteConverter.from_concrete_functions(
    [concrete_func],
    gpt2_lm)

converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS, # enable TFLite ops
    tf.lite.OpsSet.SELECT_TF_OPS, # enable TF ops
]
converter.allow_custom_ops = True
converter.target_spec.experimental_select_user_tf_ops = [
    "UnsortedSegmentJoin",
    "UpperBound"
]
converter._experimental_guarantee_all_funcs_one_use = True
generate_tflite = converter.convert()
run_inference("I'm enjoying a", generate_tflite)

量化

TensorFlow Lite 实现了名为**量化**的优化技术,可以减小模型大小并加速推理。通过量化过程,将 32 位浮点数映射到更小的 8 位整数,从而将模型大小减少 4 倍,以便在现代硬件上更高效地执行。TensorFlow 中有几种量化方法。您可以访问 TFLite 模型优化TensorFlow 模型优化工具包 页面以了解更多信息。下面简要介绍了量化类型。

在这里,您将使用 训练后动态范围量化 对 GPT-2 模型进行量化,方法是将转换器优化标志设置为 tf.lite.Optimize.DEFAULT,其余转换过程与之前详细介绍的相同。我们测试发现,使用这种量化技术,Pixel 7 上的延迟约为 6.7 秒,最大输出长度设置为 100。

gpt2_lm.jit_compile = False
converter = tf.lite.TFLiteConverter.from_concrete_functions(
    [concrete_func],
    gpt2_lm)

converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS, # enable TFLite ops
    tf.lite.OpsSet.SELECT_TF_OPS, # enable TF ops
]
converter.allow_custom_ops = True
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.experimental_select_user_tf_ops = [
    "UnsortedSegmentJoin",
    "UpperBound"
]
converter._experimental_guarantee_all_funcs_one_use = True
quant_generate_tflite = converter.convert()
run_inference("I'm enjoying a", quant_generate_tflite)

动态范围

动态范围量化是优化设备上模型的推荐起点。它可以将模型大小减少约 4 倍,并且是推荐的起点,因为它可以减少内存使用量并加快计算速度,而无需您提供用于校准的代表性数据集。这种类型的量化在转换时仅将权重从浮点数静态量化为 8 位整数。

FP16

浮点模型也可以通过将权重量化为 float16 类型来优化。float16 量化 的优点是将模型大小减少一半(因为所有权重都变为原来的一半),精度损失最小,并且支持可以直接对 float16 数据进行操作的 GPU 代理(这比 float32 数据的计算速度更快)。转换为 float16 权重的模型仍然可以在 CPU 上运行,无需额外修改。float16 权重在第一次推理之前被上采样到 float32,这允许减少模型大小,以换取对延迟和精度的最小影响。

全整数量化

全整数量化 将 32 位浮点数(包括权重和激活)都转换为最接近的 8 位整数。这种类型的量化会产生更小的模型,并提高推理速度,这在使用微控制器时非常有价值。当激活对量化敏感时,建议使用此模式。

Android 应用集成

您可以按照此 Android 示例 将您的 TFLite 模型集成到 Android 应用中。

先决条件

如果您还没有安装 Android Studio,请按照网站上的说明进行安装。

  • Android Studio 2022.2.1 或更高版本。
  • 内存大于 4G 的 Android 设备或 Android 模拟器

使用 Android Studio 构建和运行

  • 打开 Android Studio,从欢迎屏幕中选择**打开现有 Android Studio 项目**。
  • 从出现的打开文件或项目窗口中,导航到并选择 lite/examples/generative_ai/android 目录(您从 TensorFlow Lite 示例 GitHub 存储库中克隆的位置)。
  • 您可能还需要根据错误消息安装各种平台和工具。
  • 将转换后的 .tflite 模型重命名为 autocomplete.tflite 并将其复制到 app/src/main/assets/ 文件夹中。
  • 选择菜单**构建 -> 生成项目**以构建应用。(Ctrl+F9,具体取决于您的版本)。
  • 单击菜单**运行 -> 运行“app”**。(Shift+F10,具体取决于您的版本)

或者,您也可以使用 gradle 包装器 在命令行中构建它。有关更多信息,请参阅 Gradle 文档

(可选)构建 .aar 文件

默认情况下,应用会自动下载所需的 .aar 文件。但是,如果您想自己构建,请切换到 app/libs/build_aar/ 文件夹并运行 ./build_aar.sh。此脚本将从 TensorFlow Text 中提取必要的运算符并构建 Select TF 运算符的 aar。

编译后,将生成一个新的文件 tftext_tflite_flex.aar。替换 app/libs/ 文件夹中的 .aar 文件并重新构建应用。

请注意,您仍然需要在 gradle 文件中包含标准的 tensorflow-lite aar。

上下文窗口大小

该应用有一个可更改的参数“上下文窗口大小”,这是必需的,因为当今的 LLM 通常具有固定的上下文大小,这限制了可以作为“提示”输入模型的单词/标记数量(请注意,在这种情况下,“单词”不一定等同于“标记”,因为不同的标记化方法)。这个数字很重要,因为

  • 如果设置得太小,模型将没有足够的上下文来生成有意义的输出
  • 如果设置得太大,模型将没有足够的空间来处理(因为输出序列包含提示)

您可以尝试一下,但将其设置为输出序列长度的约 50% 是一个不错的起点。

安全和负责任的 AI

如原始 OpenAI GPT-2 公告 中所述,GPT-2 模型存在 一些值得注意的注意事项和局限性。事实上,当今的 LLM 通常存在一些众所周知的挑战,例如幻觉、公平性和偏差;这是因为这些模型是在真实世界数据上训练的,这使得它们反映了真实世界的问题。

此代码实验室仅用于演示如何使用 TensorFlow 工具创建由 LLM 支持的应用。在此代码实验室中生成的模型仅供教育目的,不适合生产使用。

LLM 生产使用需要仔细选择训练数据集和全面的安全缓解措施。此 Android 应用中提供的一个此类功能是脏话过滤器,它会拒绝不良的用户输入或模型输出。如果检测到任何不适当的语言,应用将拒绝该操作。要了解有关 LLM 上下文中的负责任 AI 的更多信息,请务必观看 Google I/O 2023 上的“使用生成式语言模型进行安全和负责任的开发”技术会议,并查看 负责任的 AI 工具包