跳到主要内容

使用 Sentence Transformers 和 MLflow 进行高级语义相似度分析介绍

下载此 Notebook

在本全面的教程中,深入了解如何使用 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, sentence_2 = model_input.iloc[0, 0], 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 轻松访问,这是在该平台中记录模型的先决条件。

准备输入示例和 Artifact

  • 输入示例创建:准备一个包含示例句子的 DataFrame,代表典型的模型输入,并有助于定义模型的输入格式。
  • 定义 Artifact:将保存的模型文件路径指定为 MLflow 中的一个 artifact,这是将模型与 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 Experiment,这样我们要记录模型的运行就不会记录到默认实验中,而是拥有自己的上下文相关的条目。

# 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 展示了预期的模型输入格式,有助于用户理解和模型可用性。包含推断出的签名,详细说明输入-输出模式,加强了模型的正确使用。Artifacts 字典指定了序列化的 Sentence Transformer 模型的位置,这对于模型重构至关重要。列出了 sentence_transformersnumpy 等依赖项,确保模型在不同部署环境中的功能完整性。

模型日志记录的重要性

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

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

pyfunc_path = "/tmp/sbert_pyfunc"

with mlflow.start_run() as run:
model_info = mlflow.pyfunc.log_model(
"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 应用

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

展望未来

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

感谢您加入我们,共同探索使用 Sentence Transformers 和 MLflow 进行高级 NLP 建模的旅程。我们希望本教程能启发您进一步探索并在您的 NLP 实践中进行创新!

建模愉快!