TensorFlow Text – Tensorflow でテキスト処理 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/12/2019
* 本ページは、github レポジトリ tensorflow/text の TensorFlow Text – Text processing in Tensorflow (README.md) を翻訳した上で適宜、補足説明したものです:
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
TensorFlow Text – Tensorflow でテキスト処理
イントロダクション
TensorFlow Text は TensorFlow 2.0 ですぐに使えるテキスト関連クラスと ops のコレクションを提供します。
ライブラリはテキストベースのモデルで通常必要とされる前処理を遂行できて、コア TensorFlow では提供されない、シークエンスモデル化のために有用な他の特徴を含みます。
貴方のテキスト処理でこれらの ops を使用するメリットはそれらが TensorFlow グラフ内で行われることです。推論時のトークン化とは異なる訓練におけるトークン化や前処理スクリプトを管理することについて貴方は心配する必要はありません。
Eager Execution
TensorFlow Text は TensorFlow eager モードとグラフモードの両者と互換です。
import tensorflow as tf import tensorflow_text as text tf.enable_eager_execution()
Unicode
殆どの ops は文字列が UTF-8 であることを想定しています。異なるエンコーディングを使用している場合、UTF-8 にコード変換するためにコア tensorflow transcode op を使用できます。入力が妥当ではないかもしれない場合には文字列に構造的に正当な UTF-8 を強制するために同じ op を使用することもできます。
docs = tf.constant([u'Everything not saved will be lost.'.encode('UTF-16-BE'), u'Sad☹'.encode('UTF-16-BE')]) utf8_docs = tf.strings.unicode_transcode(docs, input_encoding='UTF-16-BE', output_encoding='UTF-8')
正規化
テキストの異なるソースを扱うとき、同じ単語が同一であると認識されることは重要です。Unicode における case-insensitive (大文字小文字を区別しない) マッチングのための一般的なテクニックは case folding です (lower-casing (小文字化) に似ています)。(case folding は内部的には NFKC 正規化を適用することに注意してください。)
私達はまた (デフォルトでは) 正規化形式 KC (NFKC, Normalization Form KC) によって文字列を文字の標準表現に変形するための Unicode 正規化 ops も提供します。
print(text.case_fold_utf8(['Everything not saved will be lost.'])) print(text.normalize_utf8(['Äffin'])) print(text.normalize_utf8(['Äffin'], 'nfkd'))
tf.Tensor(['everything not saved will be lost.'], shape=(1,), dtype=string) tf.Tensor(['\xc3\x84ffin'], shape=(1,), dtype=string) tf.Tensor(['A\xcc\x88ffin'], shape=(1,), dtype=string)
トークン化
トークン化は文字列をトークンに分解する過程です。一般に、これらのトークンは単語、数字、and/or 句読点です。
主要なインターフェイスは Tokenizer と TokenizerWithOffsets でそれぞれ単一のメソッド tokenize と tokenizeWithOffsets を持ちます。利用可能な複数のトークナイザーの実装が今はあります。これらの各々は (Tokenizer を拡張した) TokenizerWithOffsets を実装しこれはバイトオフセットを元の文字列に含めるためのオプションを含みます。これは呼び出し側に (そこからトークンが作成された) 元の文字列におけるバイトを知ることを可能にします。
総てのトークナイザーは元の個々の文字列にマップされるトークンの最内部 (= inner-most) 次元を持つ RaggedTensor を返します。その結果、結果としての shape のランクは一つずつ増やされます。それらについて馴染みがないのであれば ragged tensor ガイドをレビューしてください。https://www.tensorflow.org/guide/ragged_tensors
WhitespaceTokenizer
これは UTF-8 文字列を ICU 定義された空白文字 (eg. スペース、タブ、改行 (= new line))で分解する基本的なトークナイザーです。
tokenizer = text.WhitespaceTokenizer() tokens = tokenizer.tokenize(['everything not saved will be lost.', u'Sad☹'.encode('UTF-8')]) print(tokens.to_list())
[['everything', 'not', 'saved', 'will', 'be', 'lost.'], ['Sad\xe2\x98\xb9']]
UnicodeScriptTokenizer
このトークナイザーは UTF-8 文字列を Unicode スクリプト境界を元に分解します。使用されるスクリプトコードは International Components for Unicode (ICU) UScriptCode 値に対応しています。http://icu-project.org/apiref/icu4c/uscript_8h.html 参照。
実際には、これは WhitespaceTokenizer に似ています。 (互いに言語テキストを分割もする一方で) それは言語テキスト (eg. USCRIPT_LATIN, USCRIPT_CYRILLIC, etc) から句読点 (USCRIPT_COMMON) を分割するという最も明白な違いを持ちます。
tokenizer = text.UnicodeScriptTokenizer() tokens = tokenizer.tokenize(['everything not saved will be lost.', u'Sad☹'.encode('UTF-8')]) print(tokens.to_list())
[['everything', 'not', 'saved', 'will', 'be', 'lost', '.'], ['Sad', '\xe2\x98\xb9']]
Unicode split
単語をセグメントするための空白なしで言語をトークン化するとき、文字で単に分割することは一般的です、これはコアで見つかる unicode_split op を使用して成されます。
tokens = tf.strings.unicode_split([u"仅今年前".encode('UTF-8')], 'UTF-8') print(tokens.to_list())
[['\xe4\xbb\x85', '\xe4\xbb\x8a', '\xe5\xb9\xb4', '\xe5\x89\x8d']]
オフセット
文字列をトークン化するとき、トークンが由来する元の文字列のどこかを知ることはしばしば望ましいです。この理由のため、TokenizerWithOffsets を実装する各トークナイザーは tokenize_with_offsets を持ちます、これはトークンと一緒にバイトオフセットを返します。offset_starts は各トークンが始まる元の文字列のバイトをリストアップし、そして offset_limits は各トークンが終わるところのバイトをリストアップします。
tokenizer = text.UnicodeScriptTokenizer() (tokens, offset_starts, offset_limits) = tokenizer.tokenize_with_offsets( ['everything not saved will be lost.', u'Sad☹'.encode('UTF-8')]) print(tokens.to_list()) print(offset_starts.to_list()) print(offset_limits.to_list())
[['everything', 'not', 'saved', 'will', 'be', 'lost', '.'], ['Sad', '\xe2\x98\xb9']] [[0, 11, 15, 21, 26, 29, 33], [0, 3]] [[10, 14, 20, 25, 28, 33, 34], [3, 6]]
TF.Data サンプル
トークナイザーは tf.data API で期待どおりに動作します。単純な例は下で提供されます。
docs = tf.data.Dataset.from_tensor_slices([['Never tell me the odds.'], ["It's a trap!"]]) tokenizer = text.WhitespaceTokenizer() tokenized_docs = docs.map(lambda x: tokenizer.tokenize(x)) iterator = tokenized_docs.make_one_shot_iterator() print(iterator.get_next().to_list()) print(iterator.get_next().to_list())
[['Never', 'tell', 'me', 'the', 'odds.']] [["It's", 'a', 'trap!']]
他の Text Ops
TF.Text は他の有用な前処理 ops をパッケージ化しています。下で 2, 3 をレビューします。
Wordshape
幾つかの自然言語理解モデルで使用される一般的な特徴はテキスト文字列が特定のプロパティを持つかを見ます。例えば、センテンス分解モデルは単語キャピタリゼーションや句読点文字が文字列の最後であるかを調べる特徴を含むかもしれません。
Wordshape は貴方の入力テキストで様々な関連パターンに適合する各種の有用な正規表現ベースのヘルパー関数を定義します。ここに 2,3 のサンプルがあります。
tokenizer = text.WhitespaceTokenizer() tokens = tokenizer.tokenize(['Everything not saved will be lost.', u'Sad☹'.encode('UTF-8')]) # Is capitalized? f1 = text.wordshape(tokens, text.WordShape.HAS_TITLE_CASE) # Are all letters uppercased? f2 = text.wordshape(tokens, text.WordShape.IS_UPPERCASE) # Does the token contain punctuation? f3 = text.wordshape(tokens, text.WordShape.HAS_SOME_PUNCT_OR_SYMBOL) # Is the token a number? f4 = text.wordshape(tokens, text.WordShape.IS_NUMERIC_VALUE) print(f1.to_list()) print(f2.to_list()) print(f3.to_list()) print(f4.to_list())
[[True, False, False, False, False, False], [True]] [[False, False, False, False, False, False], [False]] [[False, False, False, False, False, True], [True]] [[False, False, False, False, False, False], [False]]
N-gram & スライディング・ウィンドウ
N-gram は n のスライディング・ウィンドウのサイズが与えられたときのシークエンシャルな単語 (群) です。トークンを結合するとき、サポートされる 3 つの削減メカニズムがあります。テキストについては、Reduction.STRING_JOIN を使用することを望むでしょう、これは文字列を互いに付加します。デフォルトの区切り文字はスペースですが、これは string_separater 引数で変更可能です。
他の 2 つの削減メソッドは殆どの場合数値とともに使用され、これらは Reduction.SUM と Reduction.MEAN です。
tokenizer = text.WhitespaceTokenizer() tokens = tokenizer.tokenize(['Everything not saved will be lost.', u'Sad☹'.encode('UTF-8')]) # Ngrams, in this case bi-gram (n = 2) bigrams = text.ngrams(tokens, 2, reduction_type=text.Reduction.STRING_JOIN) print(bigrams.to_list())
[['Everything not', 'not saved', 'saved will', 'will be', 'be lost.'], []]
インストール
PIP を使用してインストール
pip install -U tensorflow-text
以上