Apa perbedaan ruang lingkup nama dan ruang lingkup variabel dalam tensorflow?

276

Apa perbedaan antara fungsi-fungsi ini?

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

Mengembalikan manajer konteks untuk mendefinisikan op yang menciptakan variabel. Manajer konteks ini memvalidasi bahwa nilai yang diberikan berasal dari grafik yang sama, memastikan bahwa grafik tersebut adalah grafik default, dan mendorong cakupan nama dan cakupan variabel.


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

Mengembalikan manajer konteks untuk digunakan ketika mendefinisikan op Python. Manajer konteks ini memvalidasi bahwa nilai yang diberikan berasal dari grafik yang sama, memastikan bahwa grafik tersebut adalah grafik default, dan mendorong cakupan nama.


tf.name_scope(name)

Wrapper untuk Graph.name_scope()menggunakan grafik default. Lihat Graph.name_scope()untuk lebih jelasnya.


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

Mengembalikan konteks untuk cakupan variabel. Ruang lingkup variabel memungkinkan untuk membuat variabel baru dan untuk berbagi yang sudah dibuat sambil memberikan pemeriksaan untuk tidak membuat atau berbagi secara tidak sengaja. Untuk detailnya, lihat Variabel Lingkup Cara, di sini kami hanya menyajikan beberapa contoh dasar.

Xiuyi Yang
sumber

Jawaban:

377

Mari kita mulai dengan pengantar singkat untuk berbagi variabel. Ini adalah mekanisme TensorFlowyang memungkinkan untuk berbagi variabel yang diakses di berbagai bagian kode tanpa meneruskan referensi ke variabel sekitar.

Metode tf.get_variableini dapat digunakan dengan nama variabel sebagai argumen untuk membuat variabel baru dengan nama tersebut atau mengambil yang dibuat sebelumnya. Ini berbeda dengan menggunakan tf.Variablekonstruktor yang akan membuat variabel baru setiap kali dipanggil (dan berpotensi menambahkan akhiran ke nama variabel jika variabel dengan nama tersebut sudah ada).

Untuk tujuan mekanisme berbagi variabel inilah diperkenalkan jenis cakupan yang terpisah (lingkup variabel).

Akibatnya, kami akhirnya memiliki dua jenis cakupan yang berbeda:

Kedua cakupan memiliki efek yang sama pada semua operasi serta variabel yang dibuat menggunakan tf.Variable, yaitu, ruang lingkup akan ditambahkan sebagai awalan untuk operasi atau nama variabel.

Namun, ruang lingkup nama diabaikan oleh tf.get_variable. Kita bisa melihat itu dalam contoh berikut:

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

Satu-satunya cara untuk menempatkan variabel yang diakses menggunakan tf.get_variabledalam lingkup adalah dengan menggunakan lingkup variabel, seperti dalam contoh berikut:

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

Ini memungkinkan kami untuk dengan mudah berbagi variabel di berbagai bagian program, bahkan dalam lingkup nama yang berbeda:

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

MEMPERBARUI

Pada versi r0.11, op_scopedan variable_op_scopekeduanya sudah usang dan digantikan oleh name_scopedan variable_scope.

Andrzej Pronobis
sumber
41
Terima kasih atas penjelasan yang jelas. Secara alami, sebuah pertanyaan lanjutan adalah " Mengapa Tensorflow memiliki kedua mekanisme yang mirip ini? Mengapa tidak menggantinya dengan hanya satu scopemetode yang secara efektif melakukan variable_scope?"
John
8
Saya tidak berpikir saya mengerti secara konseptual mengapa perbedaan antara variable_scopevs name_scopebahkan diperlukan. Jika seseorang membuat variabel (dengan cara apa pun dengan tf.Variableatau tf.get_variable), tampaknya lebih alami bagi saya bahwa kita harus selalu bisa mendapatkannya jika kita menentukan ruang lingkup atau nama lengkapnya. Saya tidak mengerti mengapa satu mengabaikan nama ruang lingkup sedangkan yang lain tidak. Apakah Anda memahami alasan perilaku aneh ini?
Charlie Parker
23
Alasannya adalah bahwa dengan cakupan variabel, seseorang dapat mendefinisikan cakupan terpisah untuk variabel yang dapat digunakan kembali yang tidak terpengaruh oleh cakupan nama saat ini yang digunakan untuk mendefinisikan operasi.
Andrzej Pronobis
6
Halo, dapatkah Anda menjelaskan mengapa nama variabel dalam variabel_scope selalu diakhiri dengan: 0? Apakah ini berarti mungkin ada nama variabel diakhiri dengan: 1,: 2, dll, jadi bagaimana ini bisa terjadi?
James Fan
2
@JamesFan Setiap "deklarasi" adalah operasi, jadi ketika Anda mengatakan a = tf.Variable (.. name) Anda mendapatkan kembali tensor, tetapi sebenarnya juga menciptakan sebuah operasi. jika Anda mencetak a, Anda akan mendapatkan tensor dengan: 0. Jika Anda mencetak a.op Anda mendapatkan operasi yang akan menghitung nilai tensor itu.
Robert Lugg
84

Baik variable_op_scope dan op_scope sekarang usang dan tidak boleh digunakan sama sekali.

Mengenai dua lainnya, saya juga memiliki masalah dalam memahami perbedaan antara variable_scope dan name_scope (mereka terlihat hampir sama) sebelum saya mencoba memvisualisasikan semuanya dengan membuat contoh sederhana:

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

Di sini saya membuat fungsi yang membuat beberapa variabel dan konstanta dan mengelompokkannya dalam cakupan (tergantung pada jenis yang saya berikan). Dalam fungsi ini, saya juga mencetak nama-nama semua variabel. Setelah itu, saya mengeksekusi grafik untuk mendapatkan nilai dari nilai yang dihasilkan dan menyimpan file acara untuk menyelidiki mereka di TensorBoard. Jika Anda menjalankan ini, Anda akan mendapatkan yang berikut:

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 

Anda melihat pola yang sama jika Anda membuka TensorBoard (seperti yang Anda lihat di bluar scope_namepersegi panjang):


Ini memberi Anda jawabannya :

Sekarang Anda melihat bahwa tf.variable_scope()menambahkan awalan ke nama-nama semua variabel (tidak peduli bagaimana Anda membuatnya), ops, konstanta. Di sisi lain tf.name_scope()mengabaikan variabel yang dibuat dengantf.get_variable() karena mengasumsikan bahwa Anda tahu variabel mana dan dalam lingkup mana Anda ingin menggunakan.

Dokumentasi yang baik tentang variabel Berbagi memberi tahu Anda hal itu

tf.variable_scope(): Mengelola ruang nama untuk nama yang diteruskan ke tf.get_variable().

Dokumentasi yang sama memberikan perincian lebih lanjut bagaimana cara kerja Variable Scope dan kapan itu berguna.

Salvador Dali
sumber
2
Jawaban yang luar biasa dengan contoh dan visualnya, mari kita jawab orang-orang ini dengan baik!
David Parks
43

Ruang nama adalah cara untuk mengatur nama untuk variabel dan operator secara hierarkis (mis. "ScopeA / scopeB / scopeC / op1")

  • tf.name_scope menciptakan namespace untuk operator dalam grafik default.
  • tf.variable_scope menciptakan namespace untuk variabel dan operator dalam grafik default.

  • tf.op_scopesama dengan tf.name_scope, tetapi untuk grafik di mana variabel tertentu dibuat.

  • tf.variable_op_scopesama dengan tf.variable_scope, tetapi untuk grafik di mana variabel tertentu dibuat.

Tautan ke sumber-sumber di atas membantu menyamarkan masalah dokumentasi ini.

Contoh ini menunjukkan bahwa semua jenis cakupan menentukan ruang nama untuk variabel dan operator dengan perbedaan berikut:

  1. lingkup yang ditentukan oleh tf.variable_op_scopeatau tf.variable_scopekompatibel dengantf.get_variable (mengabaikan dua cakupan lainnya)
  2. tf.op_scopedan tf.variable_op_scopecukup pilih grafik dari daftar variabel tertentu untuk membuat ruang lingkup. Selain daripada perilaku mereka sama tf.name_scopedan tf.variable_scopesesuai
  3. tf.variable_scopedan variable_op_scopetambahkan initializer yang ditentukan atau standar.
Alexander Gorban
sumber
Untuk grafik di mana variabel tertentu dibuat? Apakah ini berarti seperti contoh di atas oleh fabrizioM, dengan tf.variable_op_scope ([a, b], nama, "mysum2") sebagai ruang lingkup, di sini parameter a dan b tidak terpengaruh oleh fungsi ini dan variabel yang ditentukan dalam lingkup ini terpengaruh?
Xiuyi Yang
Jawaban untuk kedua pertanyaan adalah ya: grafik di mana variabel yang ditentukan dibuat dan mereka tidak dimodifikasi.
Alexander Gorban
Apakah ini berarti bahwa tf.name_scope dan tf.variable_scope hanya digunakan dalam grafik default, tetapi ketika Anda jelas mendefinisikan dan menyusun grafik menggunakan tf.Graph (), dua fungsi lainnya tf.op_scope dan tf.variable_op_scope tidak dapat digunakan dalam grafik ini!
Xiuyi Yang
12

Mari kita membuatnya sederhana: gunakan saja tf.variable_scope. Mengutip pengembang TF, :

Saat ini, kami menyarankan semua orang untuk menggunakan variable_scopedan tidak menggunakan name_scopekecuali untuk kode internal dan perpustakaan.

Selain fakta bahwa variable_scopefungsionalitas pada dasarnya memperluas fungsi mereka name_scope, pertimbangkan bagaimana mereka tidak bermain begitu baik bersama:

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

Dengan berpegang teguh pada variable_scopehanya Anda menghindari beberapa sakit kepala karena ketidakcocokan semacam ini.

P-Gn
sumber
9

Adapun API r0.11, op_scopedan variable_op_scopekeduanya sudah usang . name_scopedan variable_scopedapat disarangkan:

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'
sgu
sumber
8

Anda dapat menganggap mereka sebagai dua kelompok: variable_op_scopedan op_scopemengambil satu set variabel sebagai input dan dirancang untuk membuat operasi. Perbedaannya terletak pada bagaimana mereka memengaruhi pembuatan variabel dengan 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

perhatikan nama variabel vdalam dua contoh.

sama untuk tf.name_scopedan 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

Anda dapat membaca lebih lanjut tentang ruang lingkup variabel dalam tutorial . Pertanyaan serupa diajukan sebelumnya di Stack Overflow.

fabrizioM
sumber
2

Dari bagian terakhir halaman ini dari dokumentasi tensorflow: Nama ops intf.variable_scope()

[...] ketika kita melakukannya with tf.variable_scope("name"), ini secara implisit membuka a tf.name_scope("name"). Sebagai contoh:

with tf.variable_scope("foo"):
  x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"

Lingkup nama dapat dibuka di samping ruang lingkup variabel, dan kemudian mereka hanya akan mempengaruhi nama-nama ops, tetapi tidak pada variabel.

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"

Saat membuka lingkup variabel menggunakan objek yang diambil alih-alih string, kami tidak mengubah lingkup nama saat ini untuk ops.

Guillermo González de Garibay
sumber
2

Tensorflow 2.0 Kompatibel Jawaban : Penjelasan Andrzej Pronobisdan Salvador Dalisangat rinci tentang Fungsi yang berkaitan dengan Scope.

Dari Fungsi Lingkup yang dibahas di atas, yang aktif seperti yang sekarang (17 Februari 2020) adalah variable_scopedanname_scope .

Menentukan 2.0 Panggilan Kompatibel untuk fungsi-fungsi itu, kami bahas di atas, untuk kepentingan komunitas.

Fungsi dalam 1.x :

tf.variable_scope

tf.name_scope

Fungsi Masing-masing dalam 2.x :

tf.compat.v1.variable_scope

tf.name_scope( tf.compat.v2.name_scopejika bermigrasi dari 1.x to 2.x)

Untuk informasi lebih lanjut tentang migrasi dari 1.x ke 2.x, silakan merujuk Panduan Migrasi ini .

Dukungan Tensorflow
sumber