【问题标题】:How can I select a row from a SparseTensor in TensorFlow?如何从 TensorFlow 中的 SparseTensor 中选择一行?
【发布时间】:2017-04-22 09:54:30
【问题描述】:

说,如果我有两个SparseTensors 如下:

[[1, 0, 0, 0],
 [2, 0, 0, 0],
 [1, 2, 0, 0]]

[[1.0, 0, 0, 0],
 [1.0, 0, 0, 0],
 [0.3, 0.7, 0, 0]]

我想从中提取前两行。我需要非零条目的索引和值作为SparseTensors,以便我可以将结果传递给tf.nn.embedding_lookup_sparse。我该怎么做?

我的申请是: 我想使用词嵌入,这在 TensorFlow 中非常简单。但现在我想使用稀疏嵌入,即:对于常用词,它们有自己的嵌入。对于稀有词,它们的嵌入是常用词嵌入的稀疏线性组合。 所以我需要两本食谱来说明稀疏嵌入是如何组成的。在前面提到的例子中,食谱说:对于第一个词,它的嵌入由它自己的嵌入组成,权重为 1.0。第二个词的情况类似。对于最后一个词,它说:这个词的embedding是前两个词的embeddings的线性组合,对应的权重分别为0.3和0.7。 我需要提取一行,然后将索引和权重提供给tf.nn.embedding_lookup_sparse 以获得最终嵌入。如何在 TensorFlow 中做到这一点?

或者我需要解决它,即:预处理我的数据并处理来自 TensorFlow 的说明书?

【问题讨论】:

    标签: python tensorflow embedding


    【解决方案1】:

    我联系了一位更了解该领域的工程师,这是他传递的内容:

    我不确定我们是否对此有一个有效的实现,但这里是一个使用 dynamic_partition 和收集操作的不太理想的实现。

    def sparse_slice(indices, values, needed_row_ids):
       num_rows = tf.shape(indices)[0]
       partitions = tf.cast(tf.equal(indices[:,0], needed_row_ids), tf.int32)
       rows_to_gather = tf.dynamic_partition(tf.range(num_rows), partitions, 2)[1]
       slice_indices = tf.gather(indices, rows_to_gather)
       slice_values = tf.gather(values, rows_to_gather)
       return slice_indices, slice_values
    
    with tf.Session().as_default():
      indices = tf.constant([[0,0], [1, 0], [2, 0], [2, 1]])
      values = tf.constant([1.0, 1.0, 0.3, 0.7], dtype=tf.float32)
      needed_row_ids = tf.constant([1])
      slice_indices, slice_values = sparse_slice(indices, values, needed_row_ids)
      print(slice_indices.eval(), slice_values.eval())
    

    更新:

    工程师也发送了一个示例来帮助处理多行,感谢您指出这一点!

    def sparse_slice(indices, values, needed_row_ids):
      needed_row_ids = tf.reshape(needed_row_ids, [1, -1])
      num_rows = tf.shape(indices)[0]
      partitions = tf.cast(tf.reduce_any(tf.equal(tf.reshape(indices[:,0], [-1, 1]), needed_row_ids), 1), tf.int32)
      rows_to_gather = tf.dynamic_partition(tf.range(num_rows), partitions, 2)[1]
      slice_indices = tf.gather(indices, rows_to_gather)
      slice_values = tf.gather(values, rows_to_gather)
      return slice_indices, slice_values
    
    with tf.Session().as_default():
      indices = tf.constant([[0,0], [1, 0], [2, 0], [2, 1]])
      values = tf.constant([1.0, 1.0, 0.3, 0.7], dtype=tf.float32)
      needed_row_ids = tf.constant([0, 2])
    

    【讨论】:

    • 哦,我明白了。它巧妙地结合了dynamic_partition 和gather。这个想法是,不要形成 SparseTensor。相反,只需在密集的 indicesvalues 数组上执行 dynamic_partitiongather
    • 这很有帮助!顺便说一句,这段代码似乎只适用于单行。如何提取多行(即使有重复)?说,如果我想提取第一、第三和第三行?这意味着,在一个输入句子中,可能存在一些单词多次出现。我知道我可以多次运行sparse_slice,然后使用tf.concat 将它们连接起来,但有没有更好的方法?
    • 我终于明白了。我可以类似地对密集的indicesvalues 执行分区。明天我会发布一个解决方案,它大量使用tf.gather
    【解决方案2】:

    sp 成为您的 2d SparseTensor 的名称。您可以先为您要提取的 SparseTensor 的行创建一个指标张量,即

    mask = tf.concat([tf.constant([True, True]), tf.fill([sp.dense_shape[0] - 2],
        False)], axis=0)
    

    接下来使用 tf.gather 将其传播到稀疏索引:

    mask_sp = tf.gather(mask, sp.indices[:, 0])
    

    最后,

    values = tf.boolean_mask(sp.values, mask_sp)
    indices = tf.boolean_mask(sp.indices, mask_sp)
    dense_shape = [sp.dense_shape[0] - 2, sp.dense_shape[1]]
    output_sp = tf.SparseTensor(indices=indices, values=values, dense_shape=dense_shape)
    

    【讨论】:

      【解决方案3】:

      它不应该表现得更像这样吗:

      此版本将保留 selected_indices 中索引的顺序和频率,因此,例如多次选择同一行:

      import tensorflow as tf
      tf.enable_eager_execution()
      
      def sparse_gather(indices, values, selected_indices, axis=0):
          """
          indices: [[idx_ax0, idx_ax1, idx_ax2, ..., idx_axk], ... []]
          values:  [ value1,                                 , ..., valuen]
          """
          mask = tf.equal(indices[:, axis][tf.newaxis, :], selected_indices[:, tf.newaxis])
          to_select = tf.where(mask)[:, 1]
          return tf.gather(indices, to_select, axis=0), tf.gather(values, to_select, axis=0)
      
      
      indices = tf.constant([[1, 0], [2, 0], [3, 0], [7, 0]])
      values = tf.constant([1.0, 2.0, 3.0, 7.0], dtype=tf.float32)
      needed_row_ids = tf.constant([7, 3, 2, 2, 3, 7])
      slice_indices, slice_values = sparse_gather(indices, values, needed_row_ids)
      print(slice_indices, slice_values)
      

      【讨论】:

        【解决方案4】:

        我尝试了“Pete Warden”的答案,该答案仅适用于小数据。给定具有 m 个非零元素的稀疏张量 A,我们想取出 n 行。 tf.equal 将占用 m*n 空间,这在我的任务中是不可接受的。

        我的建议是使用 Scipy.sparse 而不是 tensorflow。 详情:

        1. 从 tf、索引和数据中取出所有数据,并形成一个 Scipy.sparse。使用酷
        2. 如果您需要取出行,请使用 csr 甲酸盐。如果您需要取出 cols,请使用 csc
        3. A[:,m]
        4. 转换为酷
        5. 转换为 tf

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多