状態空間モデルとTransformer
長い系列を扱うとき、状態空間モデル(SSM)とTransformerは異なる計算原理で情報を集約します。ここでは両者の挙動差を小さい系列で確認します。
長い系列をどう覚えるかで、モデルの性格は変わる
SSM は内部状態を更新しながら過去を畳み込み、Transformer は自己注意で必要な位置を直接見にいきます。どちらも系列を読む方法ですが、情報の溜め方と取り出し方がかなり違います。
ここでは小さな系列に遠く離れたイベントを埋め込み、二つの流儀がその影響をどの程度追えるかを比べます。見たいのは性能順位ではなく、長距離依存に対する考え方の違いです。
逐次更新と直接参照
SSM は『いま持っている状態に過去を圧縮して持つ』設計で、Transformer は『必要なら過去の特定位置を見直す』設計です。系列長が伸びたときの計算の形も、そこで大きく変わります。
この notebook の見どころ
x[5] と x[25] に仕込んだイベントが、SSM 風の更新と Transformer 風の集約でどう扱われるかを MSE と系列の形で見ます。
ここでの Transformer 側は学習済み attention の完全実装ではなく、考え方を模した簡略代理です。だから数値の勝敗より、『どの仕組みで遠い情報を拾っているか』に注目してください。
比較で読みたいのは性能表ではない
MSE の差だけを見るとランキングの話に流れがちですが、この notebook の主題はそこではありません。更新コスト、長距離依存、系列長への向き合い方を比べるための教材です。
読み方の軸
長い系列で効くモデルを一つ選ぶ話ではなく、『内部状態に蓄えるか、注意で取りにいくか』という二つの発想を整理するつもりで進めてください。
長距離依存を含む系列を作る
まずは遠く離れた位置のイベントが後段に効くような系列を用意し、比較の土台を作ります。
import numpy as np
np.random.seed(2)
T = 40
x = np.zeros(T)
x[5] = 1.0
x[25] = 0.8 # 長距離イベント
y_target = np.zeros(T)
for t in range(1, T):
y_target[t] = 0.7 * y_target[t - 1] + x[t]
二つの集約のしかたを並べる
次に、逐次更新型と注意型で同じ系列を読み、どこで情報の拾い方が変わるかを見ます。
# SSM: h_t = a h_{t-1} + b x_t, y_t = c h_t
a, b, c = 0.8, 1.0, 1.0
h = 0.0
y_ssm = np.zeros(T)
for t in range(T):
h = a * h + b * x[t]
y_ssm[t] = c * h
# Transformer風: 位置に依存した自己注意で過去を加重平均
idx = np.arange(T)
y_attn = np.zeros(T)
for t in range(T):
past = x[: t + 1]
dist = (t - idx[: t + 1]).astype(float)
score = -0.15 * dist # 近いほど重い単純な注意
w = np.exp(score - score.max())
w /= w.sum()
y_attn[t] = np.dot(w, past)
mse_ssm = np.mean((y_ssm - y_target) ** 2)
mse_attn = np.mean((y_attn - y_target) ** 2)
print('SSM-like MSE =', round(mse_ssm, 6))
print('Transformer-like MSE=', round(mse_attn, 6))
SSM は更新コストの軽さに、Transformer は直接参照のしやすさに強みがあります。この notebook の比較は、その設計差を手触りとして掴むためのものです。