これらの機能の違いは何ですか?
tf.variable_op_scope(values, name, default_name, initializer=None)
変数を作成する操作を定義するためのコンテキストマネージャを返します。このコンテキストマネージャは、与えられた値が同じグラフからのものであることを検証し、そのグラフがデフォルトグラフであることを確認し、そして名前スコープと変数スコープをプッシュします。
tf.op_scope(values, name, default_name=None)
Pythonの操作を定義するときに使用するコンテキストマネージャを返します。このコンテキストマネージャは、与えられた値が同じグラフからのものであることを検証し、そのグラフがデフォルトのグラフであることを確認し、そして名前スコープをプッシュします。
tf.name_scope(name)
デフォルトのグラフを使った
Graph.name_scope()
のラッパー。詳しくはGraph.name_scope()
をご覧ください。
tf.variable_scope(name_or_scope, reuse=None, initializer=None)
変数スコープのコンテキストを返します。変数スコープは、新しい変数を作成し、すでに作成されたものを共有しながら、偶然に作成または共有しないようにチェックを提供します。詳細については、可変範囲の操作方法を参照してください。ここでは、基本的な例をいくつか紹介します。
変数共有の簡単な紹介から始めましょう。これはTensorFlow
内のメカニズムであり、変数への参照を渡すことなくコードのさまざまな部分でアクセスされた変数を共有することを可能にします。
メソッド tf.get_variable
を引数として変数の名前と共に使用して、そのような名前で新しい変数を作成するか、以前に作成されたものを取得することができます。これは、呼び出されるたびに新しい変数を作成する tf.Variable
コンストラクタを使用するのとは異なります(そのような名前の変数がすでに存在する場合は、変数名にサフィックスを追加することもできます)。
変数共有メカニズムの目的のために、別のタイプのスコープ(変数スコープ)が導入されました。
結果として、2つの異なる種類のスコープを持つことになります。
tf.name_scope
を使用して作成tf.variable_scope
を使用して作成されたvariable scope両方のスコープは、すべての操作とtf.Variable
を使用して作成された変数に同じ効果を持ちます。つまり、スコープは操作または変数名の接頭辞として追加されます。
ただし、名前の有効範囲はtf.get_variable
では無視されます。次の例でそれがわかります。
with tf.name_scope("my_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # var1:0
print(v2.name) # my_scope/var2:0
print(a.name) # my_scope/Add:0
スコープ内でtf.get_variable
を使用してアクセスされた変数を配置する唯一の方法は、次の例のように変数スコープを使用することです。
with tf.variable_scope("my_scope"):
v1 = tf.get_variable("var1", [1], dtype=tf.float32)
v2 = tf.Variable(1, name="var2", dtype=tf.float32)
a = tf.add(v1, v2)
print(v1.name) # my_scope/var1:0
print(v2.name) # my_scope/var2:0
print(a.name) # my_scope/Add:0
これにより、異なる名前スコープ内であっても、プログラムのさまざまな部分で変数を簡単に共有できます。
with tf.name_scope("foo"):
with tf.variable_scope("var_scope"):
v = tf.get_variable("var", [1])
with tf.name_scope("bar"):
with tf.variable_scope("var_scope", reuse=True):
v1 = tf.get_variable("var", [1])
assert v1 == v
print(v.name) # var_scope/var:0
print(v1.name) # var_scope/var:0
バージョンr0.11の時点で、op_scope
とvariable_op_scope
はどちらも deprecated であり、name_scope
とvariable_scope
に置き換えられています。
variable_op_scope と op_scope の両方は現在推奨されていないため、まったく使用しないでください。
他の2つに関しては、簡単な例を作成してすべてを視覚化する前に、 variable_scope と name_scope の違いを理解するのに問題がありました(それらはほぼ同じに見えました)。
import tensorflow as tf
def scoping(fn, scope1, scope2, vals):
with fn(scope1):
a = tf.Variable(vals[0], name='a')
b = tf.get_variable('b', initializer=vals[1])
c = tf.constant(vals[2], name='c')
with fn(scope2):
d = tf.add(a * b, c, name='res')
print '\n '.join([scope1, a.name, b.name, c.name, d.name]), '\n'
return d
d1 = scoping(tf.variable_scope, 'scope_vars', 'res', [1, 2, 3])
d2 = scoping(tf.name_scope, 'scope_name', 'res', [1, 2, 3])
with tf.Session() as sess:
writer = tf.summary.FileWriter('logs', sess.graph)
sess.run(tf.global_variables_initializer())
print sess.run([d1, d2])
writer.close()
ここでは、いくつかの変数と定数を作成し、それらをスコープ内にグループ化する関数を作成します(提供したタイプによって異なります)。この関数では、すべての変数の名前も表示します。その後、グラフを実行して結果の値を取得し、イベントファイルを保存してTensorBoardでそれらを調べます。これを実行すると、次のようになります。
scope_vars
scope_vars/a:0
scope_vars/b:0
scope_vars/c:0
scope_vars/res/res:0
scope_name
scope_name/a:0
b:0
scope_name/c:0
scope_name/res/res:0
TensorBoardを開くと、同様のパターンが表示されます(b
がscope_name
の矩形の外側にあるように見えます):
これはあなたに答えを与える :
これで、tf.variable_scope()
は(変数の作成方法に関係なく)すべての変数、ops、定数の名前に接頭辞を追加することがわかりました。一方、tf.name_scope()
は、tf.get_variable()
で作成された変数を無視します。
変数の共有 に関する優れたドキュメントは、
tf.variable_scope()
:tf.get_variable()
に渡される名前の名前空間を管理します。
同じドキュメントに、変数スコープの機能の詳細と有用性に関する詳細が記載されています。
名前空間は、変数と演算子の名前を階層的に整理する方法です(例: "scopeA/scopeB/scopeC/op1")。
tf.name_scope
はデフォルトグラフの演算子の名前空間を作成します。tf.variable_scope
はデフォルトグラフの変数と演算子の両方の名前空間を作成します。
tf.op_scope
tf.name_scope
と同じですが、指定された変数が作成されたグラフ用です。
tf.variable_op_scope
tf.variable_scope
と同じですが、指定された変数が作成されたグラフ用です。
上記の資料へのリンクは、このドキュメントの問題を明確にするのに役立ちます。
この例 は、すべての種類のスコープが、変数と演算子の両方に対して名前空間を定義していることを示しています。
tf.variable_op_scope
またはtf.variable_scope
で定義されたスコープはtf.get_variable
と互換性があります(他の2つのスコープは無視されます)。tf.op_scope
とtf.variable_op_scope
はスコープを作成するために指定された変数のリストからグラフを選択するだけです。それ以外の動作はtf.name_scope
およびtf.variable_scope
と同等ですtf.variable_scope
とvariable_op_scope
は、指定された、またはデフォルトの初期化子を追加します。API r0.11に関しては、op_scope
とvariable_op_scope
は両方とも 非推奨 です。 name_scope
とvariable_scope
は入れ子にすることができます。
with tf.name_scope('ns'):
with tf.variable_scope('vs'): #scope creation
v1 = tf.get_variable("v1",[1.0]) #v1.name = 'vs/v1:0'
v2 = tf.Variable([2.0],name = 'v2') #v2.name= 'ns/vs/v2:0'
v3 = v1 + v2 #v3.name = 'ns/vs/add:0'
variable_op_scope
とop_scope
は、入力として変数のセットを受け取り、操作を作成するように設計されている2つのグループとして考えることができます。違いは、それらがtf.get_variable
による変数の作成にどのように影響するかです。
def mysum(a,b,name=None):
with tf.op_scope([a,b],name,"mysum") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert v2.name == "mysum/v2:0", v2.name
return tf.add(a,b)
def mysum2(a,b,name=None):
with tf.variable_op_scope([a,b],name,"mysum2") as scope:
v = tf.get_variable("v", 1)
v2 = tf.Variable([0], name="v2")
assert v.name == "mysum2/v:0", v.name
assert v2.name == "mysum2/v2:0", v2.name
return tf.add(a,b)
with tf.Graph().as_default():
op = mysum(tf.Variable(1), tf.Variable(2))
op2 = mysum2(tf.Variable(1), tf.Variable(2))
assert op.name == 'mysum/Add:0', op.name
assert op2.name == 'mysum2/Add:0', op2.name
2つの例の変数v
の名前に注目してください。
tf.name_scope
とtf.variable_scope
についても同じです。
with tf.Graph().as_default():
with tf.name_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
with tf.Graph().as_default():
with tf.variable_scope("name_scope") as scope:
v = tf.get_variable("v", [1])
op = tf.add(v, v)
v2 = tf.Variable([0], name="v2")
assert v.name == "name_scope/v:0", v.name
assert op.name == "name_scope/Add:0", op.name
assert v2.name == "name_scope/v2:0", v2.name
tutorial で変数スコープについてもっと読むことができます。 以前に尋ねられた スタックオーバーフローについての同様の質問。
簡単にしましょう:tf.variable_scope
を使うだけです。 TF開発者の名言、 :
現在、内部コードとライブラリを除いて、誰もが
variable_scope
を使用し、name_scope
を使用しないことをお勧めします。
variable_scope
の機能が基本的にname_scope
の機能を拡張しているという事実に加えて、それらがどのように一緒にそれほどうまく遊ばないのかを考えてください:
with tf.name_scope('foo'):
with tf.variable_scope('bar'):
x = tf.get_variable('x', shape=())
x2 = tf.square(x**2, name='x2')
print(x.name)
# bar/x:0
print(x2.name)
# foo/bar/x2:0
variable_scope
だけに固執することによって、あなたはこの種の非互換性のためにいくつかの頭痛を避けます。
テンソルフロードキュメントのこのページの最後のセクションから: tf.variable_scope()
内のopsの名前
[...]
with tf.variable_scope("name")
を実行すると、暗黙のうちにtf.name_scope("name")
が開きます。例えば:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
変数スコープに加えて名前スコープを開くことができます。その場合、それらはopsの名前にのみ影響し、変数の名前には影響しません。
with tf.variable_scope("foo"):
with tf.name_scope("bar"):
v = tf.get_variable("v", [1])
x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"
文字列ではなくキャプチャされたオブジェクトを使用して変数のスコープを開くときに、opsの現在の名前のスコープを変更しません。