#!/usr/bin/env python
# coding: utf-8
#
# 線形代数の使いどころ
#
#
# cc by Shigeto R. Nishitani
#
#
#
# # Table of Contents
#
#
# 線形代数の使いどころ
#
#
# cc by Shigeto R. Nishitani
#
#
#
# # 線形代数
#
# この頃大学でしかやらない数学の領域の代表例が線形代数です.情報科学の多くの領域で,線形代数はその基本となる概念を提供してくれます.線形代数の概念が身につくと問題の見通しがよくなるんです.
#
# 講義の内容としては,
# * 応用
# * 計算アルゴリズム
# * 概念
#
# というのが必要なのですが,ここでは,「応用例」と「
# 概念を視覚化」する様子を紹介します.
#
# はじめに,エラー訂正符号の計算をして見ましょう.
# # エラー訂正符号
# ## チェック行列
#
# 次の計算をしてみてください.
# $$
# \begin{align}
# H & =
# \left(\begin{matrix}0 & 0 & 0 & 1 & 1 & 1 & 1\\0 & 1 & 1 & 0 & 0 & 1 & 1\\1 & 0 & 1 & 0 & 1 & 0 & 1\end{matrix}\right)
# \\
# v_1 & = \left( \begin{matrix}0\\0\\1\\0\\0\\0\\0\end{matrix}\right)
# \\
# H.v_1 = ?
# \end{align}
# $$
#
# In[1]:
from sympy import *
init_printing()
H=Matrix([[0,0,0,1,1,1,1],[0,1,1,0,0,1,1],[1,0,1,0,1,0,1]])
H
# In[2]:
v_e=Matrix([0,0,1,0,0,0,0])
v_e
# In[3]:
H.dot(v_e)
# ## エラー検出の原理
#
# これはハミングが見つけた,エラーを見つけるチェック行列と呼ばれています.
#
# 例えばAからBへコードワード$v_{code}$を送った時に,仮に一箇所エラー$v_{error}$が入ったとします.Bが受け取る信号$v_{signal}$は
# $
# v_{signal} = v_{code} + v_{error}
# $
# となるわけですが,これを$H$に通すと自動的にその場所を特定してくれるわけです.
#
# その条件は
# > もし,$H.v_{code}=0$ならば
#
# です.
#
# ## Hammingの生成行列(generator matrix)
# $H.v_{code}=0$となる$v_{code}$(コードワードと呼ばれます)を生成するHammingの生成行列(generator matrix)は
# $$
# G= \left(\begin{matrix}1 & 0 & 1 & 1\\1 & 1 & 0 & 1\\0 & 0 & 0 & 1\\1 & 1 & 1 & 0\\0 & 0 & 1 & 0\\0 & 1 & 0 & 0\\1 & 0 & 0 & 0\end{matrix}\right)
# $$
#
# です.例えば,送りたい信号
# $v_{orig}=[1,0,0,1]$だとすると,
# これを$G$に通して出てきたコードワード$v_{code}$を
# さらに$H$に通すと零ベクトルとなります.
#
# このようにある行列に作用させた時に零ベクトルとなる
# ベクトルの作る空間をヌルスペース(null space)と呼びます.
# In[4]:
G=Matrix([[1,0,1,1],
[1,1,0,1],
[0,0,0,1],
[1,1,1,0],
[0,0,1,0],
[0,1,0,0],
[1,0,0,0]])
G
# In[5]:
v_1 = Matrix([1,0,0,1])
v_1
# In[6]:
G.dot(v_1)
# In[7]:
Matrix([2,2,1,1,0,0,1])
# In[8]:
H.dot(Matrix([0,0,1,1,0,0,1]))
# ## GF(2)
# おっと,一つ計算上のルールを忘れていました.
# ここの計算では$GF(2)$上の算術とします.
# $GF(2)$での算術をまとめると
#
# |$\times$|0|1|
# |:----:|:---:|:---:|
# |0| 0| 0|
# |1| 0| 1|
#
# |$+$|0|1|
# |:----:|:---:|:---:|
# |0| 0| 1|
# |1| 1| 0|
#
# となります.要素は0と1だけの体です.
# GF(2)は2元ガロア体(Galois Field 2)の略で,
# 20歳で早世した抽象代数の基礎を築いたGaloisにちなんでいます.
#
# なので,上の行列計算で1以上が出た時には,2で割ってそのあまりを考えることになります.
# # Deep Learning
# 深層学習という手法によって
# 「AIが目を手に入れた」
# と評されています.
#
# 画像認識のトライアルとしてよく例示される手書き数字認識で,deep learningで何をしているかを実感してもらおうと思います.ここでの記述と関数は「ゼロから作るDeep Learning――Pythonで学ぶディープラーニングの理論と実装」斎藤 康毅 著,(Oreilly Japan 2016)によります.
#
# ## 手書き数字認識(MNIST)
#
# [mnist](http://yann.lecun.com/exdb/mnist/)によると,nistが提供していたhand writingのDBとしてspecial database 3とspecial database 1というのがあって,SD-3はCensus Bureauの雇用者からSD-1はJunior high schoolの学生からあつめたもので,そこには認識率におおきな差があったのだって.それらを混ぜ合わせた,training setとtest setとして新たに提供されたのが,mixing NIST's datasetsからこの呼び名がついたって.
# ## load_mnist
# In[9]:
import sys, os
sys.path.append(os.pardir)
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = \
load_mnist(flatten=True, normalize=False)
print(x_train.shape)
# 本に書いてあるcodeではjupyterで表示しなかったので,
# http://biopython.seesaa.net/article/451770389.html
# に従って修正.
# In[11]:
# coding: utf-8
get_ipython().run_line_magic('matplotlib', 'inline')
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
import matplotlib.pyplot as plt
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))
plt.imshow(np.array(pil_img))
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
for i in [8]:
img = x_test[i]
label = t_test[i]
print(label)
img = img.reshape(28, 28)
plt.imshow(img, cmap='gray')
# ## neuralnet_mnist
#
# sample_weight.pklをch03からcpしておく必要あり.
#
#
# In[12]:
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
return x_test, t_test
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
def predict(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
a3 = np.dot(z2, W3) + b3
y = softmax(a3)
return y
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p= np.argmax(y) # 最も確率の高い要素のインデックスを取得
if p == t[i]:
accuracy_cnt += 1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
# 何をするかをみるため,最後尾の駆動部を変更している.
# 最初の10データに対して,それぞれ数字の確率と,実際の数字を表示している.
#
# 例えば,一つ目のデータでは,7の確率が0.9971で,実際の字も7である.
#
# predictがやっていることを見ればいいが,単に行列の積を計算しているだけ.それで予測ができるとさ.だから,中間層を表す行列の要素さえただしく決定できればそれでニューラルネットは終わり!!
# In[13]:
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(10):
y = predict(network, x[i])
print("No:{}, Ans:{}".format(i,t[i]))
print("Guess",['{:.2f}'.format(n) for n in y])
# In[ ]: