آموزش پردازش زبان طبیعی با اکوسیستم هاگینگ فیس ؛ مدیریت چندین توالی ورودی (قسمت پنجم فصل دوم)
در این قسمت از دوره رایگان آموزش پردازش زبان طبیعی به مدیریت چندین توالی ورودی خواهیم پرداخت. سادهترین موارد کاربرد (یعنی استنباط گیری از یک توالی با طول اندک) در بخش پیشین بررسی شد. با این حال، باید پاسخ مناسبی به پرسشهای زیر داده شود:
- مدیریت چندین توالی چگونه است؟
- مدیریت چندین توالی با طول مختلف چگونه است؟
- آیا شاخصهای واژگانی تنها ورودیهایی هستند که زمینه را برای کارکرد خوبِ مدل فراهم میکنند؟
- آیا امکان دارد یک توالی بیش از حد طولانی باشد؟
در بخش زیر خواهید دید که این قبیل از پرسشها به چه مسائلی میانجامد. نحوهی حل این مسائل با ترنسفورمر API نیز توضیح داده میشود. ابتدا ویدئو زیر را تماشا کنید:
ویدئو نحوهی حل این مسائل با ترنسفورمر API
مدلها به دسته یا بچ از ورودیها نیاز دارند
در تمرین پیشین، دیدید که توالیها چگونه به لیستی از اعداد تبدیل میشوند. اینک، بیایید این لیست اعداد را به یک تنسور تبدیل و به مدل ارسال کنیم:
import tensorflow as tf from transformers import AutoTokenizer, TFAutoModelForSequenceClassification checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" tokenizer = AutoTokenizer.from_pretrained(checkpoint) model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) sequence = "I've been waiting for a HuggingFace course my whole life." tokens = tokenizer.tokenize(sequence) ids = tokenizer.convert_tokens_to_ids(tokens) input_ids = tf.constant(ids) # This line will fail. model(input_ids) . InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape]
وای! چرا این کار با موفقیت به پایان نرسید؟ مراحل پایپلاین در بخش 2 پیادهسازی شدند. (در انتهای مطلب میتوانید به دیگر قسمتهای این دوره آموزش پردازش زبان طبیعی دسترسی داشته باشید).
مشکل اینجاست که یک توالی به مدل ارسال کردیم، اما مدلهای ترنسفورمر به طور پیشفرض نیازمند چندین توالی هستند. در این بخش سعی کردیم تمام کارهای پشت صحنه توکنکننده را در صورت بهکارگیری در توالی پوشش دهیم. اما اگر با دقت به این موضوع نگاه کنید، میبینید که توکنکننده صرفاً لیست شناسههای ورودی را به تنسور تبدیل نکرده است، بلکه شاهد اضافه شدن یک بُعد در بالای آن هستیم:
tokenized_inputs = tokenizer(sequence, return_tensors="tf") print(tokenized_inputs["input_ids"]) . <tf.Tensor: shape=(1, 16), dtype=int32, numpy= array([[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102]], dtype=int32)>
اینک، بیایید دوباره امتحان کنیم و بُعد جدیدی بیفزاییم:
import tensorflow as tf from transformers import AutoTokenizer, TFAutoModelForSequenceClassification checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" tokenizer = AutoTokenizer.from_pretrained(checkpoint) model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) sequence = "I've been waiting for a HuggingFace course my whole life." tokens = tokenizer.tokenize(sequence) ids = tokenizer.convert_tokens_to_ids(tokens) input_ids = tf.constant([ids]) print("Input IDs:", input_ids) output = model(input_ids) print("Logits:", output.logits)
باید شناسههای ورودی و توابع لوجیت را چاپ کرد. به خروجی کار توجه کنید:
Input IDs: tf.Tensor( [[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 2166 1012]], shape=(1, 14), dtype=int32) Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32)
دستهبندی Batching به عمل ارسالِ همزمان چندین توالی به مدل اطلاق میشود. اگر فقط یک جمله داشته باشید، میتوانید دستهای با یک توالی ایجاد کنید:
batched_ids = [ids, ids]
این دسته دو توالی مشابه دارد.
خودتان امتحان کنید: لیست batched_ids را به تنسور کرده و به مدل انتقال دهید. به این موضوع توجه داشته باشید که باید توابع لوجیت یکسانی مثل قبل به دست بیاورید. عمل دستهبندی این امکان را در اختیار مدل قرار میدهد تا در صورت رویارویی با چندین توالی به فعالیت عادی خود ادامه دهد. استفاده از چندین توالی هم مثل ساختن دسته با یک توالی آسان است. البته مسئله دیگری هم وجود دارد. اگر میخواهید دو جمله را به صورت دستهای کنار یکدیگر قرار دهید، ممکن است آن جملات طول متفاوتی داشته باشند. اگر پیشتر با تنسورها کار کرده باشید، احتمالاً میدانید که آنها باید شکل مستطیلی داشته باشند؛ بنابراین، قادر نخواهید بود این لیست شناسههای ورودی را به طور مستقیم به تنسور تبدیل کنید. شاید بهتر است از عمل پدینگ Padding استفاده کنید.
پدینگ کردن ورودیها
امکان تبدیل لیست زیر به تنسور وجود ندارد:
batched_ids = [ [200, 200, 200], [200, 200] ]
برای اینکه در این بخش به اهداف مورد نظر دست یابیم، باید از عمل پدینگ برای اطمینان حاصل کردن از شکل مستطیلیِ تنسورها استفاده کنیم. پدینگ با افزودن واژه خاصی به نام padding token به جملات این اطمینان را میدهد که کلیه جملات طول یکسانی خواهند داشت. برای نمونه، اگر 10 جمله با 10 واژه و یک جمله با 20 واژه داشته باشید، پدینگ به نحوی عمل خواهد کرد که کلیه جملات 20 واژه داشته باشند. در مثال ما، تنسورِ بدست آمده به شکل زیر خواهد بود:
padding_id = 100 batched_ids = [ [200, 200, 200], [200, 200, padding_id] ]
شناسه پدینگ توکن padding token ID در tokenizer.pad_token_id قابل دسترس است. بیایید از این ابزار استفاده کرده و دو جمله را به طور جداگانه در اختیار مدل قرار دهیم:
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) sequence1_ids = [[200, 200, 200]] sequence2_ids = [[200, 200]] batched_ids = [ [200, 200, 200], [200, 200, tokenizer.pad_token_id] ] print(model(tf.constant(sequence1_ids)).logits) print(model(tf.constant(sequence2_ids)).logits) print(model(tf.constant(batched_ids)).logits)
.
tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) tf.Tensor( [[ 1.5693681 -1.3894582] [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32)
توابع لوجیت در پیشبینیهای ما ایراد دارند؛ سطر دوم باید مثل لوجیتهای جملهی دوم باشد، اما مقادیر کاملاً متفاوتی به دست آمده است. دلیل مشکل فوق این است که لایههای توجه به عنوان ویژگی کلیدیِ مدلهای ترنسفورمر به شمار میروند. این لایهها نقش موثری در مفهومسازی زمینهای Contextualize هر یک از توکنها دارند. در این فرایند، توکنهای پدینگ حتماً مد نظر قرار خواهند گرفت زیرا به همه توکنهای توالی Sequence میپردازند. برای اینکه هنگام انتقال تکتک جملات به مدل که طول مختلفی دارند، نتیجه یکسانی بگیرید، باید به کلیه لایههای توجه دستور دهید تا از توکنهای پدینگ چشمپوشی کنند. این کار با استفاده از ماسک توجه Attention mask صورت میپذیرد.
ماسکهای توجه
ماسکهای توجه به تنسورهایی گفته میشود که شکلشان دقیقاً مثل تنسور شناسههای ورودی است و با صفر و یک پر شدهاند. اعداد 1 نشاندهندهی توکنهایی هستند که نیاز به بررسی دارند و اعداد صفر به توکنهایی اشاره دارد که نیازمند بررسی نیستند. حال بیایید نمونه پیشین را با یک ماسک توجه تکمیل کنیم:
batched_ids = [ [200, 200, 200], [200, 200, tokenizer.pad_token_id] ] attention_mask = [ [1, 1, 1], [1, 1, 0] ] outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) print(outputs.logits)
.
tf.Tensor( [[ 1.5693681 -1.3894582 ] [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32)
اینک، لوجیتهای یکسانی برای جمله دوم در دسته به دست میآید. توجه داشته باشید که رقم آخرِ توالی دوم یک شناسه پدینگ به حساب میآید و در ماسک توجه از مقدار صفر برخوردار است.
خودتان امتحان کنید: عمل توکنسازی را به صورت جداگانه در دو جملهی مورد استفاده در بخش 2 انجام دهید. آنها را به مدل انتقال دهید و مطمئن شوید که لوجیتهای یکسانی در بخش 2 به دست میآیند. اکنون، آنها را با استفاده از padding token کنار یکدیگر قرار دهید؛ سپس، ماسک توجه مناسبی ایجاد کنید. مطمئن شوید که با بهکارگیری مدل به نتایج یکسانی میرسید.
توالیهای طولانیتر
یکی از ویژگیهای مدلهای ترنسفورمر این است که طول جملاتی که در اختیار مدل قرار میگیرد، باید محدود باشد. اکثر مدلها میتوانند توالیهایی با 512 یا 1024 توکن را به خوبی مدیریت کنند. اما اگر توالیهای طولانیتری برای پردازش در اختیارشان قرار داده شود، کارایی لازم را نخواهند داشت. دو راهکار برای این مسئله پیشنهاد شده است:
- استفاده از مدلی با طول توالی بیشتر
- کاهش طول توالیها
مدلها طول توالی متفاوتی دارند و برخی از آنها توالیهای بسیار طویل را به خوبی مدیریت میکنند. Longformer و LED نمونه بارزی از این مدلها برشمرده میشوند. اگر بر روی پروژهای کار میکنید که به توالیهای بسیار بلندی نیاز دارد، پیشنهاد میکنیم به این مدلها نگاه کنید. در غیر این صورت، توصیهمان این است که توالیهایتان را با تصریح پارامتر max_sequence_length کوتاهتر کنید:
sequence = sequence[:max_sequence_length]
برای مشاهده باقی قسمتهای این دوره وارد لینک زیر شوید:
[button href=”https://hooshio.com/%D8%B1%D8%B3%D8%A7%D9%86%D9%87-%D9%87%D8%A7/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B7%D8%A8%DB%8C%D8%B9%DB%8C/” type=”btn-default” size=”btn-lg”]آموزش پردازش زبان طبیعی[/button]