← All tutorials

GradNorm (Gradient Normalization)

GradNorm learns one loss weight per task so that every task’s gradient has a similar size and every task learns at a similar pace.

On this page

1 Unequal gradient norms 2 One loss weight per task 3 The GradNorm update 4 The three measurements 5 Target norm and gradient loss 6 Simulation with two tasks 7 Results on two toy systems 8 Implementation in PyTorch 9 When to use GradNorm 10 References

The introduction lists three causes of negative transfer (training tasks together making one of them worse than training it alone) when training on the plain sum of task losses. GradNorm, introduced by Chen, Badrinarayanan, Lee and Rabinovich (2018), fixes the first two, scale and speed. At every training step it measures each task’s gradient norm (the gradient’s length) and how far each task has progressed. It then adjusts one loss weight per task so that each gradient norm moves toward a target, and the target is higher for a task that is behind. Between steps it keeps the K loss weights, their optimizer state and each task’s starting loss. Each step costs one extra gradient per task at the last shared layer, about 5 percent more training time in the paper.

1 Unequal gradient norms

Several tasks share one trunk, the part of the model every task uses; each task also has its own small head. Task losses often sit on very different scales, for example a depth loss near 800 and a classification loss near 2. In the plain sum the larger loss dominates. Even with similar losses, one task can have much larger gradients on the shared parameters, so the trunk moves mostly for that task. Hand-tuned loss weights also go out of date as training progresses.

A task dominates through the size of its gradient, so GradNorm measures and evens out the gradient norm, the gradient’s length. GradNorm is a loss-weighting method: it changes each task’s weight, never the gradients’ directions. Gradient methods such as PCGrad edit directions instead.

Unequal normstask Atask BsumEqual normstask Atask Bsum
Figure 1. The sum follows the longer gradient (left) and lies between equal ones (right).

2 One loss weight per task

With K tasks, GradNorm gives each task i a loss weight wi that multiplies its loss. Every step it adjusts the weights toward two goals. First, every task’s weighted gradient norm should be about the same. Second, a task whose loss is falling more slowly than the others should get a larger gradient norm until it catches up. One hyperparameter, α, sets how strongly the second goal acts.

3 The GradNorm update

Each step has four parts: measure each task’s gradient norm, set each task’s target norm, move the weights toward the targets, and rescale the weights so they sum to K. The weights start at 1. Sections 4 and 5 define each part, and Figure 3 then steps through one update.

repeated every training step; the norms are measured again after each update 1 · Measure gradient norms, loss ratios 2 · Set targets average norm, raised if behind 3 · Update the weights gradient descent on the gap 4 · Rescale the weights weights sum to K, always 1 · Measure gradient norms, loss ratios 2 · Set targets average norm, raised if behind 3 · Update the weights gradient descent on the gap 4 · Rescale the weights weights sum to K, always repeated every training step; the norms are measured again after each update
Figure 2. The four parts of one GradNorm update, with the weights starting at 1.

4 The three measurements

The gradient norm says how strongly each task pushes on the shared weights. The loss ratio says how much of its starting loss each task still has. The relative inverse training rate compares that ratio with the other tasks. The norms are measured only at the last shared layer, whose weights are W; the paper chose it to keep the extra cost small.

4.1 Gradient norm

GradNorm first measures how hard each weighted task pushes the last shared layer.
GW(i) = ‖∇W wiLi‖
GW(i) is the length (norm, the double bars) of the gradient of the weighted loss wiLi with respect to W, the last shared layer’s weights (∇W). A longer gradient moves the shared layer further, so the norm measures how much the task affects the step. The weight is a plain multiplier, so GW(i) equals wi times the unweighted gradient norm: doubling wi doubles the norm.

Running example, NYUv2 indoor photos: semantic segmentation (seg, a class per pixel) and depth (metres per pixel), illustrative.

segdepth
gradient on two shared weights(2, 1)(−6, 2)
GW at w = 12.2366.325
So GW(i) is the loss-scale reading; the eq card in Section 4.2 adds the speed reading, and eq card 1 in Section 5 later sets a target for this length.

4.2 Loss ratio

Dividing each loss by its value at the start of training gives a number with no units: 1 at the start, smaller as the task learns. The paper calls it the inverse training rate, because a small value means the task learned fast. For a classification task whose starting loss depends strongly on the random initialization, the paper suggests the theoretical starting value log C for C classes instead.

The loss ratio is the share of its starting loss a task still has.
Li(t) = Li(t)Li(0)
The gradient lengths of the eq card in Section 4.1 say how hard each task pushes; this ratio adds how far each task has come. Li(t) is task i’s loss at training step t divided by its loss at step 0. It starts at 1 and falls toward 0 as the task learns. Dividing by the task’s own starting loss removes its units and scale, so a depth loss near 800 and a classification loss near 2 become comparable.

Running example (illustrative).

segdepth
loss ratio0.80.5
So the ratio is the speed reading beside the scale reading; the eq card in Section 4.3 compares each ratio to the average.

4.3 Relative inverse training rate

Each task’s loss ratio is then divided by the average ratio over all tasks. A value above 1 means the task is behind the others; below 1 means it is ahead.

The relative inverse training rate says whether a task is behind or ahead of the average task.
ri(t) = Li(t)1K Σj Lj(t)
The ratios are those of the eq card in Section 4.2. ri(t) divides task i’s loss ratio by the average loss ratio over all K tasks (Σj sums over every task j, and 1K turns the sum into an average). Above 1 the task has more of its loss left than the average task. Tasks that slow down together all stay at 1.

Running example, mean ratio 0.65 (illustrative).

segdepth
ri1.231, behind0.769, ahead
So ri turns speed into behind or ahead; eq card 1 in Section 5 raises a behind task’s target by ri to the power α.

5 Target norm and gradient loss

The average fixes the scale problem. The factor fixes the speed problem.

Each task’s target length is the average length, raised for a task that is behind.
Ti = ḠW[ri]α
ri comes from the eq card in Section 4.3, and the lengths averaged into ḠW from the eq card in Section 4.1. The target Ti is the average gradient norm ḠW times [ri]α. The average gives every task the same base norm. The factor is above 1 for a task that is behind (ri above 1) and below 1 for a task that is ahead. At α = 0 the factor is 1 for every task; a larger α spreads the targets further apart.

Running example, ḠW = 4.280 and α = 1.5, the value the GradNorm paper used on NYUv2 (illustrative pair).

segdepth
length now2.2366.325
target Ti5.8442.888
So the target fixes scale with the average and speed with ri; eq card 2 in Section 5 measures the distance to these targets.

GradNorm then defines a loss on the weights that measures how far each norm is from its target, and lowers it with an ordinary optimizer.

The gradient loss adds up how far each task’s length is from its target.
Lgrad = Σi |GW(i) − Ti|
Ti is the target of eq card 1 in Section 5. Lgrad sums, over every task i, the absolute gap between GW(i) and Ti. The absolute value makes a norm that is too large cost the same as one that is too small. Because GW(i) is wi times the unweighted norm, gradient descent on Lgrad lowers the weight of a task above its target and raises the weight of a task below it. It is zero only when every norm equals its target.

Running example at w = 1, Lgrad = 3.608 + 3.437 = 7.045 (illustrative).

segdepth
gap to target3.6083.437
So lowering Lgrad moves each weight until its task’s length meets its target, seg’s up and depth’s down here; eq card 3 in Section 5 keeps the weights from drifting in total.

Two rules keep the weight update well behaved.

  1. The target is held fixed. The target is treated as a constant when the weights are updated. Otherwise shrinking every weight would also shrink the target and lower the loss without balancing anything; the paper does this “to prevent loss weights from spuriously drifting towards zero”.
  2. The weights are rescaled to sum to K after every update. The paper does this “to decouple gradient normalization from the global learning rate”.
After each update the weights are rescaled so they add up to the number of tasks.
Σi wi = K
This rescales the weights that the update on eq card 2 in Section 5 produced. After every update the weights wi are multiplied by KΣi wi, so they sum to K. Equal weights are then all 1, the plain sum. Raising one weight lowers the others, and the overall step size stays set by the network’s learning rate.

Running example, K = 2 (illustrative).

segdepth
weight that hits the target2.6140.457
after rescaling, sum 21.7030.297
So weight moves between tasks instead of vanishing; eq card 4 in Section 5 runs the four lines as one update.

Figure 3. Task 1 is behind with small gradients, task 2 ahead with large ones.

One GradNorm update measures each length, sets each target, closes the gap and rescales the weights.
GW(i) = ‖∇W wiLi‖
Line 1 is the eq card in Section 4.1, line 2 eq card 1 in Section 5, line 3 eq card 2 and line 4 eq card 3. Each task’s norm is its weight times its unweighted gradient norm at W. In the code in Section 8, this is the loop that builds G.
Ti = ḠW[ri]α
Each target is the average norm times ri raised to the power α, so it is higher for a task that is behind. In the code, these are the two T lines.
Lgrad = Σi |GW(i) − Ti|
Lgrad sums each norm’s gap to its target. Its gradient moves only the weights.
Σi wi = K
The weights are rescaled to sum to K, so raising one weight lowers the others.

The stepper’s own toy, not the running example: task 2’s gradient is 100 times longer, and step 2 sets α = 0.5.

task 1task 2
loss ratio0.950.40
ri1.410.59
weight after one step (sum 1.8515)1.00150.85
after rescaling to sum 2about 1.08about 0.92
So one update moves weight toward task 1, the slower and quieter task of the toy (about 1.08 against 0.92), as it moves toward seg in the running example.
GW(i) task i’s gradient norm at WTi task i’s target normḠW the average normΣi wi = K the fixed weight budgetwi the loss weightsri how far behind task i isα how strongly falling behind pulls the target upLgrad the rebalancing lossLi task i's loss‖‖ a vector’s length| | absolute value: drop the sign∇ gradientW the last shared layer's parametersΣi add up over every task i

6 Simulation with two tasks

The simulation is a schematic model, not a real network. Each step, each task’s loss shrinks by about 2 percent times its share of the total gradient norm.

(a) task 1 loss (small gradients), log scale

trained aloneequal weightsGradNormloss halved

(b) the loss weights GradNorm learns (sum 2, α = 0.5)

w1, task 1w2, task 2

Figure 4. GradNorm (purple) raises w1 early, and task 1 learns sooner.

7 Results on two toy systems

The paper built two small artificial systems, one with 2 tasks and one with 10. Each task’s target outputs are multiplied by a different scale σ, so its squared loss grows with σ2. Here σ is only that loss scale, not the noise level of the same name on the Uncertainty Weighting page. The tasks differ only in loss scale, so evening out the gradient norms does all the work. The task-normalized loss divides each task’s loss by its starting loss and sums them, so large and small scales count equally.

Left column, top: the 2-task toy network with loss scales 1.0 and 100.0
Left column, bottom: the 10-task toy network with its ten loss scales

Figure 5. The toy networks and their loss scales σ. From the paper’s Figure 2.

Middle column, top: the two task weights over 25,000 training steps
Middle column, bottom: the ten task weights over 25,000 training steps

Figure 6. Small-σ tasks end with larger weights. From the paper’s Figure 2.

Right column, top: task-normalized loss of the 2-task toy for equal weighting, GradNorm and uncertainty weighting
Right column, bottom: task-normalized loss of the 10-task toy for the same three methods

Figure 7. GradNorm ends below equal weights. From the paper’s Figure 2.

From the paper's Figure 2 (arXiv:1711.02257): “Gradient Normalization on a toy 2-task (top) and 10-task (bottom) system. …”

8 Implementation in PyTorch

GradNorm runs once every training step, on that step’s batch. Its state is the K weights, their optimizer and each task’s starting loss. Its extra cost is one gradient per task down to the last shared layer, plus a second-order term through that layer; the paper measured about 5 percent more training time on NYUv2. The weighted loss is backpropagated as usual, so the heads also receive gradients scaled by wi (Section 3 of Gradient Balancing Inside the Training Loop compares this with methods that write into the shared gradients).

This step follows the paper’s Algorithm 1. W is the last shared layer’s weight tensor, params holds all network parameters, losses holds the K batch-mean losses and L0 the losses at step 0. GRAPH passes create_graph=True to grad, which makes each norm G differentiable with respect to w; RETAIN passes retain_graph=True, which keeps the graph for the network step; detach() holds the target T fixed.

import torch
from torch.autograd import grad
from torch.optim import Adam

ALPHA = 1.5  # NYUv2 in the paper
RETAIN = dict(retain_graph=True)
GRAPH = dict(create_graph=True)

w = torch.ones(K).requires_grad_()
opt_w = Adam([w], lr=0.025)
opt = Adam(params, lr=2e-5)

def gradnorm_step(losses, L0, W):
    L = torch.stack(losses)
    G = []
    for k in range(K):
        wL = w[k] * L[k]
        g_k, = grad(wL, W, **GRAPH)
        G.append(g_k.norm())
    G = torch.stack(G)
    ratio = L.detach() / L0
    r = ratio / ratio.mean()
    T = G.mean() * r ** ALPHA
    T = T.detach()  # fixed target
    L_grad = (G - T).abs().sum()
    gw, = grad(L_grad, w, **RETAIN)

    opt.zero_grad()
    total = (w.detach() * L).sum()
    total.backward()
    opt.step()
    w.grad = gw
    opt_w.step()
    with torch.no_grad():
        w.mul_(K / w.sum())
  1. 1State kept across steps: the weights w start at 1, with their own Adam optimizer.
  2. 2Gradient norm of each weighted loss at W, the eq card in Section 4.1. Keep W one shared layer; a larger W costs more, and the paper does not report its effect on accuracy.
  3. 3Loss ratio, relative inverse training rate r and the fixed target T, the eq cards in Section 4.2, Section 4.3 and Section 5. detach() matters: a target that can move lets every weight shrink together.
  4. 4Lgrad and its gradient with respect to the weights only, part 3 in Figure 2.
  5. 5The ordinary network step on the weighted sum; heads and trunk both get it.
  6. 6Weight step, then rescaling so the weights sum to K, part 4 in Figure 2. Rescale after every weight step, or the weights change the effective learning rate. A large weight learning rate can push a weight below zero; the simulation in Figure 4 keeps them above 0.02.
SettingPaper value (NYUv2)
Weight learning rate0.025 with Adam, about 1250 times the network’s
Network learning rate2×10−5 with Adam
Batch size24
α1.5
Starting weights1
Extra training timeabout 5 percent

The paper does not say how raising or lowering the weight learning rate changes the result. There is no official code. LibMTL ships a version (--weighting GradNorm) that differs from the paper: by default it measures norms over the whole shared encoder instead of the last shared layer, it keeps the weights summing to K through a softmax instead of rescaling, and it trains the heads on the unweighted losses.

1 · Forwardeach task computes its loss2 · Backwardper-task gradients, shared layers3 · Balancecombine the task gradients4 · Clipcap the gradient's length5 · Optimizer stepupdate the network's parameters6 · Logrecord what this step didloss-weighting methods act hereGradNorm reads gradient norms at Wgradient methods act here
Figure 8. Where GradNorm acts in one training step.

Gradient Balancing Inside the Training Loop covers how the weights interact with the optimizer in Sections 9.1 and 7.1.

9 When to use GradNorm

The hyperparameter α sets how strongly a task that is behind is pushed to catch up. Raising it pushes the weights further apart and cuts fast-learning tasks harder; lowering it toward 0 leaves only the equal-norm goal. The more the tasks differ, the larger the best α.

αWhat it means or what the paper found
0Every target is the average norm, so only the gradient norms are equalized
0.12Toy tasks that differ only in loss scale
0.2 to 0.3Face-landmark dataset (MTFL)
1.5NYUv2: depth, surface normals and room-layout keypoints in one network
1.75NYUv2: the depth weight fell below 0.02
0 to 3NYUv2: almost any value beat equal weights
above 2A VGG16 network’s weights became unstable

At α = 0 only the norms are equalized

21task 1 weighttraining steps 0 to 200

The norms are equalized, so the weight rises, but being behind adds nothing.

At α = 0.5 the weight rises further

21task 1 weighttraining steps 0 to 200α = 0

The gap above the α = 0 line is the extra rise from being behind.

At α = 2 the weight rises fastest

21task 1 weighttraining steps 0 to 200α = 0

The weight overshoots a little, then settles.

Figure 9. Task 1’s weight for three α, task 2’s gradient 30×.

Reach for it when tasks have very different loss scales or learn at very different speeds. The classic case is dense prediction, one prediction per pixel, such as segmentation, depth and surface normals in one network.

It costs one extra gradient per task down to the last shared layer, about 5 percent more training time on NYUv2.

It does not come with a convergence proof, and it ignores gradient direction. Two gradients with equal norms can still point against each other.

GradNorm sets the weights from training speed. Uncertainty Weighting sets them from how noisy each task is.

Two methods learn each task’s loss weight (GradNorm and Uncertainty Weighting). Four methods edit the task gradients (PCGrad, GradVac, CAGrad and MGDA). The question each one answers:

MethodThe question it answers
GradNorm (this page)How much weight should each task's loss get so all tasks train at a similar rate? (learned during training from how fast each loss falls)
Uncertainty WeightingHow much weight should each task's loss get, given how noisy that task's targets are? (the noise level is learned along with the model)
PCGradHow should a task gradient be edited when it conflicts with another task's gradient?
GradVacHow should each pair of task gradients be moved toward a target cosine, a running average of that pair's past cosines?
CAGradHow can a step raise the smallest per-task improvement while staying near the average gradient?
MGDAWhich convex combination of task gradients lowers every task's loss at once, and when does no such combination exist?

10 References

  1. Chen, Z., et al. (2018). GradNorm: Gradient Normalization for Adaptive Loss Balancing in Deep Multitask Networks. ICML. arXiv:1711.02257.