TensorFlowの画像認識コードを高解像度化してみた
Re:ゼロから始めるディープラーニング: EeePCの軌跡で宣言した通り、まったりとディープラーニングの勉強を進めてます。
ついでに職場にある私のワークステーションにもTensorFlowをインストールして、CAEがらみの画像認識実験もちょくちょくやっております。
といっても、コードは以下の記事で使用したものをほぼそのまま使ってるだけ。
TensorFlowで”日本のお城”を識別させてみた: EeePCの軌跡
このコード、画像を28×28で読み込んで学習・認識しているため、ちょっと低解像度過ぎるのが難点。
元々MNISTの手書き文字の認識用のためこの解像度でも行けたんでしょうが、私が使うレベルの画像認識にはもう少し解像度が欲しいところ。
ということで、縦横それぞれ倍の56×56に拡張してみました。
ただ、今までのコードの「28×28」の部分を「56×56」にしただけでは、画像認識の精度がかえって下がります。
このため、この辺りの記事を参考に畳み込み層+プーリング層のペアを一つ増やしてみました。
続・TensorFlowでのDeep Learningによるアイドルの顔識別 - すぎゃーんメモ
TensorFlowによるももクロメンバー顔認識(中編) - Qiita
これで高解像度化&認識率アップできます。
元々が「畳み込み層+プーリング層」×2+結合層×2の6層でしたが。
高解像度化に伴い「畳み込み層+プーリング層」×3+結合層×2の8層になりました。
◆学習用コード「cnn_train_56.py」
#!/usr/bin/env python
import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform
NUM_CLASSES = 7
IMAGE_SIZE = 56
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3
flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string('train', 'train.txt', 'File name of train data')
flags.DEFINE_string('test', 'test.txt', 'File name of train data')
flags.DEFINE_string('train_dir', '/mnt/c/linux/data', 'Directory to put the training data.')
flags.DEFINE_integer('max_steps', 300, 'Number of steps to run trainer.')
flags.DEFINE_integer('batch_size', 20, '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):
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
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')
x_image = tf.reshape(images_placeholder, [-1, 56, 56, 3])
with tf.name_scope('conv1') as scope:
W_conv1 = weight_variable([3, 3, 3, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
with tf.name_scope('pool1') as scope:
h_pool1 = max_pool_2x2(h_conv1)
with tf.name_scope('conv2') as scope:
W_conv2 = weight_variable([3, 3, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
with tf.name_scope('pool2') as scope:
h_pool2 = max_pool_2x2(h_conv2)
with tf.name_scope('conv3') as scope:
W_conv3 = weight_variable([3, 3, 64, 128])
b_conv3 = bias_variable([128])
h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3) + b_conv3)
with tf.name_scope('pool3') as scope:
h_pool3 = max_pool_2x2(h_conv3)
with tf.name_scope('fc1') as scope:
W_fc1 = weight_variable([7*7*128, 1024])
b_fc1 = bias_variable([1024])
h_pool3_flat = tf.reshape(h_pool3, [-1, 7*7*128])
h_fc1 = tf.nn.relu(tf.matmul(h_pool3_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
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):
cross_entropy = -tf.reduce_sum(labels*tf.log(logits))
tf.summary.scalar("cross_entropy", cross_entropy)
return cross_entropy
def training(loss, learning_rate):
train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
return train_step
def accuracy(logits, labels):
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__':
f = open(FLAGS.train, 'r')
train_image = []
train_label = []
for line in f:
line = line.rstrip()
l = line.split()
img = cv2.imread(l[0])
img = cv2.resize(img, (56, 56))
train_image.append(img.flatten().astype(np.float32)/255.0)
tmp = np.zeros(NUM_CLASSES)
tmp[int(l[1])] = 1
train_label.append(tmp)
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, (56, 56))
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():
images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
keep_prob = tf.placeholder("float")
logits = inference(images_placeholder, keep_prob)
loss_value = loss(logits, labels_placeholder)
train_op = training(loss_value, FLAGS.learning_rate)
acc = accuracy(logits, labels_placeholder)
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
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 = FLAGS.batch_size*i
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})
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))
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")
◆認識用コード「cnn_app2_56.py」
#!/usr/bin/env python
import sys
import numpy as np
import tensorflow as tf
import cv2
NUM_CLASSES = 7
IMAGE_SIZE = 56
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3
flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string('analysis', 'analysis.txt', 'File name of analysis data')
def inference(images_placeholder, keep_prob):
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
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')
x_image = tf.reshape(images_placeholder, [-1, 56, 56, 3])
with tf.name_scope('conv1') as scope:
W_conv1 = weight_variable([3, 3, 3, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
with tf.name_scope('pool1') as scope:
h_pool1 = max_pool_2x2(h_conv1)
with tf.name_scope('conv2') as scope:
W_conv2 = weight_variable([3, 3, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
with tf.name_scope('pool2') as scope:
h_pool2 = max_pool_2x2(h_conv2)
with tf.name_scope('conv3') as scope:
W_conv3 = weight_variable([3, 3, 64, 128])
b_conv3 = bias_variable([128])
h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3) + b_conv3)
with tf.name_scope('pool3') as scope:
h_pool3 = max_pool_2x2(h_conv3)
with tf.name_scope('fc1') as scope:
W_fc1 = weight_variable([7*7*128, 1024])
b_fc1 = bias_variable([1024])
h_pool3_flat = tf.reshape(h_pool3, [-1, 7*7*128])
h_fc1 = tf.nn.relu(tf.matmul(h_pool3_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
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
if __name__ == '__main__':
test_image = []
test_filenm = []
# for i in range(1, len(sys.argv)):
# img = cv2.imread(sys.argv[i])
# img = cv2.resize(img, (56, 56))
# test_image.append(img.flatten().astype(np.float32)/255.0)
# test_image = np.asarray(test_image)
f = open(FLAGS.analysis, 'r')
for line in f:
line = line.rstrip()
l = line.split()
test_filenm.append(l[0])
img = cv2.imread(l[0])
img = cv2.resize(img, (56, 56))
test_image.append(img.flatten().astype(np.float32)/255.0)
test_image = np.asarray(test_image)
f.close()
images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
keep_prob = tf.placeholder("float")
logits = inference(images_placeholder, keep_prob)
sess = tf.InteractiveSession()
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer())
saver.restore(sess, "./model.ckpt")
for i in range(len(test_image)):
accr = logits.eval(feed_dict={
images_placeholder: [test_image[i]],
keep_prob: 1.0 })[0]
pred = np.argmax(logits.eval(feed_dict={
images_placeholder: [test_image[i]],
keep_prob: 1.0 })[0])
print (test_filenm[i],pred,accr)
一見すると何の進歩もなさそうに見えますが、以前よりちょくちょくパラメータ値が変わってるところがあります。
まず、Anaconda 4.2.0 for Windows(64bit)+TensorFlow 0.12.0でWarningが出てたのを全部修正しました。
また、認識用コードは複数のファイルを読めるようにしました。
「analysis.txt」というファイルに認識させたい画像ファイル名を書き込んでおくと、その中にあるファイルをいっぺんに処理してくれます。
相変わらず学習用コードには”教師データファイル名+ラベル”が書かれた訓練用ファイル一覧「train.txt」とテスト用ファイル一覧「test.txt」の2つも必要です。この辺は先の記事を参考に。
早速、これを使って画像認識させてみました。
使ったのはTensorFlowで”日本のお城”を識別させてみた: EeePCの軌跡で使った画像データ。
Anaconda for Windowsのコマンドラインで
> python cnn_train_56.py
と入力して実行。
縦横2倍、データ量にして4倍に増えたため、さすがに時間かかります。
うちのメインPC(Corei3 3220 2コア4スレッド 3.3GHz)で300サイクル回すと40分ほどかかりました。以前は数分で終了。データは4倍ですが、時間は4倍以上かかります。
というのもデータ量が増えただけでなく、収束するまでのサイクルも増加。
以前は70~100サイクルも回せば十分だったのが、今回は最低でも150サイクルは必要で、余裕を見て300サイクル回してます。
学習が終了したら、今度は”認識”させてみます。
認識用に用意したこちらの画像。
各お城 3枚づつのデータを準備。
それぞれのお城のラベル(0~6)を各ファイル名の頭につけておきました。
この画像ファイル名を一覧にしたファイル「analysis.txt」を準備して
> python cnn_app2_56.py
と実行。
返ってきた結果は
こんな感じになりました。
「判定」の黄色に塗った部分が正解だった画像。
横の%でかかれた数字は、それぞれのラベルの判定率。最も数値の大きかったところをオレンジで塗ってます。
黒枠のところにオレンジが収まっているのが正解。ですが、熊本城、犬山城、大坂城でそれぞれはずれが出てますね。
全21枚中、当たりは17枚。正解率 81.0%。
特に”犬山城”のはずれっぷりが目立ちますが、犬山城の画像のうち、2枚だけは学習に使った画像よりちょっと斜め上から見たものを認識させたんです。
天守閣中央に特徴的な屋根の形があるので少々ずれてても認識するんじゃねぇ?と思って入れたんですが、やはりだめでしたね。
犬山城をのぞけば高解像度化のおかげか、まあまあの正解率。実質9割くらいじゃないかなぁと。なかなかやりますね。
ちなみに職場では「畳み込み層+プーリング層」をさらに一つ増やして112×112まで解像度を増やしたコードを作成してます。
ただ、自宅で用意した教師データは64×64になっているため、自宅用は56×56どまり。
実は112×112にしても正解率がかえって下がってしまってるため、現在いろいろとチューニングの真っ最中。うまく行ったら、またブログにて公開します。
ただ人の顔やお城くらいなら、56×56の解像度でも大丈夫っぽいですね。
しかし勉強の途中でコードをいじりだして大丈夫か?と思われそうですが。
ただ、この動くコードというのは、プログラミングを勉強する上では結構大事。
「ゼロから作るDeep Learning」を読みながらこのコードを読むと、例えば”loss”っていう関数が一体何をやってるのか?など理解が進みます。
本を読むだけでは眠くなっちゃいますが、手を動かしてコードを書き換えてみて実際の動きを確認しながら読み進めると、いろいろとわかって面白いです。
「ゼロから作るDeep Learning」自体はTensorFlowを使っているわけではありませんが、やってることは同じなので、TensorFlowのコードでも非常に参考になるんです。
とりあえず実際に動くコードを手元において、教材片手にいじりながら読むのはおすすめです。
« 中華製なCPU”龍芯3号 3A3000”搭載ノートPCが登場 | トップページ | 128×128の1.5インチOLED付Arduino互換ボード”Pixel 2.0” »
「パソコン系」カテゴリの記事
- わりといい感じの椅子を買った(2024.06.15)
- 最大45W出力のUSB-C端子を持つUSB‐A × 2 、USB-C × 2、電源4口タップを購入(2024.05.15)
- 名古屋 大須へ行ってきました(2024.04.28)
- 東京ビッグサイトへ行ってきました(2024.04.25)
- 大須へ行ってきました(2024.03.22)
「Raspberry Pi・Arduino・電子工作」カテゴリの記事
- 名古屋 大須へ行ってきました(2024.04.28)
- Raspberry Pi 5用電源購入(2024.04.19)
- Interface 2024年5月号はRaspberry Pi 5特集(2024.03.26)
- Raspberry Pi 5とPCがつながらなかった理由は「プライバシーセパレーター機能」のせいでした(2024.03.12)
- Raspberry Pi 5に日本語LLM(ELYZA-Japanese-Llama-2-7b-fast-Instruct)を入れてみた(2024.03.10)
「数値解析系」カテゴリの記事
- Tanuki-8Bの4ビット量子化ggufモデルでRAGをやってみました(2024.09.14)
- 純日本産なローカルLLM「Tanuki-8B」を試してみた(2024.09.02)
- 東京のセールスフォースに行ってきました(2024.07.24)
- ローカルLLM「Llama-3-ELYZA-JP-8B」にいろいろ聞いてみた(2024.07.01)
- ElyzaのLlama3ベースの言語モデル「Llama-3-ELYZA-JP-8B」のRAGが予想以上に賢かった件(2024.06.27)
« 中華製なCPU”龍芯3号 3A3000”搭載ノートPCが登場 | トップページ | 128×128の1.5インチOLED付Arduino互換ボード”Pixel 2.0” »
コメント