読者です 読者をやめる 読者になる 読者になる

TensorFlowのTutorialを改造して画像識別

TensorFlow

以前少しだけTensorFlowの記事を書きましたが、 久しぶりにTensorFlowを触ってみたので、成果物のご紹介。

やりたいこと

アイドルマスターシンデレラガールズのキャラクターを識別する。

やったこと

  • フリーソフトを使って画像を自動収集。
  • ここのプログラムの応用で、顔画像を切り出して、手動でタグ付け。(ファイル名を"タグ,(連番).jpg"に)
  • チュートリアルのプログラムを元に、学習プログラムを作成して、顔画像を学習。
  • 学習したパラーメタを使って検証。

学習プログラム

学習した顔画像は、64*64のリサイズにして保存しています。 また、ファイル名のカンマ以前の数字がキャラクターを識別するタグとなります。 今回は2500枚程度用意しました。

顔画像の例↓

f:id:oki-lab:20170205200131j:plain f:id:oki-lab:20170205200202j:plain

import cv2
import sys
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18
limit=3000
batch_size=100

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#cross entropy
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))

#minimize cross_entropy using the gradient descent algorithm
train_step = tf.train.GradientDescentOptimizer(0.0005).minimize(cross_entropy)

#initialize all variables
init = tf.initialize_all_variables()

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
saver=tf.train.Saver()

sess = tf.Session()
sess.run(init)

#training step
train_count=0
for i in range(limit):
    rnd=np.random.randint(image_num-batch_size)
    sess.run(train_step,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    train_count+=1
    print train_count,sess.run(accuracy,feed_dict={x:train_x[rnd:rnd+batch_size,:],y_:train_y[rnd:rnd+batch_size,:]})
    
print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

#save
saver.save(sess,"model.ckpt")

概要説明:
“images"フォルダに保存された顔画像を読み込み、画素情報を一次元化し、入力用テンソルに保存。
ウェイトやバイアス、損失関数や正答率用の関数を定義。
バッチサイズ分のデータを切り出して、学習。それを規定ステップ分繰り返し。
最後にモデルを保存。

評価用プログラム

import cv2
import os.path
import glob
import numpy as np
import tensorflow as tf

image_w=64
image_h=64
dim_in=image_w*image_h
dim_out=18

paths=glob.glob("images/*")
image_num=len(paths)

train_x=np.zeros((image_num,dim_in))
train_y=np.zeros((image_num,dim_out))

#loading images
cnt=0
for path in paths:
    image = cv2.imread(path,0)/255.0
    tag=int(os.path.basename(path).split(",")[0])
    train_x[cnt,:]=[flatten for inner in image for flatten in inner] #flatten matrix
    train_y[cnt,tag]=1
    print (tag)
    cnt+=1

#neural network
x = tf.placeholder(tf.float32, [None, dim_in]) #place holder
W = tf.Variable(tf.zeros([dim_in, dim_out])) #weight
b = tf.Variable(tf.zeros([dim_out])) #bias
y = tf.nn.softmax(tf.matmul(x, W) + b) #normalize
y_ = tf.placeholder(tf.float32, [None, dim_out]) #placeholder

#correct boolean list
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#cast to float point numbers
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    
saver=tf.train.Saver()
sess=tf.Session()
saver.restore(sess,"model.ckpt")

print sess.run(accuracy,feed_dict={x:train_x,y_:train_y})

概要説明:
画像の読み込みや変数、関数の定義は同じ。
モデルを読み込み、これを使って識別した時の正答率を表示。

所感

今回は画像があまり集められなかったことと、振り分けが面倒だったことが理由で、
画像の量が少ないですが、学習用データに対する正答率は94%程度でした。
上記のプログラムはディープラーニングではなく、非常に単純なニューラルネットワークなので、
気が向いたらディープラーニング化してみたいと思います。

広告を非表示にする