Google Article
介绍不规则张量
2018 年 12 月 12 日
发布者:Laurence Moroney

在许多情况下,数据并非均匀地划分成可以加载到张量中的形状一致的数组。一个典型的例子是训练和处理文本。例如,如果您查看使用 IMDB 数据集的文本分类教程,您会发现数据准备工作中很大一部分是将数据整形为标准化的大小。在这种情况下,每条评论都需要 256 个词长。如果它更长,就会被截断,如果它更短,就会用 0 值填充,直到它达到所需长度。

不规则张量旨在解决这个问题。它们是 TensorFlow 中嵌套可变长度列表的等效项。它们使存储和处理具有非均匀形状的数据变得容易,例如
  • 可变长度特征的特征列,例如电影中的演员阵容。
  • 可变长度顺序输入的批次,例如句子或视频片段。
  • 层次结构输入,例如细分为部分、段落、句子和单词的文本文档。
  • 结构化输入中的各个字段,例如协议缓冲区。
因此,例如,考虑这样一段语音,其中每行的长度可能变化很大
speech = tf.ragged.constant(
  [['All', 'the', 'world', 'is', 'a', 'stage'],
  ['And', 'all', 'the', 'men', 'and', 'women', 'merely', 'players'],
  ['They', 'have', 'their', 'exits', 'and', 'their', 'entrances']])
当打印出来时,我们可以看到它是由一个列表列表创建的,每个列表的长度都是可变的
<tf.RaggedTensor [['All', 'the', 'world', 'is', 'a', 'stage'], ['And', 'all', 'the', 'men', 'and', 'women', 'merely', 'players'],  ['They', 'have', 'their', 'exits', 'and', 'their', 'entrances']]>
您期望在普通张量中支持的大多数操作也适用于不规则张量,因此,例如,Python 风格的索引用于访问张量的切片,与预期一致
>>print(speech[0])
tf.Tensor(['All', 'the', 'world', 'is', 'a', 'stage'], shape=(6,), dtype=string)
tf.ragged 包还定义了许多特定于不规则张量操作。例如,tf.ragged.map_flat_values 操作可用于有效地转换不规则张量中的各个值,同时保持其形状不变
> print tf.ragged.map_flat_values(tf.strings.regex_replace,speech, pattern="([aeiouAEIOU])", rewrite=r"{\1}")
您可以在此处了解有关哪些操作受支持的更多信息。

不规则与稀疏

重要的是要注意,不规则张量不同于稀疏张量,而更像是具有不规则形状的密集张量。这里的关键区别在于,不规则张量跟踪每一行的开始和结束位置,而稀疏张量需要跟踪每个项目的坐标。您可以通过探索稀疏张量和不规则张量的级联来看到这种影响。级联稀疏张量等效于级联相应的密集张量,如下例所示(其中 Ø 表示缺失值):但当级联不规则张量时,每一行都会连接起来,形成一个具有组合长度的单行:

使用不规则张量

以下示例展示了使用不规则张量来构建和组合单字(单字词)和词对(双字词)的嵌入,这些单字和词对构成一个可变长度的词列表,形成一个短语。您也可以在不规则张量指南中亲自尝试这段代码。
import math
import tensorflow as tf
tf.enable_eager_execution()
# Set up the embeddingss
num_buckets = 1024
embedding_size = 16
embedding_table = 
    tf.Variable(
        tf.truncated_normal([num_buckets, embedding_size],
        stddev=1.0 / math.sqrt(embedding_size)),
        name="embedding_table")
# Input tensor.
queries = tf.ragged.constant([
    ['Who', 'is', 'Dan', 'Smith']
    ['Pause'],
    ['Will', 'it', 'rain', 'later', 'today']])
# Look up embedding for each word.  map_flat_values applies an operation to each value in a RaggedTensor.
word_buckets = tf.strings.to_hash_bucket_fast(queries, num_buckets)
word_embeddings = tf.ragged.map_flat_values(
        tf.nn.embedding_lookup, embedding_table, word_buckets)  # ①
# Add markers to the beginning and end of each sentence.
marker = tf.fill([queries.nrows()), 1], '#')
padded = tf.concat([marker, queries, marker], axis=1)           # ②
# Build word bigrams & look up embeddings.
bigrams = tf.string_join(
    [padded[:, :-1], padded[:, 1:]], separator='+')             # ③
bigram_buckets = 
    tf.strings.to_hash_bucket_fast(bigrams, num_buckets)
bigram_embeddings = tf.ragged.map_flat_values(
    tf.nn.embedding_lookup, embedding_table, bigram_buckets)   # ④
# Find the average embedding for each sentence
all_embeddings = 
    tf.concat([word_embeddings, bigram_embeddings], axis=1)    # ⑤
avg_embedding = tf.reduce_mean(all_embeddings, axis=1)         # ⑥
print(word_embeddings)
print(bigram_embeddings)
print(all_embeddings)
print(avg_embedding)
下图说明了这一点。请注意,这些数字仅用于说明目的。有关嵌入中的真实值,请查看代码块末尾输出的值。

结论

如您所见,不规则张量对于各种场景非常有用,可以避免您需要创建大小和等级相同的列表。在存储和处理具有非均匀形状的数据时,例如电影演员阵容之类的可变长度特征;句子之类的可变长度顺序输入的批次;层次结构数据结构,例如细分为部分、段落、句子和单词的文档,或协议缓冲区之类的结构化输入中的各个字段。对于这些用例,不规则张量比填充的tf.Tensor更有效,因为没有时间或空间浪费在填充值上;并且比使用tf.SparseTensor更灵活和方便,因为它们支持各种操作,并为可变长度列表提供正确的语义。

目前,不规则张量由低级 TensorFlow API 支持;但在未来几个月内,我们将添加对整个 TensorFlow 堆栈中处理 RaggedTensors 的支持,包括 Keras 层和 TFX。

这仅仅触及了不规则张量的表面,您可以在不规则张量指南中了解有关它们的更多信息。有关不规则张量的更多文档,请参阅 TensorFlow.org 上的tf.ragged 包文档。
下一篇文章
Introducing Ragged Tensors

发布者:Laurence Moroney

在许多情况下,数据并非均匀地划分成可以加载到张量中的形状一致的数组。一个典型的例子是训练和处理文本。例如,如果您查看使用 IMDB 数据集的文本分类教程,您会发现数据准备工作中很大一部分是将数据整形为标准化的大小。在这种情况下,每条评论都需要 256 个词长。如果它更长,就会被截断,如果它更短,就会用 0 值填充,直到它达到所需长度。