Transformers documentation

Destilación de conocimiento para visión por computadora

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Destilación de conocimiento para visión por computadora

La destilación de conocimiento es una técnica que se utiliza para transferir conocimiento de un modelo más grande y complejo (el maestro) a un modelo más pequeño y simple (el estudiante). Para destilar conocimiento de un modelo a otro, tomamos un modelo maestro preentrenado en una tarea específica (clasificación de imágenes, en este caso) e inicializamos aleatoriamente un modelo estudiante que se entrenará para la clasificación de imágenes. A continuación, entrenamos el modelo estudiante para minimizar la diferencia entre sus salidas y las del maestro, de modo que imite su comportamiento. Esta técnica fue introducida por primera vez en Distilling the Knowledge in a Neural Network, de Hinton et al. En esta guía, realizaremos destilación de conocimiento específica de la tarea. Utilizaremos el conjunto de datos beans para ello.

Esta guía demuestra cómo puedes destilar un modelo ViT afinado (modelo maestro) a un MobileNet (modelo estudiante) utilizando la API de Trainer de 🤗 Transformers.

Instalemos las bibliotecas necesarias para la destilación y la evaluación del proceso.

pip install transformers datasets accelerate tensorboard evaluate trackio --upgrade

En este ejemplo, utilizamos el modelo merve/beans-vit-224 como modelo maestro. Es un modelo de clasificación de imágenes, basado en google/vit-base-patch16-224-in21k y ajustado en el conjunto de datos beans. Destilaremos este modelo en un MobileNetV2 inicializado aleatoriamente.

Ahora cargaremos el conjunto de datos.

from datasets import load_dataset

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

Podemos usar un procesador de imágenes de cualquiera de los modelos, ya que en este caso devuelven la misma salida con la misma resolución. Utilizaremos el método map() de dataset para aplicar el preprocesamiento a cada división del conjunto de datos.

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)

En esencia, queremos que el modelo estudiante (un MobileNet inicializado aleatoriamente) imite al modelo maestro (un vision transformer afinado). Para lograrlo, primero obtenemos los logits de salida del maestro y del estudiante. Luego, dividimos cada uno de ellos por el parámetro temperature, que controla la importancia de cada objetivo suave. Un parámetro llamado lambda pondera la importancia de la pérdida de destilación. En este ejemplo, utilizaremos temperature=5 y lambda=0.5. Utilizaremos la pérdida de Divergencia de Kullback-Leibler para calcular la divergencia entre el estudiante y el maestro. Dadas dos distribuciones P y Q, la Divergencia de KL explica cuánta información adicional necesitamos para representar P usando Q. Si ambas son idénticas, su divergencia de KL es cero, ya que no se necesita otra información para explicar P a partir de Q. Por lo tanto, en el contexto de la destilación de conocimiento, la divergencia de KL resulta útil.

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

Ahora iniciaremos sesión en Hugging Face Hub para poder subir nuestro modelo al Hugging Face Hub a través de Trainer.

from huggingface_hub import notebook_login

notebook_login()

Establezcamos los TrainingArguments, el modelo maestro y el modelo estudiante.

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)

Podemos usar la función compute_metrics para evaluar nuestro modelo en el conjunto de prueba. Esta función se utilizará durante el proceso de entrenamiento para calcular la accuracy y la f1 de nuestro modelo.

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"]}

Iniciemos el Trainer con los argumentos de entrenamiento que definimos. También inicializaremos nuestro data collator.

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
)

Ahora podemos entrenar nuestro modelo.

trainer.train()

Podemos evaluar el modelo en el conjunto de prueba.

trainer.evaluate(processed_datasets["test"])

En el conjunto de prueba, nuestro modelo alcanza una precisión del 72 por ciento. Para verificar la eficiencia de la destilación, también entrenamos MobileNet desde cero en el conjunto de datos beans con los mismos hiperparámetros y observamos una precisión del 63 por ciento en el conjunto de prueba. Invitamos a los lectores a probar diferentes modelos de maestro preentrenados, arquitecturas de estudiante y parámetros de destilación, y a reportar sus hallazgos. Los registros de entrenamiento y los puntos de control del modelo destilado se pueden encontrar en este repositorio, y MobileNetV2 entrenado desde cero se puede encontrar en este repositorio.

Update on GitHub