Bot 機械学習・データサイエンス

開発記録#117(2024/10/21)MMbot開発「LSTMとの組み合わせ6種」

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

今回は「LSTMとの組み合わせのアイデア」を考えて、簡単なコードの雛形をまとめました。

Yodaka

この記事では、LSTMと組み合わせた時に優位な効果を発揮しそうなアプローチを6種類まとめました。

試したい組み合わせ

・Proximal Policy Optimization (PPO)
・Genetic Algorithms (GA)
・Gaussian Processes (GP)
・Asynchronous Advantage Actor-Critic (A3C)
・Bagging and Boosting
・Multi-task Learning

Proximal Policy Optimization (PPO)

以下は、Proximal Policy Optimization (PPO) とLSTMを組み合わせて使用するためのPythonコードの例です。このコードは、仮想通貨のトレーディングにおけるPPOエージェントを構築し、LSTMネットワークを使用して市場の時系列データを処理する方法を示しています。

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import LSTM, Dense, Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import gym

class PPOAgent:
    def __init__(self, state_size, action_size):
        self.state_size = state_size
        self.action_size = action_size
        self.gamma = 0.99
        self.learning_rate = 0.00025
        self.actor, self.critic = self.build_models()

    def build_models(self):
        # Actor model
        state_input = Input(shape=(self.state_size, 1))
        x = LSTM(64, return_sequences=True)(state_input)
        x = LSTM(32)(x)
        x = Dense(24, activation='relu')(x)
        action_output = Dense(self.action_size, activation='softmax')(x)

        actor = Model(inputs=state_input, outputs=action_output)
        actor.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=self.learning_rate))

        # Critic model
        x = LSTM(64, return_sequences=True)(state_input)
        x = LSTM(32)(x)
        x = Dense(24, activation='relu')(x)
        value_output = Dense(1, activation='linear')(x)

        critic = Model(inputs=state_input, outputs=value_output)
        critic.compile(loss='mse', optimizer=Adam(learning_rate=self.learning_rate))

        return actor, critic

    def act(self, state):
        state = state.reshape((1, self.state_size, 1))
        probabilities = self.actor.predict(state)[0]
        action = np.random.choice(self.action_size, p=probabilities)
        return action

    def train(self, state, action, reward, next_state, done):
        state = state.reshape((1, self.state_size, 1))
        next_state = next_state.reshape((1, self.state_size, 1))
        action_onehot = np.zeros(self.action_size)
        action_onehot[action] = 1

        # Update critic
        target = reward + self.gamma * self.critic.predict(next_state) * (1 - int(done))
        self.critic.train_on_batch(state, target)

        # Update actor
        advantages = target - self.critic.predict(state)
        self.actor.fit(state, action_onehot, sample_weight=advantages, verbose=0)

# Create a simple environment
env = gym.make('CartPole-v1')
state_size = env.observation_space.shape[0]
action_size = env.action_space.n

# Initialize PPO agent
agent = PPOAgent(state_size, action_size)

# Training loop
episodes = 1000
for e in range(episodes):
    state = env.reset()
    total_reward = 0
    done = False
    while not done:
        action = agent.act(state)
        next_state, reward, done, _ = env.step(action)
        agent.train(state, action, reward, next_state, done)
        state = next_state
        total_reward += reward
    print(f'Episode: {e+1}, Total Reward: {total_reward}')

このコードは、環境としてOpenAI Gymの CartPole-v1 を使用していますが、仮想通貨取引のためには独自の市場データと環境を設定する必要があります。LSTMレイヤーを使用することで、時系列データの特性を捉え、PPOアルゴリズムを通じて効果的にポリシーを学習します。この組み合わせにより、市場の時間依存性を理解し、より良い取引判断を行うことが可能です。

Genetic Algorithms, GA

遺伝的アルゴリズム(Genetic Algorithms, GA)を使用してLSTMの構造やハイパーパラメータを最適化するアプローチをPythonで実装するコード例を提供します。ここでは、遺伝的アルゴリズムを用いてLSTMの隠れ層の数やニューロンの数、学習率などのパラメータを進化させ、最も効果的なモデル構造を見つける方法を示します。

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from tensorflow.keras.optimizers import Adam
from deap import base, creator, tools, algorithms
import random

# 適応度関数の定義
def evaluate_model(individual):
    # ハイパーパラメータの展開
    num_units, learning_rate = individual
    
    # モデルの構築
    model = Sequential([
        LSTM(units=int(num_units), input_shape=(None, 1)),
        Dense(1, activation='sigmoid')
    ])
    
    # モデルのコンパイル
    optimizer = Adam(learning_rate=learning_rate)
    model.compile(optimizer=optimizer, loss='mse')
    
    # 仮想通貨のデータに基づく訓練データを用意する部分が必要
    # ここではプレースホルダーとしてランダムデータを使用
    data = np.random.rand(100, 10, 1)
    target = np.random.rand(100, 1)
    
    # モデルの訓練
    model.fit(data, target, epochs=5, verbose=0)
    
    # 性能評価(ここでは仮に損失を返す)
    loss = model.evaluate(data, target, verbose=0)
    return (loss,)

# 遺伝的アルゴリズムの設定
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

toolbox = base.Toolbox()
toolbox.register("attr_num_units", random.randint, 50, 150)
toolbox.register("attr_learning_rate", random.uniform, 0.0001, 0.01)
toolbox.register("individual", tools.initCycle, creator.Individual, 
                 (toolbox.attr_num_units, toolbox.attr_learning_rate), n=1)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("evaluate", evaluate_model)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)

# 遺伝的アルゴリズムの実行
population = toolbox.population(n=50)
ngen = 40
result = algorithms.eaSimple(population, toolbox, cxpb=0.5, mutpb=0.2, ngen=ngen, verbose=True)

# 最終結果の出力
best_individual = tools.selBest(population, k=1)[0]
print('Best Model Parameters:', best_individual)
print('Best Fitness:', best_individual.fitness.values[0])

このコードでは、LSTMのハイパーパラメータを適応的に最適化するために遺伝的アルゴリズムを利用しています。GAはランダムに初期化された個体群からスタートし、交叉、突然変異、選択を繰り返しながら最適なパラメータを探索します。適応度はLSTMモデルの損失関数によって評価され、より低い損失を持つモデルが選択されやすくなります。

ガウス過程(Gaussian Processes, GP)

LSTMとガウス過程(Gaussian Processes, GP)を組み合わせたモデルは、時系列データの解析に強力な確率的モデリングを追加することで、予測の精度と不確実性の管理を改善します。以下は、Pythonを使用してこの組み合わせを実装する方法の一例です。

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import LSTM, Dense, Input
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C

# データ生成(例としてランダムデータを使用)
def generate_data(num_samples):
    # 仮の時系列データ生成
    X = np.linspace(0, 50, num_samples)
    y = np.sin(X) + np.random.normal(0, 0.1, num_samples)
    X = X.reshape(-1, 1, 1)  # LSTMの入力に合わせた形状
    return X, y

# LSTMモデルの構築
def build_lstm(input_shape):
    inputs = Input(shape=input_shape)
    x = LSTM(50, return_sequences=False)(inputs)
    x = Dense(20, activation='relu')(x)
    outputs = Dense(1)(x)
    model = Model(inputs=inputs, outputs=outputs)
    model.compile(optimizer='adam', loss='mse')
    return model

# LSTMモデルの訓練
def train_lstm(model, X, y):
    model.fit(X, y, epochs=10, verbose=0)

# ガウス過程モデルの訓練
def train_gp(X, y):
    kernel = C(1.0, (1e-4, 1e1)) * RBF(10, (1e-2, 1e2))
    gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10, alpha=0.1)
    gp.fit(X.squeeze(), y)  # LSTMからの出力を利用
    return gp

# 予測の実施
def predict(model, gp, X):
    lstm_predictions = model.predict(X)
    gp_predictions, sigma = gp.predict(lstm_predictions, return_std=True)
    return gp_predictions, sigma

# データの生成とモデルの訓練
X, y = generate_data(1000)
lstm_model = build_lstm((None, 1))
train_lstm(lstm_model, X, y)
gp_model = train_gp(X, lstm_model.predict(X))

# 予測の実行
predictions, uncertainties = predict(lstm_model, gp_model, X)

このアプローチの利点と機能

  • LSTM: LSTM層は時系列データの長期的依存関係を把握し、市場のダイナミックな特性をモデル化します。
  • ガウス過程: LSTMからの出力に基づいて、ガウス過程が確率的な予測を提供します。これにより、予測の不確実性が定量化され、リスク管理に役立ちます。
  • 組み合わせの優位性: LSTMが提供する詳細な特徴抽出とGPによる確率的モデリングの組み合わせにより、予測の精度と信頼性が向上します。

このコードは仮想通貨市場データに対してカスタマイズする必要がありますが、基本的なアーキテクチャとして機能します。実際の市場データを使用する際には、データの前処理、特徴量の選定、モデルのパラメータ調整に注意を払う必要があります。

Asynchronous Advantage Actor-Critic(A3C)

Asynchronous Advantage Actor-Critic(A3C)とLSTMを組み合わせることで、時系列データのパターンを学習しつつ、複数のエージェントが並列に動作することによるスケーラビリティと効率の向上を図ることができます。以下に、TensorFlowとKerasを使用してこのアプローチを実装するコードの概要を示します。

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, LSTM, Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import gym

# グローバルなネットワークの定義
def build_global_model(input_shape, action_size):
    inputs = Input(shape=input_shape)
    x = LSTM(64, return_sequences=True)(inputs)
    x = LSTM(64)(x)
    x = Dense(128, activation='relu')(x)
    policy = Dense(action_size, activation='softmax')(x)
    value = Dense(1, activation='linear')(x)
    model = Model(inputs=inputs, outputs=[policy, value])
    model.compile(optimizer=Adam(learning_rate=0.001), loss=['categorical_crossentropy', 'mse'])
    return model

# エージェントの定義
class A3CAgent:
    def __init__(self, state_size, action_size):
        self.state_size = state_size
        self.action_size = action_size
        self.global_model = build_global_model((None, state_size), action_size)
        self.opt = Adam(learning_rate=0.001)

    def act(self, state):
        policy, _ = self.global_model.predict(state)
        return np.random.choice(self.action_size, p=policy[0])

# エージェントの学習プロセス
def agent_learning_process(agent, env):
    state = env.reset()
    done = False
    while not done:
        action = agent.act(state)
        next_state, reward, done, _ = env.step(action)
        # ここで報酬と次の状態を使って学習を行います
        # LSTMを使用したモデルのアップデートなど

# 環境とエージェントの初期化
env = gym.make('CartPole-v1')
state_size = env.observation_space.shape[0]
action_size = env.action_space.n
agent = A3CAgent(state_size, action_size)

# 学習の実行
agent_learning_process(agent, env)

コードの説明

  • モデルの構築: LSTM層を使用して時系列データの依存関係を学習し、ポリシー出力層と価値出力層を持つネットワークを定義します。
  • エージェントクラス: A3Cのエージェントを実装し、グローバルモデルを共有しつつ、各エージェントが独立して行動選択と学習を行います。
  • 学習プロセス: エージェントが環境と対話しながら学習を進め、グローバルモデルを更新します。このサンプルでは、実際の市場データに基づいてカスタマイズする必要があります。

このアプローチにより、LSTMを活用して時系列データからの学習と、A3Cを通じた効率的な強化学習が可能となります。複数のエージェントが並列に学習を進めることで、より広範囲の市場シナリオに対応し、適応性と学習効率を高めることができます。

アンサンブル学習

LSTMとアンサンブル学習の組み合わせにより、特に時系列データに対して予測の安定性と精度を高めることができます。ここでは、バギングとブースティングをLSTMモデルに適用する方法をPythonコードで示します。

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from sklearn.ensemble import BaggingRegressor, AdaBoostRegressor
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error

# 仮想通貨データの代わりにランダムな時系列データを生成
np.random.seed(42)
data = np.sin(np.linspace(0, 20, 1000)) + np.random.normal(scale=0.5, size=1000)
data = data.reshape(-1, 1)

# データの正規化
scaler = MinMaxScaler(feature_range=(0, 1))
data = scaler.fit_transform(data)

# 時系列データのウィンドウ生成関数
def create_dataset(data, time_step=1):
    X, Y = [], []
    for i in range(len(data)-time_step-1):
        a = data[i:(i+time_step), 0]
        X.append(a)
        Y.append(data[i + time_step, 0])
    return np.array(X), np.array(Y)

time_step = 10
X, y = create_dataset(data, time_step)
X = X.reshape(X.shape[0], X.shape[1], 1)

def build_lstm_model(input_shape):
    model = Sequential([
        LSTM(50, input_shape=input_shape),
        Dense(1)
    ])
    model.compile(loss='mean_squared_error', optimizer='adam')
    return model

# バギングアンサンブルの設定
bagging_model = BaggingRegressor(
    base_estimator=build_lstm_model((time_step, 1)),
    n_estimators=10,  # 10個のLSTMモデルを使用
    random_state=42,
    verbose=1
)

# モデルの訓練
bagging_model.fit(X, y)

# ブースティングアンサンブルの設定
boosting_model = AdaBoostRegressor(
    base_estimator=build_lstm_model((time_step, 1)),
    n_estimators=10,  # 10個のLSTMモデルを逐次的に改善
    random_state=42,
    learning_rate=0.01
)

# モデルの訓練
boosting_model.fit(X, y)

コードの説明

  • データ生成と前処理: データを生成し、正規化してウィンドウ化することでLSTMが処理しやすい形式にします。
  • LSTMモデルの定義: 単一のLSTMレイヤーと出力層からなるシンプルなモデルを定義します。
  • バギング: 複数のLSTMモデルを独立して訓練し、それぞれが異なるデータサンプルに基づいて学習することで、全体の予測精度を向上させます。
  • ブースティング: 複数のLSTMモデルを逐次的に訓練し、前のモデルの誤差を次のモデルが修正することで、予測性能を徐々に向上させます。

このコードでは、実際に動作するためにはTensorFlowとKerasの互換性があるRegressorラッパーが必要です。実際の実装では、Kerasモデルをscikit-learnのアンサンブルメソッドに適合させるためのラッパーを用意する必要があります。これは、カスタムのラッパークラスを定義するか、既存のライブラリ(例えばkeras-wrappers)を使用することで対応可能です。

マルチタスク学習

LSTMとマルチタスク学習を組み合わせることで、複数の関連する出力(例えば、仮想通貨の価格と取引量)を同時に予測するモデルを構築できます。このアプローチは、異なる特徴間の隠れた相関を利用して、各タスクの予測性能を向上させる可能性があります。以下に、TensorFlowとKerasを用いてこのアプローチを実装する方法のサンプルコードを示します。

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, LSTM, Dense
from tensorflow.keras.optimizers import Adam

# 仮想通貨価格データと取引量データの生成
np.random.seed(0)
data_size = 1000
# 価格データ
prices = np.sin(np.linspace(-3 * np.pi, 3 * np.pi, data_size)) + np.random.normal(0, 0.1, data_size)
# 取引量データ
volumes = np.cos(np.linspace(-3 * np.pi, 3 * np.pi, data_size)) + np.random.normal(0, 0.1, data_size)

prices = prices.reshape(-1, 1)
volumes = volumes.reshape(-1, 1)

# データをLSTMに入力できる形に変形
def create_dataset(prices, volumes, time_steps=10):
    X, y_price, y_volume = [], [], []
    for i in range(len(prices) - time_steps):
        v = prices[i:(i + time_steps)]
        X.append(v)
        y_price.append(prices[i + time_steps])
        y_volume.append(volumes[i + time_steps])
    return np.array(X), np.array(y_price), np.array(y_volume)

X, y_price, y_volume = create_dataset(prices, volumes)

def build_multitask_lstm(input_shape):
    # 入力層
    input_layer = Input(shape=input_shape)
    
    # LSTM層
    lstm = LSTM(50, return_sequences=False)(input_layer)
    
    # 価格予測用出力層
    price_output = Dense(1, name='price_output')(lstm)
    
    # 取引量予測用出力層
    volume_output = Dense(1, name='volume_output')(lstm)
    
    # モデルの構築
    model = Model(inputs=input_layer, outputs=[price_output, volume_output])
    
    # モデルのコンパイル
    model.compile(optimizer=Adam(learning_rate=0.001),
                  loss={'price_output': 'mse', 'volume_output': 'mse'},
                  metrics={'price_output': 'mae', 'volume_output': 'mae'})
    return model

# モデルの生成と訓練
model = build_multitask_lstm((10, 1))
model.fit(X, [y_price, y_volume], epochs=50, batch_size=32, verbose=1)

コードの説明

  • データの生成: サイン関数とコサイン関数を使って仮想通貨の価格と取引量を生成し、時系列データとして処理するために整形します。
  • モデルの構築: 入力層からLSTM層を経て、価格と取引量の予測のための二つの異なる出力層にデータを流します。
  • モデルの訓練: 訓練データに基づき、価格と取引量の両方を同時に予測するようにモデルを訓練します。

このマルチタスク学習アプローチは、市場の異なる側面からの洞察を同時に得ることができ、予測の一貫性と精度を向上させることが期待されます。

まとめ

今回は「LSTMとの組み合わせ」を考えて6種類のコードの雛形をまとめました。

ここからこれらの実装と改良を行なって精度の高い予測モデルの構築に繋げていきます。

Yodaka

雛形を作ってみると、コードを構成パターンを理解できたり取引戦略の実際のリスクなどが見えてきます。

今後もこの調子で開発の状況を発信していきます。

-Bot, 機械学習・データサイエンス