"They taught me to recognize running in March. In September the same person runs differently, and I have quietly forgotten how they walked. Nobody told me I was allowed to remember both."
A Forgetful AI Agent
Prerequisites
This section assumes the personalization and adaptation machinery of Section 26.4, which bends a model toward one user at one moment; here that moment keeps moving. You should be comfortable with the neural sequence models of Chapter 14 and with detecting when a signal's statistics shift, the change-detection tooling of Chapter 12. The deployment-side counterparts, on-device continual learning under memory limits and streaming updates, are developed in Chapter 62 and Chapter 60; evaluation discipline draws on Chapter 65.
The Big Picture
Personalization tunes a model to a user as they are today. But a person is not a fixed distribution. They recover from an injury and their gait changes; they take up cycling and introduce an activity the model has never seen; they age, and the brisk walk of last year becomes this year's shuffle. Sensors drift too: a watch is worn on the other wrist, a firmware update re-scales the accelerometer, a phone moves from pocket to bag. A model frozen at deployment does not fail loudly; it just falls quietly out of sync with a body and a world that never stop moving. Continual learning updates a model across its whole deployed lifetime: absorb new behavior as it appears, keep what it already knew. The central obstacle is catastrophic forgetting: learning today's behavior at the price of erasing yesterday's competence. This section is about why behavior drifts, why the obvious fix breaks, and the three families of methods that let a deployed activity model keep learning without erasing its own past.
Why behavior drifts and why retraining forgets
Two very different things get lumped together as "drift," and treating them the same causes trouble. In virtual drift (also called covariate shift) the incoming features \(P(x)\) change but the mapping from motion to activity, \(P(y \mid x)\), stays fixed: the same walking is now sampled from a differently worn watch. In real drift (concept drift) the relationship itself moves: the acceleration pattern that meant "jogging" for a healthy user comes to mean "brisk recovery walk" for the same user post-surgery, so the correct label for a near-identical signal has changed. The distinction matters because virtual drift can often be fixed by re-normalizing or re-calibrating the input, while real drift requires the model to learn a new decision, and only the second is a reason to change what the classifier believes.
The tempting response, fine-tune the network on whatever fresh labelled data arrives, runs straight into catastrophic forgetting. Gradient descent on a new task pulls every weight toward minimizing the new loss, with no term protecting the old one, so the shared representation is repurposed and accuracy on earlier activities collapses. This is one face of the stability-plasticity dilemma: a network plastic enough to absorb new behavior is, by the same token, plastic enough to destroy old behavior, and a network stable enough to never forget cannot learn anything new. Every method below is a different bargain struck at this exact tension.
Key Insight
Detection and adaptation are separate decisions, and conflating them is the most common design error. First ask whether to update at all: a drift detector (a change detector from Chapter 12 watching the model's own error rate, or a distance on the feature distribution) tells you something has moved. Only then ask how: whether the shift is virtual (re-calibrate the input, leave the weights alone) or real (update the decision). A system that retrains on every batch is not continually learning; it is continually forgetting, because most batches carry no new concept and each blind update spends model stability for nothing. The unglamorous win is often the update you decided not to make.
Three families that fight forgetting
Continual-learning methods for activity recognition fall into three families, distinguished by what they protect. Replay (rehearsal) keeps a small memory of past examples and mixes them into every update, so the gradient always sees old activities alongside new ones. It is the simplest idea and, on inertial activity data, usually the strongest: a few hundred stored windows per class is often enough to hold the line, because a rehearsal buffer approximates the old data distribution directly rather than trying to summarize it. The cost is storage and, for wearables and health data, the privacy weight of retaining raw user motion.
Regularization methods store no data. They instead add a penalty that discourages moving the weights that mattered for old tasks. Elastic Weight Consolidation (EWC) is the canonical example: after learning, it estimates each parameter's importance with the diagonal of the Fisher information matrix \(F_i\) and, while learning the next task, penalizes movement away from the old optimum \(\theta^{\ast}_i\),
\[ \mathcal{L}(\theta) = \mathcal{L}_{\text{new}}(\theta) + \frac{\lambda}{2} \sum_i F_i \, (\theta_i - \theta^{\ast}_i)^2 . \]Important weights are held nearly rigid while unimportant ones stay free to absorb the new activity. Regularization is memory-light and privacy-friendly, but its protection is approximate and it degrades as many tasks accumulate.
Common Misconception
It is tempting to read the penalty term as a dial with no downside: turn \(\lambda\) up, get proportionally more protection. It does not work that way. Push \(\lambda\) high enough and the old weights become so rigid the network can no longer fit the new activity at all, the same stability-plasticity trade seen from the opposite side. And because EWC's Fisher-diagonal estimate treats parameters as independent when in a real network they are not, its protection is only ever approximate, and it erodes further as more tasks accumulate no matter how large \(\lambda\) is set. Tune \(\lambda\) against measured held-out accuracy on the old activities, not intuition.
The third family, parameter isolation, sidesteps interference by giving new behavior new capacity: a small adapter or a set of masked sub-network weights per context, freezing the rest. It forgets least but grows with the number of contexts, which suits the finite, known activity set of a fitness tracker better than an open-ended stream.
The listing below implements the workhorse of the first family: a class-balanced reservoir replay buffer that maintains a bounded, uniform sample of the stream so that rare activities are not crowded out by common ones.
import numpy as np
class ReplayBuffer:
"""Per-class reservoir sampling: a bounded, uniform memory of past windows."""
def __init__(self, per_class=200, n_features=64, seed=0):
self.per_class = per_class
self.rng = np.random.default_rng(seed)
self.store, self.seen = {}, {} # label -> (X, count-seen)
def add(self, x, y):
if y not in self.store:
self.store[y] = np.zeros((self.per_class, x.size), np.float32)
self.seen[y] = 0
n = self.seen[y]
if n < self.per_class: # buffer not yet full: append
self.store[y][n] = x
else: # full: replace with prob k/n
j = self.rng.integers(0, n + 1)
if j < self.per_class:
self.store[y][j] = x
self.seen[y] = n + 1
def sample(self, k):
xs, ys = [], []
for y, X in self.store.items():
m = min(self.seen[y], self.per_class)
for i in self.rng.integers(0, m, size=max(1, k // len(self.store))):
xs.append(X[i]); ys.append(y)
return np.stack(xs), np.array(ys)
buf = ReplayBuffer(per_class=200)
for x, y in [(np.random.randn(64), lbl) for lbl in np.random.randint(0, 5, 5000)]:
buf.add(x.astype(np.float32), int(y)) # stream one window at a time
Xr, yr = buf.sample(128) # mix these into each new update
print("rehearsal batch:", Xr.shape, "classes:", np.bincount(yr))
buf.sample() into each fine-tuning batch is what turns catastrophic forgetting into a controlled trade.As Listing 26.5 shows, the mechanism that beats forgetting is modest: bounded memory plus balanced sampling. The subtlety is entirely in the sampling policy, which is why hand-rolled buffers tend to quietly starve the classes you most wanted to protect.
The Right Tool
A full continual-learning setup, replay buffers, EWC and its variants, task-aware evaluation, and the bookkeeping that computes forgetting and transfer, is 300 to 500 lines to build correctly and easy to get subtly wrong. The avalanche library (a PyTorch continual-learning framework) reduces the driver code to under 30 lines: wrap your stream as a benchmark, pick a strategy such as Replay(mem_size=...) or EWC(ewc_lambda=...), and its evaluation plugins log accuracy, forgetting, and backward transfer per experience automatically. You supply the activity model and the data stream; the library owns the buffer mechanics and the metrics. Reach for it before writing your own loop; hand-roll only the on-device version of Chapter 62, where the framework will not fit.
In Practice: a post-surgery rehabilitation wearable
A clinic issues ankle-worn inertial monitors to patients recovering from knee replacement, to score exercise adherence and gait quality across a twelve-week program. The recognizer, pre-trained on healthy adults, works in week one; by week three it is failing, and instructively so. The patient's "walking" now includes a limp and a walker, so the healthy-gait template no longer fits (real drift: same label, new signal), while a new prescribed activity, seated knee extensions, never appears in the training set at all. A naive nightly fine-tune fixed both within days but silently destroyed the model's ability to recognize normal walking, so by week ten, once the patient had recovered, the system could no longer tell they were healthy again. The deployed fix was replay: a small per-patient buffer retained early-recovery and healthy-gait exemplars and mixed them into every update alongside the new limping and knee-extension windows, tracking the patient's changing behavior across the full arc of recovery while still recognizing both endpoints, its per-class balance keeping the rare extension exercise from being drowned by ordinary walking windows.
Research Frontier
An open question is whether a model can detect and absorb real drift without a new label. Streaming self-supervised objectives, pretext tasks that build their own training target from the raw motion signal, of the kind introduced in Chapter 17, can flag a distribution shift and nudge the representation toward the new behavior before a clinician or user ever hand-labels a window. Paired with the large pretrained backbones of Chapter 20, whose features already cover much of ordinary human motion, this points toward continual learners whose bulk competence lives in a fixed foundation model while per-user adaptation is a thin, isolated adapter, confining catastrophic forgetting to a component with almost nothing left to forget. The unsolved part: deciding, with no label in hand, whether an unusual window is a new activity worth learning or a fall, a sensor fault, or plain noise worth ignoring.
Evaluating continual learning without fooling yourself
A single accuracy number cannot describe a model that changes over time, and reporting only the final one hides exactly the failure this section is about. Evaluate along the time axis with three quantities computed on held-out data from every stage the model has passed through. Average accuracy after learning stage \(T\) is the mean over all stages \(j \le T\) of accuracy on stage \(j\)'s test set. Backward transfer (forgetting) measures how much learning later stages hurt earlier ones: with \(a_{T,j}\) the accuracy on stage \(j\) after training through stage \(T\),
\[ \mathrm{BWT} = \frac{1}{T-1} \sum_{j=1}^{T-1} \left( a_{T,j} - a_{j,j} \right), \]where a large negative value is catastrophic forgetting and a small positive value means later behavior actually reinforced earlier competence. Forward transfer asks the complementary question: does what the model already learned make it faster to pick up the next behavior? Measure it by comparing accuracy on stage \(T\)'s task after a few gradient steps from the continual model against the same steps from a randomly initialized one; a positive gap means earlier stages built reusable structure, shared gravity-axis alignment, gait periodicity, that the new activity can draw on. It matters because BWT alone can flatter a method that only avoids interference: a replay buffer can hold BWT near zero while contributing nothing to how fast stage three is learned. Check forward transfer whenever a new context should resemble the old ones, a new gait variant rather than an unrelated activity, since that is exactly when reusable structure should pay off. The right online protocol is prequential (test-then-train): predict and score each incoming window, then use it to update, so every example is a genuine test before it is ever a training point. The leakage rule from Chapter 65 bites with special force here: because consecutive windows are correlated in time, a random split leaks the near-future into training and makes a forgetful model look stable. Split by contiguous time and by subject, and never let a replay buffer's contents leak into the test set. Continual learning is the temporal sibling of the test-time adaptation and distribution-shift methods of Chapter 66; the difference is that the model keeps the update, so measuring what it lost matters as much as what it gained.
Exercise
Build a three-stage continual stream from a subject in PAMAP2 or a similar dataset: stage 1 = {walk, sit, stand}, stage 2 adds {ascend stairs, descend stairs}, stage 3 introduces a simulated real drift by re-labelling a perturbed "walk" as a new "recovery walk" class. Train (a) a plain fine-tuning baseline, (b) EWC, and (c) the reservoir replay of Listing 26.5. After each stage, evaluate on the held-out test sets of all stages seen so far and report average accuracy and BWT. Show that fine-tuning has strongly negative BWT, that replay with a few hundred windows per class largely closes the gap, and that EWC lands in between. Then rerun with a random window split instead of a time-and-subject split and quantify how much it flatters the forgetful baseline.
Self-Check
1. Distinguish virtual drift from real (concept) drift with an activity-recognition example of each, and explain why only one of them is a reason to change the classifier's weights.
2. State the stability-plasticity dilemma and place replay, EWC, and parameter isolation on the trade it describes: what does each one protect, and at what cost?
3. A continual model reports 91% accuracy on its most recent activity but its backward-transfer score is -22%. What has happened, and why would a single final-accuracy number have hidden it?
What's Next
In Section 26.6, we widen the lens from one changing user to a whole population. A model that learns continually still learns from whoever generates the most data, and behavior varies not only over time but across bodies, ages, and demographics. We take up fairness across users: how activity recognizers come to work well for some groups and poorly for others, how to measure that gap, and how to close it.