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

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 op che crea variabili. Questo gestore di contesto convalida che i valori dati provengono dallo stesso grafico, assicura che tale grafico sia il grafico predefinito e inserisce un ambito del nome e un ambito variabile.


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

Restituisce un gestore di contesto da utilizzare quando si definisce un op di Python. Questo gestore di contesto convalida che i valori dati provengono dallo stesso grafico, assicura che tale grafico sia il grafico predefinito e spinga un ambito del nome.


tf.name_scope(name)

Wrapper per Graph.name_scope() utilizzando il 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. Lo scope variabile permette di creare nuove variabili e di condividere quelle già create fornendo allo stesso tempo controlli per non creare o condividere per caso. Per i dettagli, vedere l’ambito delle variabili come, qui vi presentiamo solo alcuni esempi di base.

Iniziamo con una breve introduzione alla condivisione variabile. È un meccanismo in TensorFlow che consente di condividere le variabili accessibili in diverse parti del codice senza passare i riferimenti alla variabile circostante.

Il metodo tf.get_variable può essere utilizzato con il nome della variabile come argomento per creare una nuova variabile con tale nome o recuperare quello che è stato creato in precedenza. Questo è diverso tf.Variable costruttore tf.Variable che creerà una nuova variabile ogni volta che viene chiamato (e potenzialmente aggiungere un suffisso al nome della variabile se esiste già una variabile con tale nome).

Ai fini del meccanismo di condivisione delle variabili è stato introdotto un tipo distinto di ambito (ambito variabile).

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

  • nome scope , creato usando tf.name_scope
  • scope variabile , creato usando tf.variable_scope

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

Tuttavia, l’ambito del nome 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 mediante tf.get_variable in 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 le variabili tra diverse parti del programma, anche all’interno di ambiti di nome 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_scope e variable_op_scope sono entrambi deprecati e sostituiti da name_scope e variable_scope .

Namespace è un modo per organizzare nomi per variabili e operatori in modo gerarchico (ad esempio “scopeA / scopeB / scopeC / op1”)

  • tf.name_scope crea uno spazio dei nomi per gli operatori nel grafico predefinito.
  • tf.variable_scope crea uno spazio dei nomi per variabili e operatori nel grafico predefinito.

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

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

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

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

  1. gli ambiti definiti da tf.variable_op_scope o tf.variable_scope sono compatibili con tf.get_variable (ignora altri due ambiti)
  2. tf.op_scope e tf.variable_op_scope basta selezionare un grafico da un elenco di variabili specificate per creare un ambito. A parte il loro comportamento uguale a tf.name_scope e tf.variable_scope conseguenza
  3. tf.variable_scope e variable_op_scope aggiungono l’inizializzatore specificato o predefinito.

Sia variable_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 capire la differenza tra variable_scope e name_scope (sembravano quasi gli stessi) 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. Dopodiché, eseguo il grafico per ottenere i valori dei valori risultanti e salva i file degli eventi per esaminarli in TensorBoard. Se lo esegui, 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 

Si vede il modello simile se si apre TensorBoard (come si vede b è al di fuori di scope_name rettangular): inserisci la descrizione dell'immagine qui


Questo ti dà la risposta :

Ora vedi che tf.variable_scope() aggiunge un prefisso ai nomi di tutte le variabili (non importa come li 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 vuoi usare.

Una buona documentazione sulla condivisione delle variabili ti dice che

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

La stessa documentazione fornisce maggiori dettagli su come funziona Variable Scope e quando è utile.

Per quanto riguarda l’API r0.11, op_scope e variable_op_scope sono entrambi deprecati . name_scope e variable_scope possono essere nidificati:

 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' 

Puoi considerarli come due gruppi: variable_op_scope e op_scope prendono un insieme di variabili come input e sono progettate per creare operazioni. La differenza sta nel modo in cui influiscono sulla 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 

si noti il ​​nome della variabile v nei due esempi.

lo stesso per tf.name_scope e 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 della variabile nel tutorial . Una domanda simile è stata posta prima su Stack Overflow.

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

Attualmente, raccomandiamo a tutti di usare variable_scope e non usare name_scope tranne per il codice interno e le librerie.

Oltre al fatto che la funzionalità di name_scope estende sostanzialmente quelle 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 

Attaccando a variable_scope eviti solo alcuni mal di testa a causa di questo tipo di incompatibilità.

Dall’ultima sezione di questa pagina della documentazione di tensorflow: Nomi delle operazioni in tf.variable_scope()

[…] quando facciamo with tf.variable_scope("name") , questo apre implicitamente un 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 degli operatori, 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 usando un object catturato invece di una stringa, non modifichiamo lo scope del nome corrente per gli ops.