Числовая стабильность tf.reduce_mean хуже, чем np.mean, как на процессоре, так и на процессоре.

Есть ли у tf.reduce_mean числовая проблема, когда сумма превышает предел типа с плавающей запятой?

Есть ли лучший способ вычислить среднее для массива float16 в тензорном потоке?

Результат (процессор, tf 1.13.1, linux):

np.mean 64: 0.499978537075602
np.sum  64: 499978.53707560204
np.mean 16: 0.5
np.sum  16: inf
tf.reduce_mean 16: nan

Результат (gpu, вычислительные возможности 5.2, tf 1.13.1, cuda 10.1, linux):

np.mean 64: 0.500100701606694
np.sum  64: 500100.7016066939
np.mean 16: 0.5
np.sum  16: inf
tf.reduce_mean 16: nan

Результат (gpu, вычислительные возможности 7.0, tf 1.13.1, cuda 9.0, linux):

np.mean 64: 0.4996047117607758
np.sum  64: 499604.7117607758
np.mean 16: 0.4995
np.sum  16: inf
tf.reduce_mean 16: nan

Контрольная работа:

"""
Test numerical stability of reduce_mean
"""

import numpy as np
import tensorflow as tf


N = int(1e6)
dtype = np.float16

x = np.random.random(size=N)

print("np.mean 64:", np.mean(x))
print("np.sum  64:", np.sum(x))
x = x.astype(np.float16)
mean16 = np.mean(x)
print("np.mean 16:", np.mean(x))
print("np.sum  16:", np.sum(x))

with tf.Session() as sess:
    x = tf.constant(x, dtype=np.float16)
    print("tf.reduce_mean 16:",
          sess.run(tf.reduce_mean(x)))
1
R zu 23 Июн 2019 в 20:52

3 ответа

Лучший ответ

Результат:

tf.reduce_mean, tree reduction: 0.5

Контрольная работа:

import numpy as np
import tensorflow as tf


N = int(1e8)
x = np.random.random(size=N).astype(np.float16)

with tf.Session() as sess:
    a = tf.reshape(x, (100, 100, 100, 100))
    for i in range(4):
        a = tf.reduce_mean(a, axis=-1)
    print("tf.reduce_mean, tree reduction:", sess.run(a))
0
R zu 23 Июн 2019 в 18:18

Из нудистской документации:

По умолчанию результаты float16 вычисляются с использованием промежуточных чисел float32 для дополнительной точности.

Из документации tenorflow:

Обратите внимание, что np.mean имеет параметр dtype, который можно использовать для указания типа вывода. По умолчанию это dtype=float64. С другой стороны, tf.reduce_mean имеет агрессивный вывод типа из input_tensor ...

Так что, вероятно, не лучше, чем sess.run(tf.reduce_mean(tf.cast(x, np.float32)))).

2
Imperishable Night 23 Июн 2019 в 18:12

Я попробовал это и получил результат 0.5. Я использую Tensorflow 1.13.1 с графическим процессором.

import numpy as np
import tensorflow as tf

x = np.random.random(size=10**8).astype(np.float16)
px = tf.placeholder(dtype=tf.float16, shape=(None,), name="x")

with tf.Session() as sess:
    print(sess.run(tf.reduce_mean(px), feed_dict={px: x}))
1
GZ0 23 Июн 2019 в 18:27