tensorflow - tf get_variable
¿Cuál es la diferencia del alcance del nombre y un alcance variable en el tensorflow? (7)
¿Cuáles son las diferencias entre estas funciones?
tf.variable_op_scope(values, name, default_name, initializer=None)
Devuelve un administrador de contexto para definir una operación que crea variables. Este administrador de contexto valida que los valores dados son del mismo gráfico, asegura que ese gráfico es el gráfico predeterminado y empuja un ámbito de nombre y un ámbito variable.
tf.op_scope(values, name, default_name=None)
Devuelve un administrador de contexto para usar al definir una operación de Python. Este administrador de contexto valida que los valores dados provienen del mismo gráfico, asegura que ese gráfico sea el gráfico predeterminado e inserta un ámbito de nombre.
tf.name_scope(name)
Wrapper para
Graph.name_scope()
usando el gráfico predeterminado. VerGraph.name_scope()
para más detalles.
tf.variable_scope(name_or_scope, reuse=None, initializer=None)
Devuelve un contexto para el alcance variable. El alcance variable permite crear nuevas variables y compartir las ya creadas al tiempo que proporciona comprobaciones para no crear o compartir por accidente. Para obtener más información, consulte el Cómo de alcance variable, aquí solo presentamos algunos ejemplos básicos.
Comencemos con una breve introducción al intercambio de variables.
Es un mecanismo en
TensorFlow
que permite compartir variables a las que se accede en diferentes partes del código sin pasar referencias a la variable.
El método
tf.get_variable
se puede usar con el nombre de la variable como argumento para crear una nueva variable con dicho nombre o recuperar la que se creó anteriormente.
Esto es diferente de usar el constructor
tf.Variable
que creará una nueva variable cada vez que se llame (y potencialmente agregará un sufijo al nombre de la variable si ya existe una variable con dicho nombre).
Es para el propósito del mecanismo de intercambio variable que se introdujo un tipo separado de alcance (alcance variable).
Como resultado, terminamos teniendo dos tipos diferentes de ámbitos:
-
ámbito de nombre
, creado usando
tf.name_scope
-
alcance variable
, creado usando
tf.variable_scope
Ambos ámbitos tienen el mismo efecto en todas las operaciones, así como en las variables creadas con
tf.Variable
.
tf.Variable
, es decir, el ámbito se agregará como un prefijo a la operación o al nombre de la variable.
Sin embargo,
tf.get_variable
ignora el alcance del nombre.
Podemos ver eso en el siguiente ejemplo:
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
La única forma de colocar una variable a la que se accede mediante
tf.get_variable
en un ámbito es utilizar un ámbito variable, como en el siguiente ejemplo:
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
Esto nos permite compartir fácilmente variables en diferentes partes del programa, incluso dentro de diferentes ámbitos de nombre:
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
ACTUALIZAR
A partir de la versión r0.11,
op_scope
y
variable_op_scope
están en
deprecated
y se reemplazan por
name_scope
y
variable_scope
.
Desde la última sección de esta página de la documentación de tensorflow:
Nombres de operaciones en
tf.variable_scope()
[...] cuando lo hacemos
with tf.variable_scope("name")
, esto abre implícitamente untf.name_scope("name")
. Por ejemplo:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
Los ámbitos de nombre se pueden abrir además de un ámbito variable, y luego solo afectarán los nombres de las operaciones, pero no las variables.
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"
Al abrir un ámbito variable utilizando un objeto capturado en lugar de una cadena, no alteramos el ámbito del nombre actual para las operaciones.
En cuanto a la API r0.11,
op_scope
y
variable_op_scope
están en
deprecated
.
name_scope
y
variable_scope
se pueden anidar:
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''
Hagámoslo simple: solo use
tf.variable_scope
.
Citando a un desarrollador de TF
:
Actualmente, recomendamos que todos usen
variable_scope
y no usenname_scope
excepto el código interno y las bibliotecas.
Además del hecho de que la funcionalidad de
variable_scope
básicamente extiende las de
name_scope
, considere cómo no juegan tan bien juntos:
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
Al apegarse a
variable_scope
solo evita algunos dolores de cabeza debido a este tipo de incompatibilidad.
Los espacios de nombres son una forma de organizar nombres para variables y operadores de manera jerárquica (por ejemplo, "scopeA / scopeB / scopeC / op1")
-
tf.name_scope
crea un espacio de nombres para operadores en el gráfico predeterminado. -
tf.variable_scope
crea un espacio de nombres para variables y operadores en el gráfico predeterminado. -
tf.op_scope
igual quetf.name_scope
, pero para el gráfico en el que se crearon las variables especificadas. -
tf.variable_op_scope
igual quetf.variable_scope
, pero para el gráfico en el que se crearon las variables especificadas.
Los enlaces a las fuentes anteriores ayudan a desambiguar este problema de documentación.
Este ejemplo muestra que todos los tipos de ámbitos definen espacios de nombres para variables y operadores con las siguientes diferencias:
-
Los ámbitos definidos por
tf.variable_op_scope
otf.variable_scope
son compatibles contf.get_variable
(ignora otros dos ámbitos) -
tf.op_scope
ytf.variable_op_scope
solo seleccionan un gráfico de una lista de variables especificadas para crear un alcance. Aparte de su comportamiento igual atf.name_scope
ytf.variable_scope
consecuencia -
tf.variable_scope
yvariable_op_scope
agregan inicializador especificado o predeterminado.
Puede pensarlos como dos grupos:
variable_op_scope
y
op_scope
toman un conjunto de variables como entrada y están diseñadas para crear operaciones.
La diferencia está en cómo afectan la creación de variables 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
observe el nombre de la variable
v
en los dos ejemplos.
lo mismo para
tf.name_scope
y
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
Puede leer más sobre el alcance variable en el tutorial . Una pregunta similar se hizo antes en .
Tanto variable_op_scope como op_scope ahora están en desuso y no deberían usarse en absoluto.
Con respecto a los otros dos, también tuve problemas para comprender la diferencia entre tf.variable_scope y tf.name_scope (se veían casi iguales) antes de intentar visualizar todo creando un ejemplo simple:
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()
Aquí creo una función que crea algunas variables y constantes y las agrupa en ámbitos (según el tipo que proporcioné). En esta función, también imprimo los nombres de todas las variables. Después de eso, ejecuto el gráfico para obtener valores de los valores resultantes y guardar archivos de eventos para investigarlos en TensorBoard. Si ejecuta esto, obtendrá lo siguiente:
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
Verá un patrón similar si abre TensorBoard (como ve que
b
está fuera del
scope_name
rectangular):
Esto te da la respuesta :
Ahora ve que
tf.variable_scope()
agrega un prefijo a los nombres de todas las variables (sin importar cómo las cree), operaciones, constantes.
Por otro lado,
tf.name_scope()
ignora las variables creadas con
tf.get_variable()
porque supone que usted sabe qué variable y en qué ámbito desea usar.
Una buena documentación sobre Compartir variables le dice que
tf.variable_scope()
: administra los espacios de nombres para los nombres pasados atf.get_variable()
.
La misma documentación proporciona más detalles sobre cómo funciona Variable Scope y cuándo es útil.