我怎样才能 select 来自 TensorFlow 中的 SparseTensor 的一行?
How can I select a row from a SparseTensor in TensorFlow?
比如说,如果我有两个 SparseTensor
如下:
[[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]]
我想从中提取前两行。我需要非零条目的索引和值作为 SparseTensor
s,以便我可以将结果传递给 tf.nn.embedding_lookup_sparse
。我该怎么做?
我的申请是:
我想使用词嵌入,这在 TensorFlow 中非常简单。但现在我想使用稀疏嵌入,即:对于常用词,它们有自己的嵌入。对于稀有词,它们的嵌入是常见词嵌入的稀疏线性组合。
所以我需要两本食谱来说明稀疏嵌入是如何组成的。在前面提到的示例中,食谱说:对于第一个单词,它的嵌入由其自身的权重为 1.0 的嵌入组成。第二个词的情况类似。对于最后一个词,表示:这个词的embedding是前两个词embeddings的线性组合,对应的权重分别为0.3和0.7。
我需要提取一行,然后将索引和权重提供给 tf.nn.embedding_lookup_sparse
以获得最终的嵌入。我如何在 TensorFlow 中做到这一点?
或者我需要解决它,即:预处理我的数据并处理 TensorFlow 中的食谱?
我与这里的一位工程师进行了交流,他更了解这个领域,以下是他传递的信息:
我不确定我们是否有一个有效的实现,但这里有一个使用 dynamic_partition 和 gather ops 的不太理想的实现。
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])
让 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)
它不应该更像这样吗:
此版本将保持 selected_indices 中索引的顺序和频率,因此,例如, select 同一行多次:
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)
我尝试了“Pete Warden”的答案,它只适用于小数据。给定具有 m 个非零元素的稀疏张量 A,我们想取出 n 行。 tf.equal 需要 m*n space,这在我的任务中是不可接受的。
我的建议是使用 Scipy.sparse 而不是 tensorflow。
详情:
- 从tf,indices&data中取出所有数据,组成一个Scipy.sparse。使用 coo
- 如果您需要删除行,请使用 csr formate。如果你需要删除 cols,请使用 csc
- A[:,m]
- 变身coo
- 转换为 tf
比如说,如果我有两个 SparseTensor
如下:
[[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]]
我想从中提取前两行。我需要非零条目的索引和值作为 SparseTensor
s,以便我可以将结果传递给 tf.nn.embedding_lookup_sparse
。我该怎么做?
我的申请是:
我想使用词嵌入,这在 TensorFlow 中非常简单。但现在我想使用稀疏嵌入,即:对于常用词,它们有自己的嵌入。对于稀有词,它们的嵌入是常见词嵌入的稀疏线性组合。
所以我需要两本食谱来说明稀疏嵌入是如何组成的。在前面提到的示例中,食谱说:对于第一个单词,它的嵌入由其自身的权重为 1.0 的嵌入组成。第二个词的情况类似。对于最后一个词,表示:这个词的embedding是前两个词embeddings的线性组合,对应的权重分别为0.3和0.7。
我需要提取一行,然后将索引和权重提供给 tf.nn.embedding_lookup_sparse
以获得最终的嵌入。我如何在 TensorFlow 中做到这一点?
或者我需要解决它,即:预处理我的数据并处理 TensorFlow 中的食谱?
我与这里的一位工程师进行了交流,他更了解这个领域,以下是他传递的信息:
我不确定我们是否有一个有效的实现,但这里有一个使用 dynamic_partition 和 gather ops 的不太理想的实现。
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])
让 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)
它不应该更像这样吗:
此版本将保持 selected_indices 中索引的顺序和频率,因此,例如, select 同一行多次:
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)
我尝试了“Pete Warden”的答案,它只适用于小数据。给定具有 m 个非零元素的稀疏张量 A,我们想取出 n 行。 tf.equal 需要 m*n space,这在我的任务中是不可接受的。
我的建议是使用 Scipy.sparse 而不是 tensorflow。 详情:
- 从tf,indices&data中取出所有数据,组成一个Scipy.sparse。使用 coo
- 如果您需要删除行,请使用 csr formate。如果你需要删除 cols,请使用 csc
- A[:,m]
- 变身coo
- 转换为 tf