研究室のドアの鍵は空いているか？〜それ、めんどくさいから機械学習の画像処理七つ道具に任せよう〜ver.2


#さあ、実装しよう。
画像処理には様々な種類の方法がありますが、先程のものは動体検出と呼ばれる手法のものです。
検出するということは、動画や画像から、これがそうなんじゃないの？という候補を出してくれるわけです。
今度はそれらが正しいかの判断をさせるプログラムを実装します。<b>そう、機械学習でね。</b>

#さっきのが本編じゃないのかよ！！騙された！！
私が使おうと思っているのは教師あり学習です。それらの判断をYes/Noで返してくれる、二項分類器を作ります。
これから本編です。画像処理にもいろいろ種類がありますが、勉強した内容で使うのは、こちらにしました。

#戸惑った点～機械学習の基本を知るために～
##機械学習の気持ちにならないといけない
機械学習は人間が見抜けないところを見抜くのが真髄です。しかし、機械で判断できないものもあります。

* データセットの中で判断がつかないものを入れてしまった場合
* 法則性の無いデータセットを作ってしまった場合

### 判断がつかないものをデータセットに入れてしまった場合
二項分類器は、Yes/Noで答えます。しかし、NoのデータにYesに似ているデータが入ったとしましょう・・・そう、例えばカスケード分類機が検出してしまったデータとかね・・・人間がみて明らかに違うだろうと思ったものでも機械では判断できないものもあります。（解決策を別で取れるかもしれませんが、もしご存知の方がいらっしゃれば教えてください・・・）

###法則性の無いものをデータセットに入れた場合
Yes/Noで返してくれるということを、誤解していると（私も誤解していました。）このパターンに陥ります。
Yes(鍵がかかっている。)No(掛かっていない)それぞれに鍵が空いた画像、しまった画像を入れてみましょう。しかし、他のマンションの鍵などの画像が入ったらどうでしょうか・・・？チェーンが掛かってることを認識させるために画像を混ぜますか？答えはNoです。機械学習は、数式を最適化するためのものですので、なにか全く関係ないデータをデータセットとして用いた場合、数式を最適化できません。気をつけましょう。

###データセットを格納して、活用しよう。
データセットを活用できるように整頓しましょう。フォルダを用意すれば簡単です。

* Dataset/0
* Dataset/1

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/ffc3e11f-4dc4-7fb3-1fb8-8c407aeebb9f.png)



と作ればOKです。DataSetを予め作って、その中にフォルダー0と、1を入れてくださいね！！
で、どうやってデータを取り出して行くのか・・・ですが、notMNISTというデータセットを取り込む際に、取り込み用のコードが有り、それらの読み出し方を真似て作ることで、データセットを自作して、取り込むことができます。
これらを改変して、コードを以下のように作りました。

[めもめも](http://enakai00.hatenablog.com/entry/2016/08/02/102917)

```Python
class Dataset:
    def __init__(self):
        images, labels = [], []

        for i, letter in enumerate(['0', '1']):
            directory = '(Datasetまでの絶対パス)/Dataset/%s/' % letter
            files = os.listdir(directory)
            label = np.array([0]*2)
            label[i] = 1
            i = 0
            for file in files:
                try:
                    img = cv.imread(directory+file)
# 画像を28*28のイメージに変換
                    img = cv.resize(img,(28,28))
#Pythonの画像の取り込みはBGRが基本のため、RGBに変換する。
                    img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
                    images.append(img.flatten().astype(np.float32)/255.0)
                except:
                    print ("Skip a corrupted file: " + file)
                    continue
                labels.append(label)
            train_images, test_images, train_labels, test_labels =train_test_split(images, labels, test_size=0.2, random_state=0)
        
        class train:
            def min_max_normalization(self,r_m):
                x_min = r_m.min()
                x_max = r_m.max()
                x_norm = (r_m - x_min) / (x_max - x_min)
                return x_norm
            
            def __init__(self):
                self.images = []
                self.labels = []
                self.batch_counter = 0
                
            def next_batch(self, num):
                if self.batch_counter + num >= len(self.labels):                    
                    rd.shuffle(images)
                    rd.shuffle(labels)
                    batch_images = self.images[self.batch_counter:]
                    batch_labels = self.labels[self.batch_counter:]
                    left = num - len(batch_labels)
                    batch_images.extend(self.images[:left])
                    batch_labels.extend(self.labels[:left])
                    self.batch_counter = left
                else:
                    batch_images = self.images[self.batch_counter:self.batch_counter+num]
                    batch_labels = self.labels[self.batch_counter:self.batch_counter+num]                  
                    self.batch_counter += num
                
                batch_images_std = batch_images
                c = 0
                for c in range(num):
                    batch_images_std[c] = self.min_max_normalization(batch_images_std[c])
                    c+=1
                return (batch_images_std, batch_labels)
                    
        class test:
            def __init__(self):
                self.images = []
                self.labels = []
                self.batch_counter = 0
            def min_max_normalization(self,r_m):
                x_min = r_m.min()
                x_max = r_m.max()
                x_norm = (r_m - x_min) / (x_max - x_min)
                return x_norm

            def next_batch(self, num):
                if self.batch_counter + num >= len(self.labels):                    
                    rd.shuffle(images)
                    rd.shuffle(labels)
                    batch_images = self.images[self.batch_counter:]
                    batch_labels = self.labels[self.batch_counter:]
                    left = num - len(batch_labels)
                    batch_images.extend(self.images[:left])
                    batch_labels.extend(self.labels[:left])
                    self.batch_counter = left
                else:
                    batch_images = self.images[self.batch_counter:self.batch_counter+num]
                    batch_labels = self.labels[self.batch_counter:self.batch_counter+num]                  
                    self.batch_counter += num
                
                return (batch_images, batch_labels)
        
        self.train = train()
        self.test = test()
                
        self.train.images = train_images
        self.train.labels = train_labels
        self.test.images = test_images
        self.test.labels = test_labels
```
そして、今度はちょっと数学になります。機械学習の基本は、以下の参考書に載っているかと思われますので、ぜひとも確認してください・・・

mnistという値をセットし、その中で呼び出せるようにします。

```Python
mnist = Dataset()
```

次にモジュールをimportします。

```Pyhton
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import numpy.random as rd

from scipy.misc import imread

import matplotlib.pyplot as plt
```

モジュールが見つからない場合は、Anaconda Navigatorでインストールをかけましょう。
これらの内容を小分けにしていき、JupyterNotebookで実行することがおすすめです。

```Python
# In[14]:


CHANNELS = 3
NUM_CLASSES = 3
IMAGE_SIZE = 28
IMAGE_MATRIX_SIZE = IMAGE_SIZE * IMAGE_SIZE * CHANNELS
num_units = 1024

# プレースホルダーの設定
x = tf.placeholder(tf.float32,[None, IMAGE_MATRIX_SIZE])
w1 = tf.Variable(tf.truncated_normal([IMAGE_MATRIX_SIZE, num_units]))
b1 = tf.Variable(tf.zeros([num_units]))
hidden1 = tf.nn.relu(tf.matmul(x, w1)+b1)

w0 = tf.Variable(tf.zeros([num_units,2]))
b0 = tf.Variable(tf.zeros([2]))
p = tf.nn.softmax(tf.matmul(hidden1, w0) + b0)


# In[15]:


t = tf.placeholder(tf.float32, [None, 2])
loss = -tf.reduce_sum(t * tf.log(p))
train_step = tf.train.AdamOptimizer().minimize(loss)
correct_prediction = tf.equal(tf.arg_max(p, 1), tf.arg_max(t, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


# In[16]:


sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
```
##変数解説
x=>画像の値を格納(画像が配列の集まりという概念)
w1=>最適化実施のためのパラメーター（隠れ層１層目）
　＝＞乱数を格納することで初期値を入れてる点に注意。隠れ層の係数は乱数で初期化する必要があるため。
b1=>最適化用の変数を格納（パターンを学ばせる）（まちがっていたらすみません）
hidden1=>隠れ層（判断を行うための領域の数式を格納）

w0=>隠れ層から得た、最適化実施のためのパラメータ（出力層の一次関数の係数）
b0=>隠れ層から得た値の定数項（１次関数で最適化する、定数項にあたる）

p=>ソフトマックス関数という関数で、どちらかを判断させるための数式

学習させるセクションはこちらになります。

```Python
i=0
loss_vals, acc_vals = [], []

for _ in range (2000):
    i+=1
    batch_xs, batch_ts = mnist.train.next_batch(50)
    sess.run(train_step,feed_dict={x:batch_xs, t: batch_ts})
    loss_vals, acc_vals = sess.run([loss,accuracy],feed_dict={x:batch_xs,t:batch_ts})
    time.append(i)
    
    if i % 500 == 0:
        for c in range(4):
            start = len(mnist.test.images) // 4 * c
            end = len(mnist.test.images) // 4 * (c+1)
            loss_vals, acc_vals = sess.run([loss,accuracy],feed_dict={x:mnist.test.images[start:end],t:mnist.test.labels[start:end]})
        loss_val_sum = np.sum(loss_vals)
        acc_val_sum = np.mean(acc_vals)
        print('Step: %d, Loss:%f, Accuracy: %f' 
                % (i, loss_val_sum, acc_val_sum))
saver.save(sess, '(同一ディレクトリ)/learn_result_1cell_ver1.7.2-2000', global_step=i)
```

##動作解説
###batch_xs,batch_ts
クラスで定義した,mnistの値を呼び出し、トレーニングデータ（画像）と、トレニングデータ（ラベル）をそれぞれ格納します。それぞれのデータを呼び出しますが、（）は呼び出す数を表しています。格納したデータは、最後まで来ると、最初に折り返してくれます。しかし、折り返す際に同じ並びになってはいけないので、（式の最適化にならない）それらをシャッフルします。
シャッフルする際にも気をつけたいのは、ただランダムにシャッフルできないことです。配列で格納されてる状態ですので、処理を分離させてしまうと、ランダムに画像と、ラベルが符合しない可能性があります。そこで、２つの方法があります。

* Zipで一度すべて同じ配列にして、シャッフルしていく、そしてまた格納し直す
* シャッフルシードを用意して、同じふうにシャッフルする

最初の方法のほうがシャッフルされることは確実ですが、２つ目の手法がうまく行けば、処理は２行で済みそうです。ということで、先程の実装下部が以下のようになりました

```Python
            def next_batch(self, num):
                if self.batch_counter + num >= len(self.labels):                    
                    rd.shuffle(images)
                    rd.shuffle(labels)
                    batch_images = self.images[self.batch_counter:]
                    batch_labels = self.labels[self.batch_counter:]
                    left = num - len(batch_labels)
                    batch_images.extend(self.images[:left])
                    batch_labels.extend(self.labels[:left])
                    self.batch_counter = left
```

shuffleだけで完了しますので、非常に手軽です。シャッフルする際には、シードを設定しましょう。
インポートも忘れずに！！

```Python
import numpy.random as rd
np.random.seed(好きな数)
```

###sess.run(train_step,feed_dict={x:batch_xs, t: batch_ts})
トレーニングセットで、演算をし誤差を縮めるために、繰り返し行います。train_stepは宣言した関数です。

```Python
train_step = tf.train.AdamOptimizer().minimize(loss)
```
これで学習させるセクションができました

###ifのセクションについて

```Python
    if i % 500 == 0:
        for c in range(4):
            start = len(mnist.test.images) // 4 * c
            end = len(mnist.test.images) // 4 * (c+1)
            loss_vals, acc_vals = sess.run([loss,accuracy],feed_dict={x:mnist.test.images[start:end],t:mnist.test.labels[start:end]})
        loss_val_sum = np.sum(loss_vals)
        acc_val_sum = np.mean(acc_vals)
        print('Step: %d, Loss:%f, Accuracy: %f' 
                % (i, loss_val_sum, acc_val_sum))
```
このセクションは、テストデータを格納します。もともと、このデータたちはクラスの記述の中にありますが、トレーニングデータで不要なデータを学習しないように、あえて全体からデータを分割します。その２分割されたデータがトレーニングデータと、テストデータというわけですね。それらを、500回に一回、テストデータを格納して、正解率と、損失をみます。
そうして、正解率が90％を超えたなら、成功です。

##やった！100％だ！
100％おめでとうございます。しかし、100％という数字はなかなか出るものではありません。実際のデータの判断や、分布を見たほうがいいでしょう。まずはこのようなグラフを作ってみましょう。

```Python
#日本語フォントをこれで適用できます。
from matplotlib.font_manager import FontProperties
fp = FontProperties(fname=r'C:/Windows/Fonts/HGRGM.TTC', size = 14)

#テストセットはこれで全部取り出せます。
images, labels = mnist.test.images, mnist.test.labels

p_val = sess.run(p, feed_dict={x:images})

#p_valを縦にスライス
test_data = p_val[:,:2]
fig = plt.figure(figsize=(6, 6))
subplot = fig.add_subplot(1,1,1)
subplot.set_ylim([0.0, 1.0])
subplot.set_xlim([0.0, 1.0])

# マーカーの配置
subplot.scatter(test_data[:,1:],test_data[:,:1] , marker = 'x',label = "テストデータの演算結果{}".format(len(test_data)))

#x,y軸の準備
plt.suptitle(u'隠れ層単層による分類器',fontproperties=fp)
plt.title(u'テストセット{}点'.format(len(test_data)),fontproperties=fp)
plt.xlabel(u'と判定',FontProperties=fp)
plt.ylabel(u'と判定しない',FontProperties=fp)
plt.legend(prop=fp, loc='upper right')
plt.grid(True)

x_line = np.arange(-10, 11 ,1)
x_line_one=[0.5 for i in range(21)]
subplot.plot(x_line, x_line_one , color='blue')
subplot.plot(x_line_one, x_line , color='blue')
fig.savefig('(グラフを保存したいディレクトリ名)/figure_train_and_test_set_plot_onecell.png')
```

どのような結果になりましたか？

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/31147936-47fe-42bb-475b-329c041281d3.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/5c5473d1-df00-d960-7d7c-753b069282b5.png)

データの内容はお見せできませんが・・・2項分類機は、最大値を1として、「こっちっぽいな」というのを振り分けています。
0.5以上であれば、それと判定したわけです。一枚目を見てください。

学習器A「どっちとも言えない」
学習器B「ぜんぶこれだよ！！」

どっちも実践に用いたら大変なことになりますね。どうしてこうなったのでしょう・・・
基本を理解してなかった私は、以下の原則がわかってなかったわけですね。

そうです、<b>学習器の気持ちになれてなかったわけですね</b>(今もあやふやなところ多いですが)

データに格納するものを選定しなければなりません。データセットを見直してみましょう。
ちなみに、データセットの数はもちろん、これらの学習器に大きな影響を与えることは間違いありません。
不正解のデータの数を多くしてみて、もし分数と、正答率が一致したら、データセットが悪いのではないかと疑いましょう。

ちなみに、グラフで、こういうグラフになりましたら、これはきちんと判断できているということなので、大丈夫です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/6090c335-2efb-bdd6-b2a7-8a3603889611.png)

きちんと二分化されていることがわかります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/f7c12260-b791-9463-1149-b14ec30ee64e.png)
このような場合、正答率が100％になってしまうこともあります。

#12月16日追記
この方法では、機械がどのように判断したかは理解できますが、判断したものが正解なのか、正解でないのかという判断ができません。そのため、<b>混同行列</b>をつくったほうがよさそうです。その話についてはまた後程書こうかと思います。

しかし、個々の画像を見ることはできません。そこで、このような実装を行います。（参考文献：TensorFlowで学ぶディープラーニング）

##画像がそれぞれ判断した内容を参照してみる
```Python
batch_xs, batch_ts = mnist.test.next_batch(100)          
fig = plt.figure(figsize=(12,10))

i = 0
x_edit = []
c=0
for t in range(2):
    for i in range(25):
        for c in range(25):
                for (image, label) in zip(mnist.test.images,mnist.test.labels):
                    x_tmp = np.reshape(image,(-1,2352))
                    x_edit.append(x_tmp)
            p_val_t = sess.run(p_val_t, feed_dict={x:x_edit[i]})
            subplot = fig.add_subplot(5,5,c+1)
            image = batch_xs[i]
            pred = p_val[0]
            subplot.set_title('%d/%d' % (np.argmax(pred),np.argmax(batch_ts[i])))
            subplot.imshow(image.reshape(((28,28,3))), vmin=0, vmax=1,cmap = 'gray_r', interpolation='nearest')

fig.savefig('(グラフを保存したいディレクトリ)/figure_testset_images_onecell.png')
```

すると、このような風に画像が表示されます・・・
![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/70f56d48-a3bd-2cd8-2a00-2f4bd090f132.png)

こちらの画像は、MNIST（手書き文字の認識のためのデータセット）で同じようなプログラムを実行した結果です。
左の値が、機械学習が予想した値、（これの場合、二項分類機ではなく、多項分類機なので悪しからず）右が、実際の値（ラベルの配列から取得した値）です。こちらの場合、3度for文を使っているのは、シャッフルの効果が実際にあるのかを検証するためです。

では、お次に、それぞれの画像が、どのように判断されたのかを見ていきましょう。

```Python
batch_xs, batch_ts = mnist.train.next_batch(50) 
p_val = sess.run(p, feed_dict={x:batch_xs, t:batch_ts})
fig = plt.figure(figsize = (8,15))
for i in range(10):
    c = 1
    for (image, label, pred) in zip(mnist.train.images, mnist.train.labels, p_val):
        prediction, actual = np.argmax(pred), np.argmax(label)
        if prediction != i:
            continue
        if (c < 16  and i == actual) or (c >= 4 and i != actual):
# 不正解画像の表示
#         if prediction != actual:
            subplot = fig.add_subplot(10,6,i*6+c)
            subplot.set_xticks([])
            subplot.set_yticks([])
            subplot.set_title('%d/%d' % (prediction,actual))
            subplot.imshow(image.reshape(28,28,3), vmin=0, vmax=1,cmap=plt.cm.gray_r, interpolation="nearest")
            c += 1
        if c > 24:
            break
```
実行結果は以下のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/0b5d2828-7cfa-fb4e-be3c-451d542db4ab.png)

このように機械学習がなんでこのように判断したのかの詳細を見ることができるわけですね。便利な方法なので、覚えておきましょう。
こういった統計を見ながら、データセットの調整を行うことで、効率がよく、良い学習器ができます。

最後に完成したコードを一例としてあげておきます。

```Python
# coding: utf-8

# In[5]:


import numpy as np
from sklearn.model_selection import train_test_split
from PIL import Image
import cv2 as cv
import os
import numpy.random as rd
from sklearn.preprocessing import StandardScaler
sc =StandardScaler()

np.random.seed(1996)

class NotFaminist:
    def __init__(self):
        images, labels = [], []

        for i, letter in enumerate(['0', '1']):
#ディレクトリは各々で作ってください。
            directory = 'dataset/%s/' % letter
            files = os.listdir(directory)
            label = np.array([0]*2)
            label[i] = 1
            i = 0
            for file in files:
                try:
                    img = cv.imread(directory+file)
                    img = cv.resize(img,(28,28))
                    img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
                    images.append(img.flatten().astype(np.float32)/255.0)
                except:
                    print ("Skip a corrupted file: " + file)
                    continue
                labels.append(label)
            train_images, test_images, train_labels, test_labels =train_test_split(images, labels, test_size=0.2, random_state=0)
        
        class train:
            def min_max_normalization(self,r_m):
                x_min = r_m.min()
                x_max = r_m.max()
                x_norm = (r_m - x_min) / (x_max - x_min)
                return x_norm
            
            def __init__(self):
                self.images = []
                self.labels = []
                self.batch_counter = 0
                
            def next_batch(self, num):
                if self.batch_counter + num >= len(self.labels):                    
                    rd.shuffle(images)
                    rd.shuffle(labels)
                    batch_images = self.images[self.batch_counter:]
                    batch_labels = self.labels[self.batch_counter:]
                    left = num - len(batch_labels)
                    batch_images.extend(self.images[:left])
                    batch_labels.extend(self.labels[:left])
                    self.batch_counter = left
                else:
                    batch_images = self.images[self.batch_counter:self.batch_counter+num]
                    batch_labels = self.labels[self.batch_counter:self.batch_counter+num]                  
                    self.batch_counter += num
                
                batch_images_std = batch_images
                c = 0
                for c in range(num):
                    batch_images_std[c] = self.min_max_normalization(batch_images_std[c])
                    c+=1
                return (batch_images_std, batch_labels)
                    
        class test:
            def __init__(self):
                self.images = []
                self.labels = []
                self.batch_counter = 0
            def min_max_normalization(self,r_m):
                x_min = r_m.min()
                x_max = r_m.max()
                x_norm = (r_m - x_min) / (x_max - x_min)
                return x_norm

            def next_batch(self, num):
                if self.batch_counter + num >= len(self.labels):                    
                    rd.shuffle(images)
                    rd.shuffle(labels)
                    batch_images = self.images[self.batch_counter:]
                    batch_labels = self.labels[self.batch_counter:]
                    left = num - len(batch_labels)
                    batch_images.extend(self.images[:left])
                    batch_labels.extend(self.labels[:left])
                    self.batch_counter = left
                else:
                    batch_images = self.images[self.batch_counter:self.batch_counter+num]
                    batch_labels = self.labels[self.batch_counter:self.batch_counter+num]                  
                    self.batch_counter += num
                
                return (batch_images, batch_labels)
        
        self.train = train()
        self.test = test()
                
        self.train.images = train_images
        self.train.labels = train_labels
        self.test.images = test_images
        self.test.labels = test_labels


# In[6]:


mnist = NotFaminist()


# In[8]:


#  必要な素材の収集
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# from __future__ import division
import sys, os, pickle
import numpy.random as rd

from numba import jit

from scipy.misc import imread

import matplotlib.pyplot as plt



# In[14]:


CHANNELS = 3
NUM_CLASSES = 3
IMAGE_SIZE = 28
IMAGE_MATRIX_SIZE = IMAGE_SIZE * IMAGE_SIZE * CHANNELS
num_units = 1024

# プレースホルダーの設定
x = tf.placeholder(tf.float32,[None, IMAGE_MATRIX_SIZE])
w1 = tf.Variable(tf.truncated_normal([IMAGE_MATRIX_SIZE, num_units]))
b1 = tf.Variable(tf.zeros([num_units]))
hidden1 = tf.nn.relu(tf.matmul(x, w1)+b1)

w0 = tf.Variable(tf.zeros([num_units,2]))
b0 = tf.Variable(tf.zeros([2]))
p = tf.nn.softmax(tf.matmul(hidden1, w0) + b0)


# In[15]:


t = tf.placeholder(tf.float32, [None, 2])
loss = -tf.reduce_sum(t * tf.log(p))
train_step = tf.train.AdamOptimizer().minimize(loss)
correct_prediction = tf.equal(tf.arg_max(p, 1), tf.arg_max(t, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


# In[16]:


sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()


# In[18]:


# これで可能
@jit
def train():
    i=0
    time = []
    loss_val , acc_val = [], []
    loss_vals, acc_vals = [], []

    for _ in range (2000):
        i+=1
        batch_xs, batch_ts = mnist.train.next_batch(50)
        sess.run(train_step,feed_dict={x:batch_xs, t: batch_ts})
        loss_vals, acc_vals = sess.run([loss,accuracy],feed_dict={x:batch_xs,t:batch_ts})
        time.append(i)
        loss_val.append(loss_vals)
        acc_val.append(acc_vals)
        
        if i % 500 == 0:
            for c in range(4):
                start = len(mnist.test.images) // 4 * c
                end = len(mnist.test.images) // 4 * (c+1)
                loss_vals, acc_vals = sess.run([loss,accuracy],feed_dict={x:mnist.test.images[start:end],t:mnist.test.labels[start:end]})
    #             time.append(i)
    #             loss_val.append(loss_vals)
    #             acc_val.append(acc_vals)
            loss_val_sum = np.sum(loss_vals)
            acc_val_sum = np.mean(acc_vals)
            print('Step: %d, Loss:%f, Accuracy: %f' 
                    % (i, loss_val_sum, acc_val_sum))
#学習データも自身でディレクトリを指定してください。
    saver.save(sess, '/learn_result_1cell_ver1.7.1.ckpt')

# In[ ]:


train()
```

学習データって？という方、ご安心を。ちゃんと次の章でお話いたします。

#カメラの実装
##学習データって？
「機械学習したデータって毎回学習させなきゃいけないの？めんどくさっ！」
そんなことありません。ちゃんとデータを保存してくれます。それが、先程の

```Python
saver = tf.train.Saver()
```
でセーブできます。これによってxを始めとした値が全て引きつがれて、別のプログラムでも使うことができます。
しかし、注意したいのはほぼすべての数を格納しているため、<b>足りない引数があったときはエラーを返してしまう点です。</b>
この恐ろしさは実は、プログラムが進まないということに限らないところが恐ろしいのです。
jupyter notebookの続行や、try/exceptionでそのまま、スルーさせる構文を書くと、すべて0と出力してしまう学習器が完成します。
ご注意を・・・

そのため、学習セクションで書いた変数をそのまま格納できるようにコピペしましょう。
そして、カメラの実装は以下のようになります。
[Webカメラを使ってリアルタイムに顔検出してみる](https://qiita.com/mix_dvd/items/98feedc8c98bc7790b30)
こちらを参考にして、以下のコードを書きました。

```Python
def Detect(x_,y,w,h,img,img_gray,i):
    color = (0, 0, 225)
    pen_w = 3
    cv.imwrite("cutted.jpg",img)
    img_read = cv.imread("cutted.jpg")
    # フレーム表示
    cv.rectangle(img, (x_, y), (x_+w, y+h), color, thickness = pen_w)
    img_cutter = img_read[y:y+h,x_:x_+w]
    cv.imwrite("image/cutted"+str(i)+".jpg",img_cutter)
    img_read_cut = cv.imread("imager/cutted"+str(i)+".jpg")
    img_read_resized = cv.resize(img_read_cut,(28,28))
    real_image.append(img_read_resized.flatten().astype(np.float32)/255.0)
    x_tmp = np.reshape(real_image[i],(-1,2352))
    x_edit.append(x_tmp)
    pred = Prediction(x_edit,i)
    print(pred)

def Prediction(x_edit,i):
    p_val = sess.run(p, feed_dict={x:x_edit[i]})
    return np.argmax(p_val[0])


def camera():
    if __name__ == '__main__':
        # 定数定義
        ESC_KEY = 27     # Escキー
        INTERVAL= 33     # 待ち時間
        FRAME_RATE = 30  # fps

        ORG_WINDOW_NAME = "org"
        GAUSSIAN_WINDOW_NAME = "gaussian"

        DEVICE_ID = 0
        
        # 分類器の指定
        cascade_file = "cascade1.2.xml"
        cascade = cv.CascadeClassifier(cascade_file)

        # カメラ映像取得
        cap = cv.VideoCapture(DEVICE_ID)

        # 初期フレームの読込
        end_flag, c_frame = cap.read()
        height, width, channels = c_frame.shape

        # ウィンドウの準備
        cv.namedWindow(ORG_WINDOW_NAME)
        cv.namedWindow(GAUSSIAN_WINDOW_NAME)
    
        i=0
        # 変換処理ループ
        while end_flag == True:

            # 画像の取得と顔の検出
            img = c_frame
            img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
            face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

            # 検出した顔に印を付ける
            for (x_, y, w, h) in face_list:
                 Detect(x_,y,w,h,img,img_gray,i)
                i+=1
        
            cv.imshow(GAUSSIAN_WINDOW_NAME, img)
        # Escキーで終了
            key = cv.waitKey(INTERVAL)
            if key == ESC_KEY:
                break

        # 次のフレーム読み込み
            end_flag, c_frame = cap.read()

    # 終了処理
        cv.destroyAllWindows()
        cap.release()

camera()
```

#プログラムの動作原理

動作原理は図のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/244181/6ebc431f-dd2b-5765-56ac-3d52acd5b041.png)
cameraセクションはカスケード分類器で作成した、xmlファイルを使うことで、検出するまで、もしくは、escキーを押すまで、実行し続けます。Detectセクションで、それらの画像の切り出しを行い、Predictionセクションで学習したデータと照らし合わせて、検出したデータの判定を行います。

これらの仕組みができれば、ある程度他のものでも応用が効くかと思われますので、相性のいい組み合わせだと思います。
ちなみにカットしたデータを保存できるようになっているので、それらの履歴をたどることで、また解析に使えるのではないかとも思われます。

#最適化をしよう
#numba,cython
学習セクションで見つけた、@jitってなんだろうと思った方もいると思います。
これはPythonという言語の特性から話を遡ることになります。

#forは効率が悪い
Pythonにwhileを使うべからず、という言葉があるように、LL言語とはいえ、Pythonは繰り返しの構文は実行時間は長いのです。

#numba,cythonの役割
それらの効率化をしてくれるのがnumbaや、cythonなのです。詳しくは検索してみてください

#まとめ

* 機械学習はとてもおもしろいけど、華やかなイメージを持ってはだめだよ！
* アルゴリズムとの戦いだよ！
* 卒論でやった内容のまとめだから、死ぬほど量が多くて疲れたよ！
* 理論ガバガバだから、勉強しなおしたほうがいいと感じました！
* めんどくさいから機械学習に任せるという題名だけど、こっちで実装するほうがめんどくさいと思うよね！
* 卒論がんばります！