σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyロードマップ
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップ
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python ロードマップ›モジュール 11 · 本番システムと最先端モデル›トピック 11.11·~1 時間 30 分エキスパート

予測のためのニューラルネットワーク

ロードマップ上の位置モジュール 11/11 · トピック 11/13
11.11 予測のためのニューラルネットワーク
—ラボスコア— / 100合計XP—連続日数—

つまみのある関数と、それを回す方法

ニューラルネットワークは、重みと呼ばれる調整可能な多数の数を持つ関数にすぎません。1つの層は入力に重み行列を掛けてバイアスを足し、ReLU(max(x, 0))のような非線形関数を適用して、結果を次の層に渡します。このように重ねると、非常に複雑な関係を近似できます。学習とは、予測が既知の目標に合うように重みを選ぶことです。ずれを損失(数値の予測では平均二乗誤差)で測り、各重みに対して損失がどう変わるかを計算し、損失が下がる方向に各重みを少し動かします。この動かし方を何千回も繰り返すのが勾配降下法です。

# A one-hidden-layer network: relu(x @ w1 + b1) @ w2 + b2
import numpy as np

def relu(x):
    return np.maximum(x, 0.0)

def mlp_forward(x, w1, b1, w2, b2):
    return relu(x @ w1 + b1) @ w2 + b2

x = np.array([[1.0, 2.0], [0.5, -1.0]])                       # two samples, two features
w1 = np.array([[1.0, -1.0], [0.5, 1.0]])                      # two hidden units
b1 = np.array([0.0, 0.5])
w2 = np.array([1.0, 2.0])
print(relu(np.array([-1.5, 0.0, 2.0])))                       # [0. 0. 2.]
print(mlp_forward(x, w1, b1, w2, 0.1))                        # [5.1 0.1]   a prediction for each sample; the second sample's hidden values are switched off by the relu

最も単純なモデルでの勾配降下法

ネットワークの学習では勾配を得るのに誤差逆伝播法を使いますが、考え方は線形モデル y ~ x @ w + b ですでに完結しています。平均二乗誤差の勾配は、w については 2/n * x.T @ err、b については 2 * mean(err) です(err = 予測 - 目標)。ゼロから始め、学習率×勾配を引き、繰り返します。学習率が大きすぎると行き過ぎて発散し、小さすぎると進みません。先に特徴量を標準化(平均0、分散1)して、1つの学習率がすべてに合うようにします。PyTorch のようなライブラリは勾配を自動で計算しますが、行っているのはまさにこのループです。

# Gradient descent on a line: start at zero and walk downhill on the mean squared error
import numpy as np

def mse_loss(pred, target):
    return float(np.mean((pred - target) ** 2))

def train_linear(x, y, lr, epochs):
    n, d = x.shape
    w, b = np.zeros(d), 0.0
    for _ in range(epochs):
        err = x @ w + b - y
        w = w - lr * 2 / n * x.T @ err
        b = b - lr * 2 * float(np.mean(err))
    return w, float(b)

x = np.array([[0.0], [1.0], [2.0], [3.0]])
y = np.array([1.0, 3.0, 5.0, 7.0])                          # exactly y = 2x + 1
for epochs in (0, 10, 2000):
    w, b = train_linear(x, y, 0.05, epochs)
    print(epochs, np.round(w, 3), round(b, 3), round(mse_loss(x @ w + b, y), 6))
# 0 [0.] 0.0 21.0          the zero start
# 10 [2.009] 0.958 0.00092   already close
# 2000 [2.] 1.0 0.0          the line y = 2x + 1 is found

ネットワークにとってリターン予測が難しい理由

ネットワークはほとんど何にでもフィットでき、それが金融データでは危険です。リターンの大半はノイズなので、柔軟なモデルは学習期間のノイズを記憶し、次の期間では外れます。過剰適合は、学習誤差が未見のデータの誤差よりはるかに小さいことに現れます。対策はこれまでのトピックと同じです。単純なベースライン(線形モデルや、ゼロを予測すること)と比べる。時間をシャッフルせず、ウォークフォワード検証で後の時期のデータだけで評価する。特徴量は少なく、ネットワークは小さくする。正則化(重み減衰、ドロップアウト)と早期終了を加える。異なるシードで始めた複数のネットワークを平均する。サンプル外で線形ベースラインに明確に勝てなければ、線形モデルを使いましょう。

# Overfitting in miniature: a flexible fit to pure noise looks great in-sample and useless afterwards
import numpy as np

rng = np.random.default_rng(5)
x_train, x_test = rng.normal(size=(30, 12)), rng.normal(size=(1000, 12))      # 12 features that mean nothing
y_train, y_test = rng.normal(0, 0.01, size=30), rng.normal(0, 0.01, size=1000)  # next-day returns: pure noise

w = np.linalg.lstsq(x_train, y_train, rcond=None)[0]                          # a model with 12 free weights fitted to 30 points
train_mse = np.mean((x_train @ w - y_train) ** 2)
test_mse = np.mean((x_test @ w - y_test) ** 2)
baseline_mse = np.mean(y_test ** 2)                                           # predict zero
print(train_mse < baseline_mse, test_mse > baseline_mse)                      # True True   better in-sample, worse than zero out of sample
# The learning rate matters: a small one settles, one that is too large overshoots and the error blows up
import numpy as np

x = np.array([[1.0], [2.0], [3.0]])
y = np.array([2.0, 4.0, 6.0])

def final_errors(lr, epochs):
    w, b, errors = np.zeros(1), 0.0, []
    for _ in range(epochs):
        err = x @ w + b - y
        errors.append(float(np.mean(err ** 2)))
        w = w - lr * 2 / len(y) * x.T @ err
        b = b - lr * 2 * float(np.mean(err))
    return errors

small, large = final_errors(0.05, 30), final_errors(0.5, 30)
print(small[-1] < small[0])                          # True   the error shrinks
print(large[-1] > 1000 * large[0])                   # True   the error explodes: the steps are too big
まず退屈なベースラインからどのネットワークよりも先に、同じ特徴量で線形モデルを当てはめ、そのサンプル外誤差を「超えるべき数字」として残しておきます。ニューラルネットの学習は乱数を使い、実行ごとに結果が変わるので、各実行のシード、データ期間、ハイパーパラメータを記録します。特徴量のスケーリングは学習期間の統計だけで行い、全サンプルの統計は使わないでください。未来が漏れます。そして、予測の優位性が小さくても、取引コストのほうが大きければ価値はありません。
  • 層は relu(x @ w + b)、ネットワークは層を重ねたもので、損失(予測では平均二乗誤差)が予測と目標の距離を測る
  • 学習は勾配降下法。線形モデルでは w -= lr * 2/n * x.T @ err、b -= lr * 2 * mean(err)。特徴量をスケーリングし、学習率を調整する
  • リターンの大半はノイズ。線形ベースラインと比べ、ウォークフォワードで検証し、正則化した小さなネットワークを使い、サンプル外の利益が消えたら止める

次はトレーディングのための強化学習です。ラベル付きの答えではなく、報酬から方策を学習します。

ラボ:採点される内容

  • relu で負の値を切り捨てる25点
  • mlp_forward でネットワークを順伝播させる25点
  • mse_loss で誤差を測る25点
  • train_linear で降下しながら学習する25点
エクスプローラー · lab-140-1
▾ lab-140-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-140-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-140-1 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ

コードを実行するにはログインしてください。

レクチャーはすべて無料で読めます。コードの実行、テスト、ラボの提出にはアカウントの作成かログインが必要です。

  • ブラウザ内IDEとbashターミナル。インストール不要
  • 即時採点、XP、ロードマップでの現在地
アカウントを作成ログイン
または
GitHubで続ける