टेनसफ़्लो में नाम स्कोप और एक वैरिएबल स्कोप में क्या अंतर है?


276

इन कार्यों के बीच अंतर क्या है?

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

एक सेशन को परिभाषित करने के लिए एक संदर्भ प्रबंधक देता है जो चर बनाता है। यह संदर्भ प्रबंधक यह पुष्टि करता है कि दिए गए मान एक ही ग्राफ़ से हैं, यह सुनिश्चित करता है कि ग्राफ़ डिफ़ॉल्ट ग्राफ़ है, और एक नाम गुंजाइश और एक चर गुंजाइश को धक्का देता है।


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

पायथन ऑप को परिभाषित करते समय उपयोग के लिए एक संदर्भ प्रबंधक देता है। यह संदर्भ प्रबंधक यह पुष्टि करता है कि दिए गए मान एक ही ग्राफ़ से हैं, यह सुनिश्चित करता है कि ग्राफ़ डिफ़ॉल्ट ग्राफ़ है, और एक नाम गुंजाइश को धक्का देता है।


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कंस्ट्रक्टर का उपयोग करने से अलग है जो हर बार एक नया वैरिएबल बनाएगा जिसे कहा जाता है (और संभावित रूप से वैरिएबल नाम में एक प्रत्यय जोड़ें अगर ऐसा नाम वाला चर पहले से मौजूद है)।

यह चर साझा तंत्र के उद्देश्य के लिए है कि एक अलग प्रकार के दायरे (चर गुंजाइश) को पेश किया गया था।

नतीजतन, हमारे पास दो अलग-अलग प्रकार के स्कोप हैं:

  • नाम गुंजाइश , का उपयोग कर बनायाtf.name_scope
  • चर गुंजाइश , का उपयोग कर बनायाtf.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दोनों को पदावनत और प्रतिस्थापित किया गया है name_scopeऔर variable_scope


41
स्पष्ट स्पष्टीकरण के लिए धन्यवाद। स्वाभाविक रूप से, सवाल को एक अनुवर्ती होगा " क्यों Tensorflow इन भ्रामक रूप से एक जैसी कार्यविधि के दोनों है? क्यों नहीं उन्हें सिर्फ एक के साथ बदलें scopeप्रभावी तरीके से करता है जो एक विधि variable_scope?"
जॉन

8
मुझे नहीं लगता कि मैं वैचारिक रूप से समझता हूं कि variable_scopeबनाम के बीच अंतर की आवश्यकता क्यों है name_scope। यदि कोई एक चर बनाता है (किसी भी तरह से tf.Variableया उसके साथ tf.get_variable), तो यह मेरे लिए और अधिक स्वाभाविक लगता है कि यदि हम गुंजाइश या इसका पूरा नाम निर्दिष्ट करते हैं, तो हमें हमेशा इसे प्राप्त करने में सक्षम होना चाहिए। मुझे समझ में नहीं आता कि कोई स्कोप नाम की चीज़ को नज़रअंदाज़ क्यों करता है जबकि दूसरा नहीं करता। क्या आप इस अजीब व्यवहार के लिए तर्कसंगत समझते हैं?
चार्ली पार्कर

23
कारण यह है कि परिवर्तनीय गुंजाइश के साथ, कोई पुन: प्रयोज्य चर के लिए अलग-अलग स्कोप को परिभाषित कर सकता है जो कि संचालन को परिभाषित करने के लिए उपयोग किए जाने वाले वर्तमान नाम के दायरे से प्रभावित नहीं होते हैं।
एंड्रेज प्रोजोबिस

6
नमस्कार , क्या आप बता सकते हैं कि वेरिएबल_स्कोप में वेरिएबल का नाम हमेशा a: 0 के साथ क्यों होता है? क्या इसका मतलब है कि चर नाम 1,: 2, आदि के साथ समाप्त हो सकते हैं, इसलिए यह कैसे हो सकता है?
जेम्स फैन

2
@JamesFan हर "घोषणा" एक ऑपरेशन है, इसलिए जब आप एक = tf.Variable (.. नाम) कहते हैं, तो आपको एक टेंसर वापस मिल जाता है, लेकिन यह वास्तव में एक ऑपरेशन भी बनाता है। यदि आप एक प्रिंट करते हैं, तो आप एक: 0 के साथ टेंसर प्राप्त करेंगे। यदि आप a.op प्रिंट करते हैं तो आपको वह ऑपरेशन मिलता है जो उस टेनर मान की गणना करेगा।
रॉबर्ट लैग

84

दोनों variable_op_scope और op_scope अब पदावनत कर रहे हैं और सब पर नहीं किया जाना चाहिए।

के बारे में अन्य दो, मैं भी बीच का अंतर समझ समस्या नहीं थी 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, constants। दूसरी ओर tf.name_scope()बनाए गए चरों की उपेक्षा करता है tf.get_variable()क्योंकि यह मानता है कि आप जानते हैं कि आप किस चर और किस दायरे में उपयोग करना चाहते हैं।

साझाकरण चर पर एक अच्छा प्रलेखन आपको बताता है कि

tf.variable_scope(): पारित नामों के लिए नामस्थान का प्रबंधन करता है tf.get_variable()

एक ही प्रलेखन अधिक विवरण प्रदान करता है कि चर स्कोप कैसे काम करता है और यह कब उपयोगी है।


2
उदाहरण और दृश्यों के साथ शानदार उत्तर, चलो इस उत्तर को उत्कीर्ण लोगों को प्राप्त करें!
डेविड पार्क

43

Namespaces, hierarchical तरीके से चर और ऑपरेटरों के लिए नामों को व्यवस्थित करने का एक तरीका है (उदाहरण के लिए "गुंजाइश / गुंजाइशB / गुंजाइश / 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. tf.op_scopeऔर tf.variable_op_scopeबस एक गुंजाइश बनाने के लिए निर्दिष्ट चर की सूची से एक ग्राफ का चयन करें। उनके व्यवहार के अलावा tf.name_scopeऔर उसके tf.variable_scopeअनुसार
  3. tf.variable_scopeऔर variable_op_scopeनिर्दिष्ट या डिफ़ॉल्ट इनिशियलाइज़र जोड़ें।

वह ग्राफ जिसके लिए निर्दिष्ट चर बनाए गए थे? क्या इसका मतलब fabrizioM द्वारा उपर्युक्त उदाहरण के रूप में tf.variable_op_scope ([a, b], "mysum2") के रूप में गुंजाइश के रूप में है, यहाँ पैरामीटर a और b इस फ़ंक्शन से प्रभावित नहीं हैं और इस दायरे में परिभाषित चर प्रभावित नहीं हैं?
शियायुई यांग

दोनों प्रश्नों का उत्तर हां है: वह ग्राफ जिसमें निर्दिष्ट चर बनाए गए थे और वे संशोधित नहीं हुए हैं।
अलेक्जेंडर गोर्बन

क्या इसका मतलब यह है कि tf.name_scope और tf.variable_scope का उपयोग केवल डिफ़ॉल्ट ग्राफ़ में किया जाता है, लेकिन जब आप स्पष्ट रूप से tf.Graph () का उपयोग करके एक ग्राफ़ को परिभाषित और संकुचित करते हैं, तो अन्य दो फ़ंक्शन tf.op_scope और tf.variable_op_scope का उपयोग नहीं किया जा सकता है। यह ग्राफ!
शियायुई यांग

12

आइए इसे सरल बनाएं: बस उपयोग करें tf.variable_scopeTF डेवलपर का उद्धरण :

वर्तमान में, हम सभी को आंतरिक कोड और पुस्तकालयों को छोड़कर 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

एपीआई 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

आप उन्हें दो समूहों के रूप में सोच सकते हैं: 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

चर का नाम 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

आप ट्यूटोरियल में वेरिएबल स्कोप के बारे में अधिक पढ़ सकते हैं । स्टैक ओवरफ्लो पर पहले भी इसी तरह का सवाल पूछा गया था ।


2

टेनसफ़्लो दस्तावेज़ के इस पृष्ठ के अंतिम भाग से: ऑप्स के नामtf.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"

नाम स्कोप्स को एक वैरिएबल स्कोप के अलावा खोला जा सकता है, और फिर वे केवल ऑप्स के नामों को प्रभावित करेंगे, लेकिन वेरिएबल्स के नहीं।

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"

स्ट्रिंग के बजाय कैप्चर किए गए ऑब्जेक्ट का उपयोग करके एक वैरिएबल स्कोप खोलते समय, हम ऑप्स के लिए वर्तमान नाम स्कोप को नहीं बदलते हैं।


2

Tensorflow 2.0 संगत जवाब : के स्पष्टीकरण Andrzej Pronobisऔर Salvador Daliसंबंधित कार्यों के बारे में बहुत विस्तृत हैंScope

ऊपर वर्णित स्कोप फ़ंक्शंस में से, जो अब (17 फरवरी 2020) तक सक्रिय हैं variable_scopeऔर हैंname_scope

उन कार्यों के लिए 2.0 संगत कॉल निर्दिष्ट करते हुए, हमने समुदाय के लाभ के लिए ऊपर चर्चा की।

1.x में कार्य :

tf.variable_scope

tf.name_scope

2.x में प्रतिक्रियाशील समारोह :

tf.compat.v1.variable_scope

tf.name_scope( tf.compat.v2.name_scopeयदि माइग्रेट किया गया है 1.x to 2.x)

1.x से 2.x पर माइग्रेशन के बारे में अधिक जानकारी के लिए, कृपया इस माइग्रेशन गाइड को देखें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.