云原生 ML
这一课你将能做到
- 按请求模式为模型选择正确的推理形态:在线 / 批量 / 流式 / 边缘
- 本地实现一个可运行的每日批量打分任务,给题目难度评分模型落库
- 读懂云托管训练与 Endpoint 的通用模式(SageMaker/Vertex/AzureML),掌握 spot 训练等成本手段
为什么要学
前几课的服务形态都是「在线推理」:请求来了毫秒级返回。但 ML 的推理形态不止一种——给全站 2 万道题每天更新一次难度分,用在线服务逐题调用纯属浪费;更自然的形态是每天跑一次批量任务,把分数写进数据库供站内查询。形态选错,成本和延迟都会差一个数量级。
同时,自建 K8s 是一条重运维路线,云厂商的托管 ML 平台(SageMaker / Vertex AI / Azure ML)把训练资源、Endpoint、注册中心都打包成服务。理解它们的通用模式,你才能判断「什么时候值得上、怎么避免被锁定」。人话:形态是「怎么算」,云是「在哪算」,两件事都要按成本与延迟来决策。
先建立图像
| 形态 | 触发方式 | 延迟要求 | 本站场景 | 课内实践 |
|---|---|---|---|---|
| 在线 Online | 用户请求实时触发 | 毫秒级 | 提交时预测是否 TLE | 第 1/8/10 课的 FastAPI |
| 批量 Batch | 定时任务 | 分钟~小时 | 每日全量题目难度分 | 本课 batch_score.py |
| 流式 Streaming | 事件流持续驱动 | 秒级 | 实时 TLE 率特征 | 第 2 课 Kafka |
| 边缘 Edge | 设备本地 | 极低 | 客户端离线代码提示 | TFLite(第 12 课概览) |
云托管训练的通用模式(三家平台同构):
提交代码(train.py) + 数据指针(S3/GCS) + 资源规格(instance type)
→ 平台起容器跑训练 → 指标/模型落平台存储 → 注册/部署 Endpoint
你管的:代码与数据 平台管的:环境、扩缩、容错、计费
跟着做
步骤 1:批量推理的落地任务(可运行)
题目难度评分:用历史上「有人工难度分」的题训练一个回归器,每天给新题打分。
# src/batch_score.py —— 每日批量给题目打难度分并写回数据库
import sqlite3
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
import joblib, pathlib
DB = "problems.db"
def init_db(conn: sqlite3.Connection):
conn.executescript("""
CREATE TABLE IF NOT EXISTS problems(
problem_id INTEGER PRIMARY KEY, submits INTEGER,
tle_rate_7d REAL, avg_time REAL, human_rank INTEGER, pred_rank REAL);
""")
conn.executemany(
"INSERT OR IGNORE INTO problems VALUES (?,?,?,?,?,NULL)",
[(1000 + i, 200 - i * 7, 0.5 - i * 0.02, 900 + i * 120,
(i % 5) + 1) for i in range(20)])
conn.commit()
def train(conn):
labeled = pd.read_sql(
"SELECT tle_rate_7d, avg_time, human_rank FROM problems "
"WHERE human_rank IS NOT NULL", conn)
X = labeled[["tle_rate_7d", "avg_time"]]
y = labeled["human_rank"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_tr, y_tr)
print("MAE =", round(mean_absolute_error(y_te, model.predict(X_te)), 3))
joblib.dump(model, "models/difficulty-v1.joblib")
return model
def score_all(conn, model):
todo = pd.read_sql(
"SELECT problem_id, tle_rate_7d, avg_time FROM problems", conn)
preds = model.predict(todo[["tle_rate_7d", "avg_time"]])
conn.executemany(
"UPDATE problems SET pred_rank=? WHERE problem_id=?",
zip(preds.round(2), todo["problem_id"]))
conn.commit()
if __name__ == "__main__":
pathlib.Path("models").mkdir(exist_ok=True)
with sqlite3.connect(DB) as conn:
init_db(conn)
score_all(conn, train(conn))
print(pd.read_sql("SELECT problem_id, human_rank, pred_rank "
"FROM problems LIMIT 5", conn))
python src/batch_score.py
# 真实环境:模型由第 5 课注册中心提供,任务由第 6 课编排器每日触发,
# 数据来自第 2 课的 problem_daily 特征表,输入是 SQL 而不是内存表
步骤 2:读懂云上脚本模式(概念对照,需账号)
三家平台的训练入口长得几乎一样——「脚本 + 数据指针 + 资源规格」:
# 伪代码:需要 AWS 账号,演示脚本模式的结构
from sagemaker.sklearn import SKLearn
est = SKLearn(
entry_point="train.py", # 你第 4 课写的训练脚本,改动极小
role=role, instance_type="ml.m5.xlarge",
use_spot_instances=True, # spot 抢占式实例,省 60~90%
max_run=3600, max_wait=7200, # spot 被回收时的容忍窗口
checkpoint_s3_uri=ckpt_uri, # 配合断点续训
hyperparameters={"max-iter": 400, "lr": 0.05},
)
est.fit({"train": "s3://bucket/judge_clean.parquet"})
# 训练产物自动落 S3,可注册进 SageMaker Model Registry(对应第 5 课)
Vertex AI 用 CustomJob.from_local_script,Azure ML 用 command() 组件,参数骨架一致:入口脚本、实例规格、spot/抢占选项、数据 URI。学懂一个,另两个是「查 API」而不是「重新学」。
步骤 3:形态决策演练
对本站三个需求做决策(写下来,面试可直接引用):
① 判题提交时预测超时 → 在线:毫秒级延迟是硬约束
② 每日题目难度分更新 → 批量:T+1 完全够用,成本近乎为零
③ 首页「今日难度飙升榜」→ 批量产分 + 在线读库,不需要模型实时推理
讲清楚要点
- 形态由「谁触发、多快要」决定:能批绝不在线,能异步绝不阻塞主链路。批量任务的单位成本可比在线服务低两个数量级。
- 托管训练的本质是「把环境运维外包」:你交出环境控制权,换来自动扩缩、断点容错、按秒计费。训练脚本要平台无关(参数化、数据 URI 化),这是可移植的关键。
- spot/抢占式实例是训练降本第一杠杆:代价是随时被回收,必须配 checkpoint 续训。深度学习训练把「每 N 步存 checkpoint 到对象存储」当成默认习惯。
- 多云可移植的三件套:容器镜像(第 8 课)、开放格式模型文件(joblib/ONNX)、注册中心元数据跟随 Git/DVC。平台专属 API 只允许出现在部署层薄壳里。
- 成本四账本:训练(spot/容量预留)、推理(endpoint 常驻 vs serverless 按调用)、存储(生命周期分层:热数据 SSD、冷数据归档)、流量(跨可用区/跨区传输费经常是隐形大头)。
你可能会懵的地方
- 云平台会不会锁定我?怎么防? 会,但要分清「值得被锁」与「意外被锁」。防意外锁定:训练与推理代码平台无关、数据用开放格式(Parquet/ONNX)、CI/CD 与编排用开源工具(Airflow/MLflow)。平台 API 收敛在发布薄壳层,迁移成本就只有这一层。
- 自建 K8s 和托管平台怎么选? 团队有平台工程能力、多业务共享集群、数据敏感在自有机房 → 自建/混合;团队小、想聚焦模型与产品、可接受云绑定 → 托管。中间态很常见:训练上托管(突发大算力),推理自建(常驻可控)。
- Serverless Endpoint 缩容到 0 是免费的吗? 存储与注册费用仍在,但计算确实按调用计费;代价是冷启动(分钟级拉起+模型加载)。判题超时预测这类毫秒级交互场景不适合冷启动,更适合常驻副本 + HPA。
- 生产能把 SageMaker Studio/Notebook 当服务跑吗? 不能。Notebook 实例是交互环境,无 SLA、无探针、无自动扩缩。生产必须是 Endpoint(托管)或容器化部署(自建),Notebook 只用于探索。
- 数据合规要注意什么? 用户提交的代码属于用户数据:存储加密与区域驻留(数据不出指定地域)、训练日志脱敏、删除请求可追溯(血缘此时变成义务而非特性)。出海或政务场景先过合规再谈架构。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 每次训练全量重新上传数据 | 时间与流量费双输 | 数据常驻对象存储,训练只传指针 |
| 云账号无预算告警 | 一个月跑飞半个月工资 | 开 billing alarm,训练任务设 max_run/max_wait |
| 生产服务跑在 Notebook 实例上 | 无 SLA 无自愈,随时挂 | Notebook 只做探索,生产走 Endpoint/容器 |
| 忽略跨可用区流量费 | 月底账单出现隐形大头 | 同区部署训练与存储,压测带宽账单 |
| spot 实例不配 checkpoint | 被回收即从零重训 | 定期存 checkpoint 到对象存储并验证可续训 |
卡点急救
- 批量任务重复执行打了双份分:UPDATE 天然幂等(按主键覆盖),但 INSERT 类任务要加
INSERT OR REPLACE或先删后插;配第 6 课的 ds 分区思维。 - 云 SDK 报权限不足:IAM 角色/服务账号缺最小权限集;先给「只读对象存储 + 写指定前缀」验证,再逐步加权限,别一上来用管理员。
- 训练在本地能跑、云上 OOM:实例内存小于本地;entry_point 里限制进程内存、数据分块读,或升一档实例规格并压测。
面试常问
- 批量推理和在线推理怎么选? 看三个问题:结果新鲜度要求(T+1 可接受→批量)、延迟要求(毫秒级→在线常驻)、调用量(海量低频→批量,持续高频→在线+HPA)。混合模式最常见:批量产全局分,在线算个性化增量。
- 云 ML 平台的组件与自建栈怎么对应? 托管训练↔自建训练集群+编排;Model Registry↔MLflow Registry;Endpoint↔K8s Deployment+HPA;Feature Store↔自建特征表/Feast;Studio 类 IDE↔JupyterHub。理解对应关系后,云是「加速器」而不是「另一套世界观」。
- 训练成本优化的手段清单? spot/抢占式实例 + checkpoint 续训;实验期小数据迭代、收敛前不上大机器;托管 spot 训练排队错峰;模型压缩与量化降低推理规格;存储生命周期分层;最后加预算告警兜底。
自测三问
- 四种推理形态分别适合本站哪个场景?为什么?
- spot 训练省钱的代价是什么?工程上如何兜底?
- 防止云锁定的「三件套」是什么?
小结一句话
推理形态按「触发者与延迟预算」选择,云托管平台把环境运维外包给你,用平台无关的代码与开放格式换取降本与可移植。
延伸
- AWS SageMaker 官方文档——托管训练与 Endpoint 的参考实现,可对照 Vertex AI / Azure ML 文档横向理解。
- 下一课:监控与可观测——服务指标、预测分布与数据漂移的三层监控体系。