跳到主要内容

Sentence Transformers 和 MLflow 高级语义相似度分析简介

下载此笔记本

在本综合教程中,深入了解如何使用 Sentence Transformers 和 MLflow 进行高级语义相似度分析。

学习目标

  • 配置 sentence-transformers 用于语义相似度分析。
  • 探索 MLflow 中自定义 PythonModel 的实现。
  • 使用 MLflow 记录模型并管理配置。
  • 使用 MLflow 的功能部署和应用模型进行推理。

揭示 Sentence Transformers 在 NLP 中的力量

Sentence Transformers 是 Transformer 模型的专门改编,擅长生成语义丰富的句子嵌入。这些模型非常适合语义搜索和相似度分析,为 NLP 任务带来更深层次的语义理解。

MLflow:开创灵活的模型管理和部署

MLflow 与 Sentence Transformers 的集成引入了增强的实验跟踪和灵活的模型管理,这对于 NLP 项目至关重要。了解如何在 MLflow 中实现自定义 PythonModel,扩展功能以满足独特的需求。

在本教程中,您将获得使用 MLflow 管理和部署复杂 NLP 模型的实践经验,从而提高您在语义相似度分析和模型生命周期管理方面的技能。

# Disable tokenizers warnings when constructing pipelines
%env TOKENIZERS_PARALLELISM=false

import warnings

# Disable a few less-than-useful UserWarnings from setuptools and pydantic
warnings.filterwarnings("ignore", category=UserWarning)
env: TOKENIZERS_PARALLELISM=false

使用 MLflow 实现自定义 SimilarityModel

了解如何使用 MLflow 的 PythonModel 创建自定义 SimilarityModel 类,以评估句子之间的语义相似度。

SimilarityModel 概述

SimilarityModel 是一个定制的 Python 类,它利用 MLflow 灵活的 PythonModel 接口。它专门设计用于封装使用复杂句子嵌入计算句子对之间语义相似度的复杂性。

自定义模型的关键组件

  • 导入库:导入来自 MLflow、数据处理和 Sentence Transformers 的基本库,以方便模型功能。
  • 自定义 PythonModel - SimilarityModel:
    • load_context 方法侧重于高效且安全的模型加载,这对于处理 Sentence Transformers 等复杂模型至关重要。
    • predict 方法配备了输入类型检查和错误处理,确保模型提供准确的余弦相似度分数,反映语义相关性。

自定义 SimilarityModel 的意义

  • 灵活性和定制性:模型的设计允许专门处理输入和输出,完美符合语义相似度任务的独特要求。
  • 鲁棒的错误处理:详细的输入类型检查保证了用户友好的体验,防止常见的输入错误并确保模型行为的可预测性。
  • 高效的模型加载:战略性地使用 load_context 方法进行模型初始化,避免了序列化挑战,确保了流畅的操作流程。
  • 有针对性的功能:自定义 predict 方法直接计算相似度分数,展示了模型提供任务特定、可操作见解的能力。

此自定义 SimilarityModel 示例展示了 MLflow 的 PythonModel 在构建定制 NLP 解决方案方面的适应性,为各种机器学习项目中的类似工作树立了先例。

import numpy as np
import pandas as pd
from sentence_transformers import SentenceTransformer, util

import mlflow
from mlflow.models.signature import infer_signature
from mlflow.pyfunc import PythonModel


class SimilarityModel(PythonModel):
def load_context(self, context):
"""Load the model context for inference."""
from sentence_transformers import SentenceTransformer

try:
self.model = SentenceTransformer.load(context.artifacts["model_path"])
except Exception as e:
raise ValueError(f"Error loading model: {e}")

def predict(self, context, model_input, params):
"""Predict method for comparing similarity between two sentences."""
from sentence_transformers import util

if isinstance(model_input, pd.DataFrame):
if model_input.shape[1] != 2:
raise ValueError("DataFrame input must have exactly two columns.")
sentence_1 = model_input.iloc[0, 0]
sentence_2 = model_input.iloc[0, 1]
elif isinstance(model_input, dict):
sentence_1 = model_input.get("sentence_1")
sentence_2 = model_input.get("sentence_2")
if sentence_1 is None or sentence_2 is None:
raise ValueError(
"Both 'sentence_1' and 'sentence_2' must be provided in the input dictionary."
)
else:
raise TypeError(
f"Unexpected type for model_input: {type(model_input)}. Must be either a Dict or a DataFrame."
)

embedding_1 = self.model.encode(sentence_1)
embedding_2 = self.model.encode(sentence_2)

return np.array(util.cos_sim(embedding_1, embedding_2).tolist())

准备 Sentence Transformer 模型和签名

探索使用 MLflow 设置 Sentence Transformer 模型进行日志记录和部署的基本步骤。

加载和保存预训练模型

  • 模型初始化:加载预训练的 Sentence Transformer 模型 "all-MiniLM-L6-v2",因为它在生成适用于各种 NLP 任务的高质量嵌入方面效率很高。
  • 模型保存:模型本地保存到 /tmp/sbert_model,以便 MLflow 轻松访问,这是平台中模型日志记录的先决条件。

准备输入示例和工件

  • 输入示例创建:准备一个包含样本句子的 DataFrame,代表典型的模型输入并帮助定义模型的输入格式。
  • 定义工件:保存的模型的文件路径在 MLflow 中指定为工件,这是将模型与 MLflow 运行关联起来的关键步骤。

生成签名测试输出

  • 测试输出计算:计算句子嵌入之间的余弦相似度,提供模型输出的实际示例。
  • 签名推理:利用 MLflow 的 infer_signature 函数生成一个封装预期输入和输出格式的签名,从而强化模型的操作模式。

这些步骤的重要性

  • 模型准备就绪:这些准备步骤确保模型已为在 MLflow 生态系统中的高效日志记录和无缝部署做好准备。
  • 输入-输出契约:已建立的签名充当明确的契约,定义了模型的输入-输出动态,这对于在部署场景中保持一致性和准确性至关重要。

我们已精心准备好 Sentence Transformer 模型及其签名,现在已做好充分准备,可以将其集成和管理到 MLflow 中。

# Load a pre-trained sentence transformer model
model = SentenceTransformer("all-MiniLM-L6-v2")

# Create an input example DataFrame
input_example = pd.DataFrame([{"sentence_1": "I like apples", "sentence_2": "I like oranges"}])

# Save the model in the /tmp directory
model_directory = "/tmp/sbert_model"
model.save(model_directory)

# Define artifacts with the absolute path
artifacts = {"model_path": model_directory}

# Generate test output for signature
test_output = np.array(
util.cos_sim(
model.encode(input_example["sentence_1"][0]), model.encode(input_example["sentence_2"][0])
).tolist()
)

# Define the signature associated with the model
signature = infer_signature(input_example, test_output)

# Visualize the signature
signature
inputs: 
['sentence_1': string, 'sentence_2': string]
outputs: 
[Tensor('float64', (-1, 1))]
params: 
None

创建实验

我们创建一个新的 MLflow 实验,以便我们要将模型记录到的运行不会记录到默认实验,而是具有其自己的上下文相关条目。

# If you are running this tutorial in local mode, leave the next line commented out.
# Otherwise, uncomment the following line and set your tracking uri to your local or remote tracking server.

# mlflow.set_tracking_uri("http://127.0.0.1:8080")

mlflow.set_experiment("Semantic Similarity")
<Experiment: artifact_location='file:///Users/benjamin.wilson/repos/mlflow-fork/mlflow/docs/source/llms/sentence-transformers/tutorials/semantic-similarity/mlruns/577235153137414660', creation_time=1701280997564, experiment_id='577235153137414660', last_update_time=1701280997564, lifecycle_stage='active', name='Semantic Similarity', tags={}>

使用 MLflow 记录自定义模型

了解如何使用 MLflow 记录自定义 SimilarityModel,以实现有效的模型管理和部署。

为 PyFunc 模型创建路径

我们建立 pyfunc_path,一个用于 Python 模型的临时存储位置。此路径对于 MLflow 有效地序列化和存储模型至关重要。

在 MLflow 中记录模型

  • 启动 MLflow 运行:启动 MLflow 运行,将所有模型日志记录过程封装在结构化框架内。
  • 模型日志记录详细信息:模型被标识为 "similarity",为将来的模型检索和分析提供了明确的参考。记录 SimilarityModel 的实例,封装 Sentence Transformer 模型和相似度预测逻辑。一个说明性的 DataFrame 演示了预期的模型输入格式,有助于用户理解和模型可用性。包含推断的签名(详细说明输入-输出模式),强化了模型的正确使用。工件字典指定了序列化 Sentence Transformer 模型的位置,这对于模型重建至关重要。列出了 sentence_transformersnumpy 等依赖项,确保模型在各种部署环境中的功能完整性。

模型日志记录的意义

  • 模型跟踪和版本控制:日志记录有助于全面的跟踪和有效的版本控制,从而增强模型生命周期管理。
  • 可重现性和部署:已记录的模型及其依赖项、输入示例和签名变得易于重现和部署,从而促进了跨环境的一致应用。

在 MLflow 中记录了我们的 SimilarityModel 后,它已准备好用于高级应用程序,例如比较分析、版本管理和部署以实现实际推理用例。

pyfunc_path = "/tmp/sbert_pyfunc"

with mlflow.start_run() as run:
model_info = mlflow.pyfunc.log_model(
name="similarity",
python_model=SimilarityModel(),
input_example=input_example,
signature=signature,
artifacts=artifacts,
pip_requirements=["sentence_transformers", "numpy"],
)
Downloading artifacts:   0%|          | 0/11 [00:00<?, ?it/s]
2023/11/30 16:10:34 INFO mlflow.store.artifact.artifact_repo: The progress bar can be disabled by setting the environment variable MLFLOW_ENABLE_ARTIFACTS_PROGRESS_BAR to false

模型推理和相似度预测测试

演示在 MLflow 中记录 SimilarityModel 后,如何使用它计算句子之间的语义相似度。

加载模型进行推理

  • 使用 MLflow 加载:使用模型的 URI 调用 mlflow.pyfunc.load_model 来加载自定义 SimilarityModel 以进行推理。
  • 模型准备就绪:加载的模型名为 loaded_dynamic,它具备 SimilarityModel 中定义的逻辑,并已准备好计算相似度。

准备相似度预测数据

  • 创建输入数据:构建一个 DataFrame,similarity_data,其中包含将计算相似度的句子对,展示模型的输入灵活性。

计算和显示相似度分数

  • 预测相似度:对 loaded_dynamic 调用 predict 方法,并传入 similarity_data,以计算句子嵌入之间的余弦相似度。
  • 解释结果:结果 similarity_score 以数值形式表示语义相似度,提供了对模型输出的即时洞察。

此测试的重要性

  • 模型验证:确认自定义模型在预测新数据时的预期行为,确保其有效性。
  • 实际应用:突出模型在实际场景中的实用性,展示其在语义相似度分析中的能力。
# Load our custom semantic similarity model implementation by providing the uri that the model was logged to
loaded_dynamic = mlflow.pyfunc.load_model(model_info.model_uri)

# Create an evaluation test DataFrame
similarity_data = pd.DataFrame([{"sentence_1": "I like apples", "sentence_2": "I like oranges"}])

# Verify that the model generates a reasonable prediction
similarity_score = loaded_dynamic.predict(similarity_data)

print(f"The similarity between these sentences is: {similarity_score}")
The similarity between these sentences is: [[0.63414472]]

评估不同文本对的语义相似度

探索模型通过精心选择的文本对来辨别不同程度语义相似度的能力。

文本对的选择

  • 低相似度对:句子中不同的主题预示着低相似度分数,展示了模型识别对比语义内容的能力。
  • 高相似度对:具有相似主题和语气的句子预计会产生高相似度分数,证明了模型的语义并行检测能力。

sBERT 模型在相似度计算中的作用

  • 语义理解:利用 sBERT 将语义本质编码成向量。
  • 余弦相似度:计算相似度分数以量化语义接近度。

计算和显示相似度分数

  • 预测低相似度对:观察模型对语义距离遥远的句子的解释。
  • 预测高相似度对:评估模型在上下文相关句子中检测语义相似度的能力。

为什么这很重要

  • 模型验证:这些测试证实了模型对语言的细微理解和语义关系的量化能力。
  • 实际影响:模型处理语义内容的洞察力为内容推荐、信息检索和文本比较中的应用提供了信息。
low_similarity = {
"sentence_1": "The explorer stood at the edge of the dense rainforest, "
"contemplating the journey ahead. The untamed wilderness was "
"a labyrinth of exotic plants and unknown dangers, a challenge "
"for even the most seasoned adventurer, brimming with the "
"prospect of new discoveries and uncharted territories.",
"sentence_2": "To install the software, begin by downloading the latest "
"version from the official website. Once downloaded, run the "
"installer and follow the on-screen instructions. Ensure that "
"your system meets the minimum requirements and agree to the "
"license terms to complete the installation process successfully.",
}

high_similarity = {
"sentence_1": "Standing in the shadow of the Great Pyramids of Giza, I felt a "
"profound sense of awe. The towering structures, a testament to "
"ancient ingenuity, rose majestically against the clear blue sky. "
"As I walked around the base of the pyramids, the intricate "
"stonework and sheer scale of these wonders of the ancient world "
"left me speechless, enveloped in a deep sense of history.",
"sentence_2": "My visit to the Great Pyramids of Giza was an unforgettable "
"experience. Gazing upon these monumental structures, I was "
"captivated by their grandeur and historical significance. Each "
"step around these ancient marvels filled me with a deep "
"appreciation for the architectural prowess of a civilization long "
"gone, yet still speaking through these timeless monuments.",
}

# Validate that semantically unrelated texts return a low similarity score
low_similarity_score = loaded_dynamic.predict(low_similarity)

print(f"The similarity score for the 'low_similarity' pair is: {low_similarity_score}")

# Validate that semantically similar texts return a high similarity score
high_similarity_score = loaded_dynamic.predict(high_similarity)

print(f"The similarity score for the 'high_similarity' pair is: {high_similarity_score}")
The similarity score for the 'low_similarity' pair is: [[-0.00052751]]
The similarity score for the 'high_similarity' pair is: [[0.83703309]]

结论:利用自定义 MLflow Python 函数在 NLP 中的强大功能

在结束本教程之际,让我们回顾一下我们在使用 Sentence Transformers 和 MLflow 理解和应用高级 NLP 技术方面取得的重大进展。

本教程的关键要点

  • 多功能 NLP 建模:我们探讨了如何利用 Sentence Transformers 的高级功能进行语义相似度分析,这是许多 NLP 应用程序中的一项关键任务。
  • 自定义 MLflow Python 函数:MLflow 中自定义 SimilarityModel 的实现展示了使用 Python 函数扩展和调整预训练模型功能以适应特定项目需求的力量和灵活性。
  • 模型管理和部署:我们深入研究了使用 MLflow 记录、管理和部署这些模型的过程,展示了 MLflow 如何简化机器学习生命周期的这些方面。
  • 实际语义分析:通过实践示例,我们展示了模型辨别句子对之间不同程度语义相似度的能力,验证了其在实际语义分析任务中的有效性。

MLflow Python 函数的强大功能和灵活性

  • 满足特定需求的定制化:本教程的亮点之一是演示了 MLflow 的 PythonModel 如何进行定制。这种定制不仅功能强大,而且对于根据特定 NLP 任务(超出标准模型功能)定制模型也是必要的。
  • 适应性和扩展性:MLflow 中的 PythonModel 框架为实现各种 NLP 模型提供了坚实的基础。它的适应性允许扩展基本模型功能,例如将句子嵌入模型转换为语义相似度比较工具。

赋能高级 NLP 应用

  • 易于修改:本教程展示了在 MLflow 中修改所提供的 PythonModel 实现以适应不同风格的相对容易性,使您能够创建与项目需求精确对齐的模型。
  • 广泛适用性:无论是语义搜索、内容推荐还是自动化文本比较,本教程中概述的方法都可以适应广泛的 NLP 任务,为该领域的创新应用打开大门。

展望未来

掌握了本教程中获得的知识和技能,您现在已具备将这些高级 NLP 技术应用于项目的能力。Sentence Transformers 与 MLflow 强大的模型管理和部署功能的无缝集成,为开发复杂、高效且有效的 NLP 解决方案铺平了道路。

感谢您与我们一起踏上使用 Sentence Transformers 和 MLflow 进行高级 NLP 建模的旅程。我们希望本教程能激发您在 NLP 领域进一步探索和创新!

建模愉快!