In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳はベストエフォートであるため、この翻訳が正確であることや英語の公式ドキュメントの 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリtensorflow/docsにプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 docs-ja@tensorflow.org メーリングリストにご連絡ください。
自然言語モデルは、しばしば異なる文字セットを使った異なる言語を扱います。 Unicodeは、ほぼすべての言語で文字表示に使われている標準的なエンコードの仕組みです。各文字は、0
から0x10FFFF
までの一意の整数の コードポイント(符号位置) を使ってエンコードされます。1つの Unicode文字列は、ゼロ個以上のコードポイントのシーケンスです。
このチュートリアルでは、TensorFlow での Unicode文字列の表現方法と、どうやって Unicode で標準的な文字列操作と同様の操作を行うかについて示します。また、スクリプト検出にもとづいて Unicode 文字列をトークンに分解します。
In [ ]:
import tensorflow as tf
In [ ]:
tf.constant(u"Thanks 😊")
バイト列が最小限の単位として扱われるため、tf.string
型のテンソルは可変長のバイト文字列を保持できます。また、文字列長はテンソルの次元には含まれません。
In [ ]:
tf.constant([u"You're", u"welcome!"]).shape
注 : Pythonを使って文字列を構成するとき、v2.x系とv3.x系では Unicode の扱いが異なります。v2.x系では、Unicode文字列は上記のようにプレフィックス "u" で明示します。v3.x系では、デフォルトで Unicode としてエンコードされます。
TensorFlow での Unicode文字列表現は、2つの標準的な方法があります:
string
スカラー — コードポイントのシーケンスは既知の 文字符合化方式 でエンコードされるint32
ベクトル — 各文字には単一のコードポイントが入るたとえば、以下3つはすべて Unicode文字列 "语言処理 "
(中国語で「言語処理」を意味します)を表します。
In [ ]:
# Unicode文字列。UTF-8にエンコードされた文字列スカラーとして表される
text_utf8 = tf.constant(u"语言处理")
text_utf8
In [ ]:
# Unicode文字列。UTF-16-BEにエンコードされた文字列スカラーとして表される
text_utf16be = tf.constant(u"语言处理".encode("UTF-16-BE"))
text_utf16be
In [ ]:
# Unicode文字列。Unicodeコードポイントのベクトルとして表される
text_chars = tf.constant([ord(char) for char in u"语言处理"])
text_chars
In [ ]:
tf.strings.unicode_decode(text_utf8,
input_encoding='UTF-8')
In [ ]:
tf.strings.unicode_encode(text_chars,
output_encoding='UTF-8')
In [ ]:
tf.strings.unicode_transcode(text_utf8,
input_encoding='UTF8',
output_encoding='UTF-16-BE')
複数の文字列をデコードする場合、各文字列の文字数が等しくない場合があります。返される結果はtf.RaggedTensor
であり、最も内側の次元の長さは各文字列の文字数によって異なります。:
In [ ]:
# Unicode文字列のバッチ。それぞれが、UTF8にエンコードされた文字列として表される
batch_utf8 = [s.encode('UTF-8') for s in
[u'hÃllo', u'What is the weather tomorrow', u'Göödnight', u'😊']]
batch_chars_ragged = tf.strings.unicode_decode(batch_utf8,
input_encoding='UTF-8')
for sentence_chars in batch_chars_ragged.to_list():
print(sentence_chars)
この tf.RaggedTensor
を直接使用することも、tf.RaggedTensor.to_tensor
メソッドを使ってパディングを追加した密な tf.Tensor
に変換するか、あるいは tf.RaggedTensor.to_sparse
メソッドを使って tf.SparseTensor
に変換することもできます。
In [ ]:
batch_chars_padded = batch_chars_ragged.to_tensor(default_value=-1)
print(batch_chars_padded.numpy())
In [ ]:
batch_chars_sparse = batch_chars_ragged.to_sparse()
同じ長さの複数の文字列をエンコードする場合、tf.Tensor
を入力値として使用できます。
In [ ]:
tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [ 99, 111, 119]],
output_encoding='UTF-8')
可変長の複数の文字列をエンコードする場合、tf.RaggedTensor
を入力値として使用する必要があります。
In [ ]:
tf.strings.unicode_encode(batch_chars_ragged, output_encoding='UTF-8')
パディングされた、あるいはスパースな複数の文字列を含むテンソルがある場合は、unicode_encode
を呼び出す前に tf.RaggedTensor
に変換します。
In [ ]:
tf.strings.unicode_encode(
tf.RaggedTensor.from_sparse(batch_chars_sparse),
output_encoding='UTF-8')
In [ ]:
tf.strings.unicode_encode(
tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),
output_encoding='UTF-8')
In [ ]:
# 最後の絵文字は、UTF8で4バイトを占めることに注意する
thanks = u'Thanks 😊'.encode('UTF-8')
num_bytes = tf.strings.length(thanks).numpy()
num_chars = tf.strings.length(thanks, unit='UTF8_CHAR').numpy()
print('{} bytes; {} UTF-8 characters'.format(num_bytes, num_chars))
In [ ]:
# デフォルト: unit='BYTE'. len=1 の場合、1バイトを返す
tf.strings.substr(thanks, pos=7, len=1).numpy()
In [ ]:
# unit = 'UTF8_CHAR' を指定すると、単一の文字(この場合は4バイト)が返される
print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())
In [ ]:
tf.strings.unicode_split(thanks, 'UTF-8').numpy()
In [ ]:
codepoints, offsets = tf.strings.unicode_decode_with_offsets(u"🎈🎉🎊", 'UTF-8')
for (codepoint, offset) in zip(codepoints.numpy(), offsets.numpy()):
print("At byte offset {}: codepoint {}".format(offset, codepoint))
各Unicodeコードポイントは、スクリプト として知られる単一のコードポイント集合に属しています。文字スクリプトは、その文字がどの言語なのかを判断するのに役立ちます。たとえば、「Б」がキリル文字であることがわかれば、その文字を含むテキストはロシア語やウクライナ語などのスラブ言語である可能性が高いことがわかります。
TensorFlowは、あるコードポイントがどのスクリプトかを返す tf.strings.unicode_script
を提供しています。戻り値のスクリプトコードは、International Components for Unicode (ICU) の UScriptCode
に対応する int32
値になります。
In [ ]:
uscript = tf.strings.unicode_script([33464, 1041]) # ['芸', 'Б']
print(uscript.numpy()) # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]
tf.strings.unicode_script
は、多次元のコードポイントの tf.Tensors
や tf.RaggedTensor
にも適用できます。:
In [ ]:
print(tf.strings.unicode_script(batch_chars_ragged))
セグメンテーションは、テキストを単語のような粒度に分割するタスクです。これは、スペース文字を使用して単語を区切れる場合には簡単に行えますが、一部の言語(中国語や日本語など)はスペースを使いませんし、また、一部の言語(ドイツ語など)には、意味を解析するために分ける必要がある、単語を結合した長い複合語があります。Webテキストでは、「NY株価」(ニューヨーク株価)のように、異なる言語とスクリプトがしばしば混在しています。
単語の境界を推定してスクリプトを変更することにより、(MLモデルを実装せずに)非常に大まかなセグメンテーションを実行できます。これは、上記の「NY株価」の例のような文字列に対して機能します。さまざまな言語のスペース文字はすべて、実際のテキストとは異なる特別なスクリプトコードである USCRIPT_COMMON として分類されるため、スペースを使用するほとんどの言語でも機能します。
In [ ]:
# dtype: string; shape: [num_sentences]
#
# 処理する文章。この行を編集して、さまざまな入力を試してみてください!
sentence_texts = [u'Hello, world.', u'世界こんにちは']
最初に、文章を文字ごとのコードポイントにデコードし、それから各文字のスクリプトコード(識別子)を調べます。
In [ ]:
# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_codepoint[i, j] は、i番目の文のn番目の文字のコードポイント
sentence_char_codepoint = tf.strings.unicode_decode(sentence_texts, 'UTF-8')
print(sentence_char_codepoint)
# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_scripts[i, j] は、i番目の文のn番目の文字のスクリプトコード
sentence_char_script = tf.strings.unicode_script(sentence_char_codepoint)
print(sentence_char_script)
次に、これらのスクリプトコードを使って、単語の境界を追加すべき場所を決めます。前の文字とスクリプトコードが異なるそれぞれの文字の先頭に、単語の境界を追加します。:
In [ ]:
# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_starts_word[i, j] は、i番目の文のn番目の文字が単語の始まりである場合にTrue
sentence_char_starts_word = tf.concat(
[tf.fill([sentence_char_script.nrows(), 1], True),
tf.not_equal(sentence_char_script[:, 1:], sentence_char_script[:, :-1])],
axis=1)
# dtype: int64; shape: [num_words]
#
# word_starts[i] は、i番目の単語の始まりである文字のインデックス
# (すべての文がフラット化された文字リスト)
word_starts = tf.squeeze(tf.where(sentence_char_starts_word.values), axis=1)
print(word_starts)
そして、これらの目印(開始オフセット)を使って、各単語ごとの文字リストを含む RaggedTensor
を作成します。:
In [ ]:
# dtype: int32; shape: [num_words, (num_chars_per_word)]
#
# word_char_codepoint[i, j] は、i番目の単語のn番目の文字のコードポイント
word_char_codepoint = tf.RaggedTensor.from_row_starts(
values=sentence_char_codepoint.values,
row_starts=word_starts)
print(word_char_codepoint)
最後に、RaggedTensor
をコードポイント単位でセグメント化して、文章に戻します。:
In [ ]:
# dtype: int64; shape: [num_sentences]
#
# sentence_num_words[i] は、i番目の文の単語数
sentence_num_words = tf.reduce_sum(
tf.cast(sentence_char_starts_word, tf.int64),
axis=1)
# dtype: int32; shape: [num_sentences, (num_words_per_sentence), (num_chars_per_word)]
#
# sentence_word_char_codepoint[i, j, k] は、i番目の文のn番目の単語のk番目の文字のコードポイント
sentence_word_char_codepoint = tf.RaggedTensor.from_row_lengths(
values=word_char_codepoint,
row_lengths=sentence_num_words)
print(sentence_word_char_codepoint)
最終的な結果を見やすくするために、UTF-8文字列にエンコードします。:
In [ ]:
tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()