« 郵便局の格安スマホが2月24日から全国展開へ | トップページ | ”壊れにくいPCランキング”での1位は・・・ »

2017年2月11日 (土)

TensorFlowで”日本のお城”を識別させてみた

ゼロから作るDeep LearningやInterface 3月号を読んで勉強中のわりに、相変わらずTensorFlowを使ってしょうもないことにトライしてます。

最近、大坂城の写真を見ていたら「名古屋城にちょっと似てなくない?」と思ったのがきっかけなんですが。

このレベルの微妙な差を、以前作った画像認識プログラムって識別できるんだろうか?などと考えたので、ちょっと実験してみました。

基本的には、以前書いた以下の記事のとおりにデータ収集から学習まで実行。

TensorFlowで歴代「クラウン」の画像を判別させてみた: EeePCの軌跡

ただし今回はWindows版Anaconda 4.2.0で実行(Python3.5版)させるため、コードをちょっといじってます。

■ 学習用コード「cnn_train.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 = 28
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', './', 'Directory to put the training data.')
flags.DEFINE_integer('max_steps', 200, '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):

    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, 28, 28, 3])

    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)

    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([5, 5, 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('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)

        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.scalar_summary("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.scalar_summary("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, (28, 28))
        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, (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():

        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.initialize_all_variables())

        summary_op = tf.merge_all_summaries()
        summary_writer = tf.train.SummaryWriter(FLAGS.train_dir, sess.graph_def)

        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_app.py

#!/usr/bin/env python
import sys
import numpy as np
import tensorflow as tf
import cv2

NUM_CLASSES = 7
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3

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, 28, 28, 3])

    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)

    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([5, 5, 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('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)
        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 = []
    for i in range(1, len(sys.argv)):
        img = cv2.imread(sys.argv[i])
        img = cv2.resize(img, (28, 28))
        test_image.append(img.flatten().astype(np.float32)/255.0)
    test_image = np.asarray(test_image)

    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.initialize_all_variables())
    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 (pred,accr)

注意点ですが、今回識別に使ったお城は全部で7種類のため、cnn_train.py、cnn_app.pyの最初の方に定義する変数「NUM_CLASSES =」の値は”7”です。

Windows用Anaconda(Python3.5)で動かすために、日本語のコメントは削除、print文などの書式変更をしております。

画像の入手(ImageSpyder)、ファイルの名前変更(bkrename)、収集した画像を正方形にカット(JTrim)、ファイルの一覧作成(OutFileList)は先の記事通り(TensorFlowで歴代「クラウン」の画像を判別させてみた)です。

Castle00 で、今回集めたお城のデータは以上の7種。お城の名前とナンバーの振り分け(0~6)は以下。

0、岡崎城

1、熊本城

2、犬山城

3、松本城

4、大垣城

5、大坂城

6、名古屋城

「なんでこの7種類なんだ」とか、「姫路城や弘前城、小田原城・・・・・・がないのはなぜだ!」とかいろいろ意見はあるでしょうが、この辺りで力尽きたため7種類になりました。

元々大坂城と名古屋城の比較をさせたかったため、この2つは必須だったんですが、ほかにも熊本城と松本城も黒いところが似てなくねぇ?なんて思ったのも事実。

大垣城は私の実家のあるところのお城ですし、愛知県といえば犬山城、岡崎城も外せませんね。

しかし、私の実家から2番目に近いところにあるお城(岐阜城)はすっかり忘れてました。

Castle02

で、収集した各城の画像データから学習データを作るんですが。

お城って、向きが違うとずいぶんと見栄えが違います。

てことで、それぞれ300枚以上の画像データを集め、

・ 天守閣が写っているもの

・ 最も多い画角の画像であること

を条件にして絞り込んでみました。

・ 岡崎城

0_012

なぜか手前に2本の松が写っているものが多いのですが、この画角のものを取り込み。

・ 熊本城

1_014

ググると、自身で崩れた石垣の写真が多かったですね・・・早く復旧してほしいものです。

・ 犬山城

2_005

コンクリート製の復元のお城が多い中、犬山城はオリジナルの木造のまま。国宝です。

・ 松本城

3_029

こちらもオリジナルのままの国宝のお城。黒いところは熊本城に似てますねぇ・・・似てませんか?

・大垣城

4_005

入り口付近の見上げた感じの写真が多かったので、これにしました。

石田三成、島津義久、徳川家康・・・などなどが関ケ原の合戦の前日までにらみ合ってた場所に立っているお城なんですけどねぇ。あまり有名ではありません。

・大坂城

5_003

余談ですが、Googleでは「大坂城」でも「大阪城」でも引っかかるんですけど、明治以前は「大阪」ではなく「大坂」だったので、ここでは「大坂城」で統一しております。

なんか、エレベータがついてますね、このお城。

・ 名古屋城

6_013

屋根の色だけ見ると、大坂城に似ているように見えます。

石垣だけは焼け残ったため、下はオリジナルで上の部分のみコンクリート製のお城という名古屋城。金ぴかのしゃちほこが有名ですが、それ以外にも・・・何がありましたっけ?

画角で絞り込みをやったおかげで、各々300枚以上のデータを収集したのに、残ったのはどれも30~100枚程度。

一番残ったのは意外にも犬山城で、300枚中100枚ほどが残りました。このお城、撮影するポイントが限られているのでしょうか、どの写真も似たような場所から撮影されてるっぽいですね。

で、画像が集まったところで、”bkrename”を使いファイル名を”そのお城のナンバー_3桁の数字.jpg”として名前を変更しておきます。

ファイル一覧から以下のようなテキストファイルを作成。

Tensorflow05

”ファイル名 ナンバー”の一覧を書き込んだファイルで、すべてのお城の画像ファイル名を一つのファイルに取り込み。その後、学習用とテスト用データに仕分けます。

学習用のデータは”train.txt”、テスト用は”test.txt”で保存。

学習用とテスト用の数は9:1で振り分け。60枚あったら、0_001.jpg~0_054.jpgが学習用、0_055.jpg~0_060.jpgがテスト用という具合。

画像データすべてとtrain.txt、test.txt および各コードを一つのフォルダに入れて、Windows版AnacondaでTensorFlow実行環境(”activate tensorenv”とコマンド入力)したのちに、

$ python cnn_train.py

と入力して機械学習を実行。

うちの環境では、大体10分ほどで完了。

Castle03

学習用とは別に準備した画像データを「cnn_app.py」で識別させてみます。

$ python cnn_app.py okazaki.jpg

などと打ち込むと、認識したコード(0~6)を出力。

Castle

わかりにくいですが、岡崎城なら”0”を、熊本城なら”1”を・・・名古屋城なら”6”を返してくれれば正解ですが。

なんと、用意した画像データすべて正解しました!

クラウンの時とは大違い。3種類以上のデータでもちゃんと認識できました。

やっぱり、お城はわかりやすいんですかね。

Dsc_0578

ところが私のブログ記事にも載せたこの大垣城の写真は、なぜか”1”の熊本城として認識されました。。。

天守閣のてっぺんがちゃんと写ってないので、もうちょっと後ろから撮影していれば、大垣城と認識してくれたかもしれません。

それにしてもどのあたりが”熊本城”だったのやら・・・TensorFlowの考えることはよくわかりません。

うまくいったのやらいかなかったのやら、いずれにせよ画角がちょっと変わると識別できないあたり、あまり実用性はなさそうです。

名古屋城と大坂城、熊本城と松本城を見分けることができただけでも大したものでしょうか。どちらかというと、この微妙な差を見分けられるかの実験だったので、まあ大成功といえるんじゃないでしょうか?

ところで「Re:ゼロから始めるディープラーニング: EeePCの軌跡」などという記事を書いたわりにはあまり成長を感じられない記事書いてるじゃないかと思われた方。まあ、その通りなんですけど、知識習得は継続中。

実は「ゼロから作るDeep Learning」の本以外にも機械学習について学ぶ機会ができそうで、今月からちょっといろいろ動く予定です。

さすがに私ももう40代後半ですので、いきなり成長することはありませんが、今後にご期待ください。。。

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

« 郵便局の格安スマホが2月24日から全国展開へ | トップページ | ”壊れにくいPCランキング”での1位は・・・ »

数値解析系」カテゴリの記事

コメント

最近自分も影響色々と影響を受けて、tensorflowインストールしてみた感じです。
まだとっかかりなのでチュートリアル通り進めただけで何も理解してません。というかPython自体初です。
そのくせanaconda3入れてPyCharm入れてdaracuraテーマにするといかにもHACKER的な見立てに満足。
で、全く話変わりますがこれ知ってます?CASSIE
https://m.youtube.com/watch?v=Is4JZqhAy-M
発売直後すぐ完売とのこと。
逆関節2足歩行ロボット大好き人間としては欲しいけど買えないだろうな。
作れないかなぁ。などど夢見てますw

こんにちは、もも吉さん。

私もTensorFlow、全然理解が及びませんね。”グラフ”っていう概念がまだ板についてませんし。使いこなせればすごいんでしょうけど、まだまだ既存コードでお遊びするのが精一杯です。

ちなみに、最近”R”なんていう別の言語を習得中。これもビッグデータ解析向きとしてはPython並みに強力な言語で、なかなか面白そうです。いずれブログでも紹介する予定。

このロボットはなかなかすごいですよね。構造は単純ですけど、動きがぬるぬるしてて侮れませんね。

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: TensorFlowで”日本のお城”を識別させてみた:

« 郵便局の格安スマホが2月24日から全国展開へ | トップページ | ”壊れにくいPCランキング”での1位は・・・ »

無料ブログはココログ

スポンサード リンク

ブログ村