String Unicode

Lihat di TensorFlow.org Jalankan di Google Colab Liat source di GitHub Unduh notebook

Pengenalan

Model yang memproses bahasa alami (natural language) sering menangani bahasa dan simbol/karakter yang berbeda-beda. Unicode adalah standar sistem pengkodean yang digunakan untuk mewakili simbol/karakter dari hampir semua bahasa. Setiap karakter dikodekan menggunakan integer unik code point antara 0 dan0x10FFFF. Sebuah Unicode string adalah rangkaian dari nol atau lebih code point.

Tutorial ini, menunjukkan bagaimana cara merepresentasikan string Unicode di TensorFlow dan memanipulasinya menggunakan Unicode yang ekuivalen dengan standar operasi string. Cara ini, bertujuan untuk memisahkan Unicode strings menjadi beberapa token berdasarkan kata-kata yang dideteksi.

from __future__ import absolute_import, division, print_function, unicode_literals

try:
  # %tensorflow_version hanya ada di Colab.
  %tensorflow_version 2.x
except Exception:
  pass
import tensorflow as tf

Tipe data tf.string

TensorFlow tf.stringdtype memungkinkan Anda membangun tensor dari beberapa byte string. Unicode strings secara default, menggunakan utf-8.

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

Tensor tf.string dapat menampung string byte dengan panjang yang berbeda-beda karena string byte diperlakukan sebagai unit atom. Panjang string tidak masuk dalam dimensi tensor.

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

Catatan: Saat menggunakan python untuk membangun string, penanganan unicode berbeda antara v2 dan v3. Dalam v2, unicode strings ditunjukkan oleh awalan "u", seperti di atas. Di v3, strings adalah unicode yang terkodekan secara default.

Mewakili Unicode

Ada dua cara standar untuk menunjukan string Unicode di TensorFlow:

  • string scalar - di mana urutan code points dikodekan menggunakan character encoding.
  • int32 vector - di mana setiap posisi berisi satu code points.

Misalnya, tiga nilai berikut semuanya mewakili Unicode string "语言处理" (yang berarti "pemrosesan bahasa" dalam bahasa Cina):

# Unicode string, ditunjukan sebagai string scalar yang dikodekan menggunakan format UTF-8
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, ditunjukan sebagai string scalar yang dikodekan menggunakan format UTF-16-BE
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, ditunjukan sebagai sebuah vektor dalam code point Unicode.
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)>

Konversi di antara representasi

TensorFlow menyediakan operasi untuk mengkonversi vektor, skalar, atau format :

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

Dimensi batch

Saat mendekode beberapa string, jumlah karakter dalam setiap string mungkin tidak sama. Hasil returnnya adalah tf.RaggedTensor, di mana panjang dimensi bervariasi ,tergantung pada jumlah karakter di setiap string:

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

Anda dapat menggunakan tf.RaggedTensor ini secara langsung, atau mengonversinya menjaditf.Tensor dengan padding atau tf.SparseTensor menggunakan metodetf.RaggedTensor.to_tensor dan tf.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()

Saat mengkodekan beberapa string dengan panjang yang sama, tf.Tensor dapat digunakan sebagai input:

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

Saat mengkodekan beberapa string dengan panjang yang bervariasi, tf.RaggedTensor dapat digunakan sebagai input:

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

Jika Anda memiliki tensor dengan beberapa string dalam format padded atau sparse, konversikan ke tf.RaggedTensor sebelum memanggilunicode_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)>

Operasi Unicode

Panjang karakter

Operasi tf.strings.length memiliki parameterunit, yang menunjukkan cara/format karakter harus dikodekan. unit secara default menjadi"BYTE", tetapi dapat disetel ke nilai lain, seperti"UTF8_CHAR"atau"UTF16_CHAR", untuk menentukan jumlah code point Unicode di setiapstring yang dikodekan.

# Perhatikan bahwa karakter terakhir membutuhkan 4 byte dalam 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

Substring karakter

Hampir sama, operasi tf.strings.substr terdapat parameter" unit", dan digunakan untuk menentukan jenis offset apa yang ada dalam parameter "pos "dan" len".

# default: unit='BYTE'. With len=1, we return a single byte.
# default: unit='BYTE'. Dengan len=1, menunjukan 1  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.
# Dengan mengatur unit='UTF8_CHAR', kita menunjukan 1 karakter, dengan panjang
# 4 bytes.
print(tf.strings.substr(thanks, pos=7, len=1, unit='UTF8_CHAR').numpy())
b'\xf0\x9f\x98\x8a'

Memecah Unicode Strings

Operasi tf.strings.unicode_split memecah string unicode menjadi substring karakter:

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)

Byte offset untuk karakter

Untuk menyelaraskan tensor karakter yang dihasilkan oleh tf.strings.unicode_decode dengan string asli, penting untuk mengetahui offset pada setiap awal karakter. Metode tf.strings.unicode_decode_with_offsets mirip denganunicode_decode, tapi metode ini me-return tensor kedua yang berisi offset awal setiap karakter.

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

Script Unicode

Setiap code point Unicode, merupakan milik satu kumpulan codepoint yang dikenal sebagai script. Script dari sebuah karakter sangat membantu dalam menentukan bahasa yang mungkin digunakan karakter tersebut. Misalnya, mengetahui bahwa 'Б' dalam script Cyrillic menunjukkan bahwa teks modern yang mengandung karakter tersebut kemungkinan berasal dari bahasa Slavik seperti Rusia atau Ukraina.

TensorFlow menyediakan operasi tf.strings.unicode_script untuk menentukan script mana yang digunakan oleh code point tertentu. Script code yang bernilai int32 sesuai dengan nilai International Components for Unicode (ICU) UScriptCode.

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

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

The tf.strings.unicode_script operation can also be applied to multidimensional tf.Tensors or tf.RaggedTensors of codepoints:

Operasi tf.strings.unicode_script juga dapat diterapkan ketf.Tensor atau tf.RaggedTensor dari codepoint:

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

Contoh: Segmentasi sederhana

Segmentasi adalah memisahkan teks menjadi satuan kata-kata. Segmentasi mudah dilakukan ketika karakter spasi digunakan untuk memisahkan antar kata, tetapi beberapa bahasa (seperti Cina dan Jepang) tidak menggunakan spasi, dan beberapa bahasa (seperti Jerman) mengandung gabungan yang harus dipecah untuk menganalisis artinya. Dalam teks web, berbagai bahasa dan script sering dicampur bersama, seperti dalam "NY 株 価" (Bursa Saham New York).

Kita dapat melakukan segmentasi yang sangat kasar (tanpa menerapkan model ML) dengan menggunakan perubahan nilai pada script untuk memperkirakan pembatas kata. Cara ini dapat digunakan untuk string seperti contoh "NY 株 価" di atas. Cara ini juga dapat digunakan untuk sebagian besar bahasa yang menggunakan spasi, karena karakter spasi dari berbagai script semuanya diklasifikasikan sebagai USCRIPT_COMMON, kode skrip khusus yang berbeda dengan teks aktual apa pun.

# dtype: string; shape: [num_sentences]
#
# sebuah kalimat untuk contoh.  Silakan diganti menggunakan bahasa lain untuk mencoba input yang berbeda!
sentence_texts = [u'Hello, world.', u'世界こんにちは']

First, we decode the sentences into character codepoints, and find the script identifeir for each character.

Pertama, kita menkodedan kalimat menjadi codepoints karakter, dan menemukan pengidentifikasi script untuk setiap karakter.

# dtype: int32; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_codepoint[i, j] adalah codepoint untuk karakter urutan ke j pada
# kalimat urutan ke i.
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] adalah unicode script untuk karakter urutan ke j pada
# kalimat urutan ke i.
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]]>

Selanjutnya, kita menggunakan pengidentifikasi script tersebut untuk menentukan di mana batas katanya. Kita menambahkan batas kata di awal setiap kalimat, dan untuk setiap karakter yang scripnya berbeda dari karakter sebelumnya:

# dtype: bool; shape: [num_sentences, (num_chars_per_sentence)]
#
# sentence_char_starts_word[i, j] bernilai True jika karakter urutan ke j dalam
# kalimat urutan ke i adalah awal dari sebuah kata.
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] adalah index dari karakter yang merupakan awal dari urutan kata ke i (dalam
# daftar kata dari kalimat).
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)

Kita kemudian dapat menggunakan start offsets tersebut untuk membangun sebuah RaggedTensor yang terdiri atas list kata-kata dari seluruh batch:

# dtype: int32; shape: [num_words, (num_chars_per_word)]
#
# word_char_codepoint[i, j] adalah codepoint untuk urutan karakter ke j dalam
# urutan kata ke i.
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]]>

Dan akhirnya, kita dapat mengelompokkan codepoint kata RaggedTensor kembali ke kalimat:

# dtype: int64; shape: [num_sentences]
#
# sentence_num_words[i] adalah jumlah kata dalam urutan kalimat ke-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] adalah codepoint untuk urutan karakter ke k
# dalam urutan kata ke j dalam urutan kaliman ke i.
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]]]>

Untuk membuat hasil akhir lebih mudah dibaca, kita dapat mengkodekannnya kembali ke string 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']]