第二十三课:参数调优的日志与监控
说实话,做参数调优最怕什么?
不是怕参数调不好,而是怕调了半天,回头一看——
「咦?我上次跑的那个0.75的衰减率,到底是在哪个数据集上测的?」
「这个夏普比率2.1的结果,参数组合是什么来着?」
这种问题,我踩过太多次了。所以今天这节课,咱们就聊聊怎么把调优过程「管起来」。
为什么日志和监控这么重要?
你想想看,基差交易的参数空间有多大?
入场阈值、出场阈值、止损比例、仓位管理系数、滚动窗口长度……随便一组合就是几百上千组。
手动记?不现实。
Excel记?容易出错。
最好的办法,就是用专业的工具把整个过程自动化记录下来。
核心原则:每一次调优,都应该能完整复现。包括参数、数据、环境、结果,一个都不能少。
MLflow:我最常用的实验管理工具
MLflow这东西,我用了快三年了。说实话,一开始觉得麻烦,后来发现真香。
它主要解决三个问题:
- 记录参数:每次实验的输入参数自动保存
- 记录指标:夏普、最大回撤、年化收益等自动跟踪
- 记录模型:最优参数组合可以直接打包保存
来看个实际例子。这是我做基差策略调优时常用的代码框架:
import mlflow
import mlflow.sklearn
def run_optimization(params):
with mlflow.start_run():
# 记录参数
mlflow.log_param("entry_threshold", params["entry"])
mlflow.log_param("exit_threshold", params["exit"])
mlflow.log_param("stop_loss", params["stop_loss"])
mlflow.log_param("window_size", params["window"])
# 运行回测
result = backtest_strategy(params)
# 记录指标
mlflow.log_metric("sharpe_ratio", result["sharpe"])
mlflow.log_metric("max_drawdown", result["max_dd"])
mlflow.log_metric("annual_return", result["ann_ret"])
mlflow.log_metric("win_rate", result["win_rate"])
# 保存模型(最优参数组合)
mlflow.sklearn.log_model(result["model"], "model")
return result
跑完之后,在终端输入 mlflow ui,就能在浏览器里看到所有实验的对比。
我的习惯:每次调优前,先创建一个新的Experiment。比如"2024_Q1_basis_tuning",这样不同批次的实验不会混在一起。
TensorBoard:可视化调优过程
MLflow适合记录「结果」,但如果你想看「过程」,TensorBoard是更好的选择。
我记得有一次调优,参数组合跑了整整一个周末。周一回来一看,MLflow里只有最终结果,中间过程完全不知道发生了什么。
后来改用TensorBoard,把每一轮迭代的损失函数、参数变化都记录下来,问题就清楚了。
怎么用?很简单:
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("runs/basis_tuning_001")
for epoch in range(100):
# 模拟调优过程
loss = compute_loss(params)
sharpe = compute_sharpe(params)
# 记录到TensorBoard
writer.add_scalar("Loss/train", loss, epoch)
writer.add_scalar("Metrics/Sharpe", sharpe, epoch)
writer.add_histogram("Params/entry_threshold",
params["entry"], epoch)
# 更新参数
params = update_params(params, loss)
writer.close()
然后在命令行运行 tensorboard --logdir runs,就能在浏览器里看到实时更新的图表了。
注意:TensorBoard记录的是标量、直方图、图像等。如果你需要记录完整的参数组合和回测结果,还是得靠MLflow。两者配合使用效果最好。
参数调优过程可视化
光有数字不够,得能「看」出问题来。
我个人习惯做三张图:
- 参数热力图:横轴是入场阈值,纵轴是出场阈值,颜色代表夏普比率。一眼就能看出最优区域在哪。
- 收敛曲线:每一轮迭代的损失函数变化。如果曲线震荡剧烈,说明学习率可能太大了。
- 参数重要性排序:用随机森林或SHAP值,看看哪个参数对结果影响最大。
下面这张图,展示了我常用的调优监控流程:
性能指标监控
调优过程中,哪些指标最值得关注?
我一般盯这五个:
| 指标 | 含义 | 监控频率 | 异常信号 |
|---|---|---|---|
| 夏普比率 | 风险调整后收益 | 每轮调优 | < 0.5 需警惕 |
| 最大回撤 | 账户最大亏损幅度 | 每轮调优 | > 15% 需停止 |
| 胜率 | 盈利交易占比 | 每轮调优 | < 40% 需检查 |
| 盈亏比 | 平均盈利/平均亏损 | 每轮调优 | < 1.5 需优化 |
| 参数稳定性 | 参数微小变化对结果的影响 | 调优结束后 | 波动大说明过拟合 |
我曾经踩过的坑:有一次调优,夏普比率飙到了3.5,我高兴坏了。结果仔细一看,是因为参数过拟合了历史数据,换到样本外数据直接崩了。所以后来我加了一个「参数稳定性」指标——如果参数稍微变一点,结果就剧烈波动,那这个参数组合基本不能用。
调优结果持久化
调优完了,结果得存下来。不能每次都重新跑一遍吧?
我常用的持久化方案有两种:
- 轻量级方案:用SQLite,适合个人研究。MLflow默认就支持SQLite存储。
- 团队级方案:用PostgreSQL,适合多人协作。可以共享实验数据,方便对比。
配置起来很简单:
# SQLite(个人用)
mlflow.set_tracking_uri("sqlite:///basis_tuning.db")
# PostgreSQL(团队用)
mlflow.set_tracking_uri("postgresql://user:pass@host:5432/mlflow_db")
存完之后,怎么查?
我一般用MLflow的API来查询历史结果:
import mlflow
from mlflow.tracking import MlflowClient
client = MlflowClient()
# 查询所有实验
experiments = client.search_experiments()
# 查询某个实验的所有运行记录
runs = client.search_runs(
experiment_ids=["1"],
order_by=["metrics.sharpe_ratio DESC"],
max_results=10
)
# 输出最优的5组参数
for run in runs[:5]:
print(f"Run ID: {run.info.run_id}")
print(f"夏普比率: {run.data.metrics['sharpe_ratio']}")
print(f"参数: {run.data.params}")
我的建议:每次调优结束后,把最优的3-5组参数单独导出一个CSV文件,放在项目目录下。这样即使数据库出了问题,你手里还有一份备份。
小结一下
日志和监控这件事,说白了就是给调优过程「上保险」。
MLflow管记录,TensorBoard管可视化,数据库管持久化。三者配合,你的调优工作就不再是「黑箱操作」了。
嗯,这套流程我用了两年多,基本没出过「找不到上次结果」这种低级错误。
你也试试看?