mnist 난수 종류에 따른 테스트

텐서플로우에서 제공하는 난수에 주로 등장하는 것으로 3가지가 있습니다.

  random_normal, random_uniform, truncated_normal.

난수에 따른 성능 차이가 있는지 궁금해서 테스트 했습니다.
이들 함수에 대한 정리는 [텐서플로우 정리] 08. 초기값과 난수에서 확인할 수 있습니다.

여러 번 검사하기 전에
전체 데이터에 대해 15회 반복하면서 cost가 어떻게 떨어지는지 비교했습니다.
random_normal과 truncated_normal 함수는 잘 동작하지만, random_uniform 함수는 올바르게 동작하지 않습니다.
random_uniform 함수가 만들어 내는 난수는 전체 구간에 대해 균일하기 때문에 발생하는 현상일텐데..
처음에 24404라는 값에서 2.30으로 떨어지고 나서 계속 그 값을 유지합니다.
이것이 더 이상 조절할 수 없을 만큼으로 w가 변경되었다라고 보기는 어려운데..
결과만 놓고 보면 조절할 수 없는 것이 맞기는 합니다.
이 부분은 나중에 좀더 정리가 필요한 부분입니다. 어찌 됐든 random_uniform 함수는 적절하지 않습니다.


# random_normal
# 1 : 60.478189058737286
# 2 : 11.734649042432965
# 3 : 7.067460532757375
# 4 : 4.989459909444504
# 5 : 3.778993105515836
# 6 : 2.991683001535285
# 7 : 2.480893753819504
# 8 : 2.027405534006062
# 9 : 1.7499642808224738
# 10 : 1.5208392191279025
# 11 : 1.333428899258666
# 12 : 1.1645081179615477
# 13 : 1.0243976788740985
# 14 : 0.9156795300565903
# 15 : 0.8343978138050405
# accuracy : 0.9163

# random_uniform
# 1 : 24404.246204987452
# 2 : 2.3088482627001676
# 3 : 2.303867313645103
# 4 : 2.3021448772603823
# 5 : 2.3015500276738954
# 6 : 2.301343701102516
# 7 : 2.3012730004570745
# 8 : 2.301249224922875
# 9 : 2.3012397917834178
# 10 : 2.3012363381819294
# 11 : 2.301236299167981
# 12 : 2.3012347472797723
# 13 : 2.3012353801727308
# 14 : 2.301232471899553
# 15 : 2.3012359909577773
# accuracy : 0.1135

# truncated_normal
# 1 : 42.671754805716574
# 2 : 9.975034481178634
# 3 : 6.153620355020877
# 4 : 4.410890528491953
# 5 : 3.343142766199837
# 6 : 2.629227198974904
# 7 : 2.118781123255989
# 8 : 1.751021036118762
# 9 : 1.4441868320022127
# 10 : 1.1963457991950714
# 11 : 1.0300166532051782
# 12 : 0.8463236458417003
# 13 : 0.7411801967909226
# 14 : 0.6237198447949415
# 15 : 0.5263266100296041
# accuracy : 0.9344


3가지 함수에 대해 동일한 코드를 사용했고, w와 b를 생성할 때 해당 함수를 사용하는 것만 다릅니다. 3회 반복하면서 결과를 출력합니다.

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('mnist', one_hot=True)

learning_rate = 0.01
epoches = 15
batch_size = 100

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

# ----------------------------------------------- #

# random_normal
w1 = tf.Variable(tf.random_normal([784, 256]))
w2 = tf.Variable(tf.random_normal([256, 256]))
w3 = tf.Variable(tf.random_normal([256, 10]))

b1 = tf.Variable(tf.random_normal([256]))
b2 = tf.Variable(tf.random_normal([256]))
b3 = tf.Variable(tf.random_normal([ 10]))

# random_uniform
# w1 = tf.Variable(tf.random_uniform([784, 256]))
# w2 = tf.Variable(tf.random_uniform([256, 256]))
# w3 = tf.Variable(tf.random_uniform([256, 10]))
#
# b1 = tf.Variable(tf.random_uniform([256]))
# b2 = tf.Variable(tf.random_uniform([256]))
# b3 = tf.Variable(tf.random_uniform([ 10]))

# truncated_normal
# w1 = tf.Variable(tf.truncated_normal([784, 256]))
# w2 = tf.Variable(tf.truncated_normal([256, 256]))
# w3 = tf.Variable(tf.truncated_normal([256, 10]))
#
# b1 = tf.Variable(tf.truncated_normal([256]))
# b2 = tf.Variable(tf.truncated_normal([256]))
# b3 = tf.Variable(tf.truncated_normal([ 10]))

a1 = tf.add(tf.matmul(x, w1), b1)
r1 = tf.nn.relu(a1)
a2 = tf.add(tf.matmul(r1, w2), b2)
r2 = tf.nn.relu(a2)
a3 = tf.add(tf.matmul(r2, w3), b3)

activation = a3
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=activation, labels=y))

# ----------------------------------------------- #

optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

sess = tf.Session()

for _ in range(3):
sess.run(tf.global_variables_initializer())

for epoch in range(epoches):
avg_cost = 0
total_batch = mnist.train.num_examples // batch_size # 55,000 // 100 = 550

for i in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)

_, c = sess.run([optimizer, cost],
feed_dict={x: batch_xs, y: batch_ys})

avg_cost += c / total_batch

print('{:2} : {}'.format(epoch+1, avg_cost))

# -------------------------------- #

pred = tf.equal(tf.argmax(activation, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(pred, tf.float32))

print('accuracy :', sess.run(accuracy,
feed_dict={x: mnist.test.images,
y: mnist.test.labels}))

sess.close()


마지막 15번째 반복과 정확도만 출력했습니다. random_uniform 함수를 사용할 수 없는 것은 여전히 당연한 사실이고, random_normal 보다는 truncated_normal 함수가 좀더 나은 성능을 보여줍니다. 설마 했는데.. 성능 좋은 난수가 있다는 것을 알게 되서.. 기분이 좋습니다. 다만 xavier 초기화 등의 난수를 현명하게 사용하는 방법이 있기 때문에 항상 그런 것은 아닐 수도 있습니다.

# random_normal
# 15 : 0.832641489035556
# accuracy : 0.9181
# 15 : 0.8100094339383366
# accuracy : 0.9207
# 15 : 0.7013166612056974
# accuracy : 0.9274

# random_uniform
# 15 : 2.3012339136817213
# accuracy : 0.1135
# 15 : 2.3012344139272516
# accuracy : 0.1135
# 15 : 2.3012313426624655
# accuracy : 0.1135

# truncated_normal
# 15 : 0.5887952694578703
# accuracy : 0.9247
# 15 : 0.5807194867451034
# accuracy : 0.9341
# 15 : 0.6066072065450834
# accuracy : 0.9277