multimodalart's picture
multimodalart HF Staff
Initial MetaView novel view synthesis demo
ccfee12 verified
Raw
History Blame Contribute Delete
4.95 kB
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)