Unicode文字列

TensorFlow.orgで表示GoogleColabで実行GitHubでソースを表示 ノートブックをダウンロード

序章

NLPモデルは、多くの場合、異なる文字セットを持つ異なる言語を処理します。 Unicodeは、ほとんどすべての言語の文字を表すために使用される標準的な符号化方式です。すべてのUnicode文字は、一意の整数を使用して符号化されたコードポイントの間で00x10FFFFUnicode文字列は、ゼロまたはそれ以上のコードポイントのシーケンスです。

このチュートリアルでは、TensorFlowでUnicode文字列を表現し、標準の文字列opsと同等のUnicodeを使用してそれらを操作する方法を示します。スクリプトの検出に基づいて、Unicode文字列をトークンに分離します。

import tensorflow as tf
import numpy as np

tf.stringデータ型

基本TensorFlow tf.string dtypeあなたがバイト文字列のテンソルを構築することができます。 Unicode文字列はUTF-8デフォルトでエンコードされました。

tf.constant(u"Thanks 😊")
<tf.Tensor: shape=(), dtype=string, numpy=b'Thanks \xf0\x9f\x98\x8a'>

A tf.stringテンソル扱いバイト文字列原子単位として。これにより、さまざまな長さのバイト文字列を格納できます。文字列の長さはテンソルの寸法には含まれていません。

tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])

あなたは、文字列を構築するためのPythonを使用している場合は、そのノートの文字列リテラルは、デフォルトではUnicodeでエンコードされています。

Unicodeを表す

TensorFlowでUnicode文字列を表す標準的な方法は2つあります。

  • stringスカラー-コードポイントの配列が既知用いて符号化された文字エンコーディングを
  • int32ベクター-各位置は、単一のコードポイントを含みます。

たとえば、次の3つの値は、すべてのUnicode文字列表現"语言处理" (中国語の手段「言語処理」)。

# Unicode string, represented as a UTF-8 encoded string scalar.
text_utf8 = tf.constant(u"语言处理")
text_utf8
<tf.Tensor: shape=(), dtype=string, numpy=b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'>
# Unicode string, represented as a UTF-16-BE encoded string scalar.
text_utf16be = tf.constant(u"语言处理".encode("UTF-16-BE"))
text_utf16be
<tf.Tensor: shape=(), dtype=string, numpy=b'\x8b\xed\x8a\x00Y\x04t\x06'>
# Unicode string, represented as a vector of Unicode code points.
text_chars = tf.constant([ord(char) for char in u"语言处理"])
text_chars
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)>

表現間の変換

TensorFlowは、これらの異なる表現間で変換する操作を提供します。

  • tf.strings.unicode_decode :変換するコードポイントのベクトルにエンコードされた文字列をスカラー。
  • tf.strings.unicode_encode :エンコードされた文字列をスカラーへのコードポイントのベクトルに変換します。
  • tf.strings.unicode_transcode :異なるエンコーディングにエンコードされた文字列をスカラーに変換します。
tf.strings.unicode_decode(text_utf8,
                          input_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)>
tf.strings.unicode_encode(text_chars,
                          output_encoding='UTF-8')
<tf.Tensor: shape=(), dtype=string, numpy=b'\xe8\xaf\xad\xe8\xa8\x80\xe5\xa4\x84\xe7\x90\x86'>
tf.strings.unicode_transcode(text_utf8,
                             input_encoding='UTF8',
                             output_encoding='UTF-16-BE')
<tf.Tensor: shape=(), dtype=string, numpy=b'\x8b\xed\x8a\x00Y\x04t\x06'>

バッチ寸法

複数の文字列をデコードする場合、各文字列の文字数が等しくない場合があります。戻り結果はtf.RaggedTensor最も内側の寸法の長さは、各文字列の文字数に応じて変化します。

# A batch of Unicode strings, each represented as a UTF8-encoded string.
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)
[104, 195, 108, 108, 111]
[87, 104, 97, 116, 32, 105, 115, 32, 116, 104, 101, 32, 119, 101, 97, 116, 104, 101, 114, 32, 116, 111, 109, 111, 114, 114, 111, 119]
[71, 246, 246, 100, 110, 105, 103, 104, 116]
[128522]

あなたは、この使用することができますtf.RaggedTensor直接、または密に変換tf.Tensorパディングかとtf.SparseTensor方法を使用してtf.RaggedTensor.to_tensortf.RaggedTensor.to_sparse

batch_chars_padded = batch_chars_ragged.to_tensor(default_value=-1)
print(batch_chars_padded.numpy())
[[   104    195    108    108    111     -1     -1     -1     -1     -1
      -1     -1     -1     -1     -1     -1     -1     -1     -1     -1
      -1     -1     -1     -1     -1     -1     -1     -1]
 [    87    104     97    116     32    105    115     32    116    104
     101     32    119    101     97    116    104    101    114     32
     116    111    109    111    114    114    111    119]
 [    71    246    246    100    110    105    103    104    116     -1
      -1     -1     -1     -1     -1     -1     -1     -1     -1     -1
      -1     -1     -1     -1     -1     -1     -1     -1]
 [128522     -1     -1     -1     -1     -1     -1     -1     -1     -1
      -1     -1     -1     -1     -1     -1     -1     -1     -1     -1
      -1     -1     -1     -1     -1     -1     -1     -1]]
batch_chars_sparse = batch_chars_ragged.to_sparse()

nrows, ncols = batch_chars_sparse.dense_shape.numpy()
elements = [['_' for i in range(ncols)] for j in range(nrows)]
for (row, col), value in zip(batch_chars_sparse.indices.numpy(), batch_chars_sparse.values.numpy()):
  elements[row][col] = str(value)
# max_width = max(len(value) for row in elements for value in row)
value_lengths = []
for row in elements:
  for value in row:
    value_lengths.append(len(value))
max_width = max(value_lengths)
print('[%s]' % '\n '.join(
    '[%s]' % ', '.join(value.rjust(max_width) for value in row)
    for row in elements))
[[   104,    195,    108,    108,    111,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _]
 [    87,    104,     97,    116,     32,    105,    115,     32,    116,    104,    101,     32,    119,    101,     97,    116,    104,    101,    114,     32,    116,    111,    109,    111,    114,    114,    111,    119]
 [    71,    246,    246,    100,    110,    105,    103,    104,    116,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _]
 [128522,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _,      _]]

同じ長さの複数の文字列をエンコードするとき、使用tf.Tensor入力として。

tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [99, 111, 119]],
                          output_encoding='UTF-8')
<tf.Tensor: shape=(3,), dtype=string, numpy=array([b'cat', b'dog', b'cow'], dtype=object)>

長さを変えて複数の文字列をエンコードする際に、使用tf.RaggedTensor入力として。

tf.strings.unicode_encode(batch_chars_ragged, output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy=
array([b'h\xc3\x83llo', b'What is the weather tomorrow',
       b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>

あなたはパディングまたはスパース形式で複数の文字列を持つテンソルを持っている場合は、最初にそれを変換tf.RaggedTensor呼び出す前にtf.strings.unicode_encode

tf.strings.unicode_encode(
    tf.RaggedTensor.from_sparse(batch_chars_sparse),
    output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy=
array([b'h\xc3\x83llo', b'What is the weather tomorrow',
       b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>
tf.strings.unicode_encode(
    tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),
    output_encoding='UTF-8')
<tf.Tensor: shape=(4,), dtype=string, numpy=
array([b'h\xc3\x83llo', b'What is the weather tomorrow',
       b'G\xc3\xb6\xc3\xb6dnight', b'\xf0\x9f\x98\x8a'], dtype=object)>

Unicode操作

文字の長さ

使用unitのパラメータtf.strings.length文字の長さを計算する方法を示すために、オペアンプを。 unitデフォルト"BYTE" 、それのような他の値に設定することができる"UTF8_CHAR"又は"UTF16_CHAR"各エンコードされた文字列内のUnicodeコードポイントの数を決定します。

# Note that the final character takes up 4 bytes in UTF8.
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))
11 bytes; 8 UTF-8 characters

文字の部分文字列

tf.strings.substr opは受け入れunitそれはオフセットの種類を決定するためのパラメータを、および使用poslen paremetersが含まれています。

# Here, unit='BYTE' (default). Returns a single byte with len=1
tf.strings.substr(thanks, pos=7, len=1).numpy()
b'\xf0'
# Specifying unit='UTF8_CHAR', returns a single 4 byte character in this case
print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())
b'\xf0\x9f\x98\x8a'

Unicode文字列を分割する

tf.strings.unicode_split操作は、個々の文字の部分文字列にUnicodeの文字列を分割します。

tf.strings.unicode_split(thanks, 'UTF-8').numpy()
array([b'T', b'h', b'a', b'n', b'k', b's', b' ', b'\xf0\x9f\x98\x8a'],
      dtype=object)

文字のバイトオフセット

生成された文字テンソル整列するtf.strings.unicode_decode元の文字列とし、それはそれぞれの文字の開始位置のオフセットを知っておくと便利です。方法tf.strings.unicode_decode_with_offsetsと同様であるunicode_decodeそれは各文字の開始オフセットを含む第二のテンソルを返すことを除いて、。

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))
At byte offset 0: codepoint 127880
At byte offset 4: codepoint 127881
At byte offset 8: codepoint 127882

Unicodeスクリプト

各Unicodeコードポイントは、として知られているコードポイントの単一のコレクションに属しているスクリプト。文字のスクリプトは、文字がどの言語であるかを判断するのに役立ちます。たとえば、「Б」がキリル文字であることがわかっている場合、その文字を含む現代のテキストは、ロシア語やウクライナ語などのスラブ語に由来する可能性があります。

TensorFlowが提供tf.strings.unicode_scriptどのスクリプト所定のコードポイントの使用を決定する動作を制御します。スクリプトコードは、 int32に対応する値のUnicode国際コンポーネント(ICU) UScriptCode値。

uscript = tf.strings.unicode_script([33464, 1041])  # ['芸', 'Б']

print(uscript.numpy())  # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]
[17  8]

tf.strings.unicode_script動作も多次元に適用することができるtf.Tensor Sまたはtf.RaggedTensorのコードポイントの:

print(tf.strings.unicode_script(batch_chars_ragged))
<tf.RaggedTensor [[25, 25, 25, 25, 25], [25, 25, 25, 25, 0, 25, 25, 0, 25, 25, 25, 0, 25, 25, 25, 25, 25, 25, 25, 0, 25, 25, 25, 25, 25, 25, 25, 25], [25, 25, 25, 25, 25, 25, 25, 25, 25], [0]]>

例:単純なセグメンテーション

セグメンテーションは、テキストを単語のような単位に分割するタスクです。これは、単語を区切るためにスペース文字を使用する場合に簡単ですが、一部の言語(中国語や日本語など)ではスペースを使用せず、一部の言語(ドイツ語など)には、意味を分析するために分割する必要のある長い複合語が含まれています。 Webテキストでは、「NY株価」(ニューヨーク証券取引所)のように、さまざまな言語とスクリプトが頻繁に混在しています。

スクリプトの変更を使用して単語の境界を概算することにより、(MLモデルを実装せずに)非常に大まかなセグメンテーションを実行できます。これは、上記の「NY株価」の例のような文字列で機能します。さまざまなスクリプトのスペース文字はすべて、実際のテキストとは異なる特別なスクリプトコードであるUSCRIPT_COMMONとして分類されるため、スペースを使用するほとんどの言語でも機能します。

# dtype: string; shape: [num_sentences]
#
# The sentences to process.  Edit this line to try out different inputs!
sentence_texts = [u'Hello, world.', u'世界こんにちは']

まず、文を文字コードポイントにデコードし、各文字のスクリプト識別子を見つけます。

# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_codepoint[i, j] is the codepoint for the j'th character in
# the i'th sentence.
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] is the Unicode script of the j'th character in
# the i'th sentence.
sentence_char_script = tf.strings.unicode_script(sentence_char_codepoint)
print(sentence_char_script)
<tf.RaggedTensor [[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 46], [19990, 30028, 12371, 12435, 12395, 12385, 12399]]>
<tf.RaggedTensor [[25, 25, 25, 25, 25, 0, 0, 25, 25, 25, 25, 25, 0], [17, 17, 20, 20, 20, 20, 20]]>

スクリプト識別子を使用して、単語の境界を追加する場所を決定します。各文の先頭、および前の文字とスクリプトが異なる文字ごとに単語の境界を追加します。

# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_starts_word[i, j] is True if the j'th character in the i'th
# sentence is the start of a word.
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] is the index of the character that starts the i'th word (in
# the flattened list of characters from all sentences).
word_starts = tf.squeeze(tf.where(sentence_char_starts_word.values), axis=1)
print(word_starts)
tf.Tensor([ 0  5  7 12 13 15], shape=(6,), dtype=int64)

その後、構築するために、それらの開始オフセットを使用することができますRaggedTensorすべてのバッチから単語のリストを含むを。

# dtype: int32; shape: [num_words, (num_chars_per_word)]
#
# word_char_codepoint[i, j] is the codepoint for the j'th character in the
# i'th word.
word_char_codepoint = tf.RaggedTensor.from_row_starts(
    values=sentence_char_codepoint.values,
    row_starts=word_starts)
print(word_char_codepoint)
<tf.RaggedTensor [[72, 101, 108, 108, 111], [44, 32], [119, 111, 114, 108, 100], [46], [19990, 30028], [12371, 12435, 12395, 12385, 12399]]>

仕上げに、セグメント言葉はコードポイントRaggedTensor読みやすくするためUTF-8文字列に文章やエンコードに背中を。

# dtype: int64; shape: [num_sentences]
#
# sentence_num_words[i] is the number of words in the i'th sentence.
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] is the codepoint for the k'th character
# in the j'th word in the i'th sentence.
sentence_word_char_codepoint = tf.RaggedTensor.from_row_lengths(
    values=word_char_codepoint,
    row_lengths=sentence_num_words)
print(sentence_word_char_codepoint)

tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()
<tf.RaggedTensor [[[72, 101, 108, 108, 111], [44, 32], [119, 111, 114, 108, 100], [46]], [[19990, 30028], [12371, 12435, 12395, 12385, 12399]]]>
[[b'Hello', b', ', b'world', b'.'],
 [b'\xe4\xb8\x96\xe7\x95\x8c',
  b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf']]