管理标普 500 期权序列模型的共享模型群组
代码 《交易机器学习》
总结
本笔记运行标普 500 期权的三模型序列学习群组中已声明的 NLinear 成员。拟合该成员前,先确定整个群组的请求和检查点,以便后续笔记使用同一快照运行 LSTM 和 PatchTST 模型。由于 CPU 和 GPU计算可能产生不同的拟合权重,设备被视为训练身份的一部分;非规范设备因此需要使用独立的群组名称。
工作流程强调可复现性和完整性:记录群组成员,检查 NLinear 请求是否唯一,并验证返回的检查点是否完整。序列构造被描述为能够安全处理缺口,并具备持久化拟合状态、重启支持以及符合条件键的检查。本文不报告模型表现、不比较架构,也不证明交易价值。文中说明建模工作流程的执行和身份控制,模型分析与回测留待后续工作。
核心观点
- 运行 NLinear 成员前,先确定完整的配置和检查点群组。
- 由于CPU和GPU运行可能产生不同权重,训练设备被纳入模型身份。
- 群组快照有助于在某次模型运行失败或刷新时保留已声明的成员信息。
- 笔记检查 NLinear 请求是否唯一,以及其检查点是否完整。
- 绩效和交易结论不属于本笔记的范围。
标签
全文
# 09_deep_learning.py
```py
# ---
# jupyter:
# jupytext:
# cell_metadata_filter: tags,-all
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.19.3
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
# name: python3
# ---
# %% [markdown]
# # S&P 500 Options: NLinear
#
# This notebook snapshots the complete three-model sequence population before fitting its NLinear
# member. `09a_lstm` and `09b_patchtst` execute the other declared members against the same
# immutable population. Every configured checkpoint remains eligible for model analysis and
# backtesting.
#
# Prerequisites: `03_financial_features`, `04_model_based_features`, and `05_evaluation`.
# %%
"""Fit NLinear within the declared S&P 500 options sequence population."""
import polars as pl
from case_studies.research import supersedes_for_run
from case_studies.sp500_options.research_workflow import (
ALL_LABELS,
declared_dl_device,
model_request_catalog,
open_study,
published_dl_device,
resolve_model_requests,
resolved_model_plan,
run_official_model_subset,
run_resolved_model_requests,
snapshot_official_model_catalog,
)
# %% tags=["parameters"]
EXECUTION_TIER = "canonical"
WORKSPACE: str = ""
PREVIEW_REDUCTIONS: dict = {}
DEVICE: str = ""
SEQUENCE_CONFIGS = ("nlinear", "lstm_h64", "patchtst")
POPULATION_NAME: str = ""
SUPERSEDES_POPULATION: str = "7a9dc8881c9e"
# %% [markdown]
# ### The device the population was fitted on
#
# A network trained on a GPU and the same network trained on a CPU accumulate their sums in a
# different order and reach different weights, so the device is part of what the fitted model is
# and sits inside the training identity rather than beside it. The device this population was
# fitted on is declared once, in `modeling.dl.device` in `config/setup.yaml`, and read from there
# by all four deep-learning notebooks rather than retyped in each. On a machine with no NVIDIA
# card the run stops here rather than quietly training something else: set `DEVICE="cpu"` and pass
# a `POPULATION_NAME` to fit the same requests there, under a name of their own.
# %%
CANONICAL_POPULATION_NAME = "sp500-options-sequence-validation-v1"
published_device = published_dl_device()
device = declared_dl_device(DEVICE)
population_name = POPULATION_NAME or CANONICAL_POPULATION_NAME
if device != published_device and population_name == CANONICAL_POPULATION_NAME:
raise ValueError(
f"this run fits on {device!r}, not the published {published_device!r}, so its "
f"identities are not the ones {CANONICAL_POPULATION_NAME!r} holds; pass "
f"POPULATION_NAME to give them a population of their own"
)
print(f"training device: {device} (declared: {published_device})")
# %% [markdown]
# ## Complete sequence request population
#
# The case-wide table is resolved before the first member executes. Canonical execution snapshots
# all configuration-checkpoint identities so a failed member cannot disappear from later analysis.
#
# **A name holds one generation at a time**, and this notebook is the only one that writes this
# population - `09a_lstm` and `09b_patchtst` execute members of a snapshot that already exists.
# Anything that moves a training identity moves every prediction hash with it, so the members
# this run computes are no longer the members an earlier snapshot under the same name declared,
# and those two notebooks then refuse their own work as undeclared. `SUPERSEDES_POPULATION`
# names the snapshot such a run retires, and the value is part of what the population is hashed
# over. The value here names the snapshot this run retires; it is empty only for the first
# snapshot under a name.
#
# `create` refuses a changed member list under an existing name unless this names the current
# snapshot, so the parameter is what makes refreshing this population possible at all. Without
# it the refit stops at the write with the hash it needs, which is the right failure but not
# one this notebook could act on.
# %%
study = open_study(execution_tier=EXECUTION_TIER, workspace=WORKSPACE or None)
all_requests = model_request_catalog(
"deep_learning",
labels=ALL_LABELS,
config_names=SEQUENCE_CONFIGS,
)
all_resolved = resolve_model_requests(
study,
all_requests,
execution_tier=EXECUTION_TIER,
overrides={"device": device},
preview_reductions=PREVIEW_REDUCTIONS,
)
resolved_model_plan(all_resolved)
# %% [markdown]
# ## Execute NLinear
#
# NLinear shares the gap-safe sequence construction, fold boundaries, fitted-state persistence,
# restart, and exact eligible-key checks used by the other sequence configurations.
# %%
nlinear_resolved = tuple(
request for request in all_resolved if request.spec["config_name"] == "nlinear"
)
if len(nlinear_resolved) != 1:
raise ValueError("the sequence population must contain exactly one NLinear request")
if EXECUTION_TIER == "canonical":
population = snapshot_official_model_catalog(
study,
all_requests,
population_name=population_name,
resolved_requests=all_resolved,
supersedes=supersedes_for_run(
study,
population_name=population_name,
declared=SUPERSEDES_POPULATION or None,
execution_tier=EXECUTION_TIER,
),
)
execution, population = run_official_model_subset(
study,
nlinear_resolved,
population=population,
)
else:
if not WORKSPACE or not PREVIEW_REDUCTIONS:
raise ValueError("preview execution requires WORKSPACE and PREVIEW_REDUCTIONS")
execution = run_resolved_model_requests(study, nlinear_resolved)
population = None
# %% tags=["results"]
catalog = execution.catalog_rows.select(
"family",
"label",
"config_name",
"checkpoint_kind",
"checkpoint_value",
"execution_tier",
"complete",
"training_hash",
"prediction_hash",
).sort("checkpoint_value")
if catalog.filter(~pl.col("complete")).height:
raise RuntimeError("NLinear execution returned a partial checkpoint")
catalog
# %% [markdown]
# The NLinear checkpoint artifacts are complete. The official sequence population remains open
# until `09a_lstm` and `09b_patchtst` publish their declared members.
```在遵守原作品许可的前提下,附作者信息全文展示。 许可协议: MIT
此摘要由 Stratmill 研究智能体根据原文撰写,并非原文副本。