Reservoir Computing · Algorithms

リザバーコンピューティングの種類を図解

― リング・スパイキング・蔵本・次世代RC。ESN以外の「状態のつくり方」―

リザバーコンピューティングはESN(エコーステートネットワーク)だけではありません。結合の作り方(ランダム/決定論的/物理)やノードの種類(連続値/スパイク/振動子)で多様な方式があります。本ページは代表的な方式を、仕組み・数式・コピペで動くPython・使いどころまで、共通の視点で図解します。

3行でわかる「リザバーコンピューティングの種類」

  1. リザバーはESNだけではない。結合の作り方(ランダム/決定論的/物理)とノードの種類(連続値/スパイク/振動子)で、多くの方式がある。
  2. どの方式も共通の型(入力を通す → 状態を集める → リッジ回帰1回)で作れる。違うのは「状態をつくる部分」だけ。
  3. 本ページはリング・スパイキング(LSM)・蔵本(結合振動子)・次世代RCを、仕組み・数式・コピペで動くPython・使いどころまで図解する。

NAVI Which method?

先に結論:目的別・方式の選び方

まず動かす・迷ったら

  • ESN:資料と実装が最も豊富。汎用の出発点(ESN解説
  • リング(SCR):乱数ゼロ・再現性重視・省メモリ
  • 次世代RC:少データで力学系・カオス予測

デバイス・用途が決まっている

  • 超低消費電力・脳型・イベント駆動 → スパイキング(LSM)
  • 光・電子回路・スピン素子で作る → 遅延線・結合振動子
  • 解釈性・乱数排除・軽量推論 → 次世代RC(NVAR)

まずは共通の型で1つ動かし、同じ検証条件で比べます。そのうえで、目的指標、遅延、消費電力、メモリ、デバイス要件に合わせて方式を決めます。

目次
  1. リザバー方式の全体像(マップ)
  2. すべてに共通する「作り方の型」
  3. リングリザバー(決定論的で最小)
  4. スパイキングリザバー(LSM)
  5. 蔵本モデル/結合振動子リザバー
  6. 次世代リザバー(NG-RC/NVAR)
  7. 物理リザバー方式(概観)
  8. どの方式を選ぶか
  9. よくある質問
  10. まとめ
  11. 参考文献・関連リンク

01 Landscape

リザバー方式の全体像 ― 2つの軸で整理する

方式は数多くありますが、2つの軸で見ると迷いません。ひとつは結合(つなぎ方)をどう作るか――乱数で作って固定するのか、環のように決定論的に設計するのか、物理系そのものに任せるのか。もうひとつはノード(部品)が何か――連続値のニューロンか、スパイク(発火)か、振動子か。この地図の上に、代表的な方式を置いてみます。

決定論的 構造を設計 ランダム/物理 系に任せる 連続値ノード スパイク/振動子 次世代RC 特徴量ベース リング(SCR) ESN 基準・最も普及 物理リザバー 光・電子・材料 スパイキング(LSM) 蔵本/結合振動子
図1:リザバー方式のマップ(模式図)。横軸は結合の作り方、縦軸はノードの種類。位置はおおまかな目安で、厳密な分類ではありません。次世代RCは動的なリザバーを持たず「時間遅れ+多項式特徴」で置き換える点が特殊です。

主要な方式の早見表

代表的なリザバー方式の比較
方式 ノードの種類 結合の作り方 学習するもの 際立つ長所 向く用途・実装例
ESN(基準) 連続値(tanh)乱数で作って固定読み出し層 資料・実装が最も豊富汎用の時系列予測・分類(ESN解説
リング(SCR) 連続値(tanh)決定論的な「1つの環」読み出し層 乱数ゼロ・再現性・省メモリ組込み・教育・ベースライン
遅延線 単一の非線形ノード遅延フィードバック(時間多重)読み出し層 物理系で超高速・省電力光・電子回路の物理リザバー
スパイキング(LSM) スパイク(LIF等)乱数で作って固定読み出し層 イベント駆動・脳型で低消費電力ニューロモルフィック・センサー
蔵本/結合振動子 位相・振幅の振動子平均場など(物理も可)読み出し層 物理振動子で実装・高速スピントルク・レーザー・MEMS
次世代RC(NVAR) (動的リザバーなし)時間遅れ+多項式特徴線形係数 少データ・解釈可能・乱数不要カオス予測・制御・軽量推論

表は各方式の際立つ長所をまとめたものです。最終判断では、同じデータ分割・評価指標で候補を比較してください。なお、このほかにもセルオートマトンを使うReCA、深層リザバー(Deep-ESN)など多くの派生があります。

02 Common Recipe

すべてに共通する「作り方の型」

方式が違っても、組み立て方はほとんど同じです。これが分かると「新しいリザバーも作れる」感覚がつかめます。共通の型はたった3ステップ。変わるのは真ん中の「状態をつくる部分」だけで、前後(入力を通す・状態を集める・読み出しを学習する)は全方式で共通です。

入力 u(t) センサー値など 状態をつくる部分 リング/スパイク/ 振動子/特徴量… ← ここだけ方式で変わる 状態を集める 行列 X リッジ回帰 学習はここだけ (1回) 出力 y(t) 作ったら固定(学習しない) 唯一の学習対象
図2:リザバー計算に共通する処理の流れ。オレンジの破線部分(状態をつくる部分)だけが方式で入れ替わり、その前後は全方式で共通です。

「状態を集めて、リッジ回帰で読み出しを学習する」部分は、方式によらず次の数行に集約できます。以降の各方式のコードは、この関数を共通の仕上げとして使っています。

readout.py 全方式で共通の「読み出し学習」
import numpy as np

# 状態 X(各行が時刻ごとの状態ベクトル)と教師 d から読み出し重みを1回で求める
def train_readout(X, d, beta=1e-6):
    """X:(T,N)  d:(T,)  beta:正則化係数"""
    N = X.shape[1]
    W_out = np.linalg.solve(X.T @ X + beta * np.eye(N), X.T @ d)   # リッジ回帰の閉形式
    return W_out                                                  # 予測は X @ W_out
POINTどの方式もここは同じ。違うのは「Xの作り方」だけ。

なぜ読み出しだけの学習でうまくいくのか

リザバーが入力の履歴を高次元の状態へ「豊かに」写していれば、目的の出力はその状態の線形和で近似できることが多いためです。深く知りたい場合は親ページの「なぜ固定したリザバーで機能するのか」と、ESN解説の「学習はリッジ回帰1回」をご覧ください。

03–06 Methods

方式カタログ ― 4つを図解&実装

ここからは代表的な4方式を、仕組み → 数式 → コピペで動くPython → 図で確認 → 使いどころの順で見ていきます。気になる方式へジャンプできます。

03 Ring Reservoir

リングリザバー(Simple Cycle Reservoir)

ノード:連続値(tanh) 実装難易度:やさしい ひとことで:乱数を使わない最小リザバー

ESNは内部結合を乱数で作りますが、「本当にランダムでなければダメなのか?」という問いから生まれたのがリングリザバーです。ノードを一列に並べて端と端をつなぎ、1つの環(サイクル)にする。結合の強さは全部同じ、入力の重みも大きさは共通で符号だけ変える。本実装では符号をπの小数桁から決めるため、内部結合から入力重みまで乱数を使わない完全に決定論的な構成です。それでも、多くのタスクでランダムESNとほぼ同等の精度が出ることが知られています(Rodan & Tiňo, 2011)。

イメージは「一方向の水路」です。各ノードはすぐ隣(1つ前)のノードの状態を受け取り、そこへ今の入力を少し混ぜて非線形変換する。情報は環に沿ってぐるりと巡りながら少しずつ薄まっていく――これが記憶になります。

この方式の要点

提案
Rodan & Tiňo (2011)
結合
決定論的な1つの環のみ
入力
大きさ共通・符号だけ固定
強み
乱数ゼロ/再現性/省メモリ
調整
入力符号・結合強度・複数リング
リング(決定論的) 隣から1つ受け取るだけ ランダム(ESN) 乱数で多数の結合
図3:構造の違い。リングは「1つの環」だけの決定論的な結合、ESNは乱数で作った多数の結合。にもかかわらず精度は近い(下の図5)。

数式:ESNの状態更新を「環」に置き換えるだけ

x(t+1) = tanh( v si u(t) + r x(1つ隣)(t) )
  • v si u(t):入力。大きさvは全ノード共通、符号siだけ固定パターンで変える。
  • r x(1つ隣):環に沿って1つ前のノードの状態を強さrで受け取る=記憶。コードでは np.roll(x, 1)
  • tanh(・):非線形変換。ESNと同じ。

比べてみると、ESNの状態更新式の「乱数の再帰結合 W x」を「環の隣 r x(1つ隣)」に置き換えただけだと分かります。ここでr はスペクトル半径そのもの(環の重みが全部 r なので)で、記憶の長さを決めるつまみになります。

Python実装 ― NumPyだけ、約40行

環は np.roll(x, 1) の1行で表現できます。入力符号はπの小数桁から決めるので、乱数なしで毎回同じ構成になります。python ring.py で動き、図5はこのコードの実測です。仕上げの読み出しは共通の型と同じリッジ回帰1回です。

ring.py Python 3・NumPyのみ
import numpy as np

# ---------- 1. データ:Mackey-Glass 時系列 ----------
def mackey_glass(n, tau=17):
    x = np.full(n + tau, 1.2)
    for t in range(tau, n + tau - 1):
        x[t + 1] = x[t] + 0.2 * x[t - tau] / (1 + x[t - tau] ** 10) - 0.1 * x[t]
    return x[tau:]

data = mackey_glass(4000)
n_train = 3000
mu, sd = data[:n_train].mean(), data[:n_train].std()
data = (data - mu) / sd                       # 学習区間の統計だけで標準化
u, d = data[:-1], data[1:]                    # 入力=現在値、教師=1ステップ先

# ---------- 2. リング(環)を作る:これだけ ----------
N       = 200        # ノード数
r       = 0.9        # 環に沿った1つの結合強度(=スペクトル半径そのもの)
v       = 0.1        # 入力の大きさ(全ノード共通)
beta    = 1e-8       # リッジ回帰の正則化係数
washout = 200

pi_digits = (
    "14159265358979323846264338327950288419716939937510"
    "58209749445923078164062862089986280348253421170679"
    "82148086513282306647093844609550582231725359408128"
    "48111745028410270193852110555964462294895493038196"
    "44288109756659334461284756482337867831652712019091"
    "45648566923460348610454326648213393607260249141273"
    "72458700660631558817488152092096282925409171536436"
    "78925903600113305305488204665213841469519415116094"
)
signs = np.array([1.0 if c >= "5" else -1.0 for c in pi_digits[:N]])  # πの小数桁で決定
W_in  = v * signs    # 入力重み:大きさは共通、符号パターンのみ

# ---------- 3. 状態を集める(環に沿って前のノードの値を1つ受け取る) ----------
T = len(u)
X = np.zeros((T, N + 1))                       # 先頭列はバイアス
x = np.zeros(N)
for t in range(T):
    x = np.tanh(W_in * u[t] + r * np.roll(x, 1))  # np.roll(x,1) が「環の1つ隣」
    X[t, 0] = 1.0
    X[t, 1:] = x

# ---------- 4. 読み出し層をリッジ回帰で学習(他方式と全く同じ) ----------
Xtr, dtr = X[washout:n_train], d[washout:n_train]
W_out = np.linalg.solve(Xtr.T @ Xtr + beta * np.eye(N + 1), Xtr.T @ dtr)

# ---------- 5. テスト区間で評価 ----------
y = X[n_train:] @ W_out
nrmse = np.sqrt(np.mean((y - d[n_train:]) ** 2)) / d[n_train:].std()
print(f"リングリザバー テストNRMSE: {nrmse:.4f}")   # 0.0003 前後
上段はリングリザバーによるMackey-Glass予測が真値とほぼ重なる様子、下段はノード数を増やすとリングとランダムESNのNRMSEがほぼ同等に下がるグラフ
図5:上のコードの実測(決定論的な入力符号)。上段=1ステップ先予測は真値とほぼ重なり、N=200でテストNRMSE 0.0003。下段=ノード数を増やすと、決定論的なリング(オレンジ)はランダムESN(青・6シードの範囲)とほぼ同等の精度で改善します。

遅延線リザバー ― リングの「物理版」

リングと双子の関係にあるのが遅延線リザバーです。たった1つの非線形素子に、遅れをつけて自分の出力を戻す(遅延フィードバック)。入力にはマスクをかけて時間方向に区切り、1周期の中の複数の時点を「仮想ノード」として読み出します。時間展開すると、これは環につながったノード列と同じになります――つまり数式上はリングの親戚です。素子1つで作れるため、光・電子回路の物理リザバーで定番の方式です(Appeltant et al., 2011)。

入力 × マスク u(t)·m 非線形 1素子 遅延 τ 1周期 τ を N点に区切る=仮想ノード θ これらを状態ベクトルとして読み出す(=リングの時間展開)
図4:遅延線リザバーの考え方。1つの素子+遅延で、1周期内の複数時点を仮想ノードにする。時間展開するとリング状の結合と等価になります。

使いどころと注意

リングは乱数を避けたい・再現性が要る・メモリを削りたい組込み用途や、学習のベースラインとして優秀です。ただし「決定論的なら常にESNより良い」わけではなく、タスクによっては入力の符号パターンや複数の環などの工夫が要ります。まずはESN/リングの両方を同じ条件で比べるのが確実です。

04 Spiking Reservoir

スパイキングリザバー(Liquid State Machine)

ノード:スパイク(LIF等) 実装難易度:ふつう ひとことで:脳型・イベント駆動のリザバー

脳の神経細胞は、連続値ではなくスパイク(発火)という「点」で情報をやり取りします。これを模したのがスパイキングリザバーで、代表格がリキッド・ステート・マシン(LSM)です(Maass et al., 2002)。多数のスパイキングニューロン(よく使うのは「漏れ積分発火:LIF」)をランダムに結合して固定し、入力で生じる発火のパターン=「液体(リキッド)」の状態を、線形読み出しで解釈します。名前は「水面に石を落とすと広がる波紋(liquid)」から来ています。

うれしいのはイベント駆動であること。値が変わったニューロンだけが動くため、専用チップ(ニューロモルフィック:Intel Loihi、SpiNNakerなど)では極めて低消費電力になり得ます。常時通電のセンサーやウェアラブルと好相性です。

この方式の要点

提案
Maass et al. (2002)
ノード
スパイクニューロン(LIF等)
状態
発火を平滑化した「液体状態」
強み
イベント駆動で超低電力/脳型
調整
閾値・時定数・発火率
入力スパイク × 重み 積み上げ LIFニューロン 閾値 θ 膜電位 v(t) 出力スパイク 閾値に達したら「発火」→ 膜電位をリセット → 不応期 (リセットの流れ)
図6:LIFニューロンの動き。入力を膜電位に積み上げ、閾値θに達すると発火して膜電位をリセットします。この「発火の履歴」を平滑化したものが読み出しに使う状態です。

数式:漏れ積分発火(LIF)

v(t+1) = v(t) + (1/τ) ( −v(t) + I(t) ) ,  v≥θ なら発火&v←0
  • v(t):膜電位(たまり具合)。閾値θを超えると発火。
  • I(t):入力電流=入力スパイク+他ニューロンからの発火(重み付き)+バイアス。
  • −v(t):漏れ(放っておくと下がる)。τが時定数。
  • (1/τ)(・):1ステップで入力へ近づく速さ。発火したら v を0へリセットし、少し休む(不応期)。

読み出しに使う状態は、各ニューロンの発火を指数関数で平滑化した「発火の余韻(シナプス痕跡)」です。うまく機能させる鍵は時定数の多様性――速いニューロンと遅いニューロンを混ぜると、いろいろな時間スケールの記憶がそろい、時系列を分離しやすくなります。

Python実装 ― NumPyだけ、約50行(時系列の分類)

スパイキングリザバーが得意な時系列パターンの分類を題材にします。3種類の時間パターン(周波数)を入力し、末尾の「液体状態」を線形読み出しで当てます。仕上げは共通の型と同じ(分類なので教師をワンホットにするだけ)。

lsm.py Python 3・NumPyのみ
import numpy as np
rng = np.random.default_rng(0)

# ---------- 設定 ----------
N        = 200          # ニューロン数
n_class  = 3            # クラス数(3種類の周波数)
n_trials = 600          # 試行数
L        = 80           # 1試行の長さ(ステップ)
noise    = 0.25         # 入力ノイズ
freqs    = np.linspace(1/28, 1/10, n_class)   # 各クラス=ある周波数

# ---------- リザバー(作ったら固定):多様な時定数がカギ ----------
tau_m = rng.uniform(5, 16, N)                 # 膜時定数(ニューロンごとに違える)
a_s   = np.exp(-1.0 / rng.uniform(3, 25, N))  # シナプス痕跡の減衰(記憶の長さを決める)
th    = rng.uniform(0.9, 1.1, N)              # 発火閾値
bias  = rng.uniform(0.75, 1.0, N) * 1.15      # 閾値近くに置くバイアス電流
W_in  = rng.uniform(-1, 1, N) * 2.2
W = rng.normal(0, 1, (N, N)); W[rng.random((N, N)) > 0.12] = 0.0
inh = rng.random(N) < 0.2                      # 2割を抑制性に
W[:, inh] = -np.abs(W[:, inh]); W[:, ~inh] = np.abs(W[:, ~inh])
W *= 0.9 / max(abs(np.linalg.eigvals(W)))      # 再帰結合のスケール調整

# ---------- 1試行を流して「液体状態」を取り出す ----------
def run_trial(sig, tref=2):
    v = np.zeros(N); refr = np.zeros(N, int); trace = np.zeros(N); spk = np.zeros(N)
    for t in range(len(sig)):
        I = bias + W_in * sig[t] + W @ spk     # 入力電流
        active = refr <= 0
        v = v + active * (1.0 / tau_m) * (-v + I)   # 漏れ積分(LIF)
        spk = np.zeros(N); fire = active & (v >= th); spk[fire] = 1.0
        v[fire] = 0.0; refr[fire] = tref; refr = np.maximum(refr - 1, 0)  # 発火→リセット→不応期
        trace = trace * a_s + spk              # スパイクを指数フィルタ=液体状態
    return trace                               # 試行末の状態ベクトル

# ---------- データ生成+状態収集 ----------
feats, labels = [], []
for _ in range(n_trials):
    cls = rng.integers(n_class); ph = rng.uniform(0, 2*np.pi)
    sig = np.sin(2*np.pi*freqs[cls]*np.arange(L) + ph) + noise*rng.standard_normal(L)
    feats.append(run_trial(sig)); labels.append(cls)
X = np.array(feats); y = np.array(labels)

# ---------- 線形読み出し(リッジ回帰)で分類:他方式と同じ型 ----------
ntr = int(0.7 * n_trials)
F  = np.concatenate([np.ones((ntr, 1)), X[:ntr]], axis=1)
Ft = np.concatenate([np.ones((n_trials - ntr, 1)), X[ntr:]], axis=1)
Y  = np.eye(n_class)[y[:ntr]]                  # 教師をワンホットに
W_out = np.linalg.solve(F.T @ F + 1e-1*np.eye(F.shape[1]), F.T @ Y)
pred = np.argmax(Ft @ W_out, axis=1)
acc = np.mean(pred == y[ntr:])
print(f"スパイキングリザバー テスト精度: {acc*100:.1f}%  (3クラス・チャンス33%)")  # 96%前後
左上に3種類の入力波形、右上にテスト精度96.7%、左下にニューロン200個のスパイクラスター、右下に対角成分が強い混同行列を示した図
図7:上のコードの実測。3種類の時間パターンを、LIFニューロン200個の「液体状態」を線形読み出しするだけで約96%で識別できました(チャンス33%)。左下のスパイクラスターが「液体」の実体、右下の混同行列が分類結果です。

使いどころと注意

スパイキングはニューロモルフィック機器での超低消費電力や、イベントカメラ・音・振動のようにもともと疎(スパース)な信号と好相性です。一方、連続値のESNに比べると閾値・時定数・発火率の調整が繊細で、精度もタスク依存です。まずは連続値のESN/リングで基準を作り、消費電力やハードウェア要件からスパイキングを検討するのが現実的です。

05 Coupled Oscillators

蔵本モデル/結合振動子リザバー

ノード:位相・振幅の振動子 実装難易度:ふつう ひとことで:同期する振動子で計算する

メトロノームを並べると、いつのまにか歩調がそろう――この同期を記述する古典モデルが蔵本モデルです。たくさんの振動子が、それぞれ自分のテンポ(自然周波数)を持ちつつ、互いに引き込み合う。全体のそろい具合は秩序変数 R(0=バラバラ、1=完全同期)で測ります。ホタルの明滅や拍手がそろう現象も同じ数式で説明できます。

この振動子の集団に入力を流し、各振動子の状態を読み出せばリザバーになります。魅力は物理素子で作れること――スピントルク発振素子・レーザー・MEMSなど、実在の振動子ネットワークをそのままリザバーに使えるため、超高速・省電力の物理リザバーとして研究が進んでいます(Nakajima ほか)。

この方式の要点

基礎
蔵本モデル(同期現象)
ノード
位相/振幅を持つ振動子
状態
各振動子の (cosθ, sinθ) 等
強み
物理振動子で実装・高速
本実装
振幅と減衰を持つStuart-Landau型
入力 u(t) テンポを揺さぶる R 10個の振動子(それぞれ位相を持つ) 同期度 R R≈0(バラバラ) R≈1(同期) 入力がこの間を揺らす
図8:結合振動子の考え方。各振動子は位相(矢印)を持ち、その平均が秩序変数R(同期度)。入力が同期の度合いを揺さぶり、その変化が「状態」になります。

数式:蔵本モデルからStuart-Landau実装へ

i/dt = ωi + (K/N)Σj sin(θj−θi) + ε ci u(t)
  • ωi:各振動子の自然周波数(自分のテンポ)。ばらつきが多様性=記憶の源。
  • (K/N)Σ sin(θj−θi):他の振動子と引き込み合う結合。Kが大きいほど同期しやすい。
  • ε ci u(t):入力。各振動子のテンポを少しずつ揺さぶる。

このページでは、振幅と減衰を持つStuart-Landau振動子で実装します

Stuart-Landau振動子は、位相だけでなく振幅も扱える結合振動子の標準モデルです。振幅の収束によって初期状態の影響を忘れやすく、フェーディングメモリを設計しやすいため、下のコードではこの形を採用します。位相だけの蔵本モデルをリザバーとして使う研究もありますが、その場合は入力の与え方、読み出す秩序変数、結合強度などの設計が重要です。

Python実装 ― NumPyだけ、約45行

振幅を一定の範囲へ戻す項 −|z|²z が初期状態の影響を薄め、リザバーとして使いやすいダイナミクスを作ります。題材はESNと同じMackey-Glassの1ステップ先予測で、比較しやすくしています。

oscillator.py Python 3・NumPyのみ
import numpy as np

def mackey_glass(n, tau=17):
    x = np.full(n + tau, 1.2)
    for t in range(tau, n + tau - 1):
        x[t + 1] = x[t] + 0.2 * x[t - tau] / (1 + x[t - tau] ** 10) - 0.1 * x[t]
    return x[tau:]

data = mackey_glass(4000); n_train = 3000
mu, sd = data[:n_train].mean(), data[:n_train].std()
data = (data - mu) / sd
u, d = data[:-1], data[1:]

# ---------- 振動子リザバー(作ったら固定) ----------
N       = 100      # 振動子の数
K       = 1.0      # 結合の強さ(同期のしやすさ)
eps     = 0.6      # 入力の強さ
a       = 1.0      # 各振動子の利得(振幅を生む)
dt      = 0.1      # 積分刻み
nsub    = 5        # 1入力あたりの内部積分ステップ
beta    = 1e-6
washout = 200

rng   = np.random.default_rng(0)
omega = rng.normal(0, 0.5, N)          # 自然周波数(振動子ごとにばらつく)
c_in  = rng.uniform(-1, 1, N)          # 入力の配り方
z     = 0.1 * (rng.standard_normal(N) + 1j * rng.standard_normal(N))  # 複素振幅

# ---------- 状態を集める ----------
T = len(u); X = np.zeros((T, 2 * N + 1))
for t in range(T):
    drive = eps * c_in * u[t]
    for _ in range(nsub):
        zbar = z.mean()                                  # 平均場(結合の中身)
        dz = (a + 1j * omega - np.abs(z) ** 2) * z + K * (zbar - z) + drive
        z = z + dt * dz                                  # −|z|²z が振幅を安定化
    X[t, 0] = 1.0
    X[t, 1:N+1]  = z.real                                 # 状態=各振動子の実部・虚部
    X[t, N+1:]   = z.imag

# ---------- 読み出し層をリッジ回帰で学習:他方式と同じ型 ----------
Xtr, dtr = X[washout:n_train], d[washout:n_train]
M = X.shape[1]
W_out = np.linalg.solve(Xtr.T @ Xtr + beta * np.eye(M), Xtr.T @ dtr)
y = X[n_train:] @ W_out
nrmse = np.sqrt(np.mean((y - d[n_train:]) ** 2)) / d[n_train:].std()
print(f"結合振動子リザバー テストNRMSE: {nrmse:.4f}")   # 0.012 前後
上段が入力信号、中段が振動子の状態のヒートマップと秩序変数R(t)、下段がMackey-Glassの真値と振動子リザバー予測がほぼ重なるグラフ
図9:上のコードの実測。中段=入力に合わせて集団のリズム(Re(zi))とオレンジの秩序変数R(t)が「呼吸」するように変化します。下段=この状態を線形読み出しすると、1ステップ先予測のテストNRMSEは0.012でした。

使いどころ

結合振動子は物理デバイスでリザバーを作りたいときの中心的な選択肢です。ソフトウェアでは連続値ESNの方が手軽なことが多い一方、スピントルク・フォトニクスなどのハードウェアでは、この方式が超高速・省電力を実現します。詳しくは親ページの「ソフトリザバーと物理リザバー」も参照してください。

06 Next-Generation RC

次世代リザバー(NG-RC/NVAR)

ノード:なし(特徴量ベース) 実装難易度:やさしい〜ふつう ひとことで:ランダムなリザバーを捨てる

これまでの方式は「動的なリザバー(RNN・スパイク・振動子)」を用意しました。次世代リザバー(NG-RC/NVAR)は発想を逆転させ、動的なリザバーを一切持ちません。代わりに、「少し前までの入力(時間遅れ)」と「それらの積(多項式特徴)」を並べた特徴ベクトルを作り、リッジ回帰1回で学習します(Gauthier et al., 2021)。

驚くべきことに、これは従来のリザバー計算と数学的にほぼ等価であることが示されています。しかも乱数のチューニングが不要で、必要なデータも学習時間も少なく、何を使って予測しているかが読める(解釈可能)という利点があります。カオス系(ローレンツ方程式など)の予測で特に強力です。

この方式の要点

提案
Gauthier et al. (2021)
リザバー
持たない(特徴量で代替)
特徴
時間遅れ+多項式の積
強み
少データ・乱数不要・解釈可能
注意
特徴の次元が増えやすい
特徴ベクトル(これが「リザバーの代わり」) 1 定数 + 線形:少し前までの入力(6次元) + 2次:それらの積(21次元) 線形回帰 → 次を予測 合計28次元を並べて、リッジ回帰1回。ランダムなリザバーは無い。
図10:次世代RCの特徴ベクトル。定数・線形(時間遅れ)・2次の積を並べるだけ。この例では合計28次元で、これを線形回帰にかけて次の状態を予測します。

数式:特徴ベクトルを組み立てるだけ

時刻 t の特徴ベクトルは、次の3つを縦に並べたものです。

o(t) = [ 1  |  線形:u(t), u(t−1), …(時間遅れ)  |  2次:それらの積 u·u′ … ]

予測は 次の状態 = 今の状態 + o(t)·W_out。学習は o(t) → 状態の差分 をリッジ回帰で求める1回だけです。乱数も、時間をかけた状態更新のループも要りません

Python実装 ― NumPy+標準ライブラリ、約50行(ローレンツ予測)

カオスの代表格ローレンツ方程式を予測します。学習後、予測値を入力に戻して自走させると、蝶の形(アトラクタ)まで再現します。仕上げの学習は共通の型と同じリッジ回帰1回です。

ngrc.py Python 3・NumPy+標準ライブラリ
import numpy as np
from itertools import combinations_with_replacement

# ---------- 1. データ:ローレンツ63(RK4で数値積分) ----------
def lorenz(n, dt=0.025, s=10., r=28., b=8/3., warm=1000):
    X = np.zeros((n + warm, 3)); X[0] = [1., 1., 1.]
    f = lambda v: np.array([s*(v[1]-v[0]), v[0]*(r-v[2])-v[1], v[0]*v[1]-b*v[2]])
    for t in range(n + warm - 1):
        v = X[t]; k1=f(v); k2=f(v+dt/2*k1); k3=f(v+dt/2*k2); k4=f(v+dt*k3)
        X[t+1] = v + dt/6*(k1 + 2*k2 + 2*k3 + k4)
    return X[warm:]

dt = 0.025; n = 6000; n_train = 4000; warm = 100; beta = 1e-3
k, s = 2, 1                                    # 時間遅れ:2タップ、間隔1
data = lorenz(n, dt=dt)
mu, sd = data[:n_train].mean(0), data[:n_train].std(0)
D = (data - mu) / sd

# ---------- 2. 特徴ベクトル:定数 + 線形(遅れ) + 2次の積 ----------
def features(taps):                             # taps: 形 (k, 3)
    lin = taps.flatten()                        # 線形部(3k 次元)
    quad = np.array([lin[i]*lin[j]              # 2次の単項式(重複ありの組合せ)
                     for i, j in combinations_with_replacement(range(len(lin)), 2)])
    return np.concatenate([[1.0], lin, quad])   # ← ここが「リザバーの代わり」

span = (k - 1) * s
F = np.array([features(D[t-span:t+1:s]) for t in range(span, n-1)])
Y = np.array([D[t+1] - D[t] for t in range(span, n-1)])   # 教師=1ステップ差分

# ---------- 3. リッジ回帰1回で学習:他方式と同じ型 ----------
Ftr, Ytr = F[warm:n_train], Y[warm:n_train]
M = Ftr.shape[1]                                # 特徴次元=28(=1+6+21)
W_out = np.linalg.solve(Ftr.T @ Ftr + beta*np.eye(M), Ftr.T @ Ytr)
pred = F[n_train:] @ W_out
nrmse = np.sqrt(np.mean((pred - Y[n_train:])**2)) / Y[n_train:].std()
print(f"1ステップ NRMSE: {nrmse:.5f}   特徴次元: {M}")     # 0.0017 前後

# ---------- 4. 自律走行:予測だけでアトラクタを再現 ----------
hist = list(D[n_train-span:n_train+1:s]); cur = D[n_train].copy(); gen = [cur.copy()]
for _ in range(1999):
    cur = cur + features(np.array(hist[-k:])) @ W_out
    gen.append(cur.copy()); hist.append(cur.copy())
gen = np.array(gen); truth = D[n_train:n_train+len(gen)]
m = min(len(gen), len(truth))
err = np.linalg.norm(gen[:m]-truth[:m], axis=1) / np.sqrt(3)
vt = int(np.argmax(err > 0.3)) if np.any(err > 0.3) else m
print(f"自律走行の有効予測: 約 {vt*dt:.1f} 時間単位(ローレンツのリアプノフ時間の数倍)")
左にローレンツ・アトラクタの真値とNG-RC自律生成がほぼ重なる蝶形、右にx(t)の予測が有効時間まで真値を追う様子を示した図
図11:上のコードの実測。=訓練後に予測だけで自走させると、ローレンツ・アトラクタ(蝶の形)を再現します。=短期予測はリアプノフ時間の数倍(約7.6時間単位)まで真値を追います。特徴量はわずか28次元、ランダムなリザバーは一切ありません。

使いどころと注意

次世代RCは少ないデータ・軽い計算・高い再現性が要る力学系の予測や制御で強力です。一方、次数やタップ数を増やすと特徴の次元が急増する点、状態をきれいに観測できることを前提にする点には注意が要ります(欠測やノイズが多い生信号では前処理や別方式が有利なことも)。まずは低次数(2次・数タップ)から試すのが定石です。

07 Physical Reservoirs

物理リザバー方式(概観)

ここまでの方式は「数式で書けるリザバー」でしたが、複雑なダイナミクスを持つ物理系そのものをリザバーに使う流れもあります。演算を物理現象に任せるため、超高速・超低消費電力が期待されます。前述の結合振動子遅延線は、その多くが物理リザバーの実装形態でもあります。

Photonic

フォトニック(光)

レーザーや光ファイバーの遅延系を使う。光速で動くため超高速・広帯域。遅延線方式と相性が良い。

高速・大容量/光学系の安定化が課題

Spintronics

スピントロニクス

スピントルク発振素子など、ナノスケールの磁気振動子をネットワーク化。結合振動子リザバーの物理実装。

超小型・省電力/作製ばらつきが課題

Soft matter

ソフトマテリアル/ロボット

柔らかい材料やロボットの身体の動きそのものを計算資源に使う(フィジカル・リザバー、身体性)。

身体で計算/モデル化・制御が課題

Analog / Memristor

メモリスタ/アナログ回路

アナログ電子回路や記憶抵抗(メモリスタ)の非線形応答を利用。エッジ機器への集積を狙う。

低消費電力・集積性/再現性・校正が課題

物理リザバーの位置づけ・国内の研究動向は、親ページ「ソフトリザバーと物理リザバー」で詳しく解説しています。

08 How to Choose

どの方式を選ぶか ― 迷わない順番

方式は「上から順に当てはめる」と迷いません。最初は必ず動かしやすい方式で基準を作り、要件(電力・ハードウェア・データ量)で乗り換えるのが実務的です。

  1. まず1つ動かして基準を作る

    ソフトウェアならESNリング(SCR)が最短。共通の型で状態を集めてリッジ回帰1回。ここで評価指標と時系列順の検証区間を固定します。

  2. 乱数を避けたい・再現性が要る・省メモリ

    リング(SCR)、または次世代RC。決定論的で結果が安定し、組込みにも向きます。

  3. 力学系・カオスを少ないデータで予測したい

    次世代RC(NVAR)。ローレンツのような系で強く、乱数チューニングも不要です。

  4. 超低消費電力・脳型・イベント駆動が要件

    スパイキング(LSM)。ニューロモルフィック機器や疎な信号(イベントカメラ・音・振動)と好相性です。

  5. 物理デバイスでリザバーを作りたい

    結合振動子遅延線(光・スピン・アナログ)。まずソフトで試作し、物理実装へ移すのが定石です。

  6. 最後に、同条件で比較する

    選んだ方式を、同じ学習/評価分割でLSTM・1D-CNN・勾配ブースティングなどの基準と並べて評価。複数シードで再現性も確認します。

覚えておくと迷わない一言:
「状態のつくり方」を選ぶだけ。集め方と学習(リッジ回帰1回)は、どの方式も同じ。

FAQ Questions

よくある質問

リザバーの方式はどれが一番良いですか?

まずはESNかリングで基準を作るのがおすすめです。そのうえで、少量データなら次世代RC、超低消費電力ならスパイキング、物理デバイスなら遅延線・結合振動子へ広げます。最終的には、精度・遅延・消費電力・メモリ・データ量・ハードウェアの条件をそろえ、同じ学習/評価分割で比較して決めます。

ESN以外の方式を使うメリットは何ですか?

目的次第で明確な利点があります。リングは乱数ゼロで再現性が高く省メモリ、スパイキングはイベント駆動で超低消費電力(脳型チップ向き)、結合振動子は光・スピンなどの物理デバイスで実装でき超高速、次世代RCは少データ・乱数不要・解釈可能でカオス予測に強い、といった具合です。

スパイキングリザバーは普通のPCでも動きますか?

動きます。本ページのコードも通常のCPUで実行できます。ただしスパイキングの真価は、ニューロモルフィック機器(Intel Loihi、SpiNNakerなど)で動かしたときの消費電力の低さにあります。PC上のシミュレーションは、むしろ連続値のESNより計算が重くなることもあります。

蔵本モデルは「位相だけ」ですが、それでリザバーになりますか?

なります。位相だけの蔵本モデルをリザバーとして使う研究があり、秩序変数を読み出して時系列予測に利用できます。本ページでは、初期状態の影響を忘れやすく設計しやすいStuart-Landau振動子を採用しました。位相だけで実装する場合は、入力の与え方、読み出す秩序変数、結合強度などを調整します。

次世代RCは本当にリザバー(RNN)が要らないのですか?

動的なリザバーは要りません。「少し前までの入力(時間遅れ)」と「それらの多項式の積」を並べた特徴ベクトルで、従来のリザバー計算とほぼ等価な表現を明示的に作ります。乱数のチューニングやループが不要になる一方、次数やタップ数を増やすと特徴の次元が急増する点には注意が必要です。

これらの方式は物理リザバーとどう関係しますか?

遅延線や結合振動子は、その多くが物理リザバーの実装形態です(光・スピントロニクス・アナログ回路など)。実務では、まずソフトウェア(ESN・リング・次世代RCなど)で見込みを確かめてから物理実装へ移すのが現実的です。詳しくは親ページの「ソフトリザバーと物理リザバー」をご覧ください。

09 Summary

まとめ

リザバーコンピューティングはESN一択ではなく、結合の作り方(ランダム/決定論的/物理)とノードの種類(連続値/スパイク/振動子)で多彩な方式があります。本ページでは、決定論的なリング、脳型のスパイキング(LSM)結合振動子、そして動的リザバーを持たない次世代RCを、仕組み・数式・実測付きのコードで見てきました。

大切なのは、どの方式も共通の型(入力を通す → 状態を集める → リッジ回帰1回)で作れるということ。違うのは「状態をつくる部分」だけです。この視点さえ持てば、新しいリザバーも怖くありません。まずは動かしやすい方式で基準を作り、用途と制約に合わせて選び、同条件で比較して確かめましょう。

個々の実装をさらに深めたい場合は、代表モデルの詳細解説「エコーステートネットワーク(ESN)とは」と、全体像をまとめた親ページ「リザバーコンピューティングとは?」もあわせてどうぞ。

10 References

参考文献・関連リンク

各方式の基礎文献(一次情報)

  1. Rodan, A., & Tiňo, P. (2011). Minimum Complexity Echo State Network. IEEE Transactions on Neural Networks, 22(1), 131–144.(リングリザバー=Simple Cycle Reservoirの原典)
  2. Appeltant, L., et al. (2011). Information processing using a single dynamical node as complex system. Nature Communications, 2, 468.(遅延線リザバーの基礎)
  3. Maass, W., Natschläger, T., & Markram, H. (2002). Real-time computing without stable states. Neural Computation, 14(11), 2531–2560.(Liquid State Machineの原典)
  4. Torrejon, J., et al. (2017). Neuromorphic computing with nanoscale spintronic oscillators. Nature, 547, 428–431.(スピントルク振動子によるリザバー)
  5. Nakajima, K. (2020). Physical reservoir computing—an introductory perspective. Japanese Journal of Applied Physics, 59, 060501.(物理・振動子リザバーの概観)
  6. Chiba, H., Taniguchi, K., & Sumi, T. (2025). Reservoir computing with the Kuramoto model. arXiv:2407.16172.(位相のみの蔵本モデルを使うリザバー計算)
  7. Gauthier, D. J., Bollt, E., Griffith, A., & Barbosa, W. A. S. (2021). Next generation reservoir computing. Nature Communications, 12, 5564.(NG-RC/NVARの原典)

当サイトの関連ページ

日本語の入門・実装

11 Author

執筆・監修

株式会社QuantumCore 代表取締役CEO 秋吉信吾

秋吉 信吾

株式会社QuantumCore 代表取締役CEO

Excite株式会社にて自然言語処理を活用した新規サービスやWeb検索サービスの開発に従事し、2012年にはディープラーニングを活用した動画コンテンツマッチ広告システムをいち早く手がける。Mistletoe株式会社・デジタルガレージでのAI関連R&Dを経て、2018年に株式会社QuantumCoreを創業。R&D・経営戦略・PoCプロジェクトを横断して監修し、NEDOをはじめ公的・民間プログラムの有識者・アドバイザーも務める。

12 Products

リザバーコンピューティングを試す

目的に合わせ、ノーコード検証、組み込み、異常検知、話者識別の各ソリューションを確認できます。

方式選びから、現場実装まで

どの方式が向くかは、精度だけでなく、必要データ量・遅延・メモリ・電力・ハードウェアで変わります。手元の時系列データを前に、方式の選定とPoC設計からご相談ください。

お問い合わせフォームへ