Concepts / Backpropagation and Weight Updates

Backpropagation and Weight Updates

Identical starting weights make nodes in a layer perform the same operations and receive the same updates, so they never learn different features.

  • Programming

A Tidy Start That Causes Trouble

When you first build a neural network, it is tempting to give every weight the same starting value. Zero, or any single constant, looks tidy and predictable. If every weight matches, there is nothing to puzzle over when you print a weight matrix, and the setup feels like the safe choice. This article addresses that misconception directly: identical starting weights are a trap, not a convenience. The rest of the article explains why training needs each node to begin in a slightly different place, how small random starting values provide that difference, and how to make those random values repeatable when you need to compare or debug runs.

Predicting What Identical Nodes Do

Before reading the explanation, try a prediction. Suppose two hidden nodes in the same layer start with exactly the same weights and receive the same input. What do you expect to happen to those two nodes after training updates the weights?

What do you think happens?

Two hidden nodes start with the same weights and receive the same input. After training updates, do they become different?

  • They become different, because training always separates nodes

  • They stay identical, because they receive identical updates

  • Only one of them changes, because the other is a copy

Reveal answer
Answer:

They stay identical, because they receive identical updates.

Identical weights and identical inputs make both nodes perform the same operations. The same training signal then produces the same update for each, so they never learn different features.

Symmetry Between Nodes

Definition

Symmetry is the situation in which nodes are interchangeable, because they start identical and are updated identically. When two nodes in a layer are symmetric, swapping one for the other changes nothing about what the network computes or learns.

Identical starting weights make nodes in a layer perform the same operations and receive the same updates, so they never learn different features. Training therefore needs this symmetry broken. Each node must begin in a slightly different place so that gradient updates push different nodes toward different useful patterns. Only then can a network build the varied internal representations that let it map inputs to outputs in complicated ways.

Node 1weights 0.5, 0.5Node 1 after updateidentical to Node 2Node 2weights 0.5, 0.5Node 2 after updateidentical to Node 1same updatesame update
The top pair of nodes starts with identical weights and receives the same input, so the same update is applied to both and they stay identical. The bottom pair starts from different values, so the same training signal affects each node differently and the layer can develop distinct features.

The diagram shows the identical case in the top row and the case with differing starting values in the bottom row. The training signal is the same in both cases. The difference lies entirely in the starting point, and that small difference at initialization is what allows the layer to develop distinct features. The numbers 0.5 in the diagram are only placeholders for a shared starting value; the point is that the two nodes match.

How Training Updates Reach Each Node

Training repeats a cycle. The network produces an output from its current weights, the output is compared with what was wanted, and backpropagation determines how each weight should change to reduce the mismatch. The weight update step then applies those changes. The flow below shows that cycle, with the error signal carried backward from the output to the weights that produced it.

InputHidden layerweightsOutputErroroutput versus targetGradientsone per weightUpdated weightsused in next cycleforwardforwardcomparebackpropagateapply update
Input moves forward through the hidden layer to the output. The comparison with the target produces an error, which backpropagation turns into gradients for each weight. The update step uses those gradients to set new weight values, and the next cycle begins from them.

The source describes the consequence of this cycle for symmetric nodes. If two nodes share weights and receive the same input, the gradients computed for their weights are the same, so the update step moves them identically. Backpropagation cannot separate nodes that the starting values have made indistinguishable. This is why the starting values, not the update rule, must supply the initial difference.

Why Starting Values Are Random and Small

The source specifies the remedy for symmetry: initialize weights with small random numbers. Each node then receives a different starting point, so the nodes can diverge during learning instead of acting as copies of one another. The source describes random initialization as the desired approach for this reason. Two properties of the starting values matter, and each does a different job.

Values Change Between Instantiations

Another property is easy to observe. Each time you create a network, its random values differ. Two separately instantiated networks do not start from the same weights, so the weight matrix you print will usually look different from one run to the next. That behavior is expected, and it is exactly the variation that breaks symmetry.

python
Notes on the code
  • nn.Linear(3, 2) creates a layer with 2 output nodes, each holding 3 weights
  • Each call draws a fresh set of random values
  • torch.equal returns True only when every value matches

Run this code and the two printed matrices will usually differ, and the final comparison will usually print False. The exact numbers depend on the random stream, so they are not something to memorize. The lesson is that independent instantiations start from different values, which is the expected behavior.

Reproducing Starting Weights with a Seed

Randomness has a practical cost. If every run produces different weights, you cannot easily compare results, debug a problem, or confirm that a change you made actually changed the outcome. The source resolves this by keeping the random values but making them repeatable. You seed PyTorch's random number generator with torch.manual_seed. Setting a seed before creating the network means the same sequence of random numbers is produced each time, so the initial weights come out the same across runs.

Definition

A seed is a setting on the random number generator, not on any particular model. Setting the same seed before the same sequence of random draws produces the same sequence of values, which is what makes initial weights reproducible.

python
Notes on the code
  • The first seed call resets the generator before run_one is created
  • The second seed call resets it again before run_two is created
  • Both layers draw the same sequence of random values

With both seed calls in place, the final comparison should print True. Reproducibility comes from resetting the generator before each draw, not from anything about the network itself. If you forget the second seed call, the two networks will differ, and that mismatch is a fact about the random number stream rather than a bug in the architecture.

Where the Seed Must Be Placed

The position of the seed call in the code matters. It must come before the network is created, because the weights are drawn at the moment of instantiation. A seed placed after the model is built has no effect on the weights that model already received. The worked example below traces this with a seed placed too late.

Worked example

Seeding after the model is built

A learner wants two layers to start from identical weights, so they write the seed call after creating the first layer. Will the two layers match?

  1. 1
    Create the first layer

    nn.Linear draws its random weights at this moment, using whatever state the generator is in.

  2. 2
    Seed the generator

    torch.manual_seed(0) resets the generator, but the first layer has already received its weights, so this call cannot change them.

  3. 3
    Create the second layer

    The second draw happens after the reset, so it produces a sequence that may differ from the first layer's values.

  4. 4
    Correct the order

    Moving the seed call before the first layer is created means both draws start from the same generator state, which produces matching weights.

Result

The seed must be set before each network is created. A seed placed after a model is built affects only the draws that come after it.

Mistakes When Initializing and Seeding

  • Common mistake

    Giving every weight the same constant value to make the weights easy to inspect

    What it looks like

    layer.weight.fill_(0.5) applied to every node in a hidden layer

    Why it fails

    Identical weights with identical inputs produce identical updates, so the nodes never learn different features.

    Do this instead

    Start from small random values so each node begins from a different point.

  • Common mistake

    Placing torch.manual_seed after the model has been created

    What it looks like

    Creating two layers, then calling torch.manual_seed(0) and expecting the earlier layers to match

    Why it fails

    Weights are drawn when the network is instantiated, so a later seed does not affect weights already drawn.

    Do this instead

    Call torch.manual_seed before each network is created.

  • Common mistake

    Assuming two runs will match without any seed

    What it looks like

    Printing the weight matrix in two separate runs and expecting identical numbers

    Why it fails

    Each instantiation draws new random values, so the matrices usually differ.

    Do this instead

    Set a seed before creating the network when you need reproducible starting weights.

  • Common mistake

    Treating the seed as a property of the model rather than of the random number generator

Practice Seeding Two Layers

EASY

Write a short script that creates two nn.Linear(4, 3) layers, each after its own torch.manual_seed call with the same value, and prints whether their weights match. Then change the second seed value and predict whether the comparison still prints True before running it.

Hints
  • Place each torch.manual_seed call on the line directly before the layer it should affect.
  • Use torch.equal to compare the weight tensors.
  • Two different seed values produce two different random streams, so the weights should differ.

Key Takeaways

  • Identical starting weights make nodes in a layer perform the same operations and receive the same updates, so they never learn different features.
  • Training needs symmetry broken at initialization, and small random starting values give each node a different point to diverge from.
  • Random starting values differ each time a network is instantiated, which is expected and is what breaks symmetry.
  • Calling torch.manual_seed before creating a network makes its initial weights reproducible across runs, and the seed must come before instantiation to have any effect.

Related concepts

More concepts starting with B