ホーム » TensorFlow 2.0 » TensorFlow 2.0 : Tutorials : データのロードと前処理 :- Unicode 文字列

TensorFlow 2.0 : Tutorials : データのロードと前処理 :- Unicode 文字列

TensorFlow 2.0 : Beginner Tutorials : データのロードと前処理 :- Unicode 文字列 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/07/2019

* 本ページは、TensorFlow org サイトの TF 2.0 – Beginner Tutorials – Load and preprocess data の以下のページを
翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

データのロードと前処理 :- Unicode 文字列

イントロダクション

自然言語を処理するモデルはしばしば異なる文字セットを持つ異なる言語を扱います。Unicode は殆ど総ての言語からの文字を表わすために使用される標準エンコーディング・システムです。各文字は 0 と 0x10FFFF の間の一意な整数 コードポイント を使用してエンコードされます。Unicode 文字列はゼロまたはそれ以上のコードポイントのシークエンスです。

このチュートリアルはどのように TensorFlow で Unicode 文字列を表して標準文字列 ops の Unicode 同値を使用してそれらを操作するかを示します。それは Unicode 文字列を script detection に基づいてトークンに分類します。

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf

 

tf.string データ型

基本的な TensorFlow tf.string dtype はバイト文字列の tensor を構築することを可能にします。Unicode 文字列はデフォルトでは utf-8 エンコードされます。

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

tf.string tensor は変化する長さのバイト文字列を保持できます、何故ならばバイト文字列は atomic 単位として扱われるからです。文字列長は tensor 次元には含まれません。

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

Note: 文字列を構築するために python を使用するとき、unicode の扱いは v2 と v3 の間で異なります。v2 では、unicode 文字列は上のように “u” prefix で示されます。v3 では、文字列はデフォルトで unicode-エンコードされます。

 

Unicode を表わす

TensorFlow で Unicode 文字列を表わすには 2 つの標準的な方法があります :

  • string scalar — そこではコードポイントのシークエンスが既知の文字エンコーディングを使用してエンコードされます。
  • int32 vector — そこでは各位置がシングル・コードポイントを含みます。

例えば、次の 3 つの値は総て Unicode 文字列 “语言处理” (これは中国語で「言語処理」を意味します) を表します :

# Unicode string, represented as a UTF-8 encoded string scalar.
text_utf8 = tf.constant(u"语言处理")
text_utf8
<tf.Tensor: id=2, 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: id=3, 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: id=4, 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: id=8, shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)>
tf.strings.unicode_encode(text_chars,
                          output_encoding='UTF-8')
<tf.Tensor: id=18, 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: id=19, shape=(), dtype=string, numpy=b'\x8b\xed\x8a\x00Y\x04t\x06'>

 

バッチ次元

マルチ文字列をデコードするとき、各文字列の文字数は同じではないかもしれません。return 結果は tf.RaggedTensor で、そこでは最内部 (= innermost) の次元は各文字列の文字数に依拠して変化します :

# 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.RaggedTensor.to_tensortf.RaggedTensor.to_sparse を使用して) tf.SparseTensor でそれを密な tf.Tensor に変換できます。

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()

マルチ文字列を同じ長さでエンコードするとき、tf.Tensor は入力として使用されるかもしれません :

tf.strings.unicode_encode([[99, 97, 116], [100, 111, 103], [ 99, 111, 119]],
                          output_encoding='UTF-8')
<tf.Tensor: id=119, 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: id=120, 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)>

パッドされたか sparse 形式のマルチ文字列を持つ tensor を持つ場合、unicode_encode を呼び出す前にそれを tf.RaggedTensor に変換します :

tf.strings.unicode_encode(
    tf.RaggedTensor.from_sparse(batch_chars_sparse),
    output_encoding='UTF-8')

tf.strings.unicode_encode(
    tf.RaggedTensor.from_tensor(batch_chars_padded, padding=-1),
    output_encoding='UTF-8')

 

Unicode 演算

文字長 (= Character length)

tf.strings.length 演算はパラメータ・ユニットを持ち、これは長さがどのように計算されるべきであるかを示します。ユニットのデフォルトは “BYTE” ですが、これは各エンコードされた文字列で Unicode コードポイントの数を決定するために “UTF8_CHAR” や “UTF16_CHAR” のような他の値に設定できます。

# 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

 

文字部分文字列 (= Character substrings)

同様に、tf.strings.substr 演算は “unit” パラメータを受け取り、そして “pos” と “len” パラメータがどのような種類のオフセットを含むかを決定するためにそれを使用します。

# default: unit='BYTE'. With len=1, we return a single byte.
tf.strings.substr(thanks, pos=7, len=1).numpy()
b'\xf0'
# Specifying unit='UTF8_CHAR', we return a single character, which in this case
# is 4 bytes.
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 により生成された文字 tensor をアラインするには、どこで文字が始まるかのためのオフセットを知ることは有用です。メソッド tf.strings.unicode_decode_with_offsets は unicode_decode に類似しています、それが各文字の開始オフセットを含む 2 番目の tensor を返すことを除いて。

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 コードポイントは スクリプト として知られるコードポイントの単一コレクションに属します。文字のスクリプトは文字がどの言語にあるかを決定するのに役立ちます。例えば、’Б’ がキリル文字のスクリプトにあることを知ることはその文字を含む現代のテキストはロシア語やウクライナ語のようなスラヴ語 (= Slavic language) に由来することを示します。

TensorFlow は与えられたコードポイントがどのスクリプトを使用するかを決定するために tf.strings.unicode_script 演算を提供します。スクリプト・コードは International Components for Unicode (ICU) UScriptCode 値に対応する int32 値です。

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

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

tf.strings.unicode_script 演算はまたコードポイントのマルチ次元 tf.Tensors や tf.RaggedTensors にも適用できます :

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]]>

 

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

セグメンテーションはテキストを単語ライクな単位に分割するタスクです。これは単語を分離するためにスペース文字が使用されるときはしばしば容易ですが、(中国語や日本語のような) 幾つかの言語はスペースを使用せず、そして (ドイツ語のような) 幾つかの言語はそれらの意味を解析するために分割されなかればならない長い複合 (= compound) を含みます。web テキストでは、異なる言語とスクリプトは頻繁に一緒に混合されます、”NY株価” (New York Stock Exchange) 内のように。

単語境界を見積もるためにスクリプト内の変更を使用して (どのような 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 をセンテンスにセグメントし戻すことができます :

# 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.RaggedTensor [[[72, 101, 108, 108, 111], [44, 32], [119, 111, 114, 108, 100], [46]], [[19990, 30028], [12371, 12435, 12395, 12385, 12399]]]>

最後の結果を読みやすくするために、それを UTF-8 文字列にエンコードし戻すことができます :

tf.strings.unicode_encode(sentence_word_char_codepoint, 'UTF-8').to_list()
[[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']]
 

以上



AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com