是否有更简单的方法来获取张量的切片,如下例所示?

Posted

技术标签:

【中文标题】是否有更简单的方法来获取张量的切片,如下例所示?【英文标题】:Is there a simpler method to get slice of a tensors as shown in the following example? 【发布时间】:2019-10-05 20:33:58 【问题描述】:

我想对张量进行切片,如下面的 numpy 切片。我该怎么做?

# numpy array
a = np.reshape(np.arange(60), (3,2,2,5))
idx = np.array([0, 1, 0])
N = np.shape(a)[0]
mask = a[np.arange(N),:,:,idx]


# I have tried several solutions, but only the following success.
# tensors
import tensorflow as tf
import numpy as np


a = tf.cast(tf.constant(np.reshape(np.arange(60), (3,2,2,5))), tf.int32)
idx2 = tf.constant([0, 1, 0])

fn = lambda i: a[i][:,:,idx2[i]]
idx = tf.range(tf.shape(a)[0])
masks = tf.map_fn(fn, idx)
with tf.Session() as sess:
    print(sess.run(a))
    print(sess.run(tf.shape(masks)))
    print(sess.run(masks))

有没有更简单的方法来实现这一点?

我可以使用函数tf.gathertf.gather_nd 来实现吗? 非常感谢!

【问题讨论】:

【参考方案1】:

1.另一种方法

我不确定这是否是最好的方法,但它更快。您可以使用tf.boolean_mask 代替tf.map_fn

import tensorflow as tf
import numpy as np

a = tf.cast(tf.constant(np.reshape(np.arange(60), (3,2,2,5))), tf.int32)
idx2 = tf.constant([0, 1, 0])

fn = lambda i: a[i,:,:][:,:,idx2[i]]
idx = tf.range(tf.shape(a)[0])
masks = tf.map_fn(fn, idx)

# new method
idx = tf.one_hot(idx2,depth=a.shape[-1])
masks2 = tf.boolean_mask(tf.transpose(a,[0,3,1,2]), idx)

with tf.Session() as sess:
    print('tf.map_fn version:\n',sess.run(masks))
    print('tf.boolean_mask version:\n',sess.run(masks2))

# print
tf.map_fn version:
 [[[ 0  5]
  [10 15]]

 [[21 26]
  [31 36]]

 [[40 45]
  [50 55]]]
tf.boolean_mask version:
 [[[ 0  5]
  [10 15]]

 [[21 26]
  [31 36]]

 [[40 45]
  [50 55]]]

2.性能对比

在我的 8GB GPU 内存上,向量化方法 1000 次迭代需要 0.07stf.map_fn 方法 1000 次迭代需要 0.85s。向量化方法将明显快于tf.map_fn()

import datetime
...
with tf.Session() as sess:
    start = datetime.datetime.now()
    for _ in range(1000):
        sess.run(masks)
    end = datetime.datetime.now()
    print('tf.map_fn version cost time(seconds) : %.2f' % ((end - start).total_seconds()))

    start = datetime.datetime.now()
    for _ in range(1000):
        sess.run(masks2)
    end = datetime.datetime.now()
    print('tf.boolean_mask version cost time(seconds) : %.2f' % ((end - start).total_seconds()))

# print
tf.map_fn version cost time(seconds) : 0.85
tf.boolean_mask version cost time(seconds) : 0.07

我相信随着a的形状增加,性能差异会变得更加明显。

【讨论】:

【参考方案2】:

另一种方法使用tf.gather_nd:

import tensorflow as tf
import numpy as np


a = tf.cast(tf.constant(np.reshape(np.arange(60), (3,2,2,5))), tf.int32)
idx = tf.range(tf.shape(a)[0])
idx2 = tf.constant([0,1,0])
indices = tf.stack([idx, idx2], axis=1)
a = tf.transpose(a, [0,3,1,2])
masks = tf.gather_nd(a, indices)

with tf.Session() as sess:
    print(sess.run(a))
    print(sess.run(tf.shape(masks)))
    print(sess.run(masks))

【讨论】:

以上是关于是否有更简单的方法来获取张量的切片,如下例所示?的主要内容,如果未能解决你的问题,请参考以下文章

在 Tensorflow 2.0 中是不是有更简单的方法来执行模型层?

根据张量流中给定的序列长度数组对 3D 张量进行切片

Keras:如何使用来自另一个张量的信息对张量进行切片?

是否有更简洁的方法来获取错误和 Promise 的结果 [重复]

是否有更简单的方法来加载 Spring OAuth 客户端配置

如何通过方法(不是api)通过identityserver4获取访问令牌?