Měření uhlíkové stopy vašeho kódu pomocí CodeCarbon
Pokaždé, když trénujete model strojového učení, spustíte ETL potrubí nebo spustíte dávkovou úlohu v noci spotřebováváte energii. Tato energie má skutečné uhlíkové náklady, které závisí na tom, kde a kdy běžíte kód. ICT sektor jako celek je odpovědný za 2-4 % celosvětových emisí CO₂, což je podíl srovnatelný s celým světovým leteckým průmyslem. Ale a Na rozdíl od letu jsou softwarové emise téměř vždy neviditelné.
GPT-3 školení vyrobeno cca 552 tun CO₂, což odpovídá 300 jízdám zpáteční let New York-San Francisco letadlem. Jemné doladění BERT-large na GPU A100 po dobu 10 hodin Německo (energetický mix ~381 gCO₂/kWh) vypouští cca 1,2 kg CO₂. Stejné školení přesunuto do Francie (jaderná, ~56 gCO₂/kWh) produkuje pouze 177 gramů. Rozdíl je téměř 7krát, pro stejný kód.
KódCarbon je open-source nástroj, díky kterému jsou tyto emise měřitelné a srovnatelné. Pomocí několika řádků Pythonu můžete sledovat uhlíkovou stopu jakéhokoli procesu výpočetní, od jediného experimentu ML po produkční potrubí a integrovat tyto metriky ve vašich pracovních postupech MLflow, zprávách ESG a kanálech CI/CD.
Co se naučíte
- Vnitřní architektura CodeCarbon: jak měří energii a vypočítává emise CO₂
- Nastavení pomocí
EmissionsTrackereOfflineEmissionsTracker - Sledování při tréninku modelů TensorFlow a PyTorch
- Měření GPU pomocí CUDA a NVML pro hardware NVIDIA
- Konfigurace pro různé evropské země a uhlíková intenzita sítě
- Integrace s MLflow pro emise jako experimentální metriky
- Dashboard s matplotlib a plotly pro vizualizaci trendů
- Cloud Carbon Footprint pro odhad emisí na AWS, GCP a Azure
- Srovnání nástrojů: CodeCarbon vs Eco2AI vs CarbonTracker vs ML CO2 Impact
- Skutečná případová studie: Optimalizace tréninku NLP s 96% snížením emisí
Green Software Series: 10 článků pro vývoj udržitelného softwaru
| # | Položka | Podrobit | Stát |
|---|---|---|---|
| 1 | Principy Green Software Foundation | GSF, SCI, 8 základních principů | K dispozici |
| 2 | Měření vaší uhlíkové stopy pomocí CodeCarbon | Měření, sledování, přístrojová deska | Aktuální článek |
| 3 | Integrujte Climatiq API | Výpočty protokolu GHG, rozsah 1-3 | K dispozici |
| 4 | Carbon Aware SDK | Posun času, posun místa | K dispozici |
| 5 | Rozsah 1, 2 a 3: Modelování dat ESG | Struktura dat, výpočty, agregace | K dispozici |
| 6 | GreenOps s Kubernetes | Plánování s ohledem na uhlík, infrastruktura | K dispozici |
| 7 | Hodnotový řetězec Pipeline Scope 3 | Údaje o dodavateli, audit trail | K dispozici |
| 8 | ESG Reporting a CSRD API | Evropská shoda, automatizace | K dispozici |
| 9 | Udržitelné architektonické vzory | Úložiště, mezipaměť, dávka s ohledem na uhlík | K dispozici |
| 10 | AI a Carbon: ML Training Footprint | Zelená AI, optimalizace tréninku | K dispozici |
CodeCarbon: Architektura a provozní mechanismus
CodeCarbon je open-source Python knihovna vyvinutá ve spolupráci mezi Mila Quebec AI Institute, Carnegie Mellon University, Comet.ml a BCG GAMMA. Projekt se zrodil v roce 2020 s cílem provést měření emisí kódů přístupné jakémukoli datovému vědci, aniž by bylo potřeba speciální hardwarové vybavení.
Princip fungování je založen na základním vzorci:
CodeCarbon Central Formula
Emitované CO₂ [kg] = spotřebovaná energie [kWh] × uhlíková náročnost sítě [kgCO₂/kWh]
Spotřebovaná energie se měří komponent po komponentě (GPU + CPU + RAM), zatímco intenzita uhlíku je získávána z databází aktualizovaných podle země/regionu nebo poskytované ručně pro offline prostředí.
Vnitřní měřící potrubí
CodeCarbon každý testuje spotřebu energie 15 sekund (konfigurovatelné) prostřednictvím víceúrovňové potrubí. Při každém vzorkování měří okamžitý výkon CPU, GPU a RAM, integrovat v průběhu času, abyste získali kWh, a vynásobit emisním faktorem země.
Hierarchie měření energie
| Komponent | Metoda měření | Přesnost | Dostupnost |
|---|---|---|---|
| GPU NVIDIA | NVML přes pynvml (NVIDIA Management Library) | Vysoká (přímé měření) | Pouze GPU NVIDIA s ovladači |
| CPU Intel | RAPL (Running Average Power Limit) přes pyRAPL | Vysoká (hardwarové senzory) | Linux s přístupem MSR, Intel |
| CPU AMD/ARM | Odhadované TDP + procento využití | Průměr (odhad) | Všechny systémy |
| BERAN | Empirický vzorec: 3W na 8GB | Nízký-Střední (odhad) | Všechny systémy |
| GPU AMD | ROCm SMI (je-li k dispozici) | Vysoká (přímé měření) | AMD GPU s ROCm |
Intenzita uhlíku podle země
K převodu kWh na kgCO₂ používá CodeCarbon hierarchickou databázi emisních faktorů. V online režimu získávejte data pomocí geolokace IP. V režimu offline, používá interní databázi s ročními průměrnými hodnotami pro 240+ zemí.
Intenzita uhlíku podle evropské země (2024)
| Obec | gCO₂/kWh | Hlavní energetický mix | ISO kód |
|---|---|---|---|
| Norsko | ~28 | Vodní elektrárna (90 %) | ANI |
| Francie | ~56 | Jaderná (70 %) | MEZI |
| Švédsko | ~45 | Nukleární + Hydro | SWE |
| Španělsko | ~191 | Obnovitelné zdroje + plyn | EXP |
| Itálie | ~233 | Zemní plyn + obnovitelné zdroje | ITA |
| Německo | ~381 | Plyn + uhlí + vítr | DEU |
| Polsko | ~640 | Uhlí (70 %) | POL |
Nastavení a instalace CodeCarbon
Instalace CodeCarbon vyžaduje Python 3.7+ a je k dispozici na PyPI a conda. Pro sledování GPU potřebujete ovladače NVIDIA a balíček pynvml.
Instalace
# 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')
"
Konfigurační soubor .codecarbon.config
CodeCarbon podporuje INI konfigurační soubor pro celý projekt, který se vyhýbá opakování
parametry v každém skriptu. Vytvořte soubor .codecarbon.config v kořenu projektu:
# .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: Tři způsoby použití
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: Pro prostředí bez internetu
V HPC clusterech, produkčních kontejnerech nebo strojích bez přístupu k internetu
OfflineEmissionsTracker. Kód země ISO se stává povinným.
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
)
Sledování emisí v projektech strojového učení
Primárním případem použití CodeCarbon je sledování při trénování modelů ML. Podívejme se na praktické příklady s PyTorch a TensorFlow/Keras.
Trénink PyTorch s Full Carbon Tracking
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")
Zpětné volání Keras pro 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()
Sledování GPU: Přesné měření s NVIDIA NVML
Pro zátěže náročné na GPU používá CodeCarbon pynvml, Pythonová vazba NVIDIA Management Library (NVML) pro měření přímé spotřeby energie ve wattech. Jedná se o nejpřesnější dostupnou metodu s rozlišením 1-5 wattů.
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()
Omezení sledování GPU
- Pouze NVIDIA s CUDA: GPU AMD vyžadují ROCm; Intel Arc není podporován
- Neprivilegované kontejnery Docker: NVML nemusí mít přístup k ovladačům;
přidat vlajku
--privilegednebo namontovat/dev/nvidia* - Cloudové virtuální počítače: Na EC2/GCE/Azure instance NVML nemusí odhalit skutečnou spotřebu; použijte Cloud Carbon Footprint pro cloudové odhady
- RAPL na CPU: V systému Linux vyžaduje přístup k
/sys/class/powercap/; v systémech macOS a Windows použijte odhad TDP - Celková přesnost: Nedávný výzkum (2025) naznačuje, že nástroje pro odhad mohou mít chyby až 40 %; použijte data jako řádovou hodnotu, nikoli jako absolutní míru
Integrace s MLflow: Emise jako experimentální metriky
Integrace CodeCarbon s MLflow vám umožňuje zaznamenávat emise CO₂ spolu s metrikami modelu (přesnost, ztráta, F1). Uhlíková stopa se stává kritériem výběru modelu přesně jako prediktivní výkon.
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: Nativní integrace
Společnost Dataroots vyvinula speciální balíček, který rozšiřuje MLflow o nativní podporu pro CodeCarbon,
poskytování třídy EmissionsTrackerMlflow který automaticky zaznamenává emise
v životním cyklu běhu 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
Dashboard a vizualizace emisí
CodeCarbon vygeneruje soubor CSV se všemi měřeními. Můžete vytvářet vlastní řídicí panely s plotly nebo matplotlib pro analýzu trendů, porovnání experimentů a přípravu zpráv ESG.
Struktura výstupního CSV
Hlavní pole CSV CodeCarbon
| Pole | Jednotka | Popis |
|---|---|---|
timestamp |
ISO 8601 | Okamžik měření |
project_name |
- | Název projektu |
duration |
sekundy | Celková doba sledování |
emissions |
kgCO₂ekv | Celkové emise |
cpu_energy |
kWh | energie CPU |
gpu_energy |
kWh | energie GPU |
ram_energy |
kWh | energie RAM |
energy_consumed |
kWh | Celková energie (CPU+GPU+RAM) |
carbon_intensity |
kgCO₂/kWh | Použitá intenzita uhlíku |
country_name |
- | Země provedení |
gpu_model |
- | Zjištěn model GPU |
Dashboard s Plotly a statickou zprávou s 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)
Cloudová uhlíková stopa: Emise cloudového pracovního zatížení
CodeCarbon měří místní emise na stroji, kde kód běží. Pro distribuovanou pracovní zátěž v cloudu potřebujete doplňkový nástroj: Cloudová uhlíková stopa (CCF), open-source projekt původně vyvinutý společností ThoughtWorks.
CodeCarbon vs Cloud Carbon Footprint
| Charakteristický | KódCarbon | Cloudová uhlíková stopa |
|---|---|---|
| Hlavní cíl | Místní / místní kód | Vytížení na veřejném cloudu |
| Zdroj dat | Přímý hardware (NVML, RAPL) | Poskytovatelé fakturačního rozhraní API |
| Poskytovatelé cloudu | Jakýkoli hardware | AWS, GCP, Azure |
| V reálném čase | Ano (15-30 sekund) | Ne (zpožděné fakturační údaje) |
| Zrnitost | Na proces, na GPU | Na účet, na region, na službu |
| Zabudovaný uhlík (rozsah 3) | No | Ano (výrobní odhad) |
| Webové panely | CSV + vlastní | Včetně palubní desky React |
# 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
Srovnání nástrojů: CodeCarbon vs Alternatives
Krajina nástrojů pro měření uhlíkové stopy kódu se rychle vyvíjí. Zde je technické srovnání nejpoužívanějších možností v roce 2025.
Úplné srovnání
| Nástroj | GPU | Offline | MLflow | Přesnost | Údržba |
|---|---|---|---|---|---|
| KódCarbon | NVIDIA (NVML) | Sì | Přes SDK | Středně vysoká | Aktivní (2025) |
| Eco2AI | Omezený | Sì | No | Průměrný | 2023 |
| Carbon Tracker | Sì | Částečný | No | Průměrný | 2022 |
| Dopad ML CO2 | Úcta | N/A | No | Nízká (odhad) | Webové nástroje |
| PyrRAPL | No | Sì | No | Vysoká (CPU Intel) | 2021 |
| Carbon Aware SDK | N/A | No | No | N/A (posouvání) | Aktivní (GSF) |
Pokyny pro volbu
- KódCarbon: Nejlepší volba pro školení ML v Pythonu na místním nebo on-premise hardwaru. Výborná podpora NVIDIA GPU, integrace MLflow, velká komunita.
- Cloudová uhlíková stopa: Pro analýzu uhlíkových nákladů cloudové infrastruktury. Doplněk ke CodeCarbon, nikoli náhrada.
- Kalkulačka dopadu ML CO2: Webový nástroj pro rychlé odhady před zahájením tréninku. Užitečné ve fázi plánování pro výběr hardwaru a oblasti cloudu.
- Carbon Aware SDK (GSF): Neměří emise, ale minimalizuje je prostřednictvím času/místa řazení. Použijte jej společně s CodeCarbon pro kompletní strategii.
Integrace CI/CD s akcemi GitHub
Systematické měření se stává skutečně užitečným, když je automatizováno. Zde je návod, jak integrovat CodeCarbon do pracovního postupu GitHub Actions s prosazováním uhlíkového rozpočtu.
# .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 a 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
Skutečná případová studie: Optimalizace školení NLP s CodeCarbon
Tým NLP trénoval model klasifikace sentimentu na recenzích produktů v italštině. Cílem bylo dosáhnout 90%+ přesnosti. Před představením CodeCarbon, tréninkový proces byl z hlediska uhlíkové stopy zcela neprůhledný.
Výchozí situace (základní hodnota)
Základní konfigurace
| Parametr | Výchozí hodnota | Optimalizovaná hodnota |
|---|---|---|
| Model | BERT-velký bez pouzdra (340 milionů parametrů) | DistilBERT vícejazyčný (66 milionů parametrů) |
| Železářské zboží | 1x NVIDIA A100 80GB | 1x NVIDIA A100 80GB |
| Oblast datového centra | Německo (381 gCO₂/kWh) | Francie (56 gCO₂/kWh) |
| Epochy | 20 (bez předčasného zastavení) | Předčasné zastavení, konvergence v epoše 9 |
| Velikost dávky | 16 (A100 30 % využito) | 128 (A100 využito na 92 %) |
| Smíšená přesnost | Ne (FP32) | Ano (FP16) |
| Val přesnost | 91,2 % | 90,7 % |
| Délka tréninku | ~4,5 hodiny | ~36 minut |
Výsledky měřené pomocí CodeCarbon
Porovnání uhlíkové stopy: základní vs. optimalizovaná
| Metrický | Základní linie | Optimalizováno | Snížení |
|---|---|---|---|
| emitovaného CO2 | 1 723 kg CO₂ekv | 0,061 kg CO₂ekv | -96,5 % |
| Spotřebovaná energie | 4,52 kWh | 1,09 kWh | -75,9 % |
| Délka tréninku | 4,5 hodiny | 36 minut | -86,7 % |
| Val Přesnost | 91,2 % | 90,7 % | -0,5 % (přijatelné) |
| Využití GPU | ~30 % | ~92 % | +62 str |
| Odhadovaná cena cloudu | ~13,50 $ | ~1,80 $ | -86,7 % |
Snížení 96,5 % emisí s přesností pouze -0,5 % to dokazuje ve většině případů může být uhlíková stopa softwaru ML drastická snížena bez obětování kvality modelu. Nejdůležitější lekce: změřte před optimalizací.
5 intervencí ke snížení emisí ML (v pořadí dopadu)
- Změna polohy (Německo → Francie): hlavní příspěvek – 85 % emisí. Uhlíková intenzita elektrické sítě je jedním z nejvlivnějších faktorů. Francie (jaderná, ~56 gCO₂/kWh) vs. Německo (~381 gCO₂/kWh) vytváří rozdíl 7x jsou všechny ostatní stejné.
- Předčasné zastavení: průměrná doba trvání -55 %. Většina školení ML konverguje mnohem dříve, než je nakonfigurovaný počet epoch. Včasné zastavení s trpělivostí 3-5 eliminuje zbytečné epochy.
- Zmenšená velikost modelu (BERT-large → DistilBERT): -80 % parametrů, -60 % času. Destilované nebo menší modely často dosahují srovnatelné přesnosti za zlomek výpočtu.
- FP16 se smíšenou přesností: -30-50 % energie GPU. Na GPU NVIDIA A100, RTX 3090+ a FP16 Je hardwarově akcelerovaný a téměř na polovinu snižuje spotřebu při operacích násobení matic.
- Optimální velikost dávky: -75 % trvání pro stejné epochy. Optimální velikost šarže pro dostupnou VRAM maximalizuje využití GPU a zkracuje celkovou dobu školení.
Nejlepší postupy pro systematické sledování uhlíku
Doporučená struktura projektu
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
Konvence pojmenování a konfigurace z proměnných prostředí
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-vzory, kterým je třeba se vyhnout
- Nesledovat předběžné zpracování: Tokenizace a rozšiřování dat mohou spotřebovat Významný CPU. Vždy zahrňte předzpracování do svého sledování, abyste získali plnou stopu.
- Porovnejte běhy mezi různými zeměmi: Emise CO₂ nejsou srovnatelné přímo mezi běhy v zemích s různou intenzitou uhlíku. Normalizujte podle kWh nebo použití pevná země pro všechny referenční hodnoty.
- Nepoužívejte verzi .codecarbon.config: Konfigurace trackeru musí být verze v repo, aby byla zajištěna reprodukovatelnost měření mezi vývojáři.
-
V případě výjimky zastavte sledovač: Vždy použijte pokus/konečný blok
nebo kontextový manažer, aby to zajistil
tracker.stop()je také přivolán případ havárie, zachování dílčích dat. - Považujte CSV za konečný koncový bod: Výchozím bodem je CSV. Vytvářejte analytické kanály pro získávání užitečných statistik a porovnávání experimentů.
Carbon Accounting a ESG Reporting s CodeCarbon Data
Emise naměřené pomocí CodeCarbon nejsou užitečné pouze pro optimalizaci kódu: představují cenná data pro hlášení ESG a shodu Směrnice CSRD (Corporate Sustainability Reporting Directive), který ukládá velké evropské společnosti, aby od roku 2025–2026 hlásily digitální emise. V tomto kontextu se CodeCarbon stává nástrojem řízení i vývojovým nástrojem.
Rámec protokolu o skleníkových plynech (Greenhouse Gas Protocol) klasifikuje emise do tří oblastí: Rozsah 1 (přímé emise, např. dieselové generátory), Rozsah 2 (nakoupená elektřina, která zahrnuje emise CodeCarbon) e Rozsah 3 (hodnotový řetězec, např. dodavatel cloudu a hardwarový produkt). CodeCarbon primárně pokrývá emise rozsahu 2 související s výpočetní zátěží.
Agregace dat pro čtvrtletní zprávy ESG
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"
)
Cíle snižování a vědecky podložené cíle (SBTi)
Společnosti, které se připojí k iniciativě Science Based Targets (SBTi), se zavázaly ke snižování emise v souladu s klimatickými cíli Pařížské dohody. Pro emise ICT, to obvykle znamená roční snížení 4–7 %. CodeCarbon lze použít k automatickému sledování pokroku směrem k těmto cílům.
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 a CSRD: Co potřebujete vědět
Směrnice CSRD (Corporate Sustainability Reporting Directive) vyžaduje evropské společnosti s více než 500 zaměstnanci (od roku 2025) a následně s více než 250 zaměstnanci (od roku 2026) vykazovat emise skleníkových plynů podle standardů ESRS (European Sustainability Reporting Standards). Pro digitální vydání:
- ESRS E1 (změna klimatu): Vyžaduje zveřejnění emisí rozsahu 1, 2 a 3 s metodikou GHG Protocol. CodeCarbon pokrývá rozsah 2 výpočetních operací.
- Významnost: Pokud jsou emise ICT podstatné (významné ve srovnání na podnik celkem), musí být vykázány. U technologických společností je to téměř vždy případ.
- Auditní stopy: Soubory CSV CodeCarbon poskytují podrobný auditní záznam pro ověření podávání zpráv třetí stranou, základní požadavek na důvěryhodnost zprávy ESG.
- Ujištění: CSRD vyžaduje omezené (od roku 2025) a přiměřené (od roku 2028) ujištění. Rozhodující je kvalita dat CodeCarbon (přímé měření vs. odhad).
Závěry: Měření je prvním krokem
CodeCarbon transformoval sledování kódu uhlíku z akademického cvičení na praxi betonové a dostupné inženýrství. S méně než 10 řádky Pythonu, každý datový vědec o Inženýr ML může začít měřit a kvantifikovat dopad své práce na životní prostředí.
Případová studie prokázala snížení v 96,5 % emisí CO₂ s přesností pouze -0,5 %. Toto není výjimečný případ: je to norma, kdy začínáme od neoptimalizované konfigurace. Většina školení ML má obrovské marže optimalizace uhlíku, které zůstanou neviditelné, dokud nezačnete měřit.
Cesta k udržitelnějšímu softwaru má tři fáze:
- Opatření: Integrujte CodeCarbon do všech pracovních postupů. Definujte uhlíkový rozpočet. Vytvořte měřitelné základní linie. Udělejte emise stejně viditelné jako přesnost.
- Optimalizovat: Použijte data k identifikaci uhlíkových úzkých míst. Posun místa, velikost modelu, velikost šarže a smíšená přesnost jsou nejúčinnějšími pákami.
- Zabránit: Integrujte sledování uhlíku do CI/CD. Definujte uhlíkový rozpočet podle typu experimentu. Použijte sadu Carbon Aware SDK k automatizaci posunu místa/času.
V dalším článku ze série se podíváme na to Climatiq API, nástroj doplňkové, které vám umožňuje vypočítat emise GHG protokolu (rozsah 1, 2 a 3) prostřednictvím REST API, integrující výpočty do backendu aplikací pro automatizované ESG reporting.
Zdroje a užitečné odkazy
Green Software Series pokračuje
- Článek 1: Principy Green Software Foundation — GSF, SCI, 8 principů
- Článek 2 (aktuální): Měření vaší uhlíkové stopy pomocí CodeCarbon
- Článek 3: Integrujte výpočty Climatiq API — GHG Protocol do backendu
- Článek 4: Carbon Aware SDK – Time shifting a location shifting
- Článek 6: GreenOps s Kubernetes – uhlíková infrastruktura
- Článek 10: Umělá inteligence a uhlík – Měření a snižování dopadu školení ML







