generic_benchmark_creation.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. ################################################################################
  2. # Copyright (c) 2021 ContinualAI. #
  3. # Copyrights licensed under the MIT License. #
  4. # See the accompanying LICENSE file for terms. #
  5. # #
  6. # Date: 16-04-2021 #
  7. # Author(s): Lorenzo Pellegrini #
  8. # E-mail: contact@continualai.org #
  9. # Website: avalanche.continualai.org #
  10. ################################################################################
  11. """ This module contains mid-level benchmark generators.
  12. Consider using the higher-level ones found in benchmark_generators. If none of
  13. them fit your needs, then the helper functions here listed may help.
  14. """
  15. from pathlib import Path
  16. from typing import Sequence, Union, Any, Tuple, Dict, Optional, Iterable, \
  17. NamedTuple
  18. from avalanche.benchmarks.utils import AvalancheTensorDataset, \
  19. SupportedDataset, AvalancheDataset, FilelistDataset, \
  20. PathsDataset, common_paths_root
  21. from .generic_cl_scenario import GenericCLScenario
  22. from ..utils.avalanche_dataset import AvalancheDatasetType
  23. def create_multi_dataset_generic_benchmark(
  24. train_datasets: Sequence[SupportedDataset],
  25. test_datasets: Sequence[SupportedDataset],
  26. *,
  27. other_streams_datasets: Dict[str, Sequence[SupportedDataset]] = None,
  28. complete_test_set_only: bool = False,
  29. train_transform=None, train_target_transform=None,
  30. eval_transform=None, eval_target_transform=None,
  31. other_streams_transforms: Dict[str, Tuple[Any, Any]] = None,
  32. dataset_type: AvalancheDatasetType = None) -> GenericCLScenario:
  33. """
  34. Creates a benchmark instance given a list of datasets. Each dataset will be
  35. considered as a separate experience.
  36. Contents of the datasets must already be set, including task labels.
  37. Transformations will be applied if defined.
  38. This function allows for the creation of custom streams as well.
  39. While "train" and "test" datasets must always be set, the experience list
  40. for other streams can be defined by using the `other_streams_datasets`
  41. parameter.
  42. If transformations are defined, they will be applied to the datasets
  43. of the related stream.
  44. :param train_datasets: A list of training datasets.
  45. :param test_datasets: A list of test datasets.
  46. :param other_streams_datasets: A dictionary describing the content of custom
  47. streams. Keys must be valid stream names (letters and numbers,
  48. not starting with a number) while the value must be a list of dataset.
  49. If this dictionary contains the definition for "train" or "test"
  50. streams then those definition will override the `train_datasets` and
  51. `test_datasets` parameters.
  52. :param complete_test_set_only: If True, only the complete test set will
  53. be returned by the benchmark. This means that the ``test_dataset_list``
  54. parameter must be list with a single element (the complete test set).
  55. Defaults to False.
  56. :param train_transform: The transformation to apply to the training data,
  57. e.g. a random crop, a normalization or a concatenation of different
  58. transformations (see torchvision.transform documentation for a
  59. comprehensive list of possible transformations). Defaults to None.
  60. :param train_target_transform: The transformation to apply to training
  61. patterns targets. Defaults to None.
  62. :param eval_transform: The transformation to apply to the test data,
  63. e.g. a random crop, a normalization or a concatenation of different
  64. transformations (see torchvision.transform documentation for a
  65. comprehensive list of possible transformations). Defaults to None.
  66. :param eval_target_transform: The transformation to apply to test
  67. patterns targets. Defaults to None.
  68. :param other_streams_transforms: Transformations to apply to custom
  69. streams. If no transformations are defined for a custom stream,
  70. then "train" transformations will be used. This parameter must be a
  71. dictionary mapping stream names to transformations. The transformations
  72. must be a two elements tuple where the first element defines the
  73. X transformation while the second element is the Y transformation.
  74. Those elements can be None. If this dictionary contains the
  75. transformations for "train" or "test" streams then those transformations
  76. will override the `train_transform`, `train_target_transform`,
  77. `eval_transform` and `eval_target_transform` parameters.
  78. :param dataset_type: The type of the dataset. Defaults to None, which
  79. means that the type will be obtained from the input datasets. If input
  80. datasets are not instances of :class:`AvalancheDataset`, the type
  81. UNDEFINED will be used.
  82. :returns: A :class:`GenericCLScenario` instance.
  83. """
  84. transform_groups = dict(
  85. train=(train_transform, train_target_transform),
  86. eval=(eval_transform, eval_target_transform))
  87. if other_streams_transforms is not None:
  88. for stream_name, stream_transforms in other_streams_transforms.items():
  89. if isinstance(stream_transforms, Sequence):
  90. if len(stream_transforms) == 1:
  91. # Suppose we got only the transformation for X values
  92. stream_transforms = (stream_transforms[0], None)
  93. else:
  94. # Suppose it's the transformation for X values
  95. stream_transforms = (stream_transforms, None)
  96. transform_groups[stream_name] = stream_transforms
  97. input_streams = dict(
  98. train=train_datasets,
  99. test=test_datasets)
  100. if other_streams_datasets is not None:
  101. input_streams = {**input_streams, **other_streams_datasets}
  102. if complete_test_set_only:
  103. if len(input_streams['test']) != 1:
  104. raise ValueError('Test stream must contain one experience when'
  105. 'complete_test_set_only is True')
  106. stream_definitions = dict()
  107. for stream_name, dataset_list in input_streams.items():
  108. initial_transform_group = 'train'
  109. if stream_name in transform_groups:
  110. initial_transform_group = stream_name
  111. stream_datasets = []
  112. for dataset_idx in range(len(dataset_list)):
  113. dataset = dataset_list[dataset_idx]
  114. stream_datasets.append(AvalancheDataset(
  115. dataset,
  116. transform_groups=transform_groups,
  117. initial_transform_group=initial_transform_group,
  118. dataset_type=dataset_type))
  119. stream_definitions[stream_name] = (stream_datasets,)
  120. return GenericCLScenario(
  121. stream_definitions=stream_definitions,
  122. complete_test_set_only=complete_test_set_only)
  123. def _adapt_lazy_stream(
  124. generator, transform_groups, initial_transform_group, dataset_type):
  125. """
  126. A simple internal utility to apply transforms and dataset type to all lazily
  127. generated datasets. Used in the :func:`create_lazy_generic_benchmark`
  128. benchmark creation helper.
  129. :return: A datasets in which the proper transformation groups and dataset
  130. type are applied.
  131. """
  132. for dataset in generator:
  133. dataset = AvalancheDataset(
  134. dataset, transform_groups=transform_groups,
  135. initial_transform_group=initial_transform_group,
  136. dataset_type=dataset_type)
  137. yield dataset
  138. class LazyStreamDefinition(NamedTuple):
  139. """
  140. A simple class that can be used when preparing the parameters for the
  141. :func:`create_lazy_generic_benchmark` helper.
  142. This class is a named tuple containing the fields required for defining
  143. a lazily-created benchmark.
  144. - exps_generator: The experiences generator. Can be a "yield"-based
  145. generator, a custom sequence, a standard list or any kind of
  146. iterable returning :class:`AvalancheDataset`.
  147. - stream_length: The number of experiences in the stream. Must match the
  148. number of experiences returned by the generator.
  149. - exps_task_labels: A list containing the list of task labels of each
  150. experience. If an experience contains a single task label, a single int
  151. can be used.
  152. """
  153. exps_generator: Iterable[AvalancheDataset]
  154. """
  155. The experiences generator. Can be a "yield"-based generator, a custom
  156. sequence, a standard list or any kind of iterable returning
  157. :class:`AvalancheDataset`.
  158. """
  159. stream_length: int
  160. """
  161. The number of experiences in the stream. Must match the number of
  162. experiences returned by the generator
  163. """
  164. exps_task_labels: Sequence[Union[int, Iterable[int]]]
  165. """
  166. A list containing the list of task labels of each experience.
  167. If an experience contains a single task label, a single int can be used.
  168. This field is temporary required for internal purposes to support lazy
  169. streams. This field may become optional in the future.
  170. """
  171. def create_lazy_generic_benchmark(
  172. train_generator: LazyStreamDefinition,
  173. test_generator: LazyStreamDefinition,
  174. *,
  175. other_streams_generators: Dict[str, LazyStreamDefinition] = None,
  176. complete_test_set_only: bool = False,
  177. train_transform=None, train_target_transform=None,
  178. eval_transform=None, eval_target_transform=None,
  179. other_streams_transforms: Dict[str, Tuple[Any, Any]] = None,
  180. dataset_type: AvalancheDatasetType = None) \
  181. -> GenericCLScenario:
  182. """
  183. Creates a lazily-defined benchmark instance given a dataset generator for
  184. each stream.
  185. Generators must return properly initialized instances of
  186. :class:`AvalancheDataset` which will be used to create experiences.
  187. The created datasets can have transformations already set.
  188. However, if transformations are shared across all datasets of the same
  189. stream, it is recommended to use the `train_transform`, `eval_transform`
  190. and `other_streams_transforms` parameters, so that transformations groups
  191. can be correctly applied (transformations are lazily added atop the datasets
  192. returned by the generators). The same reasoning applies to the
  193. `dataset_type` parameter.
  194. This function allows for the creation of custom streams as well.
  195. While "train" and "test" streams must be always set, the generators
  196. for other streams can be defined by using the `other_streams_generators`
  197. parameter.
  198. :param train_generator: A proper lazy-generation definition for the training
  199. stream. It is recommended to pass an instance
  200. of :class:`LazyStreamDefinition`. See its description for more details.
  201. :param test_generator: A proper lazy-generation definition for the test
  202. stream. It is recommended to pass an instance
  203. of :class:`LazyStreamDefinition`. See its description for more details.
  204. :param other_streams_generators: A dictionary describing the content of
  205. custom streams. Keys must be valid stream names (letters and numbers,
  206. not starting with a number) while the value must be a
  207. lazy-generation definition (like the ones of the training and
  208. test streams). If this dictionary contains the definition for
  209. "train" or "test" streams then those definition will override the
  210. `train_generator` and `test_generator` parameters.
  211. :param complete_test_set_only: If True, only the complete test set will
  212. be returned by the benchmark. This means that the ``test_generator``
  213. parameter must define a stream with a single experience (the complete
  214. test set). Defaults to False.
  215. :param train_transform: The transformation to apply to the training data,
  216. e.g. a random crop, a normalization or a concatenation of different
  217. transformations (see torchvision.transform documentation for a
  218. comprehensive list of possible transformations). Defaults to None.
  219. :param train_target_transform: The transformation to apply to training
  220. patterns targets. Defaults to None.
  221. :param eval_transform: The transformation to apply to the test data,
  222. e.g. a random crop, a normalization or a concatenation of different
  223. transformations (see torchvision.transform documentation for a
  224. comprehensive list of possible transformations). Defaults to None.
  225. :param eval_target_transform: The transformation to apply to test
  226. patterns targets. Defaults to None.
  227. :param other_streams_transforms: Transformations to apply to custom
  228. streams. If no transformations are defined for a custom stream,
  229. then "train" transformations will be used. This parameter must be a
  230. dictionary mapping stream names to transformations. The transformations
  231. must be a two elements tuple where the first element defines the
  232. X transformation while the second element is the Y transformation.
  233. Those elements can be None. If this dictionary contains the
  234. transformations for "train" or "test" streams then those transformations
  235. will override the `train_transform`, `train_target_transform`,
  236. `eval_transform` and `eval_target_transform` parameters.
  237. :param dataset_type: The type of the datasets. Defaults to None, which
  238. means that the type will be obtained from the input datasets. This
  239. type will be applied to all the datasets returned by the generators.
  240. :returns: A lazily-initialized :class:`GenericCLScenario` instance.
  241. """
  242. transform_groups = dict(
  243. train=(train_transform, train_target_transform),
  244. eval=(eval_transform, eval_target_transform))
  245. if other_streams_transforms is not None:
  246. for stream_name, stream_transforms in other_streams_transforms.items():
  247. if isinstance(stream_transforms, Sequence):
  248. if len(stream_transforms) == 1:
  249. # Suppose we got only the transformation for X values
  250. stream_transforms = (stream_transforms[0], None)
  251. else:
  252. # Suppose it's the transformation for X values
  253. stream_transforms = (stream_transforms, None)
  254. transform_groups[stream_name] = stream_transforms
  255. input_streams = dict(
  256. train=train_generator,
  257. test=test_generator)
  258. if other_streams_generators is not None:
  259. input_streams = {**input_streams, **other_streams_generators}
  260. if complete_test_set_only:
  261. if input_streams['test'][1] != 1:
  262. raise ValueError('Test stream must contain one experience when'
  263. 'complete_test_set_only is True')
  264. stream_definitions = dict()
  265. for stream_name, (generator, stream_length, task_labels) in \
  266. input_streams.items():
  267. initial_transform_group = 'train'
  268. if stream_name in transform_groups:
  269. initial_transform_group = stream_name
  270. adapted_stream_generator = _adapt_lazy_stream(
  271. generator, transform_groups,
  272. initial_transform_group=initial_transform_group,
  273. dataset_type=dataset_type)
  274. stream_definitions[stream_name] = (
  275. (adapted_stream_generator, stream_length), task_labels
  276. )
  277. return GenericCLScenario(
  278. stream_definitions=stream_definitions,
  279. complete_test_set_only=complete_test_set_only)
  280. def create_generic_benchmark_from_filelists(
  281. root: Optional[Union[str, Path]],
  282. train_file_lists: Sequence[Union[str, Path]],
  283. test_file_lists: Sequence[Union[str, Path]],
  284. *,
  285. other_streams_file_lists: Dict[str, Sequence[Union[str, Path]]] = None,
  286. task_labels: Sequence[int],
  287. complete_test_set_only: bool = False,
  288. train_transform=None, train_target_transform=None,
  289. eval_transform=None, eval_target_transform=None,
  290. other_streams_transforms: Dict[str, Tuple[Any, Any]] = None) \
  291. -> GenericCLScenario:
  292. """
  293. Creates a benchmark instance given a list of filelists and the respective
  294. task labels. A separate dataset will be created for each filelist and each
  295. of those datasets will be considered a separate experience.
  296. This helper functions is the best shot when loading Caffe-style dataset
  297. based on filelists.
  298. Beware that this helper function is limited is the following two aspects:
  299. - The resulting benchmark instance and the intermediate datasets used to
  300. populate it will be of type CLASSIFICATION. There is no way to change
  301. this.
  302. - Task labels can only be defined by choosing a single task label for
  303. each experience (the same task label is applied to all patterns of
  304. experiences sharing the same position in different streams).
  305. Despite those constraints, this helper function is usually sufficiently
  306. powerful to cover most continual learning benchmarks based on file lists.
  307. When in need to create a similar benchmark instance starting from an
  308. in-memory list of paths, then the similar helper function
  309. :func:`create_generic_benchmark_from_paths` can be used.
  310. When in need to create a benchmark instance in which task labels are defined
  311. in a more fine-grained way, then consider using
  312. :func:`create_multi_dataset_generic_benchmark` by passing properly
  313. initialized :class:`AvalancheDataset` instances.
  314. :param root: The root path of the dataset. Can be None.
  315. :param train_file_lists: A list of filelists describing the
  316. paths of the training patterns for each experience.
  317. :param test_file_lists: A list of filelists describing the
  318. paths of the test patterns for each experience.
  319. :param other_streams_file_lists: A dictionary describing the content of
  320. custom streams. Keys must be valid stream names (letters and numbers,
  321. not starting with a number) while the value must be a list of filelists
  322. (same as `train_file_lists` and `test_file_lists` parameters). If this
  323. dictionary contains the definition for "train" or "test" streams then
  324. those definition will override the `train_file_lists` and
  325. `test_file_lists` parameters.
  326. :param task_labels: A list of task labels. Must contain at least a value
  327. for each experience. Each value describes the task label that will be
  328. applied to all patterns of a certain experience. For more info on that,
  329. see the function description.
  330. :param complete_test_set_only: If True, only the complete test set will
  331. be returned by the benchmark. This means that the ``test_file_lists``
  332. parameter must be list with a single element (the complete test set).
  333. Alternatively, can be a plain string or :class:`Path` object.
  334. Defaults to False.
  335. :param train_transform: The transformation to apply to the training data,
  336. e.g. a random crop, a normalization or a concatenation of different
  337. transformations (see torchvision.transform documentation for a
  338. comprehensive list of possible transformations). Defaults to None.
  339. :param train_target_transform: The transformation to apply to training
  340. patterns targets. Defaults to None.
  341. :param eval_transform: The transformation to apply to the test data,
  342. e.g. a random crop, a normalization or a concatenation of different
  343. transformations (see torchvision.transform documentation for a
  344. comprehensive list of possible transformations). Defaults to None.
  345. :param eval_target_transform: The transformation to apply to test
  346. patterns targets. Defaults to None.
  347. :param other_streams_transforms: Transformations to apply to custom
  348. streams. If no transformations are defined for a custom stream,
  349. then "train" transformations will be used. This parameter must be a
  350. dictionary mapping stream names to transformations. The transformations
  351. must be a two elements tuple where the first element defines the
  352. X transformation while the second element is the Y transformation.
  353. Those elements can be None. If this dictionary contains the
  354. transformations for "train" or "test" streams then those transformations
  355. will override the `train_transform`, `train_target_transform`,
  356. `eval_transform` and `eval_target_transform` parameters.
  357. :returns: A :class:`GenericCLScenario` instance.
  358. """
  359. input_streams = dict(
  360. train=train_file_lists,
  361. test=test_file_lists)
  362. if other_streams_file_lists is not None:
  363. input_streams = {**input_streams, **other_streams_file_lists}
  364. stream_definitions = dict()
  365. for stream_name, file_lists in input_streams.items():
  366. stream_datasets = []
  367. for exp_id, f_list in enumerate(file_lists):
  368. f_list_dataset = FilelistDataset(root, f_list)
  369. stream_datasets.append(AvalancheDataset(
  370. f_list_dataset,
  371. task_labels=task_labels[exp_id]))
  372. stream_definitions[stream_name] = stream_datasets
  373. return create_multi_dataset_generic_benchmark(
  374. [], [],
  375. other_streams_datasets=stream_definitions,
  376. train_transform=train_transform,
  377. train_target_transform=train_target_transform,
  378. eval_transform=eval_transform,
  379. eval_target_transform=eval_target_transform,
  380. complete_test_set_only=complete_test_set_only,
  381. other_streams_transforms=other_streams_transforms,
  382. dataset_type=AvalancheDatasetType.CLASSIFICATION)
  383. FileAndLabel = Union[Tuple[Union[str, Path], int],
  384. Tuple[Union[str, Path], int, Sequence]]
  385. def create_generic_benchmark_from_paths(
  386. train_lists_of_files: Sequence[Sequence[FileAndLabel]],
  387. test_lists_of_files: Union[Sequence[FileAndLabel],
  388. Sequence[Sequence[FileAndLabel]]],
  389. *,
  390. other_streams_lists_of_files: Dict[str, Sequence[
  391. Sequence[FileAndLabel]]] = None,
  392. task_labels: Sequence[int],
  393. complete_test_set_only: bool = False,
  394. train_transform=None, train_target_transform=None,
  395. eval_transform=None, eval_target_transform=None,
  396. other_streams_transforms: Dict[str, Tuple[Any, Any]] = None,
  397. dataset_type: AvalancheDatasetType = AvalancheDatasetType.UNDEFINED) \
  398. -> GenericCLScenario:
  399. """
  400. Creates a benchmark instance given a sequence of lists of files. A separate
  401. dataset will be created for each list. Each of those datasets
  402. will be considered a separate experience.
  403. This is very similar to :func:`create_generic_benchmark_from_filelists`,
  404. with the main difference being that
  405. :func:`create_generic_benchmark_from_filelists` accepts, for each
  406. experience, a file list formatted in Caffe-style. On the contrary, this
  407. accepts a list of tuples where each tuple contains two elements: the full
  408. path to the pattern and its label. Optionally, the tuple may contain a third
  409. element describing the bounding box of the element to crop. This last
  410. bounding box may be useful when trying to extract the part of the image
  411. depicting the desired element.
  412. Apart from that, the same limitations of
  413. :func:`create_generic_benchmark_from_filelists` regarding task labels apply.
  414. The label of each pattern doesn't have to be an int. Also, a dataset type
  415. can be defined.
  416. :param train_lists_of_files: A list of lists. Each list describes the paths
  417. and labels of patterns to include in that training experience, as
  418. tuples. Each tuple must contain two elements: the full path to the
  419. pattern and its class label. Optionally, the tuple may contain a
  420. third element describing the bounding box to use for cropping (top,
  421. left, height, width).
  422. :param test_lists_of_files: A list of lists. Each list describes the paths
  423. and labels of patterns to include in that test experience, as tuples.
  424. Each tuple must contain two elements: the full path to the pattern
  425. and its class label. Optionally, the tuple may contain a third element
  426. describing the bounding box to use for cropping (top, left, height,
  427. width).
  428. :param other_streams_lists_of_files: A dictionary describing the content of
  429. custom streams. Keys must be valid stream names (letters and numbers,
  430. not starting with a number) while the value follow the same structure
  431. of `train_lists_of_files` and `test_lists_of_files` parameters. If this
  432. dictionary contains the definition for "train" or "test" streams then
  433. those definition will override the `train_lists_of_files` and
  434. `test_lists_of_files` parameters.
  435. :param task_labels: A list of task labels. Must contain at least a value
  436. for each experience. Each value describes the task label that will be
  437. applied to all patterns of a certain experience. For more info on that,
  438. see the function description.
  439. :param complete_test_set_only: If True, only the complete test set will
  440. be returned by the benchmark. This means that the ``test_list_of_files``
  441. parameter must define a single experience (the complete test set).
  442. Defaults to False.
  443. :param train_transform: The transformation to apply to the training data,
  444. e.g. a random crop, a normalization or a concatenation of different
  445. transformations (see torchvision.transform documentation for a
  446. comprehensive list of possible transformations). Defaults to None.
  447. :param train_target_transform: The transformation to apply to training
  448. patterns targets. Defaults to None.
  449. :param eval_transform: The transformation to apply to the test data,
  450. e.g. a random crop, a normalization or a concatenation of different
  451. transformations (see torchvision.transform documentation for a
  452. comprehensive list of possible transformations). Defaults to None.
  453. :param eval_target_transform: The transformation to apply to test
  454. patterns targets. Defaults to None.
  455. :param other_streams_transforms: Transformations to apply to custom
  456. streams. If no transformations are defined for a custom stream,
  457. then "train" transformations will be used. This parameter must be a
  458. dictionary mapping stream names to transformations. The transformations
  459. must be a two elements tuple where the first element defines the
  460. X transformation while the second element is the Y transformation.
  461. Those elements can be None. If this dictionary contains the
  462. transformations for "train" or "test" streams then those transformations
  463. will override the `train_transform`, `train_target_transform`,
  464. `eval_transform` and `eval_target_transform` parameters.
  465. :param dataset_type: The type of the dataset. Defaults to UNDEFINED.
  466. :returns: A :class:`GenericCLScenario` instance.
  467. """
  468. input_streams = dict(
  469. train=train_lists_of_files,
  470. test=test_lists_of_files)
  471. if other_streams_lists_of_files is not None:
  472. input_streams = {**input_streams, **other_streams_lists_of_files}
  473. stream_definitions = dict()
  474. for stream_name, lists_of_files in input_streams.items():
  475. stream_datasets = []
  476. for exp_id, list_of_files in enumerate(lists_of_files):
  477. common_root, exp_paths_list = common_paths_root(list_of_files)
  478. paths_dataset = PathsDataset(common_root, exp_paths_list)
  479. stream_datasets.append(AvalancheDataset(
  480. paths_dataset,
  481. task_labels=task_labels[exp_id]))
  482. stream_definitions[stream_name] = stream_datasets
  483. return create_multi_dataset_generic_benchmark(
  484. [], [],
  485. other_streams_datasets=stream_definitions,
  486. train_transform=train_transform,
  487. train_target_transform=train_target_transform,
  488. eval_transform=eval_transform,
  489. eval_target_transform=eval_target_transform,
  490. complete_test_set_only=complete_test_set_only,
  491. other_streams_transforms=other_streams_transforms,
  492. dataset_type=dataset_type)
  493. def create_generic_benchmark_from_tensor_lists(
  494. train_tensors: Sequence[Sequence[Any]],
  495. test_tensors: Sequence[Sequence[Any]],
  496. *,
  497. other_streams_tensors: Dict[str, Sequence[Sequence[Any]]] = None,
  498. task_labels: Sequence[int],
  499. complete_test_set_only: bool = False,
  500. train_transform=None, train_target_transform=None,
  501. eval_transform=None, eval_target_transform=None,
  502. other_streams_transforms: Dict[str, Tuple[Any, Any]] = None,
  503. dataset_type: AvalancheDatasetType = None) -> GenericCLScenario:
  504. """
  505. Creates a benchmark instance given lists of Tensors. A separate dataset will
  506. be created from each Tensor tuple (x, y, z, ...) and each of those training
  507. datasets will be considered a separate training experience. Using this
  508. helper function is the lowest-level way to create a Continual Learning
  509. benchmark. When possible, consider using higher level helpers.
  510. Experiences are defined by passing lists of tensors as the `train_tensors`,
  511. `test_tensors` (and `other_streams_tensors`) parameters. Those parameters
  512. must be lists containing lists of tensors, one list for each experience.
  513. Each tensor defines the value of a feature ("x", "y", "z", ...) for all
  514. patterns of that experience.
  515. By default the second tensor of each experience will be used to fill the
  516. `targets` value (label of each pattern).
  517. Beware that task labels can only be defined by choosing a single task label
  518. for each experience (the same task label is applied to all patterns of
  519. experiences sharing the same position in different streams).
  520. When in need to create a benchmark instance in which task labels are defined
  521. in a more fine-grained way, then consider using
  522. :func:`create_multi_dataset_generic_benchmark` by passing properly
  523. initialized :class:`AvalancheDataset` instances.
  524. :param train_tensors: A list of lists. The first list must contain the
  525. tensors for the first training experience (one tensor per feature), the
  526. second list must contain the tensors for the second training experience,
  527. and so on.
  528. :param test_tensors: A list of lists. The first list must contain the
  529. tensors for the first test experience (one tensor per feature), the
  530. second list must contain the tensors for the second test experience,
  531. and so on. When using `complete_test_set_only`, this parameter
  532. must be a list containing a single sub-list for the single test
  533. experience.
  534. :param other_streams_tensors: A dictionary describing the content of
  535. custom streams. Keys must be valid stream names (letters and numbers,
  536. not starting with a number) while the value follow the same structure
  537. of `train_tensors` and `test_tensors` parameters. If this
  538. dictionary contains the definition for "train" or "test" streams then
  539. those definition will override the `train_tensors` and `test_tensors`
  540. parameters.
  541. :param task_labels: A list of task labels. Must contain at least a value
  542. for each experience. Each value describes the task label that will be
  543. applied to all patterns of a certain experience. For more info on that,
  544. see the function description.
  545. :param complete_test_set_only: If True, only the complete test set will
  546. be returned by the benchmark. This means that ``test_tensors`` must
  547. define a single experience. Defaults to False.
  548. :param train_transform: The transformation to apply to the training data,
  549. e.g. a random crop, a normalization or a concatenation of different
  550. transformations (see torchvision.transform documentation for a
  551. comprehensive list of possible transformations). Defaults to None.
  552. :param train_target_transform: The transformation to apply to training
  553. patterns targets. Defaults to None.
  554. :param eval_transform: The transformation to apply to the test data,
  555. e.g. a random crop, a normalization or a concatenation of different
  556. transformations (see torchvision.transform documentation for a
  557. comprehensive list of possible transformations). Defaults to None.
  558. :param eval_target_transform: The transformation to apply to test
  559. patterns targets. Defaults to None.
  560. :param other_streams_transforms: Transformations to apply to custom
  561. streams. If no transformations are defined for a custom stream,
  562. then "train" transformations will be used. This parameter must be a
  563. dictionary mapping stream names to transformations. The transformations
  564. must be a two elements tuple where the first element defines the
  565. X transformation while the second element is the Y transformation.
  566. Those elements can be None. If this dictionary contains the
  567. transformations for "train" or "test" streams then those transformations
  568. will override the `train_transform`, `train_target_transform`,
  569. `eval_transform` and `eval_target_transform` parameters.
  570. :param dataset_type: The type of the dataset. Defaults to UNDEFINED.
  571. :returns: A :class:`GenericCLScenario` instance.
  572. """
  573. input_streams = dict(
  574. train=train_tensors,
  575. test=test_tensors)
  576. if other_streams_tensors is not None:
  577. input_streams = {**input_streams, **other_streams_tensors}
  578. stream_definitions = dict()
  579. for stream_name, list_of_exps_tensors in input_streams.items():
  580. stream_datasets = []
  581. for exp_id, exp_tensors in enumerate(list_of_exps_tensors):
  582. stream_datasets.append(AvalancheTensorDataset(
  583. *exp_tensors, dataset_type=dataset_type,
  584. task_labels=task_labels[exp_id]))
  585. stream_definitions[stream_name] = stream_datasets
  586. return create_multi_dataset_generic_benchmark(
  587. [], [],
  588. other_streams_datasets=stream_definitions,
  589. train_transform=train_transform,
  590. train_target_transform=train_target_transform,
  591. eval_transform=eval_transform,
  592. eval_target_transform=eval_target_transform,
  593. complete_test_set_only=complete_test_set_only,
  594. other_streams_transforms=other_streams_transforms,
  595. dataset_type=dataset_type)
  596. __all__ = [
  597. 'create_multi_dataset_generic_benchmark',
  598. 'LazyStreamDefinition',
  599. 'create_lazy_generic_benchmark',
  600. 'create_generic_benchmark_from_filelists',
  601. 'create_generic_benchmark_from_paths',
  602. 'create_generic_benchmark_from_tensor_lists',
  603. ]