Why Assignment Operation cannot be added as a parameter to the control depedency in tensorflow? - tensorflow

I have a simple model. But I need to modify a variable before performing an update. Hence, I have the following:
l = tf.Variable(tf.constant(0.01), trainable=False, name="l")
baseline = tf.Variable(tf.constant(0.0), dtype=tf.float32, name="baseline")
# Actor optimizer
# Note that our target is: e^{-L} where L is the loss on the validation dataset.
# So we pass to the target mae_loss in the code below
def optimize_actor(scores_a, scores_v, target):
with tf.name_scope('Actor_Optimizer'):
update_moving_loss = tf.assign(baseline, l * baseline + (1 - l) * target, name="update_baseline")
dec_l = l.assign_add(0.001)
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies([update_ops, update_moving_loss, dec_l]):
loss_a = scores_a * tf.exp(target - baseline)
loss_v = scores_v * tf.exp(target - baseline)
actor_a_optimizer = tf.train.AdamOptimizer(0.0001).minimize(loss_a)
actor_v_optimizer = tf.train.AdamOptimizer(0.0001).minimize(loss_v)
return actor_a_optimizer, actor_v_optimizer
Therefore, when running the above script, I got the following error:
Can not convert a list into a Tensor or Operation.
What is causing this problem is update_moving_loss and dec_l. When I remove them, the code runs fine.
Please note that I am using tensorflow 1.7
Any help is much appreciated!!!

I cannot reproduce your problem, but my guess is the problem lies with using tf.get_collection. As specified in the documentation, it will return a list of values in the collection. Let's call this list L to make things concise.
You then do something like this:
L = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies([L, tensor1, tensor2]):
...
The argument there is another list, with three elements: your list L from before, and two tensors. This is the problem: the first element is a list, and thus you see
Can not convert a list into a Tensor or Operation.
You can probably resolve the issue by appending to L rather than making another list-with-a-list-inside:
L = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies( L + [tensor1, tensor2]):
...
The + operator adds the new list elements to the original list L.

Related

Dataset/iterator checkpointing

I am trying to checkpoint a dataset/iterator with TF2, following up on my past question [link]. As a simple example, I wanted to see if I can reproduce the behavior of tf.data.Dataset.range whose iterator can be checkpointed so that it continues iteration where it left off.
I wanted to replace this code:
ds = tf.data.Dataset.range(10)
it = iter(ds)
ckpt = tf.train.Checkpoint(iterator=it)
manager = tf.train.CheckpointManager(ckpt, '~/tf-ckpt', max_to_keep=2)
manager.save()
with a custom logic that does the same, so that I can extend it to do something more complex while allowing iteration to automatically continue where it left off:
def count():
i = 0
while i < 10:
yield i
i += 1
ds = tf.data.Dataset.from_generator(
count, output_signature=tf.TensorSpec(shape=(), dtype=np.int32))
ckpt = tf.train.Checkpoint(iterator=it)
manager = tf.train.CheckpointManager(ckpt, '~/tf-ckpt', max_to_keep=2)
manager.save()
Unfortunately, this code gives the following error:
FailedPreconditionError: {{function_node __wrapped__SerializeIterator_device_/job:localhost/replica:0/task:0/device:CPU:0}} PyFunc is stateful. [Op:SerializeIterator]
which is quite confusing since tf.data.Dataset.range should also be stateful.
Is there a way to adapt my example to make it match the behavior of tf.data.Dataset.range?

Why does tensorflow mse() change with each run?

I used the tensorflow tf.keras.metrics.MeanSquaredError() metric to evaluate the mean squared error between two numpy arrays. But each time I call mse() it give a different result.
a = np.random.random(size=(100,2000))
b = np.random.random(size=(100,2000))
for i in range(100):
v = mse(a, b).numpy()
plt.scatter(i,v)
print(v)
where I had previously defined mse = tf.keras.metrics.MeanSquaredError() Here is the Output. Any idea what is going wrong?
np.random.random generates random data every run. So, your code should result in different mse, shouldn't it?
run 1:
[0.87148841 0.50221413 0.49858526 ... 0.22311888 0.71320089 0.36298912]
Run 2:
[0.14941241 0.78560523 0.62436783 ... 0.1865485 0.2730567 0.49300401]

Tensorflow: how to create a local variable?

I'm trying to understand how local and global variables are different in tensorflow and what's the right way to initialize the variables.
According to the doc, tf.local_variables_initializer:
Returns an Op that initializes all local variables.
This is just a shortcut for variables_initializer(local_variables())
So the essential part is tf.local_variables. The doc:
Local variables - per process variables, usually not saved/restored to checkpoint and used for temporary or intermediate values. For example, they can be used as counters for metrics computation or number of epochs this machine has read data.
It sounds logical, however, no matter how I tried, I couldn't make any variable local.
features = 2
hidden = 3
with tf.variable_scope('start'):
x = tf.placeholder(tf.float32, shape=[None, features], name='x')
y = tf.placeholder(tf.float32, shape=[None], name='y')
with tf.variable_scope('linear'):
W = tf.get_variable(name='W', shape=[features, hidden])
b = tf.get_variable(name='b', shape=[hidden], initializer=tf.zeros_initializer)
z = tf.matmul(x, W) + b
with tf.variable_scope('optimizer'):
predict = tf.reduce_sum(z, axis=1)
loss = tf.reduce_mean(tf.square(y - predict))
optimizer = tf.train.AdamOptimizer(0.1).minimize(loss)
print(tf.local_variables())
The output is always an empty list. How and should I create local variables?
A local variable is just a regular variable that's added to a "special" collection.
The collection is tf.GraphKeys.LOCAL_VARIABLES.
You can pick any variable definition and just add the parameter collections=[tf.GraphKeys.LOCAL_VARIABLES] to add the variable to the specified collection list.
Think I found it. The magic addition to make a variable local is collections=[tf.GraphKeys.LOCAL_VARIABLES] in tf.get_variable. So this way W becomes are local variable:
W = tf.get_variable(name='W', shape=[features, hidden], collections=[tf.GraphKeys.LOCAL_VARIABLES])
The documentation mentions one more possibility that also works:
q = tf.contrib.framework.local_variable(0.0, name='q')

How to access unnamed node in CNTK model

Suppose I use the following code to create a model (simplified) but don't name any of the nodes:
num_classes = 10
input_var = cntk.input_variable((12,))
model = Sequential([
Dense(256),
Dense(512),
Dense(num_classes)
])(input_var)
If I wanted to evaluate the intermediate nodes later, how do I access them?
I've used
cntk.logging.get_node_outputs(model)
to inspect the graph and get the following output:
[Output('Block30733_Output_0', [#], [10]),
Output('Block30719_Output_0', [#], [512]),
Output('Block30705_Output_0', [#], [256])]
However, calling model.find_by_name() with those names returns None.
One approach is to do a graph search. You need to find a way to distinguish between the layers you want to evaluate. You can get all the nodes like this.
blocks = C.logging.graph.depth_first_search(
model, (lambda x : type(x) == C.Function and x.is_block) , depth = 0)
For the lambda you can add any condition. To get all the blocks, you can use:
lambda x: True

Accessing learned weights of a DNN in CNTK

How can one access to the learned weights of a DNN saved as following:
lstm_network_output.save(model_path)
The weights/parameters of a network can be accessed by calling ‘lstm_network_output.parameters’ which returns a list of ‘Parameter’ variable objects. The value of a Parameter can be obtained using ‘value’ property of the Parameter object in the form of a numpy array. The value of the Parameter can be updated by ‘.value = ’.
If you used name= properties in creating your model, you can also identify layers by name. For example:
model = Sequential([Embedding(300, name='embed'), Recurrence(LSTM(500)), Dense(10)])
E = model.embed.E # accesses the embedding matrix of the embed layer
To know that the parameter is .E, please consult the docstring of the respective function (e.g. help(Embedding)). (In Dense and Convolution, the parameters would be .W and .b.)
The pattern above is for named layers, which are created using as_block(). You can also name intermediate variables, and access them in the same way. E.g.:
W = Parameter((13,42), init=0, name='W')
x = Input(13)
y = times(x, W, name='times1')
W_recovered = y.times1.W
# e.g. check the shape to see that they are the same
W_recovered.shape # --> (13, 42)
W.shape # --> (13, 42)
Technically, this will search all parameters that feed y. In case of a more complex network, you may end up having multiple parameters of the same name. Then an error will be thrown due to the ambiguity. In that case, you must work the .parameters tuple mentioned in Anna's response.
This python code worked for me to visualize some weights:
import numpy as np
import cntk as C
dnnFile = C.cntk_py.Function.load('Models\ConvNet_MNIST_5.dnn') # load model from MS example
layer8 = dnnFile.parameters()[8].value()
filter_num = 0
sliced = layer8.asarray()[ filter_num ][ 0 ] # shows filter works on input image
print(sliced)