我不是 tensorflow 专家,但这是我得到的解决方案。据我所知,张量流中对列表的所有对进行计算的唯一方法是进行矩阵乘法或使用广播规则,该解决方案在某些时候同时使用两者。
假设我们有一个输入布尔矩阵,其中n_samples 行,每组一个,n_features 列,每个可能元素一个。第 i 行第 j 列中的值 True 表示第 i 集合包含元素 j 。就像scikit-learn's pairwise_distances 期望一样。然后我们可以按照以下步骤进行。
- 将矩阵转换为数字,
True 为 1,False 为 0。
- 将矩阵乘以它自己的转置。这会产生一个矩阵,其中每个元素
M[i][j] 包含第 i 和第 j 集之间的交集的大小。
- 通过按行对输入矩阵求和,计算包含所有集合的基数的
cardv 向量。
- 根据
cardv 制作行向量和列向量。
- 计算
1 - M / (cardvrow + cardvcol - M)。添加行向量和列向量时,广播规则将完成所有工作。
这个算法整体上看起来有点 hack-ish,但它的工作原理和产生的结果在 scikit-learn 的 pairwise_distances 函数计算的结果的合理范围内。更好的算法可能应该对每对输入向量进行一次传递,并且只计算矩阵的一半,因为它是对称的。欢迎任何改进。
setsin = tf.placeholder(tf.bool, shape=(N, M))
sets = tf.cast(setsin, tf.float16)
mat = tf.matmul(sets, sets, transpose_b=True, name="Main_matmul")
#mat = tf.cast(mat, tf.float32, name="Upgrade_mat")
#sets = tf.cast(sets, tf.float32, name="Upgrade_sets")
cardinal = tf.reduce_sum(sets, 1, name="Richelieu")
cardinalrow = tf.expand_dims(cardinal, 0)
cardinalcol = tf.expand_dims(cardinal, 1)
mat = 1 - mat / (cardinalrow + cardinalcol - mat)
我使用了float16 类型,因为它似乎比float32 快得多。转换为 float32 可能仅在基数大到足以使它们不准确或在执行除法时需要更高精度时才有用。但即使需要强制转换,将矩阵乘法作为float16 似乎仍然相关。