Qual è la differenza tra scope nome e scope variabile in tensorflow?


276

Quali sono le differenze tra queste funzioni?

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

Restituisce un gestore di contesto per la definizione di un'operazione che crea variabili. Questo gestore di contesto convalida che i valori indicati provengano dallo stesso grafico, garantisce che quel grafico sia il grafico predefinito e invia un ambito nome e un ambito variabile.


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

Restituisce un gestore di contesto da utilizzare durante la definizione di un'operazione Python. Questo gestore di contesto convalida che i valori indicati provengano dallo stesso grafico, garantisce che quel grafico sia il grafico predefinito e invia un ambito di nomi.


tf.name_scope(name)

Wrapper per l' Graph.name_scope()utilizzo del grafico predefinito. Vedi Graph.name_scope()per maggiori dettagli.


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

Restituisce un contesto per ambito variabile. L'ambito delle variabili consente di creare nuove variabili e condividere quelle già create fornendo al contempo controlli per non creare o condividere per caso. Per i dettagli, vedere la sezione Ambito di applicazione delle variabili, qui presentiamo solo alcuni esempi di base.


Risposte:


377

Cominciamo con una breve introduzione alla condivisione variabile. È un meccanismo TensorFlowche consente di condividere le variabili a cui si accede in diverse parti del codice senza passare riferimenti alla variabile in giro.

Il metodo tf.get_variablepuò essere utilizzato con il nome della variabile come argomento per creare una nuova variabile con tale nome o recuperare quella creata in precedenza. Ciò è diverso dall'uso del tf.Variablecostruttore che creerà una nuova variabile ogni volta che viene chiamato (e potenzialmente aggiunge un suffisso al nome della variabile se esiste già una variabile con tale nome).

È ai fini del meccanismo di condivisione variabile che è stato introdotto un tipo di ambito separato (ambito variabile).

Di conseguenza, finiamo per avere due diversi tipi di ambiti:

Entrambi gli ambiti hanno lo stesso effetto su tutte le operazioni e sulle variabili create utilizzando tf.Variable, ovvero l'ambito verrà aggiunto come prefisso all'operazione o al nome della variabile.

Tuttavia, l'ambito dei nomi viene ignorato da tf.get_variable. Possiamo vederlo nel seguente esempio:

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

L'unico modo per posizionare una variabile a cui si accede utilizzando tf.get_variablein un ambito è utilizzare un ambito variabile, come nell'esempio seguente:

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

Questo ci consente di condividere facilmente variabili tra diverse parti del programma, anche all'interno di ambiti di nomi diversi:

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

AGGIORNARE

A partire dalla versione r0.11, op_scopee variable_op_scopesono entrambi deprecato e sostituito da name_scopee variable_scope.


41
Grazie per la chiara spiegazione. Naturalmente, una domanda di follow-up sarebbe " Perché Tensorflow ha entrambi questi meccanismi confusivamente simili? Perché non sostituirli con un solo scopemetodo che effettivamente fa un variable_scope?"
Giovanni,

8
Io non credo di capire concettualmente il motivo per cui la distinzione tra variable_scopevs name_scopeè nemmeno necessario. Se si crea una variabile (in qualche modo con tf.Variableo tf.get_variable), mi sembra più naturale che dovremmo sempre essere in grado di ottenerla se specifichiamo l'ambito o il suo nome completo. Non capisco perché uno ignori la cosa del nome dell'ambito mentre l'altro no. Capisci il razionale per questo strano comportamento?
Charlie Parker,

23
Il motivo è che con l'ambito variabile, è possibile definire ambiti separati per le variabili riutilizzabili che non sono interessate dall'ambito del nome corrente utilizzato per definire le operazioni.
Andrzej Pronobis,

6
Ciao , puoi spiegare perché il nome della variabile in una variabile_scope termina sempre con un: 0? Questo significa che potrebbero esserci nomi di variabili che terminano con: 1,: 2, ecc. Quindi, come può accadere?
James Fan,

2
@JamesFan Ogni "dichiarazione" è un'operazione, quindi quando dici a = tf.Variable (.. name) ottieni un tensore, ma in realtà crea anche un'operazione. se si stampa a, si otterrà il tensore con a: 0. Se si stampa a.op si ottiene l'operazione che calcolerà quel valore tensore.
Robert Lugg,

84

Sia variabile_op_scope che op_scope sono ora deprecati e non dovrebbero essere usati affatto.

Per quanto riguarda gli altri due, ho anche avuto problemi a comprendere la differenza tra variabile_scope e name_scope (sembravano quasi uguali) prima di provare a visualizzare tutto creando un semplice esempio:

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

Qui creo una funzione che crea alcune variabili e costanti e le raggruppa in ambiti (a seconda del tipo che ho fornito). In questa funzione, stampo anche i nomi di tutte le variabili. Successivamente, eseguo il grafico per ottenere i valori risultanti e salvare i file di eventi per esaminarli in TensorBoard. Se esegui questo, otterrai quanto segue:

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 

Vedi lo schema simile se apri TensorBoard (come vedi bè al di fuori di scope_namerettangolare):


Questo ti dà la risposta :

Ora vedi che tf.variable_scope()aggiunge un prefisso ai nomi di tutte le variabili (non importa come le crei), ops, costanti. D'altra parte tf.name_scope()ignora le variabili create con tf.get_variable()perché presuppone che tu sappia quale variabile e in quale ambito desideri utilizzare.

Una buona documentazione sulle variabili di condivisione lo dice

tf.variable_scope(): Gestisce gli spazi dei nomi per i nomi passati a tf.get_variable().

La stessa documentazione fornisce ulteriori dettagli su come funziona Scope variabile e quando è utile.


2
Risposta favolosa con l'esempio e la grafica, otteniamo questa risposta gente votata!
David Parks

43

Namespace è un modo per organizzare i nomi per variabili e operatori in modo gerarchico (es. "ScopeA / scopeB / scopeC / op1")

  • tf.name_scope crea lo spazio dei nomi per gli operatori nel grafico predefinito.
  • tf.variable_scope crea lo spazio dei nomi sia per le variabili che per gli operatori nel grafico predefinito.

  • tf.op_scopeuguale a tf.name_scope, ma per il grafico in cui sono state create le variabili specificate.

  • tf.variable_op_scopeuguale a tf.variable_scope, ma per il grafico in cui sono state create le variabili specificate.

I collegamenti alle fonti di cui sopra aiutano a chiarire questo problema di documentazione.

Questo esempio mostra che tutti i tipi di ambiti definiscono spazi dei nomi sia per variabili che per operatori con le seguenti differenze:

  1. ambiti definiti da tf.variable_op_scopeo tf.variable_scopecompatibili con tf.get_variable(ignora altri due ambiti)
  2. tf.op_scopee tf.variable_op_scopebasta selezionare un grafico da un elenco di variabili specificate per creare un ambito per. A parte il loro comportamento uguale tf.name_scopee di tf.variable_scopeconseguenza
  3. tf.variable_scopee variable_op_scopeaggiungi l'inizializzatore specificato o predefinito.

Per il grafico in cui sono state create le variabili specificate? Questo significa come nell'esempio sopra di fabrizioM, con tf.variable_op_scope ([a, b], name, "mysum2") come ambito, qui i parametri aeb non sono interessati da questa funzione e le variabili definite in questo ambito sono interessate?
Xiuyi Yang

La risposta per entrambe le domande è sì: il grafico in cui sono state create le variabili specificate e non sono state modificate.
Alexander Gorban,

Questo significa che tf.name_scope e tf.variable_scope possono essere usati solo nel grafico predefinito, ma quando ovviamente definisci e costruisci un grafico usando tf.Graph (), le altre due funzioni tf.op_scope e tf.variable_op_scope non possono essere utilizzate in questo grafico!
Xiuyi Yang,

12

Rendiamolo semplice: basta usare tf.variable_scope. Citando uno sviluppatore TF, :

Al momento, raccomandiamo a tutti di usare variable_scopee non usare ad name_scopeeccezione del codice interno e delle librerie.

Oltre al fatto che variable_scopela funzionalità sostanzialmente estende quelli di name_scope, considera come non giocano così bene insieme:

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

Attenendoti a variable_scopesolo eviti alcuni mal di testa a causa di questo tipo di incompatibilità.


9

Come per API r0.11, op_scopee variable_op_scopesono entrambi deprecati . name_scopee variable_scopepuò essere nidificato:

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

Puoi pensarli come due gruppi: variable_op_scopee op_scopeprendere un set di variabili come input e sono progettati per creare operazioni. La differenza sta nel modo in cui influenzano la creazione di variabili con 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

notare il nome della variabile v nei due esempi.

lo stesso per tf.name_scopee 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

Puoi leggere ulteriori informazioni sull'ambito variabile nel tutorial . Una domanda simile è stata posta in precedenza su StackTranslate.it.


2

Dall'ultima sezione di questa pagina della documentazione di tensorflow: Nomi di operazioni intf.variable_scope()

[...] quando lo facciamo with tf.variable_scope("name"), questo implica implicitamente a tf.name_scope("name"). Per esempio:

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

Gli ambiti dei nomi possono essere aperti in aggiunta a un ambito variabile e quindi influenzeranno solo i nomi delle operazioni, ma non delle variabili.

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"

Quando si apre un ambito variabile utilizzando un oggetto acquisito anziché una stringa, non si modifica l'ambito del nome corrente per ops.


2

Risposta compatibile Tensorflow 2.0 : le spiegazioni Andrzej Pronobise Salvador Dalisono molto dettagliate sulle funzioni correlate Scope.

Delle funzioni Scope discusse sopra, che sono attive sin da ora (17 febbraio 2020) sono variable_scopee name_scope.

Specificando le chiamate compatibili 2.0 per quelle funzioni, abbiamo discusso in precedenza, a beneficio della comunità.

Funzione in 1.x :

tf.variable_scope

tf.name_scope

Funzione rispettiva in 2.x :

tf.compat.v1.variable_scope

tf.name_scope( tf.compat.v2.name_scopese migrato da 1.x to 2.x)

Per ulteriori informazioni sulla migrazione da 1.xa 2.x, consultare questa Guida alla migrazione .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.