Accelerare i tuoi modelli con 🤗 Optimum Intel e OpenVINO

'Accelerate your models with 🤗 Optimum Intel and OpenVINO'

Lo scorso luglio, abbiamo annunciato che Intel e Hugging Face avrebbero collaborato per costruire strumenti di accelerazione hardware all’avanguardia ma semplici per i modelli Transformer. Oggi, siamo molto felici di annunciare che abbiamo aggiunto Intel OpenVINO a Optimum Intel. Ora puoi facilmente eseguire inferenze con OpenVINO Runtime su una varietà di processori Intel (vedi l’elenco completo dei dispositivi supportati) utilizzando modelli Transformers che possono essere ospitati sia sul hub di Hugging Face che localmente. Puoi anche quantizzare il tuo modello con il framework di compressione delle reti neurali OpenVINO (NNCF) e ridurne dimensioni e latenza di predizione in pochi minuti.

Questa prima versione si basa su OpenVINO 2022.2 e consente inferenze per una grande quantità di modelli PyTorch utilizzando i nostri OVModels. La quantizzazione statica post-addestramento e l’addestramento consapevole della quantizzazione possono essere applicati a molti modelli di encoder (BERT, DistilBERT, ecc.). Altri modelli di encoder saranno supportati nella prossima versione di OpenVINO. Attualmente, la quantizzazione dei modelli Encoder Decoder non è abilitata, tuttavia questa restrizione dovrebbe essere rimossa con la nostra integrazione della prossima versione di OpenVINO.

Permettici di mostrarti come iniziare in pochi minuti!

Quantizzazione di un Vision Transformer con Optimum Intel e OpenVINO

In questo esempio, eseguiremo la quantizzazione statica post-addestramento su un modello Vision Transformer (ViT) addestrato per la classificazione delle immagini sul dataset food101.

La quantizzazione è un processo che riduce i requisiti di memoria e calcolo riducendo la larghezza in bit dei parametri del modello. Ridurre il numero di bit significa che il modello risultante richiede meno memoria durante l’inferenza e che le operazioni come la moltiplicazione di matrici possono essere eseguite più velocemente grazie all’aritmetica intera.

Prima di tutto, creiamo un ambiente virtuale e installiamo tutte le dipendenze.

virtualenv openvino
source openvino/bin/activate
pip install pip --upgrade
pip install optimum[openvino,nncf] torchvision evaluate

Successivamente, passando a un ambiente Python, importiamo i moduli appropriati e scarichiamo il modello originale e il suo estrattore di caratteristiche.

from transformers import AutoFeatureExtractor, AutoModelForImageClassification

model_id = "juliensimon/autotrain-food101-1471154050"
model = AutoModelForImageClassification.from_pretrained(model_id)
feature_extractor = AutoFeatureExtractor.from_pretrained(model_id)

La quantizzazione statica post-addestramento richiede una fase di calibrazione in cui i dati vengono alimentati attraverso la rete per calcolare i parametri di attivazione quantizzati. Qui, prendiamo 300 campioni dal dataset originale per costruire il dataset di calibrazione.

from optimum.intel.openvino import OVQuantizer

quantizer = OVQuantizer.from_pretrained(model)
calibration_dataset = quantizer.get_calibration_dataset(
    "food101",
    num_samples=300,
    dataset_split="train",
)

Come al solito con i dataset di immagini, dobbiamo applicare le stesse trasformazioni delle immagini utilizzate durante l’addestramento. Utilizziamo la pre-elaborazione definita nell’estrattore di caratteristiche. Definiamo anche una funzione di aggregazione dei dati per alimentare al modello lotti di tensori correttamente formattati.

import torch
from torchvision.transforms import (
    CenterCrop,
    Compose,
    Normalize,
    Resize,
    ToTensor,
)

normalize = Normalize(mean=feature_extractor.image_mean, std=feature_extractor.image_std)
_val_transforms = Compose(
    [
        Resize(feature_extractor.size),
        CenterCrop(feature_extractor.size),
        ToTensor(),
        normalize,
    ]
)
def val_transforms(example_batch):
    example_batch["pixel_values"] = [_val_transforms(pil_img.convert("RGB")) for pil_img in example_batch["image"]]
    return example_batch

calibration_dataset.set_transform(val_transforms)

def collate_fn(examples):
    pixel_values = torch.stack([example["pixel_values"] for example in examples])
    labels = torch.tensor([example["label"] for example in examples])
    return {"pixel_values": pixel_values, "labels": labels}

Per il nostro primo tentativo, utilizziamo la configurazione predefinita per la quantizzazione. È anche possibile specificare il numero di campioni da utilizzare durante la fase di calibrazione, che per impostazione predefinita è 300.

from optimum.intel.openvino import OVConfig

quantization_config = OVConfig()
quantization_config.compression["initializer"]["range"]["num_init_samples"] = 300

Siamo ora pronti per quantizzare il modello. Il metodo OVQuantizer.quantize() quantizza il modello ed esporta il risultato nel formato OpenVINO. Il grafo risultante è rappresentato da due file: un file XML che descrive la topologia della rete e un file binario che descrive i pesi. Il modello risultante può essere eseguito su qualsiasi dispositivo Intel® target.

save_dir = "modello_quantizzato"

# Applica la quantizzazione statica ed esporta il modello quantizzato risultante nel formato OpenVINO IR
quantizer.quantize(
    quantization_config=quantization_config,
    calibration_dataset=calibration_dataset,
    data_collator=collate_fn,
    remove_unused_columns=False,
    save_directory=save_dir,
)
feature_extractor.save_pretrained(save_dir)

Dopo uno o due minuti, il modello è stato quantizzato. Possiamo quindi caricarlo facilmente con le nostre classi OVModelForXxx, l’equivalente delle classi AutoModelForXxx di Transformers presenti nella libreria transformers. Allo stesso modo, possiamo creare pipeline ed eseguire inferenze con OpenVINO Runtime.

from transformers import pipeline
from optimum.intel.openvino import OVModelForImageClassification

modello_ov = OVModelForImageClassification.from_pretrained(save_dir)
ov_pipe = pipeline("image-classification", model=modello_ov, feature_extractor=feature_extractor)
output = ov_pipe("http://farm2.staticflickr.com/1375/1394861946_171ea43524_z.jpg")
print(output)

Per verificare che la quantizzazione non abbia avuto un impatto negativo sull’accuratezza, abbiamo applicato una fase di valutazione per confrontare l’accuratezza del modello originale con quella del suo controparte quantizzato. Valutiamo entrambi i modelli su un sottoinsieme del dataset (prendendo solo il 20% del dataset di valutazione). Abbiamo osservato una perdita minima o nulla di accuratezza, con entrambi i modelli che hanno un’accuratezza del 87,6.

from datasets import load_dataset
from evaluate import evaluator

# Eseguiamo la fase di valutazione sul 20% del dataset di valutazione
dataset_valutazione = load_dataset("food101", split="validation").select(range(5050))
valutatore_task = evaluator("image-classification")

risultati_ov_eval = valutatore_task.compute(
    model_or_pipeline=ov_pipe,
    data=dataset_valutazione,
    metrica="accuracy",
    mapping_etichette=ov_pipe.model.config.label2id,
)

pipe_trfs = pipeline("image-classification", model=modello, feature_extractor=feature_extractor)
risultati_trfs_eval = valutatore_task.compute(
    model_or_pipeline=pipe_trfs,
    data=dataset_valutazione,
    metrica="accuracy",
    mapping_etichette=pipe_trfs.model.config.label2id,
)
print(risultati_trfs_eval, risultati_ov_eval)

Guardando il modello quantizzato, vediamo che la sua dimensione di memoria è diminuita di 3,8 volte da 344 MB a 90 MB. Eseguendo un rapido benchmark su 5050 predizioni di immagini, notiamo anche un’accelerazione nella latenza di 2,4 volte, da 98 ms a 41 ms per campione. Non è male per qualche riga di codice!

⚠️ Una cosa importante da menzionare è che il modello viene compilato appena prima della prima inferenza, il che aumenterà la latenza della prima inferenza. Quindi, prima di eseguire il tuo benchmark, assicurati di “scaldare” il tuo modello facendo almeno una predizione.

Puoi trovare il modello risultante ospitato sul Hugging Face hub. Per caricarlo, puoi facilmente fare quanto segue:

from optimum.intel.openvino import OVModelForImageClassification

modello_ov = OVModelForImageClassification.from_pretrained("echarlaix/vit-food101-int8")

Ora tocca a te

Come puoi vedere, è abbastanza facile accelerare i tuoi modelli con 🤗 Optimum Intel e OpenVINO. Se vuoi iniziare, visita il repository di Optimum Intel e non dimenticare di dargli una stella ⭐. Troverai anche esempi aggiuntivi lì. Se vuoi approfondire OpenVINO, la documentazione Intel ti copre.

Provalo e facci sapere cosa ne pensi. Saremmo felici di ricevere i tuoi feedback sul forum di Hugging Face e sentiti libero di richiedere funzionalità o segnalare problemi su Github.

Divertiti con 🤗 Optimum Intel e grazie per aver letto.