简介:这是一套完整的支持向量回归(SVR)预测项目代码与数据包,面向机器学习初学者和需要快速上手回归建模的开发者。资源围绕SVR模型的构建、训练、保存及加载预测展开,涵盖joblib持久化、超参数调优思路,并附带DBN深度信念网络相关脚本,可用于特征预处理或对比实验。压缩包内共35个文件,包含10个Python源码、9个编译后的pyc文件、7个CSV样例数据以及TensorFlow checkpoint模型文件等,整体约50.22MB,目录结构清晰,便于按模块学习。资源中的CSV数据可直接用于训练与验证,Python脚本注释清晰,可降低上手门槛。目前已有1737人学习下载,适合希望掌握SVR实战流程并了解模型持久化操作的读者。通过运行示例脚本,可快速复现从数据准备到模型预测的完整链路,并参考DBN与SVR结合的方式提升回归效果。
1. SVR回归预测,为什么先要正视模型保存
SVR回归预测在不少团队里,真正卡住上线的往往不是精度,而是"模型跑完没保存、第二天预测结果全变了"。我手里有个叫 wordsrt 的项目,拿 SVR 做字幕时间轴偏移的回归预测,目标很简单:输入文本长度、语速、上下文位置,预测这句字幕该平移多少毫秒。模型本身训练起来很快,但每次重新跑一遍代码,预测结果都不一样。问题不在训练,在保存与加载这条链路上的细节。这篇文章用 sklearn.svm.SVR 把"训练—保存—加载—预测"完整走一遍,适合已经跑通 SVR demo、接下来想把模型固化下来的从业者。网上关于 SVR 讲解的内容很多,但大多数停在公式和调参,真正到了保存模型这一步,踩坑的人远比想象中多。
2. SVR回归预测的第一步:把回归问题喂给模型
2.1 回归预测到底预测什么:先确认输入输出再动手
SVR 全称 Support Vector Regression,它的核心思路和分类用的 SVM 一脉相承,只是目标从"找一个超平面把类别分开"变成了"找一个超平面让尽可能多的样本落在 epsilon 管道内"。对做回归预测的人来说,不需要纠结太多数学推导,但要清楚 SVR 适合什么数据:样本量中等、特征维度不高、存在非线性关系、对异常点敏感度较低。
以 wordsrt 项目为例,输入特征是三个数值:"字幕文本长度"、"当前语速(字/分钟)"、"句子在整段对话中的位置比例"。输出是"字幕时间轴偏移量(毫秒)"。这个任务用线性回归也能做,但文本长度和偏移量之间不是严格线性关系——长的句子在低语速下可能不需要偏移,而在高语速下偏移量会突然跳变。这种带局部突变的数据,线性回归容易把突变平滑掉,SVR 的 epsilon 管道反而能容忍一定误差,把真正大的偏移抓住。
动手前要先确认一件事:特征和标签的分布。SVR 对特征尺度极其敏感,尤其是径向基核函数(RBF),它计算的是样本之间的欧氏距离,如果一个特征范围是 0 到 1000,另一个是 0 到 1,距离计算基本被大数值特征主导。这是初学者最容易翻车的地方:拿原始数据直接 fit,结果模型看起来在工作,但换一组数据泛化很差。
import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVR from sklearn.metrics import mean_squared_error, r2_score # 构造示例数据,结构参考 wordsrt 项目的真实输入 np.random.seed(42) n_samples = 800 text_length = np.random.uniform(5, 80, n_samples) speech_rate = np.random.uniform(200, 400, n_samples) position_ratio = np.random.uniform(0, 1, n_samples) # 真实映射:偏移量 = 基础值 + 长度与速率的交互 + 噪声 offset = ( 80 + text_length * 1.5 + (speech_rate - 300) * 0.8 + np.where(text_length > 50, 300, 0) + np.random.normal(0, 20, n_samples) ) X = pd.DataFrame({ "text_length": text_length, "speech_rate": speech_rate, "position_ratio": position_ratio, }) y = offset X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=7 ) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 注意:只能用训练集的 scaler 去转换测试集这段代码里有几个细节值得展开。train_test_split的random_state固定为 7,保证每次运行得到相同切分,否则模型对比没有意义。StandardScaler的用法是这段代码的灵魂:fit_transform用在训练集,transform用在测试集。如果你对测试集单独fit_transform,scaler 会学到测试集的均值和方差,这就相当于把测试集信息泄露给了模型,此时的评估分数虚高,上线后真实预测效果会打折扣。
2.2 最小训练脚本:从数据到 SVR 训练
数据准备好之后,SVR 的训练代码其实很短。用 RBF 核是默认选择,因为它能处理非线性关系,参数也相对直观。下面是完整的训练和评估过程:
model = SVR(kernel="rbf", C=100, epsilon=0.1, gamma="scale") model.fit(X_train_scaled, y_train) y_pred = model.predict(X_test_scaled) mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"MSE: {mse:.2f}") print(f"R2: {r2:.4f}")逻辑说明:model.fit接受两个参数,特征矩阵和标签向量。sklearn 的 SVR 内部会自动做数据处理,不需要手写核函数计算。model.predict返回测试集的预测值,注意传入的X_test_scaled必须和训练时的特征列顺序、缩放方式完全一致,否则预测结果就是错的。r2_score是回归任务里最常用的评估指标,取值范围负无穷到 1,越接近 1 说明模型解释的方差比例越高。
参数说明:kernel="rbf"是 SVR 最常用的核函数;C是惩罚系数,越大表示对训练集误差越不能容忍;epsilon定义了不敏感管道的宽度,在这个范围内预测误差不计入损失;gamma="scale"表示 RBF 核的宽度由特征数量自动决定,等价于1 / (n_features * X.var())。这三个参数是 SVR 回归预测里最需要花时间调的,我一般放在后一节细讲。
训练完的第一个动作不是保存模型,而是记录评估指标。如果你连测试集上的 MSE 是多少都不知道,后面模型保存、加载、再预测的每一步都缺乏参照。wordsrt 项目里的经验是:把每一次训练的 R2、MSE、C、epsilon、gamma 记在一个 CSV 里,后面模型出问题时有据可查。
2.3 三个必须调参数:C、epsilon、gamma 对预测的影响
SVR 调参不像深度学习那样要试几十个组合,多数场景下只需要调三个参数:C、epsilon、gamma。它们各自管一段逻辑:
C控制"对误差的容忍度"。C 越大,模型越试图精确拟合每一个训练点,容易过拟合;C 越小,模型越平滑,但可能欠拟合。wordsrt 项目里文本长度和偏移量有局部突变,C 如果设到 1000,模型会去拟合那些由噪声造成的起伏,测试集 R2 反倒下降。我通常从C=1开始,按 10 倍步长向上找,看测试集误差有没有持续下降,如果过了某个点开始反弹,就回头取前一个值。
epsilon控制"多大的误差可以不在乎"。epsilon 越大,模型越宽松,支持向量越少,预测结果越平滑;epsilon 太小,模型会拼命拟合所有样本,支持向量数量暴涨,训练和预测都变慢。一个常见做法是把 epsilon 设为标签标准差的 5% 到 10%。如果标签范围是 0 到 1000,标准差大约 300,epsilon 设 15 到 30 是合理区间。不要直接设成 0.0,那会让模型在训练集上钻牛角尖。
gamma是 RBF 核的宽度参数,它控制每个训练样本的影响半径。gamma="scale"是 sklearn 的默认值,适合大多数场景。如果模型在训练集上表现很好、测试集上很差,说明 gamma 过大,模型记住了每个训练点周围的小范围特征;如果两者都很差,gamma 可能太小,模型过于平滑。调整 gamma 时用对数刻度:0.01、0.1、1、10,观察 R2 的变化趋势。
下面这张表是我在 wordsrt 项目里常用的参数起点和调整方向,供参考:
| 参数 | 作用 | 起始值 | 过大的影响 | 过小的影响 |
|---|---|---|---|---|
| C | 误差惩罚系数 | 100 | 过拟合,训练集 R2 高、测试集低 | 欠拟合,两个集 R2 都低 |
| epsilon | 不敏感管道宽度 | 0.1 | 模型过度平滑,忽略真实信号 | 支持向量多,训练慢,易过拟合 |
| gamma | RBF 核宽度 | scale(自动) | 决策边界碎片化,泛化差 | 决策边界过度平滑,无法捕捉非线性 |
调参本身是体力活,我一般用GridSearchCV跑一轮粗搜索,锁定大致区间后再手调。但注意:网格搜索是在训练集内部做交叉验证,最终结果要用独立的测试集验证一次,不要在 GridSearchCV 上调测试集,否则你实际上是在用测试集做训练。
3. SVR模型保存:用 joblib 保存模型包的三层思路
3.1 pickle 与 joblib 的真实差异
训练完 SVR 模型,第一个念头通常是import pickle然后pickle.dump(model, f)。这能用,但放在工程环境里不是最优解。sklearn 官方推荐用joblib保存模型,原因是 joblib 对包含大量 numpy 数组的对象做了内存映射优化,保存和加载速度更快,尤其在模型文件超过几十 MB 时差别明显。SVR 本身不大,但如果你的模型通过Pipeline包含了 StandardScaler,或者你在GridSearchCV后保存了best_estimator_,内部可能有多个 numpy 数组,joblib 的优势就体现出来了。
另一个更隐蔽的问题:pickle 和 joblib 保存的文件不通用。你用 pickle.dump 保存的文件,joblib.load 能正常读;但反过来,joblib 默认格式的文件用 pickle.load 读会直接报错,因为 joblib 的文件头有自己的标记。这会导致一个尴尬的局面:同事用 pickle 写了个加载脚本,看到 joblib 文件直接懵了。所以保存格式要统一,别混用。
模型保存这件事,本质上是把一个 Python 对象连同它依赖的环境序列化到磁盘。SVR 模型对象内部包含支持向量、系数、核参数、训练时的样本尺度信息等,这些数据大部分是 numpy 数组。pickle 和 joblib 都能处理,区别在于 joblib 对 numpy 数组做了更高效的编码。
from sklearn.pipeline import Pipeline import joblib # 把缩放和模型放进同一个 Pipeline,保存时只要存一个对象 pipeline = Pipeline([ ("scaler", StandardScaler()), ("svr", SVR(kernel="rbf", C=100, epsilon=0.1, gamma="scale")) ]) pipeline.fit(X_train, y_train) # 直接传入原始特征,缩放由 Pipeline 内部完成 joblib.dump(pipeline, "models/svr_wordsrt_baseline.joblib") print("模型已保存")这段代码展示了一个我强烈推荐的做法:把 StandardScaler 和 SVR 一起包到 Pipeline 里。这样做的好处是保存和加载都只需要管一个对象,预测时直接传原始特征,Pipeline 会自动做标准化。如果你单独保存 scaler 和 model,加载时要写两行代码,还容易漏掉其中一个。wordsrt 项目早期就是分开保存的,结果有一次模型文件被拷贝到另一台机器,scaler 没跟着过去,预测结果全成了离谱值。
3.2 保存模型不只是存一个对象:scaler、特征名、元信息一起存
单独把模型的参数存下来,不足以支撑回归预测的完整复现。除了模型本身,至少还有三类信息应该跟着模型一起保存:模型的版本或训练时间、训练时的评估指标、特征列的顺序。为什么特征名很重要?因为 sklearn 在预测时按位置取特征,不关心列名。如果你训练时用的是["text_length", "speech_rate", "position_ratio"],加载模型后传入的 DataFrame 列顺序变成["speech_rate", "text_length", "position_ratio"],SVR 会把每一列的值当成另一个特征去算,预测结果完全错误,而且代码不报任何错。
所以保存模型时,我通常把元信息存在同一个目录的 JSON 文件里:
import json import time model_info = { "model_name": "svr_wordsrt_baseline", "created_at": time.strftime("%Y-%m-%d %H:%M:%S"), "features": ["text_length", "speech_rate", "position_ratio"], "target": "offset_ms", "metrics": {"r2": 0.87, "mse": 1234.5}, "params": {"C": 100, "epsilon": 0.1, "gamma": "scale"} } with open("models/svr_wordsrt_baseline_meta.json", "w", encoding="utf-8") as f: json.dump(model_info, f, ensure_ascii=False, indent=2)这段代码本身不复杂,但它把"模型保存"从一个 dump 动作变成了一次完整的归档。created_at字段用于追溯模型是什么时候训练的;features字段用于加载后检查输入列顺序;metrics字段记录当时的评估结果,方便后面做模型版本对比。建议把这些信息放在模型文件旁边,文件名保持一致,只后缀不同。
保存模型时还有一个小习惯:用joblib.dump的返回值确认保存路径。joblib 会返回保存的文件路径列表,如果存储空间不足或权限有问题,它会抛异常。最怕的是代码没报错,但文件没写进去——比如你保存到相对路径,当前工作目录和预期不一致,文件写到了别的地方。这时再训练一次模型,预测结果对不上,你还以为是模型的问题,实际上是文件路径的问题。
3.3 保存路径、权限、环境引起的无声失败
模型保存失败并不是总能被捕获。典型的无声失败场景是路径存在但不可写。在 Windows 上,路径含有中文字符或空格时,joblib 保存可能正常,但加载时如果用错了路径分隔符,会直接 FileNotFoundError。Linux 服务器上则常见权限问题:训练代码用 root 用户跑,保存的模型文件权限是 600,部署时切换到普通用户加载,直接 PermissionError。
为了避免这类问题,我养成了一个习惯:保存模型前先检查目录是否存在并创建;保存后立即用 os.path.getsize 检查文件大小是否大于 0。这个小检查能拦截掉一大半"无声失败":
import os os.makedirs("models", exist_ok=True) joblib.dump(pipeline, "models/svr_wordsrt_baseline.joblib") file_size = os.path.getsize("models/svr_wordsrt_baseline.joblib") assert file_size > 0, "模型文件大小为 0,保存可能失败" print(f"保存成功,文件大小: {file_size} bytes")os.makedirs加上exist_ok=True后,目录存在也不会报错。assert在这里起一个快速校验作用,文件大小为 0 时立即中止。这个检查单独看很基础,但在自动化训练脚本里,它能避免后面加载模块拿到一个损坏的文件后报一堆无关错误。模型保存不是一个一次性的动作,它会在你每次重新训练时执行。把路径检查、文件大小检查固化到脚本里,是值得投入的工程化成本。
4. 加载预测与常见问题排查:模型不能只 load 回来就完事
4.1 加载模型并做预测的最小例子
模型保存的最终目的是"加载 + 预测"。下面这段代码展示了从磁盘加载模型到对单条样本做预测的完整流程。这里我继续用 Pipeline 方案,因为加载后不需要手动处理缩放:
import joblib import pandas as pd loaded_pipeline = joblib.load("models/svr_wordsrt_baseline.joblib") new_sample = pd.DataFrame({ "text_length": [42.0], "speech_rate": [320.0], "position_ratio": [0.6] }) predicted_offset = loaded_pipeline.predict(new_sample) print(f"预测偏移量: {predicted_offset[0]:.2f} ms")逻辑说明:joblib.load返回的是之前保存的完整 Pipeline 对象,它内部包含了 StandardScaler 和 SVR。调用predict时,Pipeline 会先对输入做标准化,再传给 SVR 做预测。new_sample必须是一个二维结构,sklearn 不接受一维数组作为预测输入,所以用 DataFrame 包裹单行数据。
参数说明:如果加载的是一个单独保存的 SVR 模型,没有包含 scaler,那么预测前必须手动执行scaler.transform(new_sample),再把缩放后的数据传给model.predict。这也是为什么前面强调把 scaler 和模型一起保存——省掉的不仅是代码,还省掉了一个"忘记缩放"的隐患。一个容易被忽略的细节是 DataFrame 的列顺序。Pipeline 不会检查列名,它只看位置。new_sample的列顺序必须和训练时一致。如果训练用的特征顺序是text_length在前,speech_rate在后,预测时反过来传,模型不会报错,但预测结果毫无意义。所以我在保存模型时把特征列表写进 JSON,加载预测前先做一次列名对齐检查:assert list(new_sample.columns) == model_info["features"]。
4.2 模型加载最容易翻车的 5 个点:现象、原因、处理
以下五个问题是做 SVR 模型加载和预测时最高频的踩坑记录,每一条都是实际出现过的现象,按"现象 → 原因 → 解决"顺序列出:
问题 1:joblib.load 报 ModuleNotFoundError现象:加载模型时提示ModuleNotFoundError: No module named 'sklearn'或者某个自定义模块找不到。原因:当前 Python 环境与训练时不是同一个环境。SVR 模型保存的只是对象数据,加载时需要重新导入 sklearn 类定义。解决:在加载前确认pip list里的 scikit-learn 版本与训练环境一致,最稳妥的方案是用相同的虚拟环境文件去部署,训练与推理不要跨环境混用。
问题 2:scikit-learn 版本不一致导致 SVR 加载后 predict 报错现象:模型加载成功,但调用 predict 时报AttributeError: 'SVR' object has no attribute '_n_support'或类似的内部属性缺失。原因:sklearn 不同版本之间 SVR 的内部结构有变化,低版本保存的模型在高版本里可能缺少某些属性。解决:无条件锁定 scikit-learn 版本,用 requirements.txt 固定版本号,比如scikit-learn==1.3.2。如果已经跨版本加载,只能回到原环境重新保存模型。
问题 3:路径存在但文件加载失败现象:明明看到文件在目录里,joblib.load却报FileNotFoundError,或者在 Windows 下用相对路径加载时报错。原因:当前工作目录和应用启动目录不一致。比如在项目根目录下训练并保存模型,部署时从子目录启动服务,相对路径就指向了错误的位置。解决:不要用裸的文件名,用os.path.join拼接绝对路径,或在启动脚本里先os.chdir切换到项目根目录。用Path(__file__).resolve().parent.parent / "models" / "model.joblib"这种基于代码文件位置的路径,比相对路径可靠得多。
问题 4:DataFrame 传入后列顺序被改变现象:训练时特征顺序固定,加载模型预测时数据是从接口接收的字典,转成 DataFrame 后列顺序变了,预测结果跳动很大。原因:从字典创建 DataFrame 时,Python 3.7 后虽然保留插入顺序,但如果调用方代码里用了集合或无序遍历,列顺序会被打乱。解决:在数据进入预测函数前,统一按model_info["features"]重新选取列:df = df[model_info["features"]]。这一步能彻底消除列顺序带来的不确定性。
问题 5:保存时用了 pickle,加载时用 joblib.load现象:joblib.load读 pickle 文件时报EOFError或者无法解析的文件格式。原因:两种序列化协议的头部结构不同。解决:统一用 joblib 保存和加载,或者在代码里先判断文件后缀。.pkl和.joblib都可能是 joblib 格式,靠后缀不可靠,最稳的方法是固定一套保存和加载的方式,并把它封装成一个函数。
这些问题的共性,是"模型保存"被看成了一个孤立动作。实际上,模型保存、环境依赖、路径管理、特征对齐是一整套链路,任何一环脱节,最终都会在"加载预测"这一步爆发。每次加载模型后,先拿一条训练集样本做对照预测,如果和训练时的预测结果偏差很大,说明加载后的模型和数据链路有问题,马上排查,而不是继续往下传。
4.3 把加载测试写进工程脚本,每次用模型前自动检查
与其等模型上线后预测结果不对再回头查,不如在加载脚本里直接加一个"模型一致性检查"。这个思路来源于一个血泪经验:有次我重构代码,把训练脚本里的特征顺序改了,保存模型时也重新训练了,但接口层还是按旧顺序传数据,预测结果全部偏移。排查了一天,最后发现是列名顺序问题。从那之后,我的加载脚本长这样:
PRE_CHECK_SAMPLE = { "text_length": [42.0], "speech_rate": [320.0], "position_ratio": [0.6] } def load_model_and_validate(model_path, meta_path): model = joblib.load(model_path) with open(meta_path, "r", encoding="utf-8") as f: meta = json.load(f) sample_df = pd.DataFrame(PRE_CHECK_SAMPLE)[meta["features"]] pred = model.predict(sample_df)[0] # 这里的 expected_range 来自保存时的训练记录,需要人工根据模型表现设定 assert 50 < pred < 500, f"模型预测结果异常: {pred}" return model, meta逻辑说明:load_model_and_validate函数做了三件事:加载模型、读取元信息、用一条固定样本做预测检查。PRE_CHECK_SAMPLE是一条在训练集中真实存在的样本,预测值应该落在合理区间内。如果预测结果超出预期范围,说明模型加载异常或特征顺序有问题。
meta["features"]在样例中被用来重新排序列,保证进入模型的数据与训练时完全一致。这个检查在每次加载模型后执行,成本极低,但能拦截掉四种问题:模型文件损坏、环境不兼容、特征顺序错误、scaler 缺失。在 wordsrt 项目里,我把这个检查放在服务启动阶段,模型加载失败直接拒绝启动服务,避免带病运行。
5. 让 SVR 模型保存变成项目资产:版本、配置和回滚
5.1 模型命名带上日期和指标,索引和回滚都省心
模型保存的第一条规范是命名。不要用model.joblib这种名字,它会让你在两周后分不清这个文件是什么时候训练的、效果如何。我现在的命名格式是:
svr_wordsrt_{YYYYMMDD}_{r2:.4f}.joblib例如svr_wordsrt_20250612_0.8732.joblib,从文件名就能读出训练日期和测试集 R2。配合元信息 JSON 文件,整个模型目录就是一层简单的模型注册表:
models/ ├── svr_wordsrt_20250612_0.8732.joblib ├── svr_wordsrt_20250612_0.8732_meta.json ├── svr_wordsrt_20250610_0.8541.joblib └── svr_wordsrt_20250610_0.8541_meta.json这种命名方式在模型回滚时特别有用。如果 6 月 12 日的模型上线后出了问题,直接加载 6 月 10 日的旧版本,文件名里的 R2 一眼就能看出旧版本在测试集上的表现上限是否可接受。不要靠修改时间来识别模型版本,文件修改时间是可以被拷贝动作改变的,而文件名里的日期和指标是固定的。
5.2 每次上线前的验证脚本:重训、保存、加载、对比
模型训练、保存、加载、预测这四个环节,很多人是分开写脚本的。训练完手动保存,预测时手动加载,中间出了偏差靠肉眼观察。更好的做法是串成一个流程脚本,训练完自动保存,保存完自动加载,加载完自动对比训练时的预测结果。我推荐的最小验证流程如下:
# 1. 训练 pipeline.fit(X_train, y_train) train_pred = pipeline.predict(X_train_scaled) # 2. 同时保存新旧两个版本 current_name = f"svr_wordsrt_{time.strftime('%Y%m%d')}" joblib.dump(pipeline, f"models/{current_name}.joblib") # 3. 立刻加载并对比 reloaded = joblib.load(f"models/{current_name}.joblib") reloaded_pred = reloaded.predict(X_train_scaled) # 4. 一致性阈值判断 diff = np.max(np.abs(train_pred - reloaded_pred)) assert diff < 1e-6, f"重新加载后的预测结果变了,最大差异: {diff}"这段代码的核心价值在于第 4 步的一致性断言。理论上,同一个模型保存后加载再预测,结果应该完全相同。如果差异超过 1e-6,说明序列化或反序列化过程中有精度损失,或者文件被损坏。有些环境里浮点计算会因为 CPU 指令集不同产生微小差异,所以阈值设到 1e-6 通常够用。如果发现差异太大,就不要急着部署这个模型。
顺带提一句,市面上很多本地模型配置管理工具,界面化地帮你在"保存本地模型配置"这一步做事,但它们的底层实现五花八门,经常出现"配置保存失败"的提示,原因无非是路径权限、JSON 序列化不了某些参数对象、或者模型文件与配置文件放到了不同目录。这类工具本质上是把上述流程封装成了界面,但底层链路并没有变。自己手动维护一套命名规范的模型目录,比依赖一个黑匣子工具更可控。
5.3 推荐的落地目录结构和我的保存习惯
最终落地时,我的项目结构如下,供参考:
project/ ├── data/ │ ├── raw/ │ └── processed/ ├── models/ │ ├── svr_wordsrt_20250612_0.8732.joblib │ └── svr_wordsrt_20250612_0.8732_meta.json ├── src/ │ ├── train.py │ ├── predict.py │ └── validate_model.py └── config/ └── model_config.yaml训练脚本读取config/model_config.yaml中的参数配置,训练后按命名规范保存到models/目录,同时写出元信息 JSON。测试环境里要跑回归测试时,固定加载models/下最新版本的文件,按 4.3 节的方法做一致性校验。全流程自动化之后,模型保存不再是"跑完训练顺便存一下"的附属动作,而是一个和训练并行的重要环节。
我的保存习惯可以总结为三条:第一,模型和元信息永远成对保存;第二,加载模型后永远先跑一条校准样本再对外提供预测;第三,永远保留最近两个版本的模型文件,不轻易删除旧版。做到这三点,SVR 模型保存出错的可能性会降到一个很低的水平。这些规则是我踩了不少坑才形成的,现在每次新项目都会先搭好这套结构再开始训模型。希望帮到你。
本文还有配套的精品资源,点击获取