test_replay.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import unittest
  2. from typing import List, Dict
  3. from unittest.mock import MagicMock
  4. import torch
  5. from torch import tensor, Tensor, zeros
  6. from torch.nn import CrossEntropyLoss, Module, Identity
  7. from torch.optim import SGD
  8. from avalanche.benchmarks.utils import AvalancheDataset, AvalancheDatasetType, \
  9. AvalancheTensorDataset
  10. from avalanche.models import SimpleMLP
  11. from avalanche.training.plugins import ExperienceBalancedStoragePolicy, \
  12. ClassBalancedStoragePolicy, ReplayPlugin
  13. from avalanche.training.plugins.replay import ClassExemplarsSelectionStrategy, \
  14. HerdingSelectionStrategy, ClosestToCenterSelectionStrategy
  15. from avalanche.training.strategies import Naive, BaseStrategy
  16. from tests.unit_tests_utils import get_fast_benchmark
  17. class ReplayTest(unittest.TestCase):
  18. def test_replay_balanced_memory(self):
  19. mem_size = 25
  20. policies = [None,
  21. ExperienceBalancedStoragePolicy({}, mem_size=mem_size),
  22. ClassBalancedStoragePolicy({}, mem_size=mem_size)]
  23. for policy in policies:
  24. self._test_replay_balanced_memory(policy, mem_size)
  25. def _test_replay_balanced_memory(self, storage_policy, mem_size):
  26. benchmark = get_fast_benchmark(use_task_labels=True)
  27. model = SimpleMLP(input_size=6, hidden_size=10)
  28. replayPlugin = ReplayPlugin(mem_size=mem_size,
  29. storage_policy=storage_policy)
  30. cl_strategy = Naive(
  31. model,
  32. SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=0.001),
  33. CrossEntropyLoss(), train_mb_size=32, train_epochs=1,
  34. eval_mb_size=100, plugins=[replayPlugin]
  35. )
  36. n_seen_data = 0
  37. for step in benchmark.train_stream:
  38. n_seen_data += len(step.dataset)
  39. mem_fill = min(mem_size, n_seen_data)
  40. cl_strategy.train(step)
  41. ext_mem = replayPlugin.ext_mem
  42. lengths = []
  43. for task_id in ext_mem.keys():
  44. lengths.append(len(ext_mem[task_id]))
  45. self.assertEqual(sum(lengths), mem_fill) # Always fully filled
  46. def test_balancing(self):
  47. p1 = ExperienceBalancedStoragePolicy({}, 100, adaptive_size=True)
  48. p2 = ClassBalancedStoragePolicy({}, 100, adaptive_size=True)
  49. for policy in [p1, p2]:
  50. self.assert_balancing(policy)
  51. def assert_balancing(self, policy):
  52. ext_mem = policy.ext_mem
  53. benchmark = get_fast_benchmark(use_task_labels=True)
  54. replay = ReplayPlugin(mem_size=100, storage_policy=policy)
  55. model = SimpleMLP(num_classes=benchmark.n_classes)
  56. # CREATE THE STRATEGY INSTANCE (NAIVE)
  57. cl_strategy = Naive(model,
  58. SGD(model.parameters(), lr=0.001),
  59. CrossEntropyLoss(), train_mb_size=100,
  60. train_epochs=0,
  61. eval_mb_size=100, plugins=[replay], evaluator=None)
  62. for exp in benchmark.train_stream:
  63. cl_strategy.train(exp)
  64. print(list(ext_mem.keys()), [len(el) for el in ext_mem.values()])
  65. # buffer size should equal self.mem_size if data is large enough
  66. len_tot = sum([len(el) for el in ext_mem.values()])
  67. assert len_tot == policy.mem_size
  68. class ClassBalancePolicyTest(unittest.TestCase):
  69. def setUp(self) -> None:
  70. self.memory = {}
  71. self.policy = ClassBalancedStoragePolicy(self.memory, mem_size=4)
  72. def test_store_alone_with_enough_memory(self):
  73. order = [2, 0, 1, 3]
  74. self.observe_exemplars({0: list(range(4))}, selection_order=order)
  75. self.assert_memory_equal({0: order})
  76. def test_store_alone_without_enough_memory(self):
  77. order = [6, 4, 2, 0, 1, 3, 5]
  78. self.observe_exemplars({0: list(range(7))}, selection_order=order)
  79. self.assert_memory_equal({0: order[:4]})
  80. def test_store_multiple_with_enough_memory(self):
  81. self.observe_exemplars({0: [0, 1], 1: [10, 11]}, selection_order=[1, 0])
  82. self.assert_memory_equal({0: [1, 0], 1: [11, 10]})
  83. def test_store_multiple_without_enough_memory(self):
  84. self.observe_exemplars({0: [0, 1, 2], 1: [10, 11, 12]},
  85. selection_order=[2, 0, 1])
  86. self.assert_memory_equal({0: [2, 0], 1: [12, 10]})
  87. def test_sequence(self):
  88. # 1st observation
  89. self.observe_exemplars({0: [0, 1], 1: [10, 11]}, selection_order=[1, 0])
  90. self.assert_memory_equal({0: [1, 0], 1: [11, 10]})
  91. # 2nd observation
  92. self.observe_exemplars({2: [20, 21, 22], 3: [30, 31, 32]},
  93. selection_order=[2, 1, 0])
  94. self.assert_memory_equal({0: [1], 1: [11], 2: [22], 3: [32]})
  95. def observe_exemplars(self, class2exemplars: Dict[int, List[int]],
  96. selection_order: List[int]):
  97. self.policy.selection_strategy = FixedSelectionStrategy(selection_order)
  98. x = tensor(
  99. [i for exemplars in class2exemplars.values() for i in exemplars])
  100. y = tensor(
  101. [class_id for class_id, exemplars in class2exemplars.items() for _
  102. in exemplars]).long()
  103. dataset = AvalancheTensorDataset(
  104. x, y, dataset_type=AvalancheDatasetType.CLASSIFICATION)
  105. self.policy(MagicMock(experience=MagicMock(dataset=dataset)))
  106. def assert_memory_equal(self, class2exemplars: Dict[int, List[int]]):
  107. self.assertEqual(class2exemplars,
  108. {class_id: [x.tolist() for x, *_ in memory] for
  109. class_id, memory in self.memory.items()})
  110. class SelectionStrategyTest(unittest.TestCase):
  111. def test(self):
  112. # Given
  113. model = AbsModel()
  114. herding = HerdingSelectionStrategy(model, "features")
  115. closest_to_center = ClosestToCenterSelectionStrategy(model, "features")
  116. # When
  117. # Features are [[0], [4], [5]]
  118. # Center is [3]
  119. dataset = AvalancheTensorDataset(
  120. tensor([0, -4, 5]).float(), zeros(3),
  121. dataset_type=AvalancheDatasetType.CLASSIFICATION
  122. )
  123. strategy = MagicMock(device="cpu", eval_mb_size=8)
  124. # Then
  125. # Herding:
  126. # 1. At first pass, we select the -4 (at index 1)
  127. # because it is the closest ([4]) to the center in feature space
  128. # 2. At second pass, we select 0 (of index 0)
  129. # because the center will be [2], closest to [3] than the center
  130. # obtained if we were to select 5 ([4.5])
  131. # 3. Finally we select the last remaining exemplar
  132. self.assertSequenceEqual([1, 0, 2],
  133. herding.make_sorted_indices(strategy, dataset))
  134. # Closest to center
  135. # -4 (index 1) is the closest to the center in feature space.
  136. # Then 5 (index 2) is closest than 0 (index 0)
  137. self.assertSequenceEqual([1, 2, 0],
  138. closest_to_center.make_sorted_indices(strategy,
  139. dataset))
  140. class AbsModel(Module):
  141. """Fake model, that simply compute the absolute value of the inputs"""
  142. def __init__(self):
  143. super().__init__()
  144. self.features = AbsLayer()
  145. self.classifier = Identity()
  146. def forward(self, x: Tensor) -> Tensor:
  147. x = self.features(x)
  148. x = self.classifier(x)
  149. return x
  150. class AbsLayer(Module):
  151. def forward(self, x: Tensor) -> Tensor:
  152. return torch.abs(x).reshape((-1, 1))
  153. class FixedSelectionStrategy(ClassExemplarsSelectionStrategy):
  154. """This is a fake strategy used for testing the policy behavior"""
  155. def __init__(self, indices: List[int]):
  156. self.indices = indices
  157. def make_sorted_indices(self, strategy: "BaseStrategy",
  158. data: AvalancheDataset) -> List[int]:
  159. return self.indices