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.
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?
Reveal 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
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.
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.
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.
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.
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.
- The first seed call resets the generator before
run_oneis created - The second seed call resets it again before
run_twois 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.
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?
- 1Create the first layer
nn.Linear draws its random weights at this moment, using whatever state the generator is in.
- 2Seed the generator
torch.manual_seed(0)resets the generator, but the first layer has already received its weights, so this call cannot change them. - 3Create the second layer
The second draw happens after the reset, so it produces a sequence that may differ from the first layer's values.
- 4Correct 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.
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 likelayer.weight.fill_(0.5) applied to every node in a hidden layer
Why it failsIdentical weights with identical inputs produce identical updates, so the nodes never learn different features.
Do this insteadStart 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 likeCreating two layers, then calling torch.manual_seed(0) and expecting the earlier layers to match
Why it failsWeights are drawn when the network is instantiated, so a later seed does not affect weights already drawn.
Do this insteadCall torch.manual_seed before each network is created.
Common mistake Assuming two runs will match without any seed
What it looks likePrinting the weight matrix in two separate runs and expecting identical numbers
Why it failsEach instantiation draws new random values, so the matrices usually differ.
Do this insteadSet 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
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.