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

```txt:動作環境
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):
```

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

```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) -----------------------------------------------
```

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

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


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

```txt:変更前
  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)
```

```txt:変更後
  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](https://qiita-image-store.s3.amazonaws.com/0/32870/cf53c3e3-ad9b-353a-1eb0-77059906128c.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](https://qiita-image-store.s3.amazonaws.com/0/32870/a2d4875e-9adb-d89e-2a28-da96c3c525d6.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](https://qiita-image-store.s3.amazonaws.com/0/32870/44405406-d5fa-71d2-5438-78dab3eecb53.png)

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

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/68005920-b815-12df-e19b-c49490b27491.png)


## 注意点

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

## v0.2 (間違い修正)

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

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

```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](https://qiita-image-store.s3.amazonaws.com/0/32870/50ff0fd7-c9bd-799c-7e2a-115824d15dca.png)

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/bf51bc61-a5b1-17a1-2976-fa2e0cdc14f0.png)

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/4a636b80-521b-a517-4d74-1ff8389754aa.png)

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