Măsurarea amprentei de carbon a codului dvs. cu CodeCarbon
De fiecare dată când antrenați un model de învățare automată, rulați o conductă ETL sau învârtiți o lucrare batch noaptea, consumi energie. Acea energie are un cost real de carbon, care depinde de unde și când rulezi codul. Sectorul TIC în ansamblu este responsabil pentru 2-4% din emisiile globale de CO₂, o cotă comparabilă cu cea a întregii industrie aeronautice globale. Dar a Spre deosebire de un zbor, emisiile software sunt aproape întotdeauna invizibile.
Antrenament GPT-3 a produs cca 552 de tone de CO₂, echivalentul a 300 de călătorii dus-întors New York-San Francisco cu avionul. O reglare fină a BERT-large pe un GPU A100 timp de 10 ore în Germania (mixul energetic la ~381 gCO₂/kWh) emite aprox 1,2 kg de CO₂. Același antrenament mutat în Franța (nuclear, ~56 gCO₂/kWh) produce numai 177 de grame. Diferența este de aproape 7 ori, pentru același cod.
CodeCarbon este instrumentul open-source care face ca aceste emisii să fie măsurabile și comparabile. Cu câteva linii de Python puteți urmări amprenta de carbon a oricărui proces computaționale, de la un singur experiment ML până la conducta de producție și să integreze aceste valori în fluxurile dvs. de lucru MLflow, rapoarte ESG și conducte CI/CD.
Ce vei învăța
- Arhitectura internă a CodeCarbon: cum măsoară energia și calculează emisiile de CO₂
- Configurați cu
EmissionsTrackereOfflineEmissionsTracker - Urmărirea la antrenamentul modelelor TensorFlow și PyTorch
- Măsurare GPU cu CUDA și NVML pentru hardware NVIDIA
- Configurație pentru diferite țări europene și intensitatea de carbon a rețelei
- Integrare cu MLflow pentru emisii ca metrici de experiment
- Tabloul de bord cu matplotlib și plotly pentru vizualizarea tendințelor
- Cloud Carbon Footprint pentru a estima emisiile pe AWS, GCP și Azure
- Comparație de instrumente: CodeCarbon vs Eco2AI vs CarbonTracker vs ML CO2 Impact
- Studiu de caz real: optimizarea antrenamentului NLP cu reducerea cu 96% a emisiilor
Seria Green Software: 10 articole pentru dezvoltarea unui software durabil
| # | Articol | Subiect | Stat |
|---|---|---|---|
| 1 | Principiile Green Software Foundation | GSF, SCI, 8 principii fundamentale | Disponibil |
| 2 | Măsurarea amprentei de carbon cu CodeCarbon | Măsurare, urmărire, tablou de bord | Articolul curent |
| 3 | Integrați API-ul Climatiq | Calcule GHG Protocol, Scop 1-3 | Disponibil |
| 4 | SDK Carbon Aware | Schimbarea timpului, schimbarea locației | Disponibil |
| 5 | Domeniul 1, 2 și 3: Modelarea datelor ESG | Structura datelor, calcule, agregare | Disponibil |
| 6 | GreenOps cu Kubernetes | Programare conștientă de carbon, infrastructură | Disponibil |
| 7 | Pipeline Scope 3 Value Chain | Date despre furnizor, pistă de audit | Disponibil |
| 8 | Raportare ESG și CSRD API | Conformitate europeană, automatizare | Disponibil |
| 9 | Modele arhitecturale durabile | Stocare, cache, lot de carbon | Disponibil |
| 10 | AI și carbon: amprenta antrenamentului ML | Green AI, optimizarea antrenamentului | Disponibil |
CodeCarbon: Arhitectură și mecanism de operare
CodeCarbon este o bibliotecă Python open-source dezvoltată printr-o colaborare între Institutul Mila Quebec AI, Universitatea Carnegie Mellon, Comet.ml și BCG GAMMA. Proiectul a luat naștere în 2020 cu scopul de a face măsurarea emisiilor de cod accesibil oricărui cercetător de date, fără a necesita echipament hardware dedicat.
Principiul de funcționare se bazează pe o formulă fundamentală:
Formula centrală CodeCarbon
CO₂ emis [kg] = Energie consumată [kWh] × Intensitatea carbonului rețelei [kgCO₂/kWh]
Energia consumata este masurata componenta cu componenta (GPU + CPU + RAM), în timp ce intensitatea carbonului este preluată din bazele de date actualizate pe țară/regiune sau furnizate manual pentru medii offline.
Conducta de măsurare internă
CodeCarbon eșantionează consumul de energie fiecare 15 secunde (configurabil) prin o conductă cu mai multe niveluri. La fiecare eșantionare măsoară puterea instantanee a CPU, GPU și RAM, se integrează în timp pentru a obține kWh și se înmulțește cu factorul de emisie al țării.
Ierarhia de măsurare a energiei
| Componentă | Metoda de măsurare | Precizie | Disponibilitate |
|---|---|---|---|
| GPU-uri NVIDIA | NVML prin pynvml (Biblioteca de management NVIDIA) | Ridicat (măsurare directă) | Doar GPU-uri NVIDIA cu drivere |
| CPU Intel | RAPL (Running Average Power Limit) prin pyRAPL | Ridicat (senzori hardware) | Linux cu acces MSR, Intel |
| procesoare AMD/ARM | TDP estimat + procent de utilizare | Medie (estimare) | Toate sistemele |
| RAM | Formula empirică: 3W per 8GB | Scăzut-Mediu (estimare) | Toate sistemele |
| GPU-uri AMD | ROCm SMI (dacă este disponibil) | Ridicat (măsurare directă) | GPU AMD cu ROCm |
Intensitatea carbonului în funcție de țară
Pentru a traduce kWh în kgCO₂, CodeCarbon utilizează o bază de date ierarhică a factorilor de emisie. În modul online, preluați date prin geolocalizare IP. În modul offline, utilizează o bază de date internă cu valori medii anuale pentru peste 240 de țări.
Intensitatea carbonului pe țară europeană (2024)
| Sat | gCO₂/kWh | Mixul energetic principal | Cod ISO |
|---|---|---|---|
| Norvegia | ~28 | Hidroelectric (90%) | NICI |
| Franţa | ~56 | Nuclear (70%) | ÎNTRE |
| Suedia | ~45 | Nuclear + Hidro | SWE |
| Spania | ~191 | Energii regenerabile + gaze | EXP |
| Italia | ~233 | Gaze naturale + surse regenerabile | ITA |
| Germania | ~381 | Gaz + Cărbune + Vânt | DEU |
| Polonia | ~640 | Cărbune (70%) | POL |
Configurarea și instalarea CodeCarbon
Instalarea CodeCarbon necesită Python 3.7+ și este disponibilă pe PyPI și conda. Pentru urmărirea GPU aveți nevoie de drivere NVIDIA și pachetul pynvml.
Instalare
# Installazione base
pip install codecarbon
# Con dipendenze per visualizzazione dashboard
pip install codecarbon[viz]
# Per ambienti conda
conda install -c conda-forge codecarbon
# Verifica installazione
python -c "from codecarbon import EmissionsTracker; print('CodeCarbon OK')"
# Controlla quale hardware viene rilevato
python -c "
import pynvml
try:
pynvml.nvmlInit()
count = pynvml.nvmlDeviceGetCount()
for i in range(count):
h = pynvml.nvmlDeviceGetHandleByIndex(i)
print(f'GPU {i}: ', pynvml.nvmlDeviceGetName(h))
pynvml.nvmlShutdown()
except Exception as e:
print(f'GPU non rilevata: {e}')
print('CodeCarbon usera stima TDP per CPU')
"
Fișier de configurare .codecarbon.config
CodeCarbon acceptă un fișier de configurare INI la nivelul întregului proiect care evită repetarea
parametrii din fiecare script. Creați un fișier .codecarbon.config în rădăcina proiectului:
# .codecarbon.config
[codecarbon]
# Modalità: online (default) o offline
mode = online
# Paese ISO 3166-1 alpha-3 per carbon intensity
country_iso_code = ITA
# Intervallo di campionamento in secondi (default: 15)
measure_power_secs = 15
# File di output CSV
output_file = emissions.csv
# Directory output
output_dir = ./carbon_reports
# Log level: DEBUG, INFO, WARNING, ERROR
log_level = INFO
# Salva su CodeCarbon cloud dashboard (richiede API key)
save_to_api = false
# Modalità di tracking
tracking_mode = process
EmissionsTracker: trei moduri de utilizare
from codecarbon import EmissionsTracker
from codecarbon import track_emissions
import time
# ===== MODALITA 1: Context Manager (raccomandato) =====
with EmissionsTracker(
project_name="my-ml-project",
output_dir="./carbon_reports",
country_iso_code="ITA",
log_level="INFO"
) as tracker:
print("Training in corso...")
time.sleep(5) # Simula training
print(f"Emissioni: {tracker.final_emissions:.6f} kgCO2eq")
print(f"Energia: {tracker.final_emissions_data.energy_consumed:.4f} kWh")
# ===== MODALITA 2: Start/Stop Espliciti =====
tracker = EmissionsTracker(
project_name="batch-job",
output_file="batch_emissions.csv",
measure_power_secs=10
)
tracker.start()
print("Preprocessing...")
time.sleep(3)
tracker.flush() # Checkpoint senza fermare il tracking
print("Training...")
time.sleep(5)
emissions = tracker.stop()
print(f"CO2 emessa: {emissions:.6f} kgCO2eq")
# ===== MODALITA 3: Decorator =====
@track_emissions(
project_name="inference-pipeline",
country_iso_code="FRA",
output_dir="./carbon_reports"
)
def run_inference(model, data):
return model.predict(data)
OfflineEmissionsTracker: pentru medii fără internet
În clustere HPC, containere de producție sau mașini fără acces la internet, utilizați
OfflineEmissionsTracker. Codul de țară ISO devine obligatoriu.
from codecarbon import OfflineEmissionsTracker
tracker = OfflineEmissionsTracker(
country_iso_code="ITA", # Obbligatorio in modalità offline
project_name="hpc-training",
output_dir="/results/carbon",
measure_power_secs=30, # Meno frequente per ridurre overhead
log_level="WARNING"
)
tracker.start()
try:
run_training_pipeline()
except Exception as e:
print(f"Errore: {e}")
raise
finally:
# Chiama sempre stop() anche in caso di errore
emissions = tracker.stop()
if emissions:
print(f"[Carbon] {emissions:.4f} kgCO2eq")
# Override carbon intensity manuale (es: data center con energia 100% rinnovabile)
tracker_custom = OfflineEmissionsTracker(
country_iso_code="ITA",
# Specifica intensità carbonica del tuo fornitore (es: 20 gCO2/kWh)
# mediante variabile ambiente CODECARBON_CARBON_INTENSITY=0.020
measure_power_secs=15
)
Urmărirea emisiilor în proiecte de învățare automată
Cazul de utilizare principal al CodeCarbon este urmărirea atunci când antrenați modele ML. Să vedem exemple practice cu PyTorch și TensorFlow/Keras.
Antrenament PyTorch cu urmărire completă a carbonului
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from codecarbon import EmissionsTracker
import numpy as np
import json
from datetime import datetime
class TextClassifier(nn.Module):
def __init__(self, vocab_size, embed_dim, num_classes):
super(TextClassifier, self).__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.lstm = nn.LSTM(embed_dim, 128, batch_first=True, bidirectional=True)
self.classifier = nn.Sequential(
nn.Linear(256, 64),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(64, num_classes)
)
def forward(self, x):
embedded = self.embedding(x)
lstm_out, _ = self.lstm(embedded)
pooled = lstm_out.mean(dim=1)
return self.classifier(pooled)
def train_with_carbon_tracking(model, train_loader, val_loader, epochs=10, country="ITA"):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
optimizer = optim.AdamW(model.parameters(), lr=2e-4, weight_decay=0.01)
criterion = nn.CrossEntropyLoss()
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs)
training_history = []
tracker = EmissionsTracker(
project_name=f"text-classifier-{datetime.now().strftime('%Y%m%d_%H%M')}",
output_dir="./carbon_reports",
country_iso_code=country,
log_level="WARNING",
measure_power_secs=15
)
tracker.start()
gpu_name = torch.cuda.get_device_name(0) if torch.cuda.is_available() else "N/A"
print(f"Dispositivo: {device} | GPU: {gpu_name} | Paese: {country}")
for epoch in range(epochs):
# Training
model.train()
train_loss, correct, total = 0.0, 0, 0
for X, y in train_loader:
X, y = X.to(device), y.to(device)
optimizer.zero_grad()
out = model(X)
loss = criterion(out, y)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
train_loss += loss.item()
correct += out.argmax(1).eq(y).sum().item()
total += y.size(0)
# Validation
model.eval()
val_correct, val_total = 0, 0
with torch.no_grad():
for X, y in val_loader:
X, y = X.to(device), y.to(device)
out = model(X)
val_correct += out.argmax(1).eq(y).sum().item()
val_total += y.size(0)
scheduler.step()
stats = {
"epoch": epoch + 1,
"train_acc": 100. * correct / total,
"val_acc": 100. * val_correct / val_total,
"train_loss": train_loss / len(train_loader),
}
training_history.append(stats)
print(f"Epoch {epoch+1}/{epochs} | "
f"Train: {stats['train_acc']:.2f}% | Val: {stats['val_acc']:.2f}%")
total_emissions = tracker.stop()
em_data = tracker.final_emissions_data
final_val_acc = training_history[-1]["val_acc"]
print(f"\n=== CARBON REPORT ===")
print(f"CO2 totale: {total_emissions:.6f} kgCO2eq")
print(f"Per epoch: {total_emissions / epochs * 1000:.2f} gCO2eq")
if em_data:
print(f"Energia: {em_data.energy_consumed:.4f} kWh")
print(f"Val accuracy: {final_val_acc:.2f}%")
if total_emissions:
print(f"Efficienza: {final_val_acc / (total_emissions * 1000):.2f} acc/gCO2")
results = {
"model": "TextClassifier-BiLSTM",
"epochs": epochs,
"final_val_accuracy": final_val_acc,
"total_co2_kg": total_emissions,
"country": country,
"training_history": training_history
}
with open("./carbon_reports/training_results.json", "w") as f:
json.dump(results, f, indent=2)
return results
if __name__ == "__main__":
X = torch.randint(0, 1000, (2000, 128))
y = torch.randint(0, 3, (2000,))
dataset = TensorDataset(X, y)
train_ds, val_ds = torch.utils.data.random_split(dataset, [1600, 400])
train_loader = DataLoader(train_ds, batch_size=32, shuffle=True)
val_loader = DataLoader(val_ds, batch_size=64)
model = TextClassifier(vocab_size=1000, embed_dim=64, num_classes=3)
train_with_carbon_tracking(model, train_loader, val_loader, epochs=5, country="ITA")
Keras apel invers pentru TensorFlow
import tensorflow as tf
from tensorflow import keras
from codecarbon import EmissionsTracker
import numpy as np
class CarbonTrackingCallback(keras.callbacks.Callback):
"""Callback Keras che integra CodeCarbon per il reporting per epoch."""
def __init__(self, tracker: EmissionsTracker):
super().__init__()
self.tracker = tracker
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
val_acc = logs.get('val_accuracy', 0)
print(f"\n [Carbon] Epoch {epoch+1} | Val accuracy: {val_acc:.4f}")
def train_keras_with_carbon():
vocab_size, max_len = 10000, 200
model = keras.Sequential([
keras.layers.Embedding(vocab_size, 128, input_length=max_len),
keras.layers.Bidirectional(keras.layers.LSTM(64, return_sequences=True)),
keras.layers.GlobalMaxPooling1D(),
keras.layers.Dense(64, activation='relu'),
keras.layers.Dropout(0.3),
keras.layers.Dense(1, activation='sigmoid')
])
model.compile(
optimizer=keras.optimizers.Adam(3e-4),
loss='binary_crossentropy',
metrics=['accuracy']
)
X_train = np.random.randint(0, vocab_size, (8000, max_len))
y_train = np.random.randint(0, 2, (8000,))
X_val = np.random.randint(0, vocab_size, (2000, max_len))
y_val = np.random.randint(0, 2, (2000,))
with EmissionsTracker(
project_name="keras-sentiment",
output_dir="./carbon_reports",
country_iso_code="ITA",
log_level="WARNING"
) as tracker:
history = model.fit(
X_train, y_train,
validation_data=(X_val, y_val),
epochs=10,
batch_size=64,
callbacks=[
CarbonTrackingCallback(tracker),
keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True),
keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=2)
],
verbose=1
)
print(f"\nEmissioni totali: {tracker.final_emissions:.6f} kgCO2eq")
print(f"Val accuracy: {max(history.history['val_accuracy']):.4f}")
return model, tracker.final_emissions
train_keras_with_carbon()
Urmărire GPU: Măsurare precisă cu NVIDIA NVML
Pentru încărcăturile de lucru care utilizează intens GPU, CodeCarbon folosește pynvml, legarea Python a NVIDIA Management Library (NVML), pentru a măsura consumul direct de energie în wați. Aceasta este cea mai precisă metodă disponibilă, cu o rezoluție de 1-5 wați.
import pynvml
from codecarbon import EmissionsTracker
import torch
def inspect_gpu_power():
"""Ispezione diretta del consumo GPU con NVML (come fa CodeCarbon internamente)."""
pynvml.nvmlInit()
count = pynvml.nvmlDeviceGetCount()
print(f"GPU rilevate: {count}")
for i in range(count):
h = pynvml.nvmlDeviceGetHandleByIndex(i)
name = pynvml.nvmlDeviceGetName(h)
power_w = pynvml.nvmlDeviceGetPowerUsage(h) / 1000 # mW -> W
limit_w = pynvml.nvmlDeviceGetEnforcedPowerLimit(h) / 1000
mem = pynvml.nvmlDeviceGetMemoryInfo(h)
print(f" GPU {i}: {name}")
print(f" Consumo: {power_w:.1f}W / {limit_w:.0f}W (TDP)")
print(f" VRAM: {mem.used / 1e9:.1f}GB / {mem.total / 1e9:.1f}GB")
pynvml.nvmlShutdown()
def train_on_gpu_with_tracking():
"""Training su GPU con tracking dettagliato del consumo."""
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
tracker = EmissionsTracker(
project_name="gpu-intensive-run",
output_dir="./carbon_reports",
country_iso_code="ITA",
gpu_ids=[0], # Monitora solo GPU 0
measure_power_secs=5, # Alta frequenza per run brevi
log_level="DEBUG" # Mostra dettagli misurazione
)
tracker.start()
print(f"Dispositivo: {device}")
# Workload GPU intensivo: matrix multiplication
for step in range(100):
a = torch.randn(256, 1024, device=device)
b = torch.randn(1024, 1024, device=device)
c = torch.matmul(a, b)
loss = c.mean()
loss.backward()
if step % 25 == 0:
print(f"Step {step}/100 | Loss: {loss.item():.4f}")
emissions = tracker.stop()
data = tracker.final_emissions_data
print(f"\n=== GPU CARBON REPORT ===")
print(f"Emissioni: {emissions:.6f} kgCO2eq")
if data:
print(f"Energia: {data.energy_consumed:.4f} kWh")
return emissions
inspect_gpu_power()
train_on_gpu_with_tracking()
Limitări ale urmăririi GPU
- Numai NVIDIA cu CUDA: GPU-urile AMD necesită ROCm; Intel Arc nu este acceptat
- Containere Docker neprivilegiate: Este posibil ca NVML să nu aibă acces la drivere;
adăugați steagul
--privilegedsau monta/dev/nvidia* - VM-uri în cloud: Pe EC2/GCE/Azure, este posibil ca instanțele NVML să nu expună consumul real; utilizați amprenta de carbon din cloud pentru estimări în cloud
- RAPL pe CPU: Pe Linux necesită acces la
/sys/class/powercap/; pe macOS și Windows utilizați estimarea TDP - Precizie generală: Cercetări recente (2025) indică faptul că instrumentele de estimare pot avea erori de până la 40%; utilizați datele ca un ordin de mărime, nu o măsură absolută
Integrare cu MLflow: Emisiile ca măsurători experimentale
Integrarea CodeCarbon cu MLflow vă permite să înregistrați emisiile de CO₂ alături de valori a modelului (precizie, pierdere, F1). Amprenta de carbon devine un criteriu de selecție a modelului exact ca performanța predictivă.
import mlflow
import mlflow.pytorch
from codecarbon import EmissionsTracker
import torch
import torch.nn as nn
from datetime import datetime
def train_with_mlflow_carbon(
model_config: dict,
train_loader,
val_loader,
country: str = "ITA",
experiment_name: str = "carbon-aware-experiments"
):
"""Training con logging doppio: MLflow per metriche, CodeCarbon per CO2."""
mlflow.set_experiment(experiment_name)
with mlflow.start_run(run_name=f"run-{datetime.now().strftime('%H%M%S')}") as run:
# Log iperparametri
mlflow.log_params({
"model_type": model_config.get("type", "unknown"),
"learning_rate": model_config.get("lr", 1e-3),
"batch_size": model_config.get("batch_size", 32),
"epochs": model_config.get("epochs", 10),
"country": country
})
# Avvia tracking CO2
tracker = EmissionsTracker(
project_name=f"mlflow-{run.info.run_id[:8]}",
output_dir="./carbon_reports",
country_iso_code=country,
log_level="WARNING"
)
tracker.start()
# Training loop
model = build_model(model_config)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
opt = torch.optim.Adam(model.parameters(), lr=model_config.get("lr", 1e-3))
crit = nn.CrossEntropyLoss()
epochs = model_config.get("epochs", 10)
best_val_acc = 0.0
for epoch in range(epochs):
# Train
model.train()
train_loss, correct, total = 0.0, 0, 0
for X, y in train_loader:
X, y = X.to(device), y.to(device)
opt.zero_grad()
out = model(X)
loss = crit(out, y)
loss.backward()
opt.step()
train_loss += loss.item()
correct += out.argmax(1).eq(y).sum().item()
total += y.size(0)
# Validation
model.eval()
val_c, val_t = 0, 0
with torch.no_grad():
for X, y in val_loader:
X, y = X.to(device), y.to(device)
val_c += model(X).argmax(1).eq(y).sum().item()
val_t += y.size(0)
train_acc = correct / total
val_acc = val_c / val_t
best_val_acc = max(best_val_acc, val_acc)
mlflow.log_metrics({
"train_accuracy": train_acc,
"val_accuracy": val_acc,
"train_loss": train_loss / len(train_loader),
}, step=epoch)
# Log metriche CO2 al termine del training
total_emissions = tracker.stop()
em_data = tracker.final_emissions_data
carbon_metrics = {
"co2_kg": total_emissions or 0.0,
"best_val_accuracy": best_val_acc,
"carbon_efficiency": best_val_acc / (total_emissions * 1000) if total_emissions else 0.0,
}
if em_data:
carbon_metrics["energy_kwh"] = em_data.energy_consumed or 0.0
mlflow.log_metrics(carbon_metrics)
mlflow.set_tags({
"carbon_tracked": "true",
"country": country,
"hardware": "gpu" if torch.cuda.is_available() else "cpu"
})
mlflow.pytorch.log_model(model, "model")
print(f"\n=== Run {run.info.run_id} ===")
print(f"Best Val Acc: {best_val_acc:.4f}")
print(f"CO2 emessa: {total_emissions:.6f} kgCO2eq")
print(f"Carbon Efficiency: {carbon_metrics['carbon_efficiency']:.2f} acc/gCO2")
return {
"run_id": run.info.run_id,
"best_val_acc": best_val_acc,
"co2_kg": total_emissions,
"carbon_efficiency": carbon_metrics["carbon_efficiency"]
}
def build_model(config: dict) -> nn.Module:
h = config.get("hidden_size", 128)
return nn.Sequential(
nn.Linear(config.get("input_size", 784), h),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(h, config.get("num_classes", 10))
)
mlflow-emissions-sdk: Integrare nativă
Dataroots a dezvoltat un pachet dedicat care extinde MLflow cu suport nativ la CodeCarbon,
asigurarea clasei EmissionsTrackerMlflow care înregistrează automat emisiile
în ciclul de viață al unei rulări MLflow.
pip install mlflow-emissions-sdk
from mlflow_emissions_sdk.tracker import EmissionsTrackerMlflow
import mlflow
with mlflow.start_run():
with EmissionsTrackerMlflow(country_iso_code="ITA") as tracker:
# Le emissioni vengono loggato automaticamente su MLflow
run_training()
# Metriche disponibili nel run MLflow dopo il context manager
Vizualizarea tabloului de bord și a emisiilor
CodeCarbon generează un fișier CSV cu toate măsurătorile. Puteți crea tablouri de bord personalizate cu plotly sau matplotlib pentru a analiza tendințele, a compara experimente și a pregăti rapoarte ESG.
Structura CSV de ieșire
Câmpurile principale ale CSV CodeCarbon
| Domeniu | Unitate | Descriere |
|---|---|---|
timestamp |
ISO 8601 | Momentul de măsurare |
project_name |
- | Numele proiectului |
duration |
secunde | Durata totală de urmărire |
emissions |
kgCO₂eq | Emisii totale |
cpu_energy |
kWh | energie CPU |
gpu_energy |
kWh | Energia GPU |
ram_energy |
kWh | Energia RAM |
energy_consumed |
kWh | Energie totală (CPU+GPU+RAM) |
carbon_intensity |
kgCO₂/kWh | Intensitatea carbonului utilizată |
country_name |
- | Țara de execuție |
gpu_model |
- | Model GPU detectat |
Tabloul de bord cu Plotly și Raport static cu Matplotlib
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import matplotlib.pyplot as plt
def load_emissions_data(csv_path: str = "./carbon_reports/emissions.csv") -> pd.DataFrame:
df = pd.read_csv(csv_path)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['emissions_g'] = df['emissions'] * 1000 # kgCO2 -> gCO2
df['duration_min'] = df['duration'] / 60
return df
def create_plotly_dashboard(df: pd.DataFrame, output_path: str = "./carbon_dashboard.html"):
fig = make_subplots(
rows=2, cols=2,
subplot_titles=[
"Emissioni CO2 per Run (gCO2eq)",
"Breakdown Energetico Medio",
"Emissioni per Progetto (Totale)",
"CO2 Cumulativa nel Tempo"
],
specs=[
[{"type": "bar"}, {"type": "pie"}],
[{"type": "bar"}, {"type": "scatter"}]
]
)
# 1. Bar chart emissioni per run
fig.add_trace(
go.Bar(x=df['project_name'], y=df['emissions_g'],
name="CO2 (g)", marker_color='#e74c3c',
text=df['emissions_g'].round(3), textposition='auto'),
row=1, col=1
)
# 2. Pie chart breakdown energetico
breakdown = {
'CPU': df['cpu_energy'].mean(),
'GPU': df['gpu_energy'].fillna(0).mean(),
'RAM': df['ram_energy'].mean()
}
fig.add_trace(
go.Pie(labels=list(breakdown.keys()), values=list(breakdown.values()),
marker_colors=['#3498db', '#e67e22', '#2ecc71']),
row=1, col=2
)
# 3. Emissioni aggregate per progetto
proj = df.groupby('project_name')['emissions_g'].sum().reset_index()
fig.add_trace(
go.Bar(x=proj['project_name'], y=proj['emissions_g'],
marker_color='#9b59b6'),
row=2, col=1
)
# 4. Trend cumulativo
df_s = df.sort_values('timestamp')
fig.add_trace(
go.Scatter(x=df_s['timestamp'], y=df_s['emissions_g'].cumsum(),
mode='lines+markers', line=dict(color='#e74c3c', width=2),
fill='tozeroy', fillcolor='rgba(231,76,60,0.1)'),
row=2, col=2
)
fig.update_layout(
title="CodeCarbon Dashboard: Carbon Footprint del Progetto",
height=700, showlegend=False, template="plotly_dark"
)
fig.write_html(output_path)
print(f"Dashboard salvata in: {output_path}")
return fig
def create_matplotlib_report(df: pd.DataFrame, output_dir: str = "./carbon_reports"):
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("Carbon Footprint Report - CodeCarbon", fontsize=16, fontweight='bold')
colors = ['#27ae60', '#2ecc71', '#a8e6cf', '#dcedc1']
# 1. Emissioni per progetto
proj = df.groupby('project_name')['emissions_g'].sum()
axes[0,0].bar(range(len(proj)), proj.values, color=colors[0])
axes[0,0].set_xticks(range(len(proj)))
axes[0,0].set_xticklabels(proj.index, rotation=30, ha='right', fontsize=9)
axes[0,0].set_ylabel("CO2 emessa (gCO2eq)")
axes[0,0].set_title("Emissioni per Progetto")
# 2. Breakdown energetico
ev = [df['cpu_energy'].mean()*1000, df['gpu_energy'].fillna(0).mean()*1000,
df['ram_energy'].mean()*1000]
axes[0,1].pie(ev, labels=['CPU','GPU','RAM'], autopct='%1.1f%%', colors=colors)
axes[0,1].set_title("Breakdown Energetico Medio")
# 3. Emissioni vs durata
axes[1,0].scatter(df['duration_min'], df['emissions_g'],
c=colors[0], alpha=0.7, s=80, edgecolors='white')
axes[1,0].set_xlabel("Durata run (minuti)")
axes[1,0].set_ylabel("Emissioni (gCO2eq)")
axes[1,0].set_title("Emissioni vs Durata Run")
# 4. Cumulativo
cumulative = df.sort_values('timestamp')['emissions_g'].cumsum()
axes[1,1].fill_between(range(len(cumulative)), cumulative, alpha=0.3, color=colors[0])
axes[1,1].plot(range(len(cumulative)), cumulative, color=colors[0], linewidth=2)
axes[1,1].set_xlabel("Numero run")
axes[1,1].set_ylabel("CO2 Cumulativa (gCO2eq)")
axes[1,1].set_title("Andamento Emissioni Cumulativo")
plt.tight_layout()
plt.savefig(f"{output_dir}/carbon_report.png", dpi=150, bbox_inches='tight')
plt.savefig(f"{output_dir}/carbon_report.pdf", bbox_inches='tight')
print("Report salvato in carbon_report.png e .pdf")
return fig
if __name__ == "__main__":
df = load_emissions_data("./carbon_reports/emissions.csv")
create_plotly_dashboard(df)
create_matplotlib_report(df)
Amprenta de carbon din cloud: emisii de sarcină de lucru în cloud
CodeCarbon măsoară emisiile locale de pe mașina pe care rulează codul. Pentru sarcini de lucru distribuite pe cloud aveți nevoie de un instrument complementar: Amprenta de carbon în cloud (CCF), proiect open source dezvoltat inițial de ThoughtWorks.
CodeCarbon vs amprenta de carbon din cloud
| Caracteristică | CodeCarbon | Amprenta de carbon din cloud |
|---|---|---|
| Ținta principală | Cod local/on-premise | Volumul de lucru pe cloud public |
| Sursa datelor | Hardware Direct (NVML, RAPL) | Furnizori de cloud API de facturare |
| Furnizori de cloud | Orice hardware | AWS, GCP, Azure |
| În timp real | Da (15-30 sec) | Nu (date de facturare întârziate) |
| Granularitatea | Per-proces, per-GPU | Per cont, per regiune, per serviciu |
| Carbon incorporat (Scope 3) | No | Da (estimare de fabricație) |
| Tablouri de bord web | CSV + personalizat | Tabloul de bord React inclus |
# Setup Cloud Carbon Footprint
git clone https://github.com/cloud-carbon-footprint/cloud-carbon-footprint.git
cd cloud-carbon-footprint
# Crea file .env da template
cp packages/cli/.env.template packages/cli/.env
# Configurazione AWS (aggiungi in .env):
# AWS_TARGET_ACCOUNT_ID=123456789012
# AWS_REGIONS=eu-west-1,eu-central-1
# AWS_USE_BILLING_DATA=true
# Configurazione GCP (aggiungi in .env):
# GCP_PROJECT_ID=my-project
# GCP_BIG_QUERY_TABLE=billing_export.gcp_billing_export_v1_*
npm install
# Stima emissioni dell'ultimo mese
npx ts-node packages/cli/src/index.ts \
--startDate 2025-02-01 \
--endDate 2025-02-28 \
--groupBy month \
--cloudProviderToSeed AWS
# Output in emissions.json con breakdown per servizio e regione
Comparație de instrumente: CodeCarbon vs alternative
Peisajul instrumentelor de măsurare a amprentei de carbon cu coduri evoluează rapid. Iată o comparație tehnică a celor mai utilizate opțiuni în 2025.
Comparație completă
| Instrument | GPU | Offline | MLflow | Precizie | Întreţinere |
|---|---|---|---|---|---|
| CodeCarbon | NVIDIA (NVML) | Sì | Prin SDK | Mediu-Ridicat | Activ (2025) |
| Eco2AI | Limitat | Sì | No | Medie | 2023 |
| Carbon Tracker | Sì | Parţial | No | Medie | 2022 |
| Impactul ML CO2 | Stima | N / A | No | Scăzut (estimare) | Instrumente web |
| PyRAPL | No | Sì | No | Înalt (procesor Intel) | 2021 |
| SDK Carbon Aware | N / A | No | No | N/A (schimbări) | Activ (GSF) |
Ghid pentru alegere
- CodeCarbon: Alegere de top pentru instruirea ML în Python pe hardware local sau local. Suport excelent pentru GPU NVIDIA, integrare MLflow, comunitate mare.
- Amprenta de carbon din cloud: Pentru analiza costului de carbon al infrastructurii cloud. Complementare la CodeCarbon, nu un înlocuitor.
- Calculator de impact ML CO2: Instrument web pentru estimări rapide înainte de a începe antrenamentul. Util în faza de planificare pentru a alege hardware-ul și regiunea cloud.
- Carbon Aware SDK (GSF): Nu măsoară emisiile, ci le minimizează prin timp/locație deplasându-se. Utilizați-l împreună cu CodeCarbon pentru o strategie completă.
Integrare CI/CD cu GitHub Actions
Măsurarea sistematică devine cu adevărat utilă atunci când este automatizată. Iată cum să integrați CodeCarbon într-un flux de lucru GitHub Actions cu aplicarea bugetului de carbon.
# .github/workflows/carbon-tracking.yml
name: Carbon Footprint Tracking
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
carbon-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install codecarbon pandas
pip install -r requirements.txt
- name: Run training with carbon tracking
run: |
python scripts/train.py \
--country ITA \
--output-dir ./carbon_reports \
--epochs 5
env:
CODECARBON_LOG_LEVEL: WARNING
- name: Enforce carbon budget
run: |
python - <<'PYEOF'
import pandas as pd
import sys
df = pd.read_csv('./carbon_reports/emissions.csv')
total_g = df['emissions'].sum() * 1000
BUDGET_G = 100.0 # Budget massimo per run CI
print(f"Emissioni: {total_g:.2f}g | Budget: {BUDGET_G}g")
if total_g > BUDGET_G:
print(f"BUDGET SUPERATO: {total_g:.2f}g > {BUDGET_G}g")
sys.exit(1)
print(f"OK: {total_g/BUDGET_G*100:.1f}% del budget usato")
PYEOF
- name: Upload carbon reports
uses: actions/upload-artifact@v4
if: always()
with:
name: carbon-reports-${{ github.run_id }}
path: ./carbon_reports/
retention-days: 90
- name: Comment PR with carbon summary
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const csv = fs.readFileSync('./carbon_reports/emissions.csv', 'utf8');
const lines = csv.trim().split('\n');
const headers = lines[0].split(',');
const last = lines[lines.length - 1].split(',');
const idx = headers.indexOf('emissions');
const g = parseFloat(last[idx]) * 1000;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### Carbon Report\n| Metrica | Valore |\n|---|---|\n| CO2 | ${g.toFixed(3)} gCO2eq |\n| Paese | ITA (233 gCO2/kWh) |`
});
Carbon Budget și SCI (Software Carbon Intensity)
from codecarbon import EmissionsTracker
from dataclasses import dataclass
@dataclass
class CarbonBudget:
project_name: str
max_co2_per_run_g: float
max_co2_monthly_kg: float
def check_run(self, emissions_kg: float) -> bool:
g = emissions_kg * 1000
if g > self.max_co2_per_run_g:
print(f"BUDGET SUPERATO: {g:.2f}g > {self.max_co2_per_run_g}g")
return False
pct = g / self.max_co2_per_run_g * 100
print(f"Budget: {pct:.1f}% usato ({g:.2f}g / {self.max_co2_per_run_g}g)")
return True
BUDGETS = {
"research": CarbonBudget("research", max_co2_per_run_g=500, max_co2_monthly_kg=10),
"production": CarbonBudget("production", max_co2_per_run_g=50, max_co2_monthly_kg=2),
"ci": CarbonBudget("ci", max_co2_per_run_g=100, max_co2_monthly_kg=5),
}
def calculate_sci(emissions_kg: float, energy_kwh: float,
functional_unit: float, unit_desc: str = "prediction") -> dict:
"""
Calcola SCI (Software Carbon Intensity) secondo la specifica GSF:
SCI = CO2eq / R (functional unit)
"""
sci = emissions_kg / max(functional_unit, 1e-9)
return {
"sci": sci,
"sci_unit": f"kgCO2eq/{unit_desc}",
"co2_kg": emissions_kg,
"energy_kwh": energy_kwh,
"equiv_km_car": emissions_kg * 4.44, # ~225 gCO2/km
"equiv_iphone_charges": int(emissions_kg / 0.000008), # ~8 Wh per ricarica
}
def run_with_budget(training_fn, budget_name="production", country="ITA"):
budget = BUDGETS.get(budget_name, BUDGETS["research"])
with EmissionsTracker(
project_name=budget.project_name,
country_iso_code=country,
output_dir="./carbon_reports"
) as tracker:
result = training_fn()
em_kg = tracker.final_emissions
en_kwh = tracker.final_emissions_data.energy_consumed if tracker.final_emissions_data else 0
budget.check_run(em_kg)
n_preds = result.get("num_predictions", 1)
sci = calculate_sci(em_kg, en_kwh, n_preds)
print(f"SCI: {sci['sci']*1e6:.2f} microgCO2eq/prediction")
print(f"Equivalente a {sci['equiv_km_car']:.3f} km in auto")
return sci
Studiu de caz real: Optimizarea instruirii NLP cu CodeCarbon
O echipă NLP pregătea un model de clasificare a sentimentelor pe recenziile produselor în italiană. Scopul a fost de a obține o precizie de 90%+. Înainte de a introduce CodeCarbon, procesul de instruire a fost complet opac din punct de vedere al amprentei de carbon.
Situația inițială (linie de bază)
Configurație de bază
| Parametru | Valoarea de referință | Valoare optimizată |
|---|---|---|
| Model | BERT-large-uncased (340M parametri) | DistilBERT multilingv (66M parametri) |
| Hardware | 1x NVIDIA A100 80GB | 1x NVIDIA A100 80GB |
| Regiunea centrului de date | Germania (381 gCO₂/kWh) | Franța (56 gCO₂/kWh) |
| Epoci | 20 (fără oprire anticipată) | Oprire timpurie, convergență la epoca 9 |
| Dimensiunea lotului | 16 (A100 30% folosit) | 128 (A100 92% folosit) |
| Precizie mixtă | Nu (FP32) | Da (FP16) |
| Precizie Val | 91,2% | 90,7% |
| Durata antrenamentului | ~4,5 ore | ~36 de minute |
Rezultate măsurate cu CodeCarbon
Comparația amprentei de carbon: linia de bază vs optimizată
| Metric | Linii de bază | Optimizat | Reducere |
|---|---|---|---|
| CO2 emis | 1.723 kgCO₂eq | 0,061 kgCO₂eq | -96,5% |
| Energia consumata | 4,52 kWh | 1,09 kWh | -75,9% |
| Durata antrenamentului | 4,5 ore | 36 de minute | -86,7% |
| Precizie Val | 91,2% | 90,7% | -0,5% (acceptabil) |
| Utilizarea GPU | ~30% | ~92% | +62 pp |
| Costul cloud estimat | ~13,50 USD | ~1,80 USD | -86,7% |
Reducerea de 96,5% din emisii cu doar -0,5% precizie demonstrează că în majoritatea cazurilor amprenta de carbon a software-ului ML poate fi drastic redus fără a sacrifica calitatea modelului. Cea mai importantă lecție: măsura înainte de optimizare.
Cele 5 intervenții pentru reducerea emisiilor ML (în ordinea impactului)
- Schimbarea locației (Germania → Franța): contribuția principală -85% emisii. Intensitatea carbonului a rețelei electrice este factorul cu cel mai mare impact. Franța (nuclear, ~56 gCO₂/kWh) față de Germania (~381 gCO₂/kWh) produce o diferență de 7x toate celelalte fiind egale.
- Oprire timpurie: -55% durata medie. Majoritatea instruirii ML converg mult mai devreme decât numărul configurat de epoci. Oprirea timpurie cu răbdare 3-5 elimină epocile inutile.
- Dimensiune redusă a modelului (BERT-mare → DistilBERT): -80% parametri, -60% timp. Modelele distilate sau mai mici ating adesea o precizie comparabilă la o fracțiune din calcul.
- Precizie mixtă FP16: -30-50% energie GPU. Pe GPU NVIDIA A100, RTX 3090+ FP16 Este accelerat hardware și aproape înjumătățit consumul la operațiile de multiplicare a matricei.
- Dimensiunea optimă a lotului: -75% durată pentru aceleași epoci. O dimensiune optimă a lotului pentru VRAM disponibilă maximizează utilizarea GPU-ului și reduce timpul total de antrenament.
Cele mai bune practici pentru urmărirea sistematică a carbonului
Structura recomandată a proiectului
project/
├── .codecarbon.config # Configurazione globale
├── carbon_reports/ # Output CodeCarbon
│ ├── emissions.csv # Dati grezzi
│ ├── carbon_report.png # Report grafico
│ └── unified_report.json # Report locale + cloud
├── scripts/
│ ├── train.py # Training con EmissionsTracker
│ ├── evaluate.py # Evaluation con tracker
│ └── carbon_report.py # Genera dashboard
├── .github/workflows/
│ └── carbon-tracking.yml # CI/CD con carbon budget
└── Makefile
# make train - training con tracking
# make carbon-check - verifica budget
# make carbon-report - genera dashboard
Convenția de denumire și configurația din variabilele de mediu
import os
from datetime import datetime
from codecarbon import EmissionsTracker
def create_tracker(model: str, exp_type: str, dataset: str, country: str = None) -> EmissionsTracker:
"""
Naming convention: {model}-{type}-{dataset}-{timestamp}
Es: distilbert-finetuning-imdb-it-20250309_1430
"""
ts = datetime.now().strftime('%Y%m%d_%H%M')
project_name = f"{model}-{exp_type}-{dataset}-{ts}"
country_code = country or os.environ.get('CODECARBON_COUNTRY', 'ITA')
return EmissionsTracker(
project_name = project_name,
country_iso_code= country_code,
output_dir = os.environ.get('CODECARBON_OUTPUT_DIR', './carbon_reports'),
log_level = os.environ.get('CODECARBON_LOG_LEVEL', 'WARNING'),
measure_power_secs = int(os.environ.get('CODECARBON_INTERVAL', '15'))
)
# Utilizzo
with create_tracker("distilbert", "finetuning", "imdb-it", country="FRA"):
fine_tune_model()
Anti-modele de evitat
- Nu urmăriți preprocesarea: Tokenizarea și creșterea datelor pot consuma CPU semnificativ. Includeți întotdeauna preprocesarea în urmărire pentru a obține amprenta completă.
- Comparați cursele între diferite țări: Emisiile de CO₂ nu sunt comparabile direct între curse în țări cu intensități diferite de carbon. Normalizare prin kWh sau utilizare o țară fixă pentru toate punctele de referință.
- Nu versiunea .codecarbon.config: Configurația trackerului trebuie să fie versiunea în repo pentru a asigura reproductibilitatea măsurătorilor între dezvoltatori.
-
Opriți trackerul în caz de excepție: Utilizați întotdeauna un bloc try/finally
sau managerul de context pentru a se asigura că
tracker.stop()este de asemenea chemat în caz de accident, păstrarea datelor parțiale. - Tratați CSV ca efect final: CSV este punctul de plecare. Creați conducte de analiză pentru a extrage informații utile și pentru a compara experimente.
Contabilitatea carbonului și raportarea ESG cu date CodeCarbon
Emisiile măsurate de CodeCarbon nu sunt utile doar pentru optimizarea codului: reprezintă date valoroase pentru raportarea și conformitatea ESG Directiva CSRD (Directiva de raportare a durabilității corporative), care impune marile companii europene să raporteze emisiile digitale începând din 2025-2026. În acest context, CodeCarbon devine un instrument de guvernare, precum și un instrument de dezvoltare.
Cadrul Protocolului GHG (Greenhouse Gas Protocol) clasifică emisiile în trei domenii: Domeniul de aplicare 1 (emisii directe, de exemplu, generatoare diesel), Domeniul de aplicare 2 (energie electrică achiziționată, care include emisiile CodeCarbon) e Domeniul de aplicare 3 (lanțul valoric, de exemplu, furnizor de cloud și produs hardware). CodeCarbon acoperă în primul rând emisiile din Scopul 2 legate de sarcinile de lucru computaționale.
Agregarea datelor pentru rapoartele ESG trimestriale
import pandas as pd
import json
from datetime import datetime, timedelta
from pathlib import Path
def generate_esg_report(
emissions_csv: str = "./carbon_reports/emissions.csv",
report_period: str = "Q1-2025",
company_name: str = "MyTechCompany SRL",
output_path: str = "./esg_report.json"
) -> dict:
"""
Genera un report ESG strutturato dai dati CodeCarbon.
Compatibile con CSRD / GHG Protocol Scope 2.
"""
df = pd.read_csv(emissions_csv)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['emissions_g'] = df['emissions'] * 1000
# Statistiche aggregate
total_co2_kg = df['emissions'].sum()
total_energy_kwh = df['energy_consumed'].sum()
num_experiments = len(df)
avg_co2_per_run_g = df['emissions_g'].mean()
max_co2_run_g = df['emissions_g'].max()
# Breakdown per progetto
project_breakdown = (
df.groupby('project_name')
.agg(
total_co2_kg=('emissions', 'sum'),
total_energy_kwh=('energy_consumed', 'sum'),
num_runs=('emissions', 'count'),
avg_duration_min=('duration', lambda x: (x / 60).mean())
)
.reset_index()
.to_dict(orient='records')
)
# Equivalenze per comunicazione executive
equiv_km_car = total_co2_kg * 4.44 # km in auto media (225 gCO2/km)
equiv_flights = total_co2_kg / 255 # volo Roma-Milano ~255 gCO2 per passeggero
equiv_trees_days = total_co2_kg / 0.022 # giorni assorbimento di un albero (~22 gCO2/giorno)
# Intensità carbonica media pesata
if total_energy_kwh > 0:
weighted_intensity = (df['emissions'] * 1000 / df['energy_consumed']).mean()
else:
weighted_intensity = 0.0
report = {
"report_metadata": {
"generated_at": datetime.now().isoformat(),
"report_period": report_period,
"company": company_name,
"standard": "GHG Protocol - Scope 2 (Market-based)",
"tool": "CodeCarbon v2.x",
"boundary": "Computational workloads (ML training, batch jobs)"
},
"summary": {
"total_co2_kg": round(total_co2_kg, 4),
"total_co2_tco2eq": round(total_co2_kg / 1000, 6),
"total_energy_kwh": round(total_energy_kwh, 4),
"num_tracked_runs": num_experiments,
"avg_co2_per_run_g": round(avg_co2_per_run_g, 3),
"max_co2_single_run_g": round(max_co2_run_g, 3),
"avg_carbon_intensity": round(weighted_intensity, 4)
},
"equivalences": {
"km_car_equivalent": round(equiv_km_car, 1),
"flights_equivalent": round(equiv_flights, 2),
"tree_absorption_days": round(equiv_trees_days, 1)
},
"project_breakdown": project_breakdown,
"scope_classification": {
"scope": 2,
"category": "Purchased electricity for owned operations",
"methodology": "Activity-based (hardware power measurement)",
"data_quality": "High (direct measurement via NVML/RAPL)"
}
}
with open(output_path, 'w') as f:
json.dump(report, f, indent=2, default=str)
print(f"=== Report ESG {report_period} ===")
print(f"CO2 totale: {total_co2_kg:.4f} kgCO2eq")
print(f"Energia: {total_energy_kwh:.4f} kWh")
print(f"Equivalente a: {equiv_km_car:.1f} km in auto")
print(f"Run tracciati: {num_experiments}")
print(f"Report in: {output_path}")
return report
# Genera report per Q1 2025
report = generate_esg_report(
emissions_csv="./carbon_reports/emissions.csv",
report_period="Q1-2025",
company_name="Acme AI SRL",
output_path="./esg_carbon_q1_2025.json"
)
Obiective de reducere și ținte bazate pe știință (SBTi)
Companiile care se alătură inițiativei Science Based Targets (SBTi) se angajează să reducă emisii în conformitate cu obiectivele climatice ale Acordului de la Paris. Pentru emisiile TIC, aceasta înseamnă de obicei o reducere anuală de 4-7%. CodeCarbon poate fi folosit pentru a urmări automat progresul către aceste obiective.
import pandas as pd
from datetime import datetime
def track_reduction_progress(
emissions_csv: str,
baseline_year: int,
target_reduction_pct: float = 5.0, # 5% riduzione annuale
) -> dict:
"""
Traccia il progresso verso gli obiettivi di riduzione SBTi.
"""
df = pd.read_csv(emissions_csv)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['year'] = df['timestamp'].dt.year
annual_emissions = df.groupby('year')['emissions'].sum().to_dict()
baseline_emissions = annual_emissions.get(baseline_year, 0)
current_year = datetime.now().year
current_emissions = annual_emissions.get(current_year, 0)
years_elapsed = current_year - baseline_year
target_reduction_factor = (1 - target_reduction_pct / 100) ** years_elapsed
target_emissions = baseline_emissions * target_reduction_factor
actual_reduction_pct = 0.0
on_track = False
if baseline_emissions > 0:
actual_reduction_pct = (baseline_emissions - current_emissions) / baseline_emissions * 100
on_track = current_emissions <= target_emissions
return {
"baseline_year": baseline_year,
"baseline_emissions_kg": round(baseline_emissions, 4),
"current_year": current_year,
"current_emissions_kg": round(current_emissions, 4),
"target_emissions_kg": round(target_emissions, 4),
"target_annual_reduction_pct": target_reduction_pct,
"actual_reduction_pct": round(actual_reduction_pct, 2),
"on_track": on_track,
"annual_history": {str(k): round(v, 4) for k, v in annual_emissions.items()}
}
# Utilizzo: verifica se il team e' in linea con gli obiettivi SBTi
progress = track_reduction_progress(
emissions_csv="./carbon_reports/emissions.csv",
baseline_year=2024,
target_reduction_pct=5.0
)
status = "IN LINEA" if progress['on_track'] else "SOTTO TARGET"
print(f"Obiettivi SBTi: {status}")
print(f"Riduzione attuale: {progress['actual_reduction_pct']:.1f}%")
print(f"Target annuale: {progress['target_annual_reduction_pct']:.1f}%")
CodeCarbon și CSRD: Ce trebuie să știți
Directiva CSRD (Corporate Sustainability Reporting Directive) impune companiilor europene cu peste 500 de angajati (din 2025) si ulterior celor cu peste 250 de angajati (din 2026) să raporteze emisiile de GES în conformitate cu standardele ESRS (Standardele europene de raportare a durabilității). Pentru lansări digitale:
- ESRS E1 (Schimbarea climatică): Necesită dezvăluirea emisiilor Scopul 1, 2 și 3 cu metodologia GHG Protocol. CodeCarbon acoperă domeniul 2 al operațiunilor de calcul.
- Materialitate: Dacă emisiile TIC sunt materiale (semnificative în comparație la totalul companiei), trebuie raportat. Pentru companiile de tehnologie, acesta este aproape întotdeauna cazul.
- Piste de audit: CSV-urile CodeCarbon oferă o pistă de audit granulară pentru verificare raportarea terților, o cerință esențială pentru credibilitatea raportului ESG.
- Asigurare: CSRD necesită o asigurare limitată (din 2025) și rezonabilă (din 2028). Calitatea datelor CodeCarbon (măsurare directă vs estimare) este crucială.
Concluzii: Măsurarea este primul pas
CodeCarbon a transformat codul de urmărire a carbonului dintr-un exercițiu academic într-o practică inginerie concretă și accesibilă. Cu mai puțin de 10 linii de Python, orice cercetător de date o Inginerul ML poate începe să măsoare și să cuantifice impactul asupra mediului al muncii lor.
Studiul de caz a demonstrat o reducere a 96,5% din emisiile de CO₂ cu doar -0,5% precizie. Acesta nu este un caz excepțional: este norma când pornim de la o configurație neoptimizată. Cele mai multe antrenamente ML au marje uriașe de optimizare a carbonului care rămân invizibile până când începeți măsurarea.
Calea către un software mai sustenabil urmează trei faze:
- Măsură: Integrați CodeCarbon în toate fluxurile de lucru. Definiți bugetul de carbon. Creați linii de bază măsurabile. Faceți emisiile la fel de vizibile ca acuratețea.
- Optimizați: Utilizați datele pentru a identifica blocajele de carbon. Schimbarea locației, dimensiunea modelului, dimensiunea lotului și precizia mixtă sunt cele mai eficiente pârghii.
- Preveniți: Integrați urmărirea carbonului în CI/CD. Definiți bugetul de carbon după tip de experiment. Utilizați SDK-ul Carbon Aware pentru a automatiza schimbarea locației/ora.
În următorul articol din serie vom explora Climatiq API, un instrument complementar care vă permite să calculați emisiile GHG Protocol (Scope 1, 2 și 3) prin REST API, care integrează calcule în backend-ul aplicațiilor pentru raportarea automată ESG.
Resurse și link-uri utile
Seria Green Software continuă
- Articolul 1: Principiile Green Software Foundation — GSF, SCI, 8 principii
- Articolul 2 (actual): Măsurarea amprentei de carbon cu CodeCarbon
- Articolul 3: Integrați calculele Climatiq API — GHG Protocol în backend
- Articolul 4: SDK Carbon Aware — Schimbarea timpului și schimbarea locației
- Articolul 6: GreenOps cu Kubernetes — Infrastructură conștientă de carbon
- Articolul 10: IA și carbon — Măsurarea și reducerea amprentei antrenamentului ML







