Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Open In Colab   Open in Kaggle

Tutorial 2: Continual learning

Week 2, Day 4: Macro-Learning

By Neuromatch Academy

Content creators: Hlib Solodzhuk, Ximeng Mao, Grace Lindsay

Content reviewers: Aakash Agrawal, Alish Dipani, Hossein Rezaei, Yousef Ghanbari, Mostafa Abdollahi, Hlib Solodzhuk, Ximeng Mao, Samuele Bolotta, Grace Lindsay, Alex Murphy

Production editors: Konstantine Tsafatinos, Ella Batty, Spiros Chavlis, Samuele Bolotta, Hlib Solodzhuk, Alex Murphy


Tutorial Objectives

Estimated timing of tutorial: 25 minutes

In this tutorial, we will discover how further training on new data or tasks causes forgetting of past tasks. This is like the idea of learning a new idea by replacing an old one. This is a huge issue with the current AI models and deep neural networks and a very active area of research in the ML community. We are going to explore the problem in more detail and investigate some further issues connected to this idea, for example, how different learning schedules impact performance.


Setup

Install and import feedback gadget

Source

Imports

Source

Figure settings

Source

Plotting functions

Source

Set random seed

Source

Video 1: Continual learning

Youtube
Bilibili

Section 1: Catastrophic Forgetting

In this section, we will discuss the concept of continual learning and argue that training on new data does not guarantee that the model will remember how to handle the tasks it was trained on earlier. First it’s important to state that there are multiple ways to train some ML models. Often a model will take a training dataset and run a learning algorithm over it in a few steps and derive a solution resulting in a trained model. This is what happens in analytical solutions for linear regression, in Support Vector Machine training etc. In other cases, models can learn by being iteratively updated with single data points (or batches). This type of model can support online learning and it is specifically these models that have the potential to undergo catastrophic forgetting. Modern deep neural networks are all online learners, as are methods that are trained with variants of gradient descent. The problems of continual learning only exist for models that can be paused and then resumed with new training data, which has the potential to interact with a previous model that was also trained on prior data.

  • Catastrophic forgetting occurs when a neural network, or any machine learning model, forgets the information it previously learned upon learning new data. This is particularly problematic in scenarios where a model needs to perform well across multiple types of data or tasks that evolve over time.

  • Continual learning is an approach in machine learning that aims to mitigate the issues of catastrophic forgetting. The goal is to develop algorithms that can adapt to new data while preserving knowledge about the old data. This is essential for applications where the model must adapt to changes dynamically without losing the ability to perform tasks it was previously trained on.

Coding Exercise 1: Fitting new data

We’re back at the fruit stall. Recall the modelling problem from Tutorial 1. Let’s assume now that we want our model to predict not only the summer prices but also the autumn ones. We have already trained the MLP to predict summer months effectively but observed that it performs poorly during the autumn period. Let’s try to make the model learn new information about the prices and see whether it can remember both.

First, we will need to retrain the model for this tutorial on summer days.

R-squared value is: 0.98.

Now, let’s incrementally fit the autumn data to the trained model and monitor the R-squared values for the summer and autumn data test sets during each iteration. In the following code snippet, you are requested to complete further training using the partial_fit function, which allows us to train the existing model on new data (it runs through the data only once, and thus, we can control for the number of iterations). As we iterate through the epochs, we can append new R-squared values for each epoch. We will visually explore the performance of this model on both the summer and autumn datasets as well as R-squared values progression over epochs.

---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[8], line 3
      1 ###################################################################
      2 ## Fill out the following then remove
----> 3 raise NotImplementedError("Student exercise: complete partial fit and calculate r-squared values for both summer and autumn data")
      4 ###################################################################
      5 
      6 # Initial r-squared calculations
      7 summer_r_squared = [base_model.score(summer_days_test_norm, summer_prices_test)]

NotImplementedError: Student exercise: complete partial fit and calculate r-squared values for both summer and autumn data

Click for solution

Example output:

Solution hintSolution hint

Notice how disruptive the change is for R-squared values — even one iteration is enough to drastically alter the performance. The model has learned to perform perfectly on the autumn data, while it completely disrupts predictions for the summer days. Indeed, the model forgot the relationships for the old data and lost its predictive power while training on the new dataset. In the next section of the tutorial, we are going to explore a different approach—what if, instead of training sequentially, we train the model on both datasets together?


Section 2: Joint training

Estimated timing to here from start of tutorial: 10 minutes

In this section, we are going to explore whether joint training on both datasets simultaneously, specified in different formats, improves predictive performance, thus allowing the model to perform well in both summer and autumn.

Coding Exercise 2a: Sequential joint training

In this coding exercise, let us take a look at the following setup: we will sample KK distinct random training examples from summer data and KK random examples from autumn, training the model in total on 2K2K examples.

In sequential joint training, epochs of each data type are alternated. So, for example, the first epoch will be the KK examples from summer data, and then the second will be the KK examples from autumn data, then the summer data again, then autumn again, and so on.

Please complete the partial fits for the corresponding data to implement sequential joint training in the coding exercise. We are using the partial_fit function to specify individual updates to the model. The scikit-learn library typically exposes a fit API whose goal is to specify full training on a dataset. However, if control over sequential training is desired, where you want to specify individual batches of data of a certain type, then models that expose a partial_fit function are great ways to accomplish this. In the language of training deep learning models, fit is similar to train_model() while partial_fit is more similar to update_batch().

Every call to partial_fit takes the model from the previous call and continually updates the parameters from the previous step, in the same way that in deep neural networks, each batch update builds upon the adjusted network weights from the previous backpropagation step.

Training Progress:   0%|          | 0/50 [00:00<?, ?it/s]
Training Progress:   0%|          | 0/50 [00:00<?, ?it/s]

---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[9], line 46
     43 num_epochs = 100
     44 K = 30
---> 46 sequential_training_model, summer_r_squared, autumn_r_squared = sequential_training(K, num_epochs)
     48 plot_performance(num_epochs, summer_r_squared, autumn_r_squared)
     50 #predict for test sets

Cell In[9], line 23, in sequential_training(K, num_epochs)
     18 autumn_r_squared = []
     20 for _ in tqdm(range(num_epochs // 2), desc="Training Progress"):
     21     ###################################################################
     22     ## Fill out the following then remove
---> 23     raise NotImplementedError("Student exercise: sample indices for summer and autumn data and sequentially train on summer and then on autumn data")
     24     ###################################################################
     25 
     26     # Sample random training examples from summer and autumn
     27     sampled_summer_indices = np.random.choice(np.arange(summer_days_train_norm.shape[0]), size=K, replace=False)

NotImplementedError: Student exercise: sample indices for summer and autumn data and sequentially train on summer and then on autumn data

Click for solution

Example output:

Solution hintSolution hint

As we can see, this approach performs better than first fully learning from the summer data and then learning from the autumn data. Sequential joint training helps maintain the model’s performance across both datasets by continually refreshing its memory with information from both periods. This method prevents the model from completely forgetting the relationships learned from the first dataset while training on the second.

Coding Exercise 2b: Interspersed training

Now, we will try fully interspersed training. Unlike sequential joint training, in this approach, we will generate epochs that contain both summer and autumn data, exposing the model to both sets equally and simultaneously.

In this exercise, you are tasked with completing the code snippets that correspond to creating the labels for the interspersed epochs and training the model. This method aims to integrate the data from both periods within each training epoch, which can help in achieving a more balanced and robust model performance across different seasonal datasets.

Training Progress:   0%|          | 0/50 [00:00<?, ?it/s]
Training Progress:   0%|          | 0/50 [00:00<?, ?it/s]

---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[10], line 43
     40 num_epochs = 50
     41 K = 30
---> 43 interspersed_training_model, summer_r_squared, autumn_r_squared = interspersed_training(K, num_epochs)
     45 plot_performance(num_epochs, summer_r_squared, autumn_r_squared)
     47 #predict for test sets

Cell In[10], line 29, in interspersed_training(K, num_epochs)
     26 mixed_days_train = np.expand_dims(np.append(autumn_days_train_norm[sampled_autumn_indices], summer_days_train_norm[sampled_summer_indices]), 1)
     27 ###################################################################
     28 ## Fill out the following then remove
---> 29 raise NotImplementedError("Student exercise: make price labels for mixed epochs and train")
     30 ###################################################################
     31 mixed_prices_train = ...

NotImplementedError: Student exercise: make price labels for mixed epochs and train

Click for solution

Example output:

Solution hintSolution hint

Coding Exercise 2 Discussion

  1. Note that the number of epochs is doubled in sequential training mode compared to interspersed mode. Why is this the case?

  2. Which training scheduler performed better in this particular example? Why do you think this occurred?


Summary

Estimated timing of tutorial: 25 minutes

Here is a summary of what we’ve learned:

  1. Simply continuing to train on a new data distribution causes catastrophic forgetting

  2. Joint training, wherein different datasets are interspersed to varying degrees, helps fight catastrophic forgetting.

You can explore more advanced methods of continual learning in the following resources:

The Big Picture

What causes catastrophic forgetting? If we train tasks continually (one after the other) and not in a joint fashion, it implies the overwriting of old knowledge (information) with new knowledge (information). That doesn’t seem to happen in biological systems, so is there a lesson we can take from psychology and neuroscience to better handle catastrophic forgetting? Information seems to be distributed across all weights for this overwriting to happen. Large LLM models have developed one solution, the so-called Mixture-of-Experts Model. This is where a routing mechanism decides what sections of a neural network become active for each tasks. Is that a viable solution? These models are gigantic and extremely computationally expensive. We think there is scope to be more brain-like without requiring such vast computational giants.

If you’re interested in learning more, the topics we covered today are also often referred to as the Stability-Plasticity Dilemma. A search for that term will certainly bring you to many recent advances in exploring this idea.

But before you do that, let’s first prepare ourselves for the next tutorial on Meta-Learning. See you there!