احسان تصمیم دارد به منظور اجرای مدل برت فارسی (*[HooshvareLab/bert-fa-zwnj-base](https://huggingface.co/HooshvareLab/bert-fa-zwnj-base)*) یکی از روشهای هرس کردن یا گسستهسازی را به کار بگیرد. او حدس میزند که برخی از لایهها یا هدهای مدل برت نقش زیادی در تولید خروجی ندارند.
احسان از درس یادگیری ماشین متوجه شده که ویژگیهایی که در نمونههایی با برچسبهای متفاوت، مقدار یکسانی دارند، احتمالا ویژگی مناسبی برای طراحی یک مدل طبقهبند (*Classifier*) نیستند. و با توجه به این موضوع تصمیم گرفته است، یک آزمایش طراحی و لایهها و هدها را براساس میزان اهمیتشان در تولید خروجی دستهبندی کند.
برای پیادهسازی این آزمایش به احسان کمک کنید:
## بخش اول
به ازاء تک تک توکنهایی که در *Tokenizer* برت موجود است، بردار *Embedding* مربوط به همان یک توکن را در هر **لایه** رمزگذار (*Encoder*) محاسبه کنید و سپس مقدار *IQR* مربوط به پراکندگی ماکزیمم قدرمطلق (*MaxAbs*) درایههای آن بردار را برای کل توکنها بدست آورید.
<details class="violet">
<summary>**توضیح بیشتر**</summary>
تک تک توکنها را بعد از عبور دادن از لایه *Embedding* به اولین لایه رمزگذار بدهید و بردار *Embedding* مربوط به همان توکن را گرفته و ماکزیمم قدرمطلق درایههای آن را در نظر بگیرید، سپس برای این مقادیر بهدست آمده برای تک تک توکنها مقدار `IQR` را محاسبه کنید و برای هر لایه در یک فایل `CSV` در ستون اول شماره لایه از صفر تا ۱۱ و در ستون دوم مقدار `IQR` مربوط به آن لایه را گزارش کنید.
</details>
### نمونه خروجی بخش اول
برای خروجی این بخش شما باید یک فایل با نام `result_1.csv` که شامل دو ستون با نامهای `layer_num` و `IQR` میباشد را مطابق خواسته مسئله بارگذاری کنید. جدول زیر چند سطر اولیه از نمونهی خروجی میباشد. (دقت داشته باشید که این اعداد برای نمونه هستند و الزامی به درستی آنها نیست)
|layer_num|IQR|
|:-:|:-:|
|0|2.102|
|1|3.253|
|2|1.098|
## بخش دوم
احسان پس از انجام مرحلهی اول آزمایش، یک مرحله جدیدی را طراحی کرده است، در این مرحله شما باید **دقیقا مشابه کاری که در قسمت قبل انجام شده** را برای هر کدام از **هدها** در هر لایه انجام دهید و در یک فایل `CSV` در ستون اول شماره لایه از صفر تا ۱۱ و در ستون دوم شماره هد از صفر تا ۱۱ و در ستون سوم نیز مقدار `IQR` مربوط به آن هد را گزارش کنید.
### نمونه خروجی بخش دوم
برای خروجی این بخش شما باید یک فایل با نام `result_2.csv` که شامل سه ستون با نامهای `layer_num`، `head_num` و `IQR` میباشد را مطابق خواسته مسئله بارگذاری کنید. جدول زیر چند سطر اولیه از نمونهی خروجی میباشد. (دقت داشته باشید که این اعداد برای نمونه هستند و الزامی به درستی آنها نیست)
<details class="red">
<summary>**توجه!**</summary>
ترتیب ردیفهای جدول ابتدا باید براساس ستون `layer_num` و سپس براساس ستون `head_num` (هردو) بهصورت صعودی، باشد.
</details>
|layer_num|head_num|IQR|
|:-:|:-:|:-:|
|0|0|2.102|
|0|1|3.253|
|0|2|1.098|
## بخش سوم
وزنهای لایه `word_embedding`، هرکدام یک امبدینگ برای توکن های توکنایزر هستند. با توجه به این بردارهای امبدینگ، برای **هر دو** توکن داده شده، میانگین بردارهای امبدینگ را محاسبه کنید و سپس یکبار با استفاده از معیار **فاصله اقلیدسی (Euclidean Distance)** و بار دیگر با استفاده از معیار **شباهت کسینوسی (Cosine Similiraty)** توکنی که بردار مربوط به آن کمترین فاصله را از میانگین این دو توکن دارد بدست آورید:
1. شهر ، روستا
2. تهران ، ایران
3. مرد ، زن
خروجی این مرحله را به صورت یک فایل با نام `result_3.csv` که در ستون اول شماره سوال و در ستون دوم نزدیکترین توکن از نظر فاصله اقلیدسی و در ستون سوم نزدیکترین توکن از نظر شباهت کسینوسی درج شده است، ارسال نمایید.
### نمونه خروجی بخش سوم
نمونه خروجی این بخش به این صورت خواهد بود: (دقت داشته باشید که این اعداد برای نمونه هستند و الزامی به درستی آنها نیست)
|q_id|euclidean|cosine|
|:-:|:-:|:-:|
|1|لندن|پاریس|
|2|پسر|مرد|
## خروجی نهایی
در نهایت برای ارسال پاسخ این سوال سه فایل `result_1.csv` , `result_2.csv` و `result_3.csv` را فشرده (`zip`) کنید و با نام `result.zip` ارسال کنید.
آزمایش احسان
| مجموعهدادهی سوال را میتوانید از [این لینک](/contest/assignments/65406/download_problem_initial_project/223477/) دانلود کنید.|
| :--: |
آزمایشگاه پردازش زبان طبیعی (*Natural Language Processing*) دانشگاه فناور اندیشان قصد توسعه یک **مجموعهدادهی فارسی (Dataset)** را دارد. اعضاء این آزمایشگاه تصمیم گرفتهاند بعد از جمعآوری مجموعهداده اقدام به پیشپردازش آنها کنند. برای انجام این کار مراحلی طراحی شدهاست که به شرح زیر است:
### پرسش اول
برای هر فایل، نسبت تعداد **نویسهای (Character)** که بیشترین فراوانی را دارد به تعداد کل نویسههای آن فایل را تعیین کنید.
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_1.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `char_ratio` نسبت تعداد نویسهای که بیشترین فراوانی را دارد به تعداد کل نویسههای آن فایل را درج کنید. (دقت داشته باشید این اعداد و نامها برای نمونه هستند و الزامی به درستی آنها نیست.)
|file_name|char_ratio|
|:-:|:-:|
|1.txt|0.2|
|2.txt|0.3|
### پرسش دوم
برای هر فایل، نسبت تعداد **کلمه** (هر کلمه عبارتی است که بین دو فاصله قرار میگیرد) که بیشترین فراوانی را دارد به تعداد کل کلمات آن فایل را تعیین کنید.
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_2.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `word_ratio` نسبت تعداد کلمهای که بیشترین فراوانی را دارد به تعداد کل کلمات آن فایل را درج کنید. (دقت داشته باشید این اعداد و نامها برای نمونه هستند و الزامی به درستی آنها نیست.)
|file_name|word_ratio|
|:-:|:-:|
|1.txt|0.2|
|2.txt|0.3|
### پرسش سوم
برای هر فایل، نسبت تعداد **خطی** (انتهای خط شامل کاراکترهای `\n` یا `\r` می شود) که بیشترین فراوانی را دارد به تعداد کل خطهای آن فایل را تعیین کنید.
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_3.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `line_ratio` نسبت تعداد خطی که بیشترین فراوانی را دارد به تعداد کل خطوط آن فایل را درج کنید. (دقت کنید در تمامی قسمتها خروجی نمونه است و الزاماً جواب درست نیستند.)
|file_name|line_ratio|
|:-:|:-:|
|1.txt|0.2|
|2.txt|0.3|
### پرسش چهارم
برای هر فایل، نسبت تعداد **خطوط کوتاه** به تعداد کل خطهای آن فایل را تعیین کنید. خط کوتاه، خطی است که **کمتر از ۱۰۰ کاراکتر** داشته باشد و انتهای خط شامل نویسههای `\n` یا `\r` میشود.
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_4.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `short_line_ratio` نسبت تعداد خطوط کوتاه به کل خطوط آن فایل را درج کنید. (دقت کنید در تمامی قسمتها خروجی نمونه است و الزاماً جواب درست نیستند.)
|file_name|short_line_ratio|
|:-:|:-:|
|1.txt|0.2|
|2.txt|0.3|
### پرسش پنجم
برای هر فایل زبان اول و دوم (دو زبانی که متن فایل با بیشترین احتمال متعلق به آن زبانهاست) و احتمال مربوط به هر کدام را تعیین کنید. (برای تشخیص زبان متن از مدل موجود در [این لینک](https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.ftz) استفاده کنید و در ورودی مدل نویسههای `\n` و `\r` را حذف کنید.)
<details class="violet">
<summary>**مثال**</summary>
برای مثال متن زیر را در نظر بگیرید:
|پردازش زبان طبیعی یک وظیفه بسیار چالش برانگیز است، مثل تفسیر شعر الا یا ایهاالساقی ادر کاسا ونا ولها|
|:-:|
این متن با احتمال 0.9036 درصد فارسی و با احتمال 0.0123 درصد عربی است.
</details>
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_5.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `1st_language` اولین پیشبینی و در ستون سوم با نام `1st_percentage` احتمال آن (اولین پیشبینی) و در ستون چهارم با نام `2nd_language` دومین پیشبینی و در ستون پنجم با نام `2nd_percentage` احتمال آن (دومین پیشبینی) را درج کنید. (دقت داشته باشید این اعداد و نامها برای نمونه هستند و الزامی به درستی آنها نیست.)
|file_name|1st_language|1st_percentage|2nd_language|2nd_percentage|
|:-:|:-:|:--:|:-:|:-:|
|1.txt|fa|0.9036|ar|0.0141|
|2.txt|fa|0.8934|ar|0.1012|
### پرسش ششم
برای هر کدام از فایلها با استفاده از مدل زبانی [HooshvareLab/gpt2-fa](https://huggingface.co/HooshvareLab/gpt2-fa) معیار **perplexity** را محاسبه کنید.
<details class="yellow">
<summary>**راهنمایی**</summary>
معیار *perplexity* به این صورت حساب میشود که از ابتدای متن شروع کرده و هر بار یک پنجره با طول حداکثر ۲۵۶ (`max_length=256`)(که البته در انتهای متن این پنجره ممکن است به خاطر گام آخر، طول کمتری داشته باشد) در نظر گرفته و با استفاده از مدل احتمال کلمه بعدی در خود متن را بهدست آورید و با استفاده از تابع هزینه `CrossEntropyLoss` مقدار **خطا (loss)** را محاسبه کنید و این کار را تا آخر متن ادامه دهید و پنجره را در هر مرحله ۶۴ (`stride=64`) واحد جلو ببرید و نهایتا از تمام خطاها میانگین بگیرید)
توضیحات بیشتر مربوط به معیار *perplexity* و نحوهی محاسبه آن را میتوانید در [این لینک](https://web.stanford.edu/~jurafsky/slp3/3.pdf) ببینید.
</details>
#### خروجی نمونه
برای خروجی این بخش در یک فایل با نام `result_6.csv`، در ستون اول با نام `file_name` نام فایل و در ستون دوم با نام `perplexity` مقدار معیار *perplexity* را درج کنید. (دقت داشته باشید این اعداد و نامها برای نمونه هستند و الزامی به درستی آنها نیست.)
|file_name|perplexity|
|:-:|:-:|
|1.txt|5.09|
|2.txt|4.54|
## خروجی نهایی
در نهایت برای ارسال پاسخ این سوال شش فایل `result_1.csv` ، `result_2.csv` ، `result_3.csv` ، `result_4.csv` ،`result_5.csv` و `result_6.csv` را فشرده (`zip`) کنید و با نام `result.zip` ارسال کنید.
فارسیبازی
جلال بعد از مشاهده نتایج آزمایشهایی که احسان در سوال اول روی مدل برت *[(HooshvareLab/bert-fa-zwnj-base)](https://huggingface.co/HooshvareLab/bert-fa-zwnj-base)* انجام داده بود این ایده به ذهنش رسید که برخی از بلوکهای مدل را حذف کند تا مدل کوچکتر و سریعتر شود، اما طبیعی است که با این کار مدل به درستی کار نخواهد کرد و نیاز به تنظیمدقیق (fine-tuning) مجدد دارد. برای اینکار جلال فقط ایدهی پردازی کرده است و از شما میخواهد پیادهسازی ایدههایش را انجام دهید.
جلال از شما میخواهد، از مدل پایه فقط لایههای شماره صفر، ۴، ۸ و ۱۱ را نگهدارید و بقیه را حذف کنید. جالب است که در نهایت جلال اسم این مدل را «جلالبرت» گذاشت!
ابتدا به عنوان **مدل پایه (baseline)** تصمیم به ارزیابی «جلالبرت» گرفت و برای این کار به ازاء تمام توکنهایی که در *Tokenizer* مدل وجود داشت خروجی **لایه آخر** را با خروجی **لایه آخر مدل هوشواره** مقایسه کرد و میانگین تابع هزینه را بر اساس تابع **Kullback-Leibler Divergence** و **MSE** به طور جداگانه محاسبه کرد.
سپس تصمیم به تنظیمدقیق مدل گرفت.این تنظیم دقیق به صورت **لایه به لایه (layer-wise)** انجام میشود. توجه کنید که تناظر زیر بین لایه های مدل هوشواره و «جلالبرت» وجود دارد:
| شماره لایه در برت هوشواره | شماره لایه در «جلالبرت» |
|:-:|:-:|
| لایه صفر| لایه صفر|
| لایه چهارم| لایه اول|
| لایه هشتم| لایه دوم|
| لایه یازدهم| لایه سوم|
برای سادگی و کاهش هزینه در این مرحله، ورودی مدل برای تنظیم دقیق، همان توکنهای موجود در *Tokenizer* مدل هستند.
برای تنظیمدقیق لایه $i$ام از «جلالبرت» که $i=1,2,3,4$ است، ابتدا وزن لایههای قبل را ثابت نگه میداریم (**freeze**) و سپس **تابع هزینه (loss)** را بین خروجی این لایه و لایه متناظرش در مدل برت هوشواره محاسبه و با فرایند **انتشار رو به عقب (backpropagation)** وزنهای آن لایه را بهروزرسانی میکنیم. این کار را از $i=1$ شروع میکنیم و تا $i=4$ ادامه میدهیم. مجدداً توجه شود که در حین تنظیمدقیق یک لایه باید وزن تمام لایههای قبل از آن ثابت نگه داشته شوند.
تمام این مراحل را یکبار با تابع هزینه **میانگین مربعات خطا (MSE)** و بار دیگر با تابع هزینه **Kullback-leibler Divergence** انجام میدهیم.
برای تنظیم دقیق با استفاده از تابع هزینه **Kullback-leibler Divergence** در صورت استفاده از تابع هزینه کتابخانه `pytorch` برچسبها (*labels*) را از تابع `softmax` و پیش بینیها (*predictions*) را از تابع `log_softmax` عبور دهید. در کتابخانههای دیگر طبق مستندات کتابخانه مشابه این کار را انجام دهید.
برای تنظیم دقیق هر لایه از تنظیمات زیر استفاده کنید:
```python
Num_epoch = 10
Optimizer = Adam
Learning_rate = 2e-5
Batch_size = 32
```
## خروجی نهایی
بعد از انجام تنظیمدقیق، یک پوشه به نام `model` بسازید و دو پوشه `kld` و `mse` داخل آن ایجاد کرده و هر کدام از مدلها را در پوشه مربوط به خود قرار دهید و بعد از فشرده کردن پوشه آن را با نام `model.zip` در گوگل درایو خود آپلود کنید (جهت سهولت ارسال)، سپس لینک اشتراک فایل را (فراموش نکنید که دسترسی اشتراک لینک به صورت view داشته باشد) در یک فایل solution.txt قرار دهید و این فایل را برای داوری ارسال کنید.
یعنی تنها ارسال شما یک فایل solution.txt خواهد بود که لینک فایل `model.zip` آپلود شده در گوگل درایو را در خود دارد.
حجم هر مدل ارسالی حداکثر ۲۷۰ مگابایت باید باشد و با قطعه کد زیر قابل بارگذاری و استفاده باشد:
```python
from transformers import AutoModel
model = AutoModel.from_pretrained(“path/to/your/model/folder”)
output = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids= token_type_ids)
```
ضمناً خروجی لایه صفر و ۱ و ۲ و ۳ مدل برت ۴ لایه شما به ترتیب به صورت زیر برای محاسبه تابع هزینه باید قابل دسترسی باشد:
```python
output_of_layer_i = output.hidden_states[i+1]
```
جلالبرت!
| محتوای مربوط یه این سوال را میتوانید از [این لینک](/contest/assignments/65406/download_problem_initial_project/223713/) دانلود کنید.|
| :--: |
نسترن این ترم برای درس مدلهای زبانی بزرگ (*Large Language Model*) باید یک کد **تنظیمدقیق (fine tune)** برای یک مدل زبانی توسعه دهد. او پس از جستجو در مخزنهای کد موجود یک کد نسبتاً مناسب پیدا کرده است اما نمیتواند این کد را اجرا کند.
این کد یک مدل زبانی از نوع gpt-2 که روی نظرات فارسی تنظیمدقیق، شده است به آدرس [(HooshvareLab/gpt2-fa)](https://huggingface.co/HooshvareLab/gpt2-fa) را روی یک مجموعهدادهی ترجمه شده از *alpaca* به زبان فارسی تنظیمدقیق میکند. مجموعهداده در فولدر `dataset` موجود است. دستور (*Prompt*) مورد استفاده نیز در فولدر `utils` قرار داده شده است. به نسترن کمک کنید که بتواند این کدها را روی Colab و با تنظیمات زیر اجرا کند.
``` python
batch_size=64
num_epochs=2
learning_rate=3e-5
lr_schedular=cosine
optimizer=admaw-torch
Warmup_ratio=0.05
warmup_steps=10
max_seq_length=1024
```
در ضمن تنظیمات آموزش مدل را به نحوی قرار دهید که:
+ از *mixed precision training* با تنظیمات `fp16` استفاده شود
+ در هر ۵۰ مرحله (*step*) یک نسخه از **مدل** ذخیره شود و **حداکثر** ۳ نسخه آخر از مدل نگه داشته شود.
+ در هر ۱۰ مرحله (*step*) **مقدار تابع هزینه** و **نرخ یادگیری (Learning Rate)** و درصد پیشرفت هر **ایپاک (ِ*Epoch*)** در خروجی چاپ شود.
+ خروجی مدل به صورت `safetensors` ذخیره شود
+ نام پروژه در `wandb` به صورت `LLM-Hackathon` باشد.
## خروجی نهایی
فایلهای تکمیل شده خود را نیز شامل فولدرها و فایل زیر به صورت فشرده شده با نام `result.zip` و با همان ساختار فعلی پروژه ذخیره کنید و ارسال کنید.
+ از فولدر `/results` پوشه و محتویات فولدر `pt_lora_model` و فایل `result.log`
+ فولدر `/Arguments`
+ فولدر `/models`
+ فولدر `/utils`
+ فایل `requirements.txt`
+ فایل `run.sh`
+ فایل `run_model.py`
+ فایل `main.py`
پروژه نسترن
بهمنظور جلوگیری از هر گونه تقلب و شبهههای احتمالی که منجر به ضایع شدن حق شما شود، لازم است هر تیم فایل کد سوالات **یک**، **دو** و **سه** را ( فایل `.py`) در قالب **یک** فایل زیپ در اینجا بارگذاری کند.
## در صورتی که پس از پایان زمان مسابقه، این فایل توسط شما بارگذاری نشده باشد، شما از جدول مسابقات **حذف** خواهید شد.
توجه داشته باشید که اگر از `jupter notebook` استفاده می کنید, بایستی که از قسمت `file` و زیرقسمت `Download` خروجی `.py` را دریافت و آن را ارسال کنید. ارسال فایلهای `jupyter` مانند `.ipynb` مورد قبول واقع نخواهند شد و **فقط فایل `.py`** پذیرفته میشود.
بنابراین بهازای هر سوال (برای سوالات **آزمایش احسان**، **فارسی بازی** و **جلالبرت!**) (که به آن پاسخ دادهاید) ، یک فایل کد برای آن سوال ایجاد و تمامی کدهای مربوط به آن سوال را در آن قرار دهید. در نهایت، همه فایلها را زیپ کرده و در این قسمت **فقط یک فایل زیپ** ارسال کنید.
یعنی سه فایل با نامهای `q1.py` و `q2.py` و `q3.py` را زیپ کرده و فقط همان یک فایل زیپ را در این سوال بارگذاری کنید.
# توجه: از ارسال دادهها بپرهیزید!