Help us understand the problem. What is going on with this article?

TensorFlow > mnist_with_summaries.py をQMCでやってみた > train精度は上がった(1.000)が、test精度はそれほど変わらず

More than 3 years have passed since last update.
動作環境
Ubuntu 14.04 LTS desktop amd64
GeForce GTX 750 Ti
ASRock Z170M Pro4S [Intel Z170chipset]
TensorFlow v0.11
cuDNN v5.1 for Linux
CUDA v7.5
Python 2.7.6
IPython 5.1.0 -- An enhanced Interactive Python.

前置き

https://www.tensorflow.org/versions/r0.11/tutorials/mnist/beginners/index.html

MNISTを使った訓練についてmnist_with_summaries.pyというのがある。
ここでやっているのは、バッチ処理で訓練データの位置をランダムに取ってきて訓練する。

自分が10年以上前から使っているQMCを使えば訓練は加速されるのでは、と思い試した。

変更箇所1. TensorFlowのmnist.pyを変更

変更ファイル

TensorFlowのmnist.pyを変更することになる。
http://qiita.com/7of9/items/8d0fd50456bd02313941
に記載方法で調べたところ、以下にmnist.pyがあった。

/home/yasokada/tensorflow-GPU/lib/python2.7/site-packages/tensorflow/contrib/learn/python/learn/datasets/mnist.py

上記のファイルにおいて以下の定義がある。

  def next_batch(self, batch_size, fake_data=False):

上記の定義の下に同じインデントで以下の定義を追加する。

  # { by 7of9 (2016 Oct. 22) -----------------------------------------------
  def Halton_sequence(self, i0):
      xbase = 2
      ybase = 3

      invxbase = 1.0 / xbase
      facx = 1.0 / xbase

      invybase = 1.0 / ybase
      facy = 1.0 / ybase

      inp = i0
      x0 = 0.0
      while inp > 0:
          x0 = x0 + (inp % xbase) * invxbase
          inp = inp / xbase
          invxbase = invxbase * facx

      inp = i0
      y0 = 0.0
      while inp > 0:
          y0 = y0 + (inp % ybase) * invybase
          inp = inp / ybase
          invybase = invybase * facy

      return x0, y0

  def qmc_getIndex(self, listSize, start, getsize):
    idx = numpy.array([])
    for i0 in range(start, start + getsize):
      res, _ = self.Halton_sequence(i0) # discard 2nd dim
      # TODO: strange (normally res should not exceed 1.0)
      if res > 1.0:
        res = 1.0
      #
      idx = numpy.append(idx, res * listSize - 1)
    return idx

  def qmc_batch(self, batch_size, fake_data=False):
    """Return the next `batch_size` examples from this data set."""
    if fake_data:
      fake_image = [1] * 784
      if self.one_hot:
        fake_label = [1] + [0] * 9
      else:
        fake_label = 0
      return [fake_image for _ in xrange(batch_size)], [
          fake_label for _ in xrange(batch_size)
      ]
    start = self._index_in_epoch
    self._index_in_epoch += batch_size

    length = self._num_examples
    #length = 55000 # TODO
    idx = self.qmc_getIndex(length, start, batch_size)

    if self._index_in_epoch > self._num_examples:
      # Finished epoch
      self._epochs_completed += 1
      # Shuffle the data
      perm = numpy.arange(self._num_examples)
      numpy.random.shuffle(perm)
      self._images = self._images[perm]
      self._labels = self._labels[perm]
      # Start next epoch
      start = 0
      self._index_in_epoch = batch_size
      assert batch_size <= self._num_examples
      end = self._index_in_epoch
      return self._images[start:end], self._labels[start:end]

    return self._images[idx.astype(int)], self._labels[idx.astype(int)]
  # } by 7of9 (2016 Oct. 22) -----------------------------------------------

変更箇所2. mnist_with_summaries.pyを変更

今度はサンプルとして使っているmnist_with_summaries.pymnist_qmc.pyという名前にコピーして変更した。

def feed_dict(train):にて以下のように変更する。next_batch()の代わりにqmc_batch()を使う。

変更前
  def feed_dict(train):
    """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
    if train or FLAGS.fake_data:
      xs, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
変更後
  def feed_dict(train):
    """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
    if train or FLAGS.fake_data:
#      xs, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
      xs, ys = mnist.train.qmc_batch(100, fake_data=FLAGS.fake_data)

結果

python mnist_with_summaries.py

python mnist_qmc.py
で結果を比較した。

QMCなし (通常のmnist_with_summaries.py)

python mnist_with_summaries.py

オレンジ: test
水色: train

qiita.png

Name Smoothed Value Step Relative
test 0.9686 0.9686 990.0 37s
train 0.9600 0.9600 987.0 37s

QMCあり (python mnist_qmc.py)

python mnist_qmc.py

qiita.png

Name Smoothed Value Step Relative
test 0.9658 0.9658 990.0 59s
train 0.9800 0.9800 999.0 59s

trainが若干上がった。
なお、trainが1.000という結果をたたき出しこともある。
(その時のtestのSmoothedは0.966程度だった)
1.000になったのは10回中1回だけなので、確率としては高くない。あとは0.95から0.98の値を変動する。

QMC使用の場合、train最後の精度が急変する。
理由は不明。

qiita.png

trainが1.000の例。ただし、max_step2000で試した時。

qiita.png

注意点

QMC実装はきちんと中身を見切れてないので、まだ間違いはあるかもしれない。
resの値が1.0を超える現象があり、そこが失敗しているかもしれない。

v0.2 (間違い修正)

上記のコードは間違っていた。

mnist.pyに入れる修正は以下。

  # { by 7of9 (2016 Oct. 22) -----------------------------------------------
  def Halton_sequence(self, i0):
      xbase = 2
      ybase = 3

      invxbase = 1.0 / xbase
      facx = 1.0 / xbase

      invybase = 1.0 / ybase
      facy = 1.0 / ybase

      inp = i0
      x0 = 0.0
      while inp > 0:
          x0 = x0 + (inp % xbase) * invxbase
          inp = inp / xbase
          invxbase = invxbase * facx

      inp = i0
      y0 = 0.0
      while inp > 0:
          y0 = y0 + (inp % ybase) * invybase
          inp = inp / ybase
          invybase = invybase * facy

      return x0, y0

  def qmc_getIndex(self, listSize, start, getsize):
    idx = numpy.array([])
    for i0 in range(start, start + getsize):
      res, _ = self.Halton_sequence(i0) # discard 2nd dim
      # TODO: strange (normally res should not exceed 1.0)
      if res > 1.0:
        res = 1.0
      #
      idx = numpy.append(idx, res * listSize - 1)
    return idx

  def qmc_batch(self, batch_size, fake_data=False):
    """Return the next `batch_size` examples from this data set."""
    if fake_data:
      fake_image = [1] * 784
      if self.one_hot:
        fake_label = [1] + [0] * 9
      else:
        fake_label = 0
      return [fake_image for _ in xrange(batch_size)], [
          fake_label for _ in xrange(batch_size)
      ]
    start = self._index_in_epoch
    self._index_in_epoch += batch_size

    length = self._num_examples
    #length = 55000 # TODO
    idx = self.qmc_getIndex(length, start, batch_size)

#    if self._index_in_epoch > self._num_examples:
#      # Finished epoch
#      self._epochs_completed += 1
#      # Shuffle the data
#      perm = numpy.arange(self._num_examples)
#      numpy.random.shuffle(perm)
#      self._images = self._images[perm]
#      self._labels = self._labels[perm]
#      # Start next epoch
#      start = 0
#      self._index_in_epoch = batch_size
#      assert batch_size <= self._num_examples
#      end = self._index_in_epoch
#      return self._images[start:end], self._labels[start:end]

    return self._images[idx.astype(int)], self._labels[idx.astype(int)]
  # } by 7of9 (2016 Oct. 22) -----------------------------------------------

インデックスがself._num_examplesを超えた時のプロテクトが入ってしまっていたが、QMCを通すと、かならず(0, 1.0)の値域に入るので、これは不要。

つまりは、「勉強をしっかりやるようになった生徒に安心して途中からよく見てなかったら、漫画読んで勉強さぼっていた」状態(長い)になっていた。

こちらが訂正後の結果。精度が純増していくので大きく間違っていないかと思う。
3回連続1.000のtrain結果が出るようになった。over-learningだろうか。

qiita.png

qiita.png

qiita.png

mnist_with_summaries.pyでもmax_step=2000の時はtrainが0.9900にはなった。
QMCがすごく良いというわけでもないかも。

7of9
セブンオブナインです。Unimatrix 01の第三付属物 9の7という識別番号です。Star trek Voyagerの好きなキャラクターです。まとめ記事は後日タイトルから内容がわからなくなるため、title検索で見つかるよう個々の記事にしてます。いわゆるBorg集合体の有名なセリフから「お前たち(の知識)を吸収する。抵抗は無意味だ」。Thanks in advance.
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。
https://qiitadon.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away