নাম স্কোপ এবং টেনসরফ্লোতে একটি পরিবর্তনশীল সুযোগের পার্থক্য কী?


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
পরিষ্কার ব্যাখ্যার জন্য ধন্যবাদ। স্বাভাবিকভাবেই, একটি ফলোআপ প্রশ্ন হবে " কেন টেনসরফ্লো উভয় এই বিভ্রান্তিকরভাবে অনুরূপ প্রক্রিয়া আছে? কেন কেবল একটি scopeপদ্ধতি যা কার্যকরভাবে কার্যকর করে তাদের সাথে প্রতিস্থাপন করবেন না variable_scope?"
জন

8
আমি মনে করি না আমি বুঝতে ধারণার দিক থেকে কেন মধ্যে পার্থক্য কি variable_scopeবনাম name_scopeএমনকি প্রয়োজন হয়। যদি কেউ একটি পরিবর্তনশীল তৈরি করে ( tf.Variableবা এর সাথে যে কোনও উপায়ে tf.get_variable), এটি আমার কাছে আরও স্বাভাবিক মনে হয় যে আমরা সুযোগ বা তার পুরো নামটি নির্দিষ্ট করে দিলে আমাদের সর্বদা এটি পাওয়া সম্ভব হবে। আমি বুঝতে পারি না কেন একজন কেন স্কোপ নামের জিনিসটিকে উপেক্ষা করে অন্যটি না করে doesn't আপনি কি এই অদ্ভুত আচরণের যুক্তি বোঝেন?
চার্লি পার্কার

23
কারণটি হ'ল ভেরিয়েবল স্কোপ সহ, কেউ পুনরায় ব্যবহারযোগ্য ভেরিয়েবলগুলির জন্য পৃথক স্কোপগুলি সংজ্ঞায়িত করতে পারে যা ক্রিয়াকলাপ সংজ্ঞায়িত করতে ব্যবহৃত বর্তমান নামের স্কোপ দ্বারা প্রভাবিত হয় না।
আন্দ্রেজ প্রোনোবিস

6
হ্যালো , আপনি কী ব্যাখ্যা করতে পারেন কেন একটি ভেরিয়েবল_স্কোপে ভেরিয়েবলের নামটি সর্বদা একটি: 0 দিয়ে শেষ হয়? এর অর্থ কি এখানে ভেরিয়েবলের নামগুলি সমাপ্ত হতে পারে: 1,: 2, ইত্যাদি ইত্যাদি, সুতরাং এটি কীভাবে ঘটতে পারে?
জেমস ফ্যান

2
@ জেমসফ্যান প্রতিটি "ঘোষণা" একটি অপারেশন, সুতরাং যখন আপনি a = tf. পরিবর্তনশীল (.. নাম) বলবেন তখন আপনি একটি সেন্সর ফিরে পাবেন, তবে এটি আসলে একটি অপারেশনও তৈরি করে। আপনি যদি একটি মুদ্রণ করেন তবে আপনি একটি: 0 দিয়ে টেনসর পাবেন। যদি আপনি a.op মুদ্রণ করেন তবে আপনি অপারেশনটি পান যা সেই টেনসর মানটি গণনা করবে।
রবার্ট লাগেজ

84

ভ্যারিয়েবল_পোস্কোপ এবং অপ_স্কোপ উভয়ই এখন অবচয় করা হয়েছে এবং একেবারেই ব্যবহার করা উচিত নয়।

অন্য দুটি সম্পর্কে, আমি ভেরিয়েবল_স্কোপ এবং নাম_স্কোপের মধ্যে পার্থক্য বুঝতে সমস্যা পেয়েছিলাম (তারা প্রায় একই দেখায়) আমি একটি সাধারণ উদাহরণ তৈরি করে সবকিছু কল্পনা করার চেষ্টা করার আগে:

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()

এখানে আমি একটি ফাংশন তৈরি করি যা কিছু ভেরিয়েবল এবং ধ্রুবক তৈরি করে এবং এগুলি স্কোপগুলিতে গোষ্ঠী করে (আমি সরবরাহিত ধরণের উপর নির্ভর করে)। এই ফাংশনে, আমি সমস্ত ভেরিয়েবলের নামও মুদ্রণ করি। এর পরে, ফলাফলের মানগুলির মান পেতে আমি গ্রাফটি সম্পাদন করি এবং টেনসরবোর্ডে তদন্তের জন্য ইভেন্ট-ফাইলগুলি সংরক্ষণ করি। আপনি এটি চালিয়ে গেলে, আপনি নিম্নলিখিত পাবেন:

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 

আপনি যদি টেনসরবোর্ডটি খোলেন তবে আপনি অনুরূপ প্যাটার্নটি দেখতে পান (যেমন আপনি দেখতে পান bযে scope_nameআয়তক্ষেত্রের বাইরে ):


এটি আপনাকে উত্তর দেয় :

এখন আপনি দেখতে পাচ্ছেন যে tf.variable_scope()সমস্ত ভেরিয়েবলের নামগুলিতে একটি উপসর্গ যুক্ত হয় (আপনি কীভাবে এটি তৈরি করেন তা নয়), অপস, ধ্রুবক। অন্যদিকে tf.name_scope()তৈরি ভেরিয়েবলগুলি উপেক্ষা করে tf.get_variable()কারণ এটি ধরে নেওয়া হয় যে আপনি জানেন যে কোন পরিবর্তনশীল এবং কোন সুযোগে আপনি ব্যবহার করতে চেয়েছিলেন।

ভেরিয়েবলগুলি ভাগ করে নেওয়ার বিষয়ে একটি ভাল ডকুমেন্টেশন আপনাকে তা জানায়

tf.variable_scope(): পাস করা নামগুলির জন্য নেমস্পেসগুলি পরিচালনা করে tf.get_variable()

একই ডকুমেন্টেশনটি ভেরিয়েবল স্কোপটি কীভাবে কাজ করে এবং কখন কার্যকর হয় সে সম্পর্কে আরও বিশদ সরবরাহ করে।


2
উদাহরণ এবং ভিজ্যুয়াল সহ চমত্কার উত্তর, আসুন এই উত্তরটি আপভোটিভ ভাবেন!
ডেভিড পার্কস

43

নেমস্পেসগুলি ভেরিয়েবল এবং অপারেটরদের নামক্রমক্রমিক পদ্ধতিতে সংগঠিত করার একটি উপায় (যেমন "স্কোপএ / স্কোপবি / স্কোপসি / ওপ 1")

  • 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নির্দিষ্ট বা ডিফল্ট ইনিশিয়ালাইজার যুক্ত করুন।

গ্রাফের জন্য কোন নির্দিষ্ট ভেরিয়েবল তৈরি করা হয়েছিল? এর অর্থ কি যেমন উপরের উদাহরণস্বরূপ ফেব্রিজিওএম দ্বারা 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_scopeএকটি টিএফ বিকাশকারীকে উদ্ধৃত করে :

বর্তমানে, আমরা অভ্যন্তরীণ কোড এবং লাইব্রেরি বাদে প্রত্যেককে ব্যবহার 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

টেনসরফ্লো ২.০ সুসংগত উত্তর : সম্পর্কিত কার্যাবলী সম্পর্কে তার ব্যাখ্যা Andrzej Pronobisএবং Salvador Daliখুব বিস্তারিতScope

উপরে আলোচিত ব্যাপ্তি কার্যকারিতাগুলির মধ্যে, যা এখন পর্যন্ত সক্রিয় রয়েছে (17 ফেব্রুয়ারী 2020) variable_scopeএবং andname_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 এ স্থানান্তর সম্পর্কে আরও তথ্যের জন্য, দয়া করে এই মাইগ্রেশন গাইডটি দেখুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.