2

I am observing diverging behaviour from both Numpy and pure Tensorflow when implementing the same simple functionality that shares a variable across iterations in a for loop with tf.py_func.

Let's start with the pure Numpy version:

def my_func(x, k):
    return np.tile(x,k)

x = np.ones((1), np.int64)
for i in range(1,3):
    x = my_func(x, i)

print(x)

This produces the expected output. Initially x is [1]. On the first iteration, it is replicated once to produce [1]. Then on the next iteration, the result is replicated twice, producing the final output [1 1].

A similar approach also produces the same expected output in pure Tensorflow:

x = tf.constant([1], tf.int64)
for i in range(1,3):
    x = tf.tile(x, [i])

with tf.Session() as sess:
    xx = sess.run(x)
    print(xx)

The output is [1 1].

Now I am attempting to do essentially the same thing using tf.py_func, and I can't wrap my head around why I am seeing a different output. This code:

import tensorflow as tf
import numpy as np

def my_func(x, k):
    return np.tile(x,k)

x = tf.constant([1], tf.int64)
for i in range(1,3):
    x = tf.py_func(lambda y: my_func(y, i), [x], tf.int64)

with tf.Session() as sess:
    xx = sess.run(x)
    print(xx)

Produces the unexpected result [1 1 1 1].

Why is this happening? Does py_func have some property that it does not work well with sharing (tensor) variable names, in this case the variable x that is updated on each loop iteration?

Please note that this is a simplified example that reproduces the problem, and whose functionality is easy to reproduce in pure Tensorflow. In my actual application there is a need to use tf.py_func, since the functionality is more complicated.

1 Answer 1

2

Without the lambda function, it works as intended:

import tensorflow as tf
import numpy as np

def my_func(x, k):
    return np.tile(x,k)

x = tf.constant([1], tf.int64)
for i in range(1,3):
    x = tf.py_func(my_func, [x, i], tf.int64)

with tf.Session() as sess:
    xx = sess.run(x)
    print(xx)

returns [1 1]

edit

I found out why: lambda y: my_func(y, i) saves i by reference and not by value. Therefore the last i value of the for loop is applied to all py_func in the loop. Here is a simpler example that shows the problem:

import tensorflow as tf

def my_func(x, y):
  return x - y

x1 = tf.constant([0], tf.float32)
for i in range(2):
    x1 = tf.py_func(lambda y: my_func(y, i), [x1], tf.float32)

x2 = tf.constant([0], tf.float32)
x2 = tf.py_func(lambda y: my_func(y, 0), [x2], tf.float32)
x2 = tf.py_func(lambda y: my_func(y, 1), [x2], tf.float32)

with tf.Session() as sess:
    print(sess.run(x1))
    print(sess.run(x2))
Sign up to request clarification or add additional context in comments.

1 Comment

Nice job! This one really had me scratching my head.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.