Turn one vector into another using weights, bias, and an activation function
Follow one complete training step, from a wrong prediction to a better one
Distinguish computing gradients from updating weights
Read the tensor shapes and automatic gradients used in a small PyTorch example
You now know how text becomes vectors. Before we give a model memory, we need one more idea: a plain neural layer.
A basic neural network is a stack of these layers. Each layer does the same pattern:
multiply input numbers by learned weights
add a learned bias
pass the result through an activation function
output a new vector
One Layer, Step by Step
Neural Layer: Vector In, Vector Out
Step 1: Inputs
Input vector
x1 = 2x2 = -1
Two numbers enter the layer.
->
Weights
neuron 1[0.5, 1]
neuron 2[-1, 0.5]
Each neuron has its own weights.
->
Output
not computed yet
A neural layer starts with a vector: a short list of numbers.
What to look for: the input is a vector, the output is another vector. The weights and bias are learned during training. The activation function lets the layer model curved patterns, not just straight-line relationships.
How Does a Weight Learn?
We called those weights “learned,” but a randomly chosen weight has no reason to produce the right answer. We need a way to measure a mistake and use it to improve the next prediction.
Start with one input number, 2, and a target answer, also 2. Our tiny model multiplies the input by one adjustable weight, initially 0.5. Its first prediction is 1, too low. We leave out bias and activation for this example so there is only one number to adjust.
How does one weight learn?
Input → transform → output
Input2Given by the example
→
Multiply by weight0.5The number we can adjust
→
Prediction1.0Target: 2.0
2 × 0.5 = 1.0. The model's first guess is too low.
The input is fixed at 2. Our adjustable weight starts at 0.5, so the prediction is 1. The target is 2.
What to look for: follow all five steps with the default learning rate of 0.1. The prediction moves from 1 to 1.8, closer to the target 2, and the error score falls from 1 to 0.04. Then return to Update weight and try 0.3. A larger adjustment overshoots and makes this example worse.
Think of tuning a shower knob: check the temperature, decide which way to turn, make a small adjustment, and check again. The limit of the analogy is that a model calculates a sensitivity for each weight instead of feeling the water.
Here’s what happened in our example:
Predict. Multiply the input 2 by the current weight 0.5 to get 1. This is the forward pass, the same input → transform → output pattern you just saw.
Measure the mistake. The prediction is 1 below the target. Square that difference to get an error score of 1. We call this score the loss. A perfect prediction would have a loss of 0.
Trace the mistake backward. Compute how a tiny change to the weight would affect the loss. This sensitivity is the gradient. Here it is −4, which tells us that increasing the weight a little would reduce the loss. Backpropagation computes these sensitivities by following the forward calculation backward.
Update the weight. The learning rate, 0.1, controls how far to move. Subtracting the learning rate times the gradient increases our weight from 0.5 to 0.9. The rule that turns gradients into parameter updates is an optimizer; this simple rule is gradient descent.
Predict again. The same input 2 now gives 1.8. Its distance from the target is only 0.2, so the new squared-error loss is 0.04. We checked that this update helped instead of stopping at the new weight.
A common mistake is to think that backpropagation changes the weights. It only computes gradients. The optimizer performs the update. Another is to assume a larger step always learns faster: our 0.3 experiment shows why we must check the resulting loss.
Every symbol refers to a number in the example:
x: the fixed input, 2
y: the target answer, 2
w: the adjustable weight, initially 0.5
y^ (“y hat”): the model’s prediction
L: the squared-error loss
η (“eta”): the learning rate, 0.1
∂w∂L: the gradient, meaning the sensitivity of the loss to a small change in the weight
The forward pass and loss are:
y^=wx=0.5×2=1,L=(y^−y)2=(1−2)2=1
The loss depends on the prediction, and the prediction depends on the weight. The chain rule multiplies those two sensitivities:
∂y^∂L=2(y^−y)=−2,∂w∂y^=x=2
∂w∂L=∂y^∂L×∂w∂y^=(−2)×2=−4
Subtract the gradient times the learning rate. The subscript “new” means after this update:
wnew=w−η∂w∂L=0.5−0.1(−4)=0.9
y^new=0.9×2=1.8,Lnew=(1.8−2)2=0.04
These sensitivities describe the loss near the current weight. They do not promise that an arbitrarily large step will help: with learning rate 0.3, the weight becomes 1.7, the prediction 3.4, and the loss 1.96.
🤔Quick Check
We computed a weight's gradient as −4. What happens before the optimizer runs?
Your turn
Choose an answer to check your understanding.
Try another option
Separate the backward pass from the update step in the visualization.
Correct!
Backpropagation computes sensitivities. It does not update the parameters. The optimizer uses the gradient and learning rate to choose an update; the input and target remain fixed.
Answer: C
Backpropagation computes sensitivities. It does not update the parameters. The optimizer uses the gradient and learning rate to choose an update; the input and target remain fixed.
Attempts: 0
✍️Fill in the Blanks
Starting at weight 0.5 with gradient −4 and learning rate 0.1, the updated weight is . With input 2, the next prediction is .
Fill in every blank, then check your answer.
A blank is still empty.
Fill in every blank before checking your answer.
Not quite.
Try another answer, or reveal the solution.
Correct.
One accepted answer is shown in each blank.
Answer revealed.
The blanks now show the answers.
A Small Bridge to PyTorch
Hand calculations show what learning does. For a model with thousands of weights, we want a library to organize the numbers and keep track of those sensitivities. PyTorch provides both.
Three ideas are enough to read the example below:
Idea
Meaning
Small example
Tensor
A container of numbers, from one number to a multidimensional array
A scalar weight, a vector of features, or a batch of vectors
Shape
The size of each axis in that container
(3, 2) means 3 examples with 2 features each
Autograd
Automatic differentiation: record operations, then compute their gradients backward
loss.backward() fills the weight’s .grad
A batch is a group of examples processed together. Shape labels tell us what each axis means, so we don’t accidentally confuse examples with features. Autograd handles the backward calculation; we still choose the loss, learning rate, and update rule.
This optional code needs Python and PyTorch. It implements the same single weight update as the visualization, without a training framework around it:
import torchx = torch.tensor(2.0) # shape: () = one scalar inputtarget = torch.tensor(2.0) # shape: () = one scalar targetw = torch.tensor(0.5, requires_grad=True) # shape: () = one trainable weightlearning_rate = 0.1prediction = w * x # shape: ()loss = (prediction - target).square() # shape: ()loss.backward() # computes gradients, no update yetprint(f"Before: prediction={prediction.item():.2f}, loss={loss.item():.2f}")print(f"Gradient: {w.grad.item():.2f}")with torch.no_grad(): # don't record the update as model math w -= learning_rate * w.gradw.grad = None # clear before the next backward passwith torch.no_grad(): # evaluation needs no new gradient graph next_prediction = w * x next_loss = (next_prediction - target).square()print(f"New weight: {w.item():.2f}")print(f"After: prediction={next_prediction.item():.2f}, loss={next_loss.item():.2f}")
requires_grad=True marks a tensor for gradient tracking. .item() reads a one-element tensor as a Python number for printing. Gradients accumulate across backward calls, so we clear .grad before the next training step. We also recompute the prediction and loss for each new step.
With many parameters, a PyTorch optimizer such as torch.optim.SGD handles the update. Its zero_grad() clears old gradients, loss.backward() computes new ones, and step() applies them. An optimizer such as Adam uses additional running statistics, but the predict → loss → backward → update loop stays the same.
Here a vector has 2 input features. We process 3 examples together and produce 4 output features per example:
@ means matrix multiplication. .T transposes this two-dimensional weight tensor, turning shape (4, 2) into (2, 4). The shared dimension 2 matches the input feature count. Adding the bias reuses its four numbers for each of the three examples. The activation changes values while preserving shape.
The zero weights make this a shape demonstration with zero outputs. For training a multilayer network, we would initialize weights differently, typically with small random values so neurons can learn different features.
You can return to these snippets when you reach Train Your Own GPT. That project repeats this learning loop with batches of token sequences and many parameters. A language model uses a loss suited to next-token probabilities rather than this example’s squared error.
Why RNNs Need This
An RNN is not a totally new kind of math. It is this same vector-in, vector-out layer used repeatedly:
Model piece
What goes in
What comes out
Neural layer
one vector
a transformed vector
RNN step
current token vector + previous memory
new memory vector
The new part in an RNN is the loop: the output memory from one step becomes part of the input at the next step.
🤔Quick Check
What does a neural layer do at the highest level?
Your turn
Choose an answer to check your understanding.
Try another option
Think vector in, vector out.
Correct!
A neural layer takes a vector, mixes its numbers with learned weights and bias, applies an activation, and returns a new vector.
Answer: A
A neural layer takes a vector, mixes its numbers with learned weights and bias, applies an activation, and returns a new vector.
Attempts: 0
✍️Fill in the Blanks
A neural layer computes a weighted sum, adds a , then applies an function.
Fill in every blank, then check your answer.
A blank is still empty.
Fill in every blank before checking your answer.
Not quite.
Try another answer, or reveal the solution.
Correct.
One accepted answer is shown in each blank.
Answer revealed.
The blanks now show the answers.
Quick Summary
Step
What happens
Intuition
Weights
Scale and mix input numbers
Which inputs matter for each neuron
Bias
Shifts the score
A learned default push
Activation
Bends the result
Lets the network model nonlinear patterns
Layer output
Produces a new vector
A transformed representation
Loss
Measures how far a prediction is from its target
An error score to reduce
Backward pass
Computes the loss gradient for each trainable parameter
Which way should each knob turn?
Optimizer step
Uses gradients to update the parameters
Make an adjustment, then predict again
Tensor shape
Records the size and meaning of each axis
Keep examples and features organized
More weights. With several weights, the gradient has one entry per weight. Each entry asks how the loss changes when that weight moves a little, holding the others fixed. Autograd traces all the paths that use each weight.
Different losses. Squared error makes our numerical example easy to inspect. For next-token prediction, we’ll use cross-entropy, which penalizes assigning low probability to the correct token. Updating shared weights can help one example and hurt another, so training uses many examples and checks performance on held-out data.
More than one update. Repeat the forward pass after every update to get a fresh prediction, loss, and gradient. An old gradient describes the old weight, not every future position.
Learning Checklist
I can explain the roles of weights, bias, and activation in a neural layer
I can follow input → transform → output for one forward pass
I can distinguish a prediction, its target, and its loss
I can explain why computing a gradient and updating a weight are separate steps
I can check the new prediction and loss after a weight update
I can read a tensor’s shape and explain what loss.backward() computes
Next Steps
Now that a vector can be transformed, we can add memory. An RNN runs a similar transformation again and again as it reads a sequence. RNN Introduction →