Neural Network and Deep Learning Foundations

The complete mathematical and architectural base layer that every modern LLM builds on — from a single neuron to the training loop that produces GPT-scale models. Written so a complete beginner can start here and finish able to reason like a research engineer.

0. How to Read This Page

This page assumes no prior machine learning background. Every idea is introduced from first principles, then connected forward to how it is actually used inside large language models (LLMs). Where useful, we give the plain-English intuition first, then the precise mathematical statement, then a code snippet that shows the idea running. If you only remember one thing from this page, remember this: a neural network is just a very large, very flexible function, and training is the process of nudging its internal numbers (parameters) so that the function's outputs get closer to what we want. Everything else — layers, attention, optimizers, normalization — exists to make that nudging process work reliably at enormous scale.

1. What a Neuron Is, and What a Network Is

1.1 The single neuron

The smallest building block of a neural network is a single artificial neuron. It takes a vector of inputs \(x = (x_1, x_2, \dots, x_n)\), multiplies each input by a learned weight \(w_i\), sums the results, adds a learned bias \(b\), and passes the sum through a non-linear activation function \(f\):

\[ z = \sum_{i=1}^{n} w_i x_i + b = w \cdot x + b \]

\[ a = f(z) \]

Here \(z\) is called the pre-activation (or logit for the final layer), and \(a\) is the neuron's activation (its output). The weights \(w\) and bias \(b\) are the neuron's parameters — the numbers that training will adjust. Nothing about a single neuron is magical: it's a weighted sum passed through a squashing function.

1.2 Stacking neurons into layers

A layer is a group of neurons that all read the same input vector but each has its own independent weights and bias. If a layer has \(m\) neurons and the input has \(n\) dimensions, the layer's weights form a matrix \(W \in \mathbb{R}^{m \times n}\) and its biases form a vector \(b \in \mathbb{R}^{m}\). The whole layer computes:

\[ z = Wx + b, \qquad a = f(z) \]

where \(f\) is applied element-wise. This is why deep learning is fundamentally linear algebra: every layer is a matrix multiply plus a non-linearity, and a network is a chain of these operations.

1.3 A network is a composition of functions

A neural network with \(L\) layers is the composition:

\[ \hat{y} = f_L\big(W_L \, f_{L-1}(\dots f_1(W_1 x + b_1) \dots) + b_L\big) \]

Training adjusts every \(W_\ell\) and \(b_\ell\) (collectively called \(\theta\), the parameters) so that \(\hat{y}\) — the model's prediction — matches the true target \(y\) as closely as possible, across a whole dataset, according to some numeric measure of "closeness" called a loss function.

For a language model specifically: the input \(x\) is a sequence of token embeddings (numeric vectors representing words/subwords, see the Tokenization page), and the output \(\hat y\) is a probability distribution over every possible next token in the vocabulary. Training nudges the parameters so that the model assigns high probability to the token that actually came next in real text.

1.4 Why depth matters (the universal approximation intuition)

A network with no activation function — just stacked linear layers — collapses mathematically into a single linear layer, because the product of matrices is still a matrix:

\[ W_2(W_1 x) = (W_2 W_1)x = W' x \]

No matter how many linear layers you stack, you can only ever draw straight decision boundaries. Real-world data — language, images, audio — has highly non-linear structure: word meaning depends on context in non-additive ways, pixel patterns form curved edges, and so on. Inserting a non-linear activation function \(f\) between layers breaks this collapse and gives the network the ability to approximate arbitrarily complex functions, given enough width or depth (this is formalized by the Universal Approximation Theorem). Depth (many layers) tends to build features hierarchically: early layers learn simple local patterns, later layers combine them into increasingly abstract concepts. In language models this shows up as early transformer layers tracking local syntax and later layers tracking long-range meaning, coreference, and task-level abstractions.

1.5 Forward pass

The forward pass is simply evaluating the network: given an input, compute layer 1's output, feed it into layer 2, and so on until you reach the final prediction. Every intermediate activation is stored in memory (this matters for the backward pass below).

import torch
import torch.nn.functional as F

# Next-token cross-entropy: compare logits to true token ids
logits = model(input_ids)          # shape: [batch, seq_len, vocab]
loss = F.cross_entropy(
    logits.view(-1, logits.size(-1)),
    labels.view(-1),
    ignore_index=-100,
)

1.6 Backward pass and backpropagation

Training needs to know: "if I nudge this particular weight by a tiny amount, how much does the loss change?" That sensitivity is the gradient of the loss with respect to that weight, written \(\frac{\partial \mathcal{L}}{\partial w}\). Computing this for every parameter individually and from scratch would be astronomically expensive for a billion-parameter model. Backpropagation solves this efficiently using the chain rule of calculus, propagating gradients backward from the loss through each layer, re-using intermediate results computed during the forward pass.

For a two-layer network \(a_1 = f_1(W_1 x + b_1)\), \(\hat y = f_2(W_2 a_1 + b_2)\), and loss \(\mathcal{L}(\hat y, y)\), the chain rule gives:

\[ \frac{\partial \mathcal{L}}{\partial W_2} = \frac{\partial \mathcal{L}}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial z_2} \cdot \frac{\partial z_2}{\partial W_2}, \qquad \frac{\partial \mathcal{L}}{\partial W_1} = \frac{\partial \mathcal{L}}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial z_2} \cdot \frac{\partial z_2}{\partial a_1} \cdot \frac{\partial a_1}{\partial z_1} \cdot \frac{\partial z_1}{\partial W_1} \]

Notice that the term \(\frac{\partial \mathcal{L}}{\partial \hat y} \cdot \frac{\partial \hat y}{\partial z_2}\) is shared between both gradient calculations. Backpropagation computes this once at the output and reuses it as it walks backward layer by layer, which is why it is efficient: for a network with \(L\) layers, both the forward and backward pass cost roughly the same amount of computation, \(O(L)\), instead of costing exponentially more for deeper networks.

Once every gradient is known, an optimizer (Section 2) uses them to update the parameters, nudging each weight a small step in the direction that reduces the loss.

2. Loss Functions and Optimization

2.1 Cross-entropy loss

Language models are trained with cross-entropy loss. At each position in a sequence, the model outputs a probability distribution \(\hat p\) over the whole vocabulary (via a softmax, see Section 4). If the true next token has index \(y\), the loss for that single prediction is:

\[ \mathcal{L} = -\log \hat p_y = -\log \frac{e^{z_y}}{\sum_{j=1}^{V} e^{z_j}} \]

where \(z\) is the vector of logits (pre-softmax scores) and \(V\) is the vocabulary size. Intuitively: if the model assigns high probability to the correct token, \(-\log \hat p_y\) is small (close to 0); if it assigns low probability, the loss is large (approaching infinity as \(\hat p_y \to 0\)). Minimizing average cross-entropy over a huge text corpus is mathematically equivalent to maximum likelihood estimation — finding the parameters that make the observed training text as probable as possible under the model.

For a full sequence of length \(T\), the total loss is the average (or sum) of per-token losses:

\[ \mathcal{L}_{\text{seq}} = -\frac{1}{T}\sum_{t=1}^{T} \log P(x_t \mid x_{

This is exactly next-token prediction: at every position, predict a distribution over what token comes next given everything before it, and penalize the model by how surprised it is by the true answer.

2.2 Gradient descent, the core training algorithm

Once gradients are known, the most basic update rule, gradient descent, moves every parameter a small step in the direction that decreases the loss fastest:

\[ \theta_{t+1} = \theta_t - \eta \, \nabla_\theta \mathcal{L}(\theta_t) \]

Here \(\eta\) is the learning rate — how big a step to take — and \(\nabla_\theta \mathcal{L}\) is the gradient vector (all the partial derivatives from backpropagation). Too large a learning rate causes the loss to oscillate or diverge; too small wastes compute crawling toward a solution. In practice we never compute the gradient over the entire dataset at once (that would be far too slow); instead we use mini-batch stochastic gradient descent, estimating the gradient from a small random batch of examples at each step. This introduces noise but is far cheaper and, in practice, generalizes better.

2.3 Optimizers: SGD, Adam, AdamW

optimizer = torch.optim.AdamW(
    model.parameters(),
    lr=2e-4,
    betas=(0.9, 0.95),
    weight_decay=0.1,
)

2.4 Learning rate schedules and stabilizers

Training billion-parameter models on trillions of tokens is numerically fragile. Standard stabilizers include:

Practical note: Without warmup, cosine decay, and gradient clipping, early training spikes or late-stage divergence are common when training billion-parameter models. These three tricks are near-universal in modern LLM pretraining recipes.

3. Normalization and Stability

3.1 Why deep networks are numerically unstable

During backpropagation, gradients are computed by repeatedly multiplying terms together across many layers (the chain rule again). If those terms are consistently slightly less than 1, the product shrinks toward zero exponentially with depth — the vanishing gradient problem, where early layers stop learning because almost no gradient signal reaches them. If the terms are consistently greater than 1, the product grows exponentially — the exploding gradient problem, where parameter updates become huge and destabilize training. Both problems get worse as networks get deeper, which is exactly the regime modern LLMs operate in (tens to well over a hundred layers).

3.2 Residual (skip) connections

A residual connection adds a sublayer's input directly to its output instead of replacing it:

\[ y = x + \text{Sublayer}(x) \]

During backpropagation, the derivative of this sum with respect to \(x\) includes an identity term (\(\partial y/\partial x = I + \partial\,\text{Sublayer}/\partial x\)), which guarantees gradients have a direct, unimpeded path all the way back through the network regardless of depth. This single idea (from the ResNet paper, later adopted by the Transformer) is what makes training networks with dozens or hundreds of layers practical at all.

3.3 Batch, layer, and RMS normalization

Normalization layers rescale activations to keep their distribution stable as they flow through the network, which further stabilizes gradients and speeds up convergence.

Where normalization sits relative to the sublayer also matters: pre-norm (normalize the input before the sublayer, e.g. \(x + \text{Sublayer}(\text{Norm}(x))\)) keeps the residual stream itself unnormalized and gives more stable gradients at large depth, which is why virtually all modern LLMs are pre-norm rather than the original Transformer's post-norm design.

4. Activation Functions

Non-linear activations are what prevent stacked linear layers from collapsing into a single linear map (Section 1.4). Different activations trade off simplicity, smoothness, and expressiveness.

5. Generalization and the Bias-Variance Tradeoff

5.1 Formal picture

A model's expected error on unseen data can be decomposed (informally) into three sources:

\[ \text{Expected Error} = \text{Bias}^2 + \text{Variance} + \text{Irreducible Noise} \]

Bias is error from a model being too simple to represent the true underlying pattern — systematic, consistent error regardless of which training data you happened to see. Variance is error from a model being so flexible that it fits noise/idiosyncrasies specific to the training set, so its predictions swing wildly depending on exactly which data it was trained on. Underfitting (high bias) means the model is too simple to capture patterns in the data; in LLM training this shows up as poor benchmark scores when model or data scale is too small relative to the task's complexity. Overfitting (high variance) means the model memorizes training examples rather than learning generalizable patterns; during LLM fine-tuning this appears when the model memorizes a small instruction dataset and its broader, pretrained capabilities degrade (a phenomenon often called "catastrophic forgetting").

5.2 Regularization techniques

Mitigations more generally include gathering more/better data, scaling the model appropriately for the compute and data budget (see Scaling Laws on the LLMs page), and choosing regularization strength to match how much data is available.

6. Worked Example: One Full Training Step by Hand

To make all of the above concrete, consider a tiny network: one input, one hidden neuron with ReLU, one output neuron, and squared-error loss on a single example \((x, y) = (2, 10)\). Suppose current parameters are \(w_1=1, b_1=0, w_2=2, b_2=0\).

Forward pass: \(z_1 = w_1 x + b_1 = 2\); \(a_1 = \text{ReLU}(z_1)=2\); \(\hat y = w_2 a_1 + b_2 = 4\); loss \(\mathcal{L} = \frac{1}{2}(\hat y-y)^2 = \frac{1}{2}(4-10)^2=18\).

Backward pass: \(\frac{\partial \mathcal{L}}{\partial \hat y} = \hat y - y = -6\). Then \(\frac{\partial \mathcal{L}}{\partial w_2} = \frac{\partial \mathcal{L}}{\partial \hat y}\cdot a_1 = -6\cdot 2=-12\), and \(\frac{\partial \mathcal{L}}{\partial a_1} = \frac{\partial \mathcal{L}}{\partial \hat y}\cdot w_2 = -6\cdot 2 = -12\). Since \(z_1>0\), ReLU's derivative is 1, so \(\frac{\partial \mathcal{L}}{\partial w_1} = \frac{\partial \mathcal{L}}{\partial a_1}\cdot x = -12\cdot 2=-24\).

Gradient descent update with \(\eta=0.01\): \(w_2 \leftarrow 2-0.01\cdot(-12)=2.12\); \(w_1 \leftarrow 1-0.01\cdot(-24)=1.24\). Both weights increase, which will push \(\hat y\) closer to 10 on the next forward pass. This is exactly what happens, scaled up by many orders of magnitude, across billions of parameters and trillions of tokens when training an LLM — the mechanics never change, only the scale.

7. From Foundations to Transformers

Everything above applies directly to transformer LLMs: cross-entropy next-token prediction (Section 2.1), AdamW with warmup and cosine decay (Section 2.3–2.4), RMSNorm inside blocks (Section 3.3), residual connections around attention and MLP sublayers (Section 3.2), and gated SwiGLU activations in feed-forward networks (Section 4). Understanding these primitives makes it far easier to reason about training instability, fine-tuning behavior, and why architectural choices in modern LLMs look the way they do. The next page, Transformer Architecture, builds the attention mechanism on top of exactly this foundation.