This question already has answers here:
What's the difference of name scope and a variable scope in tensorflow?
(8 answers)
Closed 3 years ago.
What is the difference between variable_scope and name_scope? The variable scope tutorial talks about variable_scope implicitly opening name_scope. I also noticed that creating a variable in a name_scope automatically expands its name with the scope name as well. So, what is the difference?
I had problems understanding the difference between variable_scope and name_scope (they looked almost the same) before I tried to visualize everything by creating a simple example:
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()
Here I create a function that creates some variables and constants and groups them in scopes (depending by the type I provided). In this function I also print the names of all the variables. After that I executes the graph to get values of the resulting values and save event-files to investigate them in tensorboard. If you run this, you will get the following:
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
You see the similar pattern if you open TB (as you see b is outside of scope_name rectangular):
This gives you the answer:
Now you see that tf.variable_scope() adds a prefix to the names of all variables (no matter how you create them), ops, constants. On the other hand tf.name_scope() ignores variables created with tf.get_variable() because it assumes that you know which variable and in which scope you wanted to use.
A good documentation on Sharing variables tells you that
tf.variable_scope(): Manages namespaces for names passed to tf.get_variable().
The same documentation provides a more details how does Variable Scope work and when it is useful.
When you create a variable with tf.get_variable instead of tf.Variable, Tensorflow will start checking the names of the vars created with the same method to see if they collide. If they do, an exception will be raised. If you created a var with tf.get_variable and you try to change the prefix of your variable names by using the tf.name_scope context manager, this won't prevent the Tensorflow of raising an exception. Only tf.variable_scope context manager will effectively change the name of your var in this case. Or if you want to reuse the variable you should call scope.reuse_variables() before creating the var the second time.
In summary, tf.name_scope just add a prefix to all tensor created in that scope (except the vars created with tf.get_variable), and tf.variable_scope add a prefix to the variables created with tf.get_variable.
tf.variable_scope is an evolution of tf.name_scope to handle Variable reuse. As you noticed, it does more than tf.name_scope, so there is no real reason to use tf.name_scope: not surprisingly, a TF developper advises to just use tf.variable_scope.
My understanding for having tf.name_scope still lying around is that there are subtle incompatibilities in the behavior of those two, which invalidates tf.variable_scope as a drop-in replacement for tf.name_scope.
Related
I have three networks, call them V, V_target, and Actor, and I'm trying to achieve the following setup:
V and Actor share certain layers.
V_target is an exact duplicate of V.
For those familiar with deep RL, I'm using this within an actor-critic algorithm with shared layers between the value and policy networks, plus a target network V_target. I tried the following:
def shared(...):
# define some variables, e.g.
W = get_variable('W', ...)
def Actor(...):
with tf.variable_scope("shared"):
shared_out = shared(...)
... actor-specific layers ...
def V(...):
with tf.variable_scope("shared", reuse=True):
shared_out = shared(...)
... V-specific layers...
with tf.variable_scope("Policy"):
actor_out = Actor(...)
with tf.variable_scope("V_main"):
V_out = V(...)
with tf.variable_scope("V_target"):
V_target = V(...)
As expected, this doesn't work because the use of the outermost variable_scope prevents sharing between Policy and V_main: the Variable W has name Policy/shared/W in one scope but has name V_main/shared/W under the second scope.
Why not use tf.name_scope("Policy") and tf.name_scope("V_main")? If I do that, the shared variables can be defined, but then I don't have a good way to get the variables under V_main and V_target. Specifically, because tf.name_scope does not append anything to names created by tf.get_variable, I cannot use tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES ,'V_main') and tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES ,'V_target') to get both sets of objects for the so-called "target updates".
Is there any clever way around this?
I suggest you do the trick described in this question: How to create variable outside of current scope in Tensorflow?
You can clear the current variable scope by providing an instance of an existing scope.
So you simply need to define tf.variable_scope("shared") once, remember the reference to this instance and use it inside all other variable scopes (with reuse=True). W variable will be created in shared scope, no matter what the outer scope is.
I would like to use a function's parameter to create dynamic names of dataframes and/or objects in Python. I have about 40 different names so it would be really elegant to do this in a function. Is there a way to do this or do I need to do this via 'dict'? I read that 'exec' is dangerous (not that I could get this to work). SAS has this feature for their macros which is where I am coming from. Here is an example of what I am trying to do (using '#' for illustrative purposes):
def TrainModels (mtype):
model_#mtype = ExtraTreesClassifier()
model_#mtype.fit(X_#mtype, Y_#mtype)
TrainModels ('FirstModel')
TrainModels ('SecondModel')
You could use a dictionary for this:
models = {}
def TrainModels (mtype):
models[mtype] = ExtraTreesClassifier()
models[mtype].fit()
First of all, any name you define within your TrainModels function will be local to that function, so won't be accessible in the rest of your program. So you have to define a global name.
Everything in Python is a dictionary, including the global namespace. You can define a new global name dynamically as follows:
my_name = 'foo'
globals()[my_name] = 'bar'
This is terrible and you should never do it. It adds too much indirection to your code. When someone else (or yourself in 3 months when the code is no longer fresh in your mind) reads the code and see 'foo' used elsewhere, they'll have a hard time figuring out where it came from. Code analysis tools will not be able to help you.
I would use a dict as Milkboat suggested.
I am beginning to use TensorFlow for some simple Q-learning, but have run into trouble when trying to use variable scopes with layers constructed using tf.layers and tf.contrib.layers. In a nutshell, I want to apply the same layers to different input tensors (for example, to hold the current and next Q values). Here is a minimal example using tf.layers:
import tensorflow as tf
inp1 = tf.placeholder(tf.float64, (4,1))
inp2 = tf.placeholder(tf.float64, (4,1))
def process(inp):
with tf.variable_scope("foo", reuse=True):
return tf.layers.dense(inp, 12, name="bar", reuse=True)
process(inp1)
process(inp2)
Trying to execute this code gives the following exception:
ValueError: Variable foo/bar/kernel does not exist, or was not created with
tf.get_variable(). Did you mean to set reuse=None in VarScope?
I understand that setting reuse=True in tf.layers.dense() makes it try to find an already defined layer, which it may fail to do. But if I change the call into tf.layers.dense(inp, 12, name="bar"), then it fails with the same exception.
If I set reuse=None in tf.variable_scope(), then the latter version fails during the call of process(inp2) with the exception:
ValueError: Variable foo/bar/kernel already exists, disallowed.
Did you mean to set reuse=True in VarScope?
Unfortunately, similar errors occur when using tf.contrib.layers.
My question is: Is there a way to make tf.layers work with variable scopes? I know that I could define the weights and biases separately, but it would be nice to retain the abstraction given by tf.layers. Thanks a lot!
My setup is TensorFlow 1.3.0 (CPU) running with Python 3.6.1 on Windows 10 (installed through pip on 64-bit Anaconda 4.4.0).
P.S. I found the use of variable scopes for layers on page 17 of this presentation.
Two errors are different: the first one happened in process(inp1), where it tries to find the existed variables but there is not; the second happened in process(inp2), where the variable with same name existed but it tries to create a new variable with the same name, disallowed.
I guess that you want to reuse those variables for Q-learning. So the solution is quite simple: the first time you define those variables, don't use reuse, then you can set reuse=True.
In the presentation you gave, I guess they have already defined variables before.
This guide will help you under more.
I have a setup where I need to initialize an LSTM after the main initialization which uses tf.initialize_all_variables(). I.e. I want to call tf.initialize_variables([var_list])
Is there way to collect all the internal trainable variables for both:
rnn_cell.BasicLSTM
rnn_cell.MultiRNNCell
so that I can initialize JUST these parameters?
The main reason I want this is because I do not want to re-initialize some trained values from earlier.
The easiest way to solve your problem is to use variable scope. The names of the variables within a scope will be prefixed with its name. Here is a short snippet:
cell = rnn_cell.BasicLSTMCell(num_nodes)
with tf.variable_scope("LSTM") as vs:
# Execute the LSTM cell here in any way, for example:
for i in range(num_steps):
output[i], state = cell(input_data[i], state)
# Retrieve just the LSTM variables.
lstm_variables = [v for v in tf.all_variables()
if v.name.startswith(vs.name)]
# [..]
# Initialize the LSTM variables.
tf.initialize_variables(lstm_variables)
It would work the same way with MultiRNNCell.
EDIT: changed tf.trainable_variables to tf.all_variables()
You can also use tf.get_collection():
cell = rnn_cell.BasicLSTMCell(num_nodes)
with tf.variable_scope("LSTM") as vs:
# Execute the LSTM cell here in any way, for example:
for i in range(num_steps):
output[i], state = cell(input_data[i], state)
lstm_variables = tf.get_collection(tf.GraphKeys.VARIABLES, scope=vs.name)
(partly copied from Rafal's answer)
Note that the last line is equivalent to the list comprehension in Rafal's code.
Basically, tensorflow stores a global collection of variables, which can be fetched by either tf.all_variables() or tf.get_collection(tf.GraphKeys.VARIABLES). If you specify scope (scope name) in the tf.get_collection() function, then you only fetch tensors (variables in this case) in the collection whose scopes are under the specified scope.
EDIT:
You can also use tf.GraphKeys.TRAINABLE_VARIABLES to get trainable variables only. But since vanilla BasicLSTMCell does not initialize any non-trainable variable, both will be functionally equivalent. For a complete list of default graph collections, check this out.
I am writing some program using python and the z3py module.
What I am trying to do is the following: I extract a constraint of an if or a while statement from a function which is located in some other file. Additionally I extract the used variables in the statement as well as their types.
As I do not want to parse the constraint by hand into a z3py friendly form, I tried to use evaluate to do this for me. Therefore I used the tip of the following page: Z3 with string expressions
Now the problem is: I do not know how the variables in the constraint are called. But it seems as I have to name the handle of each variable like the actual variable. Otherwise evaluate won't find it. My code looks like this:
solver = Solver()
# Look up the constraint:
branch = bd.getBranchNum(0)
constr = branch.code
# Create handle for each variable, depending on its type:
for k in mapper.getVariables():
var = mapper.getVariables()[k]
if k in constr:
if var.type == "intNum":
Int(k)
else:
Real(k)
# Evaluate constraint, insert the result and solve it:
f = eval(constr)
solver.insert(f)
solve(f)
As you can see I saved the variables and constraints in classes. When executing this code I get the following error:
NameError: name 'real_x' is not defined
If I do not use the looping over the variables, but instead the following code, everything works fine:
solver = Solver()
branch = bd.getBranchNum(0)
constr = branch.code
print(constr)
real_x = Real('real_x')
int_y = Int('int_y')
f = eval(constr)
print(f)
solver.insert(f)
solve(f)
The problem is: I do not know, that the variables are called "real_x" or "int_y". Furthermore I do not know how many variables there are used, which means I have to use some dynamic thing like a loop.
Now my question is: Is there a way around this? What can I do to tell python that the handles already exist, but have a different name? Or is my approach completely wrong and I have to do something totally different?
This kind of thing is almost always a bad idea (see Why eval/exec is bad for more details), but "almost always" isn't "always", and it looks like you're using a library that was specifically designed to be used this way, in which case you've found one of the exceptions.
And at first glance, it seems like you've also hit one of the rare exceptions to the Keep data out of your variable names guideline (also see Why you don't want to dynamically create variables). But you haven't.
The only reason you need these variables like real_x to exist is so that eval can see them, right? But the eval function already knows how to look for variables in a dictionary instead of in your global namespace. And it looks like what you're getting back from mapper.getVariables() is a dictionary.
So, skip that whole messy loop, and just do this:
variables = mapper.getVariables()
f = eval(constr, globals=variables)
(In earlier versions of Python, globals is a positional-only argument, so just drop the globals= if you get an error about that.)
As the documentation explains, this gives the eval function access to your actual variables, plus the ones the mapper wants to generate, and it can do all kinds of unsafe things. If you want to prevent unsafe things, do this:
variables = dict(mapper.getVariables())
variables['__builtins__'] = {}
f = eval(constr, globals=variables)