AI とカーボン: ML トレーニングのフットプリントの測定と削減
GPT-4 トレーニングの消費量は約 50GWhの電力、十分な ヨーロッパの 4,600 以上の家庭に 1 年間電力を供給します。 GPT-3の前身である、 彼がプロデュースした 502 トンの CO₂ に相当 トレーニング中 — これは、1 台あたり年間 20,000 km を走行する 112 台のガソリン車に相当します。 BLOOM、エネルギーに関してフランスで訓練された 1,760 億パラメータのオープンソース モデル 混合して、彼は言いました 25トンのCO₂eq 普及したおかげで 原子力と再生可能エネルギーのこと。
これらは統計上の奇妙なものではありません。急速に発展している構造的問題の兆候です。 加速。生成 AI はパターンを持って指数関数的に成長します ますます大規模化、ますます大規模なデータセットと、ますます大規模なトレーニング サイクル 頻繁に。で発表された研究によると、 自然 2024 年の排出量は、 何も対策が講じられなければ、AI モデルのトレーニングは 2027 年までに 3 倍になる可能性がある システム効率の向上。 IEA は、2026 年に AI 専用のデータセンターの消費量が増加すると予測しています。 多くの中規模のヨーロッパ諸国よりも多くのエネルギーを持っています。
しかし、ML チームの大多数は、一度も測定を行わずに GPU クラスターでトレーニングを開始します。 生成される排出量。彼らが無関心だからではなく、ツールが不足しているからです 日々のワークフローに統合され、標準指標と測定文化が共有されます。 このシリーズの最後の記事では、 グリーン ソフトウェア エンジニアリング 私たちは探索します 機械学習における二酸化炭素排出量のライフサイクル全体: による正確な測定から CodeCarbon と CarbonTracker、プルーニングと蒸留によるアーキテクチャの最適化、 カーボンを意識したトレーニングのスケジューリングや本番環境での推論の最適化まで。
何を学ぶか
- 基礎モデルの実排出データ: GPT-3、GPT-4、Llama 2、BLOOM、PaLM
- CodeCarbon、CarbonTracker、ML CO₂ インパクトおよびグリーン アルゴリズムをインストールして使用する
- GPU の電力効率の比較: A100、H100、H200、B200 (FLOPS/ワット)
- アーキテクチャ最適化手法: 枝刈り、知識の蒸留、効率的な NAS
- データ中心の効率性: データの質と量、カリキュラム学習
- 二酸化炭素を意識したトレーニング: 低炭素強度の地域と時間帯でワークロードをスケジュールします。
- 推論の最適化: INT8/INT4 量子化、ONNX ランタイム、TensorRT、vLLM
- ML モデルの SCI スコアを計算し、Green AI Leaderboard を構築する
- 完全なケーススタディ: 実際の NLP モデルで排出量を 60% 削減
- 組織にグリーン AI を導入するための実践的なロードマップ
グリーン ソフトウェア エンジニアリング シリーズ — 10 件の記事
| # | アイテム | メインテーマ |
|---|---|---|
| 1 | グリーン ソフトウェア財団の原則 | GSF、SCI、8つの基本原則 |
| 2 | CodeCarbon で二酸化炭素排出量を測定する | CodeCarbon、CCF、CI/CD の統合 |
| 3 | Climatiq API と炭素会計 | REST API、LCA、スコープ 1-2-3 |
| 4 | カーボン対応 SDK と時間的/空間的シフト | ワークロードをグリーン エネルギーにシフト |
| 5 | スコープモデリングとSCI実装 | 実践的なSCI計算、インパクトフレームワーク |
| 6 | GreenOps: 持続可能性のための FinOps | クラウドのコストと炭素、Kubernetes |
| 7 | ソフトウェアパイプラインのスコープ3 | 間接排出、デジタルサプライチェーン |
| 8 | ESG、CSRD、デジタルレポーティング | 欧州コンプライアンス、ESRS E1、開示 |
| 9 | 持続可能な建築パターン | ストレージ、キャッシュ、二酸化炭素を意識したバッチ |
| 10 | AI とカーボン: ML トレーニングのフットプリント | この記事 — シリーズの最終記事 |
基礎モデルの実際の二酸化炭素排出量
問題の規模を理解するには、確かなデータが必要です。スタンフォードの研究者 Hugging Face と MLCommons がメジャーの排出量指標の公開を開始 言語モデル。次の表は、次の点に留意して利用可能なデータを集計したものです。 多くの企業、特に OpenAI は依然としてこの情報を開示していません。
トレーニング中の基礎モデルの CO₂eq 排出量
| モデル | パラメータ | エネルギー (MWh) | CO₂eq (t) | リージョン/ミックス | ソース |
|---|---|---|---|---|---|
| GPT-3 | 175B | 1,287 | 502 | アメリカ (ミディアムミックス) | パターソンら。 2021年 |
| GPT-4 | ~1.8T (推定) | ~50,000 | ~14,000 | アメリカ(推定) | 2023 年の独立した推定値 |
| 咲く | 176B | 433 | 25 | フランス (原子力+再生可能エネルギー) | ルッチョーニら。 2022年 |
| ラマ2 (70B) | 70B | ~700 | 539 | アメリカ/アズール | メタ FW 2023 |
| パルム | 540B | ~3,400 | ~507 | 米国 (TPU v4) | チョウドリーら。 2022年 |
| ミストラル 7B | 7B | ~35 | ~12 | ヨーロッパ(ミックス) | ミストラル FW 2023 |
| ファルコン180B | 180B | ~600 | ~117 | アラブ首長国連邦(ミックス) | TII 2023 |
| ジェム7B | 7B | ~32 | ~6 | 米国/TPU (RE100) | Google ディープマインド 2024 |
このデータから 3 つの基本的なパターンが明らかになります。 1つ目は、 地理的なギャップ: BLOOMは主に原子力を使用してフランスで訓練され、排出量は20分の1に減少 ラマ 2 と同程度の大きさです。 2番目は、スケール効果: パラメーターが 70 億から 1760 億になるということは、単に排出量が 25 倍増加することを意味するわけではありません。 分散通信コストとトレーニング期間は非線形に増加します。 3つ目は、 透明度のギャップ: ほとんどの企業はそうではありません 依然としてこのデータを公開しているため、比較が難しく、ベンチマークが不可能になっています 独立した測定なしで。
推論のパラドックス: トレーニングを超えるもの
直観に反して、累積排出量は、推論 彼らはしばしばそれを超えます モデルのライフサイクルにおけるトレーニングのもの。 ChatGPT のようなモデル、数百万もの 1 日あたりのリクエストの数に応じて、1 か月の生産でより多くのエネルギーを消費する可能性があります オリジナルのトレーニング全体。パターソンら。 GPT-3 の推論が大規模であると推定する ChatGPT は約 年間 11,000 トンの CO₂eq。これ トレーニングの最適化から推論の最適化に焦点を移します。 環境への影響全体を削減することが最優先事項です。
体内排出と完全なライフサイクル
AI による二酸化炭素排出量分析は、生産活動中に消費されるエネルギーに限定することはできません。 トレーニング。の 身体化された排出物 ハードウェアの CO₂ 排出量 GPU、サーバー、冷却ネットワーク、インフラストラクチャを生産するため、これらは 重要なシェア。単一の H100 チップを製造すると、約 150kgCO₂当量、 1,000 GPU クラスターでは、ハードウェアだけで約 150 トンの具体的な排出量が発生します。 トレーニングジョブを 1 つも開始する前に。
# Formula Carbon Footprint Completo per ML
# Basato su Luccioni et al. "Counting Carbon" (2023)
Total_CO2eq = Training_CO2eq + Inference_CO2eq + Embodied_CO2eq
Training_CO2eq = Energy_training (kWh) x Carbon_Intensity (kgCO2eq/kWh) x PUE
Inference_CO2eq = (Requests x Latency x GPU_Power / 3600000) x Carbon_Intensity x PUE
Embodied_CO2eq = (Hardware_Production_CO2eq / Lifespan_hours) x Training_hours
# Esempio: modello NLP medio (BERT-Large fine-tuning su task classificazione)
Energy_training = 120 kWh # 4x A100, 6 ore
Carbon_Intensity = 0.420 kg/kWh # mix europeo medio
PUE = 1.3 # data center tipico
Training_CO2eq = 120 x 0.420 x 1.3 = 65.5 kgCO2eq
# Inferenza: 10M richieste/mese, 50ms each, 1x A100 (300W)
Inference_monthly = (10_000_000 x 0.05 x 300 / 3_600_000) x 0.420 x 1.3
= 41.7 kWh x 0.420 x 1.3 = 22.7 kgCO2eq/mese
# Dopo 12 mesi: 272 kgCO2eq inferenza vs 65 kgCO2eq training
# L'inferenza domina del 77% nel ciclo di vita annuale
測定ツール: CodeCarbon からグリーン アルゴリズムまで
ML エミッションの測定には、ML ワークロード専用に設計されたツールが必要です 訓練と推論。この分野を支配する 4 つのツール: CodeCarbon、CarbonTracker、 ML CO₂ 影響計算ツールとグリーン アルゴリズム。誰もが特有の強みを持っています 最適なユースケース。
CodeCarbon: Python コードへの直接統合
CodeCarbon は、排出ガスを測定するための最も人気のあるツールです。 MLトレーニング。最も一般的なフレームワーク (PyTorch、TensorFlow、 ハグフェイストランスフォーマー)は、ほとんどのチームにとって自然な選択になります。
# pip install codecarbon
from codecarbon import EmissionsTracker, track_emissions
import torch
from transformers import Trainer, TrainingArguments
# Metodo 1: Context manager
tracker = EmissionsTracker(
project_name="bert-finetuning-sentiment",
country_iso_code="ITA",
region="lombardy",
cloud_provider="gcp",
cloud_region="europe-west8",
output_dir="./carbon_reports",
output_file="emissions.csv",
log_level="warning",
save_to_file=True,
tracking_mode="machine", # Legge sensori hardware reali
measure_power_secs=15 # Campionamento ogni 15 secondi
)
tracker.start()
try:
# Il tuo training loop qui
model = train_model(dataset, epochs=10)
finally:
emissions = tracker.stop()
print(f"Training completato: {emissions:.4f} kgCO2eq")
print(f"Equivalente a: {emissions * 2.4:.2f} km in auto")
# Metodo 2: Decorator per funzioni singole
@track_emissions(
project_name="bert-inference",
country_iso_code="ITA",
save_to_file=True
)
def run_inference_batch(model, dataloader):
results = []
with torch.no_grad():
for batch in dataloader:
outputs = model(**batch)
results.extend(outputs.logits.argmax(-1).tolist())
return results
# Metodo 3: Integrazione con Hugging Face Trainer
from codecarbon import EmissionsTracker
class CarbonAwareTrainer(Trainer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.carbon_tracker = EmissionsTracker(
project_name=f"hf-training-{self.args.run_name}",
country_iso_code="ITA",
save_to_file=True
)
def train(self, *args, **kwargs):
self.carbon_tracker.start()
result = super().train(*args, **kwargs)
emissions = self.carbon_tracker.stop()
self.log({"carbon_emissions_kgCO2eq": emissions})
return result
CarbonTracker: 予測と予算編成
コペンハーゲン大学によって開発された CarbonTracker は、その能力において傑出しています の プロジェクトの総消費量 最初のトレーニング期間に基づいています。 この機能は非常に貴重です。炭素コストを見積もることができます。 数日または数週間続くトレーニングを完了する前に。
# pip install carbontracker
from carbontracker.tracker import CarbonTracker
from carbontracker import parser
# Configurazione con proiezione
tracker = CarbonTracker(
epochs=100,
epochs_before_pred=5, # Dopo 5 epoche, proietta le 95 rimanenti
monitor_epochs=10, # Monitora ogni 10 epoche
log_dir="./carbontracker_logs",
update_interval=10,
verbose=2,
components="gpu",
ignore_errors=False
)
for epoch in range(100):
tracker.epoch_start()
# Training epoch
for batch in train_loader:
optimizer.zero_grad()
outputs = model(batch['input_ids'], batch['attention_mask'])
loss = criterion(outputs, batch['labels'])
loss.backward()
optimizer.step()
tracker.epoch_end()
tracker.stop()
# Dopo 5 epoche, CarbonTracker stampa proiezioni come:
# "Predicting training to use 2.34 kWh and emit 0.98 kgCO2eq"
# "Total: actual consumption: 0.12 kWh, 0.05 kgCO2eq (after 5 epochs)"
# Parsing dei log per analisi
logs = parser.parse_all_logs(log_dir="./carbontracker_logs")
for log in logs:
print(f"Energia: {log['actual']['energy (kWh)']:.3f} kWh")
print(f"CO2: {log['actual']['co2eq (g)']:.1f} gCO2eq")
print(f"Proiezione totale: {log['pred']['co2eq (g)']:.1f} gCO2eq")
ML CO₂ 影響計算ツールとグリーン アルゴリズム
ML CO₂ 影響計算ツール (mlco2.github.io) は Web ツールです これは、ハードウェア、クラウド プロバイダー、地域、期間に基づいて排出量を推定します。必要ありません コードへの統合: トレーニング前の迅速な見積もりや文書化に最適です。 トレーニングの問題はすでに完了しています。 AWS、GCP、Azure、および 15 以上のリージョンをサポートします。
グリーンアルゴリズム (green-algorithms.org)、大学によって開発されました ケンブリッジ大学、エネルギー消費モデルによるより科学的なアプローチを提供 実際のデータセンターのデータで検証されています。 HPC (ハイパフォーマンスコンピューティング) の計算をサポートし、 GPU クラスターとバイオインフォマティクス ワークフロー。
ML 炭素測定ツールの比較
| 楽器 | タイプ | 粒度 | 統合 | 強みポイント | 制限 |
|---|---|---|---|---|---|
| コードカーボン | Python ライブラリ | 機能・仕事 | PyTorch、T.F.、H.F. | リアルハードウェア測定 | Python のみ、オーバーヘッド <1% |
| カーボントラッカー | Python ライブラリ | 時代に向けて | 深層学習ループ | 早期終了上映 | エポックベースのトレーニングが必要 |
| ML CO₂ への影響 | ウェブツール | ジョブレベル | なし(Webフォーム) | ゼロセットアップ、迅速な見積り | 測定ではなく推定のみ |
| グリーンアルゴリズム | ウェブツール | ジョブレベル | なし(Webフォーム) | 科学的に検証されたモデル | リアルタイムではありません |
| 実験の影響トラッカー | Python ライブラリ | 実験 | 機械学習の実験 | 自動 MLflow ロギング | メンテナンスが最も少ない (2021) |
ダッシュボードと自動レポート
測定は、データが集約、視覚化され、測定に使用される場合にのみ価値があります。 決断。効果的なパターンは、CodeCarbon を MLflow と統合して、 排出量とパフォーマンス指標を記録する自動追跡システム。
import mlflow
from codecarbon import EmissionsTracker
import pandas as pd
from pathlib import Path
class GreenMLExperiment:
"""Wrapper che traccia automaticamente emissioni + performance ML."""
def __init__(self, experiment_name: str, country_code: str = "ITA"):
self.experiment_name = experiment_name
self.country_code = country_code
mlflow.set_experiment(experiment_name)
def run(self, model_fn, train_fn, eval_fn, params: dict):
with mlflow.start_run():
mlflow.log_params(params)
# Avvia tracker emissioni
tracker = EmissionsTracker(
project_name=self.experiment_name,
country_iso_code=self.country_code,
save_to_file=True,
output_dir="./emissions_logs"
)
tracker.start()
model = model_fn(**params)
train_metrics = train_fn(model)
emissions_kg = tracker.stop()
# Metriche performance
eval_metrics = eval_fn(model)
# Log tutto su MLflow
mlflow.log_metric("train_loss", train_metrics["loss"])
mlflow.log_metric("eval_accuracy", eval_metrics["accuracy"])
mlflow.log_metric("emissions_kgCO2eq", emissions_kg)
mlflow.log_metric("emissions_grams", emissions_kg * 1000)
mlflow.log_metric(
"accuracy_per_kgCO2",
eval_metrics["accuracy"] / max(emissions_kg, 0.001)
)
# Log artefatti
mlflow.log_artifacts("./emissions_logs")
return {
"model": model,
"emissions": emissions_kg,
"metrics": eval_metrics,
"efficiency_ratio": eval_metrics["accuracy"] / emissions_kg
}
# Utilizzo
experiment = GreenMLExperiment("bert-sentiment-v2", country_code="ITA")
result = experiment.run(
model_fn=create_bert_model,
train_fn=train_epoch,
eval_fn=evaluate_model,
params={"lr": 2e-5, "batch_size": 32, "epochs": 5}
)
GPU エネルギー効率: ワットあたりの FLOPS
ハードウェアの選択は、二酸化炭素排出量に最も影響を与える決定です トレーニングの様子。次世代 GPU は大幅に高いエネルギー効率を提供します A100 と H200 でのトレーニングの違いは、 同じワークロードで排出量が 40 ~ 60% 削減されます。
ML トレーニングの GPU の比較: エネルギー効率 (2025)
| GPU | Anno | TDP(W) | FP16 TFLOPS | FLOPS/ワット | HBMメモリ | CO₂相対 |
|---|---|---|---|---|---|---|
| A100SXM4 | 2020年 | 400W | 312 | 780 GFLOPS/W | 80GB HBM2e | ベースライン (1.0x) |
| H100SXM5 | 2022年 | 700W | 989 | 1.413 GFLOPS/W | 80GB HBM3 | 0.56x (-44%) |
| H200SXM5 | 2024年 | 700W | 989 | 1.413 GFLOPS/W | 141GB HBM3e | 0.56x (-44%) |
| B200SXM6 | 2025年 | 1,000W | 4,500 | 4,500 GFLOPS/W | 192GB HBM3e | 0.17x (-83%) |
| RTX4090 | 2022年 | 450W | 165 | 367 GFLOPS/W | 24GB GDDR6X | 2.12倍 (+112%) |
| AMD MI300X | 2024年 | 750W | 1,307 | 1.743 GFLOPS/W | 192GB HBM3 | 0.45x (-55%) |
H100 および H200 は、約 排出量を 44% 削減 尊重する FP8 とアーキテクチャを備えた Transformer Engine のおかげで、同じワークロードを A100 に提供 NVLink が最適化されました。 B200 は 4.5 PFLOPS と FP16 で世代の飛躍を表します ネイティブ FP4 サポートにより、83% に削減されます。
混合精度トレーニング: FP16 および BF16
でのトレーニング 混合精度 (計算には FP16 または BF16、計算には FP32 モデルパラメータ) はトレーニングと比較してエネルギー消費を 30 ~ 50% 削減します モデルの品質を大幅に低下させることなく、完全な FP32 を実現します。
import torch
from torch.cuda.amp import autocast, GradScaler
# Training con AMP (Automatic Mixed Precision)
scaler = GradScaler()
def train_epoch_amp(model, dataloader, optimizer, device):
model.train()
total_loss = 0.0
for batch in dataloader:
input_ids = batch['input_ids'].to(device)
labels = batch['labels'].to(device)
optimizer.zero_grad()
# Forward pass in FP16/BF16
with autocast(dtype=torch.bfloat16): # BF16 su A100/H100
outputs = model(input_ids=input_ids, labels=labels)
loss = outputs.loss
# Backward pass con gradient scaling
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
# Gradient clipping per stabilità
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
total_loss += loss.item()
return total_loss / len(dataloader)
# Con Hugging Face: basta un flag
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="./results",
bf16=True, # BF16 per A100/H100 (preferibile a FP16)
fp16=False,
dataloader_num_workers=4,
per_device_train_batch_size=32,
gradient_accumulation_steps=4, # Simula batch da 128
gradient_checkpointing=True, # -40% memoria VRAM, +20% tempo
# Risparmio energetico: meno transfer GPU-CPU
dataloader_pin_memory=True
)
# Benchmark: BERT-Large su 1M esempi
# FP32: 6.2 ore, 148 kWh, 62 kgCO2eq (ITA)
# BF16: 3.4 ore, 81 kWh, 34 kgCO2eq (ITA) -> -45% emissioni
アーキテクチャの最適化: プルーニング、蒸留、NAS
アーキテクチャ最適化技術によりモデルの複雑さが軽減され、 トレーニングの高速化、推論の効率化、二酸化炭素排出量の向上につながります。 全体的に減りました。 3 つの主要なテクニックは枝刈り、知識の蒸留です。 効率的なニューラル アーキテクチャ検索。
モデルのプルーニング: 冗長性の削除
枝刈りにより、わずかに寄与するモデルパラメータまたは構造が除去されます 正確に。主なアプローチは 2 つあります。 非構造化剪定 (個々の重量) e 構造化された剪定 (ヘッド、ニューロン、レイヤーに注意してください)。 後者は構造化されていないため、実際のハードウェア効率を考えると好ましいです。 プルーニングの効果を実際に発揮するには、サポートがまばらなハードウェアが必要です。
import torch
import torch.nn.utils.prune as prune
from transformers import BertForSequenceClassification
import numpy as np
def structured_pruning_bert(model, pruning_ratio=0.3):
"""
Pruning strutturato delle teste di attenzione BERT.
Rimuove le teste meno importanti basandosi sulla norma L1.
"""
pruned_heads = {}
for layer_idx, layer in enumerate(model.bert.encoder.layer):
# Calcola importanza di ogni testa (norma L1 dei pesi query)
attention = layer.attention.self
num_heads = attention.num_attention_heads
head_size = attention.attention_head_size
query_weights = attention.query.weight.data # shape: [hidden, hidden]
query_reshaped = query_weights.view(num_heads, head_size, -1)
head_importance = query_reshaped.abs().mean(dim=[1, 2])
# Seleziona le teste da prunable
num_heads_to_prune = int(num_heads * pruning_ratio)
heads_to_prune = head_importance.argsort()[:num_heads_to_prune].tolist()
if heads_to_prune:
pruned_heads[layer_idx] = set(heads_to_prune)
model.prune_heads(pruned_heads)
return model, pruned_heads
# Unstructured pruning con PyTorch
def magnitude_pruning(model, sparsity=0.5):
"""Pruning per magnitudine su tutti i layer Linear."""
parameters_to_prune = [
(module, 'weight')
for module in model.modules()
if isinstance(module, torch.nn.Linear)
]
prune.global_unstructured(
parameters_to_prune,
pruning_method=prune.L1Unstructured,
amount=sparsity
)
# Rende il pruning permanente
for module, param in parameters_to_prune:
prune.remove(module, param)
return model
# Risultati tipici su BERT-Base (110M parametri):
# Pruning 30% teste: -28% latenza inferenza, -1.2% accuracy
# Pruning 50% pesi (magnitude): -45% dimensione, -0.8% accuracy
# Emissioni inferenza: -30% con structured pruning
知識の蒸留: 大きな知識を備えた小さなモデル
知識の蒸留により、1 つの大きなモデル (教師) から別の大きなモデルに知識が転送されます。 小さい(学生)。たとえば、DistilBERT には BERT-Base のパラメータの 40% が含まれていますが、 は、GLUE ベンチマークでパフォーマンスの 97% を維持します。トレーニングの排出量 DistilBERT は 60% 低く、推論のものは 40 ~ 50% 低くなります。
import torch
import torch.nn as nn
import torch.nn.functional as F
class DistillationLoss(nn.Module):
"""
Loss combinata per knowledge distillation:
L = alpha * L_CE(student, labels) + (1-alpha) * L_KL(student, teacher)
"""
def __init__(self, alpha=0.5, temperature=4.0):
super().__init__()
self.alpha = alpha
self.temperature = temperature
self.ce_loss = nn.CrossEntropyLoss()
def forward(self, student_logits, teacher_logits, labels):
# Loss classificazione standard
loss_ce = self.ce_loss(student_logits, labels)
# Loss distillazione (KL divergence con temperature scaling)
student_soft = F.log_softmax(student_logits / self.temperature, dim=-1)
teacher_soft = F.softmax(teacher_logits / self.temperature, dim=-1)
loss_kl = F.kl_div(student_soft, teacher_soft, reduction='batchmean')
loss_kl *= self.temperature ** 2 # Scala per compensare la temperature
return self.alpha * loss_ce + (1 - self.alpha) * loss_kl
def distill_model(teacher_model, student_model, train_loader,
optimizer, device, epochs=5):
"""Training loop completo per knowledge distillation."""
distill_loss = DistillationLoss(alpha=0.5, temperature=4.0)
teacher_model.eval()
for epoch in range(epochs):
student_model.train()
total_loss = 0.0
for batch in train_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
# Teacher inference (no gradient)
with torch.no_grad():
teacher_outputs = teacher_model(
input_ids=input_ids,
attention_mask=attention_mask
)
# Student forward pass
student_outputs = student_model(
input_ids=input_ids,
attention_mask=attention_mask
)
loss = distill_loss(
student_outputs.logits,
teacher_outputs.logits,
labels
)
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch+1}: Loss = {total_loss/len(train_loader):.4f}")
# Caso d'uso tipico: distillare BERT-Large (340M) -> BERT-Tiny (14M)
# Training: 8h vs 2.5h -> -69% tempo
# Emissioni training: -71%
# Accuracy GLUE: 84.6 vs 87.2 -> -3% accettabile per la maggior parte dei task
効率的なニューラル アーキテクチャの検索
従来の NAS は皮肉なことに、最もエネルギーを大量に消費するプロセスの 1 つです ML: 最適なアーキテクチャを検索するには、何千もの完全なトレーニング セッションが必要になる場合があります。 の 効率的なNAS ワンショット NAS、ウェイト シェアリングなどの技術を使用します 予測子ベースの検索により、検索コストが 99% 削減されます。
# Esempio con Once-for-All Network (OFA) da MIT
# OFA addestra una volta una supernetwork, poi campiona subnetwork efficienti
# Installazione: pip install ofa
from ofa.model_zoo import ofa_net
# Carica supernetwork pre-addestrata (una volta sola)
ofa_network = ofa_net('ofa_resnet50', pretrained=True)
# Campiona subnetwork che rispettano constraint energetici
# senza riaddestrare (zero-cost NAS)
def find_efficient_subnet(ofa_net, target_flops: float = 200e6):
"""
Cerca una subnetwork con FLOPs < target_flops
usando evolutionary search con predictor di accuracy.
"""
from ofa.nas.search_algorithm import EvolutionFinder
finder = EvolutionFinder(
constraint_type='flops',
efficiency_constraint=target_flops,
efficiency_predictor=ofa_net.flops_counter,
accuracy_predictor=None, # Usa validazione reale
population_size=100,
max_time_budget=500,
parent_ratio=0.25,
mutation_ratio=0.5
)
best_valset_acc, best_info = finder.run_evolution_search()
return best_info['net_config']
# Risultato tipico:
# Supernetwork ResNet-50: 4.1 GFLOPs, 25.6M param
# Subnetwork trovata: 200 MFLOPs, 6.2M param
# Accuracy ImageNet: 77.8% vs 79.2% (- 1.4%, - 95% emissioni inferenza)
データ中心の効率性: 質と量
より高品質のデータセットにより、同じ精度を達成できます トレーニング エポックとデータが少なくなります。これは原則の 1 つです データ中心のAI Andrew Ng が推進: モデルを増やす代わりに または生データを使用して、既存のデータの品質を向上させます。
カリキュラム学習: 正しい順序でトレーニングする
学習カリキュラムは、難易度を上げることでトレーニング例を順序付けします。 複雑な概念に進む前に、単純な概念から始める教師のようなものです。 このアプローチはより速く、より少ない合計エポックで収束するため、 標準ベンチマークでは二酸化炭素排出量は 20 ~ 35% です。
import numpy as np
from torch.utils.data import DataLoader, SubsetRandomSampler
from sklearn.metrics import pairwise_distances
class CurriculumScheduler:
"""
Curriculum Learning: ordina il dataset dalla difficolta' crescente.
La difficolta' e' calcolata come distanza dalla media della classe.
"""
def __init__(self, dataset, difficulty_metric='loss', num_stages=4):
self.dataset = dataset
self.num_stages = num_stages
self.difficulty_scores = None
def compute_difficulty(self, model, device):
"""Calcola difficolta' come loss su un modello pre-addestrato leggero."""
model.eval()
scores = []
loader = DataLoader(self.dataset, batch_size=256, shuffle=False)
criterion = nn.CrossEntropyLoss(reduction='none')
with torch.no_grad():
for batch in loader:
input_ids = batch['input_ids'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids=input_ids)
losses = criterion(outputs.logits, labels)
scores.extend(losses.cpu().numpy())
self.difficulty_scores = np.array(scores)
return self.difficulty_scores
def get_stage_indices(self, stage: int) -> list:
"""Ritorna gli indici degli esempi per lo stage corrente."""
if self.difficulty_scores is None:
raise ValueError("Esegui compute_difficulty prima.")
# Divide il dataset in quartili di difficolta'
sorted_indices = np.argsort(self.difficulty_scores)
stage_size = len(sorted_indices) // self.num_stages
# Stage 0: esempi più' facili, Stage N: tutti gli esempi
max_idx = stage_size * (stage + 1)
return sorted_indices[:max_idx].tolist()
def curriculum_training(model, dataset, optimizer, device, total_epochs=20):
"""Training con curriculum progressivo."""
scheduler = CurriculumScheduler(dataset, num_stages=4)
# Usa un modello leggero per calcolare la difficolta'
tiny_model = load_tiny_model().to(device)
difficulty = scheduler.compute_difficulty(tiny_model, device)
for epoch in range(total_epochs):
# Progressione lineare: da 25% a 100% del dataset
stage = min(3, int(epoch / total_epochs * 4))
indices = scheduler.get_stage_indices(stage)
sampler = SubsetRandomSampler(indices)
loader = DataLoader(dataset, batch_size=32, sampler=sampler)
print(f"Epoch {epoch}: usando {len(indices)}/{len(dataset)} esempi")
train_one_epoch(model, loader, optimizer, device)
# Risultati tipici:
# Training standard BERT-Base: 10 epoche per convergenza
# Training con curriculum: 6.5 epoche -> -35% emissioni
アクティブ ラーニング: 最も有益なデータを選択する
アクティブ ラーニングでは、ラベルを付ける最も有益な例を繰り返し選択します。 データセット全体を使用する代わりに。アノテーション予算 10 ~ 20% で達成されます。 多くの場合、フルデータ トレーニングの精度は 90 ~ 95% ですが、それに比例して低下します。 二酸化炭素排出量。
from sklearn.cluster import KMeans
import torch.nn.functional as F
class ActiveLearningSelector:
"""Seleziona esempi con massima incertezza (uncertainty sampling)."""
def __init__(self, model, unlabeled_pool, strategy='entropy'):
self.model = model
self.unlabeled_pool = unlabeled_pool
self.strategy = strategy
def compute_uncertainty(self, batch_size=128) -> np.ndarray:
"""Calcola incertezza del modello su ogni esempio non etichettato."""
self.model.eval()
uncertainties = []
loader = DataLoader(self.unlabeled_pool, batch_size=batch_size)
with torch.no_grad():
for batch in loader:
logits = self.model(batch['input_ids']).logits
probs = F.softmax(logits, dim=-1)
if self.strategy == 'entropy':
# Entropia: massima quando la distribuzione e' uniforme
entropy = -(probs * probs.log()).sum(dim=-1)
uncertainties.extend(entropy.cpu().numpy())
elif self.strategy == 'margin':
# Margin: minimo quando le top-2 prob sono simili
top2 = probs.topk(2, dim=-1).values
margin = top2[:, 0] - top2[:, 1]
uncertainties.extend((1 - margin).cpu().numpy())
return np.array(uncertainties)
def select_examples(self, n_select: int) -> list:
"""Seleziona i n_select esempi più' incerti."""
uncertainties = self.compute_uncertainty()
top_indices = np.argsort(uncertainties)[-n_select:]
return top_indices.tolist()
# Workflow Active Learning
def active_learning_loop(
model, labeled_data, unlabeled_pool,
annotation_budget=500, iterations=5
):
per_iteration = annotation_budget // iterations
for iteration in range(iterations):
# Seleziona esempi
selector = ActiveLearningSelector(model, unlabeled_pool)
selected_idx = selector.select_examples(per_iteration)
# Simula annotazione (in produzione: etichettatura umana)
new_labeled = [unlabeled_pool[i] for i in selected_idx]
labeled_data.extend(new_labeled)
# Riaddestra su dati aggiornati
model = fine_tune(model, labeled_data)
acc = evaluate(model)
print(f"Iter {iteration}: {len(labeled_data)} esempi, acc={acc:.3f}")
return model
# Con 500 esempi attivi vs 5000 casuali: stesso livello di accuracy
# Risparmio training: -90% dati -> -85% emissioni
カーボンを意識したトレーニング: トレーニングをインテリジェントにスケジュール設定する
Carbon Aware トレーニングは、Carbon Aware SDK の原則を適用したものです ML の世界へ: エンジニアが設定を終えてからトレーニングを開始するのではなく 実験では、最も低い時間と地域でジョブをスケジュールします。 電力構成の炭素強度。
タイムシフト: グリーントレーニング時
エネルギーの炭素強度は 1 日を通して大きく変化します 再生可能エネルギーの利用可能状況に応じて、週ごとに異なります。イタリアでは、 最も緑が多い時間帯(夏季は11:00~15:00)と最も緑が多い時間帯との差 石炭(冬期は午後 7 時から午後 10 時まで)は 200 ~ 300 gCO₂eq/kWh になることがあります。
import asyncio
import httpx
from datetime import datetime, timedelta
from typing import Optional
import subprocess
ELECTRICITY_MAPS_TOKEN = "YOUR_TOKEN" # electricitymaps.com/api
async def get_carbon_intensity(zone: str = "IT") -> float:
"""Recupera l'intensità' carbonica attuale dalla Electricity Maps API."""
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://api.electricitymap.org/v3/carbon-intensity/latest",
params={"zone": zone},
headers={"auth-token": ELECTRICITY_MAPS_TOKEN}
)
data = resp.json()
return data["carbonIntensity"] # gCO2eq/kWh
async def get_forecast(zone: str = "IT", hours: int = 24) -> list[dict]:
"""Recupera le previsioni di intensità' carbonica per le prossime ore."""
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://api.electricitymap.org/v3/carbon-intensity/forecast",
params={"zone": zone},
headers={"auth-token": ELECTRICITY_MAPS_TOKEN}
)
data = resp.json()
return data["forecast"][:hours]
async def find_optimal_training_window(
job_duration_hours: float,
zone: str = "IT",
max_delay_hours: int = 24
) -> Optional[datetime]:
"""
Trova la finestra temporale ottimale per un training job.
Cerca il window di 'job_duration_hours' con intensità' media minima.
"""
forecast = await get_forecast(zone, hours=max_delay_hours + int(job_duration_hours))
if not forecast:
return None
window_size = max(1, int(job_duration_hours))
best_start = None
best_avg_intensity = float('inf')
for i in range(len(forecast) - window_size + 1):
window = forecast[i:i + window_size]
avg_intensity = sum(h['carbonIntensity'] for h in window) / len(window)
if avg_intensity < best_avg_intensity:
best_avg_intensity = avg_intensity
best_start = datetime.fromisoformat(forecast[i]['datetime'])
print(f"Finestra ottimale: {best_start}")
print(f"Intensità' media: {best_avg_intensity:.1f} gCO2eq/kWh")
return best_start
async def carbon_aware_submit(
training_command: str,
job_duration_hours: float = 6.0,
threshold_gco2_kwh: float = 200.0,
zone: str = "IT"
):
"""
Submette un training job solo quando l'intensità' e' sotto soglia,
altrimenti aspetta la finestra ottimale.
"""
current = await get_carbon_intensity(zone)
if current <= threshold_gco2_kwh:
print(f"Intensità' attuale {current} gCO2/kWh: avvio immediato")
subprocess.Popen(training_command.split())
return
print(f"Intensità' troppo alta ({current} gCO2/kWh > {threshold_gco2_kwh})")
optimal_window = await find_optimal_training_window(
job_duration_hours, zone
)
if optimal_window:
wait_seconds = (optimal_window - datetime.now()).total_seconds()
print(f"Scheduling per {optimal_window} (attesa: {wait_seconds/3600:.1f}h)")
await asyncio.sleep(max(0, wait_seconds))
subprocess.Popen(training_command.split())
# Utilizzo
asyncio.run(carbon_aware_submit(
training_command="python train_bert.py --epochs 10",
job_duration_hours=8.0,
threshold_gco2_kwh=150.0,
zone="IT"
))
空間シフト: 最もグリーンなクラウド領域を選択する
さまざまなクラウド プロバイダーが、非常に異なるエネルギー ミックスを地域に提供しています。 訓練地域を選択すると排出量を 70 ~ 90% 削減できる ランダムな選択と比較して。
雲領域別の平均炭素強度 (2024-2025)
| プロバイダー | 地域 | 位置 | gCO₂eq/kWh | 注意事項 |
|---|---|---|---|---|
| GCP | ヨーロッパ北部1 | フィンランド | ~35 | 水力発電 + 風力発電 |
| AWS | eu-north-1 | ストックホルム | ~40 | ほぼ100%再生可能 |
| GCP | ヨーロッパ西部1 | ベルギー | ~56 | 再生可能エネルギーと原子力の組み合わせ |
| アズール | フランス中央 | パリ | ~58 | 核支配的 |
| AWS | EU-西-1 | アイルランド | ~250 | 天然ガスが普及している |
| AWS | 米国東部-1 | バージニア州 | ~296 | 中東アメリカミックス |
| AWS | ap-南東-1 | シンガポール | ~408 | 天然ガス |
# Spot Instances per training carbon-aware
# Le spot instance non solo riducono i costi del 60-90%,
# ma tendono a essere distribuite su hardware più' recente ed efficiente
import boto3
from botocore.exceptions import ClientError
def submit_spot_training(
image_uri: str,
instance_type: str = "p4d.24xlarge", # 8x A100
region: str = "eu-north-1", # Stoccolma: ~40 gCO2/kWh
max_price_per_hour: float = 15.0
):
"""Submette un training job su spot instances AWS SageMaker."""
sagemaker = boto3.client('sagemaker', region_name=region)
response = sagemaker.create_training_job(
TrainingJobName=f"green-ml-{int(datetime.now().timestamp())}",
AlgorithmSpecification={
'TrainingImage': image_uri,
'TrainingInputMode': 'FastFile'
},
ResourceConfig={
'InstanceType': instance_type,
'InstanceCount': 1,
'VolumeSizeInGB': 100
},
# Managed Spot Training
EnableManagedSpotTraining=True,
StoppingCondition={
'MaxRuntimeInSeconds': 86400, # 24 ore max
'MaxWaitTimeInSeconds': 172800 # Aspetta fino a 48 ore
},
# Checkpointing per riprendere se lo spot viene interrotto
CheckpointConfig={
'S3Uri': f's3://my-bucket/checkpoints/',
'LocalPath': '/opt/ml/checkpoints'
}
)
return response['TrainingJobArn']
# Confronto costi e emissioni:
# p4d.24xlarge on-demand (us-east-1): $32.77/h, 296 gCO2/kWh
# p4d.24xlarge spot (eu-north-1): $9.83/h, 40 gCO2/kWh
# Risparmio economico: -70%
# Risparmio emissioni: -86% (spot + regione verde)
推論の最適化: 二酸化炭素排出量の 77%
予想通り、生産における推論が製品のライフサイクルにおける排出量の大半を占めます。 ML モデル。数百万のユーザーがいるモデルの場合、1 ミリ秒ごとの遅延が短縮されました そして、消費量が 1 ワット削減されるごとに、年間数十億のリクエストが増加します。 主な手法は、量子化、モデルのコンパイル、最適化されたバッチ処理です。
量子化: INT8、INT4、GPTQ
量子化により、モデルの重みの数値精度が FP32 または FP16 から低下します。 8 または 4 ビット整数に変換します。これにより、メモリ要件が 50 ~ 75% 削減され、推論が高速化されます。 2 ~ 4 倍になり、エネルギー消費もそれに比例して削減されます。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch
# Quantizzazione INT4 con GPTQ (post-training quantization)
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True, # QLoRA: double quantization
bnb_4bit_quant_type="nf4" # Normal Float 4: migliore qualità'
)
model_id = "meta-llama/Llama-2-7b-hf"
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=quantization_config,
device_map="auto",
torch_dtype=torch.bfloat16
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
# Verifica riduzione memoria
original_size_gb = 7 * 2 / 1024 # 7B param x 2 byte (FP16) / 1024
quantized_size_gb = 7 * 0.5 / 1024 # 7B param x 0.5 byte (INT4) / 1024
print(f"FP16: {original_size_gb:.1f} GB")
print(f"INT4: {quantized_size_gb:.1f} GB (-{(1-quantized_size_gb/original_size_gb)*100:.0f}%)")
# Quantizzazione INT8 con ONNX Runtime (per produzione)
from optimum.onnxruntime import ORTModelForSequenceClassification
from optimum.onnxruntime.configuration import AutoQuantizationConfig
# Esporta in ONNX e quantizza
ort_model = ORTModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
export=True
)
quantization_config = AutoQuantizationConfig.avx512_vnni(
is_static=False, # Dynamic quantization (no calibration data needed)
per_channel=False
)
# Salva il modello quantizzato
from optimum.onnxruntime import ORTQuantizer
quantizer = ORTQuantizer.from_pretrained(ort_model)
quantizer.quantize(
save_dir="./bert-int8-onnx",
quantization_config=quantization_config
)
# Benchmark:
# BERT-Base FP32: 23ms latenza, 100% accuracy, 1.6 GB
# BERT-Base INT8: 12ms latenza, 99.2% accuracy, 0.4 GB -> -48% energia
# BERT-Base INT4: 8ms latenza, 97.8% accuracy, 0.2 GB -> -65% energia
vLLM: LLM の効率的なサービス提供
vLLM これは、LLM のサービス提供フレームワークであり、 ページ化された注意 KV キャッシュをより効率的に管理します。素朴な盛り付けに比べて、 vLLM は、同じハードウェアでスループットを 15 ~ 24 倍向上させ、それに比例してスループットを低下させます 生成されたトークンごとのエネルギー消費量。
from vllm import LLM, SamplingParams
from codecarbon import EmissionsTracker
# Avvia LLM con vLLM (PagedAttention + continuous batching)
llm = LLM(
model="meta-llama/Llama-2-7b-chat-hf",
tensor_parallel_size=1, # GPU count
gpu_memory_utilization=0.90, # Usa il 90% della VRAM per KV cache
max_num_batched_tokens=32768, # Batch maggiori = più' efficiente
quantization="awq" # AWQ quantization integrata
)
sampling_params = SamplingParams(
temperature=0.7,
max_tokens=256
)
# Misura emissioni per 1000 richieste
tracker = EmissionsTracker(project_name="vllm-inference-benchmark")
tracker.start()
prompts = ["Spiega il concetto di machine learning in italiano"] * 1000
outputs = llm.generate(prompts, sampling_params)
emissions = tracker.stop()
tokens_generated = sum(len(o.outputs[0].token_ids) for o in outputs)
print(f"Token generati: {tokens_generated:,}")
print(f"Emissioni: {emissions*1000:.2f} gCO2eq")
print(f"gCO2eq per 1000 token: {emissions*1000/tokens_generated*1000:.4f}")
# Confronto con serving naive HuggingFace:
# HuggingFace Transformers: 1.000 req, 45 min, 890 gCO2eq
# vLLM: 1.000 req, 3 min, 59 gCO2eq (-93%)
# Throughput: 333 req/min vs 22 req/min
ML モデルの SCI スコア: 測定の標準化
仕様 SCI (炭素強度ソフトウェア) グリーン ソフトウェア財団の、 現在標準 ISO/IEC 21031:2024 は ML システムにも適用されます。 SCI は排出量を表します 機能単位ごとに表示されるため、異なるモデル間で有意義な比較が可能になります。
ML システムに適用される SCI 式
| 成分 | ML公式 | BERT推論の例 |
|---|---|---|
| E (エネルギー) | GPU パワー x 時間 / 1000 | 300W x 0.05秒 / 1000 = 0.000015 kWh |
| I (炭素強度) | 地域の gCO₂eq/kWh | 420 gCO₂eq/kWh (イタリア平均) |
| M (具現化) | ハードウェア CO₂ / (寿命 x 使用量) | 150,000 gCO₂ / (26,280h x 0.7) = 8.2 g/h |
| R (機能単位) | 1,000 回の推論または 1 つのトークン生成 | 1,000分類 |
| スキー | (E×I+M)/R | (0.015 x 0.420 + 0.00023) / 1 = 0.0065 gCO₂eq/req |
from dataclasses import dataclass
from typing import Literal
@dataclass
class MLSystemSCI:
"""Calcola SCI Score per sistemi ML."""
model_name: str
gpu_count: int
gpu_tdp_watts: float
avg_latency_ms: float # Per inferenza singola
carbon_intensity_g_kwh: float # gCO2/kWh regione
gpu_lifespan_hours: float = 26_280 # 3 anni
gpu_embodied_gco2: float = 150_000 # ~150 kgCO2 per GPU
utilization: float = 0.70
pue: float = 1.3
functional_unit: Literal['request', 'token'] = 'request'
def operational_energy_kwh(self) -> float:
"""Energia operativa per singola inferenza."""
return (
self.gpu_count
* self.gpu_tdp_watts
* (self.avg_latency_ms / 1000)
/ 1_000 # W -> kW
)
def operational_emissions_g(self) -> float:
"""Emissioni operative per singola inferenza (gCO2eq)."""
return (
self.operational_energy_kwh()
* self.carbon_intensity_g_kwh
* self.pue
)
def embodied_per_request_g(self) -> float:
"""Quota embodied per singola inferenza."""
# Secondi per richiesta / secondi per vita GPU
fraction_of_life = (self.avg_latency_ms / 1000) / (
self.gpu_lifespan_hours * 3600
)
total_embodied = self.gpu_count * self.gpu_embodied_gco2
return total_embodied * fraction_of_life / self.utilization
@property
def sci_score(self) -> float:
"""SCI = (E x I + M) / R per singola richiesta."""
return self.operational_emissions_g() + self.embodied_per_request_g()
# Confronto modelli
models = [
MLSystemSCI("BERT-Base INT8/CPU", 0, 100, 45, 420, gpu_count=0,
gpu_embodied_gco2=0),
MLSystemSCI("BERT-Base FP32/A100", 1, 400, 12, 420),
MLSystemSCI("BERT-Base INT8/A100", 1, 280, 6, 420),
MLSystemSCI("DistilBERT FP16/A100", 1, 240, 5, 420),
MLSystemSCI("BERT-Base INT8/eu-north-1", 1, 280, 6, 40), # Stoccolma
]
print(f"{'Modello':<35} {'SCI (gCO2/req)':<18} {'vs Baseline'}")
baseline = models[0].sci_score
for m in models:
sci = m.sci_score
ratio = sci / baseline
print(f"{m.model_name:<35} {sci:.6f} gCO2 {ratio:.2f}x")
グリーン AI リーダーボード: 精度よりも効率
GLUE、SuperGLUE、MMLU などの従来のリーダーボードは精度のみを測定します。 の概念 グリーン AI リーダーボード、Schwartzらによって提案されました。 (2020年) 2024 年に GSF によって正式化され、バランスのとれた複合指標が導入されています。 パフォーマンスと炭素効率。
グリーン AI メトリクス: 精度と排出量のトレードオフ (GLUE ベンチマーク)
| モデル | グルースコア | CO₂eq トレイン (t) | CO₂eq 推定値 (mg/req) | グリーンスコア* |
|---|---|---|---|---|
| BERTベース | 82.1 | 0.9 | 0.62 | 132 |
| RoBERTa-Base | 86.4 | 4.1 | 0.62 | 139 |
| 蒸留BERT | 77.0 | 0.35 | 0.31 | 248 |
| BERTベースINT8 | 81.3 | 0.9 | 0.28 | 290 |
| モバイルBERT | 78.2 | 0.6 | 0.18 | 434 |
| ALBERT ベース v2 | 82.3 | 0.5 | 0.42 | 196 |
* グリーンスコア = (GLUE スコア / CO₂eq 推論) x 1000。値が高いほど効率が高くなります。
GLUE スコアが BERT-Base より 6% 低いにもかかわらず、DistilBERT がどのように機能するかに注目してください。 ほぼ 2 倍のグリーン スコアを持っています。 MobileBERT はリスト内で最高のグリーン スコアを提供します。 これは、炭素予算が限られている大規模な導入に最適な選択肢となります。
ケーススタディ: NLP モデルで排出量を 60% 削減
このケーススタディでは、モデルに適用される現実世界の最適化パスについて説明します。 企業向けに開発された、イタリア市場向けのセンチメント分類 毎月 200 万件のレビューを処理する電子商取引の割合。
ベースライン: 初期状態
# STATO INIZIALE (Baseline)
# Modello: bert-base-multilingual-cased (177M parametri)
# Hardware: 1x NVIDIA A100 80GB SXM4 (on-demand AWS us-east-1)
# Task: classificazione sentiment 5 classi (1-5 stelle)
# Dataset: 500.000 recensioni in italiano
# Metriche baseline:
Training_time_hours = 18.5
Energy_training_kWh = 130.0 # A100 SXM4: ~400W TDP, PUE=1.5
CO2_training_kgCO2eq = 38.5 # 130 kWh x 0.296 kgCO2/kWh (us-east-1)
Inference_latency_ms = 35.0 # Per singola recensione
Inference_throughput_req_s = 28.6
CO2_inference_per_1M_req = 2.85 # kgCO2eq
Monthly_inference_requests = 2_000_000
Monthly_inference_CO2_kg = 5.70
Annual_training_runs = 4 # Re-training trimestrale
Annual_total_CO2_kg = (4 * 38.5) + (12 * 5.70) = 222.4
Accuracy_f1_macro = 0.847
段階的な最適化
# STEP 1: Cambio regione cloud (us-east-1 -> eu-north-1)
# Carbon intensity: 296 -> 40 gCO2/kWh (-86%)
# Nessun cambiamento al codice, solo flag AWS Region
CO2_training_kgCO2eq_step1 = 130.0 * 0.040 * 1.5 = 7.8 # -80%
Monthly_inference_CO2_step1 = 2.85 * (40/296) = 0.38 # -87%
Annual_CO2_step1 = (4 * 7.8) + (12 * 0.38) = 35.7 kg # -84%
# STEP 2: Cambio modello base (multilingual -> umberto italiano)
# umberto-commoncrawl-cased (bert-base size ma solo italiano)
# Dataset training ridotto del 30% (solo dati italiani puliti)
# Curriculum learning: 15 epoche vs 20 -> -25% training time
CO2_training_kgCO2eq_step2 = 7.8 * 0.75 * 0.70 = 4.1 # -47% su step1
Accuracy_f1_macro_step2 = 0.861 # +1.4% grazie a modello specializzato
# STEP 3: Quantizzazione INT8 (ONNX Runtime)
# Latenza inferenza: 35ms -> 18ms (-49%)
# Throughput: 28.6 -> 55.5 req/s (+94%)
Inference_latency_ms_step3 = 18.0
Monthly_inference_CO2_step3 = 0.38 * 0.50 = 0.19 # -50%
Accuracy_f1_macro_step3 = 0.856 # -0.5% accettabile
# STEP 4: Carbon-aware scheduling del re-training
# Spot instances + finestre energetiche verdi
# Costo spot eu-north-1: -70% vs on-demand
# Timing training nelle ore di massima rinnovabile
CO2_training_kgCO2eq_step4 = 4.1 * 0.85 = 3.5 # Spot: stesso hardware, timing migliore
# RIEPILOGO OTTIMIZZAZIONI
print("=" * 60)
print(f"Baseline: {222.4:.1f} kgCO2eq/anno | F1: 0.847")
print(f"Step 1: {35.7:.1f} kgCO2eq/anno | -84% (solo regione)")
print(f"Step 2: {26.9:.1f} kgCO2eq/anno | -87% (modello+data)")
print(f"Step 3: {21.7:.1f} kgCO2eq/anno | -90% (quantizzazione)")
print(f"Step 4: {18.6:.1f} kgCO2eq/anno | -92% (carbon-aware)")
print(f"F1 finale: 0.856 vs 0.847 baseline (+1.1%)")
print("=" * 60)
print(f"Riduzione CO2: -203.8 kgCO2eq/anno (-91.6%)")
print(f"Risparmio costi: -74% (spot + regione + efficienza)")
ケーススタディの結果: 概要
| メトリック | ベースライン | 最適化された | 変化 |
|---|---|---|---|
| 年間総 CO₂eq | 222kgCO₂eq | 19kgCO₂当量 | -91% |
| F1 スコア マクロ | 0.847 | 0.856 | +1.1% |
| 推論レイテンシ | 35ミリ秒 | 18ミリ秒 | -49% |
| スループット | 28 リクエスト/秒 | 55 リクエスト/秒 | +96% |
| 月額クラウド費用 | ~2,400ユーロ | ~620ユーロ | -74% |
重要な教訓: 精度を犠牲にすることなく排出量の 90% を削減
このケーススタディでは、各最適化ステップには次のものがあります。 改善された またはモデルの精度を維持します。保存されたクラウド領域の選択 コード行に一切触れずに排出量の 84% を達成。の専門化 イタリア語のテンプレートの品質が向上しました。量子化 レイテンシーが半分になりました。メッセージは明確です: 炭素を最適化する フットプリントと品質の最適化は矛盾する目標ではありません。
組織向けのグリーン AI ロードマップ
グリーン AI を導入するには、すぐにすべてを変革する必要はありません。ロードマップ 3 つのフェーズに分かれているため、次から始めて段階的にプラクティスを導入できます。 より少ない労力でより大きな効果をもたらす最適化。
3 段階のグリーン AI 導入ロードマップ
| 段階 | タイムライン | アクション | CO₂削減効果が期待できる |
|---|---|---|---|
| ステップ 1: 測定する | 1~4週目 |
すべてのトレーニング ジョブに CodeCarbon をインストールします。 モデルごとに排出ベースラインを定義します。 より環境に優しい雲領域を選択する |
50~85% (地域のみ) |
| ステップ 2: 最適化する | 2~4ヶ月目 |
すべてのトレーニングに混合精度 (BF16) を適用します。 本番環境でモデルを量子化します (INT8)。 バッチトレーニングにスポットインスタンスを採用する |
追加の 30 ~ 50% |
| フェーズ 3: 統合 | 月 5 ~ 12 |
二酸化炭素を意識した自動スケジューリング。 社内のグリーン AI リーダーボード。 導入基準における SCI スコア。 ESGレポートのML排出量 |
追加の 10 ~ 20% |
各トレーニング ジョブのグリーン AI チェックリスト
# Checklist Green AI da seguire prima di ogni training
# Copia in: .github/PULL_REQUEST_TEMPLATE.md o come commento training script
CHECKLIST_GREEN_AI = """
Green AI Pre-Training Checklist
================================
[ ] 1. REGIONE: Training schedulato in regione con CI < 150 gCO2/kWh?
Verifica: https://app.electricitymaps.com/zone/IT
Preferisci: GCP europe-north1, AWS eu-north-1, Azure swedencentral
[ ] 2. TIMING: Carbon-aware scheduling attivato?
Tool: Carbon Aware SDK o script custom
Finestra ottimale: verificata nelle ultime 24h
[ ] 3. HARDWARE: GPU di ultima generazione disponibile?
H100 >> A100 (44% più' efficiente)
Spot/preemptible instances preferite
[ ] 4. PRECISION: Mixed precision attivata (BF16/FP16)?
HuggingFace: bf16=True in TrainingArguments
PyTorch: torch.autocast('cuda', dtype=torch.bfloat16)
[ ] 5. EARLY STOPPING: Configurato con CarbonTracker per proiezione?
Stima emissioni dopo 5 epoche e confronta con budget CO2
[ ] 6. TRACKING: CodeCarbon configurato?
Country_iso_code, cloud_provider, cloud_region impostati
Output in: ./carbon_reports/
[ ] 7. DATI: Dataset ottimizzato con deduplication e qualità'?
Almeno 10% redundancy rimossa
Active learning per ridurre dimensione se possibile
[ ] 8. BASELINE: Esiste una run precedente da confrontare?
Registra su MLflow: accuracy, emissioni, ratio
[ ] 9. INFERENZA: Quantizzazione pianificata per produzione?
Target: INT8 con ONNX Runtime o INT4 per LLM
[ ] 10. REPORTING: Emissioni saranno incluse nel model card?
Usa: SCI Score, kgCO2eq training, gCO2eq/1000 req inferenza
"""
print(CHECKLIST_GREEN_AI)
結論: グリーン ソフトウェア エンジニアリング シリーズの概要
この記事でシリーズは終了です グリーン ソフトウェア エンジニアリング、 実践の全領域を横断する 10 の記事からなる旅 持続可能なソフトウェア開発。 GSF 原則の理論から実装まで CodeCarbon、Carbon Aware SDK、Climatiq API を使用した実践、テクニックまで 高度な ML 最適化: 包括的なツールキットを構築しました。 デジタル環境への影響を軽減したい開発者や組織。
シリーズの 10 の重要なメッセージ
| # | アイテム | 重要なメッセージ |
|---|---|---|
| 1 | GSF 原則 | 炭素効率はソフトウェア品質の指標です |
| 2 | コードカーボン | 測定しないものを減らすことはできません: 1 日目から始めましょう |
| 3 | Climatiq API | CO₂ には API があります: 炭素会計をバックエンドに統合します |
| 4 | カーボンアウェア SDK | ワークロードを時間的またはスペース的に移動すると、90% 削減できる |
| 5 | スコープモデリング | SCI はソフトウェアの炭素効率を比較するための ISO 規格です。 |
| 6 | グリーンオプス | Green と FinOps の連携: CO₂ の最適化によりクラウド コストを削減 |
| 7 | スコープ 3 パイプライン | 間接排出は直接排出よりも多くなる場合が多い |
| 8 | ESGとCSRD | 2025 年から、デジタル ESG 報告は多くの企業にとって法的義務となります |
| 9 | 持続可能なパターン | キャッシュ、バッチ、非同期は単なるパフォーマンスではなく、グリーン パターンです |
| 10 | AIカーボン | クラウド リージョンを選択すると、どのアルゴリズムよりも ML 排出量が削減されます。 |
その瞬間は今です
生成 AI は今後も成長し続けます。模型も大きくなるし、 トレーニングの頻度が高くなるほど、導入がより広範囲に行われます。質問はそうではありません AI の排出量が増加するとしても、いずれにせよ増加するでしょうが、どの程度増加するのか。 この記事の手法は、60 ~ 90% を削減できることを示しています。 精度を犠牲にすることなく、さらには削減することさえある ML システムのエミッション 費用。これは妥協ではなく、あらゆる面での勝利です。
Green Software Foundation は、すべての ML チームが次のプラクティスを採用した場合、 炭素を意識したトレーニングと推論の定量化、部門の世界的な排出量 AI を削減できる可能性があるのは、 2030年までに40~60% シナリオと比べて いつも通り。技術的なブレークスルーは必要ありません。記載されている実践が必要です。 これら 10 条を体系的に適用してください。
次のステップはあなたのものです。次のトレーニング ジョブに CodeCarbon をインストールします。 AWS または GCP リージョンの炭素強度を確認します。クオンタイズ デプロイ前のモデル。 SCI スコアを測定します。そして、そうするとき、 あなたは最も重要なステップ、すなわち「始める」を踏み出したことになるでしょう。
便利なリンクとツール
- コードカーボン: mlco2.github.io/codecarbon
- ML CO₂ 影響計算ツール: mlco2.github.io/impact
- グリーンアルゴリズム計算機: green-algorithms.org
- 電力マップ API: electricmaps.com/api
- GSF SCI 仕様: sci.グリーンソフトウェア財団
- ハグ顔排出トラッカー: ハグフェイス ハブ カーボン トラッキング
- vLLM の提供: docs.vllm.ai
- ONNX ランタイムの最適化: onnxruntime.ai
道を歩み続ける:関連シリーズ
- ビジネス向け MLOps: ML モデルのデプロイについて詳しくは、こちらをご覧ください。 MLflow、DVC、CI/CD パイプライン - 二酸化炭素排出量品質ゲートを含む。
- AIエンジニアリングとRAG: RAG システムの構築方法を調べる LLM モデルへの呼び出し数を最小限に抑え、両方を削減する効率的な方法です。 排出に伴うコスト。
- データ&AI事業: AI 法 EU と規制の仕組みを確認する ESG はグリーン AI の実践と交差し、ロードマップを構築する方法 中小企業向けの持続可能なデータドリブン。







