LoginSignup
9
11

More than 3 years have passed since last update.

逐次リザバーコンピューティング(Sequential Reservoir Computing) 

Last updated at Posted at 2020-04-22
逐次学習なし 逐次学習
予測 image.png image.png

はじめに

リザバーコンピューティング(Reservoir Computing) を、逐次学習 (sequential learning)で動かしてみました。

逐次学習は、ベイズ線形回帰で実装しています。
リザバーコンピューティングとして、Leaky Integrator Echo State Network(LI-ESN)を実装しています。

リザバーコンピューティングは、シンプルな回帰型ニューラルネットワーク(RNN:Recurrent Neural Network)で、時間パターンの処理ができ魅力的です。

リザバーの計算式

時刻を $t$ としたとき、リザバーの状態 $x$ 、出力 $y$ の計算式を次に示します。

x(t+1) = f_{activator}\biggl((1 - \delta)x(t) + \delta\Bigl(W_{in}u(t+1) + W_{res}x(t)\Bigr) \biggr)\\

y(t) = W_{out}x(t) \\

ここで、$u$ は入力、$δ$ は漏れ率を示します。
$W_{in}$、$W_{res}$、$W_{out}$ は、それぞれ、入力、リザバー状態、出力を計算する重みです。

$W_{in}$、$W_{res}$ は、初期化時にランダムに設定して固定です。
$W_{out}$ は、ベイズ線形回帰で、逐次更新します。

image.png

「Deep Reservoir Computing」 Figure 2.7: The ESN architecture より
https://etd.adm.unipi.it/theses/available/etd-02282019-191815/unrestricted/Deep_Reservoir_Computing.pdf

次の図は、tuneable frequency generator task の例です。

image.png

「Echo state network」Figure 1 より
http://www.scholarpedia.org/article/Echo_state_network

実行結果

入力 $sin(t)$ に対して、教師データ $sin(t+future)$ で学習させました。 future は予測時間です。
学習後のテストフェーズでは予測した値を入力データに戻して使用します。

予測結果は、漏れ率、予測時刻により大きく変化します。

逐次学習無し

学習フェーズでは、入力(赤)から予測(黄色)をうまく出力しています。
テストフェーズでは、時刻が経過するにつれて、予測(青)の振幅が小さくずれていきます。
位相のズレも拡大しています。

BayesianRegression(alpha=1.0, fit_intercept=True)test (future, partial, leak_rate, seq_learning)_ -1, True, 0.5, False.png

逐次学習有り

テストフェーズでは、時刻が経過しても、予測(青)の振幅と位相が維持できています。

BayesianRegression(alpha=1.0, fit_intercept=True)test (future, partial, leak_rate, seq_learning)_ -1, True, 0.5, True.png

プログラム

プログラム環境

matplotlib               3.2.1          
numpy                    1.18.2         
scikit-learn             0.22.2.post1   
scipy                    1.4.1          
Python 3.6.9

Reservoir クラス

class Reservoir: 
    def __init__(self, node_n, leak_rate=0.1, reg=linear_model.Ridge, activator=np.tanh,  W_res_file=None): # 'W_res.npy'
        self.node_n=node_n; self.leak_rate=leak_rate;  self.reg=reg; self.activator=activator # (in, res, out)
        self.State = np.array([np.zeros(self.node_n[1])]) # Log for Ridge Regression
        self.W_in = (np.random.randint(0, 2, node_n[0]*node_n[1]).reshape([node_n[0],  node_n[1]]) *2 -1) * 0.1
        if W_res_file and os.path.isfile(W_res_file): self.W_res = np.load(W_res_file)
        else:
            _weights = np.random.normal(0, 1, node_n[1] * node_n[1]).reshape([node_n[1], node_n[1]])
            _spectral_radius = max(abs(linalg.eigvals(_weights)))
            self.W_res = _weights / _spectral_radius
            if W_res_file: np.save(W_res_file + '.out', self.W_res)
    def _next_state(self, input, current_state): 
        return self.activator((1.0-self.leak_rate)*current_state + (self.leak_rate * (np.array([input])@self.W_in + current_state@self.W_res))) 
    def fit(self, X, T):
        for i, input in enumerate(X):
            current_state = np.array([self.State[-1]])
            self.State = np.append(self.State, self._next_state(input, current_state), axis=0)
        self.State = self.State[1:]
        self.reg.fit(self.State, T) 
    def partial_fit(self, X, T): 
        for i, input in enumerate(X):
            current_state = self.State[-1]
            self.State = self._next_state(input, current_state)
            self.reg.partial_fit(self.State, np.array([T[i]])) 
    def predict(self, X, init_state=False, update_state=False):
        outputs = []
        reservoir_nodes = np.zeros(self.node_n[1]) if init_state else self.State[-1]
        for x in X:
            reservoir_nodes = self._next_state(x, reservoir_nodes.reshape((self.node_n[1],)))  #.reshape((150,))
            outputs.append(self.reg.predict(reservoir_nodes))
        if update_state: self.State = reservoir_nodes 
        return np.array(outputs)

ベイズ線形回帰クラス

class BayesianRegression(): 
    def __init__(self, alpha=1.0, sigma=0.2, fit_intercept=True):
        self.lambda_ = alpha
        self.sigma = sigma # noise standard deviation
        self.fit_intercept = fit_intercept
        self.M = 0 # len(w) 
        self.w, self.intercept_, self.coef_,  = None, None, None
        self.m, self.S = None, None # mean, variance 
        self.beta = 1.0 / (self.sigma ** 2) # precision
        self.alpha = self.lambda_ * self.beta 
        if self.alpha == 0.: print("set alpha=0.001 (Prevent division by zero)")
    def fit(self, X, T): 
        self.partial_fit(X, T)
    def partial_fit(self, X, T):
        if (self.fit_intercept): X = np.insert(X, 0, 1., X.ndim-1)
        if self.M==0 and len(X)>0: # Initialize 
            self.M = (len(X[0]),len(T[0]))
            self.m = np.zeros((self.M[1], self.M[0]))
            self.S = np.array([np.identity(self.M[0]) / self.alpha]*self.M[1])  # (3.52)
        for j in range(len(T[0])): #  out nodes loop
            for i in range(len(X)): # data loop
                phi, t = np.array([X[i]]), T[i]
                phi_T = phi.T
                S_inv = np.linalg.inv(self.S[j])
                self.S[j] = np.linalg.inv(S_inv + self.beta * phi_T @ phi) # (3.51)
                self.m[j] = (self.S[j] @ ((S_inv@self.m[j]).reshape(-1,1) + self.beta *  phi_T * t[j])).reshape(-1,) # (3.50) 
        self.w = self.m
        if (self.fit_intercept): self.intercept_, self.coef_ = self.w[0], self.w[1:]         
        else: self.intercept_, self.coef_ = 0, self.w   
    def predict(self, X):
        if self.fit_intercept: X =  np.insert(X, 0, 1, X.ndim-1) 
        return X @ self.w.T

テストプログラム

%matplotlib inline

from scipy import linalg
import numpy as np
import matplotlib.pyplot as plt
from sklearn import linear_model
def test(constructor, future, t_fn=np.sin, leak_rate=0.5, seq_learning=True, partial=False, x_n=1000, train_ratio=0.25,  y_amp=1.0):
    title = "test (future, partial, leak_rate, seq_learning): "+ str(round(future, 2)) + ', ' + str(partial) + ', '+ str(leak_rate) + ', ' + str(seq_learning)
    def graph_out(x, y, x_train, train_result, x_test, predict_result, x_border):
        plt.plot(x, y, label="inputs", color="red")
        plt.plot(x_train, np.array(train_result).flatten().tolist(), label="train", color="orange")
        plt.plot(x_test, np.array(predict_result).flatten().tolist(), label="predict", color="blue")
        plt.axvline(x_border, color="black") # border of train and prediction
        plt.legend(); plt.legend(loc="lower left"); plt.grid(); plt.ylim(y_min, y_max)
        plt.xlabel("x"); plt.ylabel("y(x)"); plt.title(title + '\n' + constructor)
        plt.savefig(constructor + title + '.png'); plt.show()
    x_delta = np.pi*16
    x_min, x_max, y_min, y_max = 0, x_delta, -1.2, 2.2
    x_border = int(x_delta*train_ratio + x_min)
    future_n = max(1,int(future/(x_delta/x_n)))  if future > 0 else - future
    x = np.linspace(x_min, x_max, x_n)
    y = t_fn(x).reshape(-1, 1) * y_amp
    train_n = int(x_n * train_ratio)
    x_train, x_test = x[:train_n], x[train_n: - future_n]
    y_train, y_test = y[:train_n], y[train_n: - future_n]  
    t_train, t_test = y[future_n: future_n+train_n], y[train_n+future_n:]  
    x, y, test_n = x[:-future_n], y[:-future_n], len(x_test) 
    model = Reservoir(node_n=(1, 150, 1), reg=eval(constructor), leak_rate=leak_rate)
    if partial: model.partial_fit(y_train, t_train)
    else: model.fit(y_train, t_train)
    train_result = model.predict(y_train, init_state=True, update_state=False)
    predict_result = train_result[-future_n:]
    for _i in range(test_n ):
        if seq_learning: model.partial_fit(np.array([y_test[_i]]), np.array([t_test[_i]]))    
        tmp = model.predict(np.array([predict_result[-future_n]]), init_state=False, update_state=True)[0].flatten()
        predict_result = np.append(predict_result, [[tmp]], axis=0)
    predict_result = predict_result[future_n:]
    graph_out(x, y, x_train, train_result, x_test, predict_result, x_border)

if __name__ == '__main__':    
    def init(): np.random.seed(0)
    t_fn = lambda x: np.sin(x) +1.0
    # future = np.pi/4  
    future = -1
    leak_rate = 0.5
    init(); test('BayesianRegression(alpha=1.0, fit_intercept=True)', future, t_fn, leak_rate, partial=True, seq_learning=False)  
    init(); test('BayesianRegression(alpha=1.0, fit_intercept=True)', future, t_fn, leak_rate, partial=True, seq_learning=True)       

!ls -lt

参考資料

リザバー(Reservoir)に意識は宿るか?(記憶、概念獲得、判断、予測)
https://qiita.com/tshimizu8/items/41945567730a840e8cc1

ベイズ線形回帰ってナンだ?(Bayesian linear regression)
https://qiita.com/tshimizu8/items/e5f2320ce02973a19563

Echo state network
http://www.scholarpedia.org/article/Echo_state_network

Deep Reservoir Computing
https://etd.adm.unipi.it/theses/available/etd-02282019-191815/unrestricted/Deep_Reservoir_Computing.pdf

9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11