| | """Model utilities and helper functions.""" |
| |
|
| | import json |
| | import os |
| | from typing import Dict, Any, Optional |
| | import torch |
| | import numpy as np |
| | from sklearn.metrics import classification_report, confusion_matrix |
| | import matplotlib.pyplot as plt |
| | import seaborn as sns |
| | from transformers import AutoTokenizer, AutoModelForSequenceClassification |
| | import evaluate |
| |
|
| |
|
| | def load_model_and_tokenizer(model_name: str, num_labels: int = 2): |
| | """Load pre-trained model and tokenizer.""" |
| | tokenizer = AutoTokenizer.from_pretrained(model_name) |
| | model = AutoModelForSequenceClassification.from_pretrained( |
| | model_name, |
| | num_labels=num_labels |
| | ) |
| | return model, tokenizer |
| |
|
| |
|
| | def compute_metrics(eval_pred): |
| | """Compute metrics for evaluation.""" |
| | accuracy_metric = evaluate.load("accuracy") |
| | f1_metric = evaluate.load("f1") |
| | |
| | predictions, labels = eval_pred |
| | predictions = np.argmax(predictions, axis=1) |
| | |
| | accuracy = accuracy_metric.compute(predictions=predictions, references=labels) |
| | f1 = f1_metric.compute(predictions=predictions, references=labels, average="weighted") |
| | |
| | return { |
| | "accuracy": accuracy["accuracy"], |
| | "f1": f1["f1"] |
| | } |
| |
|
| |
|
| | def detailed_evaluation(y_true, y_pred, class_names: Optional[list] = None) -> Dict[str, Any]: |
| | """ |
| | Perform detailed evaluation with classification report and confusion matrix. |
| | |
| | Args: |
| | y_true: True labels |
| | y_pred: Predicted labels |
| | class_names: Names of classes for visualization |
| | |
| | Returns: |
| | Dictionary with evaluation metrics and plots |
| | """ |
| | if class_names is None: |
| | class_names = [f"Class {i}" for i in range(len(np.unique(y_true)))] |
| | |
| | |
| | report = classification_report(y_true, y_pred, target_names=class_names, output_dict=True) |
| | |
| | |
| | cm = confusion_matrix(y_true, y_pred) |
| | |
| | |
| | plt.figure(figsize=(8, 6)) |
| | sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', |
| | xticklabels=class_names, yticklabels=class_names) |
| | plt.title('Confusion Matrix') |
| | plt.ylabel('True Label') |
| | plt.xlabel('Predicted Label') |
| | plt.tight_layout() |
| | plt.savefig('confusion_matrix.png', dpi=300, bbox_inches='tight') |
| | plt.close() |
| | |
| | return { |
| | "classification_report": report, |
| | "confusion_matrix": cm.tolist(), |
| | "accuracy": report["accuracy"], |
| | "macro_f1": report["macro avg"]["f1-score"], |
| | "weighted_f1": report["weighted avg"]["f1-score"] |
| | } |
| |
|
| |
|
| | def save_model_info(model_path: str, config: Dict[str, Any], metrics: Dict[str, Any]): |
| | """Save model information and metrics.""" |
| | info = { |
| | "model_config": config, |
| | "training_metrics": metrics, |
| | "model_path": model_path |
| | } |
| | |
| | with open(os.path.join(model_path, "model_info.json"), "w") as f: |
| | json.dump(info, f, indent=2) |
| |
|
| |
|
| | def get_model_size(model) -> Dict[str, Any]: |
| | """Get model size information.""" |
| | param_size = 0 |
| | param_count = 0 |
| | |
| | for param in model.parameters(): |
| | param_count += param.nelement() |
| | param_size += param.nelement() * param.element_size() |
| | |
| | buffer_size = 0 |
| | for buffer in model.buffers(): |
| | buffer_size += buffer.nelement() * buffer.element_size() |
| | |
| | size_mb = (param_size + buffer_size) / 1024**2 |
| | |
| | return { |
| | "param_count": param_count, |
| | "param_size_mb": param_size / 1024**2, |
| | "buffer_size_mb": buffer_size / 1024**2, |
| | "total_size_mb": size_mb |
| | } |
| |
|
| |
|
| | def plot_training_history(trainer_log_history: list, save_path: str = "training_history.png"): |
| | """Plot training history from trainer logs.""" |
| | train_losses = [] |
| | eval_losses = [] |
| | eval_accuracies = [] |
| | epochs = [] |
| | |
| | for log in trainer_log_history: |
| | if "train_loss" in log: |
| | train_losses.append(log["train_loss"]) |
| | epochs.append(log["epoch"]) |
| | if "eval_loss" in log: |
| | eval_losses.append(log["eval_loss"]) |
| | if "eval_accuracy" in log: |
| | eval_accuracies.append(log["eval_accuracy"]) |
| | |
| | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5)) |
| | |
| | |
| | ax1.plot(epochs, train_losses, label="Train Loss", marker='o') |
| | if eval_losses: |
| | |
| | eval_epochs = [i+1 for i in range(len(eval_losses))] |
| | ax1.plot(eval_epochs, eval_losses, label="Eval Loss", marker='s') |
| | ax1.set_xlabel("Epoch") |
| | ax1.set_ylabel("Loss") |
| | ax1.set_title("Training and Evaluation Loss") |
| | ax1.legend() |
| | ax1.grid(True) |
| | |
| | |
| | if eval_accuracies: |
| | |
| | eval_acc_epochs = [i+1 for i in range(len(eval_accuracies))] |
| | ax2.plot(eval_acc_epochs, eval_accuracies, |
| | label="Eval Accuracy", marker='s', color='green') |
| | ax2.set_xlabel("Epoch") |
| | ax2.set_ylabel("Accuracy") |
| | ax2.set_title("Evaluation Accuracy") |
| | ax2.legend() |
| | ax2.grid(True) |
| | |
| | plt.tight_layout() |
| | plt.savefig(save_path, dpi=300, bbox_inches='tight') |
| | plt.close() |
| |
|
| |
|
| | def estimate_gpu_memory(model, batch_size: int, seq_length: int) -> Dict[str, float]: |
| | """Estimate GPU memory requirements.""" |
| | model_size = get_model_size(model)["total_size_mb"] |
| | |
| | |
| | activation_size_mb = batch_size * seq_length * model.config.hidden_size * 4 / 1024**2 |
| | |
| | |
| | gradient_size_mb = model_size |
| | |
| | |
| | overhead_mb = 500 |
| | |
| | total_mb = model_size + activation_size_mb + gradient_size_mb + overhead_mb |
| | |
| | return { |
| | "model_size_mb": model_size, |
| | "activation_size_mb": activation_size_mb, |
| | "gradient_size_mb": gradient_size_mb, |
| | "overhead_mb": overhead_mb, |
| | "total_estimated_mb": total_mb, |
| | "total_estimated_gb": total_mb / 1024 |
| | } |