عرض على TensorFlow.org | تشغيل في Google Colab | عرض المصدر على جيثب | تحميل دفتر |
مقدمة
غالبًا ما تتعامل نماذج البرمجة اللغوية العصبية مع لغات مختلفة بمجموعات أحرف مختلفة. يونيكود هو نظام التشفير القياسية التي تستخدم لتمثيل الحروف من اللغات كلها تقريبا. يتم ترميز حرف كل يونيكود باستخدام عدد صحيح فريد نقطة رمز بين 0
و 0x10FFFF
. سلسلة A يونيكود هي سلسلة من الصفر أو المزيد من النقاط التعليمات البرمجية.
يوضح هذا البرنامج التعليمي كيفية تمثيل سلاسل Unicode في TensorFlow ومعالجتها باستخدام معادلات Unicode من عمليات السلسلة القياسية. يفصل سلاسل Unicode إلى رموز بناءً على اكتشاف البرنامج النصي.
import tensorflow as tf
import numpy as np
و tf.string
نوع البيانات
وTensorFlow الأساسي tf.string
dtype
يسمح لك لبناء التنسورات سلاسل بايت. سلاسل يونيكود هي UTF-8 المشفرة بشكل افتراضي.
tf.constant(u"Thanks 😊")
<tf.Tensor: shape=(), dtype=string, numpy=b'Thanks \xf0\x9f\x98\x8a'>
A tf.string
يعامل موتر بايت سلاسل وحدات ذرية. وهذا يمكّنها من تخزين سلاسل البايت ذات الأطوال المتفاوتة. لم يتم تضمين طول السلسلة في أبعاد الموتر.
tf.constant([u"You're", u"welcome!"]).shape
TensorShape([2])
إذا كنت تستخدم بايثون إلى سلاسل بناء، علما بأن سلسلة حرفية هي يونيكود ترميز افتراضيا.
تمثل 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
مع الحشو أو 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)>
عمليات يونيكود
طول الحرف
استخدام 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'
انقسام سلاسل يونيكود
و tf.strings.unicode_split
عملية انشقاقات سلاسل يونيكود في سلاسل فرعية من الأحرف الفردية.
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
كل نقطة رمز Unicode تنتمي إلى مجموعة واحدة من codepoints يعرف النصي . يعد نص الحرف مفيدًا في تحديد اللغة التي قد تكون بها الشخصية. على سبيل المثال ، معرفة أن "Б" مكتوبة بخط سيريلي يشير إلى أن النص الحديث الذي يحتوي على هذا الحرف من المحتمل أن يكون من لغة سلافية مثل الروسية أو الأوكرانية.
يوفر TensorFlow و tf.strings.unicode_script
عملية لتحديد أي سيناريو معين الاستخدامات التمثيل البرمجي. رموز النصي هي int32
القيم المقابلة ل مكونات الدولي لليونيكود (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']]