NumPyの行列を用いた記憶シミュレーション

#環境
- CentOS 7.6.1810
- Python 3.6.8
- NumPy 1.17.1

#目的
- Python,及びnumpyに慣れる。
- vimに慣れる。
- プログラミングの書き方を思い出す。
- Qiitaに記事を書いて上げてみる。
- 初心者なりに頑張る。

#内容
numpyの行列計算を用いてニューロンの記憶シミュレーションを行う。
詳しくは[こちら](http://www.gaya.jp/spiking_neuron/matrix.htm)を参照。単純な行列の計算にヘブ則を導入することにより記憶がシミュレート出来るって面白いですよね。

#コード解説
[コード](https://github.com/turunasi/Neuron_Python/)はGitHubで公開しています。

```python:neuron.py
import numpy as np
import modules as m
```
自作ライブラリを使ってみたかったのでNumPy以外にもmodule.pyを作ってimportして来ています。

```python:neuron.py
if __name__ == '__main__':
    main()
```
mainで読み込まれた際にしか動かなくするヤツ(語彙力)

```python:neuron.py
def main () :
    memories = np.array([])
    print("\nThis program is simple memorization model")
    n = int(input("Define the number of neurons:"))
    brain = m.matrix_init(n)
```
生成した記憶を保存する配列**memories**を生成。
ニューロンの数を指定してn次正方行列を生成しこれを記憶させる**脳**とする。この時は空っぽ。

```python:neuron.py
	while True:
		print("\n+----------------------------------------------+")
		print("|1: Make the state of neurons into the memory  |")
		print("|2: Let the brain memorize the memory          |")
		print("|3: Let the brain remember the memory          |")
		print("|4: Check the state of the brain               |")
		print("|5: Check the memories                         |")
		print("|6: Initialize the brain                       |")
		print("|7: Initialize the memories                    |")
		print("|other: quit this program                      |")
		print("+----------------------------------------------+\n")
		cmd = int(input("Please input command:"))
```
構造としてはwhile文の中でループさせてコマンドを入力して各機能に移る。
今回付けた機能は7つ。英弱な英文だけどつまり言いたいことは...
1. ニューロンの状態を入力しそれを元に**記憶**(n次正方行列)を作る。
2. 記憶を選択し回数指定して脳に覚えさせる。
3. 脳にニューロンの状態を思い出させる。
4. 脳の状態を確認。
5. memoriesを確認。すなわち今まで作った記憶を確認。
6. 脳の初期化。
7. memoriesの初期化。

```python:neuron.py
    if cmd == 1:
	neuron = np.zeros(n,dtype=np.int)
	print("\nInput state of each neuron by a integer 1 or -1")
	print("1:active -1:inactive")
	for i in range(n):
		neuron[i] = int(input("State of neuron[%d] :" %i))
	memories = np.append(memories,m.memory(neuron))
	print("\nAdd new memory[{}] into memories".format(len(memories)-1))
```

ニューロンの状態を保存するn次配列を生成し各要素に1か-1の値を入力させる。バリデーション付け忘れているけど…
それからneuronを引数に新しいmemoryを生成しmemoriesに追加。

```python:modules.py
def __init__ (self,neuron):
		self.neuron = neuron
		self.matrix = matrix_from_neuron(neuron)
		self.count = 0
		print("\nThe input states of neurons:\n",self.neuron)
		print("\nMatrix calculated from the neuron:\n",self.matrix)
```

この時生成したmemoryはインスタンス変数として、neuronとそれからヘブ則に沿って作られたn次正方行列memoryと脳に覚えさせた回数countを持つ。

```python:neuron.py
elif cmd == 2:
			if empty_memories(memories):continue
			word = ""
			while (word in "NO No N no n"):
				print("Your created memory is...")
				for i in range(len(memories)):
					print("\nneuron[%d](count:%d) :\n" %(i,memories[i].count),memories[i].neuron)
				selected = int(input("Select memory to memorize:"))
				print("Selected memory is...\n",memories[selected].neuron)
				word = input("Let brain memorize this memory (Y/n):")
			count = int(input("How many times do you want to memorize?:"))
			brain += count*memories[selected].matrix
			memories[selected].count += count
			print("\nThe state of brain is...\n",brain)
```
memoriesが空ならばこの処理を飛ばす。
memoriesの中身を表示し選択させ、指定された回数掛けてbrainに足す(記憶させる)。
一応選択時に確認する機能をつけたけどCLI上でYesNo確認をとるときはどのように判別しているのだろうか…。
筆者はyumを想像しながら作った。

```python:neuron.py
elif cmd == 3:
			if empty_memories(memories):continue
			print("Your created memory is...")
			for i in range(len(memories)):
				print("\nneuron[%d](count:%d) :\n" %(i,memories[i].count),memories[i].neuron)
			print("Input state of each neuron by a integer 1 or -1 or 0")
			print("1:active -1:inactive 0:unknown")
			for i in range(n):
				neuron[i] = int(input("state of neuron[%d] :" %i))
			answer = np.dot(brain,neuron)
			print("The answer is\n",answer)
```
今まで作って来たneuronと記憶させた回数を表示し、それを参考に思い出すneuronの状態を入力。それをbrainに掛けたものを出力。分からないニューロンの状態を0とすることで脳が0を補完することが確認できる。neuron.pyの他の部分は解説してもつまらないので解説しない！

```python:modules.py
def matrix_init (n):
	return np.zeros((n,n),dtype=np.int)

def matrix_from_neuron (neuron):
	n = len(neuron)
	m = matrix_init(n)
	for i in range(n):
		for j in range(n):
			if i == j: continue
			m[i][j] = hebb(neuron[i],neuron[j])
	return m

def hebb (a,b):
	if a == 1 and b == 1: return 1
	return -1
```
この辺でニューロンの状態から記憶を作る。各ニューロンの状態から正方行列の各要素の値をヘブ則に沿って代入していく。3次正方行列の場合のイメージとしては以下の画像のようになっている。
![image of neurons](http://www.gaya.jp/spiking_neuron/matrix05.gif)
詳しくは参考文献みてください(投げやり)
#参考文献
- http://www.gaya.jp/spiking_neuron/matrix.htm
- http://www.sist.ac.jp/~kanakubo/research/neuro/associatron.html

#感想
これを初めて読んだ時行列の積の仕方どころか行列の概念さえ知らなかったけどプログラムとして再現できるのすごい楽しいですね。反省点としては関数名とかコードの書き方、英文法などまだまだです。次は何を作ろうかな〜！