リザバー（Reservoir）に意識は宿るか？（記憶、概念獲得、判断、予測）

| 推論グラフ<br>（-0.5 * Sin） |予測グラフ<br>（Sin）|予測動画<br>（車載カメラ）|
|:-----------------:|:------------------:|:------------------:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/0ebb7323-e3ef-5ea8-3ddc-740d55e54669.png)| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/a47c067b-47db-2953-e3f5-e2e226d75ca1.png)|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/0fceb1e0-6724-477a-49a4-8e4ae0353140.png" width=500>|

右端にある**車載カメラの予測動画**は、YouTube でご覧ください。(https://youtu.be/H15aRAFRBbk)

# はじめに

注目されているリザバーコンピューティング（RC：Reservoir Computing　貯水池計算）を、Python で動かしてみました。

リザバーコンピューティングの特徴は、

- 汎用的（**RNN：再帰型ニューラルネットワーク**）
- 計算量が少ない（学習、推論）
- シンプル

RNNなので**リザバーに意識が宿る**ような気がしてきます。

# やりたいこと

リザバーの感触を得るため、**意識のベース**であるつぎの課題を行う。

1. **記憶**：入力したデータを記憶して、遅延時刻後に出力できるか
1. **概念獲得**：加算、積算の概念を獲得し、２つの入力を加算、積算して出力できるか
1. **判断**：入力したデータが指定した範囲にあるか判断できるか
1. **予測**：入力したデータから、次時刻の入力を予測できるか。（**Sin関数の予測、カメラ画像の予測**）

本資料では各課題をリザバー上で動かして行きます。

意識とはなんだろう？　**仏教的には意識は幻想らしい。**

# 記憶
リザバーコンピューティングは、RNNの一種なので記憶ができそうです。
学習ではランダムデータを入力と、遅延時間後の教師データとして使いました。
学習後のテスト結果を次に示します。

**太字部分**が注目したい箇所です。

| データ種別|各時刻のデータ(t=1,2,3,...)|正解数|備考（少数１位） | 
|:-----------------:|:------------------|:------------------:|:------------------:|
| **入力**| **2, 0, 7, 4, 6** ||記憶するデータ。全正解数は**5**。   
| 出力<br>遅延**０**|**2, 0, 7, 4, 6**, 5, 5, 3, 3, 9|**5**|**1.9, -0.3, 7.1, 4.3, 6.2**, -0.1, 5.3, 2.9, 3.1, 8.6|
| 出力<br>遅延**１**|3, **2, 0**, 8, **4, 6**, 0, 5, 3, 3| **4**
| 出力<br>遅延**２**|8, 3, **2**, 1, 8, **4**, 7, 0, 5, 3| **2**
| 出力<br>遅延**３**|8, 7, 3, **2, 0, 7**, 5, **6**, -1, 4|**4** |8.1, 7.3, 3.3, **2.5, 0.5, 7.3**, 4.7, **6.3**, -0.8, 4.1|

遅延しても、不完全ですが記憶があるようです。
遅延０でみると、整数データでは完全に入力が再現できています。しかし、**整数化前の小数データでは値が揺れています。**
出力データが不一致の場合でも、**正解との差は１**にとどまっています。

入力と教師のデータは、つぎのように作成しました。

```python:記憶学習の入力と教師データ
    in_data = (1.0 * np.random.randint(0,10,NUM_TIME_STEPS)).reshape(-1, 1)  
    out_data = np.concatenate([np.array([[0]] * delay), in_data]) if delay > 0 else in_data
```

薄れゆく記憶、愛していたのかも 思い出せない　♬ ♩ ♬
# 概念獲得
加算と積算の概念を獲得できるか確かめます。

### 加算

学習では、２個のランダムデータを入力に、和を教師データとして使いました。
学習後の、テスト結果を次に示します。

| データ種別|加算データ|正解数|備考（少数１位） | 
|:-----------------:|:------------------:|:------------------:|:------------------:|
| 入力| **[2, 4], [0, 6], [7, 1], [4, 3]**, [6, 3]||全正解数は5| 
| 出力|**[6], [6], [8], [7]**, [10]|**4**|**[6.0], [5.8], [8.3], [7.1]**, [9.5]| 
最後だけ加算がうまくいっていません。正解は9（=6+3）ですが、10と推論しています。

入力と教師のデータは、つぎのように作成しました。

```python:加算学習の入力と教師データ
    fn = lambda x,y: x + y
    in1 = 1.0 * np.random.randint(0, 10, NUM_TIME_STEPS)
    in2 = 1.0 * np.random.randint(0, 10, NUM_TIME_STEPS)
    in_data = np.array(list(zip(in1, in2)))
    out_data = np.array([[fn(x ,y)] for (x, y) in zip(in1 ,in2)])  
```

### 積算
学習では、sinデータを入力に、教師データを**-0.5とsinデータの積**にしました。
学習中のデータ、学習後のテスト結果を次に示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/0ebb7323-e3ef-5ea8-3ddc-740d55e54669.png)

入力と教師のデータは、つぎのように作成しました。

```python:積算学習の入力と教師データ
    fn = lambda x: -0.5 * x
    seed_fn = np.sin
    in_data = (AMPLITUDE * seed_fn(np.linspace(0, T, NUM_TIME_STEPS))).reshape(-1,1)
    out_data = fn(in_data)
```

# 判断
学習ではランダムデータを入力に、教師データとして5以上では１、そうでない場合はゼロを使いました。


| データ種別|データ|正解数|備考（少数１位） | 
|:-----------------:|:------------------:|:---:|:------------:|
| 入力| **2 0 7 4 6 0 5 3 3 9** ||全正解数は10|
| 出力| **0 0 1 0 1 0 1 0 0 1**| **10** |**-0.1, -0.4, 0.8, 0.4, 0.8, -0.2, 0.5, 0.4, 0.3, 1.0**|

簡単な判断ならできそうです。

入力と教師のデータは、つぎのように作成しました。

```python:判断学習の入力と教師データ
    fn = lambda x: 1. if 5 <= x else 0.
    in_data = (1.0 * np.random.randint(0, 10, NUM_TIME_STEPS)).reshape(-1, 1)
    out_data = np.array(list(map(fn, in_data))).reshape(-1, 1)
```

# 予測

### スカラー値の予測
学習ではsinデータを入力に、教師データとして次時刻のsinデータを使いました。
つぎのグラフでは、推論で予測した出力を、次時刻の入力として使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/a47c067b-47db-2953-e3f5-e2e226d75ca1.png)

時間が経過するにつれて、予測が正解からずれていきます。

入力と教師のデータは、つぎのように作成しました。

```python:スカラー値予測学習の入力と教師データ
    seed_fn = np.sin   
    in_data = (AMPLITUDE * (seed_fn(np.linspace(0, T, NUM_TIME_STEPS)))).reshape(-1, 1)
    out_data = in_data[1:]
```
### 画像の予測

学習では車載カメラによる画像を入力に、教師データとして次時刻の画像を使いました。
映像データは、「KITTI による車載カメラの映像」http://www.cvlibs.net/datasets/kitti/raw_data.php
を、サイズ変更して使いました。

学習後のテストデータにて、リザバーから出力した動画は、YouTube でご覧ください。(https://youtu.be/H15aRAFRBbk)
車の動きが、かろうじて分かります。

リザバーから、画像を出力できるようです。（学習時のデータでは、鮮明な画像が出てきます。）

 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/0fceb1e0-6724-477a-49a4-8e4ae0353140.png" width=350>

入力と教師のデータは、つぎのように作成しました。

```python:画像予測学習の入力と教師データ
    in_data =　各時刻画像のリスト
    out_data = in_data[1:]
```
### 「画像の予測」パラメータ
　
入力画像サイズ＝出力画像サイズ： 128*128
リザバーノード数： 16384　（=128*128）
入力ノード数＝出力ノード数： 16384　（=128*128）
学習画像数：220
学習後のテスト画像数：147
全計算時間：パソコンで30分程度
（リザバー初期化時の「重み行列(16384,16384)」の固有値計算で２０分程度かかるようです）

# Pythonプログラム
「ゼロから作るReservoir Computing」
https://qiita.com/pokotsun/items/dd8eb48fadeee052110b
に、記載されている **Echo State Network** を参考にしました。
このプログラムは **numpy だけの実装**に挑戦していて、とても役立ちました。

将来的には Echo State Network に**バイアス $b$** の概念を入れて、学習能力の変化を調べたい。
具体的には、**状態の更新 $x(t)$**、**出力の計算 $z(t)$** をつぎのようにします。$\delta$は漏れ率です。

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

z(t) = W_{out}x(t) + b_{out}\\
```


# おわりに
テストの結果、**(1)記憶、(2)概念獲得、(3)判断、(4)予測** は不完全ですが、能力はありそうです。

リザバー実行時のパラメータを次に示します。


|       |カメラ画像の予測 |  それ以外     |備考
|:-----------------:|:------------------:|:------------------:|:------------------:|
| ノード数         |              16384 |      150        |
| 計算時間         |              30分 |        数秒        |　パソコンCPU
| 学習データ数      |             220 |        959       |



リザバーはつぎの点で魅力的です。


- **計算量が少ない**
- **RNNで汎用的**
- **少ないデータ数でもそれなりに学習する**


また、つぎの分野が面白そうです

- リアルタイム学習
- 音声認識と言語モデル
- 複数リザバーのネットワークなど

生物の個体発生では、自然に意識が宿るようです。
**いつか、リザバーも自然に意識を宿すか？**

# 参考資料
ゼロから作るReservoir Computing
https://qiita.com/pokotsun/items/dd8eb48fadeee052110b

リザバーコンピューティングの概念と最近の動向　田中剛平　電子情報通信学会誌 Vol.102, No.2, 2019
http://eeip.t.u-tokyo.ac.jp/gtanaka/siryo/tanaka201902_ieice.pdf

ちょっと変わったニューラルネットワーク Reservoir Computing
https://qiita.com/kazoo04/items/71b659ced9dc0342a2b0

Echo state network　Herbert Jaeger, Jacobs University Bremen, Bremen, Germany
http://www.scholarpedia.org/article/Echo_state_network

最小二乗法の解の導出
https://www.iwanttobeacat.com/entry/2018/01/13/221840

sklearn.linear_model.LinearRegression
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html
　
解明される意識 1997/12/1　ダニエル・C. デネット 
https://www.amazon.co.jp/dp/4791755960/ref=cm_sw_em_r_mt_dp_U_3MCaEbZCNCF3X