Large language models can recall obscure facts from every corner of the world, but how do they remember so much? This post explores linear maps, MLPs, and self-attention as different kinds of memory stores. The key property of a good memory store is its ability to recall what it stored. The more memories we store, the more they interfere with each other when we try to recall one. The interference-to-signal ratio measures how much the other memories get in the way during recall. The number of memories a store can hold before the interference grows as large as the signal is its capacity. We’ll show how you can go from a linear layer to something better, an MLP, which improves both capacity and recall, and then all the way to self-attention, which has very good recall and can store a potentially unbounded number of memories. With 64-dimensional keys, that’s a jump from about 64 memories, to about 2,700, to over a million.
A memory store is a function f that holds M memories, for i = 1, ..., M. A memory is one key-value pair: a key k_i ∈ ℝ^{d_k}, used for lookup based on similarity, and a value v_i ∈ ℝ^{d_v}, which is what we want to retrieve. To use f, we query it with an input x, and it recalls an output f(x). A good memory store recalls v_i when we query it with k_i, or with another vector similar to k_i. In the literature, a memory store that recalls by similarity is called an associative memory. An outer product memory store is the most basic memory store: it simply accumulates memories via outer products, W = ∑_{i=1}^{M} v_i k_i^T = V^T K, where the rows of K ∈ ℝ^{M×d_k} and V ∈ ℝ^{M×d_v} are the keys k_i^T and the values v_i^T. To store a new memory (k, v), we simply add vk^T to the existing weights. To query the memory store with an input x, we multiply the input by the matrix: f(x) = V^T K x = ∑_{i=1}^{M} v_i (k_i^T x). So recall is a lookup by similarity to the stored keys: we compare the query with every key, and return the sum of the values weighted by those similarities. Recall picks up interference: storing memories is easy, but what happens when we try to recall one? Let’s assume for simplicity that every key is normalized to have length 1, i.e. k_j^T k_j = 1. Then f(k_j) = v_j + ∑_{i≠j} v_i (k_i^T k_j). The first term is the signal we want, and the second term is the interference from other memories.
Source: Hacker News · Summarized by HeadlinesBriefing