Spaces:
Sleeping
Sleeping
| import os | |
| import yaml | |
| import nltk | |
| import pickle | |
| import torch | |
| import mlflow | |
| import mlflow.pytorch | |
| from tqdm import tqdm | |
| from preprocess_data import VQADataset | |
| from nltk.tokenize import word_tokenize | |
| from torch.utils.data import DataLoader | |
| from model import load_model_processor | |
| from transformers import get_linear_schedule_with_warmup | |
| from nltk.translate.bleu_score import sentence_bleu , SmoothingFunction | |
| from mlflow.models import infer_signature | |
| nltk.download('all') | |
| config = yaml.safe_load(open("./config.yaml", "r"))["data_location"] | |
| model_config = yaml.safe_load(open("./config.yaml", "r"))["finetune_model"] | |
| params = yaml.safe_load(open("./param.yaml", "r"))["params"] | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| model, processor = load_model_processor() | |
| print(f"Loading processed data from {config['train_processed_data']} and {config['test_processed_data']}.") | |
| with open(f'./{config["train_processed_data"]}', "rb") as f: | |
| train_dataset = pickle.load(f) | |
| with open(f'./{config["test_processed_data"]}', "rb") as f: | |
| test_dataset = pickle.load(f) | |
| print(f"Loaded processed data successfully!!!") | |
| print(f"Length of train dataset is {len(train_dataset)} and test dataset is {len(test_dataset)}") | |
| batch_size = params["batch_size"] | |
| num_epochs = params["num_epochs"] | |
| patience = params["patience"] | |
| gradient_accumulation_steps = params["gradient_accumulation_steps"] | |
| print("Preparing dataloaders................") | |
| train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, pin_memory=True) | |
| valid_dataloader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, pin_memory=True) | |
| print("Dataloaders prepared successfully!!!") | |
| mlflow.set_experiment("VQA_Model_Training") | |
| min_bleu_score = 0 | |
| early_stopping_hook = 0 | |
| tracking_information = [] | |
| optimizer = torch.optim.AdamW(filter(lambda p: p.requires_grad, model.parameters()), lr=float(params["learning_rate"]), weight_decay=float(params["weight_decay"])) | |
| total_steps = len(train_dataloader) * num_epochs | |
| warmup_steps = total_steps // 10 | |
| scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=warmup_steps, num_training_steps=total_steps) | |
| scaler = torch.amp.GradScaler('cuda') | |
| with mlflow.start_run(): | |
| for epoch in range(num_epochs): | |
| model.train() | |
| epoch_loss = 0 | |
| for step, batch in enumerate(tqdm(train_dataloader, desc=f"Epoch {epoch+1} Training")): | |
| input_ids = batch.pop('input_ids').to(device) | |
| pixel_values = batch.pop('pixel_values').to(device) | |
| attention_mask = batch.pop('attention_mask').to(device) | |
| labels = batch.pop('labels').to(device) | |
| with torch.amp.autocast('cuda', dtype=torch.float16): | |
| outputs = model(input_ids=input_ids, pixel_values=pixel_values, attention_mask=attention_mask, labels=labels) | |
| loss = outputs.loss / gradient_accumulation_steps | |
| scaler.scale(loss).backward() | |
| if (step + 1) % gradient_accumulation_steps == 0 or (step + 1) == len(train_dataloader): | |
| scaler.unscale_(optimizer) | |
| torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) | |
| scaler.step(optimizer) | |
| scaler.update() | |
| optimizer.zero_grad() | |
| epoch_loss += loss.item() * gradient_accumulation_steps | |
| # Validation Loop | |
| model.eval() | |
| eval_loss = 0 | |
| bleu_scores = [] | |
| smooth_fn = SmoothingFunction().method1 | |
| with torch.no_grad(): | |
| for batch in tqdm(valid_dataloader, desc=f"Epoch {epoch+1} Validating"): | |
| input_ids = batch.pop('input_ids').to(device) | |
| pixel_values = batch.pop('pixel_values').to(device) | |
| attention_mask = batch.pop('attention_mask').to(device) | |
| labels = batch.pop('labels').to(device) | |
| with torch.amp.autocast('cuda', dtype=torch.float16): | |
| outputs = model(input_ids=input_ids, pixel_values=pixel_values, attention_mask=attention_mask, labels=labels) | |
| eval_loss += outputs.loss.item() | |
| generated_ids = model.generate(input_ids=input_ids, pixel_values=pixel_values, attention_mask=attention_mask, max_length=8) | |
| predictions = processor.tokenizer.batch_decode(generated_ids, skip_special_tokens=True) | |
| references = processor.tokenizer.batch_decode(labels, skip_special_tokens=True) | |
| for pred, ref in zip(predictions, references): | |
| bleu_scores.append(sentence_bleu([word_tokenize(ref)], word_tokenize(pred), smoothing_function=smooth_fn)) | |
| avg_train_loss = epoch_loss / len(train_dataloader) | |
| avg_eval_loss = eval_loss / len(valid_dataloader) | |
| avg_bleu_score = sum(bleu_scores) / len(bleu_scores) | |
| tracking_information.append((avg_train_loss, avg_eval_loss, avg_bleu_score, optimizer.param_groups[0]["lr"])) | |
| mlflow.log_metrics({"train_loss": avg_train_loss, "eval_loss": avg_eval_loss, "bleu_score": avg_bleu_score}, step=epoch) | |
| mlflow.log_param(f"learning_rate_{epoch}", optimizer.param_groups[0]['lr']) | |
| print(f"Epoch {epoch+1} - Train Loss: {avg_train_loss:.4f} - Eval Loss: {avg_eval_loss:.4f} - BLEU Score: {avg_bleu_score:.4f} - LR: {optimizer.param_groups[0]['lr']}") | |
| if avg_bleu_score >= min_bleu_score: | |
| model.save_pretrained(model_config["best"], from_pt=True) | |
| print(f"Model improved (BLEU: {avg_bleu_score:.4f})! Saved to {model_config['best']}") | |
| min_bleu_score = avg_bleu_score | |
| early_stopping_hook = 0 | |
| else: | |
| early_stopping_hook += 1 | |
| if early_stopping_hook > patience: | |
| print("Early stopping triggered.") | |
| break | |
| model.save_pretrained(model_config["last"], from_pt=True) | |
| scheduler.step() | |
| # Log the saved PEFT adapters as an artifact instead of trying to pickle the Quantized model | |
| mlflow.log_artifacts(model_config["best"], artifact_path="VQA_model_best") | |
| print("Model adapters logged with MLflow.") | |