1

I have defined an unsupervised problem in tensorflow, I need to update my B and my tfZ with every iteration, but I don't know how to update my tfZ using the tensorflow session.

tfY = tf.placeholder(shape=(15, 15), dtype=tf.float32)

with tf.variable_scope('test'):
    B = tf.Variable(tf.zeros([]))
    tfZ = tf.convert_to_tensor(Z, dtype=tf.float32)

def loss(tfY):
    r = tf.reduce_sum(tfZ*tfZ, 1)
    r = tf.reshape(r, [-1, 1])
    D = tf.sqrt(r - 2*tf.matmul(tfZ, tf.transpose(tfZ)) + tf.transpose(r) + 1e-9)
    return tf.reduce_sum(tfY*tf.log(tf.sigmoid(D+B))+(1-tfY)*tf.log(1-tf.sigmoid(D+B)))

LOSS = loss(Y)
GRADIENT = tf.gradients(LOSS, [B, tfZ])

sess = tf.Session()
sess.run(tf.global_variables_initializer())

tot_loss = sess.run(LOSS, feed_dict={tfY: Y})

loss_grad = sess.run(GRADIENT, feed_dict={tfY: Y})

learning_rate = 1e-4
for i in range(1000):
    sess.run(B.assign(B - learning_rate * loss_grad[0]))
    print(tfZ)
    sess.run(tfZ.assign(tfZ - learning_rate * loss_grad[1]))

    tot_loss = sess.run(LOSS, feed_dict={tfY: Y})
    if i%10==0:
        print(tot_loss)

This code prints the following:

Tensor("test_18/Const:0", shape=(15, 2), dtype=float32)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-35-74ddafc0bf3a> in <module>()
     25     sess.run(B.assign(B - learning_rate * loss_grad[0]))
     26     print(tfZ)
---> 27     sess.run(tfZ.assign(tfZ - learning_rate * loss_grad[1]))
     28 
     29     tot_loss = sess.run(LOSS, feed_dict={tfY: Y})

AttributeError: 'Tensor' object has no attribute 'assign'

A tensor object correctly has no assign attribute, but I cannot find any other function attached to the object that could do just that. How do I update my tensor correctly?

Maxim
  • 52,561
  • 27
  • 155
  • 209
NicolaiF
  • 1,283
  • 1
  • 20
  • 44

1 Answers1

8

Unlike tf.Variable, tf.Tensor doesn't provide a assign method; if the tensor is mutable, you have to call tf.assign function explicitly:

tf.assign(tfZ, tfZ - learning_rate * loss_grad[1])

Update: not all tensors are mutable, e.g. your tfZ isn't. As of now, mutable tensors are only those that correspond to variables as explained in this answer (at least in tensorflow 1.x, this can be expanded in the future). Ordinary tensors are handles to the result of an op, i.e. they're bound to that operation and it's inputs. To change an immutable tensor value, one has to change the source tensors (placeholders or variables). In your particular case, it'd be easier to make a tfZ a variable as well.

By the way, tf.Variable.assign() is just a wrapper over tf.assign and one has to run the result op in a session to actually perform an assignment.

Note in both cases a new node in the graph is created. If you call it in a loop (like in your snippet), the graph will by inflated by a thousand nodes. Doing so in real production code is a bad practice, because it can easily cause OOM.

Maxim
  • 52,561
  • 27
  • 155
  • 209
  • Thanks for the explanation, running tf.assign(tfZ, tfZ - learning_rate * loss_grad[1]) does still produce the same error message though: "Tensor' object has no attribute 'assign'" – NicolaiF Mar 07 '18 at 10:47
  • @NicolaiF Oops, my bad, I forgot to mention one important point – Maxim Mar 07 '18 at 10:52
  • 1
    @NicolaiF I've updated the answer, sorry for initial confusion – Maxim Mar 07 '18 at 11:02
  • Thank you so much for the great explanation, I changed my code from: tfZ = tf.convert_to_tensor(Z, dtype=tf.float32) to tfZ = tf.Variable(tf.convert_to_tensor(Z, dtype=tf.float32)) so it act as a variable, and now I assign the same way as I do with B. – NicolaiF Mar 07 '18 at 11:08
  • You write what I am doing is bad practise, what is the right way to go about doing this? – NicolaiF Mar 07 '18 at 11:08
  • 1
    A better way would be to create an assign op once (before starting a session) and then call it as many times as needed. This means using `GRADIENT` instead of `loss_grad`. By the way, variables support `assign_sub` method. – Maxim Mar 07 '18 at 11:27