|
17 | 17 | from collections.abc import Callable |
18 | 18 | from dataclasses import dataclass, field |
19 | 19 | import functools |
| 20 | +from types import SimpleNamespace |
20 | 21 | from typing import Any, Sequence |
21 | 22 | import unittest |
22 | 23 | from unittest.mock import MagicMock, Mock, patch |
@@ -1730,5 +1731,46 @@ def test_update_kv_caches_after_scan_invalid_type(self): |
1730 | 1731 | maxtext_utils.update_kv_caches_after_scan(kv_caches_tuple, returned_kv_cache, scan_length=1, block_len=2) |
1731 | 1732 |
|
1732 | 1733 |
|
| 1734 | +class TestGetOffloadRematNames(unittest.TestCase): |
| 1735 | + """Tests for maxtext_utils.get_offload_remat_names.""" |
| 1736 | + |
| 1737 | + @staticmethod |
| 1738 | + def _cfg(remat_policy, tensors_on_device=None, tensors_to_offload=None): |
| 1739 | + return SimpleNamespace( |
| 1740 | + remat_policy=remat_policy, |
| 1741 | + tensors_on_device=tensors_on_device, |
| 1742 | + tensors_to_offload=tensors_to_offload, |
| 1743 | + ) |
| 1744 | + |
| 1745 | + def test_named_preset_matches_equivalent_custom(self): |
| 1746 | + """qkv_proj_offloaded resolves identically to custom with the same offloads.""" |
| 1747 | + preset = maxtext_utils.get_offload_remat_names(self._cfg("qkv_proj_offloaded")) |
| 1748 | + custom = maxtext_utils.get_offload_remat_names( |
| 1749 | + self._cfg("custom", tensors_on_device=[], tensors_to_offload=["query_proj", "value_proj", "key_proj", "kv_proj"]) |
| 1750 | + ) |
| 1751 | + self.assertEqual(preset, custom) |
| 1752 | + |
| 1753 | + def test_kv_proj_retained_in_offload_presets(self): |
| 1754 | + """Regression guard: kv_proj must stay in the offload presets (it is a real checkpoint name).""" |
| 1755 | + _, qkv_offload = maxtext_utils.get_offload_remat_names(self._cfg("qkv_proj_offloaded")) |
| 1756 | + _, minimal_offload = maxtext_utils.get_offload_remat_names(self._cfg("minimal_offloaded")) |
| 1757 | + self.assertIn("kv_proj", qkv_offload) |
| 1758 | + self.assertIn("kv_proj", minimal_offload) |
| 1759 | + |
| 1760 | + def test_custom_reads_config_lists(self): |
| 1761 | + save, offload = maxtext_utils.get_offload_remat_names( |
| 1762 | + self._cfg("custom", tensors_on_device=["context"], tensors_to_offload=["out_proj"]) |
| 1763 | + ) |
| 1764 | + self.assertEqual(save, ["context"]) |
| 1765 | + self.assertEqual(offload, ["out_proj"]) |
| 1766 | + |
| 1767 | + def test_custom_handles_none_lists(self): |
| 1768 | + self.assertEqual(maxtext_utils.get_offload_remat_names(self._cfg("custom")), ([], [])) |
| 1769 | + |
| 1770 | + def test_non_offloading_policies_return_none(self): |
| 1771 | + for policy in ("full", "minimal", "save_out_proj", "save_qkv_proj", "none"): |
| 1772 | + self.assertIsNone(maxtext_utils.get_offload_remat_names(self._cfg(policy))) |
| 1773 | + |
| 1774 | + |
1733 | 1775 | if __name__ == "__main__": |
1734 | 1776 | unittest.main() |
0 commit comments