如何创建一个多维的单热张量

时间:2018-01-10 23:37:46

标签: tensorflow

我有一个K(x_i,y_i)对的列表,其中0 <= x_i&lt; X和0 <= y_i&lt; Y表示形状的张量[K,2]。

我想创建一个形状[K,X,Y]的张量T,其中如果x = x_i且y = y_i则T [i,x,y] = 1,否则为0。

我知道对于索引列表我可以使用tf.one_hot,但不确定我是否可以在这里重用它?类似于tf.one_hot(对,深度=(X,Y))

2 个答案:

答案 0 :(得分:0)

this SO post开始,我们可以在numpy中轻松完成此操作:

(np.arange(a.max()) == a[...,None]-1).astype(int)

完全使用这个技巧,现在我们只需将其移植到tensorflow

# for the numpy, full credit to @Divakar and https://stackoverflow.com/questions/34987509/tensorflow-max-of-a-tensor-along-an-axis
print('first an awesome way to do it in numpy...')
a = np.array([[1,2,4],[3,1,0]])
print((np.arange(a.max()) == a[...,None]-1).astype(int))

# porting this to tensorflow...
print('\nnow in tensorflow...')
b = tf.constant([[1,2,4],[3,1,0]])
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(tf.cast(tf.equal(tf.range(tf.reduce_max(b)),tf.reshape(b,[2,3,1])-1),tf.int32)))

返回:

first an awesome way to do it in numpy...
[[[1 0 0 0]
  [0 1 0 0]
  [0 0 0 1]]

 [[0 0 1 0]
  [1 0 0 0]
  [0 0 0 0]]]

now in tensorflow...
[[[1 0 0 0]
  [0 1 0 0]
  [0 0 0 1]]

 [[0 0 1 0]
  [1 0 0 0]
  [0 0 0 0]]]

这很有趣。

答案 1 :(得分:0)

我认为最好的解决方案是使用tf.sparse_to_dense。例如,如果我们希望将它们放在10x8矩阵的(6,2),(3,4),(4,5)位置:

indices = sorted([[6,2],[3,4],[4,5]])
one_hot_encoded = tf.sparse_to_dense(sparse_indices=indices, output_shape=[10,8], sparse_values=1)
with tf.Session() as session:
    tf.global_variables_initializer().run()
    print(one_hot_encoded.eval())

这将返回以下内容:

[[0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]]

此外,输入(例如索引)可能是tf.Variable对象,不需要保持不变。

它有两个限制,即必须对索引进行排序(因此,上面的sorted)并且不能重复。您也可以直接使用tf.one_hot。在这种情况下,您需要将索引作为所有x之前和之后的所有y,即list(zip(*indices))的两个向量。然后一个人可以做:

new_indices = list(zip(*indices))
# one of the following: the first one is for xy index convention:
flat_indices = new_indices[1] * depth[1] + new_indices[0]
# this other for ij convention:
# flat_indices = new_indices[0] * depth[1] + new_indices[1]

# Apply tf.one_hot to the flattened vector, then sum along the newly created dimension
one_hot_flat = tf.reduce_sum(tf.one_hot(flat_indices, depth=np.prod(im_size)), axis=0)

# Finally reshape
one_hot_encoded = tf.reshape(oh, im_size)

with tf.Session() as session:
    tf.global_variables_initializer().run()
    print(one_hot_encoded.eval())

这与上面的返回相同。但是,索引不需要排序,并且可以重复(在这种情况下,对应的条目将是出现的次数;对于到处都是简单的“ 1”,请将tf.reduce_sum替换为{{1} }。这也支持变量。

但是,对于大索引/深度,内存消耗可能是一个问题。它创建一个临时tf.reduce_max张量,其中N x W x H是索引元组的数量,可能会出现问题。因此,在可能的情况下,第一种解决方案可能是更可取的。

实际上,如果可以使用稀疏张量就可以了,那么最有效利用内存的方法可能就是:

N

运行时,这将返回更神秘的内容:

sparse = tf.SparseTensor(indices=indices, values=[1]*len(indices), dense_shape=[10, 8])