Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Understand the Avalanche Package Structure
Welcome to the "Introduction" tutorial of the "From Zero to Hero" series. We will start our journey by taking a quick look at the Avalanche main modules to understand its general architecture.
As hinted in the getting started introduction Avalanche is organized in five main modules:
Benchmarks
: This module maintains a uniform API for data handling: mostly generating a stream of data from one or more datasets. It contains all the major CL benchmarks (similar to what has been done for torchvision).
Training
: This module provides all the necessary utilities concerning model training. This includes simple and efficient ways of implement new continual learning strategies as well as a set pre-implemented CL baselines and state-of-the-art algorithms you will be able to use for comparison!
Evaluation
: This module provides all the utilities and metrics that can help evaluate a CL algorithm with respect to all the factors we believe to be important for a continually learning system. It also includes advanced logging and plotting features, including native Tensorboard support.
Models
: In this module you'll find several model architectures and pre-trained models that can be used for your continual learning experiment (similar to what has been done in torchvision.models). Furthermore, we provide everything you need to implement architectural strategies, task-aware models, and dynamic model expansion.
Logging
: It includes advanced logging and plotting features, including native stdout, file and Tensorboard support (How cool it is to have a complete, interactive dashboard, tracking your experiment metrics in real-time with a single line of code?)
In this series of tutorials, you'll get the chance to learn in-depth all the features offered by each module and sub-module of Avalanche, how to put them together and how to master Avalanche, for a stress-free continual learning prototyping experience!
In the following tutorials we will assume you have already installed Avalanche on your computer or server. If you haven't yet, check out how you can do it following our How to Install guide.
First things first: let's start with a good model!
Welcome to the "Models" tutorial of the "From Zero to Hero" series. In this notebook we will talk about the features offered by the models
Avalanche sub-module.
Every continual learning experiment needs a model to train incrementally. You can use any torch.nn.Module
, even pretrained models. The models
sub-module provides for you the most commonly used architectures in the CL literature.
You can use any model provided in the official ecosystem models as well as the ones provided by !
A continual learning model may change over time. As an example, a classifier may add new units for previously unseen classes, while progressive networks add a new set units after each experience. Avalanche provides DynamicModule
s to support these use cases. DynamicModule
s are torch.nn.Module
s that provide an addition method, adaptation
, that is used to update the model's architecture. The method takes a single argument, the data from the current experience.
For example, an IncrementalClassifier updates the number of output units:
As you can see, after each call to the adaptation
method, the model adds 2 new units to account for the new classes. Notice that no learning occurs at this point since the method only modifies the model's architecture.
Keep in mind that when you use Avalanche strategies you don't have to call the adaptation yourself. Avalanche strategies automatically call the model's adaptation and update the optimizer to include the new parameters.
Some models, such as multi-head classifiers, are designed to exploit task labels. In Avalanche, such models are implemented as MultiTaskModule
s. These are dynamic models (since they need to be updated whenever they encounter a new task) that have an additional task_labels
argument in their forward
method. task_labels
is a tensor with a task id for each sample.
When you use a MultiHeadClassifier
, a new head is initialized whenever a new task is encountered. Avalanche strategies automatically recognizes multi-task modules and provide the task labels to them.
If you want to define a custom multi-task module you need to override two methods: adaptation
(if needed), and forward_single_task
. The forward
method of the base class will split the mini-batch by task-id and provide single task mini-batches to forward_single_task
.
Alternatively, if you only want to convert a single-head model into a multi-head model, you can use the as_multitask
wrapper, which converts the model for you.
You can run this chapter and play with it on Google Colaboratory:
Installing Avalanche has Never Been so Simple
Avalanche has been designed for extreme portability and usability. Indeed, it can be run on every OS and native python environment. 💻🍎🐧
you can install Avalanche with pip:
That's it. Now you can start using Avalanche.
We suggest you to use the pip package, but if you need some recent features you may want to install directly from the master branch. In general, the master branch is well tested and safe to use. However, the API of new features may change more frequently or break backward compatibility. Reproducibility is also easier if you use the pip package.
On Linux, alternatively, you can simply run the install_environment.sh
in the Avalanche home directory. The script takes 2 arguments: --python
and --cuda_version
. Check --help
for details.
You can test your installation by running the examples/test_install.py
script. Make sure to include avalanche into your $PYTHONPATH if you are running examples with the command line interface.
If you want to expand Avalanche and help us improve it (see the "From Zero to Hero" Tutorial). In this case we suggest to create an environment in developer-mode as follows (just a couple of more dependencies will be installed).
Assuming you have Anaconda (or Miniconda) installed on your system, you can follow these simple steps:
Install the avalanche-dev-env
environment and activate it.
Install Pytorch + TorchVision (follow the instructions on the website to use conda).
Update the Conda Environment.
These three steps can be accomplished with the following lines of code:
On Linux, alternatively, you can simply run the install_environment_dev.sh
in the Avalanche home directory. The script takes 2 arguments: --python
and --cuda_version
. Check --help
for details.
You can test your installation by running the examples/test_install.py
script. Make sure to include avalanche into your $PYTHONPATH if you are running examples with the command line interface.
That's it. now we have Avalanche up and running and we can start contribute to it!
You can run this chapter and play with it on Google Colaboratory:
Create your Continual Learning Benchmark and Start Prototyping
Welcome to the "benchmarks" tutorial of the "From Zero to Hero" series. In this part we will present the functionalities offered by the Benchmarks
module.
First off, let's clarify a bit the nomenclature we are going to use, introducing the following terms: Datasets
, Scenarios
, Benchmarks
and Generators
.
By Dataset
we mean a collection of examples that can be used for training or testing purposes but not already organized to be processed as a stream of batches or tasks. Since Avalanche is based on Pytorch, our Datasets are torch.utils.Datasets objects.
By Scenario
we mean a particular setting, i.e. specificities about the continual stream of data, a continual learning algorithm will face.
By Benchmark
we mean a well-defined and carefully thought combination of a scenario with one or multiple datasets that we can use to asses our continual learning algorithms.
By Generator
we mean a function that given a specific scenario and a dataset can generate a Benchmark.
The bechmarks
module offers 3 types of utils:
Datasets: all the Pytorch datasets plus additional ones prepared by our community and particularly interesting for continual learning.
Classic Benchmarks: classic benchmarks used in CL litterature ready to be used with great flexibility.
Benchmarks Generators: a set of functions you can use to create your own benchmark starting from any kind of data and scenario. In particular, we distinguish two type of generators: Specific
and Generic
. The first ones will let you create a benchmark based on a clear scenarios and Pytorch dataset(s); the latters, instead, are more generic and flexible, both in terms of scenario definition then in terms of type of data they can manage.
Specific:
nc_benchmark: given one or multiple datasets it creates a benchmark instance based on scenarios where New Classes (NC) are encountered over time. Notable scenarios that can be created using this utility include Class-Incremental, Task-Incremental and Task-Agnostic scenarios.
ni_benchmark: it creates a benchmark instance based on scenarios where New Instances (NI), i.e. new examples of the same classes are encountered over time. Notable scenarios that can be created using this utility include Domain-Incremental scenarios.
Generic:
filelist_benchmark: It creates a benchmark instance given a list of filelists.
paths_benchmark: It creates a benchmark instance given a list of file paths and class labels.
tensors_benchmark: It creates a benchmark instance given a list of tensors.
dataset_benchmark: It creates a benchmark instance given a list of pytorch datasets.
But let's see how we can use this module in practice!
Let's start with the Datasets
. As we previously hinted, in Avalanche you'll find all the standard Pytorch Datasets available in the torchvision package as well as a few others that are useful for continual learning but not already officially available within the Pytorch ecosystem.
Of course also the basic utilities ImageFolder
and DatasetFolder
can be used. These are two classes that you can use to create a Pytorch Dataset directly from your files (following a particular structure). You can read more about these in the Pytorch official documentation here.
We also provide an additional FilelistDataset
and AvalancheDataset
classes. The former to construct a dataset from a filelist (caffe style) pointing to files anywhere on the disk. The latter to augment the basic Pytorch Dataset functionalities with an extention to better deal with a stack of transformations to be used during train and test.
The Avalanche benchmarks (instances of the Scenario class), contains several attributes that characterize the benchmark. However, the most important ones are the train
and test streams
.
In Avalanche we often suppose to have access to these two parallel stream of data (even though some benchmarks may not provide such feature, but contain just a unique test set).
Each of these streams
are iterable, indexable and sliceable objects that are composed of unique experiences. Experiences are batch of data (or "tasks") that can be provided with or without a specific task label.
It is worth mentioning that all the data belonging to a stream are not loaded into the RAM beforehand. Avalanche actually loads the data when a specific mini-batches are requested at training/test time based on the policy defined by each Dataset
implementation.
This means that memory requirements are very low, while the speed is guaranteed by a multi-processing data loading system based on the one defined in Pytorch.
So, as we have seen, each scenario
object in Avalanche has several useful attributes that characterizes the benchmark, including the two important train
and test streams
. Let's check what you can get from a scenario object more in details:
The train and test streams can be used for training and testing purposes, respectively. This is what you can do with these streams:
Each stream can in turn be treated as an iterator that produces a unique experience
, containing all the useful data regarding a batch or task in the continual stream our algorithms will face. Check out how can you use these experiences below:
Now that we know how our benchmarks work in general through scenarios, streams and experiences objects, in this section we are going to explore common benchmarks already available for you with one line of code yet flexible enough to allow proper tuning based on your needs:
Many of the classic benchmarks will download the original datasets they are based on automatically and put it under the "~/.avalanche/data"
directory.
Let's see now how we can use the classic benchmark or the ones that you can create through the generators (see next section). For example, let's try out the classic PermutedMNIST
benchmark (Task-Incremental scenario).
What if we want to create a new benchmark that is not present in the "Classic" ones? Well, in that case Avalanche offer a number of utilites that you can use to create your own benchmark with maximum flexibility: the benchmarks generators!
The specific scenario generators are useful when starting from one or multiple Pytorch datasets you want to create a "New Instances" or "New Classes" benchmark: i.e. it supports the easy and flexible creation of a Domain-Incremental, Class-Incremental or Task-Incremental scenarios among others.
For the New Classes scenario you can use the following function:
nc_benchmark
for the New Instances:
ni_benchmark
Let's start by creating the MNIST dataset object as we would normally do in Pytorch:
Then we can, for example, create a new benchmark based on MNIST and the classic Domain-Incremental scenario:
Or, we can create a benchmark based on MNIST and the Class-Incremental (what's commonly referred to as "Split-MNIST" benchmark):
Finally, if you cannot create your ideal benchmark since it does not fit well in the aforementioned new classes or new instances scenarios, you can always use our generic generators:
filelist_benchmark
paths_benchmark
dataset_benchmark
tensors_benchmark
Let's start with the filelist_benchmark
utility. This function is particularly useful when it is important to preserve a particular order of the patterns to be processed (for example if they are frames of a video), or in general if we have data scattered around our drive and we want to create a sequence of batches/tasks providing only a txt file containing the list of their paths.
For Avalanche we follow the same format of the Caffe filelists ("path class_label"):
/path/to/a/file.jpg 0 /path/to/another/file.jpg 0 ... /path/to/another/file.jpg M /path/to/another/file.jpg M ... /path/to/another/file.jpg N /path/to/another/file.jpg N
So let's download the classic "Cats vs Dogs" dataset as an example:
You can now see in the content
directory on colab the image we downloaded. We are now going to create the filelists and then use the filelist_benchmark
function to create our benchmark:
In the previous cell we created a benchmark instance starting from file lists. However, paths_benchmark
is a better choice if you already have the list of paths directly loaded in memory:
Let us see how we can use the dataset_benchmark
utility, where we can use several PyTorch datasets as different batches or tasks. This utility expectes a list of datasets for the train, test (and other custom) streams. Each dataset will be used to create an experience:
Adding task labels can be achieved by wrapping each datasets using AvalancheDataset
. Apart from task labels, AvalancheDataset
allows for more control over transformations and offers an ever growing set of utilities (check the documentation for more details).
And finally, the tensors_benchmark
generator:
This completes the "Benchmark" tutorial for the "From Zero to Hero" series. We hope you enjoyed it!
Few words about PyTorch Datasets
This short preamble will briefly go through the basic notions of Dataset offered natively by PyTorch. A solid grasp of these notions are needed to understand:
How PyTorch data loading works in general
How AvalancheDatasets differs from PyTorch Datasets
In PyTorch, a Dataset
is a class exposing two methods:
__len__()
, which returns the amount of instances in the dataset (as an int
).
__getitem__(idx)
, which returns the data point at index idx
.
In other words, a Dataset instance is just an object for which, similarly to a list, one can simply:
Obtain its length using the Python len(dataset)
function.
Obtain a single data point using the x, y = dataset[idx]
syntax.
The content of the dataset can be either loaded in memory when the dataset is instantiated (like the torchvision MNIST dataset does) or, for big datasets like ImageNet, the content is kept on disk, with the dataset keeping the list of files in an internal field. In this case, data is loaded from the storage on-the-fly when __getitem__(idx)
is called. The way those things are managed is specific to each dataset implementation.
The PyTorch library offers 4 Dataset implementations:
Dataset
: an interface defining the __len__
and __getitem__
methods.
TensorDataset
: instantiated by passing X and Y tensors. Each row of the X and Y tensors is interpreted as a data point. The __getitem__(idx)
method will simply return the idx
-th row of X and Y tensors.
ConcatDataset
: instantiated by passing a list of datasets. The resulting dataset is a concatenation of those datasets.
Subset
: instantiated by passing a dataset and a list of indices. The resulting dataset will only contain the data points described by that list of indices.
As explained in the mini How-Tos, Avalanche offers a customized version for all these 4 datasets.
Most datasets from the torchvision libraries (as well as datasets found "in the wild") allow for a transformation
function to be passed to the dataset constructor. The support for transformations is not mandatory for a dataset, but it is quite common to support them. The transformation is used to process the X value of a data point before returning it. This is used to normalize values, apply augmentations, etcetera.
As explained in the mini How-Tos, the AvalancheDataset
class implements a very rich and powerful set of functionalities for managing transformations.
The Dataset
is a very simple object that only returns one data point given its index. In order to create minibatches and speed-up the data loading process, a DataLoader
is required.
The PyTorch DataLoader
class is a very efficient mechanism that, given a Dataset
, will return minibatches by optonally shuffling data brefore each epoch and by loading data in parallel by using multiple workers.
To wrap-up, let's see how the native, non-Avalanche, PyTorch components work in practice. In the following code we create a TensorDataset
and then we load it in minibatches using a DataLoader
.
With these notions in mind, you can start start your journey on understanding the functionalities offered by the AvalancheDatasets by going through the Mini How-Tos.
A Brief Introduction to Avalanche
Avalanche was born within ContinualAI with a clear goal in mind:
Pushing Continual Learning to the next level, providing a shared and collaborative library for fast prototyping, training and reproducible evaluation of continual learning algorithms.
As a powerful avalanche, a Continual Learning agent incrementally improves its knowledge and skills over time, building upon the previously acquired ones and learning how to interact with the external world.
We hope Avalanche may trigger the same positive reinforcement loop within our community, moving towards a more collaborative and inclusive way of doing research and helping us tackle bigger problems, faster and better, but together! 👪
Avalanche has several advantages:
Shared & Coherent Codebase: Aren't you tired of re-inventing the wheel in continual learning? We are. Re-producing paper results has always been daunting in machine learning and it is even more so in continual learning. Avalanche makes you stop re-write your (and other people) code all over again with a coherent and shared codebase that provides already all the utilities, benchmark, metrics and baselines you may need for your next great continual learning research project!
Errors Reduction: The more code we write, the more bugs we introduce in our code. This is the rule, not the exception. Avalanche, let you focus on what really matters: defining your CL solution. Benchmarks preparation to training, evaluation and comparison with other methods will be already there for you. This in turn, massively reduce the amount of errors introduced and the time needed to debug your code.
Faster Prototyping: As researchers or data scientists, we have dozens ideas every day and time is always too little to execute them. However, if we think about it, most of the time spent in bringing our ideas to life is consumed in installing software, preparing and cleaning our data, preparing the experiments code infrastructure and so on. Avalanche lets you focus just on the original algorithmic proposal, taking care of most of the rest!
Improved Reproducibility & Portability: One of the great features of Avalanche, is the possibility of reproducing experimental results easily and on any OS. Researchers can simply plug-in their algorithm into the codebase and see how it goes with respect of other researchers' methods. Their algorithm in turn, is used as a baseline for other methods, creating a virtuous circle. This is only possible thanks to the simple, yet powerful idea of providing shared benchmarks, training and evaluation in a single place.
Improved Modularity: Avalanche has been designed with modularity in mind. As you will learn more about Avalanche, you will realize we have sometimes forego simplicity in favor of modularity and reusability (we hate code replication as you do 🤪). However, we believe this will help us scale in the near future as we collaboratively bring this codebase into maturity.
Increased Efficiency & Scalability: Full-stack researchers & data scientists know this, making your algorithm memory and computationally efficient is tough. Avalanche is already optimized for you, so that you can run your ImageNet continual learning experiment on your 8GB laptop (buy a cooling fan 💨) or even try it on embedded devices of your latest product!
But most of all, Avalanche, can help us standardize our field and work better together, more collaboratively, towards our shared goal of making machines learn over time like humans do.
Avalanche the first experiment of a End-to-end Library for reproducible continual learning research where you can find benchmarks, algorithms, evaluation utilities and much more in the same place.
Let's make it together 👫 a wonderful ride! 🎈
A Short Guide for Researchers on the Run
Avalanche is mostly about making the life of a continual learning researcher easier.
What are the three pillars of any respectful continual learning research project?
Benchmarks
: Machine learning researchers need multiple benchmarks with efficient data handling utils to design and prototype new algorithms. Quantitative results on ever-changing benchmarks has been one of the driving forces of Deep Learning.
Training
: Efficient implementation and training of continual learning algorithms; comparisons with other baselines and state-of-the-art methods become fundamental to asses the quality of an original algorithmic proposal.
Evaluation
: Training utils and Benchmarks are not enough alone to push continual learning research forward. Comprehensive and sound evaluation protocols and metrics need to be employed as well.
With Avalanche, you can find all these three fundamental pieces together and much more, in a single and coherent, well-maintained codebase.
Let's take a quick tour on how you can use Avalanche for your research projects with a 5-minutes guide, for researchers on the run!
In this short guide we assume you have already installed Avalanche. If you haven't yet, check out how you can do it following our How to Install guide.
Avalanche is organized in five main modules:
Benchmarks
: This module maintains a uniform API for data handling: mostly generating a stream of data from one or more datasets. It contains all the major CL benchmarks (similar to what has been done for torchvision).
Training
: This module provides all the necessary utilities concerning model training. This includes simple and efficient ways of implement new continual learning strategies as well as a set pre-implemented CL baselines and state-of-the-art algorithms you will be able to use for comparison!
Evaluation
: This modules provides all the utilities and metrics that can help in evaluating a CL algorithm with respect to all the factors we believe to be important for a continually learning system.
Models
: In this module you'll be able to find several model architectures and pre-trained models that can be used for your continual learning experiment (similar to what has been done in torchvision.models).
Logging
: It includes advanced logging and plotting features, including native stdout, file and Tensorboard support (How cool it is to have a complete, interactive dashboard, tracking your experiment metrics in real-time with a single line of code?)
In the graphic below, you can see how Avalanche sub-modules are available and organized as well:
We will learn more about each of them during this tutorial series, but keep in mind that the Avalanche API documentation is your friend as well!
All right, let's start with the benchmarks module right away 👇
The benchmark module offers three main features:
Datasets: a comprehensive list of PyTorch Datasets ready to use (It includes all the Torchvision Datasets and more!).
Classic Benchmarks: a set of classic Continual Learning Benchmarks ready to be used (there can be multiple benchmarks based on a single dataset).
Generators: a set of functions you can use to generate your own benchmark starting from any PyTorch Dataset!
Datasets can be imported in Avalanche as simply as:
Of course, you can use them as you would use any PyTorch Dataset.
The Avalanche benchmarks (instances of the Scenario class), contains several attributes that describe the benchmark. However, the most important ones are the train
and test streams
.
In Avalanche we often suppose to have access to these two parallel stream of data (even though some benchmarks may not provide such feature, but contain just a unique test set).
Each of these streams
are iterable, indexable and sliceable objects that are composed of experiences. Experiences are batch of data (or "tasks") that can be provided with or without a specific task label.
Avalanche maintains a set of commonly used benchmarks built on top of one or multiple datasets.
What if we want to create a new benchmark that is not present in the "Classic" ones? Well, in that case Avalanche offers a number of utilities that you can use to create your own benchmark with maximum flexibility: the benchmark generators!
The specific scenario generators are useful when starting from one or multiple PyTorch datasets and you want to create a "New Instances" or "New Classes" benchmark: i.e. it supports the easy and flexible creation of a Domain-Incremental, Class-Incremental or Task-Incremental scenarios among others.
Finally, if your ideal benchmark does not fit well in the aforementioned Domain-Incremental, Class-Incremental or Task-Incremental scenarios, you can always use our generic generators:
filelist_scenario
paths_scenario
dataset_scenario
tensor_scenario
You can read more about how to use them the full Benchmarks module tutorial!
The training
module in Avalanche is build on modularity and it has two main goals:
provide a set of standard continual learning baselines that can be easily run for comparison;
provide the necessary utilities to implement and run your own strategy in the most efficient and simple way possible thanks to the building blocks we already prepared for you.
If you want to compare your strategy with other classic continual learning algorithms or baselines, in Avalanche this is as simple as creating an object:
The simplest way to build your own strategy is to create a python class that implements the main train
and eval
methods.
Let's define our Continual Learning algorithm "MyStrategy" as a simple python class:
Then, we can use our strategy as we would do for the pre-implemented ones:
While this is the easiest possible way to add your own strategy, Avalanche supports more sophisticated modalities (based on callbacks) that lets you write more neat, modular and reusable code, inheriting functionality from a parent classes and using pre-implemented plugins.
Check out more details about what Avalanche can offer in this module following the "Training" chapter of the "From Zero to Hero" tutorial!
The evaluation
module is quite straightforward: it offers all the basic functionalities to evaluate and keep track of a continual learning experiment.
This is mostly done through the Metrics and the Loggers. The Metrics provide a set of classes which implements the main continual learning metrics like A_ccuracy_, F_orgetting_, M_emory Usage_, R_unning Times_, etc.
Metrics should be created via the utility functions (e.g. accuracy_metrics
, timing_metrics
and others) specifying in the arguments when those metrics should be computed (after each minibatch, epoch, experience etc...).
The Loggers specify a way to report the metrics (e.g. with Tensorboard, on console or others). Loggers are created by instantiating the respective class.
Metrics and loggers interact via the Evaluation Plugin: this is the main object responsible of tracking the experiment progress. Metrics and loggers are directly passed to the EvaluationPlugin
instance. You will see the output of the loggers automatically during training and evaluation! Let's see how to put this together in few lines of code:
For more details about the evaluation module (how to write new metrics/loggers, a deeper tutorial on metrics) check out the extended guide in the "Evaluation" chapter of the "From Zero to Hero" Avalanche tutorial!
You've learned how to install Avalanche, how to create benchmarks that can suit your needs, how you can create your own continual learning algorithm and how you can evaluate its performance.
Here we show how you can use all these modules together to design your experiments as quantitative supporting evidence for your research project or paper.
You can run this chapter and play with it on Google Colaboratory:
Notebook currently unavailable.
Make it Custom, Make it Yours
Having learned how to use all the Avalanche main features, you may end up willing to customize the framework a little to suit your eagerness of continually better functionalities (as a true continual learner would indeed do! ⚡).
Hence, now is the time to get your hands dirty! 🙌
Take you time to explore the in great detail. We made sure everything is well documented (even if improvable), but try to take a look at the code as well to resolve any uncertainties (of course if you have any question )
You can start by .
We suggest to delve into the code using an appropriate IDE, such as . This will help you navigate the code better and with tons of cool discovery features. Once you have a clear understanding of the entire codebase (or at least the module you'd like to extend/customize) you can start making changes.
If you think your changes may be interesting for the rest of the Continual Learning community, why not contributing back to Avalanche? You can learn how to do it in the next chapter.
You can run this chapter and play with it on Google Colaboratory:
Logging... logging everywhere! 🔮
Welcome to the "Logging" tutorial of the "From Zero to Hero" series. In this part we will present the functionalities offered by the Avalanche logging
module.
In the previous tutorial we have learned how to evaluate a continual learning algorithm in Avalanche, through different metrics that can be used off-the-shelf via the Evaluation Plugin or stand-alone. However, computing metrics and collecting results, may not be enough at times.
While running complex experiments with long waiting times, logging results over-time is fundamental to "babysit" your experiments in real-time, or even understand what went wrong in the aftermath.
This is why in Avalanche we decided to put a strong emphasis on logging and provide a number of loggers that can be used with any set of metrics!
Avalanche at the moment supports four main Loggers:
InteractiveLogger: This logger provides a nice progress bar and displays real-time metrics results in an interactive way (meant for stdout
).
TextLogger: This logger, mostly intended for file logging, is the plain text version of the InteractiveLogger
. Keep in mind that it may be very verbose.
TensorboardLogger: It logs all the metrics on in real-time. Perfect for real-time plotting.
WandBLogger: It leverages tools to log metrics and results on a dashboard. It requires a W&B account.
In order to keep track of when each metric value has been logged, we leverage two global counters
, one for the training phase, one for the evaluation phase. You can see the global counter
value reported in the x axis of the logged plots.
Each global counter
is an ever-increasing value which starts from 0 and it is increased by one each time a training/evaluation iteration is performed (i.e. after each training/evaluation minibatch). The global counters
are updated automatically by the strategy.
If the available loggers are not sufficient to suit your needs, you can always implement a custom logger by specializing the behaviors of the StrategyLogger
base class.
This completes the "Logging" tutorial for the "From Zero to Hero" series. We hope you enjoyed it!
Avalnche Features: Benchmarks, Strategies & Metrics
Avalanche is a framework in constant development. Thanks to the support of the community and its active members we plan to extend its features and improve its usability based on the demands of our research community! A the moment, Avalanche is in Beta (v0.1.0). We support a large number of Benchmarks, Strategies and Metrics, that makes it, we believe, the best tool out there for your continual learning research! 💪
You can find the full list of available features on the .
Do you think we are missing some important features? Please ! We deeply value !
You find a complete list of the features on the .
Avalanche supports all the most popular computer vision datasets used in Continual Learning. Some of them are available in , while other have been integrated by us. Most datasets are automatically downloaded by Avalanche.
Toy datasets: MNIST, Fashion MNIST, KMNIST, EMNIST, QMNIST.
CIFAR: CIFAR10, CIFAR100.
ImageNet: TinyImagenet, MiniImagenet, Imagenet.
Others: EndlessCLDataset, CUB200, OpenLORIS, Stream-51, INATURALIST2018, Omniglot, ...
All the major continual learning benchmarks are available and ready to use. Benchmarks split the datasets and create the train and test streams:
MNIST: SplitMNIST, RotatedMNIST, PermutedMNIST, SplitFashionMNIST.
CIFAR10: SplitCIFAR10, SplitCIFAR100, SplitCIFAR110.
CORe50: all the CORe50 scenarios are supported.
Others: SplitCUB200, CLStream51, OpenLORIS.
Avalanche provides Continual Learning algorithms (strategies). We are continuously expanding the library with new algorithms.
Baselines: Naive, JointTraining, Cumulative.
Rehearsal: Replay with reservoir sampling and balanced buffers, GSS greedy, CoPE.
Regularization: EWC, LwF, GEM, AGEM, CWR*, Synaptic Intelligence.
Architectural: Progressive Neural Networks, multi-head, incremental classifier.
Others: GDumb, iCaRL, AR1, Streaming LDA, LFL.
Avalanche uses and extends pytorch nn.Module
s to define continual learning models:
support for nn.Module
s and torchvision
models.
Dynamic output heads for class-incremental scenarios and multi heads for task-incremental scenarios.
support for architectural strategies and dynamically expanding models such as progressive neural networks.
Avalanche provides continuous evaluation of CL strategies with a large set of Metrics. They are collected and logged automatically by the strategy during the training and evaluation loops.
accuracy, loss, confusion (averaged over streams or experiences).
CL-Metrics: backward/forward transfer, forgetting.
Computational Resources: CPU and RAM usage, MAC, execution times.
Automatic Evaluation with Pre-implemented Metrics
Welcome to the "Evaluation" tutorial of the "From Zero to Hero" series. In this part we will present the functionalities offered by the evaluation
module.
The evaluation
module is quite straightforward: it offers all the basic functionalities to evaluate and keep track of a continual learning experiment.
This is mostly done through the Metrics: a set of classes which implement the main continual learning metrics computation like A_ccuracy_, F_orgetting_, M_emory Usage_, R_unning Times_, etc. At the moment, in Avalanche we offer a number of pre-implemented metrics you can use for your own experiments. We made sure to include all the major accuracy-based metrics but also the ones related to computation and memory.
Each metric comes with a standalone class and a set of plugin classes aimed at emitting metric values on specific moments during training and evaluation.
As an example, the standalone Accuracy
class can be used to monitor the average accuracy over a stream of <input,target>
pairs. The class provides an update
method to update the current average accuracy, a result
method to print the current average accuracy and a reset
method to set the current average accuracy to zero. The call to result
does not change the metric state.
The Accuracy
metric requires the task_labels
parameter, which specifies which task is associated with the current patterns. The metric returns a dictionary mapping task labels to accuracy values.
If you want to integrate the available metrics automatically in the training and evaluation flow, you can use plugin metrics, like EpochAccuracy
which logs the accuracy after each training epoch, or ExperienceAccuracy
which logs the accuracy after each evaluation experience. Each of these metrics emits a curve composed by its values at different points in time (e.g. on different training epochs). In order to simplify the use of these metrics, we provided utility functions with which you can create different plugin metrics in one shot. The results of these functions can be passed as parameters directly to the EvaluationPlugin
(see below).
We recommend to use the helper functions when creating plugin metrics.
The Evaluation Plugin is the object in charge of configuring and controlling the evaluation procedure. This object can be passed to a Strategy as a "special" plugin through the evaluator attribute.
The Evaluation Plugin accepts as inputs the plugin metrics you want to track. In addition, you can add one or more loggers to print the metrics in different ways (on file, on standard output, on Tensorboard...).
It is also recommended to pass to the Evaluation Plugin the benchmark instance used in the experiment. This allows the plugin to check for consistency during metrics computation. For example, the Evaluation Plugin checks that the strategy.eval
calls are performed on the same stream or sub-stream. Otherwise, same metric could refer to different portions of the stream.
These checks can be configured to raise errors (stopping computation) or only warnings.
To implement a standalone metric, you have to subclass Metric
class.
To implement a plugin metric you have to subclass PluginMetric
class
If you want to access all the metrics computed during training and evaluation, you have to make sure that collect_all=True
is set when creating the EvaluationPlugin
(default option is True
). This option maintains an updated version of all metric results in the plugin, which can be retrieved by calling evaluation_plugin.get_all_metrics()
. You can call this methods whenever you need the metrics.
The result is a dictionary with full metric names as keys and a tuple of two lists as values. The first list stores all the x
values recorded for that metric. Each x
value represents the time step at which the corresponding metric value has been computed. The second list stores metric values associated to the corresponding x
value.
Alternatively, the train
and eval
method of every strategy
returns a dictionary storing, for each metric, the last value recorded for that metric. You can use these dictionaries to incrementally accumulate metrics.
This completes the "Evaluation" tutorial for the "From Zero to Hero" series. We hope you enjoyed it!
Design Your Continual Learning Experiments
Welcome to the "Putting All Together" tutorial of the "From Zero to Hero" series. In this part we will summarize the major Avalanche features and how you can put them together for your continual learning experiments.
Here we report a complete example of the Avalanche usage:
Dealing with AvalancheDatasets
The AvalancheDataset
is an implementation of the PyTorch Dataset
class that comes with many useful out-of-the-box functionalities. For most users, the AvalancheDataset can be used as a plain PyTorch Dataset that will return x, y, t
elements. However, the AvalancheDataset is much more powerful than a simple PyTorch Dataset.
A serie of Mini How-Tos will guide you through the functionalities of the AvalancheDataset and its subclasses:
Brefore jumping to the actual Mini How-Tos, we recommend having a look at the basic notions of Dataset and DataLoader by reading the .
How to Contribute Back to the Avalanche Community
The last step to become a real continual learning super-hero ⚡ is to fall into a radioactive dump.☢️ Just kidding, it's much easier than that: you need to contribute back to Avalanche!
There are no superheroes that are not altruistic!
In order to contribute to Avalanche, first of all you need to become familiar with all its features and the codebase structure, so if you have not followed the "From Zero to Hero Tutorial" from the beginning we suggest to do it before starting to make changes.
First of all, if you haven't already. After you've familiarized with the Avalanche codebase you have two roads ahead of you:
You can start working on a (we have dozen of them!)
You can and propose yourself to work on it.
In any of the two cases you'd need to follow the steps below:
⭐_Star_ + 👁️_watch_ the repository.
Fork the repository.
Create or assign an existing issue/feature to yourself.
Make your changes.
The following rules should be respected:
Use PEP8 coding style and work within the 80 columns limit.
Always pull before pushing a commit.
Try to assign to yourself one issue at a time.
Try closing an issue within roughly 7 days. If you are not able to do that, please break it down into multiple ones you can tackle more easily, or you can always remove your assignment to the issue!
If you add a new feature, please include also a test and a usage example in your PR.
Also, before making your PR make sure that the following commands return without any errors:
Otherwise fix them and run again these commands until everything is working correctly. You should also check if everything is working on GPUs, using the env variable USE_GPU=True
:
Faster integrity checks can be run with the env variable FAST_TEST=True
:
Contribute to the Avalanche documentation
To contribute to the documentation you need to follow the steps below:
The notebooks are contained in the folder notebooks
. The folder structure is specular to the documentation, so do not create or delete any folder.
Detect the notebook that you want to edit and do all the modifications 📝
Commit the changes and open a pull request (PR).
If your pull request will be accepted, your edited notebooks will be automatically converted and uploaded to the official Avalanche website 🎊!
Powered by ContinualAI
Avalanche is an End-to-End Continual Learning Library based on , born within with the unique goal of providing a shared and collaborative open-source (MIT licensed) codebase for fast prototyping, training and of continual learning algorithms.
Avalanche can help Continual Learning researchers and practitioners in several ways:
Write less code, prototype faster & reduce errors
Improve reproducibility
Improve modularity and reusability
Increase code efficiency, scalability & portability
Augment impact and usability of your research products
The library is organized in five main modules:
Training
: This module provides all the necessary utilities concerning model training. This includes simple and efficient ways of implement new continual learning strategies as well as a set pre-implemented CL baselines and state-of-the-art algorithms you will be able to use for comparison!
Evaluation
: This modules provides all the utilities and metrics that can help evaluate a CL algorithm with respect to all the factors we believe to be important for a continually learning system.
Let's make it together 👫 a wonderful ride! 🎈
Check out how your code changes when you start using Avalanche! 👇
We know that learning a new tool may be tough at first. This is why we made Avalanche as easy as possible to learn with a set of resources that will help you along the way.
For example, you may start with our 5-minutes guide that will let you acquire the basics about Avalanche and how you can use it in your research project:
We have also prepared for you a large set of examples & snippets you can plug-in directly into your code and play with:
Having completed these two sections, you will already feel with superpowers ⚡, this is why we have also created an in-depth tutorial that will cover all the aspect of Avalanche in details and make you a true Continual Learner! 👨🎓️
A variation of the standard Dataset
exist in PyTorch: the . When using an IterableDataset
, one can load the data points in a sequential way only (by using a tape-alike approach). The dataset[idx]
syntax and len(dataset)
function are not allowed. Avalanche does NOT support IterableDataset
s. You shouldn't worry about this because, realistically, you will never encounter such datasets.
Please refer to the for a complete list. It is recommended to start with the "Creating AvalancheDatasets" Mini How-To.
You can run this chapter and play with it on Google Colaboratory by clicking here:
You can run this chapter and play with it on Google Colaboratory:
and .
You can run this chapter and play with it on Google Colaboratory:
You can run this chapter and play with it on Google Colaboratory:
and #avalanche-dev channel (optional but recommended)
Make a (PR).
Apart from the code, you can also contribute to the Avalanche documentation 📚! We use to write the documentation, so both code and text can be smoothly inserted, and, as you may have noticed, all our documentation can be run on !
You can run this chapter and play with it on Google Colaboratory:
Benchmarks
: This module maintains a uniform API for data handling: mostly generating a stream of data from one or more datasets. It contains all the major CL benchmarks (similar to what has been done for ).
Models
: In this module you'll be able to find several model architectures and pre-trained models that can be used for your continual learning experiment (similar to what has been done in ).
Logging
: It includes advanced logging and plotting features, including native stdout, file and support (How cool it is to have a complete, interactive dashboard, tracking your experiment metrics in real-time with a single line of code?)
Avalanche the first experiment of a End-to-end Library for research & development where you can find benchmarks, algorithms, evaluation metrics and much more, in the same place.
If you used Avalanche in your research project, please remember to cite our reference paper . This will help us make Avalanche better known in the machine learning community, ultimately making a better tool for everyone:
Avalanche is the flagship open-source collaborative project of : a non profit research organization and the largest open community on Continual Learning for AI.
Do you have a question, do you want to report an issue or simply ask for a new feature? Check out the center. Do you want to improve Avalanche yourself? Follow these simple rules on .
The Avalanche project is maintained by the collaborative research team and used extensively by the Units of the consortium, a research network of the major continual learning stakeholders around the world.
We are always looking for new awesome members willing to join the ContinualAI Lab, so check out our if you want to learn more about us and our activities, or .
Learn more about the !
How to implement replay and data loading
Avalanche provides several components that help you to balance data loading and implement rehearsal strategies.
Dataloaders are used to provide balancing between groups (e.g. tasks/classes/experiences). This is especially useful when you have unbalanced data.
Buffers are used to store data from the previous experiences. They are dynamic datasets with a fixed maximum size, and they can be updated with new data continuously.
Finally, Replay strategies implement rehearsal by using Avalanche's plugin system. Most rehearsal strategies use a custom dataloader to balance the buffer with the current experience and a buffer that is updated for each experience.
First, let's install Avalanche. You can skip this step if you have installed it already.
Avalanche dataloaders are simple iterators, located under avalanche.benchmarks.utils.data_loader
. Their interface is equivalent to pytorch's dataloaders. For example, GroupBalancedDataLoader
takes a sequence of datasets and iterates over them by providing balanced mini-batches, where the number of samples is split equally among groups. Internally, it instantiate a DataLoader
for each separate group. More specialized dataloaders exist such as TaskBalancedDataLoader
.
All the dataloaders accept keyword arguments (**kwargs
) that are passed directly to the dataloaders for each group.
Memory buffers store data up to a maximum capacity, and they implement policies to select which data to store and which the to remove when the buffer is full. They are available in the module avalanche.training.storage_policy
. The base class is the ExemplarsBuffer
, which implements two methods:
update(strategy)
- given the strategy's state it updates the buffer (using the data in strategy.experience.dataset
).
resize(strategy, new_size)
- updates the maximum size and updates the buffer accordingly.
The data can be access using the attribute buffer
.
At first, the buffer is empty. We can update it with data from a new experience.
Notice that we use a SimpleNamespace
because we want to use the buffer standalone, without instantiating an Avalanche strategy. Reservoir sampling requires only the experience
from the strategy's state.
Notice after each update some samples are substituted with new data. Reservoir sampling select these samples randomly.
Avalanche offers many more storage policies. For example, ParametricBuffer
is a buffer split into several groups according to the groupby
parameters (None
, 'class', 'task', 'experience'), and according to an optional ExemplarsSelectionStrategy
(random selection is the default choice).
The advantage of using grouping buffers is that you get a balanced rehearsal buffer. You can even access the groups separately with the buffer_groups
attribute. Combined with balanced dataloaders, you can ensure that the mini-batches stay balanced during training.
Avalanche's strategy plugins can be used to update the rehearsal buffer and set the dataloader. This allows to easily implement replay strategies:
And of course, we can use the plugin to train our continual model
Creation and manipulation of AvalancheDatasets and its subclasses.
The AvalancheDataset is an implementation of the PyTorch Dataset class which comes with many out-of-the-box functionalities. The AvalancheDataset (an its few subclass) are extensively used through the whole Avalanche library as the reference way to manipulate datasets:
The dataset carried by the experience.dataset
field is always an AvalancheDataset.
Benchmark creation functions accept AvalancheDatasets to create benchmarks where a finer control over task labels is required.
Internally, benchmarks are created by manipulating AvalancheDatasets.
This first Mini How-To will guide through the main ways you can use to instantiate an AvalancheDataset while the other Mini How-Tos (complete list here) will show how to use its functionalities.
It is warmly recommended to run this page as a notebook using Colab (info at the bottom of this page).
Let's start by installing avalanche:
This mini How-To will guide you through the main ways used to instantiate an AvalancheDataset.
First thing: the base class AvalancheDataset
is a wrapper for existing datasets. Only two things must be considered when wrapping an existing dataset:
Apart from the x and y values, the resulting AvalancheDataset will also return a third value: the task label (which defaults to 0).
The wrapped dataset must contain a valid targets field.
The targets field is available is nearly all torchvision datasets. It must be a list containing the label for each data point (usually the y value). In this way, Avalanche can use that field when instantiating benchmarks like the "Class/Task-Incremental* and Domain-Incremental ones.
Avalanche exposes 4 classes of AvalancheDatasets which map exactly the 4 Dataset classes offered by PyTorch:
AvalancheDataset
: the base class, which acts a wrapper to existing Dataset instances.
AvalancheTensorDataset
: equivalent to PyTorch TesnsorDataset
.
AvalancheSubset
: equivalent to PyTorch Subset
.
AvalancheConcatDataset
: equivalent to PyTorch ConcatDataset
.
Given a dataset (like MNIST), an AvalancheDataset can be instantiated as follows:
Just like any other Dataset, a data point can be obtained using the x, y = dataset[idx]
syntax. When obtaining a data point from an AvalancheDataset, an additional third value (the task label) will be returned:
Useful tip: if you are not sure if you are dealing with a PyTorch Dataset or an AvalancheDataset, or if you want to ignore task labels, you can use this syntax:
The PyTorch TensorDataset is one of the most useful Dataset classes as it can be used to quickly prototype the data loading part of your code.
A TensorDataset can be wrapped in an AvalancheDataset just like any Dataset, but this is not much convenient, as shown below:
Instead, it is recommended to use the AvalancheTensorDataset class to get the same result. In this way, you can just skip one intermediate step.
In both cases, AvalancheDataset will automatically populate its targets field by using the values from the second Tensor (which usually contains the Y values). This behaviour can be customized by passing a custom targets
constructor parameter (by either passing a list of targets or the index of the Tensor to use).
The cell below shows the content of the target field of the dataset created in the cell above. Notice that the targets field has been filled with the content of the second Tensor (y_data).
Avalanche offers the AvalancheSubset
and AvalancheConcatDataset
implementations that extend the functionalities of PyTorch Subset and ConcatDataset.
Regarding the subsetting operation, AvalancheSubset
behaves in the same way the PyTorch Subset
class does: both implementations accept a dataset and a list of indices as parameters. The resulting Subset is not a copy of the dataset, it's just a view. This is similar to creating a view of a NumPy array by passing a list of indexes using the numpy_array[list_of_indices]
syntax. This can be used to both create a smaller dataset and to change the order of data points in the dataset.
Here we create a toy dataset in which each X and Y values are ints. We then obtain a subset of it by creating an AvalancheSubset:
Concatenation is even simpler. Just like with PyTorch ConcatDataset, one can easily concatentate datasets with AvalancheConcatDataset.
Both AvalancheConcatDataset and PyTorch ConcatDataset accept a list of datasets to concatenate.
This Mini How-To showed you how to create instances of AvalancheDataset (and its subclasses).
Other Mini How-Tos will guide you through the functionalities offered by AvalancheDataset. The list of Mini How-Tos can be found here.
Dealing with transformations (groups, appending, replacing, freezing).
AvalancheDataset (and its subclasses like the AvalancheTensor/Subset/ConcatDataset) allow for a finer control over transformations. While torchvision (and other) datasets allow for a minimal mechanism to apply transformations, with AvalancheDataset one can:
Have multiple transformation "groups" in the same dataset (like separated train and test transformations).
Append, replace and remove transformations, even by using nested Subset/Concat Datasets.
Freeze transformations, so that they can't be changed.
The following sub-sections show examples on how to use these features. Please note that all the constructor parameters and the methods described in this How-To can be used on AvalancheDataset subclasses as well. For more info on all the available subclasses, refer to this Mini How-To.
It is warmly recommended to run this page as a notebook using Colab (info at the bottom of this page).
Let's start by installing Avalanche:
AvalancheDatasets can contain multiple transformation groups. This can be useful to keep train and test transformations in the same dataset and to have different set of transformations. This may come in handy in many situations (for instance, to apply ad-hoc transformations to replay data).
As in torchvision datasets, AvalancheDataset supports the two kind of transformations: the transform
, which is applied to X values, and the target_transform
, which is applied to Y values. The latter is rarely used. This means that a transformation group is a pair of transformations to be applied to the X and Y values of each instance returned by the dataset. In both torchvision and Avalanche implementations, a transformation must be a function (or other callable object) that accepts one input (the X or Y value) and outputs its transformed version. This pair of functions is stored in the transform
and target_transform
fields of the dataset. A comprehensive guide on transformations can be found in the torchvision documentation.
In the following example, a MNIST dataset is created and then wrapped in an AvalancheDataset. When creating the AvalancheDataset, we can set train and eval transformations by passing a transform_groups parameter. Train transformations usually include some form of random augmentation, while eval transformations usually include a sequence of deterministic transformations only. Here we define the sequence of train transformations as a random rotation followed by the ToTensor operation. The eval transformations only include the ToTensor operation.
Of course, one can also just use the transform
and target_transform
constructor parameters to set the transformations for both the train and the eval groups. However, it is recommended to use the approach based on transform_groups (shown in the code above) as it is much more flexible.
.train()
and .eval()
The default behaviour of the AvalancheDataset is to use transformations from the train group. However, one can easily obtain a version of the dataset where the eval group is used. Note: when obtaining the dataset of experiences from the test stream, those datasets will already be using the eval group of transformations so you don't need to switch to the eval group ;).
As noted before, transformations for the current group are loaded in the transform
and target_transform
fields. These fields can be changed directly, but this is NOT recommended, as this will not create a copy of the dataset and may probably affect other parts of the code in which the dataset is used.
The recommended way to switch between the train and eval groups is to use the .train()
and .eval()
methods to obtain a copy (view) of the dataset with the proper transformations enabled. This is another very handy feature of the AvalancheDataset: methods that manipulate the AvalancheDataset fields (and transformations) always create a view of the dataset. The original dataset is never changed.
In the following cell we use the avl_mnist_transform dataset created in the cells above. We first obtain a view of it in which eval transformations are enabled. Then, starting from this view, we obtain a version of it in which train transformations are enabled. We want to double-stress that .train()
and .eval()
never change the group of the dataset on which they are called: they always create a view.
One can check that the correct transformation group is in use by looking at the content of the transform/target_transform fields.
In AvalancheDatasets the train and eval transformation groups are always available. However, AvalancheDataset also supports custom transformation groups.
The following example shows how to create an AvalancheDataset with an additional group named replay. We define the replay transformation as a random crop followed by the ToTensor operation.
However, once created the dataset will use the train group. There are two ways to switch to our custom group:
Set the group when creating the dataset using the initial_transform_group
constructor parameter
Switch to the group using the .with_transforms(group_name)
method
The .with_transforms(group_name)
method behaves in the same way .train()
and .eval()
do by creating a view of the original dataset.
The following example shows how to use both methods:
In the standard torchvision datasets the only way to append (that is, add a new transformation step to the list of existing one) is to change the transform field directly by doing something like this:
This solution has many huge drawbacks:
The transformation field of the dataset is changed directly. This will affect other parts of the code that use that dataset instance.
If the initial transform is None
, then Compose
will not complain, but the process will crash later (try it by yourself: replace the first element of Compose in cell above with None
, then try obtaining a data point from the dataset).
If you need to change transformations only temporarly to do some specific things in a limited part of the code, then you need to store the previous set of transformations in some variable in order to switch back to them later.
AvalancheDataset offers a very simple method to append transformations without incurring in those issues. The .add_transforms(transform=None, target_transform=None)
method will append the given transform(s) to the currently enabled transform group and will return a new (a view actually) dataset with given transformations appended to the existing ones. The original dataset is not affected. One can also use .add_transforms_to_group(group_name, transform, target_transform)
to change transformations for a different group.
The next cell shows how to use .add_transforms(...)
to append the to_append_transform transform defined in the cell above.
Note that by using .add_transforms(...)
:
The original dataset is not changed, which means that other parts of the code that use that dataset instance are not affected.
You don't need to worry about None transformations.
In order to revert to the original transformations you don't need to keep a copy of them: the original dataset is not affected!
The replacement operation follows the same idea (and benefits) of the append one. By using .replace_transforms(transform, target_transform)
one can obtain a view of the original dataset in which the transformaations for the current group are replaced with the given ones. One may also change tranformations for other groups by passing the name of the group as the optional parameter group
. As with any transform-related operation, the original dataset is not affected.
Note: one can use .replace_transforms(...)
to remove previous transformations (by passing None
as the new transform).
The following cell shows how to use .replace_transforms(...)
to replace the transformations of the current group:
One last functionality regarding transformations is the ability to "freeze" transformations. Freezing transformations menas permanently glueing transformations to the dataset so that they can't be replaced or changed in any way (usually by mistake). Frozen transformations cannot be changed by using .replace_transforms(...)
or even by changing the transform
field directly.
One may wonder when this may come in handy... in fact, you will probably rarely need to freeze transformations. However, imagine having to instantiate the PermutedMNIST benchmark. You want the permutation transformation to not be changed by mistake. However, the end users do not know how the internal implementations of the benchmark works, so they may end up messing with those transformations. By freezing the permutation transformation, users cannot mess with it.
Transformations for all transform groups can be frozen at once by using .freeze_transforms()
. Transformations can be frozen for a single group by using .freeze_group_transforms(group_name)
. As always, those methods return a view of the original dataset.
The cell below shows a simplified excerpt from the PermutedMNIST benchmark implementation. First, a PixelsPermutation instance is created. That instance is a transformation that will permute the pixels of the input image. We then create the train end test sets. Once created, transformations for those datasets are frozen using .freeze_transforms()
.
In this way, that transform can't be removed. However, remember that one can always append other transforms atop of frozen transforms.
The cell below shows that replace_transforms
can't remove frozen transformations:
This completes the Mini How-To for the functionalities of the AvalancheDataset related to transformations.
Here you learned how to use transformation groups and how to append/replace/freeze transformations in a simple way.
Other Mini How-Tos will guide you through the other functionalities offered by the AvalancheDataset class. The list of Mini How-Tos can be found here.
Continual Learning Algorithms Prototyping Made Easy
Welcome to the "Training" tutorial of the "From Zero to Hero" series. In this part we will present the functionalities offered by the training
module.
First, let's install Avalanche. You can skip this step if you have installed it already.
The training
module in Avalanche is designed with modularity in mind. Its main goals are to:
provide a set of popular continual learning baselines that can be easily used to run experimental comparisons;
provide simple abstractions to create and run your own strategy as efficiently and easily as possible starting from a couple of basic building blocks we already prepared for you.
At the moment, the training
module includes two main components:
Strategies: these are popular baselines already implemented for you which you can use for comparisons or as base classes to define a custom strategy.
Plugins: these are classes that allow to add some specific behaviour to your own strategy. The plugin system allows to define reusable components which can be easily combined together (e.g. a replay strategy, a regularization strategy). They are also used to automatically manage logging and evaluation.
Keep in mind that many Avalanche components are independent from Avalanche strategies. If you already have your own strategy which does not use Avalanche, you can use Avalanche's benchmarks, models, data loaders, and metrics without ever looking at Avalanche's strategies.
If you want to compare your strategy with other classic continual learning algorithm or baselines, in Avalanche you can instantiate a strategy with a couple lines of code.
Most strategies require only 3 mandatory arguments:
model: this must be a torch.nn.Module
.
optimizer: torch.optim.Optimizer
already initialized on your model
.
loss: a loss function such as those in torch.nn.functional
.
Additional arguments are optional and allow you to customize training (batch size, epochs, ...) or strategy-specific parameters (buffer size, regularization strength, ...).
Each strategy object offers two main methods: train
and eval
. Both of them, accept either a single experience(Experience
) or a list of them, for maximum flexibility.
We can train the model continually by iterating over the train_stream
provided by the scenario.
Most continual learning strategies follow roughly the same training/evaluation loops, i.e. a simple naive strategy (a.k.a. finetuning) augmented with additional behavior to counteract catastrophic forgetting. The plugin systems in Avalanche is designed to easily augment continual learning strategies with custom behavior, without having to rewrite the training loop from scratch. Avalanche strategies accept an optional list of plugins
that will be executed during the training/evaluation loops.
For example, early stopping is implemented as a plugin:
In Avalanche, most continual learning strategies are implemented using plugins, which makes it easy to combine them together. For example, it is extremely easy to create a hybrid strategy that combines replay and EWC together by passing the appropriate plugins
list to the BaseStrategy
:
Beware that most strategy plugins modify the internal state. As a result, not all the strategy plugins can be combined together. For example, it does not make sense to use multiple replay plugins since they will try to modify the same strategy variables (mini-batches, dataloaders), and therefore they will be in conflict.
If you arrived at this point you already know how to use Avalanche strategies and are ready to use it. However, before making your own strategies you need to understand a little bit the internal implementation of the training and evaluation loops.
In Avalanche you can customize a strategy in 2 ways:
Plugins: Most strategies can be implemented as additional code that runs on top of the basic training and evaluation loops (Naive
strategy, or BaseStrategy
). Therefore, the easiest way to define a custom strategy such as a regularization or replay strategy, is to define it as a custom plugin. The advantage of plugins is that they can be combined together, as long as they are compatible, i.e. they do not modify the same part of the state. The disadvantage is that in order to do so you need to understand the BaseStrategy
loop, which can be a bit complex at first.
Subclassing: In Avalanche, continual learning strategies inherit from the BaseStrategy
, which provides generic training and evaluation loops. Most BaseStrategy
methods can be safely overridden (with some caveats that we will see later).
Keep in mind that if you already have a working continual learning strategy that does not use Avalanche, you can use most Avalanche components such as benchmarks
, evaluation
, and models
without using Avalanche's strategies!
As we already mentioned, Avalanche strategies inherit from BaseStrategy
. This strategy provides:
Basic Training and Evaluation loops which define a naive (finetuning) strategy.
Callback points, which are used to call the plugins at a specific moments during the loop's execution.
A set of variables representing the state of the loops (current model, data, mini-batch, predictions, ...) which allows plugins and child classes to easily manipulate the state of the training loop.
The training loop has the following structure:
The evaluation loop is similar:
Methods starting with before/after
are the methods responsible for calling the plugins. Notice that before the start of each experience during training we have several phases:
dataset adaptation: This is the phase where the training data can be modified by the strategy, for example by adding other samples from a separate buffer.
dataloader initialization: Initialize the data loader. Many strategies (e.g. replay) use custom dataloaders to balance the data.
model adaptation: Here, the dynamic models (see the models
tutorial) are updated by calling their adaptation
method.
optimizer initialization: After the model has been updated, the optimizer should also be updated to ensure that the new parameters are optimized.
The strategy state is accessible via several attributes. Most of these can be modified by plugins and subclasses:
self.clock
: keeps track of several event counters.
self.experience
: the current experience.
self.adapted_dataset
: the data modified by the dataset adaptation phase.
self.dataloader
: the current dataloader.
self.mbatch
: the current mini-batch. For classification problems, mini-batches have the form <x, y, t>
, where x
is the input, y
is the target class, and t
is the task label.
self.mb_output
: the current model's output.
self.loss
: the current loss.
self.is_training
: True
if the strategy is in training mode.
Plugins provide a simple solution to define a new strategy by augmenting the behavior of another strategy (typically a naive strategy). This approach reduces the overhead and code duplication, improving code readability and prototyping speed.
Creating a plugin is straightforward. You create a class which inherits from StrategyPlugin
and implements the callbacks that you need. The exact callback to use depend on your strategy. You can use the loop shown above to understand what callbacks you need to use. For example, we show below a simple replay plugin that uses after_training_exp
to update the buffer after each training experience, and the before_training_exp
to customize the dataloader. Notice that before_training_exp
is executed after make_train_dataloader
, which means that the BaseStrategy
already updated the dataloader. If we used another callback, such as before_train_dataset_adaptation
, our dataloader would have been overwritten by the BaseStrategy
. Plugin methods always receive the strategy
as an argument, so they can access and modify the strategy's state.
Check StrategyPlugin
's documentation for a complete list of the available callbacks.
You can always define a custom strategy by overriding BaseStrategy
methods. However, There is an important caveat to keep in mind. If you override a method, you must remember to call all the callback's handlers (the methods starting with before/after
) at the appropriate points. For example, train
calls before_training
and after_training
before and after the training loops, respectively. The easiest way to avoid mistakes is to start from the BaseStrategy
method that you want to override and modify it to your own needs without removing the callbacks handling.
Notice that even though you don't use plugins, BaseStrategy
implements some internal components as plugins. Also, the EvaluationPlugin
(see evaluation
tutorial) uses the strategy callbacks.
BaseStrategy
provides the global state of the loop in the strategy's attributes, which you can safely use when you override a method. As an example, the Cumulative
strategy trains a model continually on the union of all the experiences encountered so far. To achieve this, the cumulative strategy overrides adapt_train_dataset
and updates `self.adapted_dataset' by concatenating all the previous experiences with the current one.
Easy, isn't it? :-)
In general, we recommend to implement a Strategy via plugins, if possible. This approach is the easiest to use and requires a minimal knowledge of the BaseStrategy
. It also allows other people to use your plugin and facilitates interoperability among different strategies.
For example, replay strategies can be implemented as a custom strategy of the BaseStrategy
or as plugins. However, creating a plugin is allows to use the replay strategy in conjunction with other strategies.
This completes the "Training" chapter for the "From Zero to Hero" series. We hope you enjoyed it!
To get Answers of Life, Ask Questions
We know that learning a new tool may be tough at times. This is why we are here to help you 🙏
Don't be afraid to ask questions, there are no stupid questions and we will always answer to you.
However, in order to help you, we need you to help us first. First of all, if the question is more of a code issue please use the **** **** page. For general questions, ideas, and discussions use .
If instead, this is a quick question about Avalanche or a request for support, in this case you can ask us directly (#avalanche channel). In any case, please make sure to follow the steps below:
Clarify your information needs.
Formulate them coherently.
Check if the same question or a related one can be found.
Ask your question.
Then we will try to answer as swiftly as possible! 🤗
Help us Find Bug in Avalanche
If you encounter a problem in Avalanche, please do not give up on us and help us fix it as soon as possible**. This first of all means reporting it**. We are grateful to all the people who took the time to report an issue or even fix it with a Pull Request.
Check current Avalanche issue or submit a new one here:
Please try to use the appropriate tags and explain your issue with a simple code snippet to reproduce it.
Help us Design Avalanche of the Future
Do you think an important feature is missing in Avalanche? You are in the right place!
We try to keep the design of Avalanche as open, collaborative and inclusive as possible. This means discussing Avalanche issues, development and future ideas openly through general , its , and .
If you'd like to add a new feature to Avalanche please let us know, so we can work on it, or team up with you to make it a happen! 😄
Features request can be opened on the appropriate . Vote your preferred features and we will try to implement the most voted first!
For a Swift and Effective Contribution
If you are here it means you are considering contributing to Avalanche. It is thanks to people like you that we are making Avalanche a reality! 😍
In order to contribute the this awesome framework we recommend to go through the "From Zero to Hero" Avalanche Tutorial:
In this tutorial you'll learn Avalanche in-depth and learn how to extend and contribute back to the community! In particular, be sure to read the "Contribute to Avalanche" chapter:
At the moment, we don't have a lot of rules for contributing or a strict code of conduct, please enjoy this freedom with a grain of salt! 😁
All the People that Made Avalanche Great
The Project is maintained mostly by ContinualAI Lab members, with the core mission of supporting the production, organization and dissemination of original research on CL with technical research, open source projects and tools that can make the life of a CL researcher easier.
Antonio Carta (Lead Mantainer)
Lorenzo Pellegrini (Mantainer)
Andrea Cossu (Mantainer)
Gabriele Graffieti (Mantainer)
Hamed Hemati (Mantainer)
Vincenzo Lomonaco (Project Manager)
Avalanche is a large community effort. It is only fair to list here all the people who made it a great tool that anyone can use without any restrictions at all!
Tyler Hayes, Matthias De Lange, Marc Masana, Jary Pomponi, Gido van de Ven, Martin Mundt, Qi She, Keiland Cooper, Jeremy Forest, Eden Belouadah, Adrian Popescu, Andreas Tolias, Fabio Cuzzolin, Simone Scardapane, Simone Calderara, Subutai Amhad, Luca Antiga, Christopher Kanan, Joost van de Weijer, Tinne Tuytelaars, Davide Bacciu, German I. Parisi, Razvan Pascanu, Davide Maltoni ...see the full list on GitHub!
Avalanche is a great tool also thanks to its many users. Here we list some research groups using Avalanche for their continual learning research:
ContinualAI Lab (PI: Vincenzo Lomonaco)
Pervasive AI Lab (PI: Davide Bacciu)
BioLab (PI: Davide Maltoni, University of Bologna)
Computational Intelligence & Machine Learning Group (PI: Alessio Micheli, University of Pisa)
Italian Association for Machine Learning (President: Simone Scardapane, Sapienza University)
AIforPeople (President: Marta Ziosi, University of Oxford)
Learning and Machine Perception Team (PI: Joost van de Weijer)
Tinne Tuytelaars’ group (PI: Tinne Tuytelaars)
Machine and Neuromorphic Perception Laboratory (PI: Christopher Kanan)
LASTI Lab (PI: Adrian Popescu)
Visual Artificial Intelligence Laboratory (PI: Fabio Cuzzolin)
Eugenio Culurciello’s group (PI: Eugenio Culurciello)
If you want to contact us don't hesitate to send an email to vincenzo.lomonaco@continualai.org
, contact@continualai.org
, or you can join us on slack and chat with us all! 😃
We are all ears!
Avalanche is a tool from the continual learning research community and for the continual learning research community. We try to keep the design of Avalanche as open, collaborative and inclusive as possible. This is why we are always keen to hear your feedback about Avalanche! Join directly on slack (#avalanche channel) for a quick feedback or write a post on GitHub Discussions!
Happiness is only Real when Shared
Do you want to make Avalanche more suitable for your own research project? Or maybe you just want to learn more about it and sharpen your coding skills in this area?
No matter the reasons, we are always looking for new members that can help help us improve Avalanche and make it a better tool for everyone!
Building something great together 👪 is fun and fulfilling 🎈. Joining our team you will also join a family of mentors and friends that can let you collaborate, fave fun and ultimately achieve more in this area.
No matter your research or coding expertise level you may have, we believe anyone has her own strengths that can help us build a wonderful tool, being passion and time the fundamental ingredients.
So, don't hesistate to contact our team to learn more about how you can help. Do it now! 😊