# التقطير المعرفي لرؤية الحاسوب

Knowledge distillation is a technique used to transfer knowledge from a larger, more complex model (teacher) to a smaller, simpler model (student). To distill knowledge from one model to another, we take a pre-trained teacher model trained on a certain task (image classification for this case) and randomly initialize a student model to be trained on image classification. Next, we train the student model to minimize the difference between its outputs and the teacher's outputs, thus making it mimic the behavior. It was first introduced in [Distilling the Knowledge in a Neural Network by Hinton et al](https://huggingface.co/papers/1503.02531). In this guide, we will do task-specific knowledge distillation. We will use the [beans dataset](https://huggingface.co/datasets/AI-Lab-Makerere/beans) for this.

يُبيّن هذا الدليل كيفية تقطير [نموذج ViT المُحسَّن](https://huggingface.co/merve/vit-mobilenet-beans-224) (نموذج المعلم) إلى [MobileNet](https://huggingface.co/google/mobilenet_v2_1.4_224) (نموذج الطالب) باستخدام [واجهة Trainer API](../main_classes/trainer#trainer) في 🤗 Transformers.

لنقم بتثبيت المكتبات اللازمة للتقطير وتقييم العملية.

```bash
pip install transformers datasets accelerate tensorboard evaluate trackio --upgrade
```

في هذا المثال، نستخدم نموذج `merve/beans-vit-224` كنموذج مُعلِّم. وهو نموذج لتصنيف الصور، مبني على `google/vit-base-patch16-224-in21k` وخضع لضبط الدقة على مجموعة بيانات beans. سنقوم بتقطير هذا النموذج إلى نموذج MobileNetV2 مُهيأ عشوائيًا.

سنقوم الآن بتحميل مجموعة البيانات.

```python
from datasets import load_dataset

dataset = load_dataset("AI-Lab-Makerere/beans")
```

يمكننا استخدام مُعالج صور من أيٍّ من النموذجين، ففي هذه الحالة يُرجِعان نفس المخرجات بنفس الدقة. سنستخدم طريقة `map()` الخاصة بـ`dataset` لتطبيق المعالجة المسبقة على كل تقسيم من مجموعات البيانات.

```python
from transformers import AutoImageProcessor
teacher_processor = AutoImageProcessor.from_pretrained("merve/beans-vit-224")

def process(examples):
    processed_inputs = teacher_processor(examples["image"])
    return processed_inputs

processed_datasets = dataset.map(process, batched=True)
```

في جوهر الأمر، نرغب في أن يحاكي النموذج الطالب (MobileNet مُهيّأ عشوائياً) النموذج المعلم (vision transformer المُحسَّن). لتحقيق ذلك، نحصل أولاً على مخرجات logits من النموذج المعلم والنموذج الطالب. ثم نقسم كل منهما على المعامل `temperature` الذي يتحكم في أهمية كل هدف ناعم. ويوزن معامل يُسمى `lambda` أهمية خسارة التقطير. في هذا المثال، سنستخدم `temperature=5` و`lambda=0.5`. سنستخدم خسارة تباعد كولباك-لايبلر (Kullback-Leibler Divergence) لحساب التباعد بين النموذج الطالب والنموذج المعلم. عند وجود بيانات P وQ، يوضح تباعد KL مقدار المعلومات الإضافية التي نحتاجها لتمثيل P باستخدام Q. إذا كانت البيانات متطابقة، يكون تباعد KL صفراً، إذ لا توجد معلومات أخرى مطلوبة لشرح P من Q. وبالتالي، في سياق تقطير المعرفة، يكون تباعد KL مفيداً.

```python
from transformers import TrainingArguments, Trainer
from accelerate import Accelerator
import torch
import torch.nn as nn
import torch.nn.functional as F

class ImageDistilTrainer(Trainer):
    def __init__(self, teacher_model=None, student_model=None, temperature=None, lambda_param=None,  *args, **kwargs):
        super().__init__(model=student_model, *args, **kwargs)
        self.teacher = teacher_model
        self.student = student_model
        self.loss_function = nn.KLDivLoss(reduction="batchmean")
        device = Accelerator().device
        self.teacher.to(device)
        self.teacher.eval()
        self.temperature = temperature
        self.lambda_param = lambda_param

    def compute_loss(self, student, inputs, return_outputs=False):
        student_output = self.student(**inputs)

        with torch.no_grad():
          teacher_output = self.teacher(**inputs)

        # Compute soft targets for teacher and student
        soft_teacher = F.softmax(teacher_output.logits / self.temperature, dim=-1)
        soft_student = F.log_softmax(student_output.logits / self.temperature, dim=-1)

        # Compute the loss
        distillation_loss = self.loss_function(soft_student, soft_teacher) * (self.temperature ** 2)

        # Compute the true label loss
        student_target_loss = student_output.loss

        # Calculate final loss
        loss = (1. - self.lambda_param) * student_target_loss + self.lambda_param * distillation_loss
        return (loss, student_output) if return_outputs else loss
```

سنسجّل الدخول الآن إلى Hugging Face Hub حتى نتمكن من دفع نموذجنا إلى Hugging Face Hub عبر `Trainer`.

```python
from huggingface_hub import notebook_login

notebook_login()
```

لنقم بتعيين `TrainingArguments` ونموذج المعلم ونموذج الطالب.

```python
from transformers import AutoModelForImageClassification, MobileNetV2Config, MobileNetV2ForImageClassification

training_args = TrainingArguments(
    output_dir="my-awesome-model",
    num_train_epochs=30,
    fp16=True,
    logging_strategy="epoch",
    eval_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    metric_for_best_model="accuracy",
    push_to_hub=True,
    hub_strategy="every_save",
    hub_model_id=repo_name,
    report_to="trackio",
    run_name="distillation",
    )

num_labels = len(processed_datasets["train"].features["labels"].names)

# initialize models
teacher_model = AutoModelForImageClassification.from_pretrained(
    "merve/beans-vit-224",
    num_labels=num_labels,
    ignore_mismatched_sizes=True
)

# training MobileNetV2 from scratch
student_config = MobileNetV2Config()
student_config.num_labels = num_labels
student_model = MobileNetV2ForImageClassification(student_config)
```

يمكننا استخدام دالة `compute_metrics` لتقييم نموذجنا على مجموعة الاختبار. ستُستخدم هذه الدالة أثناء عملية التدريب لحساب `accuracy` و `f1` لنموذجنا.

```python
import evaluate
import numpy as np

accuracy = evaluate.load("accuracy")

def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    acc = accuracy.compute(references=labels, predictions=np.argmax(predictions, axis=1))
    return {"accuracy": acc["accuracy"]}
```

لنقم بتهيئة `Trainer` باستخدام حُجج التدريب التي عرّفناها. كما سنقوم بتهيئة مُجمِّع البيانات الخاص بنا.

```python
from transformers import DefaultDataCollator

data_collator = DefaultDataCollator()
trainer = ImageDistilTrainer(
    student_model=student_model,
    teacher_model=teacher_model,
    training_args=training_args,
    train_dataset=processed_datasets["train"],
    eval_dataset=processed_datasets["validation"],
    data_collator=data_collator,
    processing_class=teacher_processor,
    compute_metrics=compute_metrics,
    temperature=5,
    lambda_param=0.5
)
```

يمكننا الآن تدريب نموذجنا.

```python
trainer.train()
```

يمكننا تقييم النموذج على مجموعة الاختبار.

```python
trainer.evaluate(processed_datasets["test"])
```

على مجموعة الاختبار، تصل دقة نموذجنا إلى 72 في المئة. ولإجراء فحص صحة لكفاءة التقطير، قمنا أيضاً بتدريب MobileNet على مجموعة بيانات الفول من الصفر باستخدام نفس المعلمات الفائقة، ولاحظنا دقة قدرها 63 في المئة على مجموعة الاختبار. ندعو القراء إلى تجربة نماذج معلمة مسبقة التدريب مختلفة، وهياكل طالب مختلفة، ومعلمات تقطير مختلفة، وإبلاغ نتائجهم. يمكن العثور على سجلات التدريب ونقاط التفتيش للنموذج المُقطَّر في [هذا المستودع](https://huggingface.co/merve/vit-mobilenet-beans-224)، ويمكن العثور على MobileNetV2 المُدرَّب من الصفر في هذا [المستودع](https://huggingface.co/merve/resnet-mobilenet-beans-5).

