| |
|
|
| |
| |
| |
| |
|
|
| """ |
| Test script for the curriculum learning implementation. |
| |
| This script tests the basic functionality without running full training. |
| """ |
|
|
| import os |
| import sys |
| import torch |
| import json |
|
|
| |
|
|
| from curriculum_learning import CurriculumTrainer |
|
|
| device = "cuda" if torch.cuda.is_available() else "cpu" |
|
|
|
|
| |
| def _sanitize_llm_id(llm_id: str) -> str: |
| if not llm_id: |
| return "unknown_llm" |
| name = llm_id.split("/")[-1] |
| name = name.replace(".", "_").replace("-", "_") |
| while "__" in name: |
| name = name.replace("__", "_") |
| return name |
|
|
|
|
| LLM_ID = "meta-llama/Llama-3.2-1B" |
| LLM_ID_SAFE = _sanitize_llm_id(LLM_ID) |
|
|
|
|
| def test_curriculum_trainer_initialization(): |
| """Test that the CurriculumTrainer can be initialized correctly.""" |
| print("๐งช Testing CurriculumTrainer initialization...") |
|
|
| try: |
| |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
| assert trainer.model_type == "OpenTSLMFlamingo" |
| assert trainer.device in ["cuda", "mps", "cpu"] |
| print("โ
OpenTSLMFlamingo initialization successful") |
|
|
| |
| trainer = CurriculumTrainer("OpenTSLMSP", llm_id=LLM_ID, device=device) |
| assert trainer.model_type == "OpenTSLMSP" |
| print("โ
OpenTSLMSP initialization successful") |
|
|
| except Exception as e: |
| print(f"โ Initialization failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_results_directory_creation(): |
| """Test that the results directory structure is created correctly.""" |
| print("\n๐งช Testing results directory creation...") |
|
|
| try: |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
|
|
| |
| assert os.path.exists("results"), "Main results directory not created" |
|
|
| |
| llm_dir = os.path.join("results", LLM_ID_SAFE) |
| assert os.path.exists(llm_dir), "LLM directory not created" |
|
|
| |
| model_dir = os.path.join(llm_dir, "OpenTSLMFlamingo") |
| assert os.path.exists(model_dir), "Model directory not created" |
|
|
| |
| for stage in ["stage1_mcq", "stage2_captioning"]: |
| stage_dir = os.path.join(model_dir, stage) |
| assert os.path.exists(stage_dir), f"Stage directory {stage} not created" |
|
|
| |
| checkpoints_dir = os.path.join(stage_dir, "checkpoints") |
| results_dir = os.path.join(stage_dir, "results") |
| assert os.path.exists(checkpoints_dir), ( |
| f"Checkpoints directory for {stage} not created" |
| ) |
| assert os.path.exists(results_dir), ( |
| f"Results directory for {stage} not created" |
| ) |
|
|
| print("โ
Results directory structure created correctly") |
|
|
| except Exception as e: |
| print(f"โ Directory creation failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_optimizer_creation(): |
| """Test that optimizers can be created for both model types.""" |
| print("\n๐งช Testing optimizer creation...") |
|
|
| try: |
| |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
| optimizer = trainer._get_optimizer() |
| assert optimizer is not None, "Flamingo optimizer is None" |
| print("โ
OpenTSLMFlamingo optimizer created successfully") |
|
|
| |
| trainer = CurriculumTrainer("OpenTSLMSP", llm_id=LLM_ID, device=device) |
| optimizer = trainer._get_optimizer() |
| assert optimizer is not None, "SP optimizer is None" |
| print("โ
OpenTSLMSP optimizer created successfully") |
|
|
| except Exception as e: |
| print(f"โ Optimizer creation failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_accuracy_calculation(): |
| """Test the accuracy calculation function.""" |
| print("\n๐งช Testing accuracy calculation...") |
|
|
| try: |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
|
|
| |
| print("๐งช Testing exact matches...") |
| predictions = ["A", "B", "C", "D"] |
| gold_answers = ["A", "B", "C", "D"] |
| accuracy = trainer._calculate_accuracy(predictions, gold_answers) |
| assert accuracy == 1.0, f"Expected 1.0, got {accuracy}" |
|
|
| |
| print("๐งช Testing partial matches...") |
| predictions = ["A", "B", "C", "E"] |
| gold_answers = ["A", "B", "C", "D"] |
| accuracy = trainer._calculate_accuracy(predictions, gold_answers) |
| assert accuracy == 0.75, f"Expected 0.75, got {accuracy}" |
|
|
| |
| print("๐งช Testing case insensitive matches...") |
| predictions = ["a", "B", "c", "D"] |
| gold_answers = ["A", "b", "C", "d"] |
| accuracy = trainer._calculate_accuracy(predictions, gold_answers) |
| assert accuracy == 0.0, f"Expected 0.0, got {accuracy}" |
|
|
| |
| print("๐งช Testing empty lists...") |
| accuracy = trainer._calculate_accuracy([], []) |
| assert accuracy == 0.0, f"Expected 0.0, got {accuracy}" |
|
|
| print("โ
Accuracy calculation working correctly") |
|
|
| except Exception as e: |
| print(f"โ Accuracy calculation failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_checkpoint_operations(): |
| """Test checkpoint saving and loading operations.""" |
| print("\n๐งช Testing checkpoint operations...") |
|
|
| try: |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
|
|
| |
| class MockOptimizer: |
| def state_dict(self): |
| return {} |
|
|
| def load_state_dict(self, state_dict): |
| pass |
|
|
| class MockScheduler: |
| def state_dict(self): |
| return {} |
|
|
| def load_state_dict(self, state_dict): |
| pass |
|
|
| mock_optimizer = MockOptimizer() |
| mock_scheduler = MockScheduler() |
|
|
| |
| trainer._save_checkpoint("stage1_mcq", 5, 0.123, mock_optimizer, mock_scheduler) |
|
|
| checkpoint_path = os.path.join( |
| "results", |
| LLM_ID_SAFE, |
| "OpenTSLMFlamingo", |
| "stage1_mcq", |
| "checkpoints", |
| "best_model.pt", |
| ) |
| assert os.path.exists(checkpoint_path), "Checkpoint file not saved" |
|
|
| |
| epoch, val_loss = trainer._load_checkpoint( |
| "stage1_mcq", mock_optimizer, mock_scheduler |
| ) |
| assert epoch == 5, f"Expected epoch 5, got {epoch}" |
| assert val_loss == 0.123, f"Expected val_loss 0.123, got {val_loss}" |
|
|
| print("โ
Checkpoint operations working correctly") |
|
|
| except Exception as e: |
| print(f"โ Checkpoint operations failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_previous_stage_loading(): |
| """Test loading previous stage model and metrics.""" |
| print("\n๐งช Testing previous stage loading...") |
|
|
| try: |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
|
|
| |
| metrics_dir = os.path.join( |
| "results", LLM_ID_SAFE, "OpenTSLMFlamingo", "stage1_mcq", "results" |
| ) |
| os.makedirs(metrics_dir, exist_ok=True) |
|
|
| mock_metrics = {"accuracy": 0.85, "test_loss": 0.234} |
|
|
| with open(os.path.join(metrics_dir, "metrics.json"), "w") as f: |
| json.dump(mock_metrics, f) |
|
|
| |
| checkpoint_dir = os.path.join( |
| "results", LLM_ID_SAFE, "OpenTSLMFlamingo", "stage1_mcq", "checkpoints" |
| ) |
| os.makedirs(checkpoint_dir, exist_ok=True) |
|
|
| mock_checkpoint = { |
| "model_state": trainer.model.state_dict(), |
| "optimizer_state": {}, |
| "scheduler_state": {}, |
| "val_loss": 0.123, |
| "epoch": 10, |
| } |
|
|
| torch.save(mock_checkpoint, os.path.join(checkpoint_dir, "best_model.pt")) |
|
|
| |
| previous_info = trainer._load_previous_stage_model("stage2_captioning") |
|
|
| assert previous_info is not None, "Should load previous stage info" |
| assert previous_info["stage"] == "stage1_mcq", "Should load stage1_mcq" |
| assert previous_info["metrics"] == mock_metrics, "Should load correct metrics" |
| assert previous_info["epoch"] == 10, "Should load correct epoch" |
| assert previous_info["val_loss"] == 0.123, "Should load correct val_loss" |
|
|
| |
| first_stage_info = trainer._load_previous_stage_model("stage1_mcq") |
| assert first_stage_info is None, "First stage should return None" |
|
|
| print("โ
Previous stage loading working correctly") |
|
|
| except Exception as e: |
| print(f"โ Previous stage loading failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_stage_methods_exist(): |
| """Test that the stage methods exist and are callable.""" |
| print("\n๐งช Testing stage methods...") |
|
|
| try: |
| trainer = CurriculumTrainer("OpenTSLMFlamingo", llm_id=LLM_ID, device=device) |
|
|
| |
| assert hasattr(trainer, "stage1_mcq"), "stage1_mcq method not found" |
| assert hasattr(trainer, "stage2_captioning"), ( |
| "stage2_captioning method not found" |
| ) |
| assert callable(trainer.stage1_mcq), "stage1_mcq is not callable" |
| assert callable(trainer.stage2_captioning), "stage2_captioning is not callable" |
|
|
| print("โ
Stage methods exist and are callable") |
|
|
| except Exception as e: |
| print(f"โ Stage methods test failed: {e}") |
| return False |
|
|
| return True |
|
|
|
|
| def test_invalid_model_type(): |
| """Test that invalid model types are handled correctly.""" |
| print("\n๐งช Testing invalid model type handling...") |
|
|
| try: |
| |
| trainer = CurriculumTrainer("InvalidModel", llm_id=LLM_ID, device=device) |
| print("โ Should have raised ValueError for invalid model type") |
| return False |
|
|
| except ValueError as e: |
| print("โ
Invalid model type correctly rejected") |
| return True |
| except Exception as e: |
| print(f"โ Unexpected error: {e}") |
| return False |
|
|
|
|
| def cleanup_test_files(): |
| """Clean up test files and directories.""" |
| print("\n๐งน Cleaning up test files...") |
|
|
| try: |
| import shutil |
|
|
| if os.path.exists("results"): |
| shutil.rmtree("results") |
| print("โ
Test files cleaned up") |
| except Exception as e: |
| print(f"โ ๏ธ Cleanup warning: {e}") |
|
|
|
|
| def main(): |
| """Run all tests.""" |
| print("๐ Running Curriculum Learning Tests") |
| print("=" * 50) |
|
|
| tests = [ |
| test_curriculum_trainer_initialization, |
| test_results_directory_creation, |
| test_optimizer_creation, |
| test_accuracy_calculation, |
| test_checkpoint_operations, |
| test_previous_stage_loading, |
| test_stage_methods_exist, |
| test_invalid_model_type, |
| ] |
|
|
| passed = 0 |
| total = len(tests) |
|
|
| for test in tests: |
| try: |
| if test(): |
| passed += 1 |
| except Exception as e: |
| print(f"โ Test {test.__name__} failed with exception: {e}") |
|
|
| print(f"\n๐ Test Results: {passed}/{total} tests passed") |
|
|
| if passed == total: |
| print("๐ All tests passed!") |
| else: |
| print("โ ๏ธ Some tests failed") |
|
|
| |
| cleanup_test_files() |
|
|
| return passed == total |
|
|
|
|
| if __name__ == "__main__": |
| success = main() |
| sys.exit(0 if success else 1) |
|
|