質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

Tensorflow画像識別実行結果がおかしい

解決済

回答 4

投稿

  • 評価
  • クリップ 3
  • VIEW 3,277

pfirsich

score 15

前提・実現したいこと

プログラミング初心者です以下当然のことを記載していたらすいません。

TensorFlowでアニメゆるゆりの制作会社を識別する(http://kivantium.hateblo.jp/entry/2015/11/18/233834)のブログを参考に画像認識識別をしようと実行したところ下記のように同じ結果しかでません。

1番最初に動かした時はstep145くらいまで精度があがり最高0.992843までいきましたが、step146になった途端精度が0.0889571に下がりそれ以降全200step行いましたがずっとその精度が表示され、その後何度試しても下記のような結果がでてしまうようになりました。

正常に動かない原因は何でしょうか。

発生している問題・エラーメッセージ

step 0 training accuracy 0.0889571
test accuracy 0.2
step 1 training accuracy 0.0889571
test accuracy 0.2
step 2 training accuracy 0.0889571
test accuracy 0.2
step 3 training accuracy 0.0889571
test accuracy 0.2
step 4 training accuracy 0.0889571
test accuracy 0.2
step 5 training accuracy 0.0889571
test accuracy 0.2
step 6 training accuracy 0.0889571
test accuracy 0.2
step 7 training accuracy 0.0889571
test accuracy 0.2
step 8 training accuracy 0.0889571
test accuracy 0.2
step 9 training accuracy 0.0889571
test accuracy 0.2
step 10 training accuracy 0.0889571
test accuracy 0.2
step 11 training accuracy 0.0889571
test accuracy 0.2
step 12 training accuracy 0.0889571
test accuracy 0.2
step 13 training accuracy 0.0889571
test accuracy 0.2
step 14 training accuracy 0.0889571
test accuracy 0.2
step 15 training accuracy 0.0889571
test accuracy 0.2
step 16 training accuracy 0.0889571
test accuracy 0.2
step 17 training accuracy 0.0889571
test accuracy 0.2
step 18 training accuracy 0.0889571
test accuracy 0.2
step 19 training accuracy 0.0889571
test accuracy 0.2

該当のソースコード

import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform

NUM_CLASSES =10  
IMAGE_SIZE = 28 
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3

flags = tf.app.flags
FLAGS = flags.FLAGS

flags.DEFINE_string('train', '/home/k123/anaconda2/envs/tensorflow/data/train2.txt', 'File name of train data')
flags.DEFINE_string('test', '/home/k123/anaconda2/envs/tensorflow/data/test.txt', 'File name of train data')
flags.DEFINE_string('train_dir', '/home/k123/anaconda2/envs/tensorflow/data/gazo', 'Directory to put the training data.')
flags.DEFINE_integer('max_steps', 20, '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):
     # 重みを標準偏差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):
     # 交差エントロピーの計算
    cross_entropy = -tf.reduce_sum(labels*tf.log(logits))
    # TensorBoardで表示するよう指定
    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()
        # データを読み込んで28x28に縮小
        img = cv2.imread(l[0])
        img = cv2.resize(img, (28, 28))
        # 一列にした後、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.initialize_all_variables())
        # TensorBoardで表示する値の設定
        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(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, "model0.ckpt")

試したこと

◎画像の分類するクラス数を減らして実行したところ、トレーニング精度の数値が現在の0.889571から変わったもののやはり学習回数をいくらつんでも同じ精度しか表示されませんでした。
◎モデルファイル”model0.ckpt”を一回消して実行してみましたが変わりませんでした。

補足情報(言語/FW/ツール等のバージョンなど)

ubuntu16.04/python3.5
画像形式はjpgまたはpngです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2017/07/01 10:30

    訓練用の画像と検証用の画像、それぞれの数(枚数)はいくつでしょうか?

    キャンセル

  • pfirsich

    2017/07/02 21:10

    練習用1000枚、検証用3枚で実行しました。

    キャンセル

回答 4

check解決した方法

+1

学習率の値を1e-5にしたところ正常に学習値があがるようになりました。この学習率が今回は適正だった為でしょうか。

また、1e-4や1e-8の学習値では上記の実行結果のように正常な学習ができませんでした。

1e-5より高い値のみできないとなると発散したことで正常な学習ができないとわかりますが、低い値も正常に動かなかったことから結局原因はなんだったんでしょうか。今後も学習率、勾配について勉強して、画像、分類項目を減らしたり増やしたりすると学習率に関係してくるのかどうなるか今後も勉強していきたいと思います。

丁寧に回答してくれた方々、知らない言葉もでてきて調べたりしました、とても勉強になり助かりました。ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

練習用1000枚、検証用3枚で実行しました。

理由はよくわかりませんが、ロジックが完璧だったとしても、練習用の画像や検証用の画像もバッチサイズの倍数でないとうまくいかなかったと思います。

とりあえず、検証用画像をあと7枚用意するか、検証用を5枚にしてバッチサイズを5にするかのような手当てをしてみてください。


この場合、
練習用は10(バッチサイズ)x100(ステップ)--->バッチサイズの倍数なのでOK
検証用は10(バッチサイズ)x0.333(ステップ)->バッチサイズの倍数でないのでNG

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/03 15:35

    バッチサイズとの関連性があるとは知りませんでした、勉強になります、ありがとうございます。
    訓練用1000枚、検証用10枚、バッチサイズ10で実行したところ、
    step 0 training accuracy 0.0889571
    test accuracy 0.1
    とtest accuaryの値は変化したもののこのままステップ数をかさねてもやはり結果はずっと同じ表示でした。モデルや保存の部分で問題があるのでしょうか・・。

    関連するかはわかりませんがpythonを閉じずに2回目に同じコードを実行しようとすると、最初のほうのコードの
    flags.DEFINE_string('train', '/home/k123/anaconda2/envs/tensorflow/data/train2.txt', 'File name of train data')
    flags.DEFINE_string('test', '/home/k123/anaconda2/envs/tensorflow/data/test.txt', 'File name of train data')
    flags.DEFINE_string('train_dir', '/home/k123/anaconda2/envs/tensorflow/data/gazo', 'Directory to put the training data.')
    flags.DEFINE_integer('max_steps', 20, '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.')
    の部分を実行すると、
    ArgumentError: argument --train: conflicting option string: --train
    というエラーがでます。このエラーは例えばflags.DEFINE_string('train', '/home/k・...の部分をflags.DEFINE_string('train002', '/home/k...など別の名前にするとエラーはなくなりました。

    引き続き原因を探して行きたいと思います。回答ありがとうございました。

    キャンセル

  • 2017/07/03 21:15

    >flags.DEFINE_string(...
    の部分は、tensorflowで使う変数を簡単に扱えるように定義している部分だと思います。
    trainは学習用、testは検証用のリストですね。
    >ArgumentError: argument --train: conflicting option string: --train
    引数エラー:引数 --train: オプション文字列 --trainが衝突(カブって)います。
    という意味ですので、確かにtrain002とすれば被らなくはなりますが、tensorflowが参照しない文字列になってしまう(無意味な定義)になってしまうと思います。
    どういう状態かモヤーっとしていますが、一度pythonを落として再起動させたほうが良さそうですね。

    k_mawa82さんが別の切り口から回答してくれていますので、そちらもご参照ください。

    キャンセル

+1

pythonユーザーです。

もしヒントになればと試しに書き込んでみました。あんまりうまく行かなければごめんなさい。

「step145くらいまで精度があがり最高0.992843までいきましたが、step146になった途端精度が0.0889571に下がりそれ以降全200step行いましたがずっとその精度が表示され、その後何度試しても下記のような結果がでてしまう」

ここから勾配が146stepで消えてしまった可能性がある(いわゆる勾配消失)ので検証してみてはいかがでしょうか?活性化関数でReLU関数が使われているので、ReLU関数に入力する値が負の数であれば導関数の値は0になるので、学習が不安定になることが知られています。(ちょっとお使いのデータ見てないのでわかりませんが、正規化すると平均が0になるため負の数も元データに混ざるため 影響することもありそうかなと・・・)

解決策は、アクティベーションに勾配消失しにくい他の関数をつかう、ですが、ハイパボリックタンジェント関数(as tf でインポート後 tf.nn.tanh() )がtensor flow では使えるようです。他にReLUの親戚のLeakyReLU、ParametricReLUというものがあるようですが、tensor flowではサポートがなく自分で書く必要があるようなので検索してコード例を調べると検証できると思います。

あとは学習率をわざといじって、学習がきちんと学習率に応じて進んで行くかどうか調べてバグがないか調べていくのも良いかもしれません。(学習率は大きすぎるとコスト関数の値がどんどん大きくなり発散しますので、そのあたりを留意しながらという点はあります・・・)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/07 14:33

    学習率を1e-8にしたりしていじったところやはり同じ様な結果になりました。勾配消失の可能性も視野に入れて少しプログラムを見直してみます。

    何度もモデルファイルを消し実行したところまた1回だけ学習が上がってうまくいくことがありました。

    サイズとファイル形式が統一されていない画像データにも問題がありそうなので、データに問題があるか、MNISTに差し替えて調査していきたいと思います。

    回答ありがとうございました。

    キャンセル

+1

よくわからないところもありますが、以下を確認してみてはいかがでしょうか?

  1. 単純に勾配の数値を見るかグラフにする
  2. gradient clipping する
  3. initializerを設定する

そもそも、勾配が原因なのかを確認してみましょう。
次に、勾配が発散していたら clippingしてある大きさ以上学習しないようにしましょう。
また、initializerを設定するとそもそも発散しにくくなります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/14 17:42

    勾配の数値ですが、損失関数?と同じ意味でしょうか。知識不足ですいません。
    表示させたところloss値は固まっていました。今回は発散はしていなかったのでしょうか・・。
    2。3とても参考になります。まだpython自体わからないことだらけなので、プログラムを理解した上で初期値の設定も今後していきたいと思います。ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる