跳到主要内容

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 模型和签名

探索设置 Sentence Transformer 模型以供 MLflow 记录和部署的基本步骤。

加载和保存预训练模型

  • 模型初始化:加载预训练的 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 展示了预期的模型输入格式,有助于用户理解和模型可用性。包含推断出的签名,详细说明了输入-输出模式,强化了模型的正确使用。artifacts 字典指定了序列化 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 应用

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

展望未来

有了本教程获得的知识和技能,您现在可以自信地将这些进阶 NLP 技术应用到您的项目中。Sentence Transformers 与 MLflow 强大的模型管理和部署功能的无缝集成,为开发复杂、高效且有效的 NLP 解决方案铺平了道路。

感谢您与我们一起踏上这次通过 Sentence Transformers 和 MLflow 进行进阶 NLP 建模的旅程。我们希望本教程能激发您在 NLP 领域进行更深入的探索和创新!

建模愉快!