| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| from __future__ import annotations |
|
|
| import json |
| import os |
| from typing import TYPE_CHECKING, Any |
|
|
| from .. import logging |
| from .trainer_callback import TrainerCallback, TrainerState |
|
|
|
|
| if TYPE_CHECKING: |
| from ...config import TrainingArguments |
|
|
|
|
| logger = logging.get_logger(__name__) |
|
|
|
|
| class LoggingCallback(TrainerCallback): |
| """Logs training metrics to stdout on rank-0 and appends to ``state.log_history``. |
| |
| On each logging step the entry is also persisted as a JSON line in |
| ``<output_dir>/trainer_log.jsonl`` so that training history survives crashes. |
| """ |
|
|
| def on_log( |
| self, |
| args: TrainingArguments, |
| state: TrainerState, |
| logs: dict[str, Any], |
| **kwargs: Any, |
| ) -> None: |
| |
| state.log_history.append(dict(logs)) |
|
|
| |
| from ...accelerator.interface import DistributedInterface |
|
|
| if DistributedInterface().get_rank() != 0: |
| return |
|
|
| |
| display_logs = {**logs, "step": state.global_step, "total_steps": state.num_training_steps} |
| parts = ", ".join(f"{k}: {v:.4f}" if isinstance(v, float) else f"{k}: {v}" for k, v in display_logs.items()) |
| logger.info_rank0(parts) |
|
|
| |
| os.makedirs(args.output_dir, exist_ok=True) |
| log_file = os.path.join(args.output_dir, "trainer_log.jsonl") |
| with open(log_file, "a", encoding="utf-8") as f: |
| f.write(json.dumps(display_logs, ensure_ascii=False) + "\n") |
|
|