Reputation: 32051
a = tf.constant([[1,2,3],[4,5,6]])
b = tf.constant([True, False], dtype=tf.bool)
a.eval()
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
b.eval()
array([ True, False], dtype=bool)
I want to apply a functions to the inputs above, a
, and b
using tf.map_fn
. It will input both [1,2,3]
, and True
and output similar values.
Let's say out function is simply the identity: lambda(x,y): x,y
so, given an input of [1,2,3], True
, it will output those identical tensors.
I know how to use tf.map_fn(...)
with one variable, but not with two. And in this case I have mixed data types (int32 and bool) so I can't simply concatenate the tensors and split them after the call.
Can I use tf.map_fn(...)
with multiple inputs/outputs of different data types?
Upvotes: 17
Views: 15413
Reputation: 3821
Updated answer for TFv2
Given
a = tf.constant([[1,2,3],[4,5,6]], dtype=tf.int32)
b = tf.constant([True, False], dtype=tf.bool)
The fn
should only take 1 arg but you can pass a tuple of tf.Tensor
to your function and then split them inside the function like
def fn(a_and_b):
a, b = a_and_b
# then do more stuff on a and b
return (a, b)
Then call tf.map_fn
by
c = tf.map_fn(
fn,
elems=(a, b),
fn_output_signature=(
tf.TensorSpec(shape=[3], dtype=tf.int32),
tf.TensorSpec(shape=[], dtype=tf.bool),
),
)
This gives
>>> c
(<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)>,
<tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])>)
Note dtype
argument is deprecated for tf.map_fn
.
Upvotes: 1
Reputation: 775
Both of these are a little messy, you can define the stack "type" explicitly with a custom Extension Type. Here's your example in a hopefully more readable form:
class BoolAndVector(tf.experimental.BatchableExtensionType):
"""A collection bools and vectors."""
bool: tf.Tensor
vector: tf.Tensor
@tf.function
def fn(bool_and_vector):
return BoolAndVector(bool=bool_and_vector.bool,
vector=[bool_and_vector.vector[0]])
c = tf.map_fn(fn, BoolAndVector(bool=b, vector=a))
You might have to explicitly state the signature type, but the errors will guide you to what TF wants.
Note, you'll need to use BatchableExtensionType to make this usable with map.
Upvotes: 0
Reputation: 19
Do what is said below, but tuple unpack the values inside the tf.function
without the lambda, as computationally expensive and lambdas do not work well with TensorFlow as tf functions.
@tf.function
def x(x):
x,y = tuple(x)
return
c = tf.map_fn(, (a,b), dtype=(tf.int32, tf.bool))
Upvotes: -1
Reputation: 32051
Figured it out. You have to define the data types for each tensor in dtype
for each of the different tensors, then you can pass the tensors as a tuple, your map function receives a tuple of inputs, and map_fn
returns back back a tuple.
Example that works:
a = tf.constant([[1,2,3],[4,5,6]])
b = tf.constant([True, False], dtype=tf.bool)
c = tf.map_fn(lambda x: (x[0], x[1]), (a,b), dtype=(tf.int32, tf.bool))
c[0].eval()
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
c[1].eval()
array([ True, False], dtype=bool)
Upvotes: 24