このページは Cloud Translation API によって翻訳されました。
Switch to English

ラグドテンソル

TensorFlow.org上に表示します Googleのコラボで実行します GitHubの上のソースを表示 ダウンロードノート

セットアップ

 !pip install -q tf_nightly
import math
import tensorflow as tf
 

概要

あなたのデータは、多くの形で来ます。あなたのテンソルはあまりにもする必要があります。 ラグドテンソルは、ネストされた可変長リストのTensorFlowと同等です。彼らはそれが簡単に、不均一な形状を含むのプロセスデータを格納するために行います。

  • 可変長は、映画で俳優のセットとして備えています。
  • そのような文章やビデオクリップなどの可変長シーケンシャル入力のバッチ。
  • そのようなテキストのセクションに細分化された文書、段落、文、単語などの階層入力、。
  • そのようなプロトコルバッファとして構成され、入力の個々のフィールド、。

あなたはボロボロテンソルで何を行うことができます

不揃いテンソルは、(例えば、数学操作を含む、百以上TensorFlow操作でサポートされているtf.addtf.reduce_mean )、(例えば、配列操作tf.concattf.tileなど)、文字列操作のOPS( tf.substr )、制御フローなどの操作( tf.while_looptf.map_fn )、および多くの他:

 digits = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])
words = tf.ragged.constant([["So", "long"], ["thanks", "for", "all", "the", "fish"]])
print(tf.add(digits, 3))
print(tf.reduce_mean(digits, axis=1))
print(tf.concat([digits, [[5, 3]]], axis=0))
print(tf.tile(digits, [1, 2]))
print(tf.strings.substr(words, 0, 2))
print(tf.map_fn(tf.math.square, digits))
 
<tf.RaggedTensor [[6, 4, 7, 4], [], [8, 12, 5], [9], []]>
tf.Tensor([2.25              nan 5.33333333 6.                nan], shape=(5,), dtype=float64)
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9, 2], [6], [], [5, 3]]>
<tf.RaggedTensor [[3, 1, 4, 1, 3, 1, 4, 1], [], [5, 9, 2, 5, 9, 2], [6, 6], []]>
<tf.RaggedTensor [[b'So', b'lo'], [b'th', b'fo', b'al', b'th', b'fi']]>
<tf.RaggedTensor [[9, 1, 16, 1], [], [25, 81, 4], [36], []]>

ファクトリメソッド、変換方法、および値マッピング操作を含む不揃いテンソル、に特異的である方法及び動作の数もあります。サポートOPSの一覧については、 tf.raggedパッケージのドキュメントを

ラグドテンソルを含む多くのTensorFlowのAPIによってサポートされてKerasデータセットtf.functionSavedModels 、およびtf.Example 。詳細については、以下のTensorFlow APIに関するセクションを参照してください。

通常のテンソルと同じように、あなたはボロボロテンソルのアクセス特定のスライスにPythonのスタイルのインデックスを使用することができます。詳細については、以下のインデックス作成のセクションを参照してください。

 print(digits[0])       # First row
 
tf.Tensor([3 1 4 1], shape=(4,), dtype=int32)

 print(digits[:, :2])   # First two values in each row.
 
<tf.RaggedTensor [[3, 1], [], [5, 9], [6], []]>

 print(digits[:, -2:])  # Last two values in each row.
 
<tf.RaggedTensor [[4, 1], [], [9, 2], [6], []]>

そして、ちょうど通常のテンソルのように、あなたは、要素ごとの操作を実行するためにPythonの算術演算と比較演算子を使用することができます。詳細については、以下のオーバーロード演算子のセクションを参照してください。

 print(digits + 3)
 
<tf.RaggedTensor [[6, 4, 7, 4], [], [8, 12, 5], [9], []]>

 print(digits + tf.ragged.constant([[1, 2, 3, 4], [], [5, 6, 7], [8], []]))
 
<tf.RaggedTensor [[4, 3, 7, 5], [], [10, 15, 9], [14], []]>

あなたがの値に要素単位変換を実行する必要がある場合RaggedTensorは、使用することができますtf.ragged.map_flat_values機能に加えて1つ以上の引数を取り、変換する関数を適用され、 RaggedTensorの値を。

 times_two_plus_one = lambda x: x * 2 + 1
print(tf.ragged.map_flat_values(times_two_plus_one, digits))
 
<tf.RaggedTensor [[7, 3, 9, 3], [], [11, 19, 5], [13], []]>

ラグドテンソルは、ネストされたPythonのに変換することができlist Sとnumpyのarray S:

 digits.to_list()
 
[[3, 1, 4, 1], [], [5, 9, 2], [6], []]
 digits.numpy()
 
array([array([3, 1, 4, 1], dtype=int32), array([], dtype=int32),
       array([5, 9, 2], dtype=int32), array([6], dtype=int32),
       array([], dtype=int32)], dtype=object)

ぼろぼろのテンソルを構築

不揃いテンソルを構築する最も簡単な方法は、使用されるtf.ragged.constant構築、 RaggedTensor所定のネストのPythonに対応するlistまたはnumpyのarray

 sentences = tf.ragged.constant([
    ["Let's", "build", "some", "ragged", "tensors", "!"],
    ["We", "can", "use", "tf.ragged.constant", "."]])
print(sentences)
 
<tf.RaggedTensor [[b"Let's", b'build', b'some', b'ragged', b'tensors', b'!'], [b'We', b'can', b'use', b'tf.ragged.constant', b'.']]>

 paragraphs = tf.ragged.constant([
    [['I', 'have', 'a', 'cat'], ['His', 'name', 'is', 'Mat']],
    [['Do', 'you', 'want', 'to', 'come', 'visit'], ["I'm", 'free', 'tomorrow']],
])
print(paragraphs)
 
<tf.RaggedTensor [[[b'I', b'have', b'a', b'cat'], [b'His', b'name', b'is', b'Mat']], [[b'Do', b'you', b'want', b'to', b'come', b'visit'], [b"I'm", b'free', b'tomorrow']]]>

不揃いテンソルはまた、これらの値は以下のようなファクトリクラスメソッド使用して、列に分割されるべきかを示す行分割テンソルとフラット値テンソルをペアリングすることによって構築することができるtf.RaggedTensor.from_value_rowidstf.RaggedTensor.from_row_lengths 、及びtf.RaggedTensor.from_row_splits

tf.RaggedTensor.from_value_rowids

あなたはそれぞれの値がに属する行を知っている場合は、構築することができますRaggedTensor使用してvalue_rowids行分割テンソルを:

value_rowids

 print(tf.RaggedTensor.from_value_rowids(
    values=[3, 1, 4, 1, 5, 9, 2],
    value_rowids=[0, 0, 0, 0, 2, 2, 3]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

tf.RaggedTensor.from_row_lengths

あなたは、各行がどのくらい知っている場合は、使用することができますrow_lengths行分割テンソルを:

row_lengths

 print(tf.RaggedTensor.from_row_lengths(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_lengths=[4, 0, 2, 1]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

tf.RaggedTensor.from_row_splits

あなたは、各行の開始と終了インデックスを知っている場合は、使用することができますrow_splits行分割テンソルを:

row_splits

 print(tf.RaggedTensor.from_row_splits(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_splits=[0, 4, 4, 6, 7]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

参照してくださいtf.RaggedTensorファクトリメソッドの完全なリストについては、クラスのドキュメントを。

あなたはボロボロテンソルに何を保存することができます

通常と同様Tensor S、の値RaggedTensorすべて同じ型でなければなりません。そして、値はすべて同じネストの深さ(テンソルのランク )である必要があります。

 print(tf.ragged.constant([["Hi"], ["How", "are", "you"]]))  # ok: type=string, rank=2
 
<tf.RaggedTensor [[b'Hi'], [b'How', b'are', b'you']]>

 print(tf.ragged.constant([[[1, 2], [3]], [[4, 5]]]))        # ok: type=int32, rank=3
 
<tf.RaggedTensor [[[1, 2], [3]], [[4, 5]]]>

 try:
  tf.ragged.constant([["one", "two"], [3, 4]])              # bad: multiple types
except ValueError as exception:
  print(exception)
 
Can't convert Python sequence with mixed types to Tensor.

 try:
  tf.ragged.constant(["A", ["B", "C"]])                     # bad: multiple nesting depths
except ValueError as exception:
  print(exception)
 
all scalar values must have the same nesting depth

例のユースケース

次の例では、方法を示しRaggedTensor sは、各センテンスの開始と終了のための特別なマーカーを使用して、構築し、可変長クエリのバッチのためにユニグラムとバイグラム埋め込みを組み合わせるために使用することができます。この例で使用されるオペレーションの詳細については、を参照tf.raggedパッケージのドキュメントを。

 queries = tf.ragged.constant([['Who', 'is', 'Dan', 'Smith'],
                              ['Pause'],
                              ['Will', 'it', 'rain', 'later', 'today']])

# Create an embedding table.
num_buckets = 1024
embedding_size = 4
embedding_table = tf.Variable(
    tf.random.truncated_normal([num_buckets, embedding_size],
                       stddev=1.0 / math.sqrt(embedding_size)))

# Look up the embedding for each word.
word_buckets = tf.strings.to_hash_bucket_fast(queries, num_buckets)
word_embeddings = 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.strings.join([padded[:, :-1], padded[:, 1:]], separator='+')   # ③

bigram_buckets = tf.strings.to_hash_bucket_fast(bigrams, num_buckets)
bigram_embeddings = 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(avg_embedding)
 
tf.Tensor(
[[-0.06177589  0.28342518 -0.11636773  0.16240317]
 [-0.058149    0.18231267 -0.08166277  0.39316788]
 [ 0.07948986 -0.1654076  -0.02149549 -0.17634445]], shape=(3, 4), dtype=float32)

ragged_example

ラグドと均一な寸法

不揃いの寸法は、そのスライス異なる長さを有することができる寸法です。例えば、内側(コラム)の寸法rt=[[3, 1, 4, 1], [], [5, 9, 2], [6], []]カラムスライス(以降、不揃いれるrt[0, :] 、...、 rt[4, :] )は、異なる長さを有します。そのスライスすべて同じ長さを持っている寸法は、 均一な寸法と呼ばれています。

それは単一のスライスで構成さ(及びしたがってスライスの長さが異なるために可能性がない)ので、不揃いテンソルの最も外側の寸法は、常に均一です。残りの寸法は、いずれかの不規則または均一であってもよいです。例えば、我々は、形状の不揃いテンソル用いて文章のバッチ中の各単語の単語の埋め込みを格納するかもしれない[num_sentences, (num_words), embedding_size]周りの括弧、 (num_words)寸法が不揃いであることを示しています。

sent_word_embed

ラグドテンソルは、複数の不揃い寸法を有することができます。例えば、我々は、形状のテンソルを用いて構造化テキスト文書のバッチを格納することができる[num_documents, (num_paragraphs), (num_sentences), (num_words)] (再び括弧は不揃いな寸法を示すために使用されます)。

同様tf.Tensor 、不規則テンソルの階数は、(両方の不揃い及び均一な寸法を含む)の寸法のその総数です。 潜在的にぼろぼろテンソルは、どちらかであるかもしれない値であるtf.Tensortf.RaggedTensor

RaggedTensorの形状を説明するとき、不揃いな寸法は、従来括弧で囲んで示されています。例えば、上で見たように、文章のバッチ中の各単語の格納ワード埋め込みは以下のように書くことができることを3-D RaggedTensorの形状[num_sentences, (num_words), embedding_size]

RaggedTensor.shape属性が返されますtf.TensorShapeぼろ寸法はサイズがない不揃いテンソル、用None

 tf.ragged.constant([["Hi"], ["How", "are", "you"]]).shape
 
TensorShape([2, None])

この方法tf.RaggedTensor.bounding_shape与えられたためにタイトなバウンディング形状見つけるために使用することができRaggedTensor

 print(tf.ragged.constant([["Hi"], ["How", "are", "you"]]).bounding_shape())
 
tf.Tensor([2 3], shape=(2,), dtype=int64)

ラグド対スパース

ボロボロテンソルは、まばらなテンソルの種類として考えるべきでありません 。特に、疎テンソルはtf.Tensor、そのモデルコンパクトなフォーマットでのデータのための効率的な符号化です。しかし不揃いテンソルは、データのモデルその拡大クラスtf.Tensorに拡張ものです。操作を定義するときにこの違いは重要です:

  • スパースまたは密テンソルにオペアンプを適用すると、常に同じ結果を与える必要があります。
  • ギザギザまたはスパーステンソルにオペアンプを適用すると、異なる結果を与える可能性があります。

例示的な一例として、のような配列操作方法を検討concatstack 、およびtile不揃い対疎テンソルのために定義されています。不揃いテンソルを連結して組み合わせた長さを有する単一の列を形成するように各行を結合します。

ragged_concat

 ragged_x = tf.ragged.constant([["John"], ["a", "big", "dog"], ["my", "cat"]])
ragged_y = tf.ragged.constant([["fell", "asleep"], ["barked"], ["is", "fuzzy"]])
print(tf.concat([ragged_x, ragged_y], axis=1))
 
<tf.RaggedTensor [[b'John', b'fell', b'asleep'], [b'a', b'big', b'dog', b'barked'], [b'my', b'cat', b'is', b'fuzzy']]>

しかし、疎なテンソルを連結する(oが欠損値を示す)以下の例で示すように、対応する密なテンソルを連結と等価です。

sparse_concat

 sparse_x = ragged_x.to_sparse()
sparse_y = ragged_y.to_sparse()
sparse_result = tf.sparse.concat(sp_inputs=[sparse_x, sparse_y], axis=1)
print(tf.sparse.to_dense(sparse_result, ''))
 
tf.Tensor(
[[b'John' b'' b'' b'fell' b'asleep']
 [b'a' b'big' b'dog' b'barked' b'']
 [b'my' b'cat' b'' b'is' b'fuzzy']], shape=(3, 5), dtype=string)

この区別は重要である理由の別の例では、のようなOPは、「各列の平均値」の定義を考えるtf.reduce_mean 。不揃いテンソルのために、行の平均値は、行の幅で割った行の値の合計です。しかし、疎テンソルのために、行の平均値は、(以上、最長の行の幅に等しい)疎テンソルの全幅で割った行の値の合計です。

TensorFlowのAPI

Keras

tf.kerasは深い学習モデルを構築し、訓練のためのTensorFlowの高レベルAPIです。不揃いテンソルは、設定によってKerasモデルへの入力として渡すことがragged=Truetf.keras.Input又はtf.keras.layers.InputLayer 。ラグドテンソルもKeras層の間に渡され、Kerasモデルによって返されることがあります。次の例では、ボロボロテンソルを使用して訓練されたおもちゃのLSTMのモデルを示しています。

 # Task: predict whether each sentence is a question or not.
sentences = tf.constant(
    ['What makes you think she is a witch?',
     'She turned me into a newt.',
     'A newt?',
     'Well, I got better.'])
is_question = tf.constant([True, False, True, False])

# Preprocess the input strings.
hash_buckets = 1000
words = tf.strings.split(sentences, ' ')
hashed_words = tf.strings.to_hash_bucket_fast(words, hash_buckets)

# Build the Keras model.
keras_model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=[None], dtype=tf.int64, ragged=True),
    tf.keras.layers.Embedding(hash_buckets, 16),
    tf.keras.layers.LSTM(32, use_bias=False),
    tf.keras.layers.Dense(32),
    tf.keras.layers.Activation(tf.nn.relu),
    tf.keras.layers.Dense(1)
])

keras_model.compile(loss='binary_crossentropy', optimizer='rmsprop')
keras_model.fit(hashed_words, is_question, epochs=5)
print(keras_model.predict(hashed_words))
 
WARNING:tensorflow:Layer lstm will not use cuDNN kernel since it doesn't meet the cuDNN kernel criteria. It will use generic GPU kernel as fallback when running on GPU
Epoch 1/5

/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/framework/indexed_slices.py:433: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.
  "Converting sparse IndexedSlices to a dense Tensor of unknown shape. "

1/1 [==============================] - 2s 2s/step - loss: 7.7126
Epoch 2/5
1/1 [==============================] - 0s 14ms/step - loss: 7.7125
Epoch 3/5
1/1 [==============================] - 0s 16ms/step - loss: 7.7125
Epoch 4/5
1/1 [==============================] - 0s 15ms/step - loss: 7.7125
Epoch 5/5
1/1 [==============================] - 0s 15ms/step - loss: 7.7125
[[-0.01186859]
 [-0.01535043]
 [-0.01233396]
 [-0.0137249 ]]

tf.Example

tf.Exampleは標準でいるProtobufの TensorFlowデータのエンコード。データがでエンコードtf.Exampleしばしば可変長の機能が含まれてい秒。たとえば、次のコードは、4つのバッチ定義tf.Example異なる特徴の長さのメッセージを:

 import google.protobuf.text_format as pbtext

def build_tf_example(s):
  return pbtext.Merge(s, tf.train.Example()).SerializeToString()

example_batch = [
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["red", "blue"]} } }
      feature {key: "lengths" value {int64_list {value: [7]} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["orange"]} } }
      feature {key: "lengths" value {int64_list {value: []} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["black", "yellow"]} } }
      feature {key: "lengths" value {int64_list {value: [1, 3]} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["green"]} } }
      feature {key: "lengths" value {int64_list {value: [3, 5, 2]} } } }''')]
 

私たちは、使用して、この符号化されたデータを解析することができtf.io.parse_exampleシリアライズされた文字列のテンソルと機能仕様辞書を取り、テンソルに辞書マッピング機能の名前を返します。ぼろぼろのテンソルに可変長の機能を読み取るには、我々は単に使用tf.io.RaggedFeature機能仕様辞書に:

 feature_specification = {
    'colors': tf.io.RaggedFeature(tf.string),
    'lengths': tf.io.RaggedFeature(tf.int64),
}
feature_tensors = tf.io.parse_example(example_batch, feature_specification)
for name, value in feature_tensors.items():
  print("{}={}".format(name, value))
 
colors=<tf.RaggedTensor [[b'red', b'blue'], [b'orange'], [b'black', b'yellow'], [b'green']]>
lengths=<tf.RaggedTensor [[7], [], [1, 3], [3, 5, 2]]>

tf.io.RaggedFeatureまた、複数の不揃い寸法の機能を読み取るために使用することができます。詳細については、 APIドキュメントを

データセット

tf.dataはあなたが単純なものから複雑な入力パイプライン、再利用可能な部分を構築することができますAPIです。そのコアデータ構造であるtf.data.Dataset各要素は、1つのまたは複数のコンポーネントから構成されている要素のシーケンスを表します。

 # Helper function used to print datasets in the examples below.
def print_dictionary_dataset(dataset):
  for i, element in enumerate(dataset):
    print("Element {}:".format(i))
    for (feature_name, feature_value) in element.items():
      print('{:>14} = {}'.format(feature_name, feature_value))
 

ぼろぼろのテンソルとデータセットの構築

データセットからそれらを構築するために使用されるのと同じ方法を使用して不規則なテンソルから構築することができるtf.Tensor Sまたはnumpyのarrayなどの、 Dataset.from_tensor_slices

 dataset = tf.data.Dataset.from_tensor_slices(feature_tensors)
print_dictionary_dataset(dataset)
 
Element 0:
        colors = [b'red' b'blue']
       lengths = [7]
Element 1:
        colors = [b'orange']
       lengths = []
Element 2:
        colors = [b'black' b'yellow']
       lengths = [1 3]
Element 3:
        colors = [b'green']
       lengths = [3 5 2]

ぼろぼろのテンソルとバッチ処理とunbatchingデータセット

不揃いテンソルを持つデータセットをバッチ処理することができる(これは、単一の要素にコンバインn個の連続する要素)を用いDataset.batch方法。

 batched_dataset = dataset.batch(2)
print_dictionary_dataset(batched_dataset)
 
Element 0:
        colors = <tf.RaggedTensor [[b'red', b'blue'], [b'orange']]>
       lengths = <tf.RaggedTensor [[7], []]>
Element 1:
        colors = <tf.RaggedTensor [[b'black', b'yellow'], [b'green']]>
       lengths = <tf.RaggedTensor [[1, 3], [3, 5, 2]]>

逆に、バッチデータセットを使用してフラットデータセットに変換することができるDataset.unbatch

 unbatched_dataset = batched_dataset.unbatch()
print_dictionary_dataset(unbatched_dataset)
 
Element 0:
        colors = [b'red' b'blue']
       lengths = [7]
Element 1:
        colors = [b'orange']
       lengths = []
Element 2:
        colors = [b'black' b'yellow']
       lengths = [1 3]
Element 3:
        colors = [b'green']
       lengths = [3 5 2]

可変長非不揃いテンソルとバッチ処理データセット

あなたは非ぼろぼろテンソルが含まれているデータセットを持っており、テンソル長さは、要素間で異なる場合は、することができます一括適用することにより、ギザギザのテンソルにそれらの非ぼろぼろテンソルdense_to_ragged_batch変換を:

 non_ragged_dataset = tf.data.Dataset.from_tensor_slices([1, 5, 3, 2, 8])
non_ragged_dataset = non_ragged_dataset.map(tf.range)
batched_non_ragged_dataset = non_ragged_dataset.apply(
    tf.data.experimental.dense_to_ragged_batch(2))
for element in batched_non_ragged_dataset:
  print(element)
 
<tf.RaggedTensor [[0], [0, 1, 2, 3, 4]]>
<tf.RaggedTensor [[0, 1, 2], [0, 1]]>
<tf.RaggedTensor [[0, 1, 2, 3, 4, 5, 6, 7]]>

ぼろぼろのテンソルとデータセットの変換

データセット内ラグドテンソルも作成または使用して変換することができますDataset.map

 def transform_lengths(features):
  return {
      'mean_length': tf.math.reduce_mean(features['lengths']),
      'length_ranges': tf.ragged.range(features['lengths'])}
transformed_dataset = dataset.map(transform_lengths)
print_dictionary_dataset(transformed_dataset)
 
Element 0:
   mean_length = 7
 length_ranges = <tf.RaggedTensor [[0, 1, 2, 3, 4, 5, 6]]>
Element 1:
   mean_length = 0
 length_ranges = <tf.RaggedTensor []>
Element 2:
   mean_length = 2
 length_ranges = <tf.RaggedTensor [[0], [0, 1, 2]]>
Element 3:
   mean_length = 3
 length_ranges = <tf.RaggedTensor [[0, 1, 2], [0, 1, 2, 3, 4], [0, 1]]>

tf.function

tf.functionは、事前計算Pythonの機能のためのTensorFlowグラフ、実質上ごTensorFlowコードのパフォーマンスを向上させることができることデコレータです。ラグドテンソルはと透過的に使用することができます@tf.function -decorated機能。たとえば、以下の機能がボロボロと非不揃いの両方テンソルで動作します:

 @tf.function
def make_palindrome(x, axis):
  return tf.concat([x, tf.reverse(x, [axis])], axis)
 
 make_palindrome(tf.constant([[1, 2], [3, 4], [5, 6]]), axis=1)
 
<tf.Tensor: shape=(3, 4), dtype=int32, numpy=
array([[1, 2, 2, 1],
       [3, 4, 4, 3],
       [5, 6, 6, 5]], dtype=int32)>
 make_palindrome(tf.ragged.constant([[1, 2], [3], [4, 5, 6]]), axis=1)
 
<tf.RaggedTensor [[1, 2, 2, 1], [3, 3], [4, 5, 6, 6, 5, 4]]>

あなたが明示的に指定したい場合はinput_signatureためtf.function 、あなたが使用して行うことができtf.RaggedTensorSpec

 @tf.function(
    input_signature=[tf.RaggedTensorSpec(shape=[None, None], dtype=tf.int32)])
def max_and_min(rt):
  return (tf.math.reduce_max(rt, axis=-1), tf.math.reduce_min(rt, axis=-1))

max_and_min(tf.ragged.constant([[1, 2], [3], [4, 5, 6]]))
 
(<tf.Tensor: shape=(3,), dtype=int32, numpy=array([2, 3, 6], dtype=int32)>,
 <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 3, 4], dtype=int32)>)

コンクリートの機能

具体的な機能は、によって構築されている個々のトレースされたグラフカプセル化tf.function 。 TensorFlow 2.3(とで始まるtf-nightly )、不揃いテンソルは、具体的な機能と透過的に使用することができます。

 # Preferred way to use ragged tensors with concrete functions (TF 2.3+):
try:
  @tf.function
  def increment(x):
    return x + 1

  rt = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
  cf = increment.get_concrete_function(rt)
  print(cf(rt))
except Exception as e:
  print(f"Not supported before TF 2.3: {type(e)}: {e}")
 
<tf.RaggedTensor [[2, 3], [4], [5, 6, 7]]>

あなたはTensorFlow 2.3に先立って、具体的な機能をぼろぼろテンソルを使用する必要がある場合、我々は彼らの部品(にギザギザテンソル分解をお勧めしますvaluesrow_splits )、および個別の引数として渡します。

 # Backwards-compatible way to use ragged tensors with concrete functions:
@tf.function
def decomposed_ragged_increment(x_values, x_splits):
  x = tf.RaggedTensor.from_row_splits(x_values, x_splits)
  return x + 1

rt = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
cf = decomposed_ragged_increment.get_concrete_function(rt.values, rt.row_splits)
print(cf(rt.values, rt.row_splits))
 
<tf.RaggedTensor [[2, 3], [4], [5, 6, 7]]>

SavedModels

A SavedModelは重みおよび計算の両方を含むシリアライズTensorFlowプログラム、です。それはKerasモデルからまたはカスタムモデルから構築することができます。いずれの場合においても、ギザギザテンソルはSavedModelによって定義された機能および方法と透過的に使用することができます。

例:Kerasモデルを保存します

 import tempfile

keras_module_path = tempfile.mkdtemp()
tf.saved_model.save(keras_model, keras_module_path)
imported_model = tf.saved_model.load(keras_module_path)
imported_model(hashed_words)
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: /tmp/tmp62sp6hi4/assets

<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[-0.01186859],
       [-0.01535043],
       [-0.01233396],
       [-0.0137249 ]], dtype=float32)>

例:カスタムモデルを保存します

 class CustomModule(tf.Module):
  def __init__(self, variable_value):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(variable_value)

  @tf.function
  def grow(self, x):
    return x * self.v

module = CustomModule(100.0)

# Before saving a custom model, we must ensure that concrete functions are
# built for each input signature that we will need.
module.grow.get_concrete_function(tf.RaggedTensorSpec(shape=[None, None],
                                                      dtype=tf.float32))

custom_module_path = tempfile.mkdtemp()
tf.saved_model.save(module, custom_module_path)
imported_model = tf.saved_model.load(custom_module_path)
imported_model.grow(tf.ragged.constant([[1.0, 4.0, 3.0], [2.0]]))
 
INFO:tensorflow:Assets written to: /tmp/tmpefz3830s/assets

<tf.RaggedTensor [[100.0, 400.0, 300.0], [200.0]]>

オーバーロード演算子

RaggedTensorクラスは、基本的な要素ごとの演算を実行するために簡単にそれを作る、Pythonの標準算術演算と比較演算子をオーバーロード:

 x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
y = tf.ragged.constant([[1, 1], [2], [3, 3, 3]])
print(x + y)
 
<tf.RaggedTensor [[2, 3], [5], [7, 8, 9]]>

オーバーロードされた演算子が要素単位計算を実行するので、すべてのバイナリ操作への入力は、同じ形状を有し、又は同一の形状にbroadcastableなければなりません。最も単純な放送の場合に、単一のスカラーは不揃いテンソルの各値と結合要素単位です。

 x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
print(x + 3)
 
<tf.RaggedTensor [[4, 5], [6], [7, 8, 9]]>

より高度な例については、 放送のセクションを参照してください。

ラグドテンソルは通常通りの演算子の同じセットオーバーロードTensor秒:単項演算子-~およびabs() ;そして、バイナリ演算子+- *///%**&|^==<<= > 、および>=

インデキシング

ラグドテンソルは、多次元インデックスとスライスを含め、Pythonのスタイルのインデックス作成をサポートしています。以下の実施例は、2-D及び3-Dとのでこぼこテンソルインデクシングはテンソルを不揃い実証します。

例のインデックス作成:2Dはテンソルをラグド

 queries = tf.ragged.constant(
    [['Who', 'is', 'George', 'Washington'],
     ['What', 'is', 'the', 'weather', 'tomorrow'],
     ['Goodnight']])
 
 print(queries[1])                   # A single query
 
tf.Tensor([b'What' b'is' b'the' b'weather' b'tomorrow'], shape=(5,), dtype=string)

 print(queries[1, 2])                # A single word
 
tf.Tensor(b'the', shape=(), dtype=string)

 print(queries[1:])                  # Everything but the first row
 
<tf.RaggedTensor [[b'What', b'is', b'the', b'weather', b'tomorrow'], [b'Goodnight']]>

 print(queries[:, :3])               # The first 3 words of each query
 
<tf.RaggedTensor [[b'Who', b'is', b'George'], [b'What', b'is', b'the'], [b'Goodnight']]>

 print(queries[:, -2:])              # The last 2 words of each query
 
<tf.RaggedTensor [[b'George', b'Washington'], [b'weather', b'tomorrow'], [b'Goodnight']]>

インデックス例3Dは、テンソルをラグド

 rt = tf.ragged.constant([[[1, 2, 3], [4]],
                         [[5], [], [6]],
                         [[7]],
                         [[8, 9], [10]]])
 
 print(rt[1])                        # Second row (2-D RaggedTensor)
 
<tf.RaggedTensor [[5], [], [6]]>

 print(rt[3, 0])                     # First element of fourth row (1-D Tensor)
 
tf.Tensor([8 9], shape=(2,), dtype=int32)

 print(rt[:, 1:3])                   # Items 1-3 of each row (3-D RaggedTensor)
 
<tf.RaggedTensor [[[4]], [[], [6]], [], [[10]]]>

 print(rt[:, -1:])                   # Last item of each row (3-D RaggedTensor)
 
<tf.RaggedTensor [[[4]], [[6]], [[7]], [[10]]]>

RaggedTensorのサポート多次元インデックス付けとスライス、1制限付き:不揃いの次元へのインデックスが許可されていません。指示値は、いくつかの行ではなく、他に存在する可能性があるため、この場合には問題があります。このような場合には、それは我々が(1)調達する必要があるかどうかは明らかではありませんIndexError 。 (2)デフォルト値を使用します。または(3)は、その値をスキップして使い始めたよりも少ない行でテンソルを返します。以下のパイソンの指導原則 (「曖昧さの顔には、推測する誘惑を拒否」)、我々は現在、この操作を禁止します。

テンソルの型変換

RaggedTensor間で変換するために使用できるクラス定義の方法RaggedTensor S及びtf.Tensor Sまたはtf.SparseTensors

 ragged_sentences = tf.ragged.constant([
    ['Hi'], ['Welcome', 'to', 'the', 'fair'], ['Have', 'fun']])
 
 # RaggedTensor -> Tensor
print(ragged_sentences.to_tensor(default_value='', shape=[None, 10]))
 
tf.Tensor(
[[b'Hi' b'' b'' b'' b'' b'' b'' b'' b'' b'']
 [b'Welcome' b'to' b'the' b'fair' b'' b'' b'' b'' b'' b'']
 [b'Have' b'fun' b'' b'' b'' b'' b'' b'' b'' b'']], shape=(3, 10), dtype=string)

 # Tensor -> RaggedTensor
x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]
print(tf.RaggedTensor.from_tensor(x, padding=-1))
 
<tf.RaggedTensor [[1, 3], [2], [4, 5, 8, 9]]>

 #RaggedTensor -> SparseTensor
print(ragged_sentences.to_sparse())
 
SparseTensor(indices=tf.Tensor(
[[0 0]
 [1 0]
 [1 1]
 [1 2]
 [1 3]
 [2 0]
 [2 1]], shape=(7, 2), dtype=int64), values=tf.Tensor([b'Hi' b'Welcome' b'to' b'the' b'fair' b'Have' b'fun'], shape=(7,), dtype=string), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))

 # SparseTensor -> RaggedTensor
st = tf.SparseTensor(indices=[[0, 0], [2, 0], [2, 1]],
                     values=['a', 'b', 'c'],
                     dense_shape=[3, 3])
print(tf.RaggedTensor.from_sparse(st))
 
<tf.RaggedTensor [[b'a'], [], [b'b', b'c']]>

ぼろぼろのテンソルの評価

ぼろぼろテンソルの値にアクセスするには、次のことができます。

  1. 使用tf.RaggedTensor.to_list()ネストされたPythonのリストに不揃いテンソルを変換します。
  2. 使用tf.RaggedTensor.numpy()その値がネストされたnumpyの配列でnumpyのアレイに不揃いテンソルを変換します。
  3. 使用して、その成分に不揃いテンソルを分解tf.RaggedTensor.valuestf.RaggedTensor.row_splits特性を、または行paritioningような方法tf.RaggedTensor.row_lengths()tf.RaggedTensor.value_rowids()
  4. 使用Pythonはボロボロテンソルから値を選択するためにインデックスを付けます。
 rt = tf.ragged.constant([[1, 2], [3, 4, 5], [6], [], [7]])
print("python list:", rt.to_list())
print("numpy array:", rt.numpy())
print("values:", rt.values.numpy())
print("splits:", rt.row_splits.numpy())
print("indexed value:", rt[1].numpy())
 
python list: [[1, 2], [3, 4, 5], [6], [], [7]]
numpy array: [array([1, 2], dtype=int32) array([3, 4, 5], dtype=int32)
 array([6], dtype=int32) array([], dtype=int32) array([7], dtype=int32)]
values: [1 2 3 4 5 6 7]
splits: [0 2 5 6 6 7]
indexed value: [3 4 5]

放送

放送は異なる形状を有するテンソルを製造する方法は、要素ごとの操作のために互換性のある形状を有することです。放送の詳細な背景については、以下を参照してください。

二つの入力の放送のための基本的な手順xy互換性のある形状を有することです。

  1. 場合xy寸法の同じ番号を持っていない彼らが行うまで、(サイズ1)外形寸法を追加します。

  2. 各次元のxy異なるサイズを有します。

    • 場合xまたはy大き有する1次元でdは、寸法を横切ってその値を繰り返しd他の入力の大きさに合うように。

    • そうでない場合、(例外が発生しxおよびy互換性が放送されていません)。

均一な寸法でテンソルのサイズは、単一の数(その次元を横切るスライスのサイズ)です。そして不揃い寸法でテンソルの大きさ(つまり寸法を横切る全てのスライスのための)スライスの長さのリストです。

例の番組

 # x       (2D ragged):  2 x (num_rows)
# y       (scalar)
# result  (2D ragged):  2 x (num_rows)
x = tf.ragged.constant([[1, 2], [3]])
y = 3
print(x + y)
 
<tf.RaggedTensor [[4, 5], [6]]>

 # x         (2d ragged):  3 x (num_rows)
# y         (2d tensor):  3 x          1
# Result    (2d ragged):  3 x (num_rows)
x = tf.ragged.constant(
   [[10, 87, 12],
    [19, 53],
    [12, 32]])
y = [[1000], [2000], [3000]]
print(x + y)
 
<tf.RaggedTensor [[1010, 1087, 1012], [2019, 2053], [3012, 3032]]>

 # x      (3d ragged):  2 x (r1) x 2
# y      (2d ragged):         1 x 1
# Result (3d ragged):  2 x (r1) x 2
x = tf.ragged.constant(
    [[[1, 2], [3, 4], [5, 6]],
     [[7, 8]]],
    ragged_rank=1)
y = tf.constant([[10]])
print(x + y)
 
<tf.RaggedTensor [[[11, 12], [13, 14], [15, 16]], [[17, 18]]]>

 # x      (3d ragged):  2 x (r1) x (r2) x 1
# y      (1d tensor):                    3
# Result (3d ragged):  2 x (r1) x (r2) x 3
x = tf.ragged.constant(
    [
        [
            [[1], [2]],
            [],
            [[3]],
            [[4]],
        ],
        [
            [[5], [6]],
            [[7]]
        ]
    ],
    ragged_rank=2)
y = tf.constant([10, 20, 30])
print(x + y)
 
<tf.RaggedTensor [[[[11, 21, 31], [12, 22, 32]], [], [[13, 23, 33]], [[14, 24, 34]]], [[[15, 25, 35], [16, 26, 36]], [[17, 27, 37]]]]>

ここではブロードキャストしない形状のいくつかの例は以下のとおりです。

 # x      (2d ragged): 3 x (r1)
# y      (2d tensor): 3 x    4  # trailing dimensions do not match
x = tf.ragged.constant([[1, 2], [3, 4, 5, 6], [7]])
y = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
1
b'lengths='
4
b'dim_size='
2, 4, 1

 # x      (2d ragged): 3 x (r1)
# y      (2d ragged): 3 x (r2)  # ragged dimensions do not match.
x = tf.ragged.constant([[1, 2, 3], [4], [5, 6]])
y = tf.ragged.constant([[10, 20], [30, 40], [50]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
1
b'lengths='
2, 2, 1
b'dim_size='
3, 1, 2

 # x      (3d ragged): 3 x (r1) x 2
# y      (3d ragged): 3 x (r1) x 3  # trailing dimensions do not match
x = tf.ragged.constant([[[1, 2], [3, 4], [5, 6]],
                        [[7, 8], [9, 10]]])
y = tf.ragged.constant([[[1, 2, 0], [3, 4, 0], [5, 6, 0]],
                        [[7, 8, 0], [9, 10, 0]]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
2
b'lengths='
3, 3, 3, 3, 3
b'dim_size='
2, 2, 2, 2, 2

RaggedTensorエンコーディング

ラグドテンソルを使用してエンコードされRaggedTensorクラスを。内部的には、各RaggedTensorで構成されています。

  • values扁平リストに可変長列を連結テンソル、。
  • row_partitionこれらの平坦化の値が列に分割されているかを示します。

ragged_encoding_2

row_partition 4つの異なるエンコーディングを使用して保存することができます。

  • row_splits列間の分割点を指定する整数のベクトルです。
  • value_rowids各値の行インデックスを指定する整数のベクトルです。
  • row_lengths各行の長さを指定する整数のベクトルです。
  • uniform_row_lengthすべての行の単一の長さを指定する整数のスカラーです。

partition_encodings

整数スカラーnrowsまた、中に含めることができるrow_partition持つ空の末尾行を考慮するために、符号化value_rowids有する、または空行uniform_row_length

 rt = tf.RaggedTensor.from_row_splits(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_splits=[0, 4, 4, 6, 7])
print(rt)
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

横分割に使用するエンコーディングの選択は、いくつかの状況では、効率を向上させるために、ギザギザテンソルによって内部的に管理されます。具体的には、異なる行分割方式の利点と欠点のいくつかは以下のとおりです。

  • 効率的な索引付けrow_splitsエンコーディングが不揃いテンソルに一定の時間インデックスとスライシングを可能にします。

  • 効率的連結row_lengths不揃いテンソルを連結するときに、2つのテンソルが一緒に連結されている場合、行の長さが変化しないので、コードは、より効率的です。

  • 小さな符号化サイズvalue_rowidsテンソルのサイズは、値のみの合計数に依存するため、空の行の数が多い不規則なテンソルを記憶するときにコードがより効率的です。一方、 row_splitsrow_lengths長い行の不揃いテンソルを記憶するときに行ごとに一つだけのスカラー値を必要とするのでエンコーディングは、より効率的です。

  • 互換性value_rowidsスキームが一致するセグメント化などの操作で使用される形式tf.segment_sumrow_limitsスキームは、以下のようなOPSで使用される形式と一致tf.sequence_mask

  • 均一な寸法 :ASは、以下に説明uniform_row_length符号を符号化するために使用され、均一な寸法でテンソルを不揃い。

複数のギザギザ寸法

複数の不揃い寸法の不揃いテンソルは、ネストされた使用してエンコードされRaggedTensorするためのvaluesテンソル。各ネストされたRaggedTensor 、単一の不揃いの次元を追加します。

ragged_rank_2

 rt = tf.RaggedTensor.from_row_splits(
    values=tf.RaggedTensor.from_row_splits(
        values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
        row_splits=[0, 3, 3, 5, 9, 10]),
    row_splits=[0, 1, 1, 5])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
 
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>
Shape: (3, None, None)
Number of partitioned dimensions: 2

工場機能tf.RaggedTensor.from_nested_row_splitsのリストを提供することによって、直接複数の不揃い寸法RaggedTensorを構築するために使用されてもよいrow_splitsテンソルを:

 rt = tf.RaggedTensor.from_nested_row_splits(
    flat_values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
    nested_row_splits=([0, 1, 1, 5], [0, 3, 3, 5, 9, 10]))
print(rt)
 
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>

ラグドランクとフラットな値

ぼろぼろのテンソルのギザギザのランクが根底にあることを回数であるvaluesテンソルは、分割された(すなわち、のネストの深さRaggedTensorオブジェクト)。最も内側のvaluesそのflat_valuesとして知られているテンソル。次の例では、 conversations ragged_rank = 3を有し、そのflat_values 1DでTensor 24列を有します。

 # shape = [batch, (paragraph), (sentence), (word)]
conversations = tf.ragged.constant(
    [[[["I", "like", "ragged", "tensors."]],
      [["Oh", "yeah?"], ["What", "can", "you", "use", "them", "for?"]],
      [["Processing", "variable", "length", "data!"]]],
     [[["I", "like", "cheese."], ["Do", "you?"]],
      [["Yes."], ["I", "do."]]]])
conversations.shape
 
TensorShape([2, None, None, None])
 assert conversations.ragged_rank == len(conversations.nested_row_splits)
conversations.ragged_rank  # Number of partitioned dimensions.
 
3
 conversations.flat_values.numpy()
 
array([b'I', b'like', b'ragged', b'tensors.', b'Oh', b'yeah?', b'What',
       b'can', b'you', b'use', b'them', b'for?', b'Processing',
       b'variable', b'length', b'data!', b'I', b'like', b'cheese.', b'Do',
       b'you?', b'Yes.', b'I', b'do.'], dtype=object)

制服内寸

均一な内側寸法を有するギザギザテンソルは、多次元用いて符号化されるtf.Tensor flat_values(すなわち、最も内側のためのvalues )。

uniform_inner

 rt = tf.RaggedTensor.from_row_splits(
    values=[[1, 3], [0, 0], [1, 3], [5, 3], [3, 3], [1, 2]],
    row_splits=[0, 3, 4, 6])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
print("Flat values shape: {}".format(rt.flat_values.shape))
print("Flat values:\n{}".format(rt.flat_values))
 
<tf.RaggedTensor [[[1, 3], [0, 0], [1, 3]], [[5, 3]], [[3, 3], [1, 2]]]>
Shape: (3, None, 2)
Number of partitioned dimensions: 1
Flat values shape: (6, 2)
Flat values:
[[1 3]
 [0 0]
 [1 3]
 [5 3]
 [3 3]
 [1 2]]

制服非内寸

均一な非内側寸法を有する不規則テンソルを用いて行を分割して符号化されるuniform_row_length

uniform_outer

 rt = tf.RaggedTensor.from_uniform_row_length(
    values=tf.RaggedTensor.from_row_splits(
        values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
        row_splits=[0, 3, 5, 9, 10]),
    uniform_row_length=2)
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
 
<tf.RaggedTensor [[[10, 11, 12], [13, 14]], [[15, 16, 17, 18], [19]]]>
Shape: (2, 2, None)
Number of partitioned dimensions: 2