¿Cuál es la diferencia entre el alcance del nombre y el alcance variable en tensorflow?
¿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 provienen del mismo gráfico, garantiza que ese gráfico sea el predeterminado y envía un alcance de nombre y un alcance de 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, garantiza que ese gráfico sea el predeterminado y envía un alcance de nombre.
tf.name_scope(name)
Envoltorio para
Graph.name_scope()
usar 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 de la variable. El alcance de la variable permite crear nuevas variables y compartir las ya creadas, al tiempo que proporciona controles para no crear ni compartir por accidente. Para obtener más información, consulte el artículo sobre alcance variable. Aquí presentamos solo algunos ejemplos básicos.
Comencemos con una breve introducción al uso compartido de variables. Es un mecanismo 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 utilizar con el nombre de la variable como argumento para crear una nueva variable con dicho nombre o recuperar la que se creó antes. Esto es diferente de usar el tf.Variable
constructor 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 ese nombre).
Es a efectos del mecanismo de intercambio de variables que se introdujo un tipo separado de alcance (alcance variable).
Como resultado, terminamos teniendo dos tipos diferentes de ámbitos:
- alcance del nombre , creado usando
tf.name_scope
- alcance variable , creado usando
tf.variable_scope
Ambos alcances tienen el mismo efecto en todas las operaciones, así como en las variables creadas con tf.Variable
, es decir, el alcance se agregará como prefijo a la operación o al nombre de la variable.
Sin embargo tf.get_variable
, . 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 usando tf.get_variable
en un alcance es usar un alcance de 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 entre diferentes partes del programa, incluso dentro de diferentes ámbitos de nombres:
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, están obsoletosop_scope
y variable_op_scope
reemplazados por y .name_scope
variable_scope
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 entender la diferencia entre variable_scope y 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 los valores de los valores resultantes y guardo los 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ás un patrón similar si abres TensorBoard (como ves, b
está fuera del scope_name
rectángulo):
Esto te da la respuesta :
Ahora ves que tf.variable_scope()
agrega un prefijo a los nombres de todas las variables (sin importar cómo las crees), operaciones, constantes. Por otro lado, tf.name_scope()
ignora las variables creadas tf.get_variable()
porque supone que sabes qué variable y en qué ámbito deseas usar.
Una buena documentación sobre Compartir variables te dice que
tf.variable_scope()
: Administra espacios de nombres para los nombres pasados atf.get_variable()
.
La misma documentación proporciona más detalles sobre cómo funciona el alcance variable y cuándo es útil.