AI și carbon: Măsurarea și reducerea amprentei antrenamentului ML
Antrenament GPT-4 consumat aprox 50 GWh de energie electrică, suficient pentru a alimenta peste 4.600 de case europene pentru un an întreg. GPT-3, predecesorul său, el a produs 502 tone echivalent CO₂ în timpul antrenamentului - echivalentul a 112 mașini pe benzină care parcurg 20.000 km pe an fiecare. BLOOM, modelul open-source cu 176 de miliarde de parametri, instruit în Franța în domeniul energiei amestecat, a emis 25 de tone de CO₂eq datorită utilizării predominante de energie nucleară și regenerabilă.
Acestea nu sunt curiozități statistice: sunt semne ale unei probleme structurale care se dezvoltă rapid accelerare. IA generativă crește la ritmuri exponențiale, cu modele seturi de date tot mai mari, tot mai mari și cicluri de antrenament tot mai mari frecvente. Potrivit unui studiu publicat în Natură în 2024, emisiile legate de Instruirea modelului AI s-ar putea tripla până în 2027 dacă nu se iau măsuri de eficienţă sistemică. AIE estimează că centrele de date dedicate AI în 2026 vor consuma mai multă energie decât multe state europene de dimensiuni medii.
Cu toate acestea, marea majoritate a echipelor ML încep să se antreneze pe clustere GPU fără să măsoare vreodată emisiile produse. Nu pentru că nu le pasă, ci pentru că le lipsesc instrumentele integrate în fluxul de lucru zilnic, valorile standard partajate și cultura de măsurare. În acest articol final al seriei Green Software Engineering vom explora întregul ciclu de viață al amprentei de carbon în Machine Learning: de la măsurarea precisă cu CodeCarbon și CarbonTracker, la optimizarea arhitecturală cu tăiere și distilare, până la programarea antrenamentului conștient de carbon și optimizarea inferenței în producție.
Ce vei învăța
- Date reale de emisie pentru modelele de bază: GPT-3, GPT-4, Llama 2, BLOOM, PaLM
- Instalați și utilizați algoritmi CodeCarbon, CarbonTracker, ML CO₂ Impact și Green
- Comparați GPU-uri pentru eficiența energetică: A100, H100, H200, B200 în FLOPS/Wați
- Tehnici de optimizare arhitecturală: tăiere, distilare a cunoștințelor, NAS eficient
- Eficiență centrată pe date: calitatea datelor vs cantitate, învățarea curriculumului
- Antrenamentul conștient de carbon: programați sarcinile de lucru în regiuni și perioade cu intensitate scăzută de carbon
- Optimizare inferență: cuantizare INT8/INT4, ONNX Runtime, TensorRT, vLLM
- Calculați scorul SCI pentru modelele ML și construiți un clasament Green AI
- Studiu de caz complet: reducerea cu 60% a emisiilor pe un model NLP real
- Foaia de parcurs practică pentru adoptarea Green AI în organizații
Seria Green Software Engineering — 10 articole
| # | Articol | Tema principală |
|---|---|---|
| 1 | Principiile Green Software Foundation | GSF, SCI, 8 principii fundamentale |
| 2 | Măsurarea amprentei de carbon cu CodeCarbon | CodeCarbon, CCF, integrare CI/CD |
| 3 | Climatiq API și Carbon Accounting | API REST, LCA, Scop 1-2-3 |
| 4 | SDK Carbon-Aware și deplasare temporală/spațială | Treceți sarcinile de lucru la energie verde |
| 5 | Modelarea domeniului și implementarea SCI | Calcul practic SCI, Cadrul de impact |
| 6 | GreenOps: FinOps pentru durabilitate | Costul cloud și carbon, Kubernetes |
| 7 | Scopul 3 în Pipeline de software | Emisii indirecte, lanț de aprovizionare digital |
| 8 | ESG, CSRD și Digital Reporting | Conformitate europeană, ESRS E1, divulgare |
| 9 | Modele arhitecturale durabile | Stocare, stocare în cache, lot conștient de carbon |
| 10 | AI și carbon: amprenta antrenamentului ML | Acest articol - articolul final al seriei |
Amprenta reală de carbon a modelelor fundamentale
Înțelegerea amplorii problemei necesită date solide. cercetătorii de la Stanford Hugging Face și MLCommons au început să publice valorile emisiilor pentru specializări modele lingvistice. Următorul tabel agregă datele disponibile, ținând cont de faptul că multe companii – în special OpenAI – încă nu dezvăluie aceste informații.
Emisiile de CO₂eq ale modelelor fundamentale în timpul antrenamentului
| Model | Parametrii | Energie (MWh) | CO₂eq (t) | Regiune/Amestec | Sursă |
|---|---|---|---|---|---|
| GPT-3 | 175B | 1.287 | 502 | SUA (mix mediu) | Patterson şi colab. 2021 |
| GPT-4 | ~1,8 T (est.) | ~50.000 | ~14.000 | SUA (estimare) | Estimări independente 2023 |
| FLOARE | 176B | 433 | 25 | Franța (nucleare+regenerabile) | Luccini et al. 2022 |
| Lama 2 (70B) | 70B | ~700 | 539 | SUA/Azure | Meta FW 2023 |
| Palmier | 540B | ~3.400 | ~507 | SUA (TPU v4) | Chowdhery și colab. 2022 |
| Mistral 7B | 7B | ~35 | ~12 | Europa (mix) | Mistral FW 2023 |
| Falcon 180B | 180B | ~600 | ~117 | Emiratele Arabe Unite (mix) | TII 2023 |
| Bijuterie 7B | 7B | ~32 | ~6 | SUA/TPU (RE100) | Google DeepMind 2024 |
Aceste date dezvăluie trei modele fundamentale. Primul este decalaj geografic: BLOOM, antrenat în Franța cu energie nucleară, a emis de 20 de ori mai puțin de Llama 2 la același ordin de mărime. Al doilea esteefect de scară: trecerea de la parametrii 7B la 176B nu înseamnă pur și simplu de 25 de ori mai multe emisii - costurile de comunicare distribuite și durata antrenamentului cresc neliniar. Al treilea este decalaj de transparență: Majoritatea companiilor nu încă publică aceste date, ceea ce face comparația dificilă și compararea imposibilă fără măsurători independente.
Paradoxul inferenței: mai mare decât antrenamentul
În mod contraintuitiv, emisiile cumulate dededucere ele depăşesc adesea cele ale pregătirii în ciclul de viaţă al unui model. Un model precum ChatGPT, cu milioane de solicitari pe zi, poate consuma mai multa energie intr-o luna de productie a întregului antrenament original. Patterson şi colab. estimați că inferența GPT-3 la scară ChatGPT produce cca 11.000 de tone de CO₂eq pe an. Aceasta schimbă atenția de la optimizarea antrenamentului la optimizarea inferenței ca prioritate primară pentru reducerea impactului total asupra mediului.
Emisii încorporate și ciclu de viață complet
Analiza amprentei de carbon AI nu poate fi limitată la energia consumată în timpul antrenamentul. The emisii încorporate a hardware-ului — CO₂ emis pentru a produce GPU-uri, servere, rețele de răcire și infrastructură - acestea reprezintă a pondere semnificativă. Producerea unui singur cip H100 emite aprox 150 kgCO₂eq, și un cluster de 1.000 de GPU duce la emisii încorporate de aproximativ 150 de tone numai pentru hardware, chiar înainte de a începe un singur loc de muncă de formare.
# Formula Carbon Footprint Completo per ML
# Basato su Luccioni et al. "Counting Carbon" (2023)
Total_CO2eq = Training_CO2eq + Inference_CO2eq + Embodied_CO2eq
Training_CO2eq = Energy_training (kWh) x Carbon_Intensity (kgCO2eq/kWh) x PUE
Inference_CO2eq = (Requests x Latency x GPU_Power / 3600000) x Carbon_Intensity x PUE
Embodied_CO2eq = (Hardware_Production_CO2eq / Lifespan_hours) x Training_hours
# Esempio: modello NLP medio (BERT-Large fine-tuning su task classificazione)
Energy_training = 120 kWh # 4x A100, 6 ore
Carbon_Intensity = 0.420 kg/kWh # mix europeo medio
PUE = 1.3 # data center tipico
Training_CO2eq = 120 x 0.420 x 1.3 = 65.5 kgCO2eq
# Inferenza: 10M richieste/mese, 50ms each, 1x A100 (300W)
Inference_monthly = (10_000_000 x 0.05 x 300 / 3_600_000) x 0.420 x 1.3
= 41.7 kWh x 0.420 x 1.3 = 22.7 kgCO2eq/mese
# Dopo 12 mesi: 272 kgCO2eq inferenza vs 65 kgCO2eq training
# L'inferenza domina del 77% nel ciclo di vita annuale
Instrumente de măsurare: de la CodeCarbon la algoritmi verzi
Măsurarea emisiilor ML necesită instrumente concepute special pentru sarcinile de lucru ML antrenament și inferență. Patru instrumente domină spațiul: CodeCarbon, CarbonTracker, Calculator de impact ML CO₂ și algoritmi verzi. Fiecare are puncte forte specifice și cazuri de utilizare optime.
CodeCarbon: Integrare directă în codul Python
CodeCarbon este cel mai popular instrument pentru măsurarea emisiilor în timpul Antrenamentul ML. Integrarea sa cu cele mai comune cadre (PyTorch, TensorFlow, Hugging Face Transformers) îl face alegerea naturală pentru majoritatea echipelor.
# pip install codecarbon
from codecarbon import EmissionsTracker, track_emissions
import torch
from transformers import Trainer, TrainingArguments
# Metodo 1: Context manager
tracker = EmissionsTracker(
project_name="bert-finetuning-sentiment",
country_iso_code="ITA",
region="lombardy",
cloud_provider="gcp",
cloud_region="europe-west8",
output_dir="./carbon_reports",
output_file="emissions.csv",
log_level="warning",
save_to_file=True,
tracking_mode="machine", # Legge sensori hardware reali
measure_power_secs=15 # Campionamento ogni 15 secondi
)
tracker.start()
try:
# Il tuo training loop qui
model = train_model(dataset, epochs=10)
finally:
emissions = tracker.stop()
print(f"Training completato: {emissions:.4f} kgCO2eq")
print(f"Equivalente a: {emissions * 2.4:.2f} km in auto")
# Metodo 2: Decorator per funzioni singole
@track_emissions(
project_name="bert-inference",
country_iso_code="ITA",
save_to_file=True
)
def run_inference_batch(model, dataloader):
results = []
with torch.no_grad():
for batch in dataloader:
outputs = model(**batch)
results.extend(outputs.logits.argmax(-1).tolist())
return results
# Metodo 3: Integrazione con Hugging Face Trainer
from codecarbon import EmissionsTracker
class CarbonAwareTrainer(Trainer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.carbon_tracker = EmissionsTracker(
project_name=f"hf-training-{self.args.run_name}",
country_iso_code="ITA",
save_to_file=True
)
def train(self, *args, **kwargs):
self.carbon_tracker.start()
result = super().train(*args, **kwargs)
emissions = self.carbon_tracker.stop()
self.log({"carbon_emissions_kgCO2eq": emissions})
return result
CarbonTracker: proiecții și bugetare
CarbonTracker, dezvoltat de Universitatea din Copenhaga, se remarcă prin capacitatea sa de consumul total al proiectului pe baza primelor perioade de pregătire. Această funcționalitate este neprețuită: vă permite să estimați costul carbonului înainte de a finaliza antrenamentul care durează zile sau săptămâni.
# pip install carbontracker
from carbontracker.tracker import CarbonTracker
from carbontracker import parser
# Configurazione con proiezione
tracker = CarbonTracker(
epochs=100,
epochs_before_pred=5, # Dopo 5 epoche, proietta le 95 rimanenti
monitor_epochs=10, # Monitora ogni 10 epoche
log_dir="./carbontracker_logs",
update_interval=10,
verbose=2,
components="gpu",
ignore_errors=False
)
for epoch in range(100):
tracker.epoch_start()
# Training epoch
for batch in train_loader:
optimizer.zero_grad()
outputs = model(batch['input_ids'], batch['attention_mask'])
loss = criterion(outputs, batch['labels'])
loss.backward()
optimizer.step()
tracker.epoch_end()
tracker.stop()
# Dopo 5 epoche, CarbonTracker stampa proiezioni come:
# "Predicting training to use 2.34 kWh and emit 0.98 kgCO2eq"
# "Total: actual consumption: 0.12 kWh, 0.05 kgCO2eq (after 5 epochs)"
# Parsing dei log per analisi
logs = parser.parse_all_logs(log_dir="./carbontracker_logs")
for log in logs:
print(f"Energia: {log['actual']['energy (kWh)']:.3f} kWh")
print(f"CO2: {log['actual']['co2eq (g)']:.1f} gCO2eq")
print(f"Proiezione totale: {log['pred']['co2eq (g)']:.1f} gCO2eq")
Calculator de impact ML CO₂ și algoritmi verzi
Calculator de impact ML CO₂ (mlco2.github.io) este un instrument web care estimează emisiile pe baza hardware-ului, furnizorului de cloud, regiune și durată. Nu necesită Integrare în cod: Ideal pentru estimări sau documentare rapide înainte de antrenament probleme de formare deja finalizate. Suportă AWS, GCP, Azure și peste 15 regiuni.
Algoritmi verzi (green-algorithms.org), dezvoltat de Universitate Cambridge, oferă o abordare mai științifică cu modele de consum de energie validate pe date reale ale centrului de date. Suportă calcule pentru HPC (High Performance Computing), Clustere GPU și fluxuri de lucru bioinformatice.
Comparația instrumentelor de măsurare a carbonului ML
| Instrument | Tip | Granularitatea | Integrare | Punct de forță | Prescripţie |
|---|---|---|---|---|---|
| CodeCarbon | Python lib | Funcție/post | PyTorch, T.F., H.F | Măsurare hardware reală | Numai Python, overhead <1% |
| Carbon Tracker | Python lib | Pentru epocă | Bucle de învățare profundă | Proiecții de oprire timpurie | Necesită pregătire bazată pe epocă |
| Impactul ML CO₂ | Instrumente web | Nivelul postului | Niciunul (formular web) | Configurare zero, estimare rapidă | Doar estimare, nu măsurare |
| Algoritmi verzi | Instrumente web | Nivelul postului | Niciunul (formular web) | Modele validate științific | Nu în timp real |
| Experimentarea Impact Tracker | Python lib | Experiment | Experimente ML | Înregistrare automată MLflow | Cel mai puțin întreținut (2021) |
Tabloul de bord și raportarea automată
Măsurarea este valoroasă doar dacă datele sunt agregate, vizualizate și utilizate pentru a lua deciziilor. Un model eficient este integrarea CodeCarbon cu MLflow pentru a crea un sistem de urmărire automată care înregistrează emisiile împreună cu valorile de performanță.
import mlflow
from codecarbon import EmissionsTracker
import pandas as pd
from pathlib import Path
class GreenMLExperiment:
"""Wrapper che traccia automaticamente emissioni + performance ML."""
def __init__(self, experiment_name: str, country_code: str = "ITA"):
self.experiment_name = experiment_name
self.country_code = country_code
mlflow.set_experiment(experiment_name)
def run(self, model_fn, train_fn, eval_fn, params: dict):
with mlflow.start_run():
mlflow.log_params(params)
# Avvia tracker emissioni
tracker = EmissionsTracker(
project_name=self.experiment_name,
country_iso_code=self.country_code,
save_to_file=True,
output_dir="./emissions_logs"
)
tracker.start()
model = model_fn(**params)
train_metrics = train_fn(model)
emissions_kg = tracker.stop()
# Metriche performance
eval_metrics = eval_fn(model)
# Log tutto su MLflow
mlflow.log_metric("train_loss", train_metrics["loss"])
mlflow.log_metric("eval_accuracy", eval_metrics["accuracy"])
mlflow.log_metric("emissions_kgCO2eq", emissions_kg)
mlflow.log_metric("emissions_grams", emissions_kg * 1000)
mlflow.log_metric(
"accuracy_per_kgCO2",
eval_metrics["accuracy"] / max(emissions_kg, 0.001)
)
# Log artefatti
mlflow.log_artifacts("./emissions_logs")
return {
"model": model,
"emissions": emissions_kg,
"metrics": eval_metrics,
"efficiency_ratio": eval_metrics["accuracy"] / emissions_kg
}
# Utilizzo
experiment = GreenMLExperiment("bert-sentiment-v2", country_code="ITA")
result = experiment.run(
model_fn=create_bert_model,
train_fn=train_epoch,
eval_fn=evaluate_model,
params={"lr": 2e-5, "batch_size": 32, "epochs": 5}
)
Eficiență energetică a GPU: FLOPS per Watt
Alegerea hardware-ului este cea mai importantă decizie pentru amprenta de carbon a instruirii. GPU-urile de ultimă generație oferă eficiențe energetice semnificativ mai mari comparativ cu predecesorii, iar diferența dintre antrenamentul pe A100 vs H200 poate însemna o reducere de 40-60% a emisiilor pentru aceeași sarcină de muncă.
Comparație GPU pentru antrenamentul ML: eficiență energetică (2025)
| GPU | An | TDP (W) | FP16 TFLOPS | FLOPS/Watt | Memoria HBM | CO₂ relativ |
|---|---|---|---|---|---|---|
| A100 SXM4 | 2020 | 400W | 312 | 780 GFLOPS/W | 80 GB HBM2e | Linia de referință (1,0x) |
| H100 SXM5 | 2022 | 700W | 989 | 1,413 GFLOPS/W | 80 GB HBM3 | 0,56x (-44%) |
| H200 SXM5 | 2024 | 700W | 989 | 1,413 GFLOPS/W | 141 GB HBM3e | 0,56x (-44%) |
| B200 SXM6 | 2025 | 1.000 W | 4.500 | 4.500 GFLOPS/W | 192 GB HBM3e | 0,17x (-83%) |
| RTX 4090 | 2022 | 450W | 165 | 367 GFLOPS/W | 24 GB GDDR6X | 2,12x (+112%) |
| AMD MI300X | 2024 | 750W | 1.307 | 1.743 GFLOPS/W | 192 GB HBM3 | 0,45x (-55%) |
H100 și H200 oferă aproximativ Reducere cu 44% a emisiilor respect la A100 pentru aceeași sarcină de lucru, datorită Transformer Engine cu FP8 și arhitecturii NVLink optimizat. B200 reprezintă un salt generațional cu 4,5 PFLOPS și FP16 suport nativ FP4, aducând reducerea la 83%.
Antrenament mixt de precizie: FP16 și BF16
Antrenamentul în precizie mixtă (FP16 sau BF16 pentru calcule, FP32 pentru parametrii modelului) reduce consumul de energie cu 30-50% comparativ cu antrenamentul FP32 complet, fără o degradare semnificativă a calității modelului.
import torch
from torch.cuda.amp import autocast, GradScaler
# Training con AMP (Automatic Mixed Precision)
scaler = GradScaler()
def train_epoch_amp(model, dataloader, optimizer, device):
model.train()
total_loss = 0.0
for batch in dataloader:
input_ids = batch['input_ids'].to(device)
labels = batch['labels'].to(device)
optimizer.zero_grad()
# Forward pass in FP16/BF16
with autocast(dtype=torch.bfloat16): # BF16 su A100/H100
outputs = model(input_ids=input_ids, labels=labels)
loss = outputs.loss
# Backward pass con gradient scaling
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
# Gradient clipping per stabilità
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
total_loss += loss.item()
return total_loss / len(dataloader)
# Con Hugging Face: basta un flag
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="./results",
bf16=True, # BF16 per A100/H100 (preferibile a FP16)
fp16=False,
dataloader_num_workers=4,
per_device_train_batch_size=32,
gradient_accumulation_steps=4, # Simula batch da 128
gradient_checkpointing=True, # -40% memoria VRAM, +20% tempo
# Risparmio energetico: meno transfer GPU-CPU
dataloader_pin_memory=True
)
# Benchmark: BERT-Large su 1M esempi
# FP32: 6.2 ore, 148 kWh, 62 kgCO2eq (ITA)
# BF16: 3.4 ore, 81 kWh, 34 kgCO2eq (ITA) -> -45% emissioni
Optimizare arhitecturală: tăiere, distilare și NAS
Tehnicile de optimizare arhitecturală reduc complexitatea modelului, conducând la un antrenament mai rapid, o inferență mai eficientă și o amprentă de carbon total redus. Cele trei tehnici principale sunt tăierea, distilarea cunoștințelor și căutare eficientă a arhitecturii neuronale.
Tunderea modelului: Eliminați redundanța
Tunderea elimină parametrii sau structurile modelului care contribuie marginal la precizie. Există două abordări principale: tăierea nestructurată (greutăți individuale) e tăierea structurată (capete de atenție, neuroni, straturi). Acesta din urmă este de preferat pentru eficiența hardware reală, deoarece este nestructurat tăierea necesită hardware cu suport rar pentru a beneficia cu adevărat.
import torch
import torch.nn.utils.prune as prune
from transformers import BertForSequenceClassification
import numpy as np
def structured_pruning_bert(model, pruning_ratio=0.3):
"""
Pruning strutturato delle teste di attenzione BERT.
Rimuove le teste meno importanti basandosi sulla norma L1.
"""
pruned_heads = {}
for layer_idx, layer in enumerate(model.bert.encoder.layer):
# Calcola importanza di ogni testa (norma L1 dei pesi query)
attention = layer.attention.self
num_heads = attention.num_attention_heads
head_size = attention.attention_head_size
query_weights = attention.query.weight.data # shape: [hidden, hidden]
query_reshaped = query_weights.view(num_heads, head_size, -1)
head_importance = query_reshaped.abs().mean(dim=[1, 2])
# Seleziona le teste da prunable
num_heads_to_prune = int(num_heads * pruning_ratio)
heads_to_prune = head_importance.argsort()[:num_heads_to_prune].tolist()
if heads_to_prune:
pruned_heads[layer_idx] = set(heads_to_prune)
model.prune_heads(pruned_heads)
return model, pruned_heads
# Unstructured pruning con PyTorch
def magnitude_pruning(model, sparsity=0.5):
"""Pruning per magnitudine su tutti i layer Linear."""
parameters_to_prune = [
(module, 'weight')
for module in model.modules()
if isinstance(module, torch.nn.Linear)
]
prune.global_unstructured(
parameters_to_prune,
pruning_method=prune.L1Unstructured,
amount=sparsity
)
# Rende il pruning permanente
for module, param in parameters_to_prune:
prune.remove(module, param)
return model
# Risultati tipici su BERT-Base (110M parametri):
# Pruning 30% teste: -28% latenza inferenza, -1.2% accuracy
# Pruning 50% pesi (magnitude): -45% dimensione, -0.8% accuracy
# Emissioni inferenza: -30% con structured pruning
Distilarea cunoștințelor: modele mici cu cunoștințe mari
Distilarea cunoștințelor transferă cunoștințele de la un model mare (profesor) la unul mic (elev). DistilBERT, de exemplu, are 40% din parametrii BERT-Base dar își menține 97% din performanță pe benchmark-ul GLUE. Emisiile de antrenament ale DistilBERT sunt cu 60% mai mici, iar cele de inferență cu 40-50%.
import torch
import torch.nn as nn
import torch.nn.functional as F
class DistillationLoss(nn.Module):
"""
Loss combinata per knowledge distillation:
L = alpha * L_CE(student, labels) + (1-alpha) * L_KL(student, teacher)
"""
def __init__(self, alpha=0.5, temperature=4.0):
super().__init__()
self.alpha = alpha
self.temperature = temperature
self.ce_loss = nn.CrossEntropyLoss()
def forward(self, student_logits, teacher_logits, labels):
# Loss classificazione standard
loss_ce = self.ce_loss(student_logits, labels)
# Loss distillazione (KL divergence con temperature scaling)
student_soft = F.log_softmax(student_logits / self.temperature, dim=-1)
teacher_soft = F.softmax(teacher_logits / self.temperature, dim=-1)
loss_kl = F.kl_div(student_soft, teacher_soft, reduction='batchmean')
loss_kl *= self.temperature ** 2 # Scala per compensare la temperature
return self.alpha * loss_ce + (1 - self.alpha) * loss_kl
def distill_model(teacher_model, student_model, train_loader,
optimizer, device, epochs=5):
"""Training loop completo per knowledge distillation."""
distill_loss = DistillationLoss(alpha=0.5, temperature=4.0)
teacher_model.eval()
for epoch in range(epochs):
student_model.train()
total_loss = 0.0
for batch in train_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
# Teacher inference (no gradient)
with torch.no_grad():
teacher_outputs = teacher_model(
input_ids=input_ids,
attention_mask=attention_mask
)
# Student forward pass
student_outputs = student_model(
input_ids=input_ids,
attention_mask=attention_mask
)
loss = distill_loss(
student_outputs.logits,
teacher_outputs.logits,
labels
)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch+1}: Loss = {total_loss/len(train_loader):.4f}")
# Caso d'uso tipico: distillare BERT-Large (340M) -> BERT-Tiny (14M)
# Training: 8h vs 2.5h -> -69% tempo
# Emissioni training: -71%
# Accuracy GLUE: 84.6 vs 87.2 -> -3% accettabile per la maggior parte dei task
Căutare eficientă a arhitecturii neuronale
NAS tradițional este, în mod ironic, unul dintre procesele cele mai consumatoare de energie în ML: Căutarea arhitecturii optime poate necesita mii de sesiuni complete de antrenament. The NAS eficient folosește tehnici precum NAS one-shot, partajarea greutății și căutare bazată pe predictori pentru a reduce costurile de căutare cu 99%.
# Esempio con Once-for-All Network (OFA) da MIT
# OFA addestra una volta una supernetwork, poi campiona subnetwork efficienti
# Installazione: pip install ofa
from ofa.model_zoo import ofa_net
# Carica supernetwork pre-addestrata (una volta sola)
ofa_network = ofa_net('ofa_resnet50', pretrained=True)
# Campiona subnetwork che rispettano constraint energetici
# senza riaddestrare (zero-cost NAS)
def find_efficient_subnet(ofa_net, target_flops: float = 200e6):
"""
Cerca una subnetwork con FLOPs < target_flops
usando evolutionary search con predictor di accuracy.
"""
from ofa.nas.search_algorithm import EvolutionFinder
finder = EvolutionFinder(
constraint_type='flops',
efficiency_constraint=target_flops,
efficiency_predictor=ofa_net.flops_counter,
accuracy_predictor=None, # Usa validazione reale
population_size=100,
max_time_budget=500,
parent_ratio=0.25,
mutation_ratio=0.5
)
best_valset_acc, best_info = finder.run_evolution_search()
return best_info['net_config']
# Risultato tipico:
# Supernetwork ResNet-50: 4.1 GFLOPs, 25.6M param
# Subnetwork trovata: 200 MFLOPs, 6.2M param
# Accuracy ImageNet: 77.8% vs 79.2% (- 1.4%, - 95% emissioni inferenza)
Eficiență centrată pe date: calitate vs cantitate
Un set de date de calitate superioară vă permite să obțineți aceeași acuratețe cu mai puține epoci de antrenament și mai puține date. Acesta este unul dintre principiile IA centrată pe date promovat de Andrew Ng: în loc să mărească modelul sau date brute, îmbunătățiți calitatea datelor existente.
Curriculum Learning: Training in the Right Order
Curriculum-ul de învățare ordonează exemplele de instruire prin creșterea dificultății, ca un profesor care începe cu concepte simple înainte de a trece la cele complexe. Această abordare converge mai rapid și cu mai puține epoci totale, reducând amprenta de carbon de 20-35% pe criteriile de referință standard.
import numpy as np
from torch.utils.data import DataLoader, SubsetRandomSampler
from sklearn.metrics import pairwise_distances
class CurriculumScheduler:
"""
Curriculum Learning: ordina il dataset dalla difficolta' crescente.
La difficolta' e' calcolata come distanza dalla media della classe.
"""
def __init__(self, dataset, difficulty_metric='loss', num_stages=4):
self.dataset = dataset
self.num_stages = num_stages
self.difficulty_scores = None
def compute_difficulty(self, model, device):
"""Calcola difficolta' come loss su un modello pre-addestrato leggero."""
model.eval()
scores = []
loader = DataLoader(self.dataset, batch_size=256, shuffle=False)
criterion = nn.CrossEntropyLoss(reduction='none')
with torch.no_grad():
for batch in loader:
input_ids = batch['input_ids'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids=input_ids)
losses = criterion(outputs.logits, labels)
scores.extend(losses.cpu().numpy())
self.difficulty_scores = np.array(scores)
return self.difficulty_scores
def get_stage_indices(self, stage: int) -> list:
"""Ritorna gli indici degli esempi per lo stage corrente."""
if self.difficulty_scores is None:
raise ValueError("Esegui compute_difficulty prima.")
# Divide il dataset in quartili di difficolta'
sorted_indices = np.argsort(self.difficulty_scores)
stage_size = len(sorted_indices) // self.num_stages
# Stage 0: esempi più' facili, Stage N: tutti gli esempi
max_idx = stage_size * (stage + 1)
return sorted_indices[:max_idx].tolist()
def curriculum_training(model, dataset, optimizer, device, total_epochs=20):
"""Training con curriculum progressivo."""
scheduler = CurriculumScheduler(dataset, num_stages=4)
# Usa un modello leggero per calcolare la difficolta'
tiny_model = load_tiny_model().to(device)
difficulty = scheduler.compute_difficulty(tiny_model, device)
for epoch in range(total_epochs):
# Progressione lineare: da 25% a 100% del dataset
stage = min(3, int(epoch / total_epochs * 4))
indices = scheduler.get_stage_indices(stage)
sampler = SubsetRandomSampler(indices)
loader = DataLoader(dataset, batch_size=32, sampler=sampler)
print(f"Epoch {epoch}: usando {len(indices)}/{len(dataset)} esempi")
train_one_epoch(model, loader, optimizer, device)
# Risultati tipici:
# Training standard BERT-Base: 10 epoche per convergenza
# Training con curriculum: 6.5 epoche -> -35% emissioni
Învățare activă: selectați cele mai informative date
Învățarea activă selectează în mod iterativ cele mai informative exemple de etichetat, în loc să utilizați întregul set de date. Cu un buget de adnotare de 10-20% se realizează adesea 90-95% din acuratețea antrenamentului cu date complete, reducând proporțional amprenta de carbon.
from sklearn.cluster import KMeans
import torch.nn.functional as F
class ActiveLearningSelector:
"""Seleziona esempi con massima incertezza (uncertainty sampling)."""
def __init__(self, model, unlabeled_pool, strategy='entropy'):
self.model = model
self.unlabeled_pool = unlabeled_pool
self.strategy = strategy
def compute_uncertainty(self, batch_size=128) -> np.ndarray:
"""Calcola incertezza del modello su ogni esempio non etichettato."""
self.model.eval()
uncertainties = []
loader = DataLoader(self.unlabeled_pool, batch_size=batch_size)
with torch.no_grad():
for batch in loader:
logits = self.model(batch['input_ids']).logits
probs = F.softmax(logits, dim=-1)
if self.strategy == 'entropy':
# Entropia: massima quando la distribuzione e' uniforme
entropy = -(probs * probs.log()).sum(dim=-1)
uncertainties.extend(entropy.cpu().numpy())
elif self.strategy == 'margin':
# Margin: minimo quando le top-2 prob sono simili
top2 = probs.topk(2, dim=-1).values
margin = top2[:, 0] - top2[:, 1]
uncertainties.extend((1 - margin).cpu().numpy())
return np.array(uncertainties)
def select_examples(self, n_select: int) -> list:
"""Seleziona i n_select esempi più' incerti."""
uncertainties = self.compute_uncertainty()
top_indices = np.argsort(uncertainties)[-n_select:]
return top_indices.tolist()
# Workflow Active Learning
def active_learning_loop(
model, labeled_data, unlabeled_pool,
annotation_budget=500, iterations=5
):
per_iteration = annotation_budget // iterations
for iteration in range(iterations):
# Seleziona esempi
selector = ActiveLearningSelector(model, unlabeled_pool)
selected_idx = selector.select_examples(per_iteration)
# Simula annotazione (in produzione: etichettatura umana)
new_labeled = [unlabeled_pool[i] for i in selected_idx]
labeled_data.extend(new_labeled)
# Riaddestra su dati aggiornati
model = fine_tune(model, labeled_data)
acc = evaluate(model)
print(f"Iter {iteration}: {len(labeled_data)} esempi, acc={acc:.3f}")
return model
# Con 500 esempi attivi vs 5000 casuali: stesso livello di accuracy
# Risparmio training: -90% dati -> -85% emissioni
Antrenament Carbon-Aware: Programează instruirea în mod inteligent
Instruirea Carbon Aware este aplicarea principiilor Carbon Aware SDK către lumea ML: în loc să înceapă antrenamentul când inginerul a terminat configurarea experiment, programăm locul de muncă la momentul și în regiunea cu cel mai mic intensitatea carbonului a mixului electric.
Time Shift: Când antrenamentul verde
Intensitatea de carbon a energiei variază enorm pe parcursul zilei și săptămâna, în funcție de disponibilitatea surselor regenerabile. In Italia, diferența dintre orele cele mai verzi (11:00-15:00 vara) și cea mai mare cărbunele (19:00-22:00 iarna) poate fi de 200-300 gCO₂eq/kWh.
import asyncio
import httpx
from datetime import datetime, timedelta
from typing import Optional
import subprocess
ELECTRICITY_MAPS_TOKEN = "YOUR_TOKEN" # electricitymaps.com/api
async def get_carbon_intensity(zone: str = "IT") -> float:
"""Recupera l'intensità' carbonica attuale dalla Electricity Maps API."""
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://api.electricitymap.org/v3/carbon-intensity/latest",
params={"zone": zone},
headers={"auth-token": ELECTRICITY_MAPS_TOKEN}
)
data = resp.json()
return data["carbonIntensity"] # gCO2eq/kWh
async def get_forecast(zone: str = "IT", hours: int = 24) -> list[dict]:
"""Recupera le previsioni di intensità' carbonica per le prossime ore."""
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://api.electricitymap.org/v3/carbon-intensity/forecast",
params={"zone": zone},
headers={"auth-token": ELECTRICITY_MAPS_TOKEN}
)
data = resp.json()
return data["forecast"][:hours]
async def find_optimal_training_window(
job_duration_hours: float,
zone: str = "IT",
max_delay_hours: int = 24
) -> Optional[datetime]:
"""
Trova la finestra temporale ottimale per un training job.
Cerca il window di 'job_duration_hours' con intensità' media minima.
"""
forecast = await get_forecast(zone, hours=max_delay_hours + int(job_duration_hours))
if not forecast:
return None
window_size = max(1, int(job_duration_hours))
best_start = None
best_avg_intensity = float('inf')
for i in range(len(forecast) - window_size + 1):
window = forecast[i:i + window_size]
avg_intensity = sum(h['carbonIntensity'] for h in window) / len(window)
if avg_intensity < best_avg_intensity:
best_avg_intensity = avg_intensity
best_start = datetime.fromisoformat(forecast[i]['datetime'])
print(f"Finestra ottimale: {best_start}")
print(f"Intensità' media: {best_avg_intensity:.1f} gCO2eq/kWh")
return best_start
async def carbon_aware_submit(
training_command: str,
job_duration_hours: float = 6.0,
threshold_gco2_kwh: float = 200.0,
zone: str = "IT"
):
"""
Submette un training job solo quando l'intensità' e' sotto soglia,
altrimenti aspetta la finestra ottimale.
"""
current = await get_carbon_intensity(zone)
if current <= threshold_gco2_kwh:
print(f"Intensità' attuale {current} gCO2/kWh: avvio immediato")
subprocess.Popen(training_command.split())
return
print(f"Intensità' troppo alta ({current} gCO2/kWh > {threshold_gco2_kwh})")
optimal_window = await find_optimal_training_window(
job_duration_hours, zone
)
if optimal_window:
wait_seconds = (optimal_window - datetime.now()).total_seconds()
print(f"Scheduling per {optimal_window} (attesa: {wait_seconds/3600:.1f}h)")
await asyncio.sleep(max(0, wait_seconds))
subprocess.Popen(training_command.split())
# Utilizzo
asyncio.run(carbon_aware_submit(
training_command="python train_bert.py --epochs 10",
job_duration_hours=8.0,
threshold_gco2_kwh=150.0,
zone="IT"
))
Schimbare spațială: alegeți cea mai verde regiune de nor
Diferiți furnizori de cloud oferă regiuni cu mixuri energetice foarte diferite. Alegerea regiunii de antrenament poate reduce emisiile cu 70-90% comparativ cu o alegere aleatorie.
Intensitatea medie a carbonului în funcție de regiunea cloud (2024-2025)
| Furnizorii | Regiune | Locaţie | gCO₂eq/kWh | Note |
|---|---|---|---|---|
| GCP | europa-nord1 | Finlanda | ~35 | Hidroelectric + eolian |
| AWS | eu-nord-1 | Stockholm | ~40 | Aproape 100% regenerabile |
| GCP | europa-vest1 | Belgia | ~56 | Mix de energie regenerabilă + nucleară |
| Azur | francecentral | Paris | ~58 | Nuclear dominant |
| AWS | eu-vest-1 | Irlanda | ~250 | Gaze naturale predominante |
| AWS | noi-est-1 | Virginia | ~296 | Mix din Orientul Mijlociu SUA |
| AWS | ap-sud-est-1 | Singapore | ~408 | Gaz natural |
# Spot Instances per training carbon-aware
# Le spot instance non solo riducono i costi del 60-90%,
# ma tendono a essere distribuite su hardware più' recente ed efficiente
import boto3
from botocore.exceptions import ClientError
def submit_spot_training(
image_uri: str,
instance_type: str = "p4d.24xlarge", # 8x A100
region: str = "eu-north-1", # Stoccolma: ~40 gCO2/kWh
max_price_per_hour: float = 15.0
):
"""Submette un training job su spot instances AWS SageMaker."""
sagemaker = boto3.client('sagemaker', region_name=region)
response = sagemaker.create_training_job(
TrainingJobName=f"green-ml-{int(datetime.now().timestamp())}",
AlgorithmSpecification={
'TrainingImage': image_uri,
'TrainingInputMode': 'FastFile'
},
ResourceConfig={
'InstanceType': instance_type,
'InstanceCount': 1,
'VolumeSizeInGB': 100
},
# Managed Spot Training
EnableManagedSpotTraining=True,
StoppingCondition={
'MaxRuntimeInSeconds': 86400, # 24 ore max
'MaxWaitTimeInSeconds': 172800 # Aspetta fino a 48 ore
},
# Checkpointing per riprendere se lo spot viene interrotto
CheckpointConfig={
'S3Uri': f's3://my-bucket/checkpoints/',
'LocalPath': '/opt/ml/checkpoints'
}
)
return response['TrainingJobArn']
# Confronto costi e emissioni:
# p4d.24xlarge on-demand (us-east-1): $32.77/h, 296 gCO2/kWh
# p4d.24xlarge spot (eu-north-1): $9.83/h, 40 gCO2/kWh
# Risparmio economico: -70%
# Risparmio emissioni: -86% (spot + regione verde)
Optimizarea inferenței: 77% din amprenta de carbon
După cum era anticipat, inferența în producție domină emisiile în ciclul de viață al Modele ML. Pentru un model cu milioane de utilizatori, fiecare milisecundă de latență redusă și fiecare watt de consum redus se înmulțește cu miliarde de solicitări pe an. Principalele tehnici sunt cuantizarea, compilarea modelului și loturile optimizate.
Cuantizare: INT8, INT4 și GPTQ
Cuantizarea reduce precizia numerică a greutăților modelului de la FP32 sau FP16 la numere întregi de 8 sau 4 biți. Acest lucru reduce cerințele de memorie cu 50-75%, accelerează inferența de 2-4x și reduce proporțional consumul de energie.
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch
# Quantizzazione INT4 con GPTQ (post-training quantization)
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True, # QLoRA: double quantization
bnb_4bit_quant_type="nf4" # Normal Float 4: migliore qualità'
)
model_id = "meta-llama/Llama-2-7b-hf"
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=quantization_config,
device_map="auto",
torch_dtype=torch.bfloat16
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
# Verifica riduzione memoria
original_size_gb = 7 * 2 / 1024 # 7B param x 2 byte (FP16) / 1024
quantized_size_gb = 7 * 0.5 / 1024 # 7B param x 0.5 byte (INT4) / 1024
print(f"FP16: {original_size_gb:.1f} GB")
print(f"INT4: {quantized_size_gb:.1f} GB (-{(1-quantized_size_gb/original_size_gb)*100:.0f}%)")
# Quantizzazione INT8 con ONNX Runtime (per produzione)
from optimum.onnxruntime import ORTModelForSequenceClassification
from optimum.onnxruntime.configuration import AutoQuantizationConfig
# Esporta in ONNX e quantizza
ort_model = ORTModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
export=True
)
quantization_config = AutoQuantizationConfig.avx512_vnni(
is_static=False, # Dynamic quantization (no calibration data needed)
per_channel=False
)
# Salva il modello quantizzato
from optimum.onnxruntime import ORTQuantizer
quantizer = ORTQuantizer.from_pretrained(ort_model)
quantizer.quantize(
save_dir="./bert-int8-onnx",
quantization_config=quantization_config
)
# Benchmark:
# BERT-Base FP32: 23ms latenza, 100% accuracy, 1.6 GB
# BERT-Base INT8: 12ms latenza, 99.2% accuracy, 0.4 GB -> -48% energia
# BERT-Base INT4: 8ms latenza, 97.8% accuracy, 0.2 GB -> -65% energia
vLLM: Servire eficientă pentru LLM
vLLM este un cadru de servire pentru LLM care utilizează PagedAtenție pentru a gestiona mult mai eficient memoria cache KV. În comparație cu o porție naivă, vLLM crește debitul de 15-24x cu același hardware, reducând proporțional consumul de energie pe token generat.
from vllm import LLM, SamplingParams
from codecarbon import EmissionsTracker
# Avvia LLM con vLLM (PagedAttention + continuous batching)
llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
tensor_parallel_size=1, # GPU count
gpu_memory_utilization=0.90, # Usa il 90% della VRAM per KV cache
max_num_batched_tokens=32768, # Batch maggiori = più' efficiente
quantization="awq" # AWQ quantization integrata
)
sampling_params = SamplingParams(
temperature=0.7,
max_tokens=256
)
# Misura emissioni per 1000 richieste
tracker = EmissionsTracker(project_name="vllm-inference-benchmark")
tracker.start()
prompts = ["Spiega il concetto di machine learning in italiano"] * 1000
outputs = llm.generate(prompts, sampling_params)
emissions = tracker.stop()
tokens_generated = sum(len(o.outputs[0].token_ids) for o in outputs)
print(f"Token generati: {tokens_generated:,}")
print(f"Emissioni: {emissions*1000:.2f} gCO2eq")
print(f"gCO2eq per 1000 token: {emissions*1000/tokens_generated*1000:.4f}")
# Confronto con serving naive HuggingFace:
# HuggingFace Transformers: 1.000 req, 45 min, 890 gCO2eq
# vLLM: 1.000 req, 3 min, 59 gCO2eq (-93%)
# Throughput: 333 req/min vs 22 req/min
Scor SCI pentru modelele ML: standardizarea măsurătorilor
Caietul de sarcini SCI (Software pentru intensitatea carbonului) al Green Software Foundation, acum standardul ISO/IEC 21031:2024, se aplică și sistemelor ML. SCI exprimă emisiile per unitate funcțională, permițând comparații semnificative între diferite modele.
Formula SCI aplicată sistemelor ML
| Componentă | Formula ML | Exemplu de inferență BERT |
|---|---|---|
| E (Energie) | Putere GPU x Timp / 1000 | 300 W x 0,05 s / 1000 = 0,000015 kWh |
| I (Intensitatea carbonului) | gCO₂eq/kWh din regiune | 420 gCO₂eq/kWh (media Italia) |
| M (Intruchipat) | Hardware CO₂ / (durată de viață x utilizare) | 150.000 gCO₂ / (26.280 h x 0,7) = 8,2 g/h |
| R (Unitate funcțională) | 1.000 de inferențe sau 1 token generat | 1.000 de clasificări |
| SCHI | (E x I + M) / R | (0,015 x 0,420 + 0,00023) / 1 = 0,0065 gCO₂eq/req |
from dataclasses import dataclass
from typing import Literal
@dataclass
class MLSystemSCI:
"""Calcola SCI Score per sistemi ML."""
model_name: str
gpu_count: int
gpu_tdp_watts: float
avg_latency_ms: float # Per inferenza singola
carbon_intensity_g_kwh: float # gCO2/kWh regione
gpu_lifespan_hours: float = 26_280 # 3 anni
gpu_embodied_gco2: float = 150_000 # ~150 kgCO2 per GPU
utilization: float = 0.70
pue: float = 1.3
functional_unit: Literal['request', 'token'] = 'request'
def operational_energy_kwh(self) -> float:
"""Energia operativa per singola inferenza."""
return (
self.gpu_count
* self.gpu_tdp_watts
* (self.avg_latency_ms / 1000)
/ 1_000 # W -> kW
)
def operational_emissions_g(self) -> float:
"""Emissioni operative per singola inferenza (gCO2eq)."""
return (
self.operational_energy_kwh()
* self.carbon_intensity_g_kwh
* self.pue
)
def embodied_per_request_g(self) -> float:
"""Quota embodied per singola inferenza."""
# Secondi per richiesta / secondi per vita GPU
fraction_of_life = (self.avg_latency_ms / 1000) / (
self.gpu_lifespan_hours * 3600
)
total_embodied = self.gpu_count * self.gpu_embodied_gco2
return total_embodied * fraction_of_life / self.utilization
@property
def sci_score(self) -> float:
"""SCI = (E x I + M) / R per singola richiesta."""
return self.operational_emissions_g() + self.embodied_per_request_g()
# Confronto modelli
models = [
MLSystemSCI("BERT-Base INT8/CPU", 0, 100, 45, 420, gpu_count=0,
gpu_embodied_gco2=0),
MLSystemSCI("BERT-Base FP32/A100", 1, 400, 12, 420),
MLSystemSCI("BERT-Base INT8/A100", 1, 280, 6, 420),
MLSystemSCI("DistilBERT FP16/A100", 1, 240, 5, 420),
MLSystemSCI("BERT-Base INT8/eu-north-1", 1, 280, 6, 40), # Stoccolma
]
print(f"{'Modello':<35} {'SCI (gCO2/req)':<18} {'vs Baseline'}")
baseline = models[0].sci_score
for m in models:
sci = m.sci_score
ratio = sci / baseline
print(f"{m.model_name:<35} {sci:.6f} gCO2 {ratio:.2f}x")
Clasament verde AI: eficiență peste acuratețe
Clasamentele tradiționale precum GLUE, SuperGLUE și MMLU măsoară doar precizia. Conceptul de Clasament verde AI, propus de Schwartz et al. (2020) și oficializat de GSF în 2024, introduce metrici compozite care echilibrează performanta si eficienta carbonului.
Valori Green AI: Compensație acuratețe/emisii (indice de referință GLUE)
| Model | Scorul GLUE | CO₂eq Tren (t) | CO₂eq Infer (mg/req) | Scor verde* |
|---|---|---|---|---|
| BERT-Baza | 82.1 | 0,9 | 0,62 | 132 |
| ROBERTa-Baza | 86.4 | 4.1 | 0,62 | 139 |
| DistilBERT | 77,0 | 0,35 | 0,31 | 248 |
| BERT-Base INT8 | 81.3 | 0,9 | 0,28 | 290 |
| MobileBERT | 78.2 | 0,6 | 0,18 | 434 |
| ALBERT-Base v2 | 82.3 | 0,5 | 0,42 | 196 |
* Scor verde = (Scor GLUE / Inferență CO₂eq) x 1000. Valori mai mari = mai eficient.
Observați cum DistilBERT, în ciuda unui scor GLUE cu 6% mai mic decât BERT-Base, are un scor verde aproape dublu. MobileBERT oferă cel mai bun scor verde de pe listă, făcându-l alegerea optimă pentru implementări la scară cu bugete limitate de carbon.
Studiu de caz: Reducerea cu 60% a emisiilor pe un model NLP
Acest studiu de caz descrie o cale de optimizare reală aplicată unui model de clasificare a sentimentelor pentru piața italiană, dezvoltată pentru o companie de comerț electronic cu 2 milioane de recenzii lunare de procesat.
Linia de referință: starea inițială
# STATO INIZIALE (Baseline)
# Modello: bert-base-multilingual-cased (177M parametri)
# Hardware: 1x NVIDIA A100 80GB SXM4 (on-demand AWS us-east-1)
# Task: classificazione sentiment 5 classi (1-5 stelle)
# Dataset: 500.000 recensioni in italiano
# Metriche baseline:
Training_time_hours = 18.5
Energy_training_kWh = 130.0 # A100 SXM4: ~400W TDP, PUE=1.5
CO2_training_kgCO2eq = 38.5 # 130 kWh x 0.296 kgCO2/kWh (us-east-1)
Inference_latency_ms = 35.0 # Per singola recensione
Inference_throughput_req_s = 28.6
CO2_inference_per_1M_req = 2.85 # kgCO2eq
Monthly_inference_requests = 2_000_000
Monthly_inference_CO2_kg = 5.70
Annual_training_runs = 4 # Re-training trimestrale
Annual_total_CO2_kg = (4 * 38.5) + (12 * 5.70) = 222.4
Accuracy_f1_macro = 0.847
Optimizare pas cu pas
# STEP 1: Cambio regione cloud (us-east-1 -> eu-north-1)
# Carbon intensity: 296 -> 40 gCO2/kWh (-86%)
# Nessun cambiamento al codice, solo flag AWS Region
CO2_training_kgCO2eq_step1 = 130.0 * 0.040 * 1.5 = 7.8 # -80%
Monthly_inference_CO2_step1 = 2.85 * (40/296) = 0.38 # -87%
Annual_CO2_step1 = (4 * 7.8) + (12 * 0.38) = 35.7 kg # -84%
# STEP 2: Cambio modello base (multilingual -> umberto italiano)
# umberto-commoncrawl-cased (bert-base size ma solo italiano)
# Dataset training ridotto del 30% (solo dati italiani puliti)
# Curriculum learning: 15 epoche vs 20 -> -25% training time
CO2_training_kgCO2eq_step2 = 7.8 * 0.75 * 0.70 = 4.1 # -47% su step1
Accuracy_f1_macro_step2 = 0.861 # +1.4% grazie a modello specializzato
# STEP 3: Quantizzazione INT8 (ONNX Runtime)
# Latenza inferenza: 35ms -> 18ms (-49%)
# Throughput: 28.6 -> 55.5 req/s (+94%)
Inference_latency_ms_step3 = 18.0
Monthly_inference_CO2_step3 = 0.38 * 0.50 = 0.19 # -50%
Accuracy_f1_macro_step3 = 0.856 # -0.5% accettabile
# STEP 4: Carbon-aware scheduling del re-training
# Spot instances + finestre energetiche verdi
# Costo spot eu-north-1: -70% vs on-demand
# Timing training nelle ore di massima rinnovabile
CO2_training_kgCO2eq_step4 = 4.1 * 0.85 = 3.5 # Spot: stesso hardware, timing migliore
# RIEPILOGO OTTIMIZZAZIONI
print("=" * 60)
print(f"Baseline: {222.4:.1f} kgCO2eq/anno | F1: 0.847")
print(f"Step 1: {35.7:.1f} kgCO2eq/anno | -84% (solo regione)")
print(f"Step 2: {26.9:.1f} kgCO2eq/anno | -87% (modello+data)")
print(f"Step 3: {21.7:.1f} kgCO2eq/anno | -90% (quantizzazione)")
print(f"Step 4: {18.6:.1f} kgCO2eq/anno | -92% (carbon-aware)")
print(f"F1 finale: 0.856 vs 0.847 baseline (+1.1%)")
print("=" * 60)
print(f"Riduzione CO2: -203.8 kgCO2eq/anno (-91.6%)")
print(f"Risparmio costi: -74% (spot + regione + efficienza)")
Rezultatele studiului de caz: rezumat
| Metric | Linii de bază | Optimizat | Variaţie |
|---|---|---|---|
| CO₂eq. total anual | 222 kgCO₂eq | 19 kgCO₂eq | -91% |
| F1-Scor Macro | 0,847 | 0,856 | +1,1% |
| Latența de inferență | 35 ms | 18 ms | -49% |
| Debit | 28 solicitat/s | 55 solicitat/s | +96% |
| Cost lunar cloud | ~2.400 EUR | ~620 EUR | -74% |
Lecție cheie: 90% din emisii sunt reduse fără a sacrifica acuratețea
În acest studiu de caz, fiecare pas de optimizare are îmbunătățită sau a menținut acuratețea modelului. Alegerea regiunii cloud salvate 84% din emisii fără a atinge o linie de cod. Specializarea de șablonul pentru limba italiană a îmbunătățit calitatea. Cuantizarea a înjumătăţit latenţa. Mesajul este clar: optimizați pentru carbon amprenta și optimizarea pentru calitate nu sunt obiective contradictorii.
Foaia de parcurs verde AI pentru organizații
Adoptarea Green AI nu necesită revoluționarea imediată a tuturor lucrurilor. O foaie de parcurs în trei faze vă permite să introduceți practicile progresiv, începând de la optimizări cu impact mai mare și mai puțin efort.
Foaia de parcurs pentru adoptarea AI verde în 3 faze
| Fază | Cronologie | Acțiuni | Se așteaptă reducerea CO₂ |
|---|---|---|---|
| Pasul 1: Măsurați | Săptămâna 1-4 |
Instalați CodeCarbon pe toate joburile de instruire; definirea liniilor de bază ale emisiilor per model; alegeți regiuni de nori mai verzi |
50-85% (numai regiune) |
| Pasul 2: Optimizați | Luna 2-4 |
Aplicați precizie mixtă (BF16) la toate antrenamentele; cuantificarea modelelor în producție (INT8); adoptați instanțe spot pentru instruirea în loturi |
Suplimentar 30-50% |
| Faza 3: Integrare | Luna 5-12 |
Programare automatizată cu respectarea carbonului; Clasament intern Green AI; scor SCI în criteriile de implementare; ESG care raportează emisiile ML |
Suplimentar 10-20% |
Lista de verificare verde AI pentru fiecare job de formare
# Checklist Green AI da seguire prima di ogni training
# Copia in: .github/PULL_REQUEST_TEMPLATE.md o come commento training script
CHECKLIST_GREEN_AI = """
Green AI Pre-Training Checklist
================================
[ ] 1. REGIONE: Training schedulato in regione con CI < 150 gCO2/kWh?
Verifica: https://app.electricitymaps.com/zone/IT
Preferisci: GCP europe-north1, AWS eu-north-1, Azure swedencentral
[ ] 2. TIMING: Carbon-aware scheduling attivato?
Tool: Carbon Aware SDK o script custom
Finestra ottimale: verificata nelle ultime 24h
[ ] 3. HARDWARE: GPU di ultima generazione disponibile?
H100 >> A100 (44% più' efficiente)
Spot/preemptible instances preferite
[ ] 4. PRECISION: Mixed precision attivata (BF16/FP16)?
HuggingFace: bf16=True in TrainingArguments
PyTorch: torch.autocast('cuda', dtype=torch.bfloat16)
[ ] 5. EARLY STOPPING: Configurato con CarbonTracker per proiezione?
Stima emissioni dopo 5 epoche e confronta con budget CO2
[ ] 6. TRACKING: CodeCarbon configurato?
Country_iso_code, cloud_provider, cloud_region impostati
Output in: ./carbon_reports/
[ ] 7. DATI: Dataset ottimizzato con deduplication e qualità'?
Almeno 10% redundancy rimossa
Active learning per ridurre dimensione se possibile
[ ] 8. BASELINE: Esiste una run precedente da confrontare?
Registra su MLflow: accuracy, emissioni, ratio
[ ] 9. INFERENZA: Quantizzazione pianificata per produzione?
Target: INT8 con ONNX Runtime o INT4 per LLM
[ ] 10. REPORTING: Emissioni saranno incluse nel model card?
Usa: SCI Score, kgCO2eq training, gCO2eq/1000 req inferenza
"""
print(CHECKLIST_GREEN_AI)
Concluzii: Rezumatul seriei Green Software Engineering
Acest articol încheie seria Green Software Engineering, o călătorie în 10 articole care a străbătut întregul spectru de practici dezvoltare durabilă de software. De la teoria principiilor GSF la implementări practici cu CodeCarbon, Carbon Aware SDK, Climatiq API, până la tehnici optimizare avansată ML: am creat un set de instrumente cuprinzător pentru dezvoltatori și organizații care doresc să își reducă impactul asupra mediului digital.
Cele 10 mesaje cheie ale seriei
| # | Articol | Mesaj cheie |
|---|---|---|
| 1 | Principiile GSF | Eficiența carbonului este o măsură a calității software |
| 2 | CodeCarbon | Nu poți reduce ceea ce nu măsori: începe din ziua 1 |
| 3 | Climatiq API | CO₂ are un API: integrați contabilitatea carbonului în backend-ul dvs |
| 4 | SDK Carbon Aware | Mutarea unei sarcini de lucru în timp sau spațiu poate reduce cu 90% |
| 5 | Modelarea domeniului | SCI este standardul ISO pentru compararea eficienței de carbon a software-ului |
| 6 | GreenOps | Verde și FinOps se aliniază: optimizarea CO₂ reduce costurile cloud |
| 7 | Conducta Scope 3 | Emisiile indirecte sunt adesea mai mari decât emisiile directe |
| 8 | ESG și CSRD | Din 2025, raportarea digitală ESG este o obligație legală pentru multe companii |
| 9 | Modele durabile | Cache-ul, lotul și asincronizarea nu sunt doar performanță: sunt modele verzi |
| 10 | AI Carbon | Alegerea regiunii cloud reduce emisiile ML mai mult decât orice algoritm |
Momentul este Acum
Inteligența artificială generativă va continua să crească. Modelele vor deveni mai mari, cu cât instruirea este mai frecventă, cu atât implementarea este mai răspândită. Întrebarea nu este dacă emisiile de IA vor crește — vor crește oricum — dar cu cât. Tehnicile din acest articol demonstrează că este posibil să se reducă 60-90% emisiile unui sistem ML fără a sacrifica acuratețea și, adesea, chiar a reduce costurile. Acesta nu este un compromis: este o victorie pe toate fronturile.
Green Software Foundation estimează că dacă fiecare echipă ML ar adopta practicile de formarea conștientă de carbon și cuantificarea inferenței, a emisiilor globale ale sectorului AI ar putea fi redusă cu 40-60% până în 2030 comparativ cu scenariul afaceri ca de obicei. Nu avem nevoie de progrese tehnologice: avem nevoie de practicile descrise în aceste zece articole, se aplică sistematic.
Următorul pas este al tău. Instalați CodeCarbon la următoarea sarcină de antrenament. Verificați intensitatea carbonului din regiunea dvs. AWS sau GCP. Cuantizează modelul înainte de a-l implementa. Măsurați scorul SCI. Și când o faci, veți fi făcut cel mai important pas: începerea.
Link-uri și instrumente utile
- CodeCarbon: mlco2.github.io/codecarbon
- Calculator de impact ML CO₂: mlco2.github.io/impact
- Calculator de algoritmi verzi: green-algorithms.org
- Electricity Maps API: electricitymaps.com/api
- Specificația GSF SCI: sci.greensoftware.fundație
- Urmăritorul emisiilor Hugging Face: Urmărirea carbonului HuggingFace Hub
- Servire vLLM: docs.vllm.ai
- ONNX Runtime Optimization: onnxruntime.ai
Continuați Calea: Seria similară
- MLOps pentru afaceri: Aflați mai multe despre implementarea modelelor ML cu Conducte MLflow, DVC și CI/CD - inclusiv porți de calitate a amprentei de carbon.
- AI Engineering & RAG: Explorați cum să construiți sisteme RAG eficientă care minimizează numărul de apeluri către modelele LLM, reducând ambele costurile pe care emisiile.
- Afaceri cu date și inteligență artificială: Aflați cum AI Act UE și reglementări ESG se intersectează cu practicile Green AI și cum să construiți o foaie de parcurs sustenabil bazat pe date pentru IMM-uri.







