הצג באתר TensorFlow.org | הפעל בגוגל קולאב | צפה במקור ב-GitHub | הורד מחברת |
מבוא
מודלים של NLP לרוב מטפלים בשפות שונות עם ערכות תווים שונות. Unicode הוא מערכת קידוד רגילה המשמשת לייצג דמויות כמעט בכול שפות. אופי כל Unicode מקודד באמצעות מספר שלם ייחודי נקודת קוד בין 0
ו 0x10FFFF
. Unicode המהווה מחרוזת היא רצף של אפס או יותר נקודות קוד.
מדריך זה מראה כיצד לייצג מחרוזות Unicode ב-TensorFlow ולתפעל אותן באמצעות מקבילות Unicode של פעולות מחרוזות סטנדרטיות. זה מפריד מחרוזות Unicode לאסימונים המבוססים על זיהוי סקריפט.
import tensorflow as tf
import numpy as np
tf.string
סוג הנתונים
TensorFlow הבסיסי tf.string
dtype
מאפשר לך לבנות tensors של מחרוזות בייט. מחרוזות Unicode הם utf-8 מקודד כברירת מחדל.
tf.constant(u"Thanks 😊")
<tf.Tensor: shape=(), dtype=string, numpy=b'Thanks \xf0\x9f\x98\x8a'>
tf.string
פינוקים מותח בית אחד מחרוזות כיחידות אטומיות. זה מאפשר לו לאחסן מחרוזות בתים באורכים שונים. אורך המיתר אינו כלול במידות הטנזור.
tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])
אם אתה משתמש Python למחרוזות מבנה, פתק כי literals מחרוזת הם יוניקוד בקידוד כברירת מחדל.
מייצג את יוניקוד
ישנן שתי דרכים סטנדרטיות לייצוג מחרוזת 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
עם ריפוד או 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
אופ מקבלת את 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
, למעט עובדה שהיא מחזירה מותחת שנייה המכילה התחילה לקזז של כול תו.
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 שייכת לאוסף יחיד של codePoints ידוע בתור סקריפט . התסריט של דמות מועיל בקביעה באיזו שפה הדמות עשויה להיות. לדוגמה, הידיעה ש-'Б' הוא בכתב קירילי מצביע על כך שטקסט מודרני המכיל את הדמות הזו כנראה משפה סלאבית כמו רוסית או אוקראינית.
TensorFlow מספק את tf.strings.unicode_script
פעולה כדי לקבוע איזה תסריט שימושים codepoint נתון. קודי סקריפט הם 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']]