tensorflowの名前スコープと変数スコープの違いは何ですか?


276

これらの機能の違いは何ですか?

tf.variable_op_scope(values, name, default_name, initializer=None)

変数を作成するopを定義するためのコンテキストマネージャを返します。このコンテキストマネージャは、指定された値が同じグラフからのものであることを検証し、そのグラフがデフォルトのグラフであることを確認し、名前スコープと変数スコープをプッシュします。


tf.op_scope(values, name, default_name=None)

Python opを定義するときに使用するコンテキストマネージャを返します。このコンテキストマネージャは、指定された値が同じグラフからのものであることを検証し、そのグラフがデフォルトのグラフであることを確認して、名前スコープをプッシュします。


tf.name_scope(name)

Graph.name_scope()デフォルトのグラフを使用するためのラッパー。詳細についてはGraph.name_scope()、を参照してください。


tf.variable_scope(name_or_scope, reuse=None, initializer=None)

変数スコープのコンテキストを返します。変数スコープを使用すると、新しい変数を作成したり、すでに作成した変数を共有したりできますが、誤って作成したり共有したりしないことを確認できます。詳細については、変数スコープのハウツーを参照してください。ここでは、いくつかの基本的な例のみを示します。


回答:


377

変数共有の簡単な紹介から始めましょう。これはTensorFlow、変数への参照を渡さずに、コードのさまざまな部分でアクセスされる変数を共有できるメカニズムです。

このメソッドtf.get_variableは、変数の名前を引数として使用して、そのような名前で新しい変数を作成するか、以前に作成された変数を取得できます。これは、tf.Variable呼び出されるたびに新しい変数を作成するコンストラクターを使用する場合とは異なります(そのような名前の変数がすでに存在する場合は、変数名にサフィックスを追加する可能性があります)。

別のタイプのスコープ(変数スコープ)が導入されたのは、変数共有メカニズムのためです。

結果として、2つの異なるタイプのスコープができます。

両方のスコープは、すべての操作とを使用して作成された変数に同じ影響を及ぼします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_scopevariable_op_scopeの両方されている非推奨と置き換えられname_scopevariable_scope


41
明確な説明をありがとう。当然のことながら、質問のフォローアップは次のようになり、「なぜ Tensorflowは、これらの紛らわしいメカニズムの両方を持っているのですか?なぜ1つのだけでなく、それらを置き換えるscope効果的に行い方法variable_scope?」
ジョン

8
なぜvariable_scopevs の区別がname_scope必要なのか、概念的には理解できないと思います。変数を(tf.Variableまたはを使用してtf.get_variable)作成した場合、スコープまたはその完全名を指定すると、常に変数を取得できるはずです。なぜスコープ名を無視するのか、他の人が無視しないのか分かりません。この奇妙な行動の合理性を理解していますか?
チャーリーパーカー

23
その理由は、変数スコープを使用すると、操作の定義に使用される現在の名前スコープの影響を受けない、再利用可能な変数に対して個別のスコープを定義できるためです。
アンジェイプロノビス2017年

6
こんにちは、variable_scopeの変数名が常に:0で終わる理由を説明できますか?これは、変数名が:1、:2などで終わる可能性があることを意味しますか?
Jamesファン

2
@JamesFanすべての「宣言」は操作なので、a = tf.Variable(.. name)と言うとテンソルが返されますが、実際には操作も作成されます。aを出力すると、:0のテンソルが得られます。a.opを出力すると、そのテンソル値を計算する操作が得られます。
Robert Lugg

84

どちらもvariable_op_scopeop_scopeが廃止され、すべてで使用すべきではありません。

他の2つについても、簡単な例を作成してすべてを視覚化しようとする前に、variable_scopename_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を開くと、同様のパターンが表示されます(ご覧のとおりbscope_name長方形の外側にあります)。


これはあなたに答えを与えます

これでtf.variable_scope()、すべての変数(作成方法に関係なく)、ops、定数の名前にプレフィックスが追加されます。一方、では、使用したい変数とスコープがわかっていることを前提としているため、でtf.name_scope()作成されtf.get_variable()た変数は無視されます。

変数の共有に関する優れたドキュメントは、

tf.variable_scope():に渡される名前の名前空間を管理しますtf.get_variable()

同じドキュメントに、変数スコープのしくみとその有用性について詳しく説明されています。


2
例とビジュアルを使ったすばらしい答えです。この答えに賛成票を投じましょう。
デビッドパークス

43

名前空間は、変数や演算子の名前を階層的に整理する方法です(「scopeA / scopeB / scopeC / op1」など)。

  • tf.name_scope デフォルトのグラフに演算子の名前空間を作成します。
  • tf.variable_scope デフォルトのグラフに変数と演算子の両方の名前空間を作成します。

  • tf.op_scopeと同じですがtf.name_scope、指定された変数が作成されたグラフ用です。

  • tf.variable_op_scopeと同じですがtf.variable_scope、指定された変数が作成されたグラフ用です。

上記のソースへのリンクは、このドキュメントの問題を明確にするのに役立ちます。

この例は、すべてのタイプのスコープが変数と演算子の両方の名前空間を定義していることを示していますが、次の違いがあります。

  1. によって定義された、tf.variable_op_scopeまたはtf.variable_scope互換性tf.get_variableのあるスコープ(他の2つのスコープは無視されます)
  2. tf.op_scopeそしてtf.variable_op_scopeちょうどのためのスコープを作成するために、指定された変数のリストからグラフを選択します。同等のtf.name_scopetf.variable_scopeしたがってそれに応じた行動以外
  3. tf.variable_scopevariable_op_scope指定またはデフォルトの初期化子を追加します。

指定された変数が作成されたグラフについては?これは、上記のfabrizioMの例のように、スコープとしてtf.variable_op_scope([a、b]、name、 "mysum2")を使用することを意味しますか?ここで、パラメーターaおよびbはこの関数の影響を受けず、このスコープで定義された変数が影響を受けますか?
Xiuyi Yang

両方の質問に対する答えは「はい」です。指定された変数が作成され、変更されていないグラフ。
Alexander Gorban 2016年

これは、tf.name_scopeとtf.variable_scopeがデフォルトのグラフでのみ使用されることを意味しますが、tf.Graph()を使用して明らかにグラフを定義および構築すると、他の2つの関数tf.op_scopeおよびtf.variable_op_scopeは使用できません。このグラフ!
Xiuyi Yang

12

簡単にしましょう:を使用するだけ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このような非互換性に起因するいくつかの頭痛を避けるためにあなただけに固執することによって。


9

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'

8

これらは2つのグループと考えることができます。variable_op_scopeまたop_scope、変数のセットを入力として受け取り、操作を作成するように設計されています。違いは、変数の作成にどのように影響するかです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

v2つの例の変数の名前に注意してください。

同じのためtf.name_scopetf.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

変数スコープの詳細については、チュートリアルをご覧ください。Stack Overflowで以前に同様の質問が行われました。


2

tensorflowドキュメントのこのページの最後のセクションから:in ops in intf.variable_scope()

[...]実行する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の現在の名前スコープは変更しません。


2

Tensorflow 2.0互換性のある回答:に関連する関数の説明Andrzej PronobisSalvador Dali非常に詳細Scopeです。

上記(2020年2月17日)の時点でアクティブになっている上記のスコープ関数にはvariable_scope、およびがありname_scopeます。

コミュニティのために、上記で説明した、これらの関数の2.0互換呼び出しを指定します。

1.xの機能

tf.variable_scope

tf.name_scope

2.xの各機能

tf.compat.v1.variable_scope

tf.name_scopetf.compat.v2.name_scopeから移行した場合1.x to 2.x

1.xから2.x への移行の詳細については、この移行ガイドを参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.