Affinamento dei modelli di diffusione stabili su CPU Intel
Optimizing stable diffusion models on Intel CPUs
I modelli di diffusione hanno contribuito a rendere popolare l’IA generativa grazie alla loro straordinaria capacità di generare immagini fotorealistiche da prompt di testo. Questi modelli sono ora stati adottati in ambito aziendale per casi d’uso come la generazione di dati sintetici o la creazione di contenuti. L’hub di Hugging Face include oltre 5.000 modelli preaddestrati per la conversione di testo in immagini. Combinandoli con la libreria Diffusers, non è mai stato così facile iniziare a sperimentare e creare flussi di lavoro per la generazione di immagini.
Come i modelli Transformer, è possibile affinare i modelli di diffusione per aiutarli a generare contenuti che si adattano alle esigenze aziendali. Inizialmente, l’affinamento era possibile solo su infrastrutture GPU, ma le cose stanno cambiando! Alcuni mesi fa, Intel ha lanciato la quarta generazione di CPU Xeon, chiamata in codice Sapphire Rapids. Sapphire Rapids introduce le Intel Advanced Matrix Extensions (AMX), un nuovo acceleratore hardware per carichi di lavoro di deep learning. Abbiamo già dimostrato i vantaggi di AMX in diversi articoli del blog: affinamento dei modelli NLP Transformer, inferenza con i modelli NLP Transformer e inferenza con i modelli di diffusione stabile.
Questo post ti mostrerà come affinare un modello di diffusione stabile su un cluster di CPU Intel Sapphire Rapids. Utilizzeremo l’inversione testuale, una tecnica che richiede solo un piccolo numero di immagini di esempio. Ne useremo solo cinque!
Cominciamo.
- Analisi esplorativa dei dati in Google Sheets
- DAE Talking Generazione di un volto parlante ad alta fedeltà guidata dalla voce con un Diffusion Autoencoder
- Tutorial Docker per Data Scientist
Preparazione del cluster
I nostri amici di Intel hanno fornito quattro server ospitati su Intel Developer Cloud (IDC), una piattaforma di servizi per lo sviluppo e l’esecuzione di carichi di lavoro in ambienti di distribuzione ottimizzati da Intel con gli ultimi processori Intel e stack software ottimizzati per le prestazioni.
Ogni server è alimentato da due CPU Intel Sapphire Rapids con 56 core fisici e 112 thread. Ecco l’output di lscpu
:
Architettura: x86_64
Modalità di funzionamento della CPU: 32-bit, 64-bit
Dimensioni degli indirizzi: 52 bit fisici, 57 bit virtuali
Byte Order: Little Endian
CPU(s): 224
Elenco delle CPU online: 0-223
ID produttore: GenuineIntel
Nome del modello: Intel(R) Xeon(R) Platinum 8480+
Famiglia della CPU: 6
Modello: 143
Thread per core: 2
Core per socket: 56
Socket(s): 2
Stepping: 8
Frequenza massima CPU MHz: 3800.0000
Frequenza minima CPU MHz: 800.0000
BogoMIPS: 4000.00
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_per fmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm ida arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
Per prima cosa elenchiamo gli indirizzi IP dei nostri server in nodefile.
La prima riga si riferisce al server primario.
cat << EOF > nodefile
192.168.20.2
192.168.21.2
192.168.22.2
192.168.23.2
EOF
La formazione distribuita richiede una connessione ssh
senza password tra il server primario e gli altri nodi. Ecco un buon articolo su come fare questo se non sei familiare con il processo.
Successivamente, creiamo un nuovo ambiente su ogni nodo e installiamo le dipendenze software. In particolare, installiamo due librerie Intel: oneCCL, per gestire la comunicazione distribuita, e l’Estensione Intel per PyTorch (IPEX) per sfruttare le funzionalità di accelerazione hardware presenti in Sapphire Rapids. Aggiungiamo anche gperftools
per installare libtcmalloc,
una libreria di allocazione della memoria ad alte prestazioni.
conda create -n diffuser python==3.9
conda activate diffuser
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install transformers accelerate==0.19.0
pip3 install oneccl_bind_pt -f https://developer.intel.com/ipex-whl-stable-cpu
pip3 install intel_extension_for_pytorch
conda install gperftools -c conda-forge -y
Successivamente, cloniamo il repository diffusers su ogni nodo e lo installiamo dalla sorgente.
git clone https://github.com/huggingface/diffusers.git
cd diffusers
pip install .
Successivamente, aggiungiamo IPEX allo script di fine-tuning in diffusers/examples/textual_inversion
. Importiamo IPEX e ottimizziamo i modelli U-Net e Variable Auto Encoder. Assicurati che ciò sia applicato a tutti i nodi.
diff --git a/examples/textual_inversion/textual_inversion.py b/examples/textual_inversion/textual_inversion.py
index 4a193abc..91c2edd1 100644
--- a/examples/textual_inversion/textual_inversion.py
+++ b/examples/textual_inversion/textual_inversion.py
@@ -765,6 +765,10 @@ def main():
unet.to(accelerator.device, dtype=weight_dtype)
vae.to(accelerator.device, dtype=weight_dtype)
+ import intel_extension_for_pytorch as ipex
+ unet = ipex.optimize(unet, dtype=weight_dtype)
+ vae = ipex.optimize(vae, dtype=weight_dtype)
+
# Dobbiamo ricalcolare il numero totale di passaggi di addestramento poiché la dimensione del dataloader di addestramento potrebbe essere cambiata.
num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
if overrode_max_train_steps:
Infine, scarichiamo le immagini di addestramento. Idealmente, dovremmo utilizzare una cartella NFS condivisa, ma per semplicità, scaricheremo le immagini su ogni nodo. Assicurati che siano nella stessa directory su tutti i nodi (/home/devcloud/dicoo
).
mkdir /home/devcloud/dicoo
cd /home/devcloud/dicoo
wget https://huggingface.co/sd-concepts-library/dicoo/resolve/main/concept_images/0.jpeg
wget https://huggingface.co/sd-concepts-library/dicoo/resolve/main/concept_images/1.jpeg
wget https://huggingface.co/sd-concepts-library/dicoo/resolve/main/concept_images/2.jpeg
wget https://huggingface.co/sd-concepts-library/dicoo/resolve/main/concept_images/3.jpeg
wget https://huggingface.co/sd-concepts-library/dicoo/resolve/main/concept_images/4.jpeg
Ecco le immagini:
La configurazione del sistema è ora completa. Configuriamo il lavoro di addestramento.
Configurazione del lavoro di fine-tuning
La libreria Accelerate semplifica molto l’esecuzione dell’addestramento distribuito. È necessario eseguirlo su ogni nodo e rispondere a semplici domande.
Ecco uno screenshot per il nodo principale. Sugli altri nodi, è necessario impostare il rank su 1, 2 e 3. Tutte le altre risposte sono identiche.
Infine, è necessario impostare l’ambiente sul nodo principale. Verrà propagato agli altri nodi all’avvio del lavoro di fine-tuning. La prima riga imposta il nome dell’interfaccia di rete collegata alla rete locale in cui vengono eseguiti tutti i nodi. Potrebbe essere necessario adattarlo utilizzando ifconfig
per ottenere le informazioni appropriate.
export I_MPI_HYDRA_IFACE=ens786f1
oneccl_bindings_for_pytorch_path=$(python -c "from oneccl_bindings_for_pytorch import cwd; print(cwd)")
source $oneccl_bindings_for_pytorch_path/env/setvars.sh
export LD_PRELOAD=${LD_PRELOAD}:${CONDA_PREFIX}/lib/libiomp5.so
export LD_PRELOAD=${LD_PRELOAD}:${CONDA_PREFIX}/lib/libtcmalloc.so
export CCL_ATL_TRANSPORT=ofi
export CCL_WORKER_COUNT=1
export MODEL_NAME="runwayml/stable-diffusion-v1-5"
export DATA_DIR="/home/devcloud/dicoo"
Ora possiamo avviare il lavoro di fine-tuning.
Fine-tuning del modello
Avviamo il lavoro di fine-tuning con mpirun
, che configura la comunicazione distribuita tra i nodi elencati in nodefile
. Eseguiremo 16 task (-n
) con quattro task per nodo (-ppn
). Accelerate
configura automaticamente l’addestramento distribuito su tutti i task.
Qui, addestriamo per 200 passaggi, che dovrebbero richiedere circa cinque minuti.
mpirun -f nodefile -n 16 -ppn 4 \
accelerate launch diffusers/examples/textual_inversion/textual_inversion.py \
--pretrained_model_name_or_path=$MODEL_NAME --train_data_dir=$DATA_DIR \
--learnable_property="object" --placeholder_token="<dicoo>" --initializer_token="toy" \
--resolution=512 --train_batch_size=1 --seed=7 --gradient_accumulation_steps=1 \
--max_train_steps=200 --learning_rate=2.0e-03 --scale_lr --lr_scheduler="constant" \
--lr_warmup_steps=0 --output_dir=./textual_inversion_output --mixed_precision bf16 \
--save_as_full_pipeline
Ecco uno screenshot del cluster impegnato:
Risoluzione dei problemi
L’addestramento distribuito può essere complicato, soprattutto se sei nuovo in questo campo. Il problema più probabile è una piccola errata configurazione su un singolo nodo: dipendenza mancante, immagini archiviate in una posizione diversa, ecc.
Puoi individuare rapidamente il problema accedendo a ciascun nodo e addestrando localmente. Prima, impostare lo stesso ambiente del nodo principale, quindi eseguire:
python diffusers/examples/textual_inversion/textual_inversion.py \
--pretrained_model_name_or_path=$MODEL_NAME --train_data_dir=$DATA_DIR \
--learnable_property="object" --placeholder_token="<dicoo>" --initializer_token="toy" \
--resolution=512 --train_batch_size=1 --seed=7 --gradient_accumulation_steps=1 \
--max_train_steps=200 --learning_rate=2.0e-03 --scale_lr --lr_scheduler="constant" \
--lr_warmup_steps=0 --output_dir=./textual_inversion_output --mixed_precision bf16 \
--save_as_full_pipeline
Se l’addestramento parte correttamente, interrompilo e passa al nodo successivo. Se l’addestramento parte correttamente su tutti i nodi, torna al nodo principale e controlla nuovamente il file dei nodi, l’ambiente e il comando mpirun
. Non preoccuparti, troverai il problema 🙂
Generazione di immagini con il modello ottimizzato
Dopo 5 minuti di addestramento, il modello viene salvato localmente. Possiamo caricarlo con una pipeline diffusers
di base e fare una previsione. Invece, useremo Optimum Intel e OpenVINO per ottimizzare il modello. Come discusso in un post precedente, questo ti permette di generare un’immagine su una singola CPU in meno di 5 secondi!
pip install optimum[openvino]
Qui, carichiamo il modello, lo ottimizziamo per una forma statica e lo salviamo:
from optimum.intel.openvino import OVStableDiffusionPipeline
model_id = "./textual_inversion_output"
ov_pipe = OVStableDiffusionPipeline.from_pretrained(model_id, export=True)
ov_pipe.reshape(batch_size=5, height=512, width=512, num_images_per_prompt=1)
ov_pipe.save_pretrained("./textual_inversion_output_ov")
Successivamente, carichiamo il modello ottimizzato, generiamo cinque immagini diverse e le salviamo:
from optimum.intel.openvino import OVStableDiffusionPipeline
model_id = "./textual_inversion_output_ov"
ov_pipe = OVStableDiffusionPipeline.from_pretrained(model_id, num_inference_steps=20)
prompt = ["un robot giallo sulla spiaggia, di alta qualità"]*5
images = ov_pipe(prompt).images
print(images)
for idx,img in enumerate(images):
img.save(f"immagine{idx}.png")
Ecco un’immagine generata. È impressionante che il modello abbia avuto bisogno solo di cinque immagini per imparare che i dicoos indossano gli occhiali!
Se vuoi, puoi ulteriormente perfezionare il modello. Ecco un bel esempio generato da un modello di 3.000 passaggi (circa un’ora di addestramento).
Conclusione
Grazie a Hugging Face e Intel, ora puoi utilizzare server con CPU Xeon per generare immagini di alta qualità adattate alle esigenze della tua azienda. Sono generalmente più accessibili e ampiamente disponibili rispetto all’hardware specializzato come le GPU. Le CPU Xeon possono anche essere facilmente riutilizzate per altre attività di produzione, dai server web ai database, rendendole una scelta versatile e flessibile per la tua infrastruttura IT.
Ecco alcune risorse per aiutarti a iniziare:
- Documentazione di Diffusers
- Documentazione di Optimum Intel
- Intel IPEX su GitHub
- Risorse per sviluppatori da Intel e Hugging Face.
- Server Sapphire Rapids su Intel Developer Cloud, AWS e GCP.
Se hai domande o feedback, saremmo felici di leggerli sul forum di Hugging Face.
Grazie per la lettura!