Files
2024-11-08 15:17:09 +08:00

139 lines
5.4 KiB
Python
Executable File

from typing import Union, Dict, List, Tuple, Any, Callable
import glob
import os
import io
import re
import torch
import shutil
import time
from dataset.hdfs_io import hexists, hmkdir, hopen, hcopy
def _sorted_checkpoints(args, checkpoint_prefix="checkpoint", use_mtime=False) -> List[str]:
ordering_and_checkpoint_path = []
glob_checkpoints = glob.glob(os.path.join(args.output_dir, "{}-*".format(checkpoint_prefix)))
for path in glob_checkpoints:
if use_mtime:
ordering_and_checkpoint_path.append((os.path.getmtime(path), path))
else:
regex_match = re.match(".*{}-([0-9]+)".format(checkpoint_prefix), path)
if regex_match and regex_match.groups():
ordering_and_checkpoint_path.append((int(regex_match.groups()[0]), path))
checkpoints_sorted = sorted(ordering_and_checkpoint_path)
checkpoints_sorted = [checkpoint[1] for checkpoint in checkpoints_sorted]
return checkpoints_sorted
def _rotate_checkpoints(args, checkpoint_prefix="checkpoint", use_mtime=False) -> None:
if not args.save_total_limit:
return
if args.save_total_limit <= 0:
return
# Check if we should delete older checkpoint(s)
checkpoints_sorted = _sorted_checkpoints(args, checkpoint_prefix, use_mtime)
if len(checkpoints_sorted) <= args.save_total_limit:
return
number_of_checkpoints_to_delete = max(0, len(checkpoints_sorted) - args.save_total_limit)
checkpoints_to_be_deleted = checkpoints_sorted[:number_of_checkpoints_to_delete]
for checkpoint in checkpoints_to_be_deleted:
print("Deleting older checkpoint [{}] due to args.save_total_limit".format(checkpoint))
shutil.rmtree(checkpoint)
def ModelSaver(output_dir, model, optimizer=None):
output_model_file = os.path.join(output_dir, "model.pt")
state_dict = {k: v.cpu() if isinstance(v, torch.Tensor) else v
for k, v in model.state_dict().items()}
torch.save(state_dict, output_model_file)
if optimizer is not None:
torch.save(optimizer.state_dict(), f'{output_dir}/optimizer.pt')
# checkpointer from fex. Save to hdfs
def save(obj, filepath: str, **kwargs):
""" save model """
if filepath.startswith("hdfs://"):
with hopen(filepath, "wb") as writer:
torch.save(obj, writer, **kwargs)
else:
torch.save(obj, filepath, **kwargs)
def save_checkpoint(output_dir: str,
epoch: Union[int, str],
lg_loss_scale: float,
model_state: Dict[str, Any],
training_states: Dict[str, Any],
num_serialized_models_to_keep: int = 20) -> None:
"""
保存 checkpoint到remote hdfs中:
args:
epoch: 当前训练的epoch数
model_state: 当前训练model的参数
training_states: 当前训练的参数
is_best_so_far: 当前是否save的checkpoint是否为最优
"""
if not hexists(output_dir):
hmkdir(output_dir)
model_path = os.path.join(output_dir, "model_state-{}.th".format(epoch))
training_path = os.path.join(output_dir, "optimizer_state_latest.th")
save(model_state["cur_model"], model_path)
save({"state_dict": training_states, "step": epoch, "lg_loss_scale": lg_loss_scale}, training_path)
def save_checkpoint_ema(output_dir: str,
epoch: Union[int, str],
models_state: Dict[str, Any],
optimizer_state: Dict[str, Any],
scaler_state: Dict[str, Any],
num_serialized_models_to_keep: int = 20) -> None:
"""
保存 checkpoint到remote hdfs中:
args:
epoch: 当前训练的epoch数
model_state: ema 参数, 0: 当前训练model的参数, others: ema_model 参数
training_states: 当前训练的参数
is_best_so_far: 当前是否save的checkpoint是否为最优
"""
if not hexists(output_dir):
hmkdir(output_dir)
for ema_rate, model_state in models_state.items():
if ema_rate == 0:
# 0: 当前训练model的参数
model_path = os.path.join(output_dir, "model_state-{}.th".format(epoch))
elif isinstance(ema_rate, str):
# some other keyword
model_path = os.path.join(output_dir, "model_state-{}_{}.th".format(epoch, ema_rate))
else:
model_path = os.path.join(output_dir, "model_state-{}_ema_{}.th".format(epoch, ema_rate))
save(model_state, model_path)
training_path = os.path.join(output_dir, "optimizer_state_latest.th")
if hexists(training_path):
hcopy(training_path, os.path.join(output_dir, f"optimizer_state_{epoch}.th"))
save({"state_dict": optimizer_state, "step": epoch, "scaler_state_dict": scaler_state}, training_path)
# resuming training
def load(filepath: str, **kwargs):
""" load model """
if not filepath.startswith("hdfs://"):
return torch.load(filepath, **kwargs)
with hopen(filepath, "rb") as reader:
accessor = io.BytesIO(reader.read())
state_dict = torch.load(accessor, **kwargs)
del accessor
return state_dict
def load_from_pretrain(pretrain_path, map_location='cpu'):
# partial load pretrain state dict
pretrain_state_dict_parsed = {}
if pretrain_path != "":
pretrain_state_dict = load(pretrain_path, map_location=map_location)
return pretrain_state_dict