芸能人の顔を機械学習で分類してみた（その７）

[その６](https://qiita.com/yuni/items/95628d1534da94bb3466)で、沢尻エリカと武井咲の画像100枚ずつを機械学習させてみた学習モデルの精度は、85%でした。
100枚しか学習させてないので、こんなものでしょうか？
今回は200枚ずつ学習させてみます。
精度あがるかな？

画像は[その４](https://qiita.com/yuni/items/7edfe68de918e12af0ee)で、すでに収集し、顔切り出し後の画像になっています。

《既にあるデータ》

* 沢尻エリカ：273
* 武井咲：284

###ラベル作成

《使うデータ》

* trainデータ：沢尻エリカ(200枚), 武井咲(200枚), 計400枚
* testデータ ：沢尻エリカ(50枚), 武井咲(50枚), 計100枚


train.txt, test.txtには、画像pathの後ろに0（沢尻エリカ）or 1（武井咲）のラベルを記載したものがそれぞれ400行、100行ずつ書かれています。

```
[yuni@machinelearningvm tensorflow]$ cat /home/yuni/azureVM/train.txt |wc -l
400
[yuni@machinelearningvm tensorflow]$ cat /home/yuni/azureVM/test.txt |wc -l
100
```

###学習
さっそく学習開始です。

```testFaceType.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

NUM_CLASSES = 2
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3

flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string('train', '/home/yuni/azureVM/train.txt', 'File name of train data')
flags.DEFINE_string('test', '/home/yuni/azureVM/test.txt', 'File name of train data')
flags.DEFINE_string('train_dir', '/home/yuni/azureVM/data', 'Directory to put the training data.')
flags.DEFINE_integer('max_steps', 100, 'Number of steps to run trainer.')
flags.DEFINE_integer('batch_size', 10, 'Batch size'
                     'Must divide evenly into the dataset sizes.')
flags.DEFINE_float('learning_rate', 1e-4, 'Initial learning rate.')

def inference(images_placeholder, keep_prob):
    """ 予測モデルを作成する関数

    引数: 
      images_placeholder: 画像のplaceholder
      keep_prob: dropout率のplace_holder

    返り値:
      y_conv: 各クラスの確率(のようなもの)
    """
    # 重みを標準偏差0.1の正規分布で初期化
    def weight_variable(shape):
      initial = tf.truncated_normal(shape, stddev=0.1)
      return tf.Variable(initial)

    # バイアスを標準偏差0.1の正規分布で初期化
    def bias_variable(shape):
      initial = tf.constant(0.1, shape=shape)
      return tf.Variable(initial)

    # 畳み込み層の作成
    def conv2d(x, W):
      return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    # プーリング層の作成
    def max_pool_2x2(x):
      return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                            strides=[1, 2, 2, 1], padding='SAME')
    
    # 入力を28x28x3に変形
    x_image = tf.reshape(images_placeholder, [-1, 28, 28, 3])

    # 畳み込み層1の作成
    with tf.name_scope('conv1') as scope:
        W_conv1 = weight_variable([5, 5, 3, 32])
        b_conv1 = bias_variable([32])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    # プーリング層1の作成
    with tf.name_scope('pool1') as scope:
        h_pool1 = max_pool_2x2(h_conv1)
    
    # 畳み込み層2の作成
    with tf.name_scope('conv2') as scope:
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

    # プーリング層2の作成
    with tf.name_scope('pool2') as scope:
        h_pool2 = max_pool_2x2(h_conv2)

    # 全結合層1の作成
    with tf.name_scope('fc1') as scope:
        W_fc1 = weight_variable([7*7*64, 1024])
        b_fc1 = bias_variable([1024])
        h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
        # dropoutの設定
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    # 全結合層2の作成
    with tf.name_scope('fc2') as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    # ソフトマックス関数による正規化
    with tf.name_scope('softmax') as scope:
        y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

    # 各ラベルの確率のようなものを返す
    return y_conv

def loss(logits, labels):
    """ lossを計算する関数

    引数:
      logits: ロジットのtensor, float - [batch_size, NUM_CLASSES]
      labels: ラベルのtensor, int32 - [batch_size, NUM_CLASSES]

    返り値:
      cross_entropy: 交差エントロピーのtensor, float

    """

    # 交差エントロピーの計算
    cross_entropy = -tf.reduce_sum(labels*tf.log(logits))
    # TensorBoardで表示するよう指定
    tf.summary.scalar("cross_entropy", cross_entropy)
    return cross_entropy

def training(loss, learning_rate):
    """ 訓練のOpを定義する関数

    引数:
      loss: 損失のtensor, loss()の結果
      learning_rate: 学習係数

    返り値:
      train_step: 訓練のOp

    """

    train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
    return train_step

def accuracy(logits, labels):
    """ 正解率(accuracy)を計算する関数

    引数: 
      logits: inference()の結果
      labels: ラベルのtensor, int32 - [batch_size, NUM_CLASSES]

    返り値:
      accuracy: 正解率(float)

    """
    correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(labels, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    tf.summary.scalar("accuracy", accuracy)
    return accuracy

if __name__ == '__main__':
    tf.reset_default_graph()
    # ファイルを開く
    f = open(FLAGS.train, 'r')
    # データを入れる配列
    train_image = []
    train_label = []
    for line in f:
        # 改行を除いてスペース区切りにする
        line = line.rstrip()
        l = line.split()
        # データを読み込んで28x28に縮小
        img = cv2.imread(l[0])
        if(img is None):
            print('画像を開けません。')
            quit()
        # print(l[0])
        #表示
        img = cv2.resize(img, (28, 28))
        # cv2.imshow('image', img)
        # cv2.waitKey(0)
        # 一列にした後、0-1のfloat値にする
        train_image.append(img.flatten().astype(np.float32)/255.0)
        # ラベルを1-of-k方式で用意する
        tmp = np.zeros(NUM_CLASSES)
        tmp[int(l[1])] = 1
        train_label.append(tmp)
    # numpy形式に変換
    train_image = np.asarray(train_image)
    train_label = np.asarray(train_label)
    f.close()

    f = open(FLAGS.test, 'r')
    test_image = []
    test_label = []
    for line in f:
        line = line.rstrip()
        l = line.split()
        img = cv2.imread(l[0])
        img = cv2.resize(img, (28, 28))
        test_image.append(img.flatten().astype(np.float32)/255.0)
        tmp = np.zeros(NUM_CLASSES)
        tmp[int(l[1])] = 1
        test_label.append(tmp)
    test_image = np.asarray(test_image)
    test_label = np.asarray(test_label)
    f.close()
    
    with tf.Graph().as_default():
        # 画像を入れる仮のTensor
        images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
        # ラベルを入れる仮のTensor
        labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
        # dropout率を入れる仮のTensor
        keep_prob = tf.placeholder("float")

        # inference()を呼び出してモデルを作る
        logits = inference(images_placeholder, keep_prob)
        # loss()を呼び出して損失を計算
        loss_value = loss(logits, labels_placeholder)
        # training()を呼び出して訓練
        train_op = training(loss_value, FLAGS.learning_rate)
        # 精度の計算
        acc = accuracy(logits, labels_placeholder)

        # 保存の準備
        saver = tf.train.Saver()
        # Sessionの作成
        sess = tf.Session()
        # 変数の初期化
        sess.run(tf.global_variables_initializer())
        # TensorBoardで表示する値の設定
        summary_op = tf.summary.merge_all()
        summary_writer = tf.summary.FileWriter(FLAGS.train_dir, sess.graph)
        
        # 訓練の実行
        for step in range(FLAGS.max_steps):
            #追記
            for i in range(int(len(train_image)/FLAGS.batch_size)):
                # batch_size分の画像に対して訓練の実行
                batch = FLAGS.batch_size*i
                # feed_dictでplaceholderに入れるデータを指定する
                sess.run(train_op, feed_dict={
                  images_placeholder: train_image[batch:batch+FLAGS.batch_size],
                  labels_placeholder: train_label[batch:batch+FLAGS.batch_size],
                  keep_prob: 0.5})

            # 1 step終わるたびに精度を計算する
            train_accuracy = sess.run(acc, feed_dict={
                images_placeholder: train_image,
                labels_placeholder: train_label,
                keep_prob: 1.0})
            print ("step %d, training accuracy %g"%(step, train_accuracy))

            # 1 step終わるたびにTensorBoardに表示する値を追加する
            summary_str = sess.run(summary_op, feed_dict={
                images_placeholder: train_image,
                labels_placeholder: train_label,
                keep_prob: 1.0})
            summary_writer.add_summary(summary_str, step)

    # 訓練が終了したらテストデータに対する精度を表示
    print ("test accuracy %g"%sess.run(acc, feed_dict={
        images_placeholder: test_image,
        labels_placeholder: test_label,
        keep_prob: 1.0}))

    # 最終的なモデルを保存
    save_path = saver.save(sess, "model.ckpt")
```

###結果
```
[yuni@machinelearningvm tensorflow]$ python3 testFaceType.py
step 0, training accuracy 0.5
step 1, training accuracy 0.5
step 2, training accuracy 0.505
step 3, training accuracy 0.5275
step 4, training accuracy 0.5525
step 5, training accuracy 0.58
step 6, training accuracy 0.63
step 7, training accuracy 0.6725
step 8, training accuracy 0.7075
step 9, training accuracy 0.7775
step 10, training accuracy 0.7975
step 11, training accuracy 0.795
step 12, training accuracy 0.815
step 13, training accuracy 0.8225
step 14, training accuracy 0.835
step 15, training accuracy 0.86
step 16, training accuracy 0.86
step 17, training accuracy 0.865
step 18, training accuracy 0.8975
step 19, training accuracy 0.895
step 20, training accuracy 0.9125
step 21, training accuracy 0.925
step 22, training accuracy 0.9375
step 23, training accuracy 0.9475
step 24, training accuracy 0.9575
step 25, training accuracy 0.945
step 26, training accuracy 0.965
step 27, training accuracy 0.965
step 28, training accuracy 0.965
step 29, training accuracy 0.9775
step 30, training accuracy 0.985
step 31, training accuracy 0.97
step 32, training accuracy 0.975
step 33, training accuracy 0.985
step 34, training accuracy 0.985
step 35, training accuracy 0.9925
step 36, training accuracy 0.995
step 37, training accuracy 0.99
step 38, training accuracy 0.995
step 39, training accuracy 0.995
step 40, training accuracy 0.995
step 41, training accuracy 0.995
step 42, training accuracy 0.9975
step 43, training accuracy 1
step 44, training accuracy 1
step 45, training accuracy 1
step 46, training accuracy 1
step 47, training accuracy 1
step 48, training accuracy 1
step 49, training accuracy 1
step 50, training accuracy 1
step 51, training accuracy 1
step 52, training accuracy 1
step 53, training accuracy 1
step 54, training accuracy 1
step 55, training accuracy 1
step 56, training accuracy 1
step 57, training accuracy 1
step 58, training accuracy 1
step 59, training accuracy 1
step 60, training accuracy 1
step 61, training accuracy 1
step 62, training accuracy 1
step 63, training accuracy 1
step 64, training accuracy 1
step 65, training accuracy 1
step 66, training accuracy 1
step 67, training accuracy 1
step 68, training accuracy 1
step 69, training accuracy 1
step 70, training accuracy 1
step 71, training accuracy 1
step 72, training accuracy 1
step 73, training accuracy 1
step 74, training accuracy 1
step 75, training accuracy 1
step 76, training accuracy 1
step 77, training accuracy 1
step 78, training accuracy 1
step 79, training accuracy 1
step 80, training accuracy 1
step 81, training accuracy 1
step 82, training accuracy 1
step 83, training accuracy 1
step 84, training accuracy 1
step 85, training accuracy 1
step 86, training accuracy 1
step 87, training accuracy 1
step 88, training accuracy 1
step 89, training accuracy 1
step 90, training accuracy 1
step 91, training accuracy 1
step 92, training accuracy 1
step 93, training accuracy 1
step 94, training accuracy 1
step 95, training accuracy 1
step 96, training accuracy 1
step 97, training accuracy 1
step 98, training accuracy 1
step 99, training accuracy 1
test accuracy 0.9
```
テストデータの正解率90%でした。
まあまあ？

###確認
[その６](https://qiita.com/yuni/items/95628d1534da94bb3466)で確認に使った画像で、再度確認します。
0が返ってくれば沢尻エリカ、1が返ってくれば武井咲です。
その時の分類スコアも表示しています。

####結果1
沢尻エリカ、前回同様10枚全部正解まる。

```
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/f885be6e6214433e531a36f265b89030feffcfcc38524a1f9fe50fd270cc2177.jpeg
[[0.99367887 0.00632114]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/f918d1eddf2c94592868075d45bf9368c818050cab86d56dbf8dfcf42445daaa.jpg
[[0.99821824 0.00178173]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/f918d1eddf2c94592868075d45bf9368c818050cab86d56dbf8dfcf42445daaa.jpg
[[0.99821824 0.00178173]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fab18876e469d224fcead1dff74ee50c2ec2f46087741725ef1c100f7bf1839f.jpg
[[0.9385539  0.06144615]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fbdac60677937487f9584c6d13b07597f5a3c757a65eacba0672f0659740848d.jpg
[[9.9964714e-01 3.5290144e-04]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fcbf4c42a6368963d43a659d684ee0bdd979acb3ead64e4d0317df7b0e6ba4c8.jpg
[[0.97049487 0.02950513]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fdfe7f0e994cc49a5fa32d73a5d15919206347e6c3fa0f622d217eab210bbba4.jpg
[[9.9997604e-01 2.3901297e-05]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/febb582342e4a6f4733c0bee2d61f032fe675c2d5ed73e02ac3b6d6ad788bc0e.jpg
[[0.7245246  0.27547538]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fecf271a586c97bb06105fab3babc1d9091d0303b92e8b3ad1f06202476e512a.jpg
[[0.7742604  0.22573964]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/ffe965f8aa816fe0609e697044242e7f9b7796a02a44de3785283df2943c8a65.jpg
[[9.9912161e-01 8.7841856e-04]]
0
```

####結果２
武井咲、10枚中7枚正解。
前回と同じやん...

```
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/f98c5f34aa13755a011ddd8fce4d9190c0504fbbde93f3402679758bb031f304.jpg
[[0.97942907 0.02057101]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fc41110aedf620e4546564c84317de072c778042c546325d15f36c8b86f0d88f.jpg
[[0.00810461 0.9918954 ]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fc529e533490bff6386fd84d94821ec7e9bc6d9d6dfe4e9b02611755ee6ee77a.jpg
[[0.00872763 0.9912724 ]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fdfdabc1999453193207a07dedbe2a5be0e9d2f8629a3ab949ae1f7b77d4f0d4.jpg
[[4.6933314e-05 9.9995303e-01]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fe06812f63527de0151c80b873d079af0e816f3585837aee92ae8117dc5b4fc9.jpg
[[0.6502485 0.3497514]]
0
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/febd41e6de949d68929aafe4ec2f3a3bad06331dece61270de73e8d622dc76d1.jpg
[[0.0509674  0.94903255]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/fec8bd3c8ac308acf872420db4d27f6ad6c4f9f56aec799d2685cdd19f42dc2c.jpeg
[[7.1482116e-04 9.9928516e-01]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/ff2f844294dd52092043d60fff85a1d8fbf6a033b299bdee6daa077f5da98c14.png
[[0.23403439 0.76596564]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/ff9b638e43b0760f1a546b75321150fc9c190535aedfd023fa5839729d1c51a3.jpeg
[[0.00766279 0.9923373 ]]
1
[yuni@machinelearningvm tensorflow]$ python3 FaceType.py /home/yuni/azureVM/data/f8c84ef8beb5f0726483d2cdf51cd17bf1fe2d59e5fc1124f0c10df9af767004.jpg
[[0.5016615 0.4983385]]
0
```

精度90％のモデルのはずなのに、17/20の正解率ってどうなの？？
つぎは4クラス分類に挑戦してみます！