使用 ONNX 格式的 Transformer 模型生成嵌入

本教程介绍了如何将 Transformer 模型导出为开放神经网络交换 (ONNX) 格式,将 ONNX 模型导入 BigQuery 数据集,然后使用该模型通过 SQL 查询生成嵌入。

本教程使用 sentence-transformers/all-MiniLM-L6-v2 模型。此句子转换器模型以其在生成句子嵌入方面的快速高效而闻名。句子嵌入通过捕获文本的潜在含义,实现语义搜索、聚类和句子相似性等任务。

ONNX 提供了一种用于表示任何机器学习 (ML) 框架的统一格式。BigQuery ML 对 ONNX 的支持让您可以执行以下操作:

  • 使用您偏好的框架训练模型。
  • 将模型转换为 ONNX 模型格式。
  • 将 ONNX 模型导入 BigQuery 并使用 BigQuery ML 进行预测。

将 Transformer 模型文件转换为 ONNX

您可以选择按照本部分中的步骤将 sentence-transformers/all-MiniLM-L6-v2 模型和分词器手动转换为 ONNX。 否则,您可以使用公共 gs://cloud-samples-data Cloud Storage 存储桶中已转换的示例文件。

如果您选择手动转换文件,则必须拥有已安装 Python 的本地命令行环境。如需详细了解如何安装 Python,请参阅 Python 下载

将 Transformer 模型导出为 ONNX

使用 Hugging Face Optimum CLI 将 sentence-transformers/all-MiniLM-L6-v2 模型导出到 ONNX。 如需详细了解如何使用 Optimum CLI 导出模型,请参阅使用 optimum.exporters.onnx 将模型导出为 ONNX

如需导出模型,请打开命令行环境并按以下步骤操作:

  1. 安装 Optimum CLI:

    pip install optimum[onnx]
    
  2. 导出模型。--model 实参用于指定 Hugging Face 模型 ID。 --opset 实参用于指定 ONNXRuntime 库版本,并设置为 17 以保持与 BigQuery 支持的 ONNXRuntime 库的兼容性。

    optimum-cli export onnx \
      --model sentence-transformers/all-MiniLM-L6-v2 \
      --task sentence-similarity \
      --opset 17 all-MiniLM-L6-v2/
    

模型文件会导出到 all-MiniLM-L6-v2 目录,并命名为 model.onnx

对 Transformer 模型应用量化

使用 Optimum CLI 对导出的 Transformer 模型应用量化,以减小模型大小并加快推理速度。如需了解详情,请参阅量化

如需对模型应用量化,请在命令行中运行以下命令:

optimum-cli onnxruntime quantize \
  --onnx_model all-MiniLM-L6-v2/ \
  --avx512_vnni -o all-MiniLM-L6-v2_quantized

量化模型文件将导出到 all-MiniLM-L6-v2_quantized 目录,并命名为 model_quantized.onnx

将分词器转换为 ONNX

如需使用 ONNX 格式的 Transformer 模型生成嵌入,您通常会使用分词器生成模型的两个输入,即 input_idsattention_mask

如需生成这些输入,请使用 onnxruntime-extensions 库将 sentence-transformers/all-MiniLM-L6-v2 模型的分词器转换为 ONNX 格式。转换分词器后,您可以直接对原始文本输入执行分词,以生成 ONNX 预测。

如需转换分词器,请在命令行中按以下步骤操作:

  1. 安装 Optimum CLI:

    pip install optimum[onnx]
    
  2. 使用您选择的文本编辑器,创建一个名为 convert-tokenizer.py 的文件。以下示例使用 nano 文本编辑器:

    nano convert-tokenizer.py
    
  3. 将以下 Python 脚本复制并粘贴到 convert-tokenizer.py 文件中:

    from onnxruntime_extensions import gen_processing_models
    
    # Load the Huggingface tokenizer
    tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
    
    # Export the tokenizer to ONNX using gen_processing_models
    onnx_tokenizer_path = "tokenizer.onnx"
    
    # Generate the tokenizer ONNX model, and set the maximum token length.
    # Ensure 'max_length' is set to a value less than the model's maximum sequence length, failing to do so will result in error during inference.
    tokenizer_onnx_model = gen_processing_models(tokenizer, pre_kwargs={'max_length': 256})[0]
    
    # Modify the tokenizer ONNX model signature.
    # This is because certain tokenizers don't support batch inference.
    tokenizer_onnx_model.graph.input[0].type.tensor_type.shape.dim[0].dim_value = 1
    
    # Save the tokenizer ONNX model
    with open(onnx_tokenizer_path, "wb") as f:
      f.write(tokenizer_onnx_model.SerializeToString())
    
  4. 保存 convert-tokenizer.py 文件。

  5. 运行 Python 脚本以转换分词器:

    python convert-tokenizer.py
    

转换后的分词器将导出到 all-MiniLM-L6-v2_quantized 目录,并命名为 tokenizer.onnx

将转换后的模型文件上传到 Cloud Storage

转换 Transformer 模型和分词器后,请执行以下操作:

创建数据集

创建 BigQuery 数据集以存储机器学习模型。

控制台

  1. 在 Google Cloud 控制台中,前往 BigQuery 页面。

    转到 BigQuery 页面

  2. 探索器窗格中,点击您的项目名称。

  3. 点击 查看操作 > 创建数据集

  4. 创建数据集 页面上,执行以下操作:

    • 数据集 ID 部分,输入 bqml_tutorial

    • 位置类型部分,选择多区域,然后选择 US (multiple regions in United States)(美国[美国的多个区域])。

    • 保持其余默认设置不变,然后点击创建数据集

bq

如需创建新数据集,请使用带有 --location 标志的 bq mk 命令。 如需查看完整的潜在参数列表,请参阅 bq mk --dataset 命令参考文档。

  1. 创建一个名为 bqml_tutorial 的数据集,并将数据位置设置为 US,说明为 BigQuery ML tutorial dataset

    bq --location=US mk -d \
     --description "BigQuery ML tutorial dataset." \
     bqml_tutorial

    该命令使用的不是 --dataset 标志,而是 -d 快捷方式。如果省略 -d--dataset,该命令会默认创建一个数据集。

  2. 确认已创建数据集:

    bq ls

API

使用已定义的数据集资源调用 datasets.insert 方法。

{
  "datasetReference": {
     "datasetId": "bqml_tutorial"
  }
}

BigQuery DataFrame

在尝试此示例之前,请按照《BigQuery 快速入门:使用 BigQuery DataFrames》中的 BigQuery DataFrames 设置说明进行操作。如需了解详情,请参阅 BigQuery DataFrames 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭证。如需了解详情,请参阅为本地开发环境设置 ADC

import google.cloud.bigquery

bqclient = google.cloud.bigquery.Client()
bqclient.create_dataset("bqml_tutorial", exists_ok=True)

将 ONNX 模型导入 BigQuery

将转换后的分词器和句子转换器模型作为 BigQuery ML 模型导入。

从下列选项中选择一项:

控制台

  1. 在 Google Cloud 控制台中,打开 BigQuery Studio。

    进入 BigQuery Studio

  2. 在查询编辑器中,运行以下 CREATE MODEL 语句以创建 tokenizer 模型。

     CREATE OR REPLACE MODEL `bqml_tutorial.tokenizer`
      OPTIONS (MODEL_TYPE='ONNX',
       MODEL_PATH='TOKENIZER_BUCKET_PATH')

    TOKENIZER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TOKENIZER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/tokenizer.onnx

    操作完成后,您会在查询结果窗格中看到类似于以下内容的消息:Successfully created model named tokenizer

  3. 点击前往模型以打开详细信息窗格。

  4. 查看特征列部分可了解模型输入,查看标签列可了解模型输出。

    分词器模型的 **详细信息** 窗格

  5. 在查询编辑器中,运行以下 CREATE MODEL 语句以创建 all-MiniLM-L6-v2 模型。

     CREATE OR REPLACE MODEL `bqml_tutorial.all-MiniLM-L6-v2`
      OPTIONS (MODEL_TYPE='ONNX',
       MODEL_PATH='TRANSFORMER_BUCKET_PATH')

    TRANSFORMER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TRANSFORMER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/model_quantized.onnx

    操作完成后,您会在查询结果窗格中看到类似于以下内容的消息:Successfully created model named all-MiniLM-L6-v2

  6. 点击前往模型以打开详细信息窗格。

  7. 查看特征列部分可了解模型输入,查看标签列可了解模型输出。

    `all-MiniLM-L6-v2` 模型的 **详细信息** 窗格

bq

使用 bq 命令行工具 query 命令运行 CREATE MODEL 语句。

  1. 在命令行中,运行以下命令以创建 tokenizer 模型。

    bq query --use_legacy_sql=false \
    "CREATE OR REPLACE MODEL
    `bqml_tutorial.tokenizer`
    OPTIONS
    (MODEL_TYPE='ONNX',
    MODEL_PATH='TOKENIZER_BUCKET_PATH')"

    TOKENIZER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TOKENIZER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/tokenizer.onnx

    操作完成后,您会看到类似于以下内容的消息:Successfully created model named tokenizer

  2. 在命令行中,运行以下命令以创建 all-MiniLM-L6-v2 模型。

    bq query --use_legacy_sql=false \
    "CREATE OR REPLACE MODEL
    `bqml_tutorial.all-MiniLM-L6-v2`
    OPTIONS
    (MODEL_TYPE='ONNX',
      MODEL_PATH='TRANSFORMER_BUCKET_PATH')"

    TRANSFORMER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TRANSFORMER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/model_quantized.onnx

    操作完成后,您会看到类似于以下内容的消息:Successfully created model named all-MiniLM-L6-v2

  3. 导入模型后,请验证这些模型是否显示在数据集中。

    bq ls -m bqml_tutorial

    输出类似于以下内容:

    tableId            Type
    ------------------------
    tokenizer          MODEL
    all-MiniLM-L6-v2   MODEL

API

使用 jobs.insert 方法导入模型。在请求正文中,使用 CREATE MODEL 语句填充 QueryRequest 资源query 参数。

  1. 使用以下 query 参数值创建 tokenizer 模型。

    {
    "query": "CREATE MODEL `PROJECT_ID :bqml_tutorial.tokenizer` OPTIONS(MODEL_TYPE='ONNX' MODEL_PATH='TOKENIZER_BUCKET_PATH')"
    }

    替换以下内容:

    • PROJECT_ID 替换为您的项目 ID。
    • TOKENIZER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TOKENIZER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/tokenizer.onnx
  2. 使用以下 query 参数值创建 all-MiniLM-L6-v2 模型。

    {
    "query": "CREATE MODEL `PROJECT_ID :bqml_tutorial.all-MiniLM-L6-v2` OPTIONS(MODEL_TYPE='ONNX' MODEL_PATH='TRANSFORMER_BUCKET_PATH')"
    }

    替换以下内容:

    • PROJECT_ID 替换为您的项目 ID。
    • TRANSFORMER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TRANSFORMER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/model_quantized.onnx

BigQuery DataFrame

在尝试此示例之前,请按照《BigQuery 快速入门:使用 BigQuery DataFrames》中的 BigQuery DataFrames 设置说明进行操作。如需了解详情,请参阅 BigQuery DataFrames 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭证。如需了解详情,请参阅为本地开发环境设置 ADC

使用 ONNXModel 对象导入分词器和句子转换器模型。

import bigframes
from bigframes.ml.imported import ONNXModel

bigframes.options.bigquery.project = PROJECT_ID

bigframes.options.bigquery.location = "US"

tokenizer = ONNXModel(
  model_path= "TOKENIZER_BUCKET_PATH"
)
imported_onnx_model = ONNXModel(
  model_path="TRANSFORMER_BUCKET_PATH"
)

替换以下内容:

  • PROJECT_ID 替换为您的项目 ID。
  • TOKENIZER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TOKENIZER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/tokenizer.onnx
  • TRANSFORMER_BUCKET_PATH 替换为您上传到 Cloud Storage 的模型的路径。如果您使用的是示例模型,请将 TRANSFORMER_BUCKET_PATH 替换为以下值:gs://cloud-samples-data/bigquery/ml/onnx/all-MiniLM-L6-v2/model_quantized.onnx

使用导入的 ONNX 模型生成嵌入

使用导入的分词器和句子转换器模型,根据 bigquery-public-data.imdb.reviews 公共数据集中的数据生成嵌入。

从下列选项中选择一项:

控制台

使用 ML.PREDICT 函数通过模型生成嵌入。

该查询使用嵌套的 ML.PREDICT 调用,通过分词器和嵌入模型直接处理原始文本,如下所示:

  • 分词(内部查询):内部 ML.PREDICT 调用使用 bqml_tutorial.tokenizer 模型。它将 bigquery-public-data.imdb.reviews 公共数据集中的 title 列作为其 text 输入。 tokenizer 模型将原始文本字符串转换为主模型所需的数字令牌输入,包括 input_idsattention_mask 输入。
  • 嵌入生成(外部查询):外部 ML.PREDICT 调用使用 bqml_tutorial.all-MiniLM-L6-v2 模型。该查询将内部查询输出中的 input_idsattention_mask 列作为输入。

SELECT 语句会检索 sentence_embedding 列,该列是一个 FLOAT 值数组,表示文本的语义嵌入。

  1. 在 Google Cloud 控制台中,打开 BigQuery Studio。

    进入 BigQuery Studio

  2. 在查询编辑器中,运行以下查询。

    SELECT
    sentence_embedding
    FROM
    ML.PREDICT (MODEL `bqml_tutorial.all-MiniLM-L6-v2`,
      (
      SELECT
        input_ids, attention_mask
      FROM
        ML.PREDICT(MODEL `bqml_tutorial.tokenizer`,
          (
          SELECT
            title AS text
          FROM
            `bigquery-public-data.imdb.reviews` limit 10))))

    结果类似于以下内容:

    +-----------------------+
    | sentence_embedding    |
    +-----------------------+
    | -0.02361682802438736  |
    | 0.02025664784014225   |
    | 0.005168713629245758  |
    | -0.026361213997006416 |
    | 0.0655381828546524    |
    | ...                   |
    +-----------------------+
    

bq

使用 bq 命令行工具的 query 命令运行查询。该查询使用 ML.PREDICT 函数通过模型生成嵌入。

该查询使用嵌套的 ML.PREDICT 调用,通过分词器和嵌入模型直接处理原始文本,如下所示:

  • 分词(内部查询):内部 ML.PREDICT 调用使用 bqml_tutorial.tokenizer 模型。它将 bigquery-public-data.imdb.reviews 公共数据集中的 title 列作为其 text 输入。 tokenizer 模型将原始文本字符串转换为主模型所需的数字令牌输入,包括 input_idsattention_mask 输入。
  • 嵌入生成(外部查询):外部 ML.PREDICT 调用使用 bqml_tutorial.all-MiniLM-L6-v2 模型。该查询将内部查询输出中的 input_idsattention_mask 列作为输入。

SELECT 语句会检索 sentence_embedding 列,该列是一个 FLOAT 值数组,表示文本的语义嵌入。

在命令行中,运行以下命令以运行查询。

bq query --use_legacy_sql=false \
'SELECT
sentence_embedding
FROM
ML.PREDICT (MODEL `bqml_tutorial.all-MiniLM-L6-v2`,
  (
  SELECT
    input_ids, attention_mask
  FROM
    ML.PREDICT(MODEL `bqml_tutorial.tokenizer`,
      (
      SELECT
        title AS text
      FROM
        `bigquery-public-data.imdb.reviews` limit 10))))'

结果类似于以下内容:

+-----------------------+
| sentence_embedding    |
+-----------------------+
| -0.02361682802438736  |
| 0.02025664784014225   |
| 0.005168713629245758  |
| -0.026361213997006416 |
| 0.0655381828546524    |
| ...                   |
+-----------------------+

BigQuery DataFrame

在尝试此示例之前,请按照《BigQuery 快速入门:使用 BigQuery DataFrames》中的 BigQuery DataFrames 设置说明进行操作。如需了解详情,请参阅 BigQuery DataFrames 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭证。如需了解详情,请参阅为本地开发环境设置 ADC

使用 predict 方法通过 ONNX 模型生成嵌入。

import bigframes.pandas as bpd

df = bpd.read_gbq("bigquery-public-data.imdb.reviews", max_results=10)
df_pred = df.rename(columns={"title": "text"})
tokens = tokenizer.predict(df_pred)
predictions = imported_onnx_model.predict(tokens)
predictions.peek(5)

输出类似于以下内容:

Transformer 模型的输出。