CodeCarbon으로 코드의 탄소 배출량 측정
기계 학습 모델을 교육할 때마다 ETL 파이프라인을 실행하거나 배치 작업을 실행합니다. 밤에는 에너지를 소비합니다. 그 에너지에는 실제 탄소 비용이 있는데, 이는 언제 어디서 달리는지에 따라 달라집니다. 코드. ICT 부문 전체가 다음을 담당합니다. 전 세계 배출량의 2~4% CO2의이는 전 세계 항공산업 전체와 맞먹는 점유율이다. 하지만 비행과 달리 소프트웨어 방출은 거의 항상 보이지 않습니다.
GPT-3 교육은 대략적으로 이루어졌습니다. CO2 552톤, 300회 운행에 해당 비행기로 뉴욕-샌프란시스코 왕복 여행. A100 GPU에서 10시간 동안 BERT-large를 미세 조정했습니다. 독일(~381 gCO₂/kWh의 에너지 혼합)은 약 CO2 1.2kg. 동일한 교육이 프랑스로 이전됨(원자력, ~56 gCO₂/kWh) 177그램. 동일한 코드에 대해 차이는 거의 7배입니다.
코드카본 이러한 배출량을 측정 가능하게 만드는 오픈 소스 도구입니다. 비교할 수 있는. 몇 줄의 Python을 사용하면 모든 프로세스의 탄소 배출량을 추적할 수 있습니다. 단일 ML 실험부터 프로덕션 파이프라인까지 계산을 수행하고 이러한 측정항목을 통합합니다. MLflow 워크플로, ESG 보고서 및 CI/CD 파이프라인에서.
무엇을 배울 것인가
- CodeCarbon의 내부 아키텍처: 에너지를 측정하고 CO2 배출량을 계산하는 방법
- 설정
EmissionsTrackereOfflineEmissionsTracker - TensorFlow 및 PyTorch 모델 학습 시 추적
- NVIDIA 하드웨어용 CUDA 및 NVML을 사용한 GPU 측정
- 다양한 유럽 국가 및 그리드 탄소 강도에 대한 구성
- 실험 측정항목으로 배출을 위해 MLflow와 통합
- 추세 시각화를 위한 matplotlib 및 플롯을 갖춘 대시보드
- AWS, GCP 및 Azure의 배출량을 추정하는 클라우드 탄소 발자국
- 도구 비교: CodeCarbon, Eco2AI, CarbonTracker, ML CO2 Impact
- 실제 사례 연구: 배출량 96% 감소로 NLP 교육 최적화
친환경 소프트웨어 시리즈: 지속 가능한 소프트웨어 개발을 위한 10가지 기사
| # | Articolo | 주제 | 상태 |
|---|---|---|---|
| 1 | 그린 소프트웨어 기반 원칙 | GSF, SCI, 8가지 기본 원칙 | 사용 가능 |
| 2 | CodeCarbon으로 탄소 배출량 측정 | 측정, 추적, 대시보드 | 현재 기사 |
| 3 | Climatiq API 통합 | GHG 프로토콜 계산, 범위 1-3 | 사용 가능 |
| 4 | 탄소 인식 SDK | 시간 이동, 위치 이동 | 사용 가능 |
| 5 | 범위 1, 2, 3: ESG 데이터 모델링 | 데이터 구조, 계산, 집계 | 사용 가능 |
| 6 | Kubernetes를 사용한 GreenOps | 탄소 인식 스케줄링, 인프라 | 사용 가능 |
| 7 | 파이프라인 범위 3 가치 사슬 | 공급업체 데이터, 감사 추적 | 사용 가능 |
| 8 | ESG 보고 및 CSRD API | 유럽 규정 준수, 자동화 | 사용 가능 |
| 9 | 지속 가능한 아키텍처 패턴 | 스토리지, 캐시, 탄소 인식 배치 | 사용 가능 |
| 10 | AI 및 Carbon: ML 훈련 공간 | 그린 AI, 훈련 최적화 | 사용 가능 |
CodeCarbon: 아키텍처 및 운영 메커니즘
CodeCarbon은 두 기업이 협력하여 개발한 오픈 소스 Python 라이브러리입니다. Mila Quebec AI Institute, Carnegie Mellon University, Comet.ml 및 BCG GAMMA. 이 프로젝트는 코드 방출 측정을 목표로 2020년에 탄생했습니다. 전용 하드웨어 장비 없이도 모든 데이터 과학자가 액세스할 수 있습니다.
작동 원리는 다음과 같은 기본 공식을 기반으로 합니다.
코드카본 센트럴 포뮬러
CO2 배출량 [kg] = 소비된 에너지 [kWh] × 네트워크의 탄소 집약도 [kgCO2/kWh]
소비되는 에너지는 구성 요소별로 측정됩니다(GPU + CPU + RAM). 탄소 강도는 국가/지역별로 업데이트된 데이터베이스에서 검색됩니다. 또는 오프라인 환경에서는 수동으로 제공됩니다.
내부 측정 파이프라인
CodeCarbon은 매 시간 에너지 소비량을 샘플링합니다. 15초 (configurable) through a multi-level pipeline. 각 샘플링에서 CPU, GPU 및 RAM의 순간 전력을 측정합니다. 시간이 지남에 따라 적분하여 kWh를 구하고 국가의 배출 계수를 곱합니다.
에너지 측정 계층
| 요소 | 측정 방법 | 정도 | 유효성 |
|---|---|---|---|
| 엔비디아 GPU | pynvml을 통한 NVML(NVIDIA 관리 라이브러리) | 높음(직접 측정) | 드라이버가 포함된 NVIDIA GPU만 |
| 인텔 CPU | pyRAPL을 통한 RAPL(실행 평균 전력 제한) | 높음(하드웨어 센서) | MSR 액세스가 가능한 Linux, Intel |
| AMD/ARM CPU | 예상 TDP + 사용 비율 | 평균(추정) | 모든 시스템 |
| 숫양 | 실험식: 8GB당 3W | 낮음-중간(예상) | 모든 시스템 |
| AMD GPU | ROCm SMI(사용 가능한 경우) | 높음(직접 측정) | ROCm을 탑재한 AMD GPU |
국가별 탄소 집약도
kWh를 kgCO2로 변환하기 위해 CodeCarbon은 배출 계수의 계층적 데이터베이스를 사용합니다. 온라인 모드에서는 IP 위치정보를 통해 데이터를 검색합니다. 오프라인 모드에서는 240개 이상의 국가에 대한 연간 평균 값이 포함된 내부 데이터베이스를 사용합니다.
유럽 국가별 탄소 집약도(2024)
| 마을 | gCO₂/kWh | 주요 에너지 믹스 | ISO 코드 |
|---|---|---|---|
| 노르웨이 | ~28 | 수력발전 (90%) | 도 아니다 |
| 프랑스 | ~56 | 원자력 (70%) | 사이 |
| 스웨덴 | ~45 | 원자력 + 수력 | 스웨덴 |
| 스페인 | ~191 | 재생에너지 + 가스 | 경험치 |
| 이탈리아 | ~233 | 천연가스 + 재생에너지 | ITA |
| 독일 | ~381 | 가스 + 석탄 + 풍력 | DEU |
| 폴란드 | ~640 | 석탄 (70%) | POL |
CodeCarbon 설정 및 설치
CodeCarbon을 설치하려면 Python 3.7 이상이 필요하며 PyPI 및 conda에서 사용할 수 있습니다. GPU 추적을 위해서는 NVIDIA 드라이버와 pynvml 패키지가 필요합니다.
설치
# 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')
"
구성 파일 .codecarbon.config
CodeCarbon은 반복을 방지하는 프로젝트 전체 INI 구성 파일을 지원합니다.
각 스크립트의 매개변수 파일 만들기 .codecarbon.config 프로젝트 루트에서:
# .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: 세 가지 사용 모드
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: 인터넷이 없는 환경용
HPC 클러스터, 프로덕션 컨테이너 또는 인터넷에 액세스할 수 없는 머신에서는 다음을 사용합니다.
OfflineEmissionsTracker. ISO 국가 코드는 필수가 됩니다.
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
)
기계 학습 프로젝트의 배출량 추적
CodeCarbon의 주요 사용 사례는 ML 모델을 훈련할 때 추적하는 것입니다. PyTorch와 TensorFlow/Keras를 사용한 실제 사례를 살펴보겠습니다.
전체 탄소 추적을 통한 PyTorch 훈련
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")
TensorFlow용 Keras 콜백
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()
GPU 추적: NVIDIA NVML을 통한 정밀한 측정
GPU 집약적인 워크로드의 경우 CodeCarbon은 다음을 사용합니다. pynvml, Python 바인딩 NVML(NVIDIA 관리 라이브러리)은 직접 전력 소비량을 와트 단위로 측정합니다. 이는 1~5와트의 분해능을 갖춘 가장 정확한 방법입니다.
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()
GPU 추적의 한계
- CUDA만 지원하는 NVIDIA: AMD GPU에는 ROCm이 필요합니다. Intel Arc는 지원되지 않습니다.
- 권한이 없는 Docker 컨테이너: NVML은 드라이버에 액세스할 수 없습니다.
깃발을 추가하다
--privileged또는 마운트/dev/nvidia* - 클라우드 VM: EC2/GCE/Azure에서 NVML 인스턴스는 실제 소비를 노출하지 않을 수 있습니다. 클라우드 추정에 Cloud Carbon Footprint 사용
- CPU의 RAPL: Linux에서는 다음에 대한 액세스가 필요합니다.
/sys/class/powercap/; macOS 및 Windows에서는 TDP 추정치를 사용합니다. - 전반적인 정확도: 최근 연구(2025)에 따르면 추정 도구는 최대 40%의 오류가 있을 수 있습니다. 절대적인 척도가 아닌 크기의 순서로 데이터를 사용하십시오.
MLflow와의 통합: 실험 지표로서의 배출량
CodeCarbon을 MLflow와 통합하면 측정항목과 함께 CO2 배출량을 기록할 수 있습니다. 모델의 (정확도, 손실, F1). 탄소발자국이 모델 선택 기준이 되다 예측 성능과 똑같습니다.
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: 기본 통합
Dataroots는 CodeCarbon에 대한 기본 지원을 통해 MLflow를 확장하는 전용 패키지를 개발했습니다.
수업을 제공하는 EmissionsTrackerMlflow 배출량을 자동으로 기록하는
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
대시보드 및 배출량 시각화
CodeCarbon은 모든 측정값이 포함된 CSV 파일을 생성합니다. 맞춤형 대시보드를 구축할 수 있습니다. 플롯이나 matplotlib를 사용하여 추세를 분석하고, 실험을 비교하고, ESG 보고서를 준비합니다.
출력 CSV의 구조
CodeCarbon CSV의 주요 분야
| 필드 | 단위 | 설명 |
|---|---|---|
timestamp |
ISO 8601 | 측정 순간 |
project_name |
- | 프로젝트 이름 |
duration |
secondi | 총 추적 기간 |
emissions |
kgCO²eq | 총 배출량 |
cpu_energy |
kWh | CPU 에너지 |
gpu_energy |
kWh | GPU 에너지 |
ram_energy |
kWh | RAM 에너지 |
energy_consumed |
kWh | 총 에너지(CPU+GPU+RAM) |
carbon_intensity |
kgCO₂/kWh | 사용된 탄소 강도 |
country_name |
- | 처형 국가 |
gpu_model |
- | GPU 모델 감지됨 |
Plotly가 포함된 대시보드 및 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)
클라우드 탄소 배출량: 클라우드 워크로드 배출량
CodeCarbon은 코드가 실행되는 기계의 국지적 배출량을 측정합니다. 분산 워크로드용 클라우드에는 보완 도구가 필요합니다. 클라우드 탄소 발자국(CCF), ThoughtWorks에서 처음 개발한 오픈 소스 프로젝트입니다.
CodeCarbon과 클라우드 탄소 발자국
| 특성 | 코드카본 | 클라우드 탄소 발자국 |
|---|---|---|
| 주요 타겟 | 로컬/온프레미스 코드 | 퍼블릭 클라우드의 워크로드 |
| 데이터 소스 | 하드웨어 다이렉트(NVML, RAPL) | Billing API 클라우드 제공업체 |
| 클라우드 제공업체 | 모든 하드웨어 | AWS, GCP, 애저 |
| 실시간 | 예(15~30초) | 아니요(결제 데이터 지연) |
| 세분성 | 프로세스별, GPU별 | 계정별, 지역별, 서비스별 |
| 구체화된 탄소(범위 3) | No | 예(제조 견적) |
| 웹 대시보드 | CSV + 맞춤 | 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
도구 비교: CodeCarbon과 대안
코드 탄소 배출량 측정 도구의 환경은 빠르게 발전하고 있습니다. 다음은 2025년에 가장 많이 사용된 옵션에 대한 기술 비교입니다.
전체 비교
| 기구 | GPU | 오프라인 | MLflow | 정확성 | 유지 |
|---|---|---|---|---|---|
| 코드카본 | 엔비디아(NVML) | Sì | SDK를 통해 | 중간-높음 | 활성 (2025) |
| 에코2AI | 제한된 | Sì | No | 평균 | 2023년 |
| 탄소 추적기 | Sì | 부분 | No | 평균 | 2022년 |
| ML CO2 영향 | 존중 | 해당 없음 | No | 낮음(추정) | 웹 도구 |
| 파이라플 | No | Sì | No | 높음(인텔 CPU) | 2021 |
| 탄소 인식 SDK | 해당 없음 | No | No | 해당 없음(변속) | 활성(GSF) |
선택 지침
- 코드카본: 로컬 또는 온프레미스 하드웨어에서 Python을 사용한 ML 교육을 위한 최고의 선택입니다. 뛰어난 NVIDIA GPU 지원, MLflow 통합, 대규모 커뮤니티.
- 클라우드 탄소 발자국: 클라우드 인프라의 탄소 비용 분석용입니다. 대체품이 아닌 CodeCarbon을 보완합니다.
- ML CO2 영향 계산기: 훈련을 시작하기 전에 빠른 예측을 위한 웹 도구입니다. 하드웨어 및 클라우드 지역을 선택하는 계획 단계에서 유용합니다.
- 탄소 인식 SDK(GSF): 배출량을 측정하지 않고 시간/장소를 통해 최소화합니다. 이동. 완전한 전략을 위해 CodeCarbon과 함께 사용하세요.
GitHub Actions와 CI/CD 통합
체계적인 측정은 자동화되면 정말 유용해집니다. 탄소 예산 집행을 통해 CodeCarbon을 GitHub Actions 워크플로에 통합하는 방법은 다음과 같습니다.
# .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) |`
});
탄소 예산 및 SCI(소프트웨어 탄소 강도)
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
실제 사례 연구: CodeCarbon을 사용한 NLP 훈련 최적화
NLP 팀은 제품 리뷰에 대한 감정 분류 모델을 훈련하고 있었습니다. 이탈리아어로. 목표는 90% 이상의 정확도를 달성하는 것이었습니다. CodeCarbon을 소개하기 전에, 훈련 과정은 탄소 발자국 관점에서 볼 때 완전히 불투명했습니다.
초기 상황(기준)
기준 구성
| 매개변수 | 기준값 | 최적화된 가치 |
|---|---|---|
| 모델 | BERT-대형-비케이스(340M 매개변수) | DitilBERT 다국어(66M 매개변수) |
| 하드웨어 | 1x 엔비디아 A100 80GB | 1x 엔비디아 A100 80GB |
| 데이터 센터 지역 | 독일(381 gCO₂/kWh) | 프랑스(56gCO²/kWh) |
| 시대 | 20 (조기 중단 없음) | 조기 중단, 에포크 9에서 수렴 |
| 배치 크기 | 16 (A100 30% 사용) | 128 (A100 92% 사용) |
| 혼합 정밀도 | 아니요(FP32) | 예(FP16) |
| 발 정확도 | 91.2% | 90.7% |
| 훈련 기간 | ~4.5시간 | ~36분 |
CodeCarbon으로 측정한 결과
탄소 배출량 비교: 기준선과 최적화
| 미터법 | 기준선 | 최적화됨 | 절감 |
|---|---|---|---|
| CO2 배출 | 1,723kgCO²eq | 0.061kgCO²eq | -96.5% |
| 에너지 소비 | 4.52kWh | 1.09kWh | -75.9% |
| 훈련 기간 | 4.5시간 | 36분 | -86.7% |
| 발 정확도 | 91.2% | 90.7% | -0.5%(허용) |
| GPU 활용도 | ~30% | ~92% | +62pp |
| 예상 클라우드 비용 | ~$13.50 | ~$1.80 | -86.7% |
감소 배출량의 96.5% -0.5%의 정확도만으로 다음을 증명합니다. 대부분의 경우 ML 소프트웨어의 탄소 배출량은 극적으로 증가할 수 있습니다. 모델 품질을 저하시키지 않고 축소됩니다. 가장 중요한 교훈: 최적화하기 전에 측정.
ML 배출을 줄이기 위한 5가지 개입(영향 순)
- 위치 이동(독일 → 프랑스): 주요 기여도 -85% 배출량. 전력망의 탄소 집약도는 가장 큰 영향을 미치는 단일 요소입니다. 프랑스(원자력, ~56 gCO2/kWh)와 독일(~381 gCO2/kWh)의 차이 7x의 다른 모든 것은 동일합니다.
- 조기 중단: 평균 지속 시간 -55%. ML 학습의 대부분은 수렴됩니다. 구성된 에포크 수보다 훨씬 빠릅니다. 인내심을 3~5로 조기에 중단하면 불필요한 시대가 제거됩니다.
- 축소된 모델 크기(BERT-large → DitilBERT): -80% 매개변수, -60% 시간. 증류되거나 더 작은 모델은 종종 컴퓨팅의 일부만으로 비슷한 정확도를 달성합니다.
- 혼합 정밀도 FP16: -30-50% GPU 에너지. NVIDIA A100 GPU, RTX 3090+에서 FP16 하드웨어 가속이며 행렬 곱셈 연산의 소비를 거의 절반으로 줄입니다.
- 최적의 배치 크기: 동일한 에포크 동안 지속 시간이 -75%입니다. 최적의 배치 크기 사용 가능한 VRAM의 경우 GPU 활용도를 최대화하고 총 훈련 시간을 줄입니다.
체계적인 탄소 추적을 위한 모범 사례
권장 프로젝트 구조
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
환경 변수의 명명 규칙 및 구성
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()
피해야 할 안티패턴
- 전처리를 추적하지 마세요. 토큰화 및 데이터 증대는 다음과 같은 소비를 가져올 수 있습니다. 상당한 CPU. 전체 공간을 확보하려면 항상 추적에 전처리를 포함하세요.
- 여러 국가 간 실행 비교: CO2 배출량은 비교할 수 없습니다. 탄소 강도가 다른 국가의 실행 사이에 직접적으로. kWh로 정규화하거나 사용 모든 벤치마크에 대해 고정된 국가입니다.
- .codecarbon.config 버전을 지정하지 마세요. 추적기 구성은 다음과 같아야 합니다. 개발자 간의 측정 재현성을 보장하기 위해 저장소에 버전이 지정되어 있습니다.
-
예외 발생 시 추적기를 중지합니다. 항상 try/finally 블록을 사용하세요.
또는 컨텍스트 관리자가 이를 보장합니다.
tracker.stop()에서도 호출됩니다. 충돌이 발생한 경우 부분 데이터를 보존합니다. - CSV를 최종 끝점으로 처리합니다. CSV가 출발점입니다. 분석 파이프라인을 구축하여 실행 가능한 통찰력을 추출하고 실험을 비교하세요.
CodeCarbon 데이터를 사용한 탄소 회계 및 ESG 보고
CodeCarbon으로 측정된 배출량은 코드 최적화에만 유용하지 않습니다. ESG 보고 및 규정 준수를 위한 귀중한 데이터를 나타냅니다. CSRD 지침(기업 지속 가능성 보고 지침), 이는 유럽 대기업은 2025~2026년부터 디지털 배출량을 보고합니다. 이러한 맥락에서 CodeCarbon은 개발 도구이자 거버넌스 도구가 됩니다.
GHG 프로토콜(온실가스 프로토콜) 프레임워크는 배출을 세 가지 범위로 분류합니다. 범위 1 (직접 배출, 예: 디젤 발전기), 범위 2 (구매한 전력, CodeCarbon 배출 포함) e 범위 3 (가치 사슬, 예: 클라우드 공급업체 및 하드웨어 제품) CodeCarbon은 주로 계산 작업 부하와 관련된 Scope 2 배출을 다룹니다.
분기별 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"
)
감축 목표 및 과학 기반 목표(SBTi)
과학 기반 목표 이니셔티브(SBTi)에 참여하는 회사는 파리 협약의 기후 목표에 맞춰 배출합니다. ICT 배출의 경우, 이는 일반적으로 연간 4-7%. CodeCarbon을 사용하면 이러한 목표를 향한 진행 상황을 자동으로 추적할 수 있습니다.
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 및 CSRD: 알아야 할 사항
CSRD 지침(Corporate Sustainability Reporting Directive)은 유럽 기업이 요구하는 사항입니다. 직원 수 500명 이상(2025년부터), 이후 직원 수 250명 이상(2026년) ESRS 표준(유럽 지속가능성 보고 표준)에 따라 온실가스 배출량을 보고합니다. 디지털 릴리스의 경우:
- ESRS E1(기후 변화): 범위 1, 2, 3 배출 공개가 필요합니다. GHG 프로토콜 방법론을 사용합니다. CodeCarbon은 계산 작업의 범위 2를 다룹니다.
- 유형: ICT 배출량이 중요한 경우(비교하면 상당한 수준) 회사총액)을 신고하여야 합니다. 기술 회사의 경우 이는 거의 항상 그렇습니다.
- 감사 추적: CodeCarbon CSV는 검증을 위한 세부적인 감사 추적을 제공합니다. 제3자 보고는 ESG 보고서의 신뢰성을 위한 필수 요구 사항입니다.
- 보증: CSRD는 제한적(2025년부터) 및 합리적인(2028년부터) 보증을 요구합니다. CodeCarbon 데이터의 품질(직접 측정과 추정)이 중요합니다.
결론: 측정이 첫 번째 단계입니다.
CodeCarbon은 코드 탄소 추적을 학문적 연습에서 실습으로 전환했습니다. 구체적이고 접근 가능한 엔지니어링. 10줄 미만의 Python으로 데이터 과학자라면 누구나 o ML 엔지니어는 작업이 환경에 미치는 영향을 측정하고 정량화할 수 있습니다.
사례 연구에서는 CO2 배출량 96.5% 정확도가 -0.5%에 불과합니다. 이는 예외적인 경우가 아니며 다음과 같은 경우가 일반적입니다. 최적화되지 않은 구성에서 시작합니다. 대부분의 ML 교육에는 큰 마진이 있습니다. 측정을 시작할 때까지 눈에 보이지 않는 탄소 최적화.
보다 지속 가능한 소프트웨어를 향한 길은 세 단계를 따릅니다.
- 측정하다: CodeCarbon을 모든 워크플로에 통합합니다. 탄소 예산을 정의합니다. 측정 가능한 기준선을 만듭니다. 배출량을 정확성만큼 눈에 띄게 만드세요.
- 최적화: 데이터를 사용하여 탄소 병목 현상을 식별합니다. 위치이동, 모델 크기, 배치 크기 및 혼합 정밀도가 가장 효과적인 요소입니다.
- 예방하다: 탄소 추적을 CI/CD에 통합합니다. 유형별 탄소 예산 정의 실험의. Carbon Aware SDK를 사용하여 위치/시간 이동을 자동화하세요.
시리즈의 다음 기사에서 우리는 탐구할 것입니다 Climatiq API, 도구 이를 통해 GHG 프로토콜 배출량(범위 1, 2 및 3)을 계산할 수 있습니다. 자동화된 ESG 보고를 위해 계산을 애플리케이션의 백엔드에 통합하는 REST API입니다.







