我有一个整数(b,n)的张量labels
,其值在[0,1,2,3,4,5]中。
我想创建一个形状(b,n)的张量weights
,在位置(i,j)携带整数labels[i,j]
在标签中出现的次数的倒数。
工作示例代码:
import tensorflow as tf
import numpy as np
tf.InteractiveSession()
labels=tf.convert_to_tensor(np.array([[1,0,0,1,2,4],[2,2,2,4,2,1]]), dtype=tf.int32)
weights=tf.ones_like(labels, dtype=tf.float32)
bc=tf.bincount(labels, minlength=6, maxlength=6)
for i in range(6):
cur_count = 1.0/(1e-10+tf.cast(bc[i], tf.float32))
count_tensor = tf.ones_like(labels, dtype=tf.float32)*cur_count
weights = tf.where(tf.equal(labels,i), count_tensor, weights)
weights.eval()
# array([[0.3333, 0.5, 0.5, 0.3333, 0.2, 0.5],
# [0.2, 0.2, 0.2, 0.5, 0.2, 0.3333]], dtype=float32)
例如,标签1
在labels
张量中出现3次,因此在weights
中,值1/3出现在每个位置,其中1
在labels
中。
现在我对这段代码不满意的是tf.bincount在我的Tensorflow版本(1.4.0)中无法在GPU上运行,并且我无法更新。 另外,我不确定张量流如何处理for循环以及由此产生多少开销。
我想我的问题有一个更优雅的解决方案。有什么想法吗?
答案 0 :(得分:3)
关于循环,您可以将其替换为对tf.gather
的调用:
import tensorflow as tf
import numpy as np
tf.InteractiveSession()
labels = tf.convert_to_tensor(
np.array([[1, 0, 0, 1, 2, 4], [2, 2, 2, 4, 2, 1]]), dtype=tf.int32)
bc = tf.bincount(labels, minlength=6, maxlength=6)
weights = tf.gather(1.0 / (1e-10 + tf.cast(bc, tf.float32)), labels)
print(weights.eval())
输出:
[[0.33333334 0.5 0.5 0.33333334 0.2 0.5 ]
[0.2 0.2 0.2 0.5 0.2 0.33333334]]
关于tf.bincount
仅限于CPU,目前似乎并非如此。实际上,since v1.5.0似乎已经提供了GPU实现。
如果您想要其他实现,可以执行以下操作:
import tensorflow as tf
import numpy as np
tf.InteractiveSession()
labels = tf.convert_to_tensor(
np.array([[1, 0, 0, 1, 2, 4], [2, 2, 2, 4, 2, 1]]), dtype=tf.int32)
eq = tf.equal(labels[:, :, tf.newaxis], tf.range(6, dtype=labels.dtype))
bc = tf.reduce_sum(tf.cast(eq, tf.float32), axis=[0, 1])
weights = tf.gather(1.0 / (1e-10 + tf.cast(bc, tf.float32)), labels)
print(weights.eval())
# Same output
但是tf.bincount
可能比这更有效。