ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูแหล่งที่มาบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค |
บทนำ
โมเดล NLP มักจะจัดการภาษาต่างๆ ด้วยชุดอักขระที่ต่างกัน Unicode เป็นระบบการเข้ารหัสมาตรฐานที่ใช้ในการแสดงละครจากเกือบทุกภาษา ตัวละครทุกตัว Unicode จะถูกเข้ารหัสโดยใช้จำนวนเต็มไม่ซ้ำกัน จุดรหัส ระหว่าง 0
และ 0x10FFFF
สตริง Unicode เป็นลำดับของศูนย์หรือมากกว่าจุดรหัส
บทช่วยสอนนี้แสดงวิธีแสดงสตริง Unicode ใน TensorFlow และจัดการโดยใช้ Unicode ที่เทียบเท่ากับ ops สตริงมาตรฐาน มันแยกสตริง 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'>
tf.string
ถือว่าเมตริกซ์ byte สตริงเป็นหน่วยอะตอม ซึ่งช่วยให้สามารถจัดเก็บสตริงไบต์ที่มีความยาวต่างกันได้ ความยาวสตริงไม่รวมอยู่ในมิติเทนเซอร์
tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])
ถ้าคุณใช้งูหลามสตริงสร้างทราบว่า ตัวอักษรของสตริง จะ Unicode เข้ารหัสโดยค่าเริ่มต้น
เป็นตัวแทนของ Unicode
มีสองวิธีมาตรฐานในการแสดงสตริง Unicode ใน TensorFlow:
-
string
เกลา - ที่ลำดับของจุดรหัสถูกเข้ารหัสโดยใช้เป็นที่รู้จัก การเข้ารหัสอักขระ -
int32
เวกเตอร์ - ที่แต่ละตำแหน่งมีจุดรหัสเดียว
ยกตัวอย่างเช่นค่าต่อไปนี้ทั้งสามเป็นตัวแทนของสายอักขระ 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
กับ padding หรือ tf.SparseTensor
โดยใช้วิธีการที่ tf.RaggedTensor.to_tensor
และ 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, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _]]
เมื่อการเข้ารหัสสตริงที่มีความยาวหลายเดียวกันใช้ 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"
เพื่อตรวจสอบจำนวน codepoints 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
พารามิเตอร์และใช้มันเพื่อตรวจสอบสิ่งที่ชนิดของการชดเชย pos
และ len
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
ยกเว้นว่ามันจะกลับเมตริกซ์ที่สองที่มีการเริ่มต้น offset ของตัวละครแต่ละตัว
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 เป็นชุดเดียวของ codepoints ที่รู้จักกันเป็น สคริปต์ สคริปต์ของอักขระมีประโยชน์ในการพิจารณาว่าอักขระนั้นอาจอยู่ในภาษาใด ตัวอย่างเช่น การรู้ว่า 'Б' อยู่ในอักษรซิริลลิกแสดงว่าข้อความสมัยใหม่ที่มีอักขระนั้นน่าจะมาจากภาษาสลาฟ เช่น รัสเซียหรือยูเครน
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
หรือ tf.RaggedTensor
ของ 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]]>
ตัวอย่าง: การแบ่งส่วนอย่างง่าย
การแบ่งกลุ่มเป็นงานของการแบ่งข้อความออกเป็นหน่วยที่เหมือนคำ ซึ่งมักจะเป็นเรื่องง่ายเมื่อใช้อักขระช่องว่างเพื่อแยกคำ แต่บางภาษา (เช่น จีนและญี่ปุ่น) ไม่ใช้ช่องว่าง และบางภาษา (เช่น เยอรมัน) มีสารประกอบยาว ๆ ที่ต้องแยกเพื่อวิเคราะห์ความหมาย ในข้อความบนเว็บ ภาษาและสคริปต์ต่างๆ มักถูกนำมาผสมกัน เช่นเดียวกับใน "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]]>
จนจบส่วนคำ codepoints 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']]