lip-forcing / lipforcing /callbacks /gpu_stats.py
multimodalart's picture
multimodalart HF Staff
Initial Lip Forcing 14B streaming demo
9368ee7 verified
Raw
History Blame Contribute Delete
3.33 kB
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import os
from typing import TYPE_CHECKING, Callable, Any, Dict, List
import pandas as pd
import psutil
import torch
from lipforcing.callbacks.callback import Callback
from lipforcing.utils.distributed import world_size, is_rank0, synchronize
import lipforcing.utils.logging_utils as logger
if TYPE_CHECKING:
from lipforcing.methods import FastGenModel
def log_prof_data(data_list: List[Dict[str, Any]]):
# Create a table to log data with rank information
metrics = list(data_list[0].keys())
# Initialize dictionaries to store min and max values for each metric
min_values = {key: float("inf") for key in metrics}
max_values = {key: float("-inf") for key in metrics}
sum_values = {key: 0.0 for key in metrics}
count = 0
for _rank, prof_data in enumerate(data_list):
count += 1
# Update min, max, and sum values
for key in metrics:
min_values[key] = min(min_values[key], prof_data[key])
max_values[key] = max(max_values[key], prof_data[key])
sum_values[key] += prof_data[key]
# Calculate average values
avg_values = {key: sum_values[key] / count for key in metrics}
summary_df = pd.DataFrame({"Avg": avg_values, "Max": max_values, "Min": min_values})
logger.info(f"GPU stats:\n{summary_df.to_string()}")
class GPUStatsCallback(Callback):
def __init__(self, every_n: int = 100):
self.every_n = every_n
def on_train_begin(self, model: FastGenModel, iteration: int = 0):
torch.cuda.reset_peak_memory_stats()
if hasattr(self, "config"):
# overwritten by logging_iter if self.config exists
self.every_n = self.config.trainer.logging_iter
logger.info(f"every_n to measure gpus stats: {self.every_n}")
def on_training_step_end(
self,
model: FastGenModel,
data_batch: dict[str, torch.Tensor],
output_batch: dict[str, torch.Tensor | Callable],
loss_dict: dict[str, torch.Tensor],
iteration: int = 0,
) -> None:
del data_batch, output_batch, loss_dict
if iteration % self.every_n == 0:
cur_process = psutil.Process(os.getpid())
cpu_memory_usage = sum(p.memory_info().rss for p in [cur_process] + cur_process.children(recursive=True))
cpu_mem_gb = cpu_memory_usage / (1024**3)
peak_gpu_mem_gb = torch.cuda.max_memory_allocated() / (1024**3)
peak_gpu_mem_reserved_gb = torch.cuda.max_memory_reserved() / (1024**3)
util = torch.cuda.utilization()
prof_data = {
"cpu_mem_gb": float(cpu_mem_gb),
"peak_gpu_mem_gb": float(peak_gpu_mem_gb),
"peak_gpu_mem_reserved_gb": float(peak_gpu_mem_reserved_gb),
"util": float(util),
}
synchronize()
data_list = [prof_data] * world_size()
# this is blocking by default
if world_size() > 1:
torch.distributed.all_gather_object(data_list, prof_data)
if is_rank0():
log_prof_data(data_list)
synchronize()