Search code examples
pythontensorflowvariable-assignmenttensorflow-gradient

Updating a tensor in tensorflow


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?


Solution

  • 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.