web-dev-qa-db-ja.com

tf.set_random_seedを使用したTensorflowの再現可能な結果

私は独立した乱数のNセットを生成しようとしています。 10個の乱数の3セットの問題を示す簡単なコードがあります。 tf.set_random_seedを使用してシードを設定しても、異なる実行の結果は似ていないことがわかります。どんな助けやコメントも大歓迎です。

(py3p6) bash-3.2$ cat test.py 
import tensorflow as tf
for i in range(3):
  tf.set_random_seed(1234)
  generate = tf.random_uniform((10,), 0, 10)
  with tf.Session() as sess:
    b = sess.run(generate)
    print(b)

これはコードの出力です:

# output :
[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]
[8.559105  3.2390785 6.447526  8.316823  1.6297233 1.4103293 2.647568
 2.954973  6.5975866 7.494894 ]
[2.0277488 6.6134906 0.7579422 4.6359386 6.97507   3.3192968 2.866236
 2.2205782 6.7940736 7.2391043]

私は何かが欲しい

[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]
[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]
[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]

更新1:実際にforループ内にシード初期化子を配置した理由は、それらを異なるように設定したいためです(たとえば、MCMCの実行が異なる場合など)。これは仕事をする私のコードですが、それが効率的かどうかはわかりません。基本的に、0〜2 ^ 32-1のランダムなシードをいくつか生成し、実行するたびにシードを変更します。メモリ/ RAMの効率を高めるためのヘルプやコメントを歓迎します。

import numpy as np
import tensorflow as tf
global_seed = 42
N_chains = 5
np.random.seed(global_seed)
seeds = np.random.randint(0, 4294967295, size=N_chains)

for i in range(N_chains):
    tf.set_random_seed(seeds[i])
    .... some stuff ....
    kernel_initializer = tf.random_normal_initializer(seed=seeds[i])
    .... some stuff
    with tf.Session() as sess:
         .... some stuff .....
 .
 .
 .
9
Mehdi Rezaie

テンソルフローでは、ランダム操作は2つの異なるシードに依存します:tf.set_random_seedで設定されるグローバルシードと、操作の引数として提供される操作シードです。それらがどのように関連するかについての詳細を見つけるでしょう ドキュメントで

各ランダムopは、擬似乱数生成のために独自の内部状態を維持するため、各ランダムopに異なるシードがあります。各ランダムジェネレーターが独自の状態を維持する理由は、変化に強いことです:同じ状態を共有している場合、グラフのどこかに新しいランダムジェネレーターを追加すると、他のすべてのジェネレーターによって生成される値が変更され、目的が無効になりますシードを使用します。

さて、なぜグローバルandのper-opシードの二重システムがあるのでしょうか?実際、グローバルシードは必要ありません。利便性のためにあります:すべてのランダムopシードを、すべてを徹底的に調べることなく、一度に異なる確定的な値(不明な場合)に設定できます。

ドキュメントによると、グローバルシードは設定されているがopシードは設定されていない場合、

システムは、一意のランダムシーケンスを取得するように、グラフレベルのシードと連動して操作シードを決定論的に選択します。

より正確には、提供されるシードは、現在のグラフで作成された最後の操作のIDです。したがって、グローバルにシードされたランダム操作は、グラフの変更、特にそれ自体の前に作成された変更に非常に敏感です。

例えば、

import tensorflow as tf
tf.set_random_seed(1234)
generate = tf.random_uniform(())
with tf.Session() as sess:
  print(generate.eval())
  # 0.96046877

前にノードを作成すると、結果が変わります:

import tensorflow as tf
tf.set_random_seed(1234)
tf.zeros(()) # new op added before 
generate = tf.random_uniform(())
with tf.Session() as sess:
  print(generate.eval())
  # 0.29252338

ただし、ノードが後に作成される場合、opシードには影響しません。

import tensorflow as tf
tf.set_random_seed(1234)
generate = tf.random_uniform(())
tf.zeros(()) # new op added after
with tf.Session() as sess:
  print(generate.eval())
  # 0.96046877

明らかに、あなたの場合のように、いくつかの操作を生成する場合、それらは異なるシードを持ちます:

import tensorflow as tf
tf.set_random_seed(1234)
gen1 = tf.random_uniform(())
gen2 = tf.random_uniform(())
with tf.Session() as sess:
  print(gen1.eval())
  print(gen2.eval())
  # 0.96046877
  # 0.85591054

好奇心として、そしてシードが単にグラフで最後に使用されたIDであるという事実を検証するために、gen2のシードをgen1に揃えることができます。

import tensorflow as tf
tf.set_random_seed(1234)
gen1 = tf.random_uniform(())
# 4 operations seems to be created after seed has been picked
seed = tf.get_default_graph()._last_id - 4
gen2 = tf.random_uniform((), seed=seed)
with tf.Session() as sess:
  print(gen1.eval())
  print(gen2.eval())
  # 0.96046877
  # 0.96046877

ただし、明らかに、これはコードレビューに合格するべきではありません。

9
P-Gn

Tensorflow 2.0tf.random.set_random_seed(seed)tf.random.set_seed(seed)に変更しました。

tFドキュメントを参照してください:

5
mx_muc

関連する GitHubの問題 があります。しかし、あなたの場合は、 tf.set_random_seed

グラフレベルのランダムシードを設定します。

おそらくsameグラフとsame操作を使用して、 samedifferentセッションの乱数。

import tensorflow as tf

tf.set_random_seed(1234)
generate = tf.random_uniform((10,), 0, 10)
tf.get_default_graph().finalize() # something everybody tends to forget

for i in range(3):
    with tf.Session() as sess:
        b = sess.run(generate)
        print(b)

与える

[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]
[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]
[9.604688  5.811516  6.4159    9.621765  0.5434954 4.1893444 5.8865128
 7.9785547 8.296125  8.388672 ]

あなたの場合、同じグラフ内に異なる操作を作成しました。

4
Patwie

パーティーに遅れて、しかし、乱数ジェネレーターがオーバーホールされました(プロセスの要約については https://github.com/tensorflow/community/pull/38 を参照)およびtf.random.experimental.Generatorクラスが必要な機能を提供するようになりました。

TF 1.14以降(TF 2.0を含む)から、ジェネレーターをシードして、セッション、プラットフォーム、またはアーキテクチャに関係なく、まったく同じ乱数を取得できます。

import tensorflow as tf

rng = tf.random.experimental.Generator.from_seed(1234)
rng.uniform((), 5, 10, tf.int64)  # draw a random scalar (0-D tensor) between 5 and 10

詳細については、ドキュメントを参照してください。

特定の質問に対処するには(TF 2.0を使用しています):

for i in range(3):
  b = tf.random.uniform((10,), 0, 10, seed=1234)
  print(b)

与える

tf.Tensor(
[2.7339518  9.339194   5.2865124  8.912003   8.402512   0.53086996
 4.385383   4.8005686  2.2077608  2.1795273 ], shape=(10,), dtype=float32)
tf.Tensor(
[9.668942   3.4503186  7.4577675  2.9200733  1.8064988  6.1576104
 3.9958012  1.889689   3.8289428  0.36031008], shape=(10,), dtype=float32)
tf.Tensor(
[8.019657  4.895439  5.90925   2.418766  4.524292  7.901089  9.702316
 5.1606855 9.744821  2.4418736], shape=(10,), dtype=float32)

これながら

for i in range(3):
  rng = tf.random.experimental.Generator.from_seed(1234)
  b = rng.uniform((10,), 0, 10)
  print(b)

あなたが欲しいものを与えます:

tf.Tensor(
[3.581475  1.132276  5.6670904 6.712369  3.2565057 1.7095459 8.468903
 6.2697005 1.0973608 2.7732193], shape=(10,), dtype=float32)
tf.Tensor(
[3.581475  1.132276  5.6670904 6.712369  3.2565057 1.7095459 8.468903
 6.2697005 1.0973608 2.7732193], shape=(10,), dtype=float32)
tf.Tensor(
[3.581475  1.132276  5.6670904 6.712369  3.2565057 1.7095459 8.468903
 6.2697005 1.0973608 2.7732193], shape=(10,), dtype=float32)
2
John Doe

グラフには1つではなく3つのgenerate変数(操作)が定義されているため、実行ごとに異なる結果が得られます。これは、forループ内に3つの操作につながる生成操作があるためです。_(Tensor("random_uniform:0"), Tensor("random_uniform_1:0"), Tensor("random_uniform_2:0"))_。 forループ内でprint(generate)するだけです。上記の3つの異なる操作が表示されます。

_tf.set_random_seed_は、グラフレベルでシードを設定します。そのため、グラフ内の各操作のシードを決定論的に選択します。そのため、3つのgenerate操作には、実行ごとに同じ3つのシードが割り当てられます。これが、実行ごとに、3つの変数すべてに対応して同じ結果が表示される理由です。ランダムシードの設定の詳細については、 this をご覧ください。

そのため、セッションを実行するたびに同じ結果が得られるようにするには、次のようにします。

_tf.set_random_seed(1234)
generate = tf.random_uniform((10,), 0, 10)
for i in range(3):
    with tf.Session() as sess:
        b = sess.run(generate)
        print(b)
_

しかし、なぜnセッションを作成したいのですか。 1つのセッションを作成してから、セッションをn回実行するのが理想的です。実行ごとに新しいセッションを作成する必要はなく、変数と操作をグラフ内のデバイス(GPUまたはCPU)に配置しようとするたびに必要です。

0