目录
- MLOps 概述与成熟度模型
- 实验追踪:MLflow 与 Weights and Biases
- 数据版本管理:DVC
- 特征存储
- 模型注册表
- ML 的 CI/CD
- 模型监控与漂移检测
- LLMOps
- 测验
MLOps 概述与成熟度模型
MLOps(Machine Learning Operations)是一套用于在生产环境中稳定运行 ML 系统的方法论、工具与文化的集合。它把 DevOps 的原则应用到 ML 工作流上,将模型从开发到部署、监控、再训练的整个生命周期自动化。
为什么需要 MLOps
有统计显示,95% 以上的 ML 项目都未能成功走到生产部署这一步。其原因大致如下:
- 不可复现的实验:代码、数据、环境都没有做版本管理
- 手动部署流程:速度慢,且容易出错
- 缺乏监控:模型性能下降被发现得太晚
- 团队孤岛:数据科学团队与工程团队之间存在脱节
MLOps 成熟度级别
Google 的 MLOps 成熟度模型将其划分为三个阶段。
Level 0:手动流程
所有流程都是手动的。数据科学家在 Jupyter Notebook 中做实验,再手动把结果部署出去。
| 特征 | 说明 |
|---|---|
| 部署周期 | 数月一次 |
| 自动化程度 | 无 |
| 可复现性 | 低 |
| 监控 | 没有或靠手动 |
局限性:缺乏实验追踪、代码与数据版本不一致、部署出错、无法及时发现模型性能下降
Level 1:ML 流水线自动化
引入了 CT(Continuous Training,持续训练)。数据流水线与模型训练已经自动化,但 CI/CD 仍是手动的。
核心组成部分:
- 自动化的数据校验流水线
- 特征工程流水线
- 模型训练流水线(Kubeflow Pipelines、Apache Airflow 等)
- 自动化的模型性能评估
- 引入特征存储
# Kubeflow Pipeline 示例 - Level 1 CT 流水线
import kfp
from kfp import dsl
@dsl.component
def data_validation_op(data_path: str) -> bool:
import great_expectations as ge
ds = ge.read_csv(data_path)
results = ds.expect_column_values_to_not_be_null("target")
return results["success"]
@dsl.component
def train_model_op(data_path: str, model_output: str):
import mlflow
import sklearn
# 模型训练逻辑
pass
@dsl.pipeline(name="CT Pipeline")
def ct_pipeline(data_path: str):
validation = data_validation_op(data_path=data_path)
with dsl.Condition(validation.output == True):
train_model_op(data_path=data_path, model_output="/models/")
Level 2:CI/CD 流水线自动化
这是完全自动化的 MLOps 阶段。代码、数据、模型全部纳入版本管理,CI/CD/CT 完全自动化。
自动化触发条件:
- 有新的训练数据到达(按计划或达到数据量阈值)
- 检测到模型性能指标下降
- 检测到数据漂移
- 代码发生变更(新特征、算法改进)
Level 2 架构:
源代码变更或数据触发
↓
CI 流水线(测试、构建)
↓
CD 流水线(部署流水线)
↓
CT 流水线(自动重训练)
↓
模型评估 → 通过/不通过
↓
注册进模型注册表
↓
Staging → Production 晋升
↓
监控与告警
实验追踪:MLflow 与 Weights and Biases
MLflow 完全指南
MLflow 是一个用于管理 ML 生命周期的开源平台,由 4 个核心组件构成。
MLflow Tracking
追踪实验的参数、指标与产出物(artifact)。
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score
import numpy as np
# 配置 MLflow Tracking 服务器
mlflow.set_tracking_uri("http://mlflow-server:5000")
mlflow.set_experiment("fraud-detection-v2")
with mlflow.start_run(run_name="rf-baseline") as run:
# 记录超参数
params = {
"n_estimators": 100,
"max_depth": 10,
"min_samples_split": 5,
"random_state": 42
}
mlflow.log_params(params)
# 训练模型
model = RandomForestClassifier(**params)
model.fit(X_train, y_train)
# 记录指标
y_pred = model.predict(X_test)
metrics = {
"accuracy": accuracy_score(y_test, y_pred),
"f1_score": f1_score(y_test, y_pred, average="weighted"),
}
mlflow.log_metrics(metrics)
# 模型自动记录(使用 sklearn autolog 时)
# mlflow.sklearn.autolog()
# 保存模型
mlflow.sklearn.log_model(
sk_model=model,
artifact_path="model",
registered_model_name="fraud-detection",
input_example=X_test[:5],
signature=mlflow.models.infer_signature(X_train, y_pred)
)
# 自定义产出物
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm)
disp.plot()
plt.savefig("confusion_matrix.png")
mlflow.log_artifact("confusion_matrix.png")
print(f"Run ID: {run.info.run_id}")
print(f"Accuracy: {metrics['accuracy']:.4f}")
MLflow Autolog
按框架自动记录,把样板代码降到最少:
import mlflow
# 自动检测框架并记录
mlflow.autolog()
# PyTorch 专用 autolog
mlflow.pytorch.autolog(
log_every_n_epoch=1,
log_models=True,
disable=False,
exclusive=False,
log_datasets=True
)
# XGBoost 专用 autolog
mlflow.xgboost.autolog(
log_input_examples=True,
log_model_signatures=True,
log_models=True,
log_datasets=True
)
MLflow Projects
打包可复现的 ML 项目:
# MLproject 文件
name: fraud-detection
conda_env: conda.yaml
entry_points:
main:
parameters:
n_estimators: { type: int, default: 100 }
max_depth: { type: int, default: 10 }
data_path: { type: str, default: 'data/train.csv' }
command: 'python train.py --n_estimators {n_estimators} --max_depth {max_depth} --data_path {data_path}'
evaluate:
parameters:
model_uri: { type: str }
test_data: { type: str }
command: 'python evaluate.py --model_uri {model_uri} --test_data {test_data}'
Weights & Biases (W&B)
W&B 是一个提供实验追踪、可视化与超参数优化的 MLOps 平台。
import wandb
from wandb.integration.keras import WandbCallback
# 初始化 W&B
run = wandb.init(
project="image-classification",
config={
"learning_rate": 0.001,
"epochs": 50,
"batch_size": 32,
"architecture": "ResNet50"
}
)
# 用 W&B Sweep 做超参数优化
sweep_config = {
"method": "bayes",
"metric": {"name": "val_accuracy", "goal": "maximize"},
"parameters": {
"learning_rate": {"min": 1e-5, "max": 1e-2},
"batch_size": {"values": [16, 32, 64]},
"dropout": {"min": 0.1, "max": 0.5}
}
}
sweep_id = wandb.sweep(sweep_config, project="image-classification")
wandb.agent(sweep_id, function=train_fn, count=50)
数据版本管理:DVC
DVC(Data Version Control)是一款与 Git 配合、为大型数据集与 ML 流水线做版本管理的工具。
DVC 工作原理
DVC 不会把大文件直接存进 Git,而是只把 .dvc 元数据文件(指针)提交到 Git。实际的数据则存放在 S3、GCS、Azure Blob、SSH 等远程存储中。
# 初始化 DVC
git init
dvc init
# 配置远程存储(S3)
dvc remote add -d myremote s3://my-bucket/dvc-store
dvc remote modify myremote region us-east-1
# 添加数据
dvc add data/train.csv
git add data/train.csv.dvc .gitignore
git commit -m "Add training data v1"
dvc push
# 在其他环境中拉取数据
git pull
dvc pull
DVC Pipeline(dvc.yaml)
以声明式的方式定义可复现的 ML 流水线:
# dvc.yaml
stages:
prepare:
cmd: python src/prepare.py --input data/raw.csv --output data/processed/
deps:
- src/prepare.py
- data/raw.csv
outs:
- data/processed/train.csv
- data/processed/test.csv
params:
- prepare:
- split_ratio
- random_seed
featurize:
cmd: python src/featurize.py
deps:
- src/featurize.py
- data/processed/train.csv
outs:
- data/features/train_features.pkl
params:
- featurize:
- max_features
- ngrams
train:
cmd: python src/train.py
deps:
- src/train.py
- data/features/train_features.pkl
outs:
- models/model.pkl
metrics:
- reports/metrics.json:
cache: false
params:
- train:
- n_estimators
- max_depth
- random_seed
evaluate:
cmd: python src/evaluate.py
deps:
- src/evaluate.py
- models/model.pkl
- data/processed/test.csv
metrics:
- reports/eval_metrics.json:
cache: false
plots:
- reports/plots/confusion_matrix.csv:
cache: false
# params.yaml
prepare:
split_ratio: 0.8
random_seed: 42
featurize:
max_features: 1000
ngrams: 2
train:
n_estimators: 100
max_depth: 10
random_seed: 42
DVC 实验管理
# 运行流水线
dvc repro
# 创建实验分支
dvc exp run --set-param train.n_estimators=200 --name exp-200-trees
# 比较实验
dvc exp show
# 输出指标表
dvc metrics show
dvc metrics diff
特征存储
特征存储(Feature Store)是用于集中存储、共享、服务 ML 特征的数据层。
为什么需要特征存储
- 消除训练/服务偏差:保证训练与推理使用相同的特征转换逻辑
- 特征复用:在团队之间共享特征,消除重复劳动
- 低延迟服务:为在线预测提供实时特征查询
- 特征一致性:维持批处理与实时流水线之间的一致性
在线存储 vs 离线存储
| 区分 | 在线存储 | 离线存储 |
|---|---|---|
| 目的 | 实时推理服务 | 模型训练 |
| 延迟 | 数毫秒 | 数秒到数分钟 |
| 存储介质 | Redis、DynamoDB、Cassandra | S3、BigQuery、Hive |
| 数据量 | 最新状态(当前值) | 全部历史 |
| 查询模式 | 单条查询(基于 key) | 批量扫描 |
Feast 特征存储
# feature_repo/feature_store.yaml
project: fraud_detection
registry: data/registry.db
provider: local
online_store:
type: redis
connection_string: "localhost:6379"
offline_store:
type: bigquery
dataset: feast_dev
# feature_repo/features.py
from datetime import timedelta
from feast import Entity, Feature, FeatureView, FileSource, ValueType
from feast.types import Float32, Int64, String
# 定义实体
user = Entity(
name="user_id",
value_type=ValueType.INT64,
description="用户 ID"
)
# 定义数据源
user_stats_source = FileSource(
path="data/user_stats.parquet",
timestamp_field="event_timestamp",
created_timestamp_column="created"
)
# 定义特征视图
user_stats_fv = FeatureView(
name="user_stats",
entities=["user_id"],
ttl=timedelta(days=7),
features=[
Feature(name="transaction_count_7d", dtype=Float32),
Feature(name="avg_transaction_amount", dtype=Float32),
Feature(name="days_since_last_login", dtype=Int64),
Feature(name="account_age_days", dtype=Int64),
],
online=True,
source=user_stats_source,
tags={"team": "fraud", "version": "v2"},
)
# 使用特征存储 - 训练
from feast import FeatureStore
import pandas as pd
store = FeatureStore(repo_path="feature_repo/")
# 获取训练数据(离线)
entity_df = pd.DataFrame({
"user_id": [1001, 1002, 1003],
"event_timestamp": pd.to_datetime(["2026-03-01", "2026-03-01", "2026-03-01"])
})
training_df = store.get_historical_features(
entity_df=entity_df,
features=[
"user_stats:transaction_count_7d",
"user_stats:avg_transaction_amount",
"user_stats:days_since_last_login",
]
).to_df()
# 在线服务 - 实时特征查询
feature_vector = store.get_online_features(
features=[
"user_stats:transaction_count_7d",
"user_stats:avg_transaction_amount",
],
entity_rows=[{"user_id": 1001}]
).to_dict()
特征漂移检测
from evidently import ColumnMapping
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset
# 生成特征漂移报告
report = Report(metrics=[DataDriftPreset()])
report.run(
reference_data=reference_features,
current_data=current_features,
column_mapping=ColumnMapping(target="label")
)
report.save_html("feature_drift_report.html")
# 查看漂移结果
results = report.as_dict()
drifted_features = [
col for col, info in results["metrics"][0]["result"]["drift_by_columns"].items()
if info["drift_detected"]
]
print(f"检测到漂移的特征: {drifted_features}")
模型注册表
MLflow Model Registry
MLflow Model Registry 是用于模型版本管理、阶段切换与团队协作的中央仓库。
import mlflow
from mlflow.tracking import MlflowClient
client = MlflowClient()
# 注册新模型
model_uri = f"runs:/{run_id}/model"
model_version = mlflow.register_model(
model_uri=model_uri,
name="fraud-detection"
)
# 添加模型说明
client.update_registered_model(
name="fraud-detection",
description="支付欺诈检测模型 - 基于 RandomForest"
)
client.update_model_version(
name="fraud-detection",
version=model_version.version,
description=f"Accuracy: 0.956, F1: 0.943 on test set"
)
# 切换到 Staging
client.transition_model_version_stage(
name="fraud-detection",
version=model_version.version,
stage="Staging",
archive_existing_versions=False
)
# 加载并校验 Staging 模型
staging_model = mlflow.pyfunc.load_model(
model_uri="models:/fraud-detection/Staging"
)
staging_preds = staging_model.predict(X_val)
staging_accuracy = accuracy_score(y_val, staging_preds)
# 校验通过后晋升到 Production
if staging_accuracy > 0.95:
client.transition_model_version_stage(
name="fraud-detection",
version=model_version.version,
stage="Production",
archive_existing_versions=True # 归档之前的 Production 版本
)
print(f"模型 v{model_version.version} 已晋升到 Production")
Hugging Face Hub 模型注册表
from huggingface_hub import HfApi, Repository
from transformers import AutoModelForSequenceClassification, AutoTokenizer
api = HfApi()
# 上传模型
api.upload_folder(
folder_path="./fine-tuned-model",
repo_id="myorg/sentiment-classifier-v2",
repo_type="model",
)
# 更新模型卡片
api.upload_file(
path_or_fileobj="README.md",
path_in_repo="README.md",
repo_id="myorg/sentiment-classifier-v2",
)
# 为特定版本打标签
api.create_tag(
repo_id="myorg/sentiment-classifier-v2",
tag="v2.1.0",
tag_message="Improved accuracy on edge cases"
)
ML 的 CI/CD
GitHub Actions ML 流水线
# .github/workflows/ml-cicd.yml
name: ML CI/CD Pipeline
on:
push:
branches: [main, develop]
paths:
- 'src/**'
- 'params.yaml'
- 'dvc.yaml'
schedule:
- cron: '0 2 * * 1' # 每周一凌晨 2 点自动重训练
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run unit tests
run: pytest tests/ -v --cov=src
- name: Data validation
run: python src/validate_data.py
train-and-evaluate:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure DVC remote
run: |
dvc remote modify myremote access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
dvc remote modify myremote secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Pull data
run: dvc pull
- name: Run DVC pipeline
run: dvc repro
- name: Log metrics to MLflow
run: python src/log_results.py
env:
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
- name: Check model performance gate
run: |
python src/check_performance_gate.py \
--min-accuracy 0.95 \
--min-f1 0.93
- name: Push results
run: |
dvc push
git add reports/metrics.json dvc.lock
git commit -m "chore: update metrics [skip ci]"
git push
deploy-staging:
needs: train-and-evaluate
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Promote model to Staging
run: python src/promote_model.py --stage Staging
- name: Run integration tests
run: pytest tests/integration/ -v
- name: Deploy to staging endpoint
run: kubectl apply -f k8s/staging/
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- name: Promote model to Production
run: python src/promote_model.py --stage Production
- name: Blue/Green deployment
run: ./scripts/blue_green_deploy.sh
- name: Smoke tests
run: pytest tests/smoke/ -v
自动重训练触发器
# src/check_retrain_trigger.py
import mlflow
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset
def should_retrain(
current_data,
reference_data,
performance_threshold=0.92,
drift_threshold=0.3
) -> tuple[bool, str]:
"""判断是否需要重训练"""
# 1. 基于性能的触发条件
current_metrics = get_current_metrics()
if current_metrics["accuracy"] < performance_threshold:
return True, f"性能下降: accuracy={current_metrics['accuracy']:.3f}"
# 2. 数据漂移触发条件
report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=reference_data, current_data=current_data)
results = report.as_dict()
drift_share = results["metrics"][0]["result"]["share_of_drifted_columns"]
if drift_share > drift_threshold:
return True, f"数据漂移: 检测到 {drift_share:.1%} 的特征发生漂移"
return False, "无需重训练"
def get_current_metrics():
client = mlflow.tracking.MlflowClient()
prod_model = client.get_latest_versions("fraud-detection", stages=["Production"])[0]
run = client.get_run(prod_model.run_id)
return {
"accuracy": float(run.data.metrics.get("accuracy", 0)),
"f1_score": float(run.data.metrics.get("f1_score", 0))
}
模型监控与漂移检测
数据漂移 vs 概念漂移
数据漂移(Data Drift):输入特征的分布发生变化。P(X) 变化,但 P(Y|X) 保持不变。例如:用户年龄分布变化、交易金额分布变化。
概念漂移(Concept Drift):输入与输出之间的关系发生变化。P(Y|X) 变化。例如:欺诈模式变化、用户偏好变化。
Evidently 漂移监控
import pandas as pd
from evidently.report import Report
from evidently.test_suite import TestSuite
from evidently import ColumnMapping
from evidently.metric_preset import (
DataDriftPreset,
DataQualityPreset,
TargetDriftPreset,
ClassificationPreset
)
from evidently.tests import (
TestNumberOfDriftedColumns,
TestShareOfDriftedColumns,
TestColumnDrift
)
# 配置列映射
column_mapping = ColumnMapping(
target="fraud_label",
prediction="fraud_score",
numerical_features=["amount", "transaction_count_7d", "avg_amount"],
categorical_features=["merchant_category", "payment_method"]
)
# 综合漂移报告
report = Report(metrics=[
DataDriftPreset(),
DataQualityPreset(),
TargetDriftPreset(),
ClassificationPreset()
])
report.run(
reference_data=reference_df,
current_data=production_df,
column_mapping=column_mapping
)
report.save_html("monitoring/report.html")
# 告警测试套件
test_suite = TestSuite(tests=[
TestNumberOfDriftedColumns(lt=3),
TestShareOfDriftedColumns(lt=0.3),
TestColumnDrift(column_name="amount"),
TestColumnDrift(column_name="transaction_count_7d"),
])
test_suite.run(
reference_data=reference_df,
current_data=production_df
)
# 测试失败时发送告警
results = test_suite.as_dict()
failed_tests = [t for t in results["tests"] if t["status"] == "FAIL"]
if failed_tests:
send_alert(f"监控告警: {len(failed_tests)} 个测试失败")
Prometheus + Grafana 指标监控
# src/monitoring/metrics.py
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time
# 定义指标
prediction_counter = Counter(
"model_predictions_total",
"预测总数",
["model_version", "result"]
)
prediction_latency = Histogram(
"model_prediction_latency_seconds",
"预测延迟",
buckets=[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0]
)
model_accuracy = Gauge(
"model_accuracy_current",
"当前模型准确率"
)
drift_score = Gauge(
"feature_drift_score",
"特征漂移分数",
["feature_name"]
)
# 在服务代码中更新指标
def predict_with_monitoring(features, model_version="v2.1"):
start_time = time.time()
prediction = model.predict(features)
latency = time.time() - start_time
prediction_latency.observe(latency)
prediction_counter.labels(
model_version=model_version,
result="fraud" if prediction[0] == 1 else "normal"
).inc()
return prediction
LLMOps
LLMOps 是面向大语言模型的开发、部署与运维,是 MLOps 的一种扩展。
LLM 流水线的特殊挑战
- 非确定性输出:相同输入产生不同输出 → 评估变得复杂
- 提示词敏感性:微小的改动会引发很大的性能差异
- 高成本的 Fine-tuning:需要大量 GPU 资源
- 幻觉(Hallucination):生成与事实不符的信息
- 上下文长度管理:处理长上下文
使用 LangSmith 进行 LLM 追踪
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langsmith import Client
import os
# LangSmith 配置
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "production-chatbot"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-api-key"
# 定义 LangChain 链(自动记录到 LangSmith 的追踪中)
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)
prompt = ChatPromptTemplate.from_template(
"你是一名友善的客户服务代表。\n\n问题: {question}\n\n回答:"
)
chain = prompt | llm
# 执行 - 自动追踪
response = chain.invoke({"question": "退款政策是怎样的?"})
# 用 LangSmith 客户端做评估
langsmith_client = Client()
# 创建数据集
dataset = langsmith_client.create_dataset(
dataset_name="customer-service-eval",
description="客户服务聊天机器人评估数据集"
)
# 添加评估样例
langsmith_client.create_examples(
inputs=[{"question": "请告诉我退款政策"}],
outputs=[{"answer": "购买后 30 天内可以退款。"}],
dataset_id=dataset.id
)
# 执行自动评估
from langsmith.evaluation import evaluate, LangChainStringEvaluator
evaluators = [
LangChainStringEvaluator("cot_qa"),
LangChainStringEvaluator("labeled_criteria", config={
"criteria": "correctness"
})
]
results = evaluate(
lambda x: chain.invoke(x),
data=dataset.name,
evaluators=evaluators,
experiment_prefix="gpt4o-baseline"
)
提示词版本管理
# prompt_registry.py
import mlflow
from dataclasses import dataclass
from typing import Optional
@dataclass
class PromptVersion:
template: str
version: str
description: str
metrics: Optional[dict] = None
class PromptRegistry:
def __init__(self, mlflow_uri: str):
mlflow.set_tracking_uri(mlflow_uri)
self.experiment_name = "prompt-versions"
mlflow.set_experiment(self.experiment_name)
def register_prompt(self, prompt: PromptVersion) -> str:
with mlflow.start_run(run_name=f"prompt-{prompt.version}") as run:
mlflow.log_param("version", prompt.version)
mlflow.log_param("description", prompt.description)
mlflow.log_text(prompt.template, "prompt_template.txt")
if prompt.metrics:
mlflow.log_metrics(prompt.metrics)
return run.info.run_id
def get_prompt(self, version: str) -> str:
client = mlflow.tracking.MlflowClient()
runs = client.search_runs(
experiment_ids=[mlflow.get_experiment_by_name(self.experiment_name).experiment_id],
filter_string=f"params.version = '{version}'"
)
if not runs:
raise ValueError(f"未找到提示词版本 {version}")
artifact_uri = runs[0].info.artifact_uri
return mlflow.artifacts.load_text(f"{artifact_uri}/prompt_template.txt")
# 使用示例
registry = PromptRegistry("http://mlflow-server:5000")
registry.register_prompt(PromptVersion(
template="你是一名 {role}。{context}\n\n问题: {question}\n回答:",
version="v1.2.0",
description="加入上下文的提示词改进版",
metrics={"accuracy": 0.87, "hallucination_rate": 0.03}
))
LLM 微调流水线
# fine_tuning_pipeline.py
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
TrainingArguments,
Trainer
)
from peft import LoraConfig, get_peft_model, TaskType
import mlflow
def fine_tune_with_lora(
base_model: str,
dataset_path: str,
output_dir: str,
lora_r: int = 16,
lora_alpha: int = 32
):
mlflow.set_experiment("llm-fine-tuning")
with mlflow.start_run():
# LoRA 配置
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=lora_r,
lora_alpha=lora_alpha,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none"
)
mlflow.log_params({
"base_model": base_model,
"lora_r": lora_r,
"lora_alpha": lora_alpha
})
# 准备模型
model = AutoModelForCausalLM.from_pretrained(base_model)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 训练配置
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
fp16=True,
report_to="mlflow"
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
)
trainer.train()
# 保存并注册模型
model.save_pretrained(output_dir)
mlflow.transformers.log_model(
transformers_model={"model": model, "tokenizer": tokenizer},
artifact_path="fine-tuned-model",
registered_model_name="customer-service-llm"
)
测验
Q1. 请说明 MLOps Level 2 中 CT(Continuous Training)自动化的 4 种触发条件。
答案:数据触发、性能触发、漂移触发、计划触发
说明:
- 数据触发:当新的训练数据达到特定阈值(例如 10 万条)、或新的数据批次流入流水线时,自动重训练就会启动。
- 性能触发:当生产模型的准确率、F1 分数等指标跌破预先定义的阈值(例如 accuracy < 0.92)时触发。
- 漂移触发:当 Evidently 等工具检测到的数据漂移比例超过阈值(例如 30% 以上的特征出现漂移)时触发。
- 计划触发:根据业务需求做周期性重训练(例如每周一凌晨 2 点),以维持数据的新鲜度。
Q2. 请说明为什么特征存储要把在线存储和离线存储分开。
答案:是为了分别针对训练与推理各自不同的访问模式和性能要求做优化。
说明:
- 离线存储(S3、BigQuery)用于模型训练。需要对数百万条历史数据做批量扫描,因此大批量处理能力和成本效率更重要,可以容忍较高的延迟(数秒到数分钟)。
- 在线存储(Redis、DynamoDB)用于实时推理。需要在数毫秒内查到某个特定实体(用户 ID、商品 ID)的最新特征,因此针对低延迟的单条查询做了优化。
- 如果不把两者分开,训练时的大批量扫描查询会干扰实时推理查询;反过来,为了满足实时性要求,训练成本又会大幅飙升。
Q3. 请说明数据漂移与概念漂移的差异,以及各自的检测方式。
答案:数据漂移是 P(X) 的变化,概念漂移是 P(Y|X) 的变化。
说明:
- 数据漂移:输入特征的统计分布发生变化。可以用 Kolmogorov-Smirnov 检验、Population Stability Index(PSI)、JS Divergence 等方法检测,Evidently 的 DataDriftPreset 就是典型代表,即使没有标签也能检测。
- 概念漂移:相同输入对应的正确输出发生了变化。例如在欺诈检测中,一旦出现新的欺诈模式,原有规则就会失效。这需要实际的标签,通过模型性能(accuracy、F1)的下降来检测。如果标签滞后到达,可以借助代理指标(proxy metric)。
Q4. 请说明 DVC 如何借助 Git 管理大型 ML 数据。
答案:把指针(元数据)文件存进 Git,实际数据则存放在远程存储中。
说明:
DVC 不会把大文件(数据集、模型)直接存进 Git,而是生成扩展名为 .dvc 的元数据文件,由 Git 来追踪。这个文件里保存着实际数据的 MD5 哈希、大小、路径等信息。实际数据会通过 dvc push 上传到 S3、GCS、Azure Blob 等远程存储。在其他环境中,可以用 dvc pull 下载到完全相同版本的数据。Git 提交与 DVC 数据版本是 1:1 对应的,由此保证了实验的可复现性。
Q5. 请说明 MLflow Model Registry 中,从 Staging 晋升到 Production 之前需要校验的项目。
答案:性能校验、公平性校验、集成测试、性能(延迟)测试、数据 schema 兼容性
说明:
- 性能校验:在留出测试集或近期生产数据上,确认准确率、F1、AUC 等指标与现有 Production 模型相比持平或有所提升。
- 公平性校验:按切片检查特定人群、年龄段等维度上是否存在性能偏差。
- 集成测试:在实际服务环境(API、特征存储连接)中确认端到端预测能够正常工作。
- 性能(延迟)测试:通过负载测试确认平均响应时间及 P99 延迟是否满足 SLA。
- Schema 兼容性:确认输入特征 schema、输出格式是否与当前服务基础设施兼容。
현재 단락 (1/711)
1. [MLOps 概述与成熟度模型](#mlops-概述与成熟度模型)