Lihat di TensorFlow.org | Jalankan di Google Colab | Lihat sumber di GitHub | Unduh buku catatan |
pengantar
Model NLP sering menangani bahasa yang berbeda dengan set karakter yang berbeda. Unicode adalah sistem pengkodean standar yang digunakan untuk mewakili karakter dari hampir semua bahasa. Karakter setiap Unicode dikodekan menggunakan bilangan bulat yang unik titik kode antara 0
dan 0x10FFFF
. Sebuah Unicode string adalah urutan nol atau lebih poin kode.
Tutorial ini menunjukkan cara merepresentasikan string Unicode di TensorFlow dan memanipulasinya menggunakan operasi string standar yang setara dengan Unicode. Ini memisahkan string Unicode menjadi token berdasarkan deteksi skrip.
import tensorflow as tf
import numpy as np
The tf.string
tipe data
Dasar TensorFlow tf.string
dtype
memungkinkan Anda untuk membangun tensor string byte. String Unicode yang utf-8 dikodekan secara default.
tf.constant(u"Thanks 😊")
<tf.Tensor: shape=(), dtype=string, numpy=b'Thanks \xf0\x9f\x98\x8a'>
Sebuah tf.string
memperlakukan tensor byte string sebagai unit atom. Ini memungkinkannya untuk menyimpan string byte dengan panjang yang bervariasi. Panjang senar tidak termasuk dalam dimensi tensor.
tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])
Jika Anda menggunakan Python untuk string konstruk, catatan bahwa string literal adalah Unicode-encoded secara default.
Mewakili Unicode
Ada dua cara standar untuk merepresentasikan string Unicode di TensorFlow:
-
string
skalar - di mana urutan poin kode dikodekan menggunakan diketahui pengkodean karakter . -
int32
vector - di mana setiap posisi berisi titik kode tunggal.
Misalnya, tiga nilai berikut semua mewakili string Unicode "语言处理"
(yang berarti "pemrosesan bahasa" dalam bahasa Cina):
# 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)>
Mengonversi antar representasi
TensorFlow menyediakan operasi untuk mengonversi antara berbagai representasi berikut:
-
tf.strings.unicode_decode
: Mengkonversi string skalar dikodekan ke vektor poin kode. -
tf.strings.unicode_encode
: Mengubah vektor poin kode untuk sebuah skalar string yang disandikan. -
tf.strings.unicode_transcode
: Mengkonversi string skalar dikodekan ke pengkodean yang berbeda.
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 di setiap string mungkin tidak sama. Hasil pengembalian adalah tf.RaggedTensor
, dimana panjang dimensi terdalam bervariasi tergantung pada jumlah karakter dalam 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 ini tf.RaggedTensor
langsung, atau mengubahnya menjadi padat tf.Tensor
dengan bantalan atau tf.SparseTensor
menggunakan metode tf.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()
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, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]]
Ketika pengkodean beberapa string dengan panjang yang sama, menggunakan tf.Tensor
sebagai masukan.
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)>
Ketika pengkodean beberapa string dengan panjang bervariasi, menggunakan tf.RaggedTensor
sebagai masukan.
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 empuk atau jarang, mengubahnya pertama menjadi tf.RaggedTensor
sebelum memanggil 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)>
Operasi Unicode
Panjang karakter
Gunakan unit
parameter dari tf.strings.length
op untuk menunjukkan bagaimana panjang karakter harus dihitung. unit
default ke "BYTE"
, tetapi dapat diatur untuk nilai-nilai lain, seperti "UTF8_CHAR"
atau "UTF16_CHAR"
, untuk menentukan jumlah codepoints Unicode di setiap string disandikan.
# 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
Substring karakter
The tf.strings.substr
op menerima unit
parameter, dan menggunakannya untuk menentukan jenis offset pos
dan len
paremeters mengandung.
# 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'
Pisahkan string Unicode
The tf.strings.unicode_split
operasi membagi string unicode ke substring dari karakter individu.
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)
Offset byte untuk karakter
Untuk menyelaraskan tensor karakter yang dihasilkan oleh tf.strings.unicode_decode
dengan string asli, ini berguna untuk mengetahui offset untuk di mana masing-masing karakter dimulai. Metode tf.strings.unicode_decode_with_offsets
mirip dengan unicode_decode
, kecuali bahwa ia mengembalikan tensor kedua berisi awal offset masing-masing 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
Skrip Unicode
Setiap titik kode Unicode milik koleksi tunggal codepoints dikenal sebagai naskah . Skrip karakter sangat membantu dalam menentukan bahasa yang digunakan karakter tersebut. Misalnya, mengetahui bahwa 'Б' dalam skrip Cyrillic menunjukkan bahwa teks modern yang berisi karakter tersebut kemungkinan berasal dari bahasa Slavia seperti Rusia atau Ukraina.
TensorFlow menyediakan tf.strings.unicode_script
operasi untuk menentukan script yang diberikan menggunakan codepoint. Kode Script yang int32
nilai-nilai yang sesuai dengan Komponen Internasional untuk Unicode (ICU) UScriptCode
nilai-nilai.
uscript = tf.strings.unicode_script([33464, 1041]) # ['芸', 'Б']
print(uscript.numpy()) # [17, 8] == [USCRIPT_HAN, USCRIPT_CYRILLIC]
[17 8]
The tf.strings.unicode_script
operasi juga dapat diterapkan untuk multidimensi tf.Tensor
s atau tf.RaggedTensor
s dari codepoints:
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 tugas memecah teks menjadi unit-unit seperti kata. Ini seringkali mudah ketika karakter spasi digunakan untuk memisahkan kata, tetapi beberapa bahasa (seperti Cina dan Jepang) tidak menggunakan spasi, dan beberapa bahasa (seperti Jerman) mengandung senyawa panjang yang harus dipisahkan untuk menganalisis artinya. Dalam teks web, bahasa dan skrip yang berbeda sering dicampur bersama, seperti dalam "NY株価" (Bursa Saham New York).
Kami dapat melakukan segmentasi yang sangat kasar (tanpa menerapkan model ML apa pun) dengan menggunakan perubahan skrip untuk memperkirakan batas kata. Ini akan bekerja untuk string seperti contoh "NY株価" di atas. Ini juga akan berfungsi untuk sebagian besar bahasa yang menggunakan spasi, karena karakter spasi dari berbagai skrip semuanya diklasifikasikan sebagai USCRIPT_COMMON, kode skrip khusus yang berbeda dari teks sebenarnya.
# dtype: string; shape: [num_sentences]
#
# The sentences to process. Edit this line to try out different inputs!
sentence_texts = [u'Hello, world.', u'世界こんにちは']
Pertama, dekode kalimat menjadi titik kode karakter, dan temukan pengidentifikasi skrip untuk setiap karakter.
# 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]]>
Gunakan pengidentifikasi skrip untuk menentukan di mana batas kata harus ditambahkan. Tambahkan batas kata di awal setiap kalimat, dan untuk setiap karakter yang skripnya berbeda dari karakter sebelumnya.
# 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)
Anda kemudian dapat menggunakan mereka offset awal untuk membangun RaggedTensor
yang berisi daftar kata-kata dari semua batch.
# 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]]>
Untuk finish, segmen kata codepoints RaggedTensor
kembali ke kalimat dan encode ke UTF-8 string untuk dibaca.
# 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']]