Digital Reactor
機械学習

時系列データの予測:LSTMとTransformerの性能比較

時系列データの予測:LSTMとTransformerの性能比較

はじめに

売上や需要の予測に深層学習を使うと決めたとき、最初に迷うのがLSTM (Long Short-Term Memory) とTransformerのどちらを選ぶかです。どちらも時系列予測の定番ですが、得意とする条件が違います。そこで同じ人工データに対して両モデルをPyTorchで実装・学習し、予測精度と計算時間を測りました。先に結果に触れると、今回のデータでは予測精度はTransformerが上回った一方、計算時間はLSTMの3倍以上かかりました。この差がどこから来るのか、実務でどう使い分けるのかを整理します。

対象読者:

  • 深層学習を用いた時系列データ分析に興味がある方
  • LSTMとTransformerの実装方法と性能差を知りたい方
  • 実務で時系列予測モデルの選定に悩んでいる方

記事のポイント:

  • LSTMとTransformerの理論的な違いを、数式を交えて解説
  • PyTorchによる具体的な実装例を提示
  • 人工データを用いた実験による、予測精度と計算時間の比較
  • 実務での応用例とモデル選択の指針を整理

LSTMとTransformerの仕組み

時系列予測は、過去のデータのパターンから未来の値を推定するタスクです。ARIMAに代表される統計モデルに対して、深層学習モデルには、非線形な関係を表現できる、長期的な依存関係を捉えられる、複数の特徴量を同時に扱えるという利点があります。その深層学習のなかで対照的な設計を持つのが、LSTMとTransformerです。

LSTM(Long Short-Term Memory)

LSTMは、RNN (Recurrent Neural Network) の一種で、時系列データの処理に向いた構造を持ちます。RNNは過去の情報を内部状態として持ち越すことで系列データを扱えますが、系列が長くなると勾配消失が起き、遠い過去の情報を学習に反映できなくなります。

LSTMはこの問題に対処するため、長期記憶を保持するセル状態と、情報の流れを制御するゲート機構を備えています。ゲートは3種類あり、入力ゲートが新しい情報をセル状態に加えるか、忘却ゲートが不要になった情報を捨てるか、出力ゲートがセル状態から何を出力するかを、それぞれ決めます。この仕組みによって、長い系列でも過去のパターンを保持したまま学習を進められます。

Transformer

Transformerは、2017年にGoogleの研究者らが機械翻訳のために提案したモデルで、時系列データへの応用も進んでいます。RNNのように系列を先頭から順に処理するのではなく、自己注意機構 (Self-Attention) で系列内の任意の位置どうしの関係を直接捉えます。逐次処理がないぶん並列計算と相性がよく、学習を高速化しやすい構造です。

自己注意機構は、以下の式で表されます。

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

ここで Q (Query) は情報を取得するためのクエリ、K (Key) はクエリと照合するためのキー、V (Value) は実際に取得する値、d_k はキーの次元数(スケーリング係数)です。この機構によって、系列のどこにある要素とでも直接関係を結べるため、離れた時点どうしの依存関係を学習しやすくなります。

なお、自己注意機構自体は要素の並び順を区別しないため、Transformerは位置エンコーディングで系列内の位置情報をモデルに与えます。

正弦波データで両モデルを比較する

条件を揃えるため、同じ人工データに対してLSTMとTransformerをPyTorchで実装し、予測精度と計算時間を測ります。

複数周期の正弦波を合成する

複数の周期を持つ正弦波にノイズを加えた人工データを生成します。

def generate_data(n_samples=1000):
    t = np.linspace(0, 100, n_samples)
    # 複数の周期の正弦波を組み合わせる
    y = (np.sin(0.02 * t) + 0.5 * np.sin(0.05 * t) + 
         0.3 * np.sin(0.2 * t) + np.random.normal(0, 0.01, n_samples))
    return t, y

周期の異なる3つの正弦波を合成し、ガウシアンノイズを加えています。時間スケールの異なる変動が重なったデータにすることで、短期のパターンと長期のパターンの両方を学習する必要がある状況を作っています。

系列を学習用に切り出す

PyTorchのDatasetクラスを継承し、時系列データ用のカスタムデータセットを作成します。

class TimeSeriesDataset(Dataset):
    def __init__(self, data, seq_length, target_length):
        self.data = torch.FloatTensor(data)
        self.seq_length = seq_length
        self.target_length = target_length

    def __len__(self):
        return len(self.data) - self.seq_length - self.target_length + 1

    def __getitem__(self, idx):
        x = self.data[idx:idx + self.seq_length]
        y = self.data[idx + self.seq_length:
                     idx + self.seq_length + self.target_length]
        return x, y

このクラスは、入力系列長(seq_length)と予測対象の長さ(target_length)を指定して、時系列データを学習用のミニバッチに分割します。

モデルの実装

LSTMモデル

class LSTMPredictor(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size):
        super().__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, 
                           batch_first=True)
        self.linear = nn.Linear(hidden_size, output_size)

    def forward__(self, x):
        lstm_out, _ = self.lstm(x)
        predictions = self.linear(lstm_out[:, -1, :])
        return predictions

LSTMモデルは、入力系列を受け取り、LSTM層で隠れ状態を更新しながら時系列パターンを学習します。batch_first=Trueは、入力データの形状を(バッチサイズ, 系列長, 特徴量数)とするための指定です。最後の時点の隠れ状態を線形層に通して、将来の値を予測します。

Transformerモデル

class TransformerPredictor(nn.Module):
    def __init__(self, input_size, d_model, nhead, num_layers, output_size):
        super().__init__()
        self.embedding = nn.Linear(input_size, d_model)
        encoder_layer = nn.TransformerEncoderLayer(d_model, nhead, 
                                                 batch_first=True)
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
        self.linear = nn.Linear(d_model, output_size)

    def forward__(self, x):
        x = self.embedding(x)
        transformer_out = self.transformer(x)
        predictions = self.linear(transformer_out[:, -1, :])
        return predictions

Transformerモデルは、まず線形層で入力を高次元空間に埋め込みます。その後、TransformerEncoderで自己注意機構を用いて系列内の関係性を学習します。d_modelは埋め込み次元、nheadはアテンションヘッドの数、num_layersはエンコーダ層の数です。LSTMと同様に、最後の時点の出力を線形層に通して予測を行います。

精度はTransformer、速度はLSTMが上回る

実験では、以下の設定でモデルを学習・評価しました。

  • 入力系列長: 200
  • 予測長: 50
  • 隠れ層のサイズ (LSTM): 64
  • 埋め込み次元 (Transformer): 64
  • アテンションヘッド数 (Transformer): 4
  • 層の数 (LSTM, Transformer): 2
  • 最適化アルゴリズム: Adam
  • 学習率: 0.001
  • エポック数: 50

実験結果は以下の通りです。

モデル訓練損失テストデータMSE計算時間 (秒)
LSTM0.00090.001190.47
Transformer0.00220.0006337.73

テストMSEはTransformerのほうが低く、今回のデータでは予測精度で上回りました。複数の周期を重ねたデータでは離れた時点どうしの関係が予測の手がかりになり、それを自己注意機構が直接参照できたためと考えられます。ただしこれはあくまで今回のデータセットでの結果で、データが変わればこの傾向が逆転することもあります。

計算時間はTransformerのほうが長く、LSTMの3倍を超えました。自己注意機構の計算量が系列長に対して二乗で増加するためです。

実務でどちらを選ぶか

LSTMとTransformerは、小売業の商品需要予測、製造ラインのセンサーデータを使った異常検知、株価や為替レートの予測、電力需要の予測など、幅広い時系列タスクに使えます。どちらを選ぶかは、扱う系列の長さと使える計算資源でおおよそ決まります。目安を表にまとめます。

観点LSTMTransformer
系列の長さ短い系列で十分な性能が出る長い系列ほど強みが出る
計算資源少ない計算資源で学習できる学習に多くの計算資源を使う
リアルタイム性計算コストが低く、リアルタイム処理に組み込みやすい計算コストが高く、そのまま載せるには工夫がいる
データの複雑さ単純な周期パターンの学習に向く複雑なパターンや長期の依存関係の学習に向く

モデル選定の相談を受けたときは、精度の話に入る前に、推論をどの頻度で回すか、再学習をどの周期で行うかを先に確認します。毎分単位の推論や頻繁な再学習が前提なら、計算コストの低いLSTMを基準に据え、系列が長く精度が頭打ちになった段階でTransformerを検討する、という順番に落ち着くことが多いです。

まとめ

同じ正弦波データで比べた結果、テストMSEはTransformerがLSTMの約半分、計算時間は3倍以上という、精度と速度のはっきりしたトレードオフが観測されました。ただしこれは、離れた時点の参照が予測に生きる複数周期の合成波という、自己注意機構に有利な設定での結果です。手元のタスクでどちらを使うか迷っているなら、まずLSTMか単純な統計モデルで精度と計算時間の基準を取り、精度が足りないと分かった段階でTransformerを試すのが手戻りの少ない進め方です。その際は精度だけでなく、系列長を伸ばしたときに計算時間がどう増えるかも併せて測ってください。

関連記事

← 技術ブログ一覧へ