如何解释tf.map_fn的结果? [英] How to explain the result of tf.map_fn?

查看:27
本文介绍了如何解释tf.map_fn的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看代码:

将tensorflow导入为tf将 numpy 导入为 npelems = tf.ones([1,2,3],dtype=tf.int64)替代 = tf.map_fn(lambda x: (x, x, x), elems, dtype=(tf.int64, tf.int64, tf.int64))使用 tf.Session() 作为 sess:打印(sess.run(替代))

输出为:

(array([[[1, 1, 1],[1, 1, 1]]], dtype=int64), array([[[1, 1, 1],[1, 1, 1]]], dtype=int64), array([[[1, 1, 1],[1, 1, 1]]], dtype=int64))

我看不懂输出,谁能告诉我?

更新

elems 是一个张量,所以它应该沿着轴 0 解包,我们将得到 [[1,1,1],[1,1,1]],然后 map_fn[[[1,1,1],[1,1,1]] 传入 lambda x:(x,x,x),表示x=[[1,1,1],[1,1,1]],我认为map_fn 是

[[[1,1,1],[1,1,1]],[[1,1,1],[1,1,1]],[[1,1,1],[1,1,1]]]

输出的形状是[3,2,3]shape(2,3)

的列表

但实际上输出的是一个张量列表,每个张量的形状是[1,2,3].

或者换句话说:

将tensorflow导入为tf将 numpy 导入为 npelems = tf.constant([1,2,3],dtype=tf.int64)替代 = tf.map_fn(lambda x: (x, 2*x, -x), elems, dtype=(tf.int64, tf.int64, tf.int64))使用 tf.Session() 作为 sess:打印(sess.run(替代))

为什么输出是

(array([1, 2, 3], dtype=int64),数组([2, 4, 6], dtype=int64),数组([-1, -2, -3], dtype=int64))

而不是

(array([1, 2, -1], dtype=int64),数组([2, 4, -2], dtype=int64),数组([3, 6, -3], dtype=int64))

这两个问题是一样的.

更新 2

将tensorflow导入为tf将 numpy 导入为 npelems = [tf.constant([1,2,3],dtype=tf.int64)]替代 = tf.map_fn(lambda x: x, elems, dtype=tf.int64)使用 tf.Session() 作为 sess:打印(sess.run(替代))

elems 是张量的列表,所以根据api,tf.constant([1,2,3],dtype=tf.int64) 会被解包沿轴 0,所以 map_fn 将用作 [x for x in [1,2,3]],但实际上它会引发错误.

ValueError: 这两个结构没有相同的嵌套结构.第一个结构ture:<dtype:'int64'>,第二个结构:[<tf.Tensor'map/while/TensorArrayReadV3:0' shape=() dtype=int64>].

怎么了?

更新 3

将tensorflow导入为tf将 numpy 导入为 npelems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))替代 = tf.map_fn(lambda x: x, elems, dtype=(tf.int64, tf.int64))使用 tf.Session() 作为 sess:打印(sess.run(替代))

输出是

(array([1, 2, 3], dtype=int64), array([1, 2, 3], dtype=int64))

elems 好像没有解压,为什么?

将tensorflow导入为tf将 numpy 导入为 npelems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))替代 = tf.map_fn(lambda x: [x], elems, dtype=(tf.int64, tf.int64))使用 tf.Session() 作为 sess:打印(sess.run(替代))

会报错

TypeError: 这两个结构没有相同的序列类型.第一结构具有类型 ,而第二个结构具有类型 .

谁能告诉我 tf.map_fn 是如何工作的?

解决方案

首先,

elems = tf.ones([1,2,3],dtype=tf.int64)

elems 是一个形状为 1x2x3 的 3 维张量,即:

[[[1, 1, 1],[1, 1, 1]]]

那么,

alternates = tf.map_fn(lambda x: (x, x, x), elems, dtype=(tf.int64, tf.int64, tf.int64))

alternates 是三个与 elems 形状相同的张量的元组,每个张量都是根据给定的函数构建的.由于该函数只返回一个重复输入三次的元组,这意味着三个张量将与 elems 相同.如果函数是 lambda x: (x, 2 * x, -x) 那么第一个输出张量将与 elems 相同,第二个将是elems 而第三个则相反.

在所有这些情况下,最好使用常规操作而不是 tf.map_fn;但是,在某些情况下,您可能有一个函数接受 N 维的张量,而您有一个 N + 1 的张量想要应用它.>

更新:

我认为您正在考虑 tf.map_fn反过来",可以这么说.张量中的元素或行数与函数中的输出数之间没有一一对应的关系;实际上,您可以传递一个函数,该函数返回一个包含任意数量元素的元组.

以你的最后一个例子为例:

elems = tf.constant([1,2,3],dtype=tf.int64)替代 = tf.map_fn(lambda x: (x, 2*x, -x), elems, dtype=(tf.int64, tf.int64, tf.int64))

tf.map_fn 第一次拆分 elems 在第一个轴上,即分为 123,并将函数应用于它们中的每一个,得到:

(1, 2, -1)(2, 4, -2)(3, 6, -3)

请注意,正如我所说,这些元组中的每一个都可以包含任意数量的元素.现在,将相同位置的结果连接起来产生最终输出;所以你得到:

[1, 2, 3][2, 4, 6][-1, -2, -3]

同样,如果函数生成包含更多元素的元组,您将获得更多输出张量.

更新 2:

关于您的新示例:

将tensorflow导入为tf将 numpy 导入为 npelems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))替代 = tf.map_fn(lambda x: x, elems, dtype=(tf.int64, tf.int64))使用 tf.Session() 作为 sess:打印(sess.run(替代))

文档 说:

<块引用>

此方法还允许多元元素和 fn 的输出.如果 elems 是一个(可能是嵌套的)张量列表或元组,那么这些张量中的每一个都必须具有匹配的第一(解包)维度.fn 的签名可以匹配 elems 的结构.也就是说,如果 elems 是 (t1, [t2, t3, [t4, t5]]),那么 fn 的合适签名是: fn = lambda (t1, [t2, t3, [t4, t5]]):.

这里 elems 是一个由两个在第一维中具有相同大小的张量组成的元组,根据需要.tf.map_fn 获取每个输入张量的一个元素一次(所以是两个元素的元组)并将给定的函数应用于它,它应该返回您在 dtypes 中传递的相同结构(也是两个元素的元组);如果您不提供 dtypes,则预期输出与输入相同(同样,两个元素的元组,因此在您的情况下 dtypes 是可选的).无论如何,它是这样的:

f((1, 1)) ->(1, 1)f((2, 2)) ->(2, 2)f((3, 3)) ->(3, 3)

将这些结果组合起来,将结构中所有对应的元素串联起来;在这种情况下,第一个位置的所有数字产生第一个输出,第二个位置的所有数字产生第二个输出.结果是,最后,请求的结构(二元素元组)填充了这些连接:

([1, 2, 3], [1, 2, 3])

Look at the code:

import tensorflow as tf
import numpy as np

elems = tf.ones([1,2,3],dtype=tf.int64)
alternates = tf.map_fn(lambda x: (x, x, x), elems, dtype=(tf.int64, tf.int64, tf.int64))
with tf.Session() as sess:
    print(sess.run(alternates))

The output is:

(array([[[1, 1, 1],
        [1, 1, 1]]], dtype=int64), array([[[1, 1, 1],
        [1, 1, 1]]], dtype=int64), array([[[1, 1, 1],
        [1, 1, 1]]], dtype=int64))

I can't understand the output, who can tell me?

update

elems is a tensor, so it should be unpacked along axis-0, and we will get [[1,1,1],[1,1,1]], and then map_fn pass [[1,1,1],[1,1,1]] into lambda x:(x,x,x),which means x=[[1,1,1],[1,1,1]], and I think the output of map_fn is

[[[1,1,1],[1,1,1]],
 [[1,1,1],[1,1,1]],
 [[1,1,1],[1,1,1]]]

The shape of output is [3,2,3] or a list of shape(2,3)

But in fact, the output is a list of tensor, the shape of each tensor is [1,2,3].

Or in other words:

import tensorflow as tf
import numpy as np

elems = tf.constant([1,2,3],dtype=tf.int64)
alternates = tf.map_fn(lambda x: (x, 2*x, -x), elems, dtype=(tf.int64, tf.int64, tf.int64))
with tf.Session() as sess:
    print(sess.run(alternates))

Why the output is

(array([1, 2, 3], dtype=int64), 
 array([2, 4, 6], dtype=int64), 
 array([-1, -2, -3], dtype=int64))

rather than

(array([1, 2, -1], dtype=int64), 
 array([2, 4, -2], dtype=int64), 
 array([3, 6, -3], dtype=int64))

The two question is the same.

Update2

import tensorflow as tf
import numpy as np

elems = [tf.constant([1,2,3],dtype=tf.int64)]
alternates = tf.map_fn(lambda x: x, elems, dtype=tf.int64)
with tf.Session() as sess:
    print(sess.run(alternates))

elems is a list of tensor, so according to api, tf.constant([1,2,3],dtype=tf.int64) will be unpacked along axis-0, so map_fn will works as [x for x in [1,2,3]], but in fact it will raise a error.

ValueError: The two structures don't have the same nested structure. First struc
ture: <dtype: 'int64'>, second structure: [<tf.Tensor 'map/while/TensorArrayRead
V3:0' shape=() dtype=int64>].

What's wrong?

update3

import tensorflow as tf
import numpy as np

elems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))
alternates = tf.map_fn(lambda x: x, elems, dtype=(tf.int64, tf.int64))
with tf.Session() as sess:
    print(sess.run(alternates))

The output is

(array([1, 2, 3], dtype=int64), array([1, 2, 3], dtype=int64))

It seems that elems aren't unpacked, why?

import tensorflow as tf
import numpy as np

elems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))
alternates = tf.map_fn(lambda x: [x], elems, dtype=(tf.int64, tf.int64))
with tf.Session() as sess:
    print(sess.run(alternates))

It will raise a error

TypeError: The two structures don't have the same sequence type. First structure
 has type <class 'tuple'>, while second structure has type <class 'list'>.

Who can tell me how tf.map_fn works?

解决方案

First,

elems = tf.ones([1,2,3],dtype=tf.int64)

elems is a 3-dimensional tensor with shape 1x2x3 full of ones, that is:

[[[1, 1, 1],
  [1, 1, 1]]]

Then,

alternates = tf.map_fn(lambda x: (x, x, x), elems, dtype=(tf.int64, tf.int64, tf.int64))

alternates is a tuple of three tensors with the same shape as elems, each of which is built according to the given function. Since the function simply returns a tuple repeating its input three times, that means that the three tensors will be the same as elems. If the function were lambda x: (x, 2 * x, -x) then the first output tensor would be the same as elems, the second would be the double of elems and the third one the opposite.

In all these cases it is preferable to use regular operations instead of tf.map_fn; however, there may be cases where you have a function accepting tensors with N dimensions and you have a tensor with N + 1 that you want to have it applied to.

UPDATE:

I think you are thinking of tf.map_fn "the other way around", so to say. There is not a one-to-one correspondence between the number of elements or rows in the tensor and the number of outputs in the function; in fact, you could pass a function returning a tuple with as many elements as you want.

Taking your last example:

elems = tf.constant([1,2,3],dtype=tf.int64)
alternates = tf.map_fn(lambda x: (x, 2*x, -x), elems, dtype=(tf.int64, tf.int64, tf.int64))

tf.map_fn first split elems in the first axis, that is into 1, 2 and 3, and applies the function to each of them, getting:

(1, 2, -1)
(2, 4, -2)
(3, 6, -3)

Note that, as I said, each of these tuples could have as many elements as you wanted. Now, the final output is produced concatenating the results in the same position; so you get:

[1, 2, 3]
[2, 4, 6]
[-1, -2, -3]

Again, if the function produced tuples with more elements you would get more output tensors.

UPDATE 2:

About your new example:

import tensorflow as tf
import numpy as np

elems = (tf.constant([1,2,3],dtype=tf.int64),tf.constant([1,2,3],dtype=tf.int64))
alternates = tf.map_fn(lambda x: x, elems, dtype=(tf.int64, tf.int64))
with tf.Session() as sess:
    print(sess.run(alternates))

The documentation says:

This method also allows multi-arity elems and output of fn. If elems is a (possibly nested) list or tuple of tensors, then each of these tensors must have a matching first (unpack) dimension. The signature of fn may match the structure of elems. That is, if elems is (t1, [t2, t3, [t4, t5]]), then an appropriate signature for fn is: fn = lambda (t1, [t2, t3, [t4, t5]]):.

Here elems is a tuple of two tensors with the same size in the first dimension, as needed. tf.map_fn takes one element of each input tensor at a time (so a tuple of two elements) and applies the given function to it, which should return the same structure that you passed in dtypes (a tuple of two elements, too); if you don't give a dtypes, then the expected output is the same as the input (again, a tuple of two elements, so in your case dtypes is optional). Anyway, it goes like this:

f((1, 1)) -> (1, 1)
f((2, 2)) -> (2, 2)
f((3, 3)) -> (3, 3)

These results are combined, concatenating all the corresponding elements in the structure; in this case, all the numbers in the first position produce the first output and all the numbers in the second positions produce the second output. The result is, finally, the requested structure (the two-element tuple) filled with these concatenations:

([1, 2, 3], [1, 2, 3])

这篇关于如何解释tf.map_fn的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆