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.
前置き
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.py
をmnist_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
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
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最後の精度が急変する。
理由は不明。
trainが1.000の例。ただし、max_step2000で試した時。
注意点
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だろうか。
mnist_with_summaries.pyでもmax_step=2000の時はtrainが0.9900にはなった。
QMCがすごく良いというわけでもないかも。