キャパの異なる2つの自己注意モデルを“学習的に”スタックして、レース予測を実戦仕様で学習・保存・再利用する起動スクリプト
今回は、レース予測モデルの学習/推論パイプラインの起点です。
このコードは、2種類のハイブリッドモデル(LSTM+埋め込み+SetTransformer)を構築してスタッキングし、go
に応じて 学習→保存 もしくは 再構築→重み読込→推論モード に切り替えます。
print("✅ train__model開始")
input_dim = X_train_seq.shape[2]
class_weights_dict = compute_class_weights(y_train)
class_weights_tensor = torch.tensor(
[class_weights_dict.get(i, 1.0) for i in range(6)],
dtype=torch.float32
).to("cuda" if torch.cuda.is_available() else "cpu")
model_self_attn = HybridRaceModelWithEmbedding(
input_dim=input_dim,
sequence_length=sequence_length,
lstm_hidden=64,
embedding_input_dims=embedding_input_dims,
embedding_output_dims=embedding_output_dims
)
model_self_attn.set_transformer = SetTransformer(
input_dim=64,
hidden_dim=16,
num_heads=1,
num_blocks=1,
dropout_p=0.1
)
model_set_transformer = HybridRaceModelWithEmbedding(
input_dim=input_dim,
sequence_length=sequence_length,
lstm_hidden=64,
embedding_input_dims=embedding_input_dims,
embedding_output_dims=embedding_output_dims
)
model_set_transformer.set_transformer = SetTransformer(
input_dim=64,
hidden_dim=32,
num_heads=2,
num_blocks=2,
dropout_p=0.4
)
# Stacking Ensemble モデルを作成
emodel = StackingEnsembleRaceModel(
model_self_attn=model_self_attn,
model_set_transformer=model_set_transformer,
hidden_dim=32
).to(device)
# ✅ 学習実行
if go:
print("🚀 Training started...")
model = train_racewise_regression_model(
input_dim=input_dim,
X_sequences=X_train_seq,
X_cat_dict=X_cat_train,
y_ranks=y_train,
race_ids=race_ids_train,
history_lengths=history_lengths_train,
val_sequences=X_val_seq,
val_cat_dict=X_cat_val,
val_ranks=y_val,
val_race_ids=race_ids_val,
val_history_lengths=history_lengths_val,
sequence_length=sequence_length,
batch_size=12,
collate_fn=grouped_race_collate_fn,
epochs=10,
lstm_hidden=64,
class_weights=class_weights_tensor,
horse_ids=horse_ids_train,
val_horse_ids=horse_ids_val,
model=emodel,
device=device
)
torch.save(model.state_dict(), "transformer_model.pth")
print("✅ transformer_model 保存済み")
else:
model_self_attn = HybridRaceModelWithEmbedding(
input_dim=input_dim,
sequence_length=sequence_length,
lstm_hidden=64,
embedding_input_dims=embedding_input_dims,
embedding_output_dims=embedding_output_dims
)
model_self_attn.set_transformer = SetTransformer(
input_dim=64,
hidden_dim=16,
num_heads=1,
num_blocks=1,
dropout_p=0.1
)
model_set_transformer = HybridRaceModelWithEmbedding(
input_dim=input_dim,
sequence_length=sequence_length,
lstm_hidden=64,
embedding_input_dims=embedding_input_dims,
embedding_output_dims=embedding_output_dims
)
model_set_transformer.set_transformer = SetTransformer(
input_dim=64,
hidden_dim=32,
num_heads=2,
num_blocks=2,
dropout_p=0.4
)
model = StackingEnsembleRaceModel(
model_self_attn=model_self_attn,
model_set_transformer=model_set_transformer,
hidden_dim=32
).to(device)
state_dict = torch.load("transformer_model.pth", map_location=device)
model.load_state_dict(state_dict)
model.to(device)
model.eval()
print("⏩ Skipped training (go=False). Using preloaded model instead.")
1) 入力次元とクラス重みの準備
input_dim = X_train_seq.shape[2]
class_weights_dict = compute_class_weights(y_train)
class_weights_tensor = torch.tensor(
[class_weights_dict.get(i, 1.0) for i in range(6)],
dtype=torch.float32
).to(device)
input_dim
:数値特徴テンソルX_train_seq
のチャネル数(学習前処理で「数値+TAIL(類似度・履歴正規化・pad旗)」を結合済み)。compute_class_weights
:学習データの ランク頻度の逆数 を計算(希少クラスを重く)。ここでは 6クラス(例:1〜5位+6=その他)を想定し、無いクラスは既定1.0。class_weights_tensor
はsoft_top1_loss
等に渡され、不均衡補正に使われます。
2) 2系統のハイブリッドモデルを構築(多様性を作る)
model_self_attn = HybridRaceModelWithEmbedding(..., lstm_hidden=64, ...)
model_self_attn.set_transformer = SetTransformer(input_dim=64, hidden_dim=16, num_heads=1, num_blocks=1, dropout_p=0.1)
model_set_transformer = HybridRaceModelWithEmbedding(..., lstm_hidden=64, ...)
model_set_transformer.set_transformer = SetTransformer(input_dim=64, hidden_dim=32, num_heads=2, num_blocks=2, dropout_p=0.4)
- 共通:数値系列+カテゴリ埋め込み → LSTM(64) → SetTransformer でレース内の相互作用を表現。
- 相違点:SetTransformer のキャパ・正則化を変えて多様性を確保。
self_attn
系:軽量(H=16, heads=1, blocks=1, dropout 0.1)set_transformer
系:重厚(H=32, heads=2, blocks=2, dropout 0.4)
model_xxx.set_transformer = ...
は 内部の集合モジュールを差し替え。同じ LSTM 出力(次元=64)を前提にするためinput_dim=64
を指定。
3) スタッキング・アンサンブルの作成
emodel = StackingEnsembleRaceModel(
model_self_attn=model_self_attn,
model_set_transformer=model_set_transformer,
hidden_dim=32
).to(device)
- 2モデルの 出力スコア([B,S]) を受け取り、
- 既定では 小さな MLP ヘッド(
Linear→ReLU→Dropout→Linear
)で学習的に融合します(平均ではない)。
- 既定では 小さな MLP ヘッド(
- 意図:異なる帰納バイアス(軽量自己注意 vs. 重装自己注意)の長所を統合し、汎化性能を底上げ。
4) 学習フロー(go=True の場合)
model = train_racewise_regression_model(
input_dim=input_dim,
X_sequences=X_train_seq, X_cat_dict=X_cat_train,
y_ranks=y_train, race_ids=race_ids_train, history_lengths=history_lengths_train,
val_sequences=X_val_seq, val_cat_dict=X_cat_val, val_ranks=y_val, val_race_ids=race_ids_val, val_history_lengths=history_lengths_val,
sequence_length=sequence_length, batch_size=12, epochs=10, lstm_hidden=64,
collate_fn=grouped_race_collate_fn, class_weights=class_weights_tensor,
horse_ids=horse_ids_train, val_horse_ids=horse_ids_val,
model=emodel, device=device
)
torch.save(model.state_dict(), "transformer_model.pth")
- 学習関数には、前段で作った スタッキングモデル
emodel
を渡します。 - 学習内部(先に説明した関数):
- LSTM が各馬の履歴(T)を要約 → SetTransformer がレース内(S)の相互作用を学習。
- 損失は ペアワイズ順位 + Top-1 + nDCG@3 の合成(履歴に基づく重みの導入あり)。
- ReduceLROnPlateau(検証 nDCG@3 を監視)と EarlyStopping で過学習を抑制。
- 学習後は 重み(state_dict)を保存。以後の推論で再利用可。
5) 推論フロー(go=False の場合)
# 同一構造で再構築
model = StackingEnsembleRaceModel(...).to(device)
state_dict = torch.load("transformer_model.pth", map_location=device)
model.load_state_dict(state_dict)
model.eval()
- 学習時と同一構造(LSTM次元・埋め込み入出力次元・SetTransformer 設定)でモデルを再構築し、保存済み重みを読込。
eval()
にして推論モード(Dropout停止、LayerNorm推論挙動)。- 注意:**入出力の前処理(列順・スケーリング・カテゴリ写像)**が学習時と一致していることが前提です(
*info.json
,*maps.json
,scale_stats.json
等)。
6) 学習ロジックの意図(要点)
- 多様性×学習的結合:2系統の自己注意モデルを 学習ヘッドで統合し、分散低減と頑健性を獲得。
- 不均衡耐性:
class_weights
による Top-1 の重み補正で、希少な勝者パターンの学習を助ける。 - 実運用指標整合:
nDCG@3
の組み込みで 上位重視の価値関数に合わせて最適化。 - 再現性:前処理の列順・スケール・カテゴリ辞書を保存/共有し、学習・推論の一貫性を担保。
代表的な変数の意味
input_dim
:数値入力チャネル数(LSTMへ入る前のD)。class_weights_tensor
:Top-1 損失で使うクラス重み(サイズ=6想定)。model_self_attn
/model_set_transformer
:構成違いの 基礎モデル。emodel
:2モデルを統合する スタッキング・アンサンブル。go
:True=学習→保存、False=再構築→読込→推論。sequence_length, batch_size, epochs, lstm_hidden
:主要ハイパーパラメータ。
コメント