The Elements of Differentiable Programming
Part II Differentiable programs

Chapter 4Parameterized programs

Neural networks can be thought of as parameterized programs: programs with learnable parameters. In this chapter, we begin by reviewing how to represent programs mathematically. We then review several key neural network architectures and components.

4.1 Representing computer programs

4.1.1 Computation chains

To begin with, we consider simple programs that apply a sequence of functions f1,…,fKf_1,\dots,f_K to an input s0∈S0\s_0 \in \cS_0. We call such programs computation chains. For example, an image may go through a sequence of transformations such as cropping, rotation, normalization, and so on. In neural networks, the transformations are typically parameterized, and the parameters are learned, leading to feedforward networks, presented in Section 4.2. Another example of a sequence of functions is a for loop, presented in Section 5.8.

Formally, a computation chain can be written as s0∈S0s1≔f1(s0)∈S1⋮sK≔fK(sK−1)∈SKf(s0)≔sK.\begin{align*} \s_0 &\in \cS_0 \\ \s_1 &\coloneqq f_1(\s_0) \in \cS_1 \\ & \hspace{6pt} \vdots \\ \s_K &\coloneqq f_K(\s_{K-1}) \in \cS_K \\ f(\s_0) &\coloneqq \s_K. \tag{4.1}\end{align*} Here, s0\s_0 is the input, sk∈Sk\sv_k \in \cS_k is an intermediate state of the program, and sK∈SK\s_K \in \cS_K is the final output. Of course, the domain (input space) of fkf_k must be compatible with the image (output space) of fk−1f_{k-1}. That is, we should have fk ⁣:Sk−1→Skf_k \colon \cS_{k-1} \to \cS_k. We can write a computation chain equivalently as f(s0)=(fK∘⋯∘f2∘f1)(s0)=fK(…f2(f1(s0))).\begin{align*} f(\s_0) &= (f_K \circ \dots \circ f_2 \circ f_1)(\s_0) \\ &= f_K(\dots f_2(f_1(\s_0))). \end{align*} A computation chain can be represented by a directed graph, shown in Fig. 4.1. The edges in the chain define a total order. The order is total, since two nodes are necessarily linked to each other by a path.

Figure 4.1: A computation chain is a sequence of function compositions. In the graph above, each intermediate node represents a single function. The first node represents the input, the last node the output. Edges represent the dependencies of the functions with respect to previous outputs or to the initial input.

4.1.2 Directed acyclic graphs

In generic programs, intermediate functions may depend, not only on the previous function output, but on the outputs of several different functions. Such dependencies are best expressed using graphs.

A directed graph G=(V,E)\cG = (\cV, \cE) is defined by a set of vertices or nodes V\cV and a set of edges E\cE defining directed dependencies between vertices. An edge (i,j)∈E(i,j) \in \cE is an ordered pair of vertices i∈Vi \in \cV and j∈Vj \in \cV. It is also denoted i→ji \rightarrow j, to indicate that jj depends on ii. For representing inputs and outputs, it will be convenient to use incoming half-edges →j\rightarrow j and outgoing half-edges i→i \rightarrow.

In a graph G=(V,E)\cG= (\cV, \cE), the parents of a vertex jj are the set of nodes pointing to jj, denoted pa⁡(j)≔{i:i→j}\parent(j) \coloneqq \{i: i \rightarrow j\}. The children of a vertex ii are the set of nodes ii is pointing to, that is, ch⁡(i)≔{j ⁣:i→j}\child(i) \coloneqq \{j \colon i \rightarrow j\}. Vertices without parents are called roots and vertices without children are called leaves.

A path from ii to jj is defined by a sequence of vertices j1,…,jmj_1, \ldots, j_m, potentially empty, such that i→j1→…→jm→ji \rightarrow j_1 \rightarrow \ldots \rightarrow j_m \rightarrow j. An acyclic graph is a graph such that there exists no vertex ii with a path from ii to ii. A directed acyclic graph (DAG) is a graph that is both directed and acyclic.

The edges of a DAG define a partial order of the vertices, denoted i⪯ji \preceq j if there exists a path from ii to jj. The order is partial, since two vertices may not necessarily be linked to each other by a path. Nevertheless, we can define a total order called a topological order: any order such that i≤ji \leq j if and only if there is no path from jj to ii.

 

Figure 4.2: Example of a directed acyclic graph. Here the nodes are V={0,1,2,3,4}\cV = \{0, 1, 2, 3, 4\}, the edges are E={(0,1),(0,2),(0,3),(1,3),(2,3),(1,4),(3,4)}\cE = \{(0, 1), (0, 2), (0, 3), (1, 3), (2, 3), (1, 4), (3, 4)\}. Parents of the node 33 are pa⁡(3)={0,1,2}\parent(3) = \{0, 1, 2\}. Children of node 11 are ch⁡(1)={3,4}\child(1) = \{3, 4\}. There is a unique root, 00, and a unique leaf, 44; 0→3→40 \rightarrow 3 \rightarrow 4 is a path from 00 to 44. This is an acyclic graph since there is no cycle (i.e., a path from a node to itself). We can order nodes 00 and 33 as 0≤30 \leq 3 since there is no path from 33 to 00. Similarly, we can order 11 and 22 as 1≤21 \leq 2 since there is no path from 22 to 11. Two possible topological orders of the nodes are (0,1,2,3,4)(0, 1, 2, 3, 4) and (0,2,1,3,4)(0, 2, 1, 3, 4).

4.1.3 Computer programs as DAGs

We assume that a program defines a mathematically valid function (a.k.a. pure function): the program should return identical values for identical arguments and should not have any side effects. We also assume that the program halts, i.e., that it terminates in a finite number of steps. As such a program is made of a finite number of intermediate functions and intermediate variables, the dependencies between functions and variables can be expressed using a directed acyclic graph (DAG). Without loss of generality, we make the following simplifying assumptions:

  1. There is a single input s0∈S0\s_0 \in \cS_0.

  2. There is a single output sK∈SK\s_K \in \cS_K.

  3. Each intermediate function fkf_k in the program outputs a single variable sk∈Sk\s_k \in \cS_k.

We number the nodes as V≔{0,1,…,K}\cV \coloneqq \{0, 1, \dots, K\}. Node 00 is the root, corresponding to the input s0∈S0\s_0 \in \cS_0. Node KK is the leaf, corresponding to the final output sK∈SK\s_K \in \cS_K. Because of the third assumption above, apart from s0\s_0, each variable sk\s_k is in bijection with a function fkf_k. Therefore, node 00 represents the input s0\s_0, and nodes 1,…,K1, \dots, K represent both a function fkf_k and an output variable sk\s_k.

Figure 4.3: Representation of f(x1,x2)=x2ex1x1+x2ex1f(x_1, x_2) = x_2e^{x_1}\sqrt{x_1 + x_2 e^{x_1}} as a DAG, with functions and variables as nodes. Edges indicate function and variable dependencies. The function ff is decomposed as 88 elementary functions in topological order.

Edges in the DAG represent dependencies. The parents i1,…,ipk≔pa⁡(k)i_1, \dots, i_{p_k} \coloneqq \parent(k) of node kk, where pk≔∣pa⁡(k)∣p_k \coloneqq |\parent(k)|, indicate the variables spa⁡(k)≔si1,…,sipk\s_{\parent(k)} \coloneqq \s_{i_1}, \dots, \s_{i_{p_k}} that the function fkf_k needs to perform its computation. Put differently, the parents i1,…,ipki_1, \dots, i_{p_k} indicate the functions fi1,…,fipkf_{i_1}, \ldots, f_{i_{p_k}} that need to be evaluated, prior to evaluating fkf_k. An example of a computation graph in our formalism is presented in Fig. 4.3.

Executing a program

To execute a program, we need to ensure that we evaluate the intermediate functions in the correct order. Therefore, we assume that the nodes 0,1,…,K0, 1, \dots, K are in a topological order (if this is not the case, we need to perform a topological sort first). We can then execute a program by evaluating for k∈[K]k \in [K] sk≔fk(spa⁡(k))≔fk(si1,…,sipk)∈Sk.\begin{align*} \s_k \coloneqq f_k(\s_{\parent(k)}) \coloneqq f_k(\s_{i_1}, \dots, \s_{i_{p_k}}) \in \cS_k. \end{align*} Note that we can either view fkf_k as a single-input function of spa⁡(k)\s_{\parent(k)}, which is a tuple of elements, or as a multi-input function of si1,…,sipk\s_{i_1}, \dots, \s_{i_{p_k}}. The two views are essentially equivalent.

The procedure for executing a program is summarized in Algorithm 4.1.

Algorithm 4.1: Executing a program

Functions: f1,…,fKf_1, \dots, f_K in topological order

Input: input s0∈S0\s_0 \in \cS_0

for k≔1,…,Kk \coloneqq 1, \ldots, K do

Retrieve parent nodes (i1,…,ipk)≔pa⁡(k)(i_1, \dots, i_{p_k}) \coloneqq \parent(k)

Compute sk≔fk(spa⁡(k))≔fk(si1,…,sipk)\s_k \coloneqq f_k(\s_{\parent(k)}) \coloneqq f_k(\s_{i_1}, \ldots, \s_{i_{p_k}})

Output: f(s0)≔sKf(\s_0) \coloneqq \s_K

Dealing with multiple program inputs or outputs

When a program has multiple inputs, we can always group them into s0∈S0\s_0 \in \cS_0 as s0=(s0,1,…,s0,N0)\s_0 = (\s_{0,1}, \dots, \s_{0,N_0}) with S0=(S0,1×⋯×S0,N0)\cS_0 = (\cS_{0,1} \times \dots \times \cS_{0,N_0}), since later functions can always filter out what elements of s0\s_0 they need. Likewise, if an intermediate function fkf_k has multiple outputs, we can always group them as a single output sk=(sk,1,…,sk,Nk)\s_k = (\s_{k,1},\dots,\s_{k,N_k}) with Sk=(Sk,1×⋯×Sk,Nk)\cS_k = (\cS_{k,1} \times \dots \times \cS_{k,N_k}), since later functions can filter out the elements of sk\s_k that they need.

Alternative representation: bipartite graphs

In our formalism, because a function fkf_k always has a single output sk\s_k, a node kk can be seen as representing both the variable sk\s_k and the function fkf_k. Alternatively, as shown in Fig. 4.4, we can represent variables and functions as separate nodes, that is, using a bipartite graph. This formalism is akin to factor graphs (Frey et al., 1997; Loeliger, 2004) used in probabilistic modeling, but with directed edges. One advantage of this formalism is that it allows functions to explicitly have multiple outputs. We focus on our formalism for simplicity.

Figure 4.4: Two possible representations of a program. Left: Functions and output variables are represented by the same nodes. Right: functions and variables are represented by a disjoint set of nodes.

4.1.4 Arithmetic circuits

Arithmetic circuits are one of the simplest examples of computation graph, originating from computational complexity theory. Formally, an arithmetic circuit over a field F\FF, such as the reals R\RR, is a directed acyclic graph (DAG) whose root nodes are elements of F\FF and whose functions fkf_k are either ++ or ×\times. The latter are often called gates. Contrary to the general computation graph case, because each fkf_k is either ++ or ×\times, it is important to allow the graph to have several root nodes. Root nodes can be either variables or constants, and should belong to F\FF.

Arithmetic circuits can be used to compute polynomials. There are potentially multiple arithmetic circuits for representing a given polynomial. One important question is then to find the most efficient arithmetic circuit for computing a given polynomial. To compare arithmetic circuits representing the same polynomial, an intuitive notion of complexity is the circuit size, as defined below.

Definition 4.1 (Circuit and polynomial sizes)

The size S(C)S(\cC) of a circuit C\cC is the number of edges in the directed acyclic graph representing C\cC. The size S(f)S(f) of a polynomial ff is the smallest S(C)S(\cC) among all C\cC representing ff.

For more information on arithmetic circuits, we refer the reader to the monograph of Chen et al. (2011).

4.2 Feedforward networks

A feedforward network can be seen as a computation chain with parameterized functions fkf_k, s0≔xs1≔f1(s0,w1)s2≔f2(s1,w2)⋮sK≔fK(sK−1,wK),\begin{align*} \sv_0 &\coloneqq \xv \\ \sv_1 &\coloneqq f_1(\sv_0, \wv_1) \\ \sv_2 &\coloneqq f_2(\sv_1, \wv_2) \\ &\vdots \\ \sv_K &\coloneqq f_K(\sv_{K-1}, \wv_K), \end{align*} for a given input x∈X\x \in \cX and learnable parameters w1,…,wK∈W1×⋯×WK\w_1, \ldots, \w_K \in \cW_1 \times \dots \times \cW_K. Each function fkf_k is called a layer and each sk∈Sk\sv_k \in \cS_k can be seen as an intermediate representation of the input x\xv. The dimensionality of Sk\cS_k is known as the width (or number of hidden units) of layer kk. A feedforward network defines a function sK≕f(x,w)\s_K \eqqcolon f(\xv, \wv) from X×W\cX \times \cW to SK\cS_K, where w≔(w1,…,wK)∈W≔W1×…×WK\wv \coloneqq (\wv_1, \dots, \wv_K) \in \cW \coloneqq \cW_1 \times \ldots \times \cW_K .

Given such a parameterized program, we can learn the parameters by adjusting w\wv to fit some data. For instance, given a dataset of (xi,yi)(\xv_i, \yv_i) pairs, we may minimize the squared loss ∥yi−f(xi,w)∥22\|\yv_i - f(\x_i, \w)\|_2^2 on average over the data, w.r.t. w\wv. The minimization of such a loss requires accessing its gradients with respect to w\w.

4.3 Multilayer perceptrons

4.3.1 Combining affine layers and activations

In the previous section, we did not specify how to parametrize the feedforward network. A typical parametrization, called the multilayer perceptron (MLP), uses fully-connected (also called dense) layers of the form sk=fk(sk−1,wk)≔ak(Wksk−1+bk), \sv_k = f_k(\sv_{k-1}, \wv_k) \coloneqq a_k(\W_k \sv_{k-1} + \bv_k), where we defined the tuple wk≔(Wk,bk)\wv_k \coloneqq (\W_k, \bv_k) and where we assumed that Wk\W_k and bk\bv_k are a matrix and a vector of appropriate size. We can further decompose the layer into two functions. The function s↦Wks+bk\sv \mapsto \W_k \sv + \bv_k is called an affine layer. The function v↦ak(v)\vv \mapsto a_k(\vv) is a parameter-free nonlinearity, often called an activation function (see Section 4.4). The value αk≔Wksk−1+bk\alphav_k \coloneqq \W_k \sv_{k-1} + \bv_k is often called the pre-activation value and the value ak(αk)a_k(\alphav_k) is the activation value.

More generally, we may replace the matrix-vector product Wksk−1\W_k \sv_{k-1} by any parametrized linear function of sk−1\sv_{k-1}. For example, convolutional layers use the convolution of an input sk−1\sv_{k-1} with some filters WkW_k, seen as a linear map.

Remark 4.1 (Dealing with multiple inputs)

Sometimes, it is necessary to deal with networks of multiple inputs. For example, suppose we want to design a function g(x1,x2,wg)g(\x_1, \x_2, \w_g), where x1∈X1\x_1 \in \cX_1 and x2∈X2\x_2 \in \cX_2. A simple way to do so is to use the concatenation x≔x1⊕x2∈X1⊕X2\x \coloneqq \x_1 \oplus \x_2 \in \cX_1 \oplus \cX_2 as input to a network f(x,wf)f(\x, \w_f). Alternatively, instead of concatenating x1\x_1 and x2\x_2 at the input layer, they can be concatenated after having been through one or more hidden layers.

4.3.2 Link with generalized linear models

When the depth is K=1K=1 (only one layer), the output of an MLP is s1=a1(W1x+b1). \s_1 = a_1(\W_1 \xv + \bv_1). This is called a generalized linear model (GLM); see Section 3.4. Therefore, MLPs include GLMs as a special case. In particular, when a1a_1 is the softargmax (see Section 4.4), we obtain (multiclass) logistic regression. For general depth KK, the output of an MLP is sK=aK(WKsK−1+bK). \s_K = a_K(\W_K \sv_{K-1} + \bv_K). This can be seen as a GLM on top of learned representation sK−1\sv_{K-1} of the input x\xv. This is the main appeal of MLPs: they learn the feature representation and the output model at the same time! We will see that MLPs can also be used as subcomponents in other architectures.

4.4 Activation functions

As we saw in Section 4.3, feedforward networks typically use an activation function aka_k at each layer. In this section, we present various nonlinearities from scalar to scalar or from vector to scalar. We also present probability mappings that can be used as such activations.

4.4.1 ReLU and softplus

Many activations are scalar-to-scalar functions, but they can also be applied to vectors in an element-wise fashion. The ReLU (rectified linear unit) is a popular nonlinearity defined as the non-negative part of its input relu(u)≔max⁡(u,0)={u,u≥00,u<0. \mathrm{relu}(u) \coloneqq \max(u, 0) = \begin{cases} u, & u \ge 0 \\ 0, & u < 0 \end{cases}. It is a piecewise linear function and includes a kink at u=0u=0. A multilayer perceptron with ReLU activations is called a rectifier neural network. The layers take the form sk=relu(Aksk−1+bk), \sv_k = \mathrm{relu}(\Av_k \sv_{k-1} + \bv_k), where the ReLU is applied element-wise. The ReLU can be replaced with a smooth approximation (i.e., without kinks), called the softplus softplus(u)≔log⁡(1+eu). \mathrm{softplus}(u) \coloneqq \log(1 + e^u). Unlike the ReLU, it is always strictly positive. Other smoothed variants of the ReLU are possible, see Section 13.4.

4.4.2 Max pooling and log-sum-exp

Many activations are vector-to-scalar functions: they reduce vectors to a scalar value. This scalar value can be seen as a statistic, “summarizing” the vector.

Max pooling

An example of vector-to-scalar reduction is the maximum value, also known as max pooling. Given a vector u∈RM\u \in \R^M, it is defined as max⁡(u)≔max⁡j∈[M]uj. \max(\u) \coloneqq \max_{j \in [M]} u_j.

Figure 4.5: The maximum operator is a piecewise linear function. The log-sum-exp (a.k.a. softmax) is a smoothed approximation.

Log-sum-exp as a soft maximum

Another example of vector-to-scalar reduction is the log-sum-exp, logsumexp(u)≔softmax(u)≔log⁡∑j=1Meuj. \lse(\u) \coloneqq \mathrm{softmax}(\u) \coloneqq \log \sum_{j=1}^M e^{u_j}. As illustrated in Fig. 4.5, it is known to behave like a soft maximum. The log-sum-exp can be seen as a generalization of the softplus, as we have for all u∈Ru \in \RR logsumexp((u,0))=softplus(u). \lse((u, 0)) = \mathrm{softplus}(u). A numerically stable implementation of the log-sum-exp is given by logsumexp(u)=logsumexp(u−c1⁡)+c, \lse(\u) = \lse(\u - c\ones) + c, where c≔max⁡j∈[M]ujc \coloneqq \max_{j \in [M]} u_j.

More generally, we can introduce a temperature parameter γ>0\gamma > 0 logsumexpγ(u)=γ⋅logsumexp(u/γ). \lse_\gamma(\u) = \gamma \cdot \lse(\u / \gamma). It can be shown that for all u∈RM\u \in \RR^M, max⁡(u)≤logsumexpγ(u)≤max⁡(u)+γ⋅log⁡(M). \max(\u) \le \lse_\gamma(\u) \le \max(\u) + \gamma \cdot \log(M). Therefore, logsumexpγ(u)→max⁡(u)\lse_\gamma(\u) \to \max(\u) as γ→0\gamma \to 0. Other definitions of soft maximum are possible; see Section 13.5.

Log-sum-exp as a log-domain sum

Besides its use as a soft maximum, the log-sum-exp often arises for computing sums in the log domain. Indeed, suppose we want to compute s≔∑i=1Muis \coloneqq \sum_{i=1}^M u_i, where ui>0u_i > 0. If we define u~i≔log⁡ui\tilde{u}_i \coloneqq \log u_i and s~≔log⁡s\tilde{s} \coloneqq \log s, we then have s~=log⁡∑i=1Mexp⁡(u~i). \tilde{s} = \log \sum_{i=1}^M \exp(\tilde{u}_i). Written differently, we have the identity log⁡(∑i=1Mui)=logsumexp(log⁡(u)). \log\left(\sum_{i=1}^M u_i\right) = \lse(\log(\u)). We can therefore see the log-sum-exp as the sum counterpart of the identity for products log⁡(∏i=1Mui)=∑i=1Mlog⁡(ui). \log\left(\prod_{i=1}^M u_i \right) = \sum_{i=1}^M \log(u_i). As an example, we use the log-sum-exp to perform the forward-backward algorithm in the log-domain in Section 10.7.1.

4.4.3 Sigmoids: binary step and logistic functions

Oftentimes, we want to map a real value to a number in [0,1][0,1], that can represent the probability of an event. For that purpose, we generally use sigmoids. A sigmoid is a function with a characteristic “S”-shaped curve. These functions are scalar-to-scalar probability mappings: they are used to squash real values to [0,1][0,1].

Binary step function

An example is the binary step function, also known as Heaviside step function, step(u)≔{1,u≥00,u<0. \mathrm{step}(u) \coloneqq \begin{cases} 1, & u \ge 0 \\ 0, & u < 0 \end{cases}. It is a mapping from R\R to {0,1}\{0, 1\}. Unfortunately, it has a discontinuity: a jump in its graph at u=0u=0. Moreover, because the function is constant at all other points, it has zero derivative at these points, which makes it difficult to use as part of a neural network trained with backpropagation.

Logistic function

A better sigmoid is the logistic function, which is a mapping from R\R to (0,1)(0, 1) and is defined as logistic(u)≔11+e−u=eu1+eu=12+12tanh⁡(u2).\begin{align*} \mathrm{logistic}(u) &\coloneqq \frac{1}{1 + e^{-u}} \\ &= \frac{e^u}{1 + e^u} \\ &= \frac{1}{2} + \frac{1}{2} \tanh\left(\frac{u}{2}\right). \end{align*} It maps (−∞,0)(-\infty, 0) to (0,0.5)(0, 0.5), [0,+∞)[0, +\infty) to [0.5,1)[0.5, 1) and it satisfies logistic(0)=0.5\mathrm{logistic}(0) = 0.5. It can therefore be seen as mapping from real values to probability values. The logistic can be seen as a differentiable approximation to the discontinuous binary step function step(u)\mathrm{step}(u). The logistic function can be shown to be the derivative of softplus, i.e., for all u∈Ru \in \RR softplus′(u)=logistic(u). \mathrm{softplus}'(u) = \mathrm{logistic}(u). Two important properties of the logistic function are that for all u∈Ru \in \RR logistic(−u)=1−logistic(u) \mathrm{logistic}(-u) = 1 - \mathrm{logistic}(u) and logistic′(u)=logistic(u)⋅logistic(−u)=logistic(u)⋅(1−logistic(u)).\begin{align*} \mathrm{logistic}'(u) &= \mathrm{logistic}(u) \cdot \mathrm{logistic}(-u) \\ &= \mathrm{logistic}(u) \cdot (1 - \mathrm{logistic}(u)). \end{align*} Other sigmoids are possible; see Section 13.6.

4.4.4 Probability mappings: argmax and softargmax

It is often useful to transform a real vector into a vector of probabilities. This is a mapping from RM\R^M to the probability simplex, defined by △M≔{π∈RM ⁣:∀j∈[M], πj≥0, ∑j=1Mπj=1}. \triangle^M \coloneqq \left\{\piv \in \R^M \colon \forall j \in [M],\ \pi_j \geq 0,\ \sum_{j=1}^M \pi_j= 1\right\}. Two examples of such vector-to-vector probability mappings are the argmax and the softargmax.

Argmax

The argmax operator is defined by argmax(u)≔ϕ(arg max⁡j∈[M]uj)∈{e1,…,eM}, \mathrm{argmax}(\u) \coloneqq \phi\left(\argmax_{j \in [M]} u_j\right) \in \{\e_1, \dots, \e_M\}, where ϕ(j)\phi(j) denotes the one-hot encoding of an integer j∈[M]j \in [M], that is, ϕ(j)≔(0,…,0,1⏟j,0,…,0)=ej∈{0,1}M. \phi(j) \coloneqq (0, \ldots, 0, \underbrace{1}_j, 0, \ldots, 0) = \e_j \in \{0,1\}^M. This mapping puts all the probability mass onto a single coordinate (in case of ties, we pick a single coordinate arbitrarily). Unfortunately, this mapping is a discontinuous function.

Softargmax

As a differentiable everywhere relaxation, we can use the softargmax defined by softargmax(u)≔exp⁡(u)∑j=1Mexp⁡(uj)∈relint(△M). \mathrm{softargmax}(\u) \coloneqq \frac{\exp(\u)}{\sum_{j=1}^M \exp(u_j)} \in \mathrm{relint}(\triangle^M). This operator is commonly known in the literature as softmax but this is a misnomer: this operator really defines a differentiable relaxation of the argmax. The output of the softargmax belongs to the relative interior of the probability simplex relint(△M)={π∈△M ⁣:π>0}\mathrm{relint}(\triangle^M) = \{\piv \in \triangle^M \colon \piv > \zeros\}, meaning that it can never reach the borders of the simplex. If we denote π=softargmax(u)\piv = \mathrm{softargmax}(\u), this means that πj∈(0,1)\pi_j \in (0,1), that is, πj\pi_j can never be exactly 00 or 11. The softargmax\mathrm{softargmax} is the gradient of log-sum-exp, ∇logsumexp(u)=softargmax(u). \nabla \mathrm{logsumexp}(\u) = \mathrm{softargmax}(\u). The softargmax\mathrm{softargmax} can be seen as a generalization of the logistic function, as we have for all u∈Ru \in \RR [softargmax((u,0))]1=logistic(u). [\mathrm{softargmax}((u, 0))]_1 = \mathrm{logistic}(u).

Remark 4.2 (Degrees of freedom and invertibility of softargmax)

The softargmax operator satisfies the property for all u∈RM\u \in \RR^M and c∈Rc \in \RR π≔softargmax(u)=softargmax(u+c1⁡). \piv \coloneqq \mathrm{softargmax}(\u) = \mathrm{softargmax}(\u + c \ones). This means that the softargmax operator has M−1M-1 degrees of freedom and is a non-invertible function. However, due to the above property, without loss of generality, we can impose u⊤1⁡=∑i=1Mui=0\u^\top \ones = \sum_{i=1}^M u_i = 0 (if this is not the case, we simply do ui←ui−uˉu_i \leftarrow u_i - \bar{u}, where uˉ≔1M∑j=1Muj\bar{u} \coloneqq \frac{1}{M} \sum_{j=1}^M u_j). Using this constraint together with log⁡πi=ui−log⁡∑j=1Mexp⁡(uj), \log \pi_i = u_i - \log \sum_{j=1}^M \exp(u_j), we then obtain ∑i=1Mlog⁡πi=−Mlog⁡∑j=1Mexp⁡(uj) \sum_{i=1}^M \log \pi_i = - M \log \sum_{j=1}^M \exp(u_j) so that ui=[softargmax−1(π)]i=log⁡πi−1M∑j=1Mlog⁡πj. u_i = [\mathrm{softargmax}^{-1}(\piv)]_i = \log \pi_i - \frac{1}{M} \sum_{j=1}^M \log \pi_j.

Figure 4.6: The argmax, the softargmax and the sparseargmax (see Section 13.7) are mappings from RM\RR^M to the probability simplex △M≔{π∈R+M ⁣:⟨π,1⁡⟩=1}\triangle^M \coloneqq \{\piv \in \RR^M_+ \colon \langle \piv, \ones \rangle =1\}. More precisely, the argmax maps to vertices of the probability simplex, the set of one-hot vectors {e1,…,eM}\{\e_1, \dots, \e_M\}, the softargmax maps to the relative interior relint(△M)={π∈△M ⁣:π>0}\mathrm{relint}(\triangle^M) = \{\piv \in \triangle^M \colon \piv > \zeros\} and the sparseargmax maps to the entire probability simplex △M\triangle^M, including sparse probability vectors. Sigmoids applied element-wise return vectors in the hypercube [0,1]M[0,1]^M, whose vertices are the 2M2^M vectors in {0,1}M\{0,1\}^M.

4.5 Normalization layers

Intermediate states in neural networks, such as activations, can often attain a wide range of different values, potentially making it difficult for gradient descent to converge. To remedy this issue, we can introduce normalization layers at suitable locations in the network. In this section, we present the two most popular ones: batch normalization and layer normalization.

4.5.1 Batch normalization

Suppose we are given a batch of intermediate variables (such as activations or states) s1,…,sB∈RD\s_1,\dots,\s_B \in \RR^D, where si≔(si,1,…,si,D)\s_i \coloneqq (s_{i,1},\dots, s_{i,D}), obtained by applying some function to BB samples drawn from the training set (we omit the dependency on the layer index kk for clarity). In batch normalization (Ioffe and Szegedy, 2015), we normalize the values by calculating the standard score (a.k.a. z-score) across batch samples, μj≔1B∑i=1Bsi,j∀j∈[D]σj2≔1B∑i=1B(si,j−μj)2∀j∈[D]s^i,j≔si,j−μjσji∈[B],j∈[D].\begin{align*} \mu_{\blue{j}} &\coloneqq \frac{1}{B} \sum_{\blue{i=1}}^{\blue{B}} s_{i,j} \quad \forall j \in [D] \\ \sigma_{\blue{j}}^2 &\coloneqq \frac{1}{B} \sum_{\blue{i=1}}^{\blue{B}} (s_{i,j} - \mu_j)^2 \quad \forall j \in [D]\\ \widehat{s}_{i,j} &\coloneqq \frac{s_{i,j} - \mu_j}{\sigma_j} \quad i \in [B], j \in [D]. \end{align*} Here, the means μj\mu_j and the standard deviations σj\sigma_j are computed for each feature j∈[D]j \in [D] across samples i∈[B]i \in [B] in the batch. In practice, we often add a small value ε>0\varepsilon > 0 to σj\sigma_j to avoid division by zero or numerical instabilities. Moreover, we often rescale the values as s~i,j≔βj+γjs^i,ji∈[B],j∈[D], \widetilde{s}_{i,j} \coloneqq \beta_j + \gamma_j \widehat{s}_{i,j} \quad i \in [B], j \in [D], where the means β≔(β1,…,βD)\betav \coloneqq (\beta_1, \dots, \beta_D) and standard deviations γ≔(γ1,…,γD)\gammav \coloneqq (\gamma_1, \dots, \gamma_D) are learnable parameters.

One issue with batch normalization is that the means μj\mu_j and standard deviations σj\sigma_j cannot be computed at inference time, as there is no notion of training batch (a single sample would lead to a variance of 00). To address this issue, we can estimate means μ^j\widehat{\mu}_j and standard deviations σ^j\widehat{\sigma}_j across the whole training set during the course of training, usually using a running average. A practical batch normalization implementation therefore needs to maintain DD mean and standard deviation statistics, so as to be able to use them at inference time.

4.5.2 Layer normalization

As an alternative, in layer normalization (Ba et al., 2016), we instead standardize the values by summing across features, μi≔1D∑j=1Dsi,j∀i∈[B]σi2≔1D∑j=1D(si,j−μi)2∀i∈[B]s^i,j≔si,j−μiσii∈[B],j∈[D].\begin{align*} \mu_{\blue{i}} &\coloneqq \frac{1}{D} \sum_{\blue{j=1}}^{\blue{D}} s_{i,j} \quad \forall i \in [B] \\ \sigma_{\blue{i}}^2 &\coloneqq \frac{1}{D} \sum_{\blue{j=1}}^{\blue{D}} (s_{i,j} - \mu_i)^2 \quad \forall i \in [B] \\ \widehat{s}_{i,j} &\coloneqq \frac{s_{i,j} - \mu_i}{\sigma_i} \quad i \in [B], j \in [D]. \end{align*} This time, the means μi\mu_i and the standard deviations σi\sigma_i are computed for each sample i∈[B]i \in [B] across features j∈[D]j \in [D] (as before, we often add a small value ε\varepsilon to σi\sigma_i). Similarly to batch normalization, we often rescale the values as s~i,j≔βj+γjs^i,ji∈[B],j∈[D], \widetilde{s}_{i,j} \coloneqq \beta_j + \gamma_j \widehat{s}_{i,j} \quad i \in [B], j \in [D], where the means β≔(β1,…,βD)\betav \coloneqq (\beta_1, \dots, \beta_D) and standard deviations γ≔(γ1,…,γD)\gammav \coloneqq (\gamma_1, \dots, \gamma_D) are learnable parameters. A key advantage of layer normalization compared to batch normalization is that it is well defined at inference time, since it is applied on a per-sample basis and does not rely on the notion of a training batch. As a result, we can view layer normalization as a function that to any si∈RD\s_i \in \RR^D (regardless of whether it is part of a batch or not) associates si~≔LayerNorm(si). \widetilde{\s_i} \coloneqq \mathrm{LayerNorm}(\s_i).

4.6 Residual neural networks

We now discuss another feedforward network parametrization: residual neural networks. Consider a feedforward network with K+1K+1 layers f1f_1, …\dots, fKf_K, fK+1f_{K+1}. Surely, as long as fK+1f_{K+1} can exactly represent the identity function, the set of functions that this feedforward network can express should be a superset of the functions that f1f_1, …\dots, fKf_K can express. In other words, depth should in theory not hurt the expressive power of feedforward networks. Unfortunately, the assumption that each fkf_k can exactly represent the identity function may not hold in practice. This means that deeper networks can sometimes be more difficult to train than shallower ones, making the accuracy saturate or degrade as a function of depth.

The key idea of residual neural networks (He et al., 2016) is to design layers fkf_k, called residual blocks, that make it easier to represent the identity function. Formally, a residual block takes the form sk=fk(sk−1,wk)≔sk−1+hk(sk−1,wk). \sv_k = f_k(\sv_{k-1}, \wv_k) \coloneqq \sv_{k-1} + h_k(\sv_{k-1}, \wv_k). The function hkh_k is called residual, since it models the difference sk−sk−1\sv_k - \sv_{k-1}. The addition with sk−1\sv_{k-1} is often called a skip connection. As long as it is easy to adjust wk\wv_k so that hk(sk−1,wk)=0h_k(\sv_{k-1}, \wv_k) = \zeros, fkf_k can freely become the identity function. For instance, if we use hk(sk−1,wk)≔Ckak(Wksk−1+bk)+dk, h_k(\sv_{k-1}, \wv_k) \coloneqq \Cv_k a_k(\W_k \sv_{k-1} + \bv_k) + \dv_k, where wk≔(Wk,bk,Ck,dk)\wv_k \coloneqq (\W_k, \bv_k, \Cv_k, \dv_k), it suffices to set Ck\Cv_k and dk\dv_k to a zero matrix and vector. Residual blocks are known to remedy the so-called vanishing gradient problem.

Many papers and software packages include an additional activation and instead define the residual block as sk=fk(sk−1,wk)≔ak(sk−1+hk(sk−1,wk)), \sv_k = f_k(\sv_{k-1}, \wv_k) \coloneqq a_k(\sv_{k-1} + h_k(\sv_{k-1}, \wv_k)), where aka_k is typically chosen to be the ReLU activation. Whether to include this additional activation or not is essentially a modelling choice. In practice, residual blocks may also include additional operations such as batch norm and convolutional layers.

4.7 Recurrent neural networks

Recurrent neural networks (RNNs) are a class of neural networks that operate on sequences of vectors, either as input, output or both. Their actual parametrization depends on the setup but the core idea is to maintain a state vector that is updated from step to step by a recursive function that uses shared parameters across steps. Unrolling this recursion defines a valid computational graph, as we will see in Chapter 8. We distinguish between the following setups illustrated in Fig. 4.7:

where LL stands for length. Note that we use the same number of parameters PP for each setup for notational convenience, but this of course does not need to be the case. Throughout this section, we use the notation p1:L≔(p1,…,pL)\p_{1:L} \coloneqq (\p_1, \dots, \p_L) for a sequence of LL vectors.

(a) One to many (decoder)

(b) Many to one (encoder)

(c) Sequence to sequence aligned

(d) Sequence to sequence unaligned

Figure 4.7: Recurrent neural network architectures

4.7.1 Vector to sequence

In this setting, we define a decoder function p1:L=fd(x,w)\p_{1:L} = f^d(\xv, \wv) from an input vector x∈RD\x \in \R^D and parameters w∈RP\w \in \R^P to an output sequence p1:L∈RL×M\p_{1:L} \in \R^{L \times M}. This is for instance useful for image caption generation, where a sentence (a sequence of word embeddings) is generated from an image (a vector of pixels). Formally, we may define p1:L≔fd(x,w)\p_{1:L} \coloneqq f^d(\x, \w) through the recursion zl≔g(x,zl−1,wg)l∈[L]pl≔h(zl,wh)l∈[L]. \begin{aligned} \z_l &\coloneqq g(\x, \z_{l-1}, \w_g) \quad l \in [L] \\ \p_l &\coloneqq h(\z_l, \w_h) \quad l \in [L]. \end{aligned} where w≔(wg,wh,z0)\wv \coloneqq (\w_g, \w_h, \z_0). The goal of gg is to update the current decoder state zl\z_l given the input x\x, and the previous decoder state zl−1\z_{l-1}. The goal of hh is to generate the output pl\p_l given the current decoder state zl\z_l. Importantly, the parameters of gg and hh are shared across steps. Typically, gg and hh are parametrized using one-hidden-layer MLPs. Note that gg has multiple inputs; we discuss how to deal with such cases in Section 4.3.

4.7.2 Sequence to vector

In this setting, we define an encoder function p=fe(x1:L,w)\p = f^e(\x_{1:L}, \wv) from an input sequence x1:L∈RL×D\x_{1:L} \in \R^{L \times D} and parameters w∈RP\w \in \R^P to an output vector p∈RM\p \in \R^M. This is for instance useful for sequence classification, such as sentiment analysis. Formally, we may define p≔fe(x1:L,w)\p \coloneqq f^e(\x_{1:L}, \w) using the recursion sl≔γ(xl,sl−1,wγ)l∈[L]p=pooling(s1:L) \begin{aligned} \s_l &\coloneqq \gamma(\x_l, \s_{l-1}, \w_\gamma) \quad l \in [L] \\ \p &= \mathrm{pooling}(\s_{1:L}) \end{aligned} where w≔(wγ,s0)\w \coloneqq (\w_\gamma, \s_0). The goal of γ\gamma is similar to gg, except that it updates encoder states and does not take previous predictions as input. The pooling function is typically parameter-less. Its goal is to reduce a sequence to a vector. Examples include using the last state, the average of states and the coordinate-wise maximum of states.

4.7.3 Sequence to sequence (aligned)

In this setting, we define a function p1:L=fa(x1:L,w)\p_{1:L} = f^a(\x_{1:L}, \wv) from an input sequence x1:L∈RL×D\x_{1:L} \in \R^{L \times D} and parameters w∈RP\w \in \R^P to an output sequence p1:L∈RL×M\p_{1:L} \in \R^{L \times M}, which we assume to be of the same length. An example of application is part-of-speech tagging, where the goal is to assign each word xl\x_l to a part-of-speech (noun, verb, adjective, etc). Formally, we may define p1:L=fa(x1:L,w)\p_{1:L} = f^a(\x_{1:L}, \w) as sl≔γ(xl,sl−1,wγ)l∈[L]pl=h(sl,wh)l∈[L] \begin{aligned} \s_l &\coloneqq \gamma(\x_l, \s_{l-1}, \w_\gamma) \quad l \in [L] \\ \p_l &= h(\s_l, \w_h) \quad l \in [L] \\ \end{aligned} where w≔(wγ,wh,s0)\wv \coloneqq (\wv_\gamma, \wv_h, \sv_0). The functions γ\gamma and hh are similar as before.

4.7.4 Sequence to sequence (unaligned)

In this setting, we define a function p1:L′=fu(x1:L,w)\p_{1:L'} = f^u(\x_{1:L}, \wv) from an input sequence x1:L∈RL×D\x_{1:L} \in \R^{L \times D} and parameters w∈RP\w \in \R^P to an output sequence p1:L′∈RL′×M\p_{1:L'} \in \R^{L' \times M}, which potentially has a different length. An example of application is machine translation, where the sentences in the source and target languages do not necessarily have the same length. Typically, p1:L′=fu(x1:L,w)\p_{1:L'} = f^u(\x_{1:L}, \w) is defined as the following two steps c≔fe(x1:L,we)p1:L′≔fd(c,wd) \begin{aligned} \c &\coloneqq f^e(\x_{1:L}, \w_e) \\ \p_{1:L'} &\coloneqq f^d(\c, \w_d) \end{aligned} where w≔(we,wd)\w \coloneqq (\w_e, \w_d), and where we reused the previously-defined encoder fef^e and decoder fdf^d. Putting the two steps together, we obtain sl≔γ(xl,sl−1,wγ)l∈[L]c=pooling(s1:L)zl≔g(c,pl−1,zl−1,wg)l∈[L′]pl≔h(zl,wh)l∈[L′]. \begin{aligned} \s_l &\coloneqq \gamma(\x_l, \s_{l-1}, \w_\gamma) \quad l \in [L] \\ \c &= \mathrm{pooling}(\s_{1:L}) \\ \z_l &\coloneqq g(\c, \p_{l-1}, \z_{l-1}, \w_g) \quad l \in [L'] \\ \p_l &\coloneqq h(\z_l, \w_h) \quad l \in [L']. \end{aligned}

This architecture is aptly named the encoder-decoder architecture. Note that we denoted the length of the target sequence as L′L'. However, in practice, the target length can be input dependent and is often not known ahead of time. To deal with this issue, the vocabulary (of size DD in our notation) is typically augmented with an “end of sequence” (EOS) token so that, at inference time, we know when to stop generating the output sequence. One disadvantage of this encoder-decoder architecture, however, is that all the information about the input sequence is contained in the context vector c\c, which can therefore become a bottleneck.

4.8 Transformers

Transformers (Vaswani et al., 2017) are one of the most successful recent developments in deep learning. In this section, we review Transformers, component by component.

4.8.1 Attention

The goal of an attention layer is to map a sequence of inputs v1,…,vL∈RDv\v_1,\dots,\v_L \in \RR^{D_v} to a sequence of outputs u1,…,uL∈RDv\u_1,\dots,\u_L \in \RR^{D_v}, of same dimension. A natural idea is to define each output element ui\u_i using a linear combination of the input elements, ui≔∑j=1Lai,jvj∈RDv. \u_i \coloneqq \sum_{j=1}^L a_{i,j} \v_j \in \RR^{D_v}. We typically use a convex combination: we assume that the combination weights are such that ai≔(ai,1,…,ai,L)∈△L\a_i \coloneqq (a_{i,1},\dots,a_{i,L}) \in \triangle^L. This ensures that increasing a coefficient ai,ja_{i,j} is made at the expense of decreasing another coefficient ai,j′a_{i,j'}, for j≠j′j \neq j'. Let us form the matrices V∈RL×Dv\V \in \RR^{L \times D_v} and U∈RL×Dv\U \in \RR^{L \times D_v} by stacking v1,…,vL\v_1,\dots,\v_L and u1,…,uL\u_1,\dots,\u_L, seen as row vectors. Let us also form the attention matrix A∈△L×L\A \in \triangle^{L \times L} gathering the entries ai,ja_{i,j}, where △L×L\triangle^{L \times L} denotes the set of row-wise stochastic L×LL \times L matrices. Then, we can rewrite attention succinctly as U=AV∈RL×Dv. \U = \A \V \in \RR^{L \times D_v}. Following Section 6.2, we can view attention as a soft dictionary lookup. From this perspective, the matrix V∈RL×Dv\V \in \RR^{L \times D_v} plays the role of dictionary values, and the attention matrix can be defined as A≔softargmax(QK⊤)∈△L×L, \A \coloneqq \mathrm{softargmax}(\Q \K^\top) \in \triangle^{L \times L}, where Q∈RL×Dk\Q \in \RR^{L \times D_k} and K∈RL×Dk\K \in \RR^{L \times D_k} play the roles of queries and dictionary keys, respectively. Intuitively, QK⊤∈RL×L\Q\K^\top \in \RR^{L \times L} can be seen as a similarity matrix containing the similarities between queries and dictionary keys. Putting everything together, we can define attention as Attention(Q,K,V)≔softargmax(QK⊤)V∈RL×Dv. \mathrm{Attention}(\Q, \K, \V) \coloneqq \mathrm{softargmax}\left(\Q \K^\top\right)\V \in \RR^{L \times D_v}. In masked attention, we additionally incorporate a mask M∈RL×L\M \in \RR^{L \times L}, Attention(Q,K,V;M)≔softargmax((QK⊤)∘M)V∈RL×Dv, \mathrm{Attention}(\Q, \K, \V; \M) \coloneqq \mathrm{softargmax}\left((\Q \K^\top) \circ \M\right)\V \in \RR^{L \times D_v}, where ∘\circ denotes the Hadamard product (element-wise multiplication). The mask can be used to force some attention weights ai,ja_{i,j} to be zero, by setting the corresponding mask entry mi,jm_{i,j} to −∞-\infty. For instance, in decoder-only architectures (Section 4.8.8), the mask will prove useful to define causal attention for autoregressive models.

Remark 4.3 (Scaled attention)

Practical implementations often use scaled attention, where a factor of 1Dk\frac{1}{\sqrt{D_k}} is used within the soft-argmax, in order to reduce the variance (Vaswani et al., 2017, Footnote 4). We omit this detail for clarity.

4.8.2 Self-attention

Suppose we are given a sequence of feature vectors x1,…,xL∈RD\x_1, \dots, \x_L \in \RR^D, that we gather as a matrix X∈RL×D\X \in \RR^{L \times D}. To define the attention weights ai,ja_{i,j}, a natural idea is to consider the similarity between xi\x_i and xj\x_j, as measured by the inner product ⟨xi,xj⟩\langle \x_i, \x_j \rangle. To ensure that ai≔(ai,1,…,ai,L)∈△L\a_i \coloneqq (a_{i,1},\dots,a_{i,L}) \in \triangle^L, we can then define ai,j≔exp⁡(⟨xi,xj⟩)∑j′=1Lexp⁡(⟨xi,xj′⟩)∈(0,1). a_{i,j} \coloneqq \frac{\exp(\langle \x_i, \x_j \rangle)}{ \sum_{j'=1}^L \exp(\langle \x_i, \x_{j'} \rangle)} \in (0,1). In matrix notation, this can be written A≔softargmax(XX⊤)∈△L×L, \A \coloneqq \mathrm{softargmax}(\X \X^\top) \in \triangle^{L \times L}, where softargmax\mathrm{softargmax} is applied in a row-wise fashion. The matrix XX⊤∈RL×L\X \X^\top \in \RR^{L \times L} is the Gram matrix associated with the row vectors x1,…,xL\x_1, \dots, \x_L. In the notation of the previous section, this corresponds to using Attention(Q,K,V)\mathrm{Attention}(\Q, \K, \V) with Q=K=V=X\Q = \K = \V = \X. In other words, the elements of the sequence “pay attention” to each other. This is called self-attention.

So far, the formulation we described is parameter-free. To give more expressive power to the self-attention layer, Vaswani et al. (2017) proposed instead to define Q\Q, K\K and V\V by projecting X\X as Q≔XWQ∈RL×DkK≔XWK∈RL×DkV≔XWV∈RL×Dv,\begin{align*} \Q &\coloneqq \X \W^Q \in \RR^{L \times D_k} \\ \K &\coloneqq \X \W^K \in \RR^{L \times D_k}\\ \V &\coloneqq \X \W^V \in \RR^{L \times D_v}, \end{align*} using the learned weight matrices WQ∈RD×DkWK∈RD×DkWV∈RD×Dv.\begin{align*} \W^Q &\in \RR^{D \times D_k} \\ \W^K &\in \RR^{D \times D_k} \\ \W^V &\in \RR^{D \times D_v}. \end{align*} Importantly, the size of the weight matrices is independent of the length LL of the sequences. This allows self-attention to work with sequences of arbitrary length.

4.8.3 Multi-head attention

In order to be able to capture multiple patterns of attention, Vaswani et al. (2017) found it beneficial to define HH attention heads Yi≔Attention(Qi,Ki,Vi;M)∈RL×Dv, \Y_i \coloneqq \mathrm{Attention}(\Q_i, \K_i, \V_i; \M) \in \RR^{L \times D_v}, where Qi≔XWiQ∈RL×DkKi≔XWiK∈RL×DkVi≔XWiV∈RL×Dv,\begin{align*} \Q_i &\coloneqq \X \W^Q_i \in \RR^{L \times D_k} \\ \K_i &\coloneqq \X \W^K_i \in \RR^{L \times D_k} \\ \V_i &\coloneqq \X \W^V_i \in \RR^{L \times D_v}, \end{align*} using the learned weight matrices WiQ∈RD×DkWiK∈RD×DkWiV∈RD×Dv.\begin{align*} \W^Q_i &\in \RR^{D \times D_k} \\ \W^K_i &\in \RR^{D \times D_k} \\ \W^V_i &\in \RR^{D \times D_v}. \end{align*} Let us denote the concatenation of the HH attention heads by Concat(Y1,…,YH)∈RL×HDv. \mathrm{Concat}(\Y_1, \dots, \Y_H) \in \RR^{L \times H D_v}. Vaswani et al. (2017) then define multi-head attention as MultiheadAttention(X;M)≔Concat(Y1,…,YH)WO=∑i=1HAttention(XWiQ,XWiK,XWiV)WiO∈RL×D\begin{align*} \mathrm{MultiheadAttention}(\X; \M) &\coloneqq \mathrm{Concat}(\Y_1, \dots, \Y_H) \W^O \\ &= \sum_{i=1}^H \mathrm{Attention}(\X \W^Q_i, \X \W_i^K, \X \W_i^V) \W_i^O \\ &\in \RR^{L \times D} \end{align*} where WO∈RHDv×D\W^O \in \RR^{H D_v \times D} is a learned matrix. We summarize the procedure in Algorithm 4.2. We use a for loop for the sake of clarity; a GPU-friendly implementation would instead be based on a single matrix multiplication.

Algorithm 4.2: Multi-head attention with HH attention heads

Input: X∈RL×D\X \in \RR^{L \times D}, optional mask M∈RL×L\M \in \RR^{L \times L}

Parameters: {WiQ}i=1H\{\W_i^Q\}_{i=1}^H, {WiK}i=1H\{\W_i^K\}_{i=1}^H, {WiV}i=1H\{\W_i^V\}_{i=1}^H, WO\W^O

for i≔1,…,Hi \coloneqq 1, \ldots, H do

Qi≔XWiQ∈RL×Dk\Q_i \coloneqq \X \W^Q_i \in \RR^{L \times D_k}

Ki≔XWiK∈RL×Dk\K_i \coloneqq \X \W^K_i \in \RR^{L \times D_k}

Vi≔XWiV∈RL×Dv\V_i \coloneqq \X \W^V_i \in \RR^{L \times D_v}

Yi≔Attention(Qi,Ki,Vi;M)∈RL×Dv\Y_i \coloneqq \mathrm{Attention}(\Q_i, \K_i, \V_i; \M) \in \RR^{L \times D_v}

Y≔Concat(Y1,…,YH)WO\Y \coloneqq \mathrm{Concat}(\Y_1, \dots, \Y_H) \W^O

Output: MultiheadAttention(X;M)≔Y∈RL×D\mathrm{MultiheadAttention}(\X; \M) \coloneqq \Y \in \RR^{L \times D}

4.8.4 Transformer layer

To improve training efficiency, we can introduce residual connections and a first layer normalization (Section 4.5.2), to define Z≔LayerNorm1(MultiheadAttention(X;M)+X)∈RL×D. \Z \coloneqq \mathrm{LayerNorm}_1(\mathrm{MultiheadAttention}(\X; \M) + \X) \in \RR^{L \times D}. To improve expressiveness, a Transformer layer further uses an MLP and a second layer normalization, X←LayerNorm2(MLP(Z)+Z)∈RL×D. \X \leftarrow \mathrm{LayerNorm}_2(\mathrm{MLP}(\Z) + \Z) \in \RR^{L \times D}. The subscripts in LayerNorm\mathrm{LayerNorm} are used to emphasize that the two layers use their own parameters. In addition, normalization is applied in an element-wise (token-wise) fashion. The MLP block typically uses a single hidden layer with an activation function σ\sigma, such as a GELU (Gaussian error linear unit); see Algorithm 4.3. Because of the use of residual connections, the input and output dimensions of the MLP block must be the same.

Algorithm 4.3: Transformer’s MLP block

Input: Z∈RL×D\Z \in \RR^{L \times D}

Parameters: W1∈RD×D1,W2∈RD1×D\W_1 \in \RR^{D \times D_1}, \W_2 \in \RR^{D_1 \times D}

Z←ZW1∈RL×D1\Z \leftarrow \Z \W_1 \in \RR^{L \times D_1}

Z←σ(Z)∈RL×D1\Z \leftarrow \sigma(\Z) \in \RR^{L \times D_1}

Z←ZW2∈RL×D\Z \leftarrow \Z \W_2 \in \RR^{L \times D}

Output: Z∈RL×D\Z \in \RR^{L \times D}

Remark 4.4 (Post-normalization vs. pre-normalization)

Our description of the Transformer layer follows the original formulation (Vaswani et al., 2017), which uses post-normalization. Some implementations instead rely on pre-normalization, that is, Z≔MultiheadAttention(LayerNorm1(X);M)+X∈RL×DX←MLP(LayerNorm2(Z))+Z∈RL×D.\begin{align*} \Z &\coloneqq \mathrm{MultiheadAttention}(\mathrm{LayerNorm}_1(\X); \M) + \X \in \RR^{L \times D} \\ \X &\leftarrow \mathrm{MLP}(\mathrm{LayerNorm}_2(\Z)) + \Z \in \RR^{L \times D}. \end{align*}

4.8.5 Transformer block

A Transformer layer can be iterated KK times (each time with different parameters) to define a Transformer block of depth KK. Keeping the dependency on parameters implicit, we can see a Transformer, with an optional mask M∈RL×L\M \in \RR^{L \times L}, as a function X↦Transformer(X;M)=Transformer(x1,…,xL;M) \X \mapsto \mathrm{Transformer}(\X; \M) = \mathrm{Transformer}(\x_1, \dots, \x_L; \M) from RL×D\RR^{L \times D} to RL×D\RR^{L \times D}. The Transformer takes a sequence X∈RL×D\X \in \RR^{L \times D} and uses the inter-dependencies between sequence elements to produce a representation of that sequence. We summarize the procedure in Algorithm 4.4. The MultiheadAttention\mathrm{MultiheadAttention}, LayerNorm\mathrm{LayerNorm} and MLP\mathrm{MLP} blocks are indexed by kk to emphasize that their parameters are different for each iteration.

Number of parameters and computational complexity

The Transformer layer can be seen as a function from RL×D\RR^{L \times D} to RL×D\RR^{L \times D}. To offer the same function signature, a standard multi-layer perceptron would have needed O(L2D2)O(L^2 D^2) parameters and a forward pass through the network would have had a time complexity of O(L2D2)O(L^2 D^2) as well. In contrast, a Transformer layer has O(D2)O(D^2) parameters. Self-attention has a complexity of O(L2D)O(L^2 D) and the final MLP layer has a complexity of O(LD2)O(L D^2).

Algorithm 4.4: Transformer block of depth KK

Input: X∈RL×D\X \in \RR^{L \times D}, optional mask M∈RL×L\M \in \RR^{L \times L}

Parameters: Multi-head attention parameters, MLP parameters and layer norm parameters (each depth kk uses different parameters)

for k≔1,…,Kk \coloneqq 1, \ldots, K do

Y≔MultiheadAttentionk(X;M)∈RL×D\Y \coloneqq \mathrm{MultiheadAttention}_k(\X; \M) \in \RR^{L \times D}

Z≔LayerNormk,1(Y+X)∈RL×D\Z \coloneqq \mathrm{LayerNorm}_{k,1}(\Y + \X) \in \RR^{L \times D} ▷  Residual connection

X←LayerNormk,2(MLPk(Z)+Z)∈RL×D\X \leftarrow \mathrm{LayerNorm}_{k,2}(\mathrm{MLP}_k(\Z) + \Z) \in \RR^{L \times D} ▷  MLP layer

Output: X∈RL×D\X \in \RR^{L \times D}

4.8.6 Token encoding

Text can be represented as a sequence x1,…,xLx_1,\dots,x_L of discrete symbols, often called tokens. Here, each token xi∈[M]x_i \in [M], where MM is the vocabulary size, can correspond to words, subwords, or even individual characters, depending on the tokenization procedure. To obtain a sequence of continuous vectors x1,…,xL\x_1, \dots, \x_L, where xi∈RD\x_i \in \RR^D, it is common to use an embedding layer. This layer transforms xi∈[M]x_i \in [M] into xi∈RD\x_i \in \RR^D using the linear projection xi≔WEexi, \x_i \coloneqq \W^E \e_{x_i}, where ej∈RM\e_j \in \RR^M is the one-hot encoding of j∈[M]j \in [M] and WE∈RD×M\W^E \in \RR^{D \times M} is a learnable embedding matrix. The column W:,jE∈RD\W^E_{:, j} \in \RR^D can be interpreted as the continuous representation of token j∈[V]j \in [V]. Usually, the vocabulary includes special tokens such as “BOS” (beginning of sequence), “EOS” (end of sequence) and “PAD” (padding token, to ensure that the sequence is of length LL).

4.8.7 Positional encoding

Due to their parameterization, Transformers are equivariant with respect to permutations: permuting the input sequence and applying the Transformer is equivalent to applying the Transformer and permuting the output sequence. Formally, for any permutation matrix P\cP of size L×LL \times L and input sequence x1,…,xL\x_1, \dots, \x_L seen as a matrix X\X, we have Transformer(PX)=PTransformer(X). \mathrm{Transformer}(\cP \X) = \cP \mathrm{Transformer}(\X). This means that Transformers treat an ordered sequence as a multi-set (a modification of the concept of a set that allows for multiple instances of its elements). To leverage order information in a Transformer, several approaches are possible (Dufter et al., 2022): adding positional encoding (either absolute or relative), modifying the attention matrix and pre-processing the input sequence with an RNN. To add positional encoding, one typically adds a vector pi∈RD\p_i \in \RR^D representing the position i∈[L]i \in [L] to the corresponding element xi∈RD\x_i \in \RR^D, xi←xi+pi. \x_i \leftarrow \x_i + \p_i. An ideal positional encoding should work with any sequence length.

Learned positional encoding

Similarly to the token encoding, a simple way to define a positional encoding is to use an embedding layer. Each position i∈[L]i \in [L] is transformed into a position vector pi∈RD\p_i \in \RR^D by pi≔WPei \p_i \coloneqq \W^P \e_i where ei∈RL\e_i \in \RR^L is the one-hot encoding of i∈[L]i \in [L] and WP∈RD×L\W^P \in \RR^{D \times L} is a learnable embedding matrix. The column W:,iP∈RD\W^P_{:, i} \in \RR^D can be interpreted as the continuous representation of position i∈[L]i \in [L].

Sinusoidal positional encoding

Instead of learning the positional encoding, we can define it in a heuristic manner. For instance, Vaswani et al. (2017) proposed the sinusoidal positional encoding pi≔(pi,1,…,pi,D)\p_i \coloneqq (p_{i,1}, \dots, \p_{i,D}), defined by pi,j≔{sin⁡(ωj⋅i) if j is evencos⁡(ωj−1⋅i) if j is odd∈[−1,1], p_{i,j} \coloneqq \begin{cases} \sin(\omega_j \cdot i) &\mbox{ if } j \text{ is even} \\ \cos(\omega_{j-1} \cdot i) &\mbox{ if } j \text{ is odd} \end{cases} \in [-1,1], where ωj≔1NjD=N−jD \omega_j \coloneqq \frac{1}{N^{\frac{j}{D}}} = N^{-\frac{j}{D}} and where NN is a constant, set to N≔10000N \coloneqq 10000 by the authors. We can gather the values in a position encoding matrix P∈RL×D\bm{P} \in \RR^{L \times D}, as depicted in Fig. 4.8.

Figure 4.8: Heatmap of a positional encoding matrix P∈RL×D\bm{P} \in \RR^{L \times D}, with L=100L=100, D=50D=50, and N=30N=30. The values belong to the range [−1,1][-1,1].

On first sight, sinusoidal positional encoding may seem a bit mysterious. To gain some intuition, it is useful to compare it to a discrete binary encoding of integers, 7↔1116↔1105↔1014↔1003↔0112↔0101↔0010↔000.\begin{align*} 7 &\leftrightarrow \blueO \blueO \blueO \\ 6 &\leftrightarrow \blueO \blueO \redZ \\ 5 &\leftrightarrow \blueO \redZ \blueO \\ 4 &\leftrightarrow \blueO \redZ \redZ \\ 3 &\leftrightarrow \redZ \blueO \blueO \\ 2 &\leftrightarrow \redZ \blueO \redZ \\ 1 &\leftrightarrow \redZ \redZ \blueO \\ 0 &\leftrightarrow \redZ \redZ \redZ. \end{align*} We see that the bits alternate more frequently between 0\redZ and 1\blueO as we go from right to left. The sinusoidal positional encoding achieves a similar behavior, but is continuous. Indeed, each coordinate j∈[D]j \in [D] is associated with a sine wave (when jj is even) or a cosine wave (when jj is odd). The wavelength or period of the wave associated with jj is 2πωj\frac{2 \pi}{\omega_j} and its frequency is ωj2π\frac{\omega_j}{2 \pi}. Since ωj\omega_j is a decreasing function of jj, we see that the waves oscillate more frequently when jj is small. This behavior is illustrated in Fig. 4.9.

Stacking sine and cosine waves has been used for creating random Fourier features (Rahimi and Recht, 2007; Sutherland and Schneider, 2015). These use waves of random frequencies, while sinusoidal positional encoding uses waves of increasing frequency. These approaches therefore mainly differ in the way we choose wave frequencies.

Figure 4.9: Using a sinusoidal positional encoding, each coordinate j∈[D]j \in [D] is associated with a sine or cosine wave. In analogy with a binary encoding, in which lower bits alternate between 00 and 11 more frequently than higher bits, the wave associated with jj oscillates more frequently when jj is small.

Recovering relative positional information

An important property of the sinusoidal positional encoding is that pi+δ\p_{i + \delta} can be represented as a linear function of pi\p_i, for any offset δ\delta (Vaswani et al., 2017; Zhang et al., 2021). The model should therefore be able to easily learn to attend by relative positions. Indeed, using the trigonometric identities for angle sums cos⁡(α+β)=cos⁡(α)cos⁡(β)−sin⁡(α)sin⁡(β)sin⁡(α+β)=sin⁡(α)cos⁡(β)+cos⁡(α)sin⁡(β),\begin{align*} \cos(\alpha + \beta) &= \cos(\alpha) \cos(\beta) - \sin(\alpha) \sin(\beta) \\ \sin(\alpha + \beta) &= \sin(\alpha) \cos(\beta) + \cos(\alpha) \sin(\beta), \end{align*} we have for jj even (pi+δ,j+1pi+δ,j)=(cos⁡(ωj(i+δ))sin⁡(ωj(i+δ)))=(cos⁡(ωj⋅i)cos⁡(ωj⋅δ)−sin⁡(ωj⋅i)sin⁡(ωj⋅δ)sin⁡(ωj⋅i)cos⁡(ωj⋅δ)+cos⁡(ωj⋅i)sin⁡(ωj⋅δ))=(cos⁡(ωj⋅δ)−sin⁡(ωj⋅δ)sin⁡(ωj⋅δ)cos⁡(ωj⋅δ))(cos⁡(ωj⋅i)sin⁡(ωj⋅i))=(cos⁡(ωj⋅δ)−sin⁡(ωj⋅δ)sin⁡(ωj⋅δ)cos⁡(ωj⋅δ))(pi,j+1pi,j)\begin{align*} \begin{pmatrix} p_{i+\delta,j+1} \\ p_{i+\delta,j} \end{pmatrix} &= \begin{pmatrix} \cos(\omega_j (i + \delta)) \\ \sin(\omega_j (i + \delta)) \end{pmatrix} \\ &= \begin{pmatrix} \cos(\omega_j \cdot i) \cos(\omega_j \cdot \delta) - \sin(\omega_j \cdot i) \sin(\omega_j \cdot \delta) \\ \sin(\omega_j \cdot i) \cos(\omega_j \cdot \delta) + \cos(\omega_j \cdot i) \sin(\omega_j \cdot \delta) \end{pmatrix} \\ &= \begin{pmatrix} \cos(\omega_j \cdot \delta) & -\sin(\omega_j \cdot \delta) \\ \sin(\omega_j \cdot \delta) & \cos(\omega_j \cdot \delta) \end{pmatrix} \begin{pmatrix} \cos(\omega_j \cdot i) \\ \sin(\omega_j \cdot i) \end{pmatrix} \\ &= \begin{pmatrix} \cos(\omega_j \cdot \delta) & -\sin(\omega_j \cdot \delta) \\ \sin(\omega_j \cdot \delta) & \cos(\omega_j \cdot \delta) \end{pmatrix} \begin{pmatrix} p_{i,j+1} \\ p_{i,j} \end{pmatrix} \end{align*} Therefore, (pi,j+1,pi,j)(p_{i,j+1}, p_{i,j}) can be linearly projected to (pi+δ,j+1,pi+δ,j)(p_{i+\delta,j+1}, p_{i+\delta,j}), by applying a rotation matrix. This allows a Transformer to easily learn to attend by relative positions.

Rotary positional encoding (RoPE)

Another popular approach for taking into account absolute positional information in self-attention is RoPE (Su et al., 2024), which stands for rotary positional encoding. For simplicity, we briefly explain the idea with a single attention head and Dv=Dk=DD_v = D_k = D. Suppose we have a sequence x1,…,xL∈RD\x_1, \dots, \x_L \in \RR^D already encoded with token encoding. We then define the query and key vectors as qm≔RD(θ,m)WQxmm∈[L]kn≔RD(θ,n)WKxnn∈[L],\begin{align*} \q_m &\coloneqq \bm{R}_D(\theta, m) \W^Q \x_m \quad m \in [L] \\ \bm{k}_n &\coloneqq \bm{R}_D(\theta, n) \W^K \x_n \quad n \in [L], \end{align*} where RD(θ,m)∈RD×D\bm{R}_D(\theta, m) \in \RR^{D \times D} is a rotation matrix. The main intuition is that we are rotating the DD-dimensional vector by an angle which is a multiple of the position mm. In contrast to the learned and sinusoidal positional encodings, the weight matrices WQ\W^Q and WK\W^K are applied before applying RoPE, not after.

When D=2D=2, RD(θ,m)=R2(θ,m)\bm{R}_D(\theta,m) = \bm{R}_2(\theta,m) is defined as the rotation matrix R2(θ,m)≔(cos⁡(mθ)−sin⁡(mθ)sin⁡(mθ)cos⁡(mθ)) \bm{R}_2(\theta, m) \coloneqq \begin{pmatrix} \cos(m\theta) & -\sin(m\theta) \\ \sin(m\theta) & \cos(m \theta) \end{pmatrix} for some angle θ∈R\theta \in \RR and position m∈[L]m \in [L]. Using Euler’s formula eimθ=cos⁡(mθ)+isin⁡(mθ), e^{im\theta} = \cos(m \theta) + i \sin(m \theta), we note that v′≔R2(θ,m)v\v' \coloneqq \bm{R}_2(\theta, m) \v for v=(v1,v2)∈R2\v = (v_1, v_2) \in \RR^2 and v′=(v1′,v2′)∈R2\v' = (v'_1, v'_2) \in \RR^2 is equivalent to z′≔zeimθz' \coloneqq z e^{i m \theta} for z≔v1+iv2∈Cz \coloneqq v_1 + i v_2 \in \CC and z′=v1′+iv2′∈Cz'= v'_1 + i v'_2 \in \CC. See Su et al. (2024) for a detailed derivation of RoPE’s formula.

When D>2D>2, assuming DD is even, RD(θ,m)\bm{R}_D(\theta, m) is defined as RD(θ,m)≔(R2(θ1,m)R2(θ2,m)⋱R2(θD/2,m)), \bm{R}_D(\theta, m) \coloneqq \begin{pmatrix} \bm{R}_2(\theta_1, m) & & & \\ & \bm{R}_2(\theta_2, m) & & \\ & & \ddots & \\ & & & \bm{R}_2(\theta_{D/2}, m) \end{pmatrix}, where θj≔10000−2(j−1)/D\theta_j \coloneqq 10000^{-2(j-1)/D}. In practice, we never materialize RD(θ,m)\bm{R}_D(\theta, m) as a matrix, since it would be very sparse, but rather view it as a linear map applied to an arbitrary vector v∈RD\v \in \RR^D, RD(θ,m)v=(v1v2v3v4⋮vD−1vD)⊗(cos⁡(mθ1)cos⁡(mθ1)cos⁡(mθ2)cos⁡(mθ2)⋮cos⁡(mθD/2)cos⁡(mθD/2))+(−v2v1−v4v3⋮−vDvD−1)⊗(sin⁡(mθ1)sin⁡(mθ1)sin⁡(mθ2)sin⁡(mθ2)⋮sin⁡(mθD/2)sin⁡(mθD/2)). \bm{R}_D(\theta, m)\v = \begin{pmatrix} v_1 \\ v_2 \\ v_3 \\ v_4 \\ \vdots \\ v_{D-1} \\ v_D \end{pmatrix} \otimes \begin{pmatrix} \cos(m \theta_1) \\ \cos(m \theta_1) \\ \cos(m \theta_2) \\ \cos(m \theta_2) \\ \vdots \\ \cos(m \theta_{D/2}) \\ \cos(m \theta_{D/2}) \end{pmatrix} + \begin{pmatrix} -v_2 \\ v_1 \\ -v_4 \\ v_3 \\ \vdots \\ -v_D \\ v_{D-1} \end{pmatrix} \otimes \begin{pmatrix} \sin(m \theta_1) \\ \sin(m \theta_1) \\ \sin(m \theta_2) \\ \sin(m \theta_2) \\ \vdots \\ \sin(m \theta_{D/2}) \\ \sin(m \theta_{D/2}) \end{pmatrix}. Once we computed Q\Q and K\K, we can use Attention(Q,K,V;M)\mathrm{Attention}(\Q, \K, \V; \M) as usual. For multi-head attention, we simply apply the same approach for each attention head.

As analyzed by Su et al. (2024), RoPE satisfies several valuable properties. In particular, it is flexible w.r.t. the sequence length LL and despite being an absolute encoding, it manages to also capture relative distance between tokens. It therefore has the merits of both absolute and relative positional encodings.

4.8.8 Decoder-only architectures

Defining a language model

Transformers were originally developed to create encoder-decoder architectures for machine translation (Vaswani et al., 2017). However, in the context of language modelling, Transformers are now routinely used for decoder-only autoregressive architectures. Suppose we are given a sequence of discrete symbols x1,…,xL∈[M]x_1, \dots, x_L \in [M] (if a sequence has less than LL elements, we can use padding symbols). The goal of (unconditional) language models is to create a function producing the joint probability, (x1,…,xL)↦P(X1=x1,…,XL=xL). (x_1, \dots, x_L) \mapsto \PP(X_1 = x_1, \dots, X_L = x_L). Using the chain rule of probability (Section 10.1), without loss of generality, we can write P(X1=x1,…,XL=xL)=∏k=1LP(Xk=xk∣X1=x1,…,Xk−1=xk−1). \PP\left(X_1 = x_1, \ldots, X_L = x_L\right) = \prod_{k=1}^L \mathbb P(X_k = x_k \mid X_1 = x_1, \dots, X_{k-1}=x_{k-1}). If the maximum length LL is very large, it is more practical to only consider a context window of size NN, P(X1=x1,…,XL=xL)≔∏k=1LP(Xk=xk∣Xk−N=xk−N,…,Xk−1=xk−1). \PP\left(X_1 = x_1, \ldots, X_L = x_L\right) \coloneqq \prod_{k=1}^L \PP(X_k = x_k \mid X_{k-N}=x_{k-N}, \dots, X_{k-1} = x_{k-1}). This amounts to defining a higher-order Markov chain (Section 10.4.3). Using this approach, creating a language model then boils down to defining a function (xk−N,…,xk−1,xk)↦P(Xk=xk∣Xk−N=xk−N,…,Xk−1=xk−1). (x_{k-N}, \dots, x_{k-1}, x_k) \mapsto \PP(X_k = x_k \mid X_{k-N}=x_{k-N}, \dots, X_{k-1} = x_{k-1}). Let us assume that the sequence of discrete symbols x1,…,xL∈[M]x_1, \dots, x_L \in [M] has been mapped to a sequence of continuous vectors x1,…,xL∈RD\x_1, \dots, \x_L \in \RR^D using token encoding (Section 4.8.6) and positional encoding (Section 4.8.7). Using a causal Transformer block, we can obtain a representation of the current context, (xk−N,…,xk−1)←Transformer(xk−N,…,xk−1;MN). (\x_{k-N}, \dots, \x_{k-1}) \leftarrow \mathrm{Transformer}(\x_{k-N}, \dots, \x_{k-1}; \M_N). To ensure that the Transformer only relies on past tokens to predict the current token, the mask matrix MN\M_N is set to a matrix of size N×NN \times N, with the elements of the lower part set to 11, and the elements of the upper part set to −∞-\infty. To reduce this to logits in RM\RR^M, we usually use the last element of the context xk−1∈RD\x_{k-1} \in \RR^D and apply a linear model, to obtain θk≔WDxk−1∈RM, \thetav_k \coloneqq \W^D \x_{k-1} \in \RR^M, where WD∈RM×D\W^D \in \RR^{M \times D} is a learned “disembedding” matrix. To obtain a valid probability distribution, we apply a soft-argmax on the logits θk\thetav_k, πk≔softargmax(θk)∈△M. \piv_k \coloneqq \mathrm{softargmax}(\thetav_k) \in \triangle^M. Finally, we can now define P(Xk=xk∣Xk−N=xk−N,…,Xk−1=xk−1)≔[πk]xk. \PP(X_k = x_k \mid X_{k-N}=x_{k-N}, \dots, X_{k-1} = x_{k-1}) \coloneqq [\piv_k]_{x_k}.

Remark 4.5 (Weight tying)

Instead of learning a separate disembedding matrix WD∈RM×D\W^D \in \RR^{M \times D}, a frequently used technique is to set WD≔(WE)⊤\W^D \coloneqq (\W^E)^\top, where WE∈RD×M\W^E \in \RR^{D \times M} is the embedding matrix from Section 4.8.6. This weight tying reduces the number of parameters to learn and is shown to work well in practice (Press and Wolf, 2016).

Training

Let us gather the Transformer parameters (multi-head attention, MLP, layer norm) as w∈RP\w \in \RR^P. The decoder-only Transformer with a context window of size NN then defines a parametric probability distribution pw(x1,…,xL)≔∏k=1Lpw(xk∣xk−N,…,xk−1). p_\w(x_1, \ldots, x_L) \coloneqq \prod_{k=1}^L p_\w(x_k \mid x_{k-N}, \dots, x_{k-1}). Given a corpus of sequences D\cD, we usually seek the parameters w∈RP\w \in \RR^P by maximizing the log-likelihood, Ex∼D[log⁡pw(x1,…,xL)]=Ex∼D[∑k=1Llog⁡pw(xk∣xk−N,…,xk−1)]. \EE_{x \sim \cD} \left[\log p_\w(x_1, \dots, x_L)\right] = \EE_{x \sim \cD} \left[\sum_{k=1}^L \log p_\w(x_k \mid x_{k-N}, \dots, x_{k-1}) \right]. This amounts to using a logistic (cross-entropy) loss in a token-wise fashion. Importantly, the context xk−N,…,xk−1x_{k-N}, \dots, x_{k-1} used to predict the next token xkx_k always comes from the data, not from the tokens generated by the model. This is called teacher forcing and makes Transformer training highly parallelizable. The objective is usually solved approximately using stochastic gradient algorithms. To maximize GPU utilization, sequences of variable lengths are usually packed together in order to form batches.

Sampling

A decoder-only Transformer with a context window of size NN can be seen as forming a higher-order Markov chain, which is a special case of Bayesian network. To generate a sequence from the model, we can therefore use ancestral sampling (Section 10.5.3), X0≔x0X1∼pw(⋅∣X0)X2∼pw(⋅∣X0,X1)⋮Xk∼pw(⋅∣Xk−N,…,Xk−1),\begin{align*} X_0 &\coloneqq x_0 \\ X_1 &\sim p_\w(\cdot \mid X_0) \\ X_2 &\sim p_\w(\cdot \mid X_0, X_1) \\ &\vdots \\ X_k &\sim p_\w(\cdot \mid X_{k-N}, \dots, X_{k-1}), \end{align*} where x0x_0 denotes the beginning-of-sequence (BOS) token. The sampling stops when the end-of-sequence (EOS) token is generated or when a maximum length is reached. The generated sequences are i.i.d. .

Because sampling happens one token at a time, it is highly sequential. The Transformer block is called sequentially as Transformer(X0;M1)Transformer(X0,X1;M2)…Transformer(Xk−1,…Xk−N;MN).\begin{align*} &\mathrm{Transformer}(X_0; \M_1) \\ &\mathrm{Transformer}(X_0, X_1; \M_2) \\ &\dots \\ &\mathrm{Transformer}(X_{k-1}, \dots X_{k-N}; \M_N). \end{align*} To avoid repeating the same computations again and again, assuming that a causal mask is used, the past key and value matrices used in multi-head attention (Section 4.8.3) are usually stored in the so-called KV cache.

4.8.9 Encoder-only architectures

Encoder-only Transformers can be used for learning to represent sequences. The most prominent example is BERT (Devlin et al., 2019), which stands for bidirectional encoder representations from transformers. BERT uses Algorithm 4.4 without causal mask (hence “bidirectional” in the acronym). Discrete sequence elements are transformed to vectors using token encoding, positional encoding and potentially segment encoding. For reasons that will become clear below, the first token of every sequence is always a special classification token [CLS]. Training is broken down into two phases: pretraining and finetuning.

Pretraining

Since pre-training is performed on an unlabeled corpus, it is necessary to synthetically generate prediction tasks.

In masked prediction, a percentage (typically 15%) of the input tokens are randomly masked. The model is then trained to predict the original vocabulary ID of the masked tokens, given the context provided by the unmasked tokens. This forces the model to learn a rich, bidirectional representation of the language. The masking strategy involves:

In next sentence prediction, the model is trained to understand the relationship between two sentences. For each training example, BERT is given two sentences, AA and BB. 50% of the time, B is the actual next sentence that follows A in the original document (labeled IsNext). The other 50% of the time, BB is a random sentence from the corpus (labeled NotNext). A special [CLS] token is prepended to the input sequence, and its final hidden state is used to predict whether sentence BB follows sentence A. The [SEP] token separates the two sentences.

Finetuning

After pre-training on a massive corpus, the pretrained BERT model can be finetuned for various downstream NLP tasks (e.g., text classification, question answering, named entity recognition) by adding a small, task-specific output layer on top of the pre-trained Transformer encoder. The entire model, including the pretrained weights, is then finetuned on the labeled data for the specific task. For classification tasks, the final hidden state corresponding to the class token [CLS] is used. For tagging tasks (token-level classification) such as named entity recognition (NER) or part-of-speech (POS) tagging, the final hidden state of each token is used. For question answering tasks, which usually involve finding a span (start and end token) within a given text, this is treated as two token-level classification problems: one for the start token and one for the end token.

4.8.10 Encoder-decoder architectures

The encoder-decoder architecture was the original architecture proposed in the seminal Transformer paper (Vaswani et al., 2017). It can be used for sequence-to-sequence tasks, such as machine translation, summarization and question answering. We denote the input sequence by X\X and the output sequence by Y\Y.

Encoder

The role of the encoder is to produce a rich representation Henc\H_{\mathrm{enc}} of the input sequence X\X, which serves as a context for the subsequent decoding phase. As in encoder-only architectures, this is achieved by using Algorithm 4.4 without causal mask. The multi-head self-attention layer allows the encoder to weigh the importance of different tokens in the input sequence relative to each other. For each token in the input, it computes a representation that incorporates information from all other tokens in the same sequence. The encoder block uses its own parameters for each sub-component (multi-head attention, layer norm, MLP). In particular, multi-head attention uses parameters {WiQ}i=1H\{\W_i^Q\}_{i=1}^H, {WiK}i=1H\{\W_i^K\}_{i=1}^H, {WiV}i=1H\{\W_i^V\}_{i=1}^H and WO\W^O.

Decoder

The role of the decoder is to generate the output sequence Y\Y one token at a time, based on the encoded representation Henc\H_{\mathrm{enc}} from the encoder and the previously generated tokens Y1:t−1\Y_{1:t-1}. The decoder differs in the way attention is applied. First, we apply causal multi-head self-attention to obtain a representation Hdec\H_{\mathrm{dec}} corresponding to the previously generated tokens Y1:t−1\Y_{1:t-1}. Second, we apply multi-head cross-attention. The key difference with multi-head self-attention is that the key, query and value matrices are defined as Qidec≔HdecW′iQKienc≔HencW′iKVienc≔HencW′iV,\begin{align*} \Q^{\mathrm{dec}}_i &\coloneqq \H_\mathrm{dec} {\W'}_i^Q \\ \K^{\mathrm{enc}}_i &\coloneqq \H_\mathrm{enc} {\W'}_i^K \\ \V^{\mathrm{enc}}_i &\coloneqq \H_\mathrm{enc} {\W'}_i^V, \end{align*} where {W′iQ}i=1H\{{\W'}_i^Q\}_{i=1}^H, {W′iK}i=1H\{{\W'}_i^K\}_{i=1}^H and {W′iV}i=1H\{{\W'}_i^V\}_{i=1}^H are the weight matrices used for the decoder. Subsequently, MLP and layer norm layers are applied, similarly as before.

Differences with decoder-only architectures

An encoder-decoder architecture provides a dedicated component for understanding the input and another for generating the output. It allows for a bidirectional understanding of the input. It is therefore best suited for sequence-to-sequence (seq2seq) tasks where the input and output sequences may have different domains or modalities.

Decoder-only models, on the other hand, are streamlined for generating text by continuously predicting the next token, leveraging a single, powerful autoregressive mechanism. That being said, due to their simplicity, decoder-only architectures are now increasingly being used even for seq2seq tasks, by prepending the input (prompt) to the context. This means that the input is subject to the causal mask, but the performance remains remarkably strong.

4.9 Summary