Spaces:
Running on Zero
Running on Zero
| import os, torch | |
| from tqdm import tqdm | |
| from accelerate import Accelerator | |
| from .training_module import DiffusionTrainingModule | |
| from src.training_module import MetaViewTrainingModule | |
| from .logger import ModelLogger | |
| from PIL import Image | |
| def collate_fn(batch): | |
| if len(batch) == 0: | |
| return {} | |
| collated = {} | |
| keys = batch[0].keys() | |
| for key in keys: | |
| values = [sample[key] for sample in batch] | |
| first_val = values[0] | |
| if isinstance(first_val, torch.Tensor): | |
| # 对于 Tensor,使用 torch.stack 沿第0维堆叠(要求所有张量形状相同) | |
| collated[key] = torch.stack(values, dim=0) | |
| elif isinstance(first_val, Image.Image): | |
| collated[key] = values | |
| elif isinstance(first_val, str): | |
| collated[key] = values | |
| else: | |
| collated[key] = values | |
| return collated | |
| def launch_training_task( | |
| accelerator: Accelerator, | |
| dataset: torch.utils.data.Dataset, | |
| model: MetaViewTrainingModule, | |
| model_logger: ModelLogger, | |
| learning_rate: float = 1e-5, | |
| weight_decay: float = 1e-2, | |
| num_workers: int = 1, | |
| save_steps: int = None, | |
| num_epochs: int = 1, | |
| batch_size: int = 1, | |
| args = None, | |
| ): | |
| if args is not None: | |
| learning_rate = args.learning_rate | |
| weight_decay = args.weight_decay | |
| num_workers = args.dataset_num_workers | |
| save_steps = args.save_steps | |
| num_epochs = args.num_epochs | |
| optimizer = torch.optim.AdamW(model.trainable_modules(), lr=learning_rate, weight_decay=weight_decay) | |
| scheduler = torch.optim.lr_scheduler.ConstantLR(optimizer) | |
| # dataloader = torch.utils.data.DataLoader(dataset, shuffle=False, collate_fn=lambda x: x[0], num_workers=num_workers) | |
| dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn, num_workers=num_workers) | |
| model, optimizer, dataloader, scheduler = accelerator.prepare(model, optimizer, dataloader, scheduler) | |
| def grad_hook(name): | |
| def hook(grad): | |
| # # print(f"{name} gradient norm:{grad.norm().item():.6f}") | |
| # if grad.norm().item() > 1: | |
| # print(f" gradient over 1: {name} {grad.norm().item():.6f}") | |
| if torch.isnan(grad).any(): | |
| print(f"!!! NaN gradient: {name}") | |
| if torch.isinf(grad).any(): | |
| print(f"!!! Inf gradient: {name}") | |
| return grad | |
| return hook | |
| for name, param in model.named_parameters(): | |
| if param.requires_grad: | |
| param.register_hook(grad_hook(name)) | |
| NaN_step = 0 | |
| for epoch_id in range(num_epochs): | |
| for data in tqdm(dataloader): | |
| with accelerator.accumulate(model): | |
| # print(type(data)) | |
| # print(data["prompt"]) | |
| optimizer.zero_grad() | |
| if dataset.load_from_cache: | |
| loss = model({}, inputs=data) | |
| else: | |
| loss = model(data) | |
| if torch.isnan(loss).any(): | |
| print(f"!!! Loss is NaN at step {model_logger.num_steps}! Skipping...") | |
| NaN_step += 1 | |
| print(data["name"]) | |
| exit(0) | |
| accelerator.backward(loss) | |
| max_norm = 5.0 | |
| if accelerator.sync_gradients: | |
| grad_norm = accelerator.clip_grad_norm_(model.parameters(), max_norm=max_norm) | |
| if accelerator.is_main_process: | |
| if grad_norm > 5.0: | |
| print(f"gradient over 5: {grad_norm:.4f}") | |
| optimizer.step() | |
| model_logger.on_step_end(accelerator, model, save_steps) | |
| scheduler.step() | |
| if save_steps is None: | |
| model_logger.on_epoch_end(accelerator, model, epoch_id) | |
| model_logger.on_training_end(accelerator, model, save_steps) | |
| def launch_data_process_task( | |
| accelerator: Accelerator, | |
| dataset: torch.utils.data.Dataset, | |
| model: DiffusionTrainingModule, | |
| model_logger: ModelLogger, | |
| num_workers: int = 8, | |
| args = None, | |
| ): | |
| if args is not None: | |
| num_workers = args.dataset_num_workers | |
| dataloader = torch.utils.data.DataLoader(dataset, shuffle=False, collate_fn=lambda x: x[0], num_workers=num_workers) | |
| model, dataloader = accelerator.prepare(model, dataloader) | |
| for data_id, data in enumerate(tqdm(dataloader)): | |
| with accelerator.accumulate(model): | |
| with torch.no_grad(): | |
| folder = os.path.join(model_logger.output_path, str(accelerator.process_index)) | |
| os.makedirs(folder, exist_ok=True) | |
| save_path = os.path.join(model_logger.output_path, str(accelerator.process_index), f"{data_id}.pth") | |
| data = model(data) | |
| torch.save(data, save_path) | |