عرض على TensorFlow.org | تشغيل في Google Colab | عرض على جيثب | تحميل دفتر | انظر نماذج TF Hub |
ملخص
الترميز هو عملية تقسيم سلسلة إلى رموز مميزة. عادةً ما تكون هذه الرموز عبارة عن كلمات و / أو أرقام و / أو علامات ترقيم. و tensorflow_text
توفر حزمة عدد من tokenizers متاحة للتجهيزها النص المطلوب من قبل النماذج القائمة على النص. من خلال تنفيذ الترميز في الرسم البياني TensorFlow ، لن تحتاج إلى القلق بشأن الاختلافات بين تدريبات سير العمل والاستدلال وإدارة البرامج النصية للمعالجة المسبقة.
يناقش هذا الدليل العديد من خيارات الترميز التي يوفرها نص TensorFlow ، عندما قد ترغب في استخدام خيار على آخر ، وكيف يتم استدعاء هذه الرموز المميزة من داخل النموذج الخاص بك.
يثبت
pip install -q tensorflow-text
import requests
import tensorflow as tf
import tensorflow_text as tf_text
الفاصل API
الواجهات الرئيسية هي Splitter
و SplitterWithOffsets
التي لها أساليب واحدة split
و split_with_offsets
. و SplitterWithOffsets
البديل (الذي يمتد Splitter
يتضمن) خيار للحصول على إزاحة بايت. يسمح هذا للمتصل بمعرفة البايت في السلسلة الأصلية التي تم إنشاء الرمز المميز منها.
و Tokenizer
و TokenizerWithOffsets
إصدارات المتخصصة في Splitter
التي توفر وسائل الراحة tokenize
و tokenize_with_offsets
على التوالي.
عموما، على أي مساهمة N-الأبعاد، الرموز عاد هم في N + 1 الأبعاد RaggedTensor مع البعد الداخلي الأكثر من الرموز رسم خرائط لسلاسل الفردية الأصلية.
class Splitter {
@abstractmethod
def split(self, input)
}
class SplitterWithOffsets(Splitter) {
@abstractmethod
def split_with_offsets(self, input)
}
وهناك أيضا Detokenizer
اجهة. يمكن لأي رمز مميز ينفذ هذه الواجهة أن يقبل موترًا ممزقًا بأبعاد N من الرموز المميزة ، ويعيد عادةً موترًا N-1-dimensional أو موترًا ممزقًا يحتوي على الرموز المميزة المجمعة معًا.
class Detokenizer {
@abstractmethod
def detokenize(self, input)
}
الرموز
يوجد أدناه مجموعة الرموز المميزة التي يوفرها TensorFlow Text. يُفترض أن تكون مدخلات السلسلة UTF-8. يرجى مراجعة دليل يونيكود لتحويل السلاسل إلى UTF-8.
tokenizers كلمة كاملة
تحاول أدوات الرموز المميزة تقسيم سلسلة بكلمات ، وهي الطريقة الأكثر سهولة لتقسيم النص.
المسافة البيضاء
و text.WhitespaceTokenizer
هو tokenizer أبسط الذي يقسم سلاسل على ICU تعريف الأحرف بيضاء (على سبيل المثال الفضاء، التبويب، خط جديد). هذا غالبًا ما يكون جيدًا لبناء نماذج أولية بسرعة.
tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py:206: batch_gather (from tensorflow.python.ops.array_ops) is deprecated and will be removed after 2017-10-25. Instructions for updating: `tf.batch_gather` is deprecated, please use `tf.gather` with `batch_dims=-1` instead. [[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]
قد تلاحظ أن أحد أوجه القصور في هذا الرمز المميز هو أن علامات الترقيم مضمنة في الكلمة لتكوين رمز مميز. لتقسيم الكلمات وعلامات الترقيم إلى الرموز منفصلة، و UnicodeScriptTokenizer
ينبغي استخدامها.
UnicodeScriptTokenizer
و UnicodeScriptTokenizer
يقسم سلاسل على أساس حدود النصي يونيكود. تتوافق أكواد البرنامج النصي المستخدمة مع قيم UScriptCode للمكونات الدولية لـ Unicode (ICU). انظر: http://icu-project.org/apiref/icu4c/uscript_8h.html
في الواقع، هذا هو مماثل ل WhitespaceTokenizer
مع معظم واضح الفرق بينهما أن ذلك سيؤدي إلى انقسام علامات الترقيم (USCRIPT_COMMON) من نصوص اللغة (على سبيل المثال. USCRIPT_LATIN، USCRIPT_CYRILLIC، الخ)، في حين يفصل أيضا نصوص اللغة من بعضها البعض. لاحظ أن هذا سيؤدي أيضًا إلى تقسيم كلمات الانكماش إلى رموز منفصلة.
tokenizer = tf_text.UnicodeScriptTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b'can', b"'", b't', b'explain', b',', b'but', b'you', b'feel', b'it', b'.']]
رموز الكلمات الفرعية
يمكن استخدام الرموز المميزة للكلمات الفرعية مع مفردات أصغر ، والسماح للنموذج بالحصول على بعض المعلومات حول الكلمات الجديدة من الكلمات الفرعية التي تقوم بإنشائها.
نناقش بإيجاز خيارات Subword tokenization أدناه، ولكن البرنامج التعليمي Subword Tokenization يذهب أكثر في عمق ويشرح كيفية إنشاء ملفات فوكب أيضا.
WordpieceTokenizer
ترميز WordPiece هو مخطط رمزي يعتمد على البيانات وينشئ مجموعة من الرموز الفرعية. قد تتوافق هذه الرموز الفرعية مع الأشكال اللغوية ، ولكن هذا ليس هو الحال في كثير من الأحيان.
يتوقع برنامج WordpieceTokenizer أن يكون الإدخال مقسمًا بالفعل إلى رموز مميزة. وبسبب هذا شرط أساسي، وكنت كثيرا ما تريد تقسيم باستخدام WhitespaceTokenizer
أو UnicodeScriptTokenizer
مسبقا.
tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]
بعد تقسيم السلسلة إلى الرموز، و WordpieceTokenizer
يمكن استخدامها لانقسام في subtokens.
url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_wp_en_vocab.txt?raw=true"
r = requests.get(url)
filepath = "vocab.txt"
open(filepath, 'wb').write(r.content)
52382
subtokenizer = tf_text.UnicodeScriptTokenizer(filepath)
subtokens = tokenizer.tokenize(tokens)
print(subtokens.to_list())
[[[b'What'], [b'you'], [b'know'], [b'you'], [b"can't"], [b'explain,'], [b'but'], [b'you'], [b'feel'], [b'it.']]]
بيرتوكينيزر
يعكس BertTokenizer التنفيذ الأصلي للرمز المميز من ورقة BERT. يتم دعم هذا بواسطة WordpieceTokenizer ، ولكنه يؤدي أيضًا مهام إضافية مثل التطبيع والترميز للكلمات أولاً.
tokenizer = tf_text.BertTokenizer(filepath, token_out_type=tf.string, lower_case=True)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[[b'what'], [b'you'], [b'know'], [b'you'], [b'can'], [b"'"], [b't'], [b'explain'], [b','], [b'but'], [b'you'], [b'feel'], [b'it'], [b'.']]]
الجمله
SentencepieceTokenizer عبارة عن رمز مميز للرمز الفرعي قابل للتكوين بدرجة عالية. هذا مدعوم من مكتبة Sentencepiece. مثل BertTokenizer ، يمكن أن يشمل التسوية وتقسيم الرمز قبل الانقسام إلى رموز فرعية.
url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_oss_model.model?raw=true"
sp_model = requests.get(url).content
tokenizer = tf_text.SentencepieceTokenizer(sp_model, out_type=tf.string)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'\xe2\x96\x81What', b'\xe2\x96\x81you', b'\xe2\x96\x81know', b'\xe2\x96\x81you', b'\xe2\x96\x81can', b"'", b't', b'\xe2\x96\x81explain', b',', b'\xe2\x96\x81but', b'\xe2\x96\x81you', b'\xe2\x96\x81feel', b'\xe2\x96\x81it', b'.']]
مقسمات أخرى
UnicodeCharTokenizer
يؤدي هذا إلى تقسيم السلسلة إلى أحرف UTF-8. إنه مفيد للغات CJK التي لا تحتوي على مسافات بين الكلمات.
tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]
الإخراج هو Unicode codepoints. يمكن أن يكون هذا مفيدًا أيضًا في إنشاء أحرف ngrams ، مثل bigrams. لإعادة التحويل إلى أحرف UTF-8.
characters = tf.strings.unicode_encode(tf.expand_dims(tokens, -1), "UTF-8")
bigrams = tf_text.ngrams(characters, 2, reduction_type=tf_text.Reduction.STRING_JOIN, string_separator='')
print(bigrams.to_list())
[[b'Wh', b'ha', b'at', b't ', b' y', b'yo', b'ou', b'u ', b' k', b'kn', b'no', b'ow', b'w ', b' y', b'yo', b'ou', b'u ', b' c', b'ca', b'an', b"n'", b"'t", b't ', b' e', b'ex', b'xp', b'pl', b'la', b'ai', b'in', b'n,', b', ', b' b', b'bu', b'ut', b't ', b' y', b'yo', b'ou', b'u ', b' f', b'fe', b'ee', b'el', b'l ', b' i', b'it', b't.']]
HubModuleTokenizer
هذا عبارة عن غلاف حول النماذج التي تم نشرها في TF Hub لتسهيل المكالمات نظرًا لأن TF Hub لا يدعم حاليًا الموترات الخشنة. يعد الحصول على رمز أداء نموذج مفيدًا بشكل خاص للغات CJK عندما تريد تقسيمها إلى كلمات ، ولكن ليس لديك مسافات لتوفير دليل إرشادي. في هذا الوقت ، لدينا نموذج تجزئة واحد للغة الصينية.
MODEL_HANDLE = "https://tfhub.dev/google/zh_segmentation/1"
segmenter = tf_text.HubModuleTokenizer(MODEL_HANDLE)
tokens = segmenter.tokenize(["新华社北京"])
print(tokens.to_list())
[[b'\xe6\x96\xb0\xe5\x8d\x8e\xe7\xa4\xbe', b'\xe5\x8c\x97\xe4\xba\xac']]
قد يكون من الصعب عرض نتائج سلاسل البايت المشفرة UTF-8. قم بفك تشفير قيم القائمة لتسهيل المشاهدة.
def decode_list(x):
if type(x) is list:
return list(map(decode_list, x))
return x.decode("UTF-8")
def decode_utf8_tensor(x):
return list(map(decode_list, x.to_list()))
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]
SplitMergeTokenizer
و SplitMergeTokenizer
و SplitMergeFromLogitsTokenizer
يكون لها هدف تستهدف تقسيم جملة مبنية على القيم المقدمة التي تشير إلى حيث يجب أن يكون سلسلة الانقسام. يكون هذا مفيدًا عند إنشاء نماذج التجزئة الخاصة بك مثل مثال التجزئة السابق.
ل SplitMergeTokenizer
، يتم استخدام قيمة 0 للإشارة إلى بدء سلسلة جديدة، وقيمة 1 يشير الحرف هو جزء من سلسلة الحالية.
strings = ["新华社北京"]
labels = [[0, 1, 1, 0, 1]]
tokenizer = tf_text.SplitMergeTokenizer()
tokens = tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]
و SplitMergeFromLogitsTokenizer
مماثل، ولكن بدلا من ذلك يقبل أزواج قيمة اللوغاريتمي من الشبكة العصبية التي تتنبأ ما إذا كان يجب تقسيم كل حرف في سلسلة جديدة أو دمجها في واحدة الحالي.
strings = [["新华社北京"]]
labels = [[[5.0, -3.2], [0.2, 12.0], [0.0, 11.0], [2.2, -1.0], [-3.0, 3.0]]]
tokenizer = tf_text.SplitMergeFromLogitsTokenizer()
tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]
RegexSplitter
و RegexSplitter
غير قادرة على سلاسل شريحة في نقاط التوقف التعسفية التي يحددها تعبير عادي المقدمة.
splitter = tf_text.RegexSplitter("\s")
tokens = splitter.split(["What you know you can't explain, but you feel it."], )
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]
إزاحة
عند ترميز السلاسل ، غالبًا ما يكون مطلوبًا معرفة مكان إنشاء الرمز المميز في السلسلة الأصلية. لهذا السبب، كل tokenizer التي تنفذ TokenizerWithOffsets
لديه طريقة tokenize_with_offsets التي سيعود إزاحة البايت جنبا إلى جنب مع الرموز. تسرد start_offsets وحدات البايت الموجودة في السلسلة الأصلية التي يبدأ عندها كل رمز مميز ، وتسرد end_offsets وحدات البايت مباشرةً بعد النقطة التي ينتهي عندها كل رمز مميز. لإعادة الصياغة ، تكون تعويضات البداية شاملة وتعويضات النهاية حصرية.
tokenizer = tf_text.UnicodeScriptTokenizer()
(tokens, start_offsets, end_offsets) = tokenizer.tokenize_with_offsets(['Everything not saved will be lost.'])
print(tokens.to_list())
print(start_offsets.to_list())
print(end_offsets.to_list())
[[b'Everything', b'not', b'saved', b'will', b'be', b'lost', b'.']] [[0, 11, 15, 21, 26, 29, 33]] [[10, 14, 20, 25, 28, 33, 34]]
تفكيك
Tokenizers التي تنفذ Detokenizer
توفير detokenize
الطريقة التي محاولات الجمع بين السلاسل. هذا لديه فرصة أن يكون ضياعًا ، لذلك قد لا تتطابق السلسلة التي تم فك ارتباطها دائمًا تمامًا مع السلسلة الأصلية التي تم ترميزها مسبقًا.
tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
strings = tokenizer.detokenize(tokens)
print(strings.numpy())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]] [b"What you know you can't explain, but you feel it."]
بيانات TF
TF Data هي واجهة برمجة تطبيقات قوية لإنشاء خط أنابيب إدخال لنماذج التدريب. تعمل الرموز المميزة كما هو متوقع مع API.
docs = tf.data.Dataset.from_tensor_slices([['Never tell me the odds.'], ["It's a trap!"]])
tokenizer = tf_text.WhitespaceTokenizer()
tokenized_docs = docs.map(lambda x: tokenizer.tokenize(x))
iterator = iter(tokenized_docs)
print(next(iterator).to_list())
print(next(iterator).to_list())
[[b'Never', b'tell', b'me', b'the', b'odds.']] [[b"It's", b'a', b'trap!']]