In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning

Michael BrenndoerferNovember 6, 202556 min read

Explore how in-context learning emerges in large language models. Learn about scale thresholds, ICL vs fine-tuning, induction heads, and meta-learning.

Reading Level

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

In-Context Learning Emergence

In Part XVIII, we introduced in-context learning (ICL) as a remarkable capability of large language models: the ability to perform new tasks simply by observing a few demonstrations in the prompt, without any gradient updates. But when we introduced ICL, we treated it as a feature of GPT-3 and its successors. What we didn't fully address was the mystery of when and how this capability appears.

ICL doesn't exist at small scales. Train a language model with 100 million parameters on the same data, with the same architecture, and you'll find something peculiar. The model doesn't learn from examples in the prompt. It will generate text, predict next tokens, and even produce coherent sentences, but showing it examples of a task at inference time has little effect on its behavior. Then, somewhere between 1 billion and 100 billion parameters, something changes. The model starts using those examples. It begins to generalize from demonstrations it has never seen during training to produce correct outputs for novel inputs.

This emergence of in-context learning represents one of the most consequential transitions in the scaling of language models. It transformed LLMs from pattern-matching text generators into flexible few-shot learners, fundamentally changing how we interact with AI systems. Understanding when this transition occurs, how it scales compared to traditional fine-tuning, and what mechanisms might explain it remains an active area of research with significant implications for both theory and practice.

ICL Emergence Curves

The emergence of in-context learning follows characteristic patterns that researchers have documented across multiple model families and scales. Unlike smooth improvements in perplexity or basic language modeling metrics, ICL ability appears relatively suddenly as models cross certain scale thresholds.

The Scale Threshold Phenomenon

Early investigations by Brown et al. with GPT-3 revealed that in-context learning performance improves dramatically with model size, but this improvement is highly non-linear. On many tasks, models below approximately 1 billion parameters show essentially random performance when given few-shot examples, while models above 10-100 billion parameters achieve substantial accuracy gains from the same demonstrations.

The emergence curve for ICL typically follows a pattern with several distinct phases:

  • Random baseline phase: Small models (typically <1B parameters) show no meaningful improvement from in-context examples. Performance remains near chance regardless of demonstration quality or quantity.
  • Transition phase: Models in an intermediate range begin showing some sensitivity to demonstrations, but performance is unstable and task-dependent.
  • Competent phase: Larger models consistently leverage demonstrations, with performance scaling log-linearly with both model size and number of examples.
In[2]:
Code
import numpy as np

np.random.seed(42)

## Simulated ICL emergence data based on published research patterns
## Model sizes in billions of parameters
model_sizes = np.array([0.1, 0.3, 0.7, 1.3, 2.7, 6.7, 13, 30, 70, 175])

## Zero-shot performance (baseline)
zero_shot = np.array(
    [0.25, 0.26, 0.27, 0.30, 0.35, 0.42, 0.48, 0.55, 0.62, 0.68]
)

## Few-shot performance (4 examples) - showing emergence
few_shot_4 = np.array(
    [0.25, 0.26, 0.28, 0.35, 0.48, 0.62, 0.72, 0.80, 0.86, 0.90]
)

## The ICL gain (difference between few-shot and zero-shot)
icl_gain = few_shot_4 - zero_shot

## Calculate key statistics for interpretation
max_icl_gain = icl_gain.max()
max_gain_idx = icl_gain.argmax()
max_gain_scale = model_sizes[max_gain_idx]
Out[3]:
Visualization
Plot showing zero-shot and few-shot performance vs model size on log scale.
Zero-shot vs few-shot performance across model scales. ICL ability emerges suddenly around 1-10B parameters.
Plot showing ICL gain vs model size on log scale.
ICL gain (benefit from demonstrations) showing sharp increase in the emergence zone.

This visualization reveals the characteristic S-curve of ICL emergence. Below 1B parameters, demonstrations provide almost no benefit. Between 1B and 10B parameters, ICL ability emerges rapidly. Above 10B parameters, models reliably exploit few-shot examples, though the marginal gains continue to compound with scale.

Task-Dependent Emergence Thresholds

Not all tasks exhibit identical emergence thresholds. Some capabilities emerge earlier than others, creating a hierarchy of ICL difficulty:

Early-emerging tasks (emerge at smaller scales) typically include:

  • Simple pattern completion
  • Basic translation of common language pairs
  • Sentiment classification with clear signals
  • Factual question answering about high-frequency knowledge

Late-emerging tasks (require larger scales) include:

  • Multi-step arithmetic
  • Abstract reasoning and analogy
  • Low-resource language translation
  • Tasks requiring world knowledge integration

This task hierarchy suggests that ICL emergence isn't a single phenomenon but rather a spectrum of capabilities that unlock progressively with scale. Wei et al. (2022) documented this pattern systematically, showing that the emergence threshold varies by more than an order of magnitude across different task types.

In[4]:
Code
## Different tasks have different emergence thresholds
task_categories = {
    "Sentiment Analysis": {"threshold": 0.5, "max_perf": 0.92},
    "Translation (High-Resource)": {"threshold": 1.0, "max_perf": 0.85},
    "Question Answering": {"threshold": 2.0, "max_perf": 0.88},
    "Translation (Low-Resource)": {"threshold": 10.0, "max_perf": 0.75},
    "Multi-Step Arithmetic": {"threshold": 30.0, "max_perf": 0.80},
}


def sigmoid_emergence(scale, threshold, max_perf, steepness=2.0):
    """
    Model emergence as a sigmoid function centered at threshold.

    This implements the emergence curve:

    $$
    P(s) = \frac{P_{\max}}{1 + \exp(-k \cdot (\log_{10}(s) - \log_{10}(s_t)))}
    $$

    where:
    - $P(s)$: the predicted ICL performance at model scale $s$
    - $P_{\max}$: the asymptotic maximum performance (max_perf parameter)
    - $s$: model size in billions of parameters (scale parameter)
    - $s_t$: the threshold scale where performance reaches 50% of maximum
    - $k$: steepness parameter controlling transition sharpness

    Args:
    - scale: model size in billions of parameters
    - threshold: the scale at which performance reaches 50% of maximum
    - max_perf: asymptotic maximum performance
    - steepness (k): controls how sharp the transition is

    Using log-scale ensures the sigmoid is symmetric in orders of magnitude.
    """
    x = np.log10(scale) - np.log10(threshold)
    return max_perf / (1 + np.exp(-steepness * x))


scales = np.logspace(-1, 2.5, 100)  # 0.1B to ~300B

task_performance = {}
for task, params in task_categories.items():
    perf = sigmoid_emergence(3.0, params["threshold"], params["max_perf"])
    task_performance[task] = {
        "threshold": params["threshold"],
        "perf_at_3B": perf,
    }

## Calculate threshold ratio for interpretation
early_threshold = task_categories["Sentiment Analysis"]["threshold"]
late_threshold = task_categories["Multi-Step Arithmetic"]["threshold"]
threshold_ratio = late_threshold / early_threshold

The sigmoid emergence function captures a fundamental insight about how capabilities develop in neural networks. Rather than appearing gradually, ICL ability transitions rapidly once the model crosses a critical scale threshold. The function operates in log-space because the relationship between model size and capability is multiplicative rather than additive. Doubling the parameters doesn't add a fixed amount of capability, but rather multiplies the model's effective capacity. The threshold parameter sts_t marks the inflection point where the model transitions from having essentially no ICL ability to having substantial capability. The steepness parameter kk controls how abrupt this transition is; higher values produce sharper phase transitions, while lower values create more gradual emergence curves. This mathematical formulation allows researchers to precisely characterize and compare emergence patterns across different tasks and model families.

Out[5]:
Console
Sentiment Analysis: threshold=0.5B, perf at 3B=0.76
Translation (High-Resource): threshold=1.0B, perf at 3B=0.61
Question Answering: threshold=2.0B, perf at 3B=0.52
Translation (Low-Resource): threshold=10.0B, perf at 3B=0.20
Multi-Step Arithmetic: threshold=30.0B, perf at 3B=0.10

Threshold ratio (hardest/easiest): 60x
Out[6]:
Visualization
Multiple sigmoid curves showing emergence thresholds varying by task type.
Different tasks exhibit different ICL emergence thresholds. Simpler tasks like sentiment analysis emerge at smaller scales, while complex reasoning tasks require much larger models.

The emergence curves reveal a clear hierarchy: sentiment analysis reaches 50% of maximum performance at just 0.5B parameters, while multi-step arithmetic requires approximately 30B parameters to achieve the same relative capability. This 60-fold difference in emergence thresholds demonstrates that ICL is not a monolithic capability but a family of skills with vastly different computational requirements.

Out[7]:
Visualization
Multiple sigmoid curves showing how steepness affects transition sharpness.
Effect of steepness parameter (k) on emergence curve sharpness.
Multiple sigmoid curves showing how threshold affects emergence timing.
Effect of threshold parameter on emergence timing.

Training Data and Compute

Scale alone doesn't fully determine ICL emergence. The Chinchilla scaling laws we covered in Part XXI showed that optimal model performance requires balancing model size with training data quantity. Given a fixed compute budget, there exist optimal allocations for both model size and training data:

NoptC0.5,DoptC0.5N_{\text{opt}} \propto C^{0.5}, \quad D_{\text{opt}} \propto C^{0.5}

where:

  • NoptN_{\text{opt}}: the optimal number of model parameters for a given compute budget
  • DoptD_{\text{opt}}: the optimal number of training tokens
  • CC: the total compute budget (measured in FLOPs)
  • \propto: denotes proportionality (the quantities scale together but may differ by a constant factor)

The exponent of 0.50.5 indicates square-root scaling: if you double your compute budget, both the optimal model size and optimal data quantity should increase by a factor of 21.41\sqrt{2} \approx 1.41. This square-root relationship ensures neither parameter count nor data becomes a bottleneck. This balance also affects ICL emergence.

To understand why this relationship matters for ICL emergence, consider what happens when you deviate from optimal allocation. If you invest all additional compute into model size while keeping data fixed, the model becomes "undertrained." It has capacity it cannot effectively use because it hasn't seen enough diverse patterns during training. Conversely, if you invest all additional compute into data while keeping model size fixed, you create an "overexposed" model that has seen more patterns than it can represent. The Chinchilla insight is that both failure modes hurt performance, and the optimal path forward maintains a balance between the two. For ICL specifically, this means that raw parameter count is insufficient. The model must also have been trained on sufficient diverse data to develop the pattern recognition capabilities that underlie few-shot learning.

Research by Hoffmann et al. demonstrated that compute-optimal training can shift emergence curves leftward, meaning ICL capabilities appear at smaller model sizes when training is more efficient. A 10B parameter model trained optimally might exhibit ICL performance comparable to a 50B parameter model trained sub-optimally.

The quality and diversity of pre-training data also matters significantly. Models trained on more diverse corpora with greater task variety tend to develop stronger ICL abilities at equivalent scales. This observation connects to the meta-learning perspective we'll explore later in this chapter.

ICL vs Fine-tuning Scaling

A central question in the scaling of language models is how in-context learning compares to traditional fine-tuning as model size increases. Both approaches allow models to adapt to new tasks, but they do so through fundamentally different mechanisms.

Fine-tuning Scaling Behavior

Fine-tuning updates model weights through gradient descent on task-specific data. As we covered in Part XVII with BERT fine-tuning, this approach has been the standard method for adapting pre-trained models to downstream tasks. The scaling behavior of fine-tuning is relatively well understood.

Fine-tuning typically shows smooth, consistent improvements with scale. Even small models benefit substantially from fine-tuning on sufficient task-specific data. A 100M parameter model, while showing no ICL ability, can achieve strong performance when fine-tuned on thousands of labeled examples. The improvement from fine-tuning scales roughly log-linearly with both model size and data quantity.

In[8]:
Code
import numpy as np

## Comparing ICL vs fine-tuning across scales
model_sizes_log = np.array([0.1, 0.3, 1, 3, 10, 30, 100, 300])

## Fine-tuning with 1000 examples - consistent improvements at all scales
finetune_1000 = (
    0.50
    + 0.08 * np.log10(model_sizes_log)
    + 0.20 * (1 - np.exp(-model_sizes_log / 2))
)

## ICL with 8 examples - emergent behavior
icl_8shot = np.array([0.26, 0.28, 0.35, 0.52, 0.70, 0.82, 0.88, 0.91])

## Fine-tuning with 100 examples
finetune_100 = (
    0.35
    + 0.06 * np.log10(model_sizes_log)
    + 0.15 * (1 - np.exp(-model_sizes_log / 3))
)

## Find crossover point
crossover_idx = np.argmin(np.abs(icl_8shot - finetune_100))
crossover_scale = model_sizes_log[crossover_idx]
crossover_icl_perf = icl_8shot[crossover_idx]
Out[9]:
Visualization
Log-scale plot comparing ICL and fine-tuning performance across model sizes.
ICL vs fine-tuning scaling comparison. Fine-tuning provides consistent gains at all scales, while ICL shows emergent behavior. At large scales, ICL with just 8 examples can match fine-tuning with 100+ examples.
Out[10]:
Console
Crossover occurs at approximately 0B parameters.
At this scale, 8-shot ICL achieves 0.26 accuracy,
matching fine-tuning with 100 examples despite using 12x fewer examples.

The crossover point represents a significant milestone: beyond this scale, the efficiency of in-context learning begins to outweigh the benefits of traditional fine-tuning for low-data scenarios.

The Crossover Point

A striking phenomenon occurs as models scale: ICL eventually becomes competitive with, and can even surpass, fine-tuning despite using orders of magnitude fewer examples. This crossover has profound practical implications.

For small models, fine-tuning is strictly superior. A 1B parameter model fine-tuned on 100 examples dramatically outperforms the same model doing 8-shot ICL. But for large models (typically >30B parameters), 8-shot ICL can match or exceed fine-tuning with 100 examples. At the largest scales, ICL with a handful of demonstrations approaches the performance of fine-tuning with thousands of examples.

This crossover represents a qualitative shift in how we can use language models. Below the crossover, adapting models to new tasks requires collecting data, writing training pipelines, and running optimization. Above the crossover, you can achieve comparable results simply by writing a prompt.

Out[11]:
Visualization
Bar chart showing data efficiency ratios across model scales.
Data efficiency comparison between ICL and fine-tuning at different model scales. The ratio shows how many fine-tuning examples are needed to match ICL performance with 8 examples.

Why the Scaling Difference?

The different scaling behaviors of ICL and fine-tuning reflect their fundamentally different mechanisms.

Fine-tuning explicitly optimizes model weights to minimize loss on task-specific data. This optimization process is reliable and well-understood. It works at any scale because gradient descent effectively finds task-relevant features in the model's representations. The limitation is that it requires many examples to adjust the millions or billions of parameters effectively.

ICL doesn't modify weights at all. Instead, it relies on the model's pre-trained ability to recognize patterns in the prompt and generalize from them. This ability is emergent, requiring sufficient model capacity and diverse pre-training to develop. Once it emerges, ICL can be remarkably data-efficient because the model has already learned general-purpose pattern recognition.

The practical implication is that ICL represents a shift from per-task adaptation to universal adaptation. A model with strong ICL abilities is essentially a general-purpose few-shot learner that can handle novel tasks without any task-specific training.

ICL Mechanism Hypotheses

Understanding how in-context learning works mechanistically remains an active research area. Several hypotheses have been proposed, offering different perspectives on what happens when a model processes demonstrations and then generalizes to new examples.

The Induction Head Hypothesis

Elhage et al. (2022) identified specific circuit structures called induction heads that appear to implement a form of in-context learning.

Induction Heads

Induction heads are attention patterns that learn to copy tokens that followed similar contexts earlier in the sequence. They implement a primitive form of pattern completion: if the sequence contains "[A][B]...[A]", the induction head predicts [B] will follow.

To understand why induction heads matter for ICL, consider what happens when you provide a model with demonstrations like "France → Paris, Germany → Berlin, Japan → ?" The model needs to recognize that the pattern "[Country] → [Capital]" has been established and that the same mapping should apply to the query. Induction heads provide exactly this capability: they scan the sequence for previous occurrences of similar patterns and copy the associated outputs. When the model encounters "Japan", an induction head can identify that similar country tokens were followed by capital city tokens, enabling it to predict "Tokyo" even without explicit training on this particular mapping.

Induction heads emerge during training, and their formation coincides with a sudden improvement in model performance. Researchers call this the "induction head phase transition." This transition typically occurs early in training and appears to be a prerequisite for more sophisticated ICL abilities.

The mechanism works through a two-step process that coordinates across multiple attention heads within the transformer architecture. First, an attention head identifies previous positions where a similar pattern occurred, effectively creating a lookup based on context similarity. Second, another attention head copies information from what followed that previous pattern, retrieving the associated continuation. This two-step coordination is what makes induction heads powerful. They implement a form of content-addressable memory where the model can retrieve relevant information based on contextual similarity rather than fixed position.

This circuit can explain simple ICL behaviors like learning a consistent mapping from inputs to outputs. If the model sees "[France → Paris], [Germany → Berlin], [Japan → ]", the induction head mechanism can recognize the pattern and predict "Tokyo" even if this specific mapping was never seen during training.

In[12]:
Code
import torch
import torch.nn.functional as F


def simulate_induction_head_attention(
    sequence_embeddings, pattern_key, pattern_value=None
):
    """
    Simplified simulation of induction head behavior.

    The model attends to positions where similar patterns occurred
    and copies what followed them.

    Args:
        sequence_embeddings: Tensor of shape (seq_len, embed_dim) containing
                           embeddings for each position in the sequence
        pattern_key: Tensor of shape (embed_dim,) representing the pattern
                    we're trying to match against previous positions
        pattern_value: Tensor of shape (embed_dim,) containing the value to
                      copy (not used in this simplified version)

    Returns:
        copied_output: The weighted combination of sequence embeddings
        combined_weights: Attention weights showing which positions were matched
    """
    seq_len = sequence_embeddings.shape[0]

    # Step 1: Find positions with similar patterns (simplified as dot product)
    pattern_matches = torch.matmul(
        sequence_embeddings, pattern_key.unsqueeze(1)
    ).squeeze()

    # Step 2: Weight by recency and match strength
    recency_weights = torch.exp(
        -0.1 * torch.arange(seq_len, 0, -1, dtype=torch.float32)
    )
    combined_weights = F.softmax(pattern_matches * recency_weights, dim=0)

    # Step 3: Copy from what followed matched positions
    # (In practice, this involves attention to the next-position values)
    copied_output = torch.matmul(combined_weights, sequence_embeddings)

    return copied_output, combined_weights
In[13]:
Code
## Create a simple sequence with repeated patterns
torch.manual_seed(42)

## Simulate embeddings for: [A, B, C, A, ?]
## The model should recognize A appeared before and B followed
embeddings = torch.randn(5, 64)  # 5 positions, 64-dim embeddings
embeddings[3] = embeddings[0] + 0.1 * torch.randn(
    64
)  # Position 3 is similar to position 0

## Pattern key represents "what are we looking for"
pattern_key = embeddings[
    3
]  # Looking for patterns similar to position 3 (which is like position 0)
pattern_value = embeddings[1]  # Position 1 is what followed position 0

output, attention_weights = simulate_induction_head_attention(
    embeddings, pattern_key, pattern_value
)
Out[14]:
Console
Induction Head Attention Weights:
Position 0 (original A): 0.000
Position 1 (B that followed A): 0.000
Position 2 (C): 0.000
Position 3 (second A): 1.000
Position 4 (query position): 0.000

The model most strongly attends to position 3, 
where a similar pattern occurred (weight: 1.000).
This allows copying the pattern that followed the matching position.
Out[15]:
Visualization
Bar chart showing attention weights across sequence positions for induction head.
Induction head attention weights. The model attends most strongly to position 0, where a similar pattern (A) occurred previously.
Heatmap showing cosine similarity between position embeddings.
Embedding similarity matrix showing which positions have similar representations.

Gradient Descent in the Forward Pass

Akyürek et al. (2022) and von Oswald et al. (2023) suggest that transformers implementing ICL effectively perform gradient descent within the forward pass. Rather than learning by updating weights, the model's attention mechanisms simulate the optimization process that gradient descent would perform.

This perspective reframes in-context learning as implicit optimization. The demonstrations serve as a training set, and the attention layers compute something functionally equivalent to gradient updates on an internal linear model. This insight matters because it connects the mystery of ICL to the well-understood mathematics of optimization. If attention layers can implement gradient descent, then ICL is not magic. It is the model running a familiar learning algorithm using the computational substrate of attention.

The mathematical intuition is that a single attention layer computes a weighted combination of values, where the weights depend on query-key similarity:

Attention(Q,K,V)=softmax(QKTd)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V

where:

  • QQ: the query matrix, representing the current position's learned representation seeking information
  • KK: the key matrix, representing what information each position offers
  • VV: the value matrix, containing the actual information to be aggregated
  • dd: the dimensionality of the key vectors, used for scaling to prevent dot products from growing too large
  • softmax()\text{softmax}(\cdot): normalizes attention weights to sum to 1, creating a probability distribution over positions

The attention mechanism operates by first computing similarity scores between queries and keys through dot products. These raw scores are scaled by d\sqrt{d} to maintain stable gradients. Without this scaling, large hidden dimensions would produce extreme dot products that make softmax outputs nearly one-hot, hampering gradient flow during training. The softmax then converts these scaled similarities into a proper probability distribution, determining how much each position contributes to the output. Finally, the value vectors are weighted by these probabilities and summed, producing an output that aggregates information from positions deemed most relevant by the query-key matching.

With appropriate weight configurations, this operation can approximate a step of gradient descent on a linear regression objective. The key insight is that attention computes a weighted sum over values, and with the right setup, these weights can encode gradient information.

To see this connection, consider linear regression where we want to find weights w\mathbf{w} that predict outputs from inputs. Gradient descent updates these weights by moving in the direction that reduces prediction error:

wnew=wold+ηi=1n(yiwoldTxi)xi\mathbf{w}_{\text{new}} = \mathbf{w}_{\text{old}} + \eta \sum_{i=1}^{n} (y_i - \mathbf{w}_{\text{old}}^T \mathbf{x}_i) \mathbf{x}_i

where:

  • wnew\mathbf{w}_{\text{new}}, wold\mathbf{w}_{\text{old}}: the weight vector after and before the update
  • η\eta: the learning rate controlling step size
  • nn: the number of training examples
  • xi\mathbf{x}_i: the ii-th input feature vector
  • yiy_i: the ii-th target value
  • (yiwoldTxi)(y_i - \mathbf{w}_{\text{old}}^T \mathbf{x}_i): the prediction error, which measures how far off the current prediction is from the target

The gradient descent update adjusts the weights by adding a correction term that is proportional to the error (yiwoldTxi)(y_i - \mathbf{w}_{\text{old}}^T \mathbf{x}_i) scaled by the input xi\mathbf{x}_i and learning rate η\eta. Larger errors lead to larger corrections, and the input vector determines which weight dimensions get updated most. This is the core principle of supervised learning: use the discrepancy between prediction and truth to guide weight adjustments, with the input features determining the direction of adjustment in weight space.

The attention mechanism mirrors this structure. The query represents the current estimate (analogous to woldTxnew\mathbf{w}_{\text{old}}^T \mathbf{x}_{\text{new}}), keys represent the training inputs (xi\mathbf{x}_i), and values encode the gradient information (error signals weighted by inputs). When the model processes demonstrations, the attention weights computed between the query position and demonstration positions can encode the gradient update that would be computed if we were training on those examples. The softmax normalization corresponds to how gradients are aggregated across training examples, and multiple attention layers can implement multiple gradient steps, refining the internal model iteratively.

In[16]:
Code
import numpy as np
import torch
import torch.nn.functional as F


def attention_as_gradient_descent(X_train, y_train, x_query, learning_rate=0.1):
    """
    Demonstrate how attention can implement gradient descent.

    For a linear model y = Wx, gradient descent updates are:
    W_new = W_old + lr * (y - W_old @ x) @ x.T

    Attention can approximate this by:
    1. Computing similarity between query and training inputs (keys)
    2. Weighting training outputs (values) by similarity
    3. Aggregating to produce a prediction
    """
    # Compute attention weights (similarity between query and training inputs)
    attention_scores = torch.matmul(X_train, x_query)
    attention_weights = F.softmax(
        attention_scores / np.sqrt(X_train.shape[1]), dim=0
    )

    # Weighted combination of training outputs
    prediction = torch.matmul(attention_weights, y_train)

    return prediction, attention_weights
In[17]:
Code
## Simple linear regression task
torch.manual_seed(123)

## True function: y = 2*x1 + 3*x2
n_train = 5
X_train = torch.randn(n_train, 2)
y_train = 2 * X_train[:, 0] + 3 * X_train[:, 1] + 0.1 * torch.randn(n_train)

## Query point
x_query = torch.tensor([1.0, 1.0])
y_true = 2 * x_query[0] + 3 * x_query[1]

## Attention-based prediction
y_pred, weights = attention_as_gradient_descent(X_train, y_train, x_query)
Out[18]:
Console
Gradient Descent via Attention Simulation:
True value: y = 2(1) + 3(1) = 5.00
Attention-predicted value: -0.69
Prediction error: 5.69

Training examples and attention weights:
  Example 1: x=(-0.11, 0.12), y=0.16, weight=0.279
  Example 2: x=(-0.37, -0.24), y=-1.50, weight=0.180
  Example 3: x=(-1.20, 0.21), y=-1.74, weight=0.138
  Example 4: x=(-0.97, -0.76), y=-4.14, weight=0.082
  Example 5: x=(0.32, -0.11), y=0.36, weight=0.322

The model attends most to example 5 (weight: 0.322),
which is most similar to the query point.
This similarity-weighted aggregation approximates gradient descent.
Out[19]:
Visualization
Scatter plot showing training data in 2D space with attention-weighted colors.
Training examples in 2D input space colored by attention weight, with query point (star).
Bar chart showing attention weights for each training example.
Attention weight distribution showing how the model weighs each training example.

This connection between attention and gradient descent provides a theoretical foundation for understanding why ICL works and why it emerges with scale. Larger models have more capacity to learn the weight configurations that implement this implicit optimization.

Task Recognition vs Task Learning

Another perspective distinguishes between two potential mechanisms: task recognition and task learning.

Task recognition proposes that during pre-training, the model learns many tasks implicitly. When given demonstrations at test time, the model doesn't learn a new task; instead, it recognizes which of its pre-existing capabilities to apply. The demonstrations serve as task specifiers rather than training data.

Task learning proposes that the model learns new input-output mappings from the demonstrations, even mappings it has never encountered during pre-training.

Research by Min et al. (2022) provided evidence for task recognition by showing that ICL performance remains robust when demonstration labels are randomized. This suggests models often recognize the task structure from the input format rather than learning the specific input-output mapping.

In[20]:
Code
## Simulating the task recognition experiment
def evaluate_icl_robustness(correct_labels=True):
    """
    Simulate the finding that ICL is robust to label corruption,
    suggesting task recognition rather than pure task learning.
    """
    # Simulated performance metrics
    if correct_labels:
        return {
            "format_benefit": 0.25,  # Benefit from seeing the task format
            "label_benefit": 0.10,  # Additional benefit from correct labels
            "total_icl_gain": 0.35,
        }
    else:
        # With random labels, format benefit remains, label benefit disappears
        return {
            "format_benefit": 0.25,
            "label_benefit": 0.00,
            "total_icl_gain": 0.25,
        }


correct_label_results = evaluate_icl_robustness(correct_labels=True)
random_label_results = evaluate_icl_robustness(correct_labels=False)
Out[21]:
Console
Task Recognition vs Task Learning Evidence:

With correct labels:
  Format benefit: +0.25
  Label benefit:  +0.10
  Total ICL gain: +0.35

With random labels:
  Format benefit: +0.25
  Label benefit:  +0.00
  Total ICL gain: +0.25

Key insight: ~71% of ICL benefit comes from format recognition, not label learning.
The remaining ~29% comes from actual label learning.
This supports the task recognition hypothesis.
Out[22]:
Visualization
Stacked bar chart comparing ICL gains with correct vs random labels.
Decomposition of ICL benefits showing format recognition vs label learning contributions.
Pie chart showing format vs label contribution percentages.
Pie chart showing the relative contribution of format recognition to ICL performance.

The reality likely involves both mechanisms. Task recognition explains why ICL works for tasks similar to pre-training distributions, while task learning (perhaps via the gradient descent mechanism) explains generalization to genuinely novel tasks.

ICL as Meta-Learning

Perhaps the most comprehensive framework for understanding in-context learning views it through the lens of meta-learning. This perspective explains both how ICL emerges and why it requires scale.

What is Meta-Learning?

Meta-Learning

Meta-learning, or "learning to learn," refers to algorithms that improve their learning ability through experience. Rather than learning a single task, a meta-learner learns how to learn new tasks quickly from limited data.

Traditional learning algorithms start fresh for each new task. Meta-learning algorithms leverage experience from previous tasks to accelerate learning on new ones. The classic formulation involves:

  • An outer loop that learns across many tasks, updating how the model learns
  • An inner loop that learns each specific task, using the meta-learned learning procedure

The goal is to develop a learning algorithm (not just a model) that can rapidly adapt to new tasks with minimal data. This is fundamentally different from traditional machine learning, where the algorithm is fixed (such as gradient descent) and only the model parameters change. In meta-learning, the learning procedure itself is learned, optimized to enable fast adaptation. The outer loop shapes the learning dynamics, while the inner loop applies those dynamics to individual tasks.

Pre-training as the Outer Loop

The meta-learning perspective on ICL views pre-training as an implicit outer loop that creates a general-purpose learning algorithm. During pre-training, the language model encounters billions of sequences containing implicit task structures. Each training sequence can be viewed as a mini-task, predicting what comes next given the context.

The diversity of pre-training data means the model implicitly sees many task distributions:

  • Passages followed by summaries (summarization task)
  • Questions followed by answers (QA task)
  • Statements in one language followed by translations (translation task)
  • Premises followed by conclusions (reasoning task)

By training on next-token prediction across this diverse distribution, the model learns to recognize task patterns and adapt its predictions accordingly. The model isn't just learning to predict text. It's learning to identify what kind of prediction is expected given the context.

This perspective illuminates why pre-training on diverse data is so crucial. Each time the model encounters a different type of text pattern, it must implicitly identify the genre, style, or task and adjust its predictions accordingly. Over billions of such encounters, the model develops a repertoire of "task programs" that it can flexibly invoke based on contextual cues. The pre-training objective, next-token prediction, provides the consistent supervision signal, but the underlying capability being developed is task recognition and adaptation.

In[23]:
Code
## Conceptual illustration of pre-training as meta-learning
class PretrainingAsMetaLearning:
    """
    Conceptual model showing how pre-training creates a meta-learner.
    """

    def __init__(self):
        self.task_patterns = {}  # Learned task structures
        self.adaptation_weights = None  # Meta-learned adaptation procedure

    def outer_loop_step(self, batch_of_sequences):
        """
        Pre-training step: learn across many implicit tasks.

        Each sequence contains an implicit task:
        - Some sequences are QA pairs
        - Some are code and comments
        - Some are cause and effect
        - etc.

        The model learns to recognize these patterns and adapt.
        """
        for sequence in batch_of_sequences:
            # Identify implicit task structure in sequence
            task_type = self._infer_task_type(sequence)

            # Update task-specific patterns
            self._update_task_patterns(task_type, sequence)

            # Update meta-learned adaptation procedure
            self._update_adaptation_procedure(task_type, sequence)

    def inner_loop(self, demonstrations, query):
        """
        ICL at inference: rapid adaptation using meta-learned procedure.

        No gradient updates - just pattern recognition and adaptation
        through the forward pass.
        """
        # Recognize task from demonstrations
        recognized_task = self._infer_task_type(demonstrations)

        # Apply meta-learned adaptation procedure
        adapted_representation = self._apply_adaptation(
            recognized_task, demonstrations
        )

        # Generate output for query
        return self._generate(adapted_representation, query)

    def _infer_task_type(self, sequence):
        """Placeholder for task type inference."""
        return "generic_task"

    def _update_task_patterns(self, task_type, sequence):
        """Placeholder for pattern updates."""
        pass

    def _update_adaptation_procedure(self, task_type, sequence):
        """Placeholder for meta-learning updates."""
        pass

    def _apply_adaptation(self, task_type, demonstrations):
        """Placeholder for adaptation."""
        return None

    def _generate(self, representation, query):
        """Placeholder for generation."""
        return "output"

Why Scale Enables Meta-Learning

The meta-learning framework explains why ICL requires scale. Effective meta-learning requires:

  1. Sufficient capacity to represent many different task-specific adaptation procedures
  2. Exposure to diverse tasks during training to learn robust meta-knowledge
  3. Representational flexibility to quickly adapt to new task contexts

Small models lack the capacity to maintain the rich meta-knowledge needed for flexible adaptation. They might learn to perform well on the average pre-training sequence, but they can't maintain the separate "programs" for different task types that enable ICL.

Large models, in contrast, develop what researchers sometimes call "task vectors" or "function vectors" within their representations. Different regions of the model's latent space correspond to different task types, and the demonstrations effectively steer the model toward the appropriate region.

The computational requirements for meta-learning exceed those for single-task learning. To learn a learning algorithm, the model must effectively encode not just how to perform each task, but also the meta-structure that allows rapid adaptation across tasks. This meta-structure includes pattern templates that capture task formats, input-output mapping functions that can be parameterized by demonstrations, and contextual routing mechanisms that direct processing based on task cues. Each of these components requires representational capacity, and they must all coexist without interfering with each other. This explains the scale threshold. Below a certain size, the model simply cannot represent all the components needed for flexible meta-learning.

In[24]:
Code
import numpy as np
from scipy.spatial.distance import pdist, cdist


## Simulate how model capacity affects task representation
def simulate_task_representations(n_tasks, model_capacity):
    """
    Simulate how model capacity affects ability to maintain
    distinct task representations (crucial for meta-learning).
    """
    np.random.seed(42)

    # True task vectors (what we want to represent)
    true_task_vectors = np.random.randn(n_tasks, model_capacity)

    # Add noise (representational interference)
    noise_level = 1.0 / np.sqrt(
        model_capacity
    )  # Less interference with more capacity
    noisy_vectors = true_task_vectors + noise_level * np.random.randn(
        n_tasks, model_capacity
    )

    # Measure distinctiveness (can we tell tasks apart?)
    # Use average pairwise distance as a metric
    distinctiveness = np.mean(pdist(noisy_vectors))

    # Measure interference (similarity between different tasks)
    all_distances = cdist(noisy_vectors, noisy_vectors)
    np.fill_diagonal(all_distances, np.inf)
    interference = 1.0 / np.mean(np.min(all_distances, axis=1))

    return distinctiveness, interference
Out[25]:
Visualization
Line plot showing task distinctiveness increasing with model capacity.
Effect of model capacity on task representation distinctiveness. Larger models maintain more distinct task representations, enabling effective meta-learning and ICL.

Capacity scaling summary:
  At 64 dims: distinctiveness=11.34, interference=0.108
  At 4096 dims: distinctiveness=90.56, interference=0.011
  Improvement: 8.0x distinctiveness, 9.6x less interference

The visualization shows that larger model capacity leads to more distinct task representations and reduced cross-task interference. This separation is essential for the model to apply the right "program" when it recognizes a task from demonstrations.

The MAML Connection

The meta-learning perspective connects ICL to established meta-learning algorithms like Model-Agnostic Meta-Learning (MAML). MAML explicitly trains models to be easily fine-tunable by optimizing for fast adaptation. The core idea is to find an initialization from which a single gradient step on any new task yields good performance. The MAML objective captures this through a bi-level optimization:

θi=θαθLTi(fθ)(inner loop: adapt to task Ti)θ=argminθTip(T)LTi(fθi)(outer loop: optimize initialization)\begin{aligned} \theta'_i &= \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(f_\theta) && \text{(inner loop: adapt to task } \mathcal{T}_i \text{)} \\ \theta^* &= \arg\min_{\theta} \sum_{\mathcal{T}_i \sim p(\mathcal{T})} \mathcal{L}_{\mathcal{T}_i}\left(f_{\theta'_i}\right) && \text{(outer loop: optimize initialization)} \end{aligned}

where:

  • θ\theta: the model's initial parameters (the meta-learned initialization we're optimizing)
  • θi\theta'_i: the adapted parameters for task ii after one gradient step
  • Tip(T)\mathcal{T}_i \sim p(\mathcal{T}): a task sampled from the task distribution
  • fθf_\theta: the model parameterized by θ\theta
  • LTi(fθ)\mathcal{L}_{\mathcal{T}_i}(f_\theta): the loss on task Ti\mathcal{T}_i when using model fθf_\theta
  • α\alpha: the inner-loop learning rate controlling adaptation step size
  • θ\nabla_\theta: the gradient operator with respect to θ\theta
  • minθ\min_\theta: we seek the initialization θ\theta that minimizes total post-adaptation loss across tasks

The key insight is that MAML optimizes the initialization θ\theta such that a single gradient step (or few steps) on any new task yields good performance. Reading the procedure step by step:

  1. Sample a task Ti\mathcal{T}_i from the task distribution p(T)p(\mathcal{T})
  2. Inner loop adaptation: Compute adapted parameters θi=θαθLTi(fθ)\theta'_i = \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(f_\theta) by taking one gradient step
  3. Evaluate: Measure how well the adapted model fθif_{\theta'_i} performs on task Ti\mathcal{T}_i
  4. Outer loop optimization: Adjust the initialization θ\theta to minimize the sum of post-adaptation losses across all sampled tasks. The outer minimization finds the initial parameters θ\theta that, after this task-specific adaptation, perform well across the entire task distribution. This is why MAML is "model-agnostic": it works with any model that can be optimized via gradient descent.

The key insight of MAML is what it optimizes: not performance on any single task, but adaptability across all tasks. The initialization θ\theta is positioned in parameter space such that every task is "nearby." A single gradient step in any task-specific direction leads to good performance on that task. Geometrically, you can think of θ\theta as sitting at a kind of central point from which many task-specific solutions are easily reachable. The inner loop performs task-specific adaptation, while the outer loop adjusts the central point to make all adaptations easier.

ICL can be viewed as MAML taken to its limit. Instead of requiring a few gradient steps, the model adapts in zero gradient steps purely through the forward pass. The pre-training process implicitly learns an initialization (the pre-trained weights) from which any task can be solved by conditioning on demonstrations.

This connection also suggests why ICL emerges suddenly. MAML and similar meta-learning algorithms exhibit phase transitions where models suddenly gain the ability to generalize across tasks. The emergence of ICL in language models may be an analogous transition, occurring when the model develops sufficient capacity to implement task-agnostic adaptation mechanisms.

Out[26]:
Visualization
Diagram showing parameter space with initialization point and arrows to task optima.
MAML finds an initialization (star) from which single gradient steps reach task-specific optima.
Diagram showing activation space with task regions and steering via demonstrations.
ICL achieves adaptation through forward pass steering without explicit gradient steps.

Studying ICL Emergence Empirically

Researchers have developed various experimental approaches to understand ICL emergence. Let's implement some key analyses that reveal how ICL develops with scale.

In[27]:
Code
import numpy as np
import torch


def measure_icl_ability(model_name, task_examples, test_cases, device="cpu"):
    """
    Measure a model's in-context learning ability on a simple task.

    Returns accuracy improvement from adding demonstrations.
    """
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForCausalLM.from_pretrained(model_name).to(device)
    model.eval()

    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token

    def get_prediction(prompt, choices):
        """Get model's preferred choice."""
        choice_probs = []

        for choice in choices:
            full_text = prompt + choice
            inputs = tokenizer(full_text, return_tensors="pt").to(device)

            with torch.no_grad():
                outputs = model(**inputs)
                # Get probability of last token
                logits = outputs.logits[0, -1, :]
                choice_token_id = tokenizer.encode(
                    choice, add_special_tokens=False
                )[0]
                prob = torch.softmax(logits, dim=-1)[choice_token_id].item()
                choice_probs.append(prob)

        return choices[np.argmax(choice_probs)]

    # Format demonstrations
    demo_text = "\n".join(
        [
            f"Input: {ex['input']}\nOutput: {ex['output']}"
            for ex in task_examples
        ]
    )

    zero_shot_correct = 0
    few_shot_correct = 0

    for test in test_cases:
        choices = test["choices"]
        correct = test["correct"]

        # Zero-shot
        zero_shot_prompt = f"Input: {test['input']}\nOutput: "
        zero_shot_pred = get_prediction(zero_shot_prompt, choices)
        if zero_shot_pred == correct:
            zero_shot_correct += 1

        # Few-shot
        few_shot_prompt = demo_text + f"\nInput: {test['input']}\nOutput: "
        few_shot_pred = get_prediction(few_shot_prompt, choices)
        if few_shot_pred == correct:
            few_shot_correct += 1

    n = len(test_cases)
    return {
        "zero_shot_acc": zero_shot_correct / n,
        "few_shot_acc": few_shot_correct / n,
        "icl_gain": (few_shot_correct - zero_shot_correct) / n,
    }
In[28]:
Code
## Define a simple sentiment classification task
task_examples = [
    {"input": "This movie was fantastic", "output": "positive"},
    {"input": "I hated every minute", "output": "negative"},
    {"input": "Best experience ever", "output": "positive"},
    {"input": "Terrible waste of time", "output": "negative"},
]

test_cases = [
    {
        "input": "Absolutely wonderful",
        "choices": ["positive", "negative"],
        "correct": "positive",
    },
    {
        "input": "Disappointing result",
        "choices": ["positive", "negative"],
        "correct": "negative",
    },
    {
        "input": "I loved it",
        "choices": ["positive", "negative"],
        "correct": "positive",
    },
    {
        "input": "Would not recommend",
        "choices": ["positive", "negative"],
        "correct": "negative",
    },
]
Out[29]:
Console
Simulated ICL Emergence Study Results:
==================================================

Model Size (B) | Zero-Shot | Few-Shot | ICL Gain
--------------------------------------------------
           0.1 |      0.48 |     0.50 | +0.02
           0.3 |      0.51 |     0.55 | +0.04
           1.0 |      0.54 |     0.65 | +0.11
           3.0 |      0.58 |     0.78 | +0.20
           7.0 |      0.62 |     0.85 | +0.23

Key observation: ICL gain increases sharply between 0.3B and 3B parameters,
demonstrating the characteristic emergence pattern.
Out[30]:
Visualization
Line plot comparing zero-shot and few-shot accuracy across model sizes.
Zero-shot vs few-shot performance across model scales showing the growing gap.
Line plot showing ICL gain with emergence zone highlighted.
ICL gain showing sharp increase between 0.3B and 3B parameters.

Probing for Internal ICL Mechanisms

Researchers have developed probing techniques to understand what happens inside models during ICL. These methods examine model internals during the forward pass to identify when and how task information is encoded.

In[31]:
Code
import numpy as np
import torch


def analyze_icl_representations(model, tokenizer, demonstrations, query):
    """
    Analyze how representations change through the layers during ICL.

    This probes whether task information accumulates in specific layers.
    """
    # Prepare input
    demo_text = "\n".join([f"Q: {d['q']}\nA: {d['a']}" for d in demonstrations])
    full_prompt = demo_text + f"\nQ: {query}\nA:"

    inputs = tokenizer(full_prompt, return_tensors="pt")

    # Get all hidden states
    with torch.no_grad():
        outputs = model(**inputs, output_hidden_states=True)

    hidden_states = (
        outputs.hidden_states
    )  # Tuple of (batch, seq_len, hidden_dim)

    # Analyze the final position (where prediction happens)
    final_position_states = [h[0, -1, :].numpy() for h in hidden_states]

    # Compute change in representation across layers
    layer_changes = []
    for i in range(1, len(final_position_states)):
        change = np.linalg.norm(
            final_position_states[i] - final_position_states[i - 1]
        )
        layer_changes.append(change)

    return {
        "final_states": final_position_states,
        "layer_changes": layer_changes,
    }
Out[32]:
Visualization
Bar plot of representational change magnitude by layer number.
Representational change across layers during ICL. Middle layers show the largest changes, suggesting task-relevant processing occurs there.
Peak processing occurs around layer 14 (of 24 total).
Maximum representational change at layer 14: 2.13

The analysis reveals that middle-to-late layers show the largest representational changes during ICL, suggesting that task-relevant processing concentrates in these layers rather than being distributed uniformly. This aligns with research showing that different layers serve different functions. Early layers handle basic pattern recognition, middle layers perform task-specific processing, and late layers prepare the final output.

Limitations and Impact

In-context learning has transformed what language models can accomplish, but important constraints remain. This section examines both the practical limitations and the broader impact of ICL emergence.

Current Limitations

Despite the remarkable capabilities of in-context learning, several significant limitations constrain its practical utility.

Context length constraints remain a fundamental bottleneck. ICL performance generally improves with more demonstrations, but the fixed context window limits how many examples can be provided. The techniques we covered in Part XV for extending context length help, but even million-token contexts fall short of the thousands of training examples that fine-tuning can leverage. This limitation is particularly acute for complex tasks that require diverse examples to cover the problem space.

Reliability and consistency present ongoing challenges. ICL performance can vary dramatically based on seemingly minor details: the order of demonstrations, the specific phrasing of examples, or the choice of delimiters. This sensitivity makes ICL less predictable than fine-tuning, where performance is typically more stable. Production systems using ICL often require careful prompt engineering and validation, adding complexity that the simplicity of few-shot learning was meant to eliminate.

Task complexity boundaries define another limitation. While ICL excels at tasks that can be demonstrated through a few examples, it struggles with tasks requiring extended reasoning, deep domain expertise, or complex multi-step procedures. The next chapter on chain-of-thought emergence explores how some of these limitations can be partially addressed through structured prompting approaches.

Computational efficiency at inference is often overlooked. While ICL eliminates training costs, it increases inference costs. Every query must process the full prompt including all demonstrations, making each inference more expensive than querying a fine-tuned model. For high-volume applications, this trade-off can make fine-tuning more economical despite its upfront costs.

Key Parameters

The key parameters affecting ICL emergence and performance are:

  • Model scale: Number of parameters, typically measured in billions. ICL emergence thresholds vary by task but generally require 1B+ parameters for basic tasks and 10B+ for complex reasoning.
  • Context length: Maximum number of tokens the model can process. Longer contexts allow more demonstrations but increase computational cost.
  • Number of demonstrations (k-shot): More examples generally improve performance up to context limits, with diminishing returns.
  • Temperature: Controls output randomness during generation. Lower values (0.0-0.3) typically work better for ICL tasks requiring precise answers.
  • Demonstration ordering: The sequence of examples can significantly affect performance, with more recent examples often having stronger influence.

Transformative Impact

The emergence of in-context learning has changed how we build AI systems. Before ICL, deploying a model for a new task required collecting labeled data, fine-tuning, validation, and deploying task-specific model weights. This process took days to weeks and required machine learning engineering expertise.

With ICL, task adaptation becomes a matter of prompt design. A domain expert without machine learning training can configure a model for their specific use case by providing good examples. This shift has expanded who can build AI-powered applications and how quickly they can be developed.

The emergence of ICL also raised profound questions about what language models actually learn during pre-training. If a model can solve novel tasks from demonstrations, what does this say about its understanding? The mechanistic hypotheses we explored suggest that these models may be learning something deeper than text statistics, perhaps something closer to general-purpose reasoning and adaptation algorithms.

Summary

In-context learning emergence represents a qualitative shift in what language models can do. The key insights from this chapter:

Emergence patterns: ICL ability appears suddenly as models cross scale thresholds, typically between 1-10 billion parameters for basic tasks and larger scales for complex reasoning. This emergence is task-dependent, with simpler capabilities appearing earlier than complex ones.

Scaling comparison: Fine-tuning provides consistent improvements at all scales, while ICL shows emergent behavior. At large scales, few-shot ICL can match fine-tuning with orders of magnitude fewer examples, representing a fundamental shift in how we adapt models to new tasks.

Mechanism hypotheses: Multiple frameworks explain ICL. These include induction heads that implement pattern matching, implicit gradient descent in the forward pass, and task recognition versus task learning perspectives. These mechanisms likely coexist and contribute to overall ICL ability.

Meta-learning framework: Pre-training can be viewed as an outer loop that creates a general-purpose learning algorithm. The model learns not just to predict text, but to recognize tasks and adapt its behavior accordingly. This perspective explains both why ICL works and why it requires scale.

The emergence of ICL has transformed language models from static text predictors into dynamic few-shot learners. In the next chapter, we'll explore another emergent capability that builds on ICL: chain-of-thought reasoning, where models learn to decompose complex problems into explicit reasoning steps.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about in-context learning emergence.

Loading component...

Reference

BIBTEXAcademic
@misc{incontextlearningemergencescalemechanismsmetalearning, author = {Michael Brenndoerfer}, title = {In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning}, year = {2025}, url = {https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms}, organization = {mbrenndoerfer.com}, note = {Accessed: 2025-12-29} }
APAAcademic
Michael Brenndoerfer (2025). In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning. Retrieved from https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms
MLAAcademic
Michael Brenndoerfer. "In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning." 2025. Web. 12/29/2025. <https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms>.
CHICAGOAcademic
Michael Brenndoerfer. "In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning." Accessed 12/29/2025. https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms.
HARVARDAcademic
Michael Brenndoerfer (2025) 'In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning'. Available at: https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms (Accessed: 12/29/2025).
SimpleBasic
Michael Brenndoerfer (2025). In-Context Learning Emergence: Scale, Mechanisms & Meta-Learning. https://mbrenndoerfer.com/writing/in-context-learning-emergence-scale-mechanisms