[機械学習・進化計算による株式取引最適化] No.07-02 モデルと配列変換

このプログラムの目的

このプログラムの目的は,PytorchのネットワークとGAの配列の相互変換を実装することです.

進化計算とニューラルネットワークを組みわせた手法は様々なものが存在します.
これらの総称をNeuro-Evolutionと呼びますが,今回はニューラルネットワークの重みを実数値GAにて最適化するという単純な方法をとります.

この方法の利点は以下の通りです.

  • 単純なため実装が簡単
  • Pytorch等のネットワークへの変換が容易なため,GPU利用がしやすい
work_share
├07_evolutionary_algorithms
  ├Dockerfile
  ├docker-compose.yml
  └src
    └neuro_evolution_torch
      ├torch_model.py (これを作成)
      ├simulation_cython.pyx
      └setup.py

使用ライブラリ

import torch
from torch import nn
import numpy as np

ネットワーク定義

入力層,隠れ層,出力層の3層ネットワークです.
あまり複雑にするとGAでの最適化が困難であると考え,最も簡易な構造にしました.

単純すぎると思った場合は自分でカスタマイズしてください.

また,強化学習の時にはネットワークの入力値に,銘柄保有比率や総資産・現金等の環境の状態を入力していました.しかし,これらの入力値は出力に与える影響が少なく,使用しないことで,入力に対する並列計算が可能になるため,今回は利用しないことにしました.

class Neural_Network_3layer(nn.Module):
    def __init__(self, input_dim, output_dim, hidden_dim):
        super(Neural_Network_3layer, self).__init__()
        self.net = torch.nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.Sigmoid(),
            nn.Linear(hidden_dim, output_dim),
            nn.Softmax()
        )
    def forward(self, x):
        return self.net(x)

重み行列と一次元配列の相互変換

モデルから一次元配列へ変換する場合.この関数は遺伝子長決定の時に利用する.

def model_w_to_vec(model):
    vec = []
    for key, tensor in model.state_dict().items():
        vec.append(tensor.view(-1))

    vec = torch.cat(vec)
    return vec.to('cpu').detach()

モデルの重みを与えた一次元配列で書き換える.

def vec_to_model_w(model, vec):
    s = 0
    new_state_dict = {}
    for key, tensor in model.state_dict().items():
        e = tensor.view(-1).shape[0]
        if len(tensor.shape) == 1:
            new_state_dict[key] = vec[s:s+e]
        if len(tensor.shape) == 2:
            new_state_dict[key] = vec[s:s+e].view(tensor.shape[0], tensor.shape[1])
        s += e
    model.load_state_dict(new_state_dict)
    return model

ネットワークの実行

モデルとベクトル(遺伝子),入力値を渡したら,実行結果(P)を返します.実行結果(P)は各銘柄の保有比率であり,銘柄数×日数の行列です.

def model_calculate(model, vec, X, device='cpu', to_numpy=True):
    torch_device = torch.device(device)
    if device == 'cuda' and X.is_cuda == False:
        X = X.to(torch_device)
    model = vec_to_model_w(model, vec)
    model.to(torch_device)
    out = model(X)
    if to_numpy:
        out = out.to('cpu').detach().numpy().astype(np.float64)
    else:
        out = out.to('cpu').detach()
    return out
タイトルとURLをコピーしました