水平平移张量,回填零

时间:2019-04-19 19:44:58

标签: tensorflow

给出2D张量

T = [[1, 2, 3]
     [4, 5, 6]]

和一个包含水平移位的1D张量,例如s = [0, -2, 1],我如何获得以下3D张量R

R[0] = T

R[1] = [[3, 0, 0],  # shifted two to the left,
        [6, 0, 0]]  # padding the rest with zeros

R[2] = [[0, 1, 2],  # shifted one to the right,
        [0, 4, 5]]  # padding the rest with zeros

我了解tf.contrib.image.translate,但这是无可区别的,所以我正在寻找可以完成相同任务的填充/切片/循环/串联操作的完美组合。

1 个答案:

答案 0 :(得分:1)

我只想出两种使用tf.map_fn()的方法。第一种方法是在T中填充大约0并将其切成薄片。

import tensorflow as tf

T = tf.constant([[1, 2, 3],[4, 5, 6]],dtype=tf.float32)
s = tf.constant([0, -2, 1])

left = tf.reduce_max(s)
right = tf.reduce_min(s)
left_mask = tf.zeros(shape=(tf.shape(T)[0],left))
right_mask = tf.zeros(shape=(tf.shape(T)[0],tf.abs(right)))
tmp_slice = tf.concat([left_mask,T,right_mask],axis=-1)

result = tf.map_fn(lambda x: tmp_slice[:,left-x:left-x+tf.shape(T)[1]],s,dtype=T.dtype)
grads = tf.gradients(ys=result,xs=T)

with tf.Session() as sess:
    print(sess.run(result))
    print(sess.run(grads))

# print
[[[1. 2. 3.]
  [4. 5. 6.]]

 [[3. 0. 0.]
  [6. 0. 0.]]

 [[0. 1. 2.]
  [0. 4. 5.]]]
[array([[2., 2., 2.],
       [2., 2., 2.]], dtype=float32)]

第二种方法是通过tf.sequence_masktf.roll()计算相应的掩码矩阵,然后通过tf.where()取值。

import tensorflow as tf

T = tf.constant([[1, 2, 3],[4, 5, 6]],dtype=tf.float32)
s = tf.constant([0, -2, 1])

def mask_f(x):
    indices = tf.tile([x], (tf.shape(T)[0],))
    mask = tf.sequence_mask(tf.shape(T)[1]-tf.abs(indices),tf.shape(T)[1])
    mask = tf.roll(mask,shift=tf.maximum(0,x),axis=-1)
    return tf.where(mask,tf.roll(T,shift=x,axis=-1),tf.zeros_like(T))

result = tf.map_fn(lambda x:mask_f(x),s,dtype=T.dtype)
grads = tf.gradients(ys=result,xs=T)

with tf.Session() as sess:
    print(sess.run(result))
    print(sess.run(grads))

# print
[[[1. 2. 3.]
  [4. 5. 6.]]

 [[3. 0. 0.]
  [6. 0. 0.]]

 [[0. 1. 2.]
  [0. 4. 5.]]]
[array([[2., 2., 2.],
       [2., 2., 2.]], dtype=float32)]

更新

我找到了实现它的新方法。本质上,水平偏移量T乘以偏移量单位矩阵。因此,我们可以使用np.eye()来创建因子。

import tensorflow as tf
import numpy as np

T = tf.constant([[1, 2, 3],[4, 5, 6]],dtype=tf.float32)
s = tf.constant([0, -2, 1])

new_T = tf.tile(tf.expand_dims(T,axis=0),[tf.shape(s)[0],1,1])
s_factor = tf.map_fn(lambda x: tf.py_func(lambda y: np.eye(T.get_shape().as_list()[-1],k=y),[x],tf.float64),s,tf.float64)

result = tf.matmul(new_T,tf.cast(s_factor,new_T.dtype))
grads = tf.gradients(ys=result,xs=T)

with tf.Session() as sess:
    print(sess.run(result))
    print(sess.run(grads))

# print
[[[1. 2. 3.]
  [4. 5. 6.]]

 [[3. 0. 0.]
  [6. 0. 0.]]

 [[0. 1. 2.]
  [0. 4. 5.]]]
[array([[2., 2., 2.],
       [2., 2., 2.]], dtype=float32)]