Transfer Learning › What Transfers: A Layer-by-Layer Analysis

Michael BrenndoerferNovember 24, 202512 min read
Language AI HandbookAll chapters
Part 34 of 67Fine-tuning Fundamentals
Chapter 249Transfer Learning › What Transfers: A Layer-by-Layer Analysis
Reading section 3 of 13 · What Transfers: A Layer-by-Layer Analysis · 12 minSection 3 of 13 · 12 min

Book contents

Section 3 of 13 · 12 min read

Transfer Learning › What Transfers: A Layer-by-Layer AnalysisOne section · Sections in this chapter3 / 13 ↓
Reading tools Definitions & inline links

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.

Article links

Make inline references clickable

Not all knowledge transfers equally. Research into what pre-trained models learn reveals a hierarchical organization where different layers capture different linguistic phenomena. Understanding this hierarchy helps explain why transfer learning works and guides decisions about how to fine-tune models effectively. The progression from lower to upper layers mirrors the progression from surface form to deep meaning, a pattern that emerges naturally from the pre-training objective.

This layered organization has a direct practical implication: when fine-tuning for tasks that require primarily syntactic processing (like parsing or part-of-speech tagging), the relevant representations are concentrated in middle layers, and you may not need to update all parameters. When fine-tuning for tasks requiring deep semantic understanding (like natural language inference or question answering), the upper layers matter most, and those need the most updating during fine-tuning. We will return to this intuition when we discuss parameter-efficient fine-tuning strategies in later chapters.

Lower Layers: Surface Patterns and Morphology

The early layers of transformer models capture surface-level patterns: character sequences, morphological structure, and local syntactic relationships. These layers learn representations that are highly transferable because they encode basic aspects of language that appear across virtually all text.

Why do lower layers specialize in surface patterns? The answer lies in how information flows through the network. The first layer receives token embeddings that encode only local information about each token's identity. Through self-attention, this layer can detect patterns in how tokens co-occur within local contexts, learning that certain character sequences form words and that certain words frequently appear together. These patterns are the building blocks upon which higher-level understanding is constructed.

Think of lower layers as the equivalent of phonological and morphological processing in human language comprehension. Before you can understand the meaning of a sentence, your brain must identify the individual words and their grammatical forms. The early transformer layers perform this same function: recognizing tokens as belonging to grammatical categories and identifying their inflectional and derivational properties.

Probing experiments reveal that lower layers can accurately predict:

  • Part-of-speech tags
  • Morphological features (tense, number, case)
  • Character-level patterns
  • Basic phrase boundaries

These representations are language-specific but task-agnostic. Whether you are doing sentiment analysis, named entity recognition, or question answering, you need to understand that "running" is a verb form and "quickly" is an adverb. The universality of these requirements explains why lower-layer representations transfer so effectively across diverse tasks.

Middle Layers: Syntactic Structure

The middle layers of pre-trained models encode syntactic structure. These layers learn implicit parse trees, dependency relationships, and long-range grammatical agreements. Remarkably, models trained only to predict words develop representations that correlate strongly with traditional linguistic formalisms, even though they were never explicitly taught these concepts.

This shows that the pre-training objective helps models learn syntax. Consider why syntactic understanding helps predict masked words. In the sentence "The dogs that live next door [MASK] loudly every morning," predicting the masked word requires knowing that "dogs" is the subject, not "door." This requires tracking the relative clause structure and maintaining agreement across intervening material. Models that learn to make such predictions accurately must develop internal representations of syntactic structure.

The key insight here is that syntax is not explicitly taught during pre-training. It emerges because syntactic structure is predictive of what words appear where. The model learns syntax as an instrumental goal on the way to minimizing prediction loss. This is a remarkable property of self-supervised learning: by optimizing a simple proxy objective (predict the missing word), the model acquires abstract linguistic knowledge that humans spent centuries formalizing in grammar theories.

Research using attention probing has found that specific attention heads specialize in tracking syntactic relationships:

  • Subject-verb agreement across intervening clauses
  • Coreference chains linking pronouns to antecedents
  • Constituency boundaries marking phrase structure

This syntactic knowledge transfers because syntax constrains meaning. Understanding that "the cat that chased the mouse ate the cheese" means the cat ate the cheese (not the mouse) requires syntactic parsing, regardless of what downstream task you are performing. A sentiment classifier, a question answering system, and a summarization model all benefit from accurate syntactic analysis, even though their ultimate outputs differ sharply.

Upper Layers: Semantics and Task Adaptation

The upper layers capture more abstract semantic relationships and are most influenced by fine-tuning. These layers encode meaning compositions, reasoning patterns, and increasingly task-specific representations as you move toward the output.

The semantic representations in upper layers integrate information gathered from lower layers into coherent interpretations. At this level, the model is word meaning in context, so the same word "bank" receives different representations depending on whether the surrounding context involves rivers or finance. These contextualized semantic representations are the primary currency of transfer learning, encoding the rich understanding that lets downstream task performance.

During fine-tuning, upper layers change more than lower layers. This makes intuitive sense: the surface-level linguistic knowledge encoded in lower layers remains useful regardless of task, while the higher-level representations need reshaping to produce task-specific outputs. A sentiment classifier and a named entity recognizer both benefit from the same morphological and syntactic analysis, but they need different semantic representations to produce their respective outputs. Fine-tuning specializes the upper layers for each task while largely preserving the shared lower-layer representations.

Think of the layer hierarchy as analogous to the layers of human cognitive processing. Low-level perceptual processing recognizes phonemes and words. Middle-level grammatical processing parses sentence structure. High-level conceptual processing interprets meaning and relates it to world knowledge. Pre-training builds all three levels simultaneously by forcing the model to predict words accurately, which requires competence at every level.

Visualizing Layer Representations

Let's examine how representations differ across layers in a pre-trained model.

In[3]:
Code
!uv pip install transformers torch numpy matplotlib scikit-learn
from transformers import AutoModel, AutoTokenizer
import torch
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from sklearn.decomposition import PCA

# Load a pre-trained BERT model
model_name = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name, output_hidden_states=True)
model.eval()
In[4]:
Code
# Example sentences with different semantic content
# First 3: Financial bank, Last 3: River bank
sentences = [
    "The bank approved my loan application.",
    "She deposited money at the bank.",
    "I need to go to the bank to withdraw cash.",
    "The river bank was covered in wildflowers.",
    "We sat on the bank and watched the fish.",
    "The boat was tied to the bank of the river.",
]


# Get hidden states for all layers
def get_layer_representations(sentences, word="bank"):
    representations = {i: [] for i in range(13)}  # 12 layers + embeddings

    for sent in sentences:
        inputs = tokenizer(sent, return_tensors="pt", padding=True)
        with torch.no_grad():
            outputs = model(**inputs)

        # Find the position of our target word
        tokens = tokenizer.tokenize(sent)
        word_idx = None
        for idx, token in enumerate(tokens):
            if word in token:
                word_idx = idx + 1  # +1 for [CLS] token
                break

        if word_idx is not None:
            for layer_idx, hidden_state in enumerate(outputs.hidden_states):
                rep = hidden_state[0, word_idx, :].numpy()
                representations[layer_idx].append(rep)

    return representations


reps = get_layer_representations(sentences)

We extract representations of the word "bank" from sentences where it has different meanings: the financial institution versus the river bank. This experiment shows how pre-trained models disambiguate word senses based on context. Let's see how these representations separate across layers:

In[5]:
Code
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.lines import Line2D
from sklearn.decomposition import PCA

use_book_style(fixed_canvas=True)
plt.rcParams["figure.figsize"] = (2.0, 1.8)

layers_to_plot = [0, 2, 4, 7, 9, 11]
# Financial (orange), River (blue)
colors = ["#ff7f0e"] * 3 + ["#1f77b4"] * 3

for layer_idx in layers_to_plot:
    plt.figure()
    plt.subplots_adjust(left=0.28, right=0.96, bottom=0.30, top=0.84)
    if len(reps[layer_idx]) >= 2:
        X = np.array(reps[layer_idx])
        pca = PCA(n_components=2)
        X_pca = pca.fit_transform(X)

        for i, (x, y) in enumerate(X_pca):
            plt.scatter(x, y, c=colors[i], s=50, alpha=0.7)

        plt.title(f"Layer {layer_idx}")
        plt.xlabel("PC1")
        plt.ylabel("PC2")

        # Add legend to the first plot as a key
        if layer_idx == 0:
            legend_elements = [
                Line2D(
                    [0],
                    [0],
                    marker="o",
                    color=theme_color("w"),
                    markerfacecolor=theme_color("#ff7f0e"),
                    label="Financial",
                ),
                Line2D(
                    [0],
                    [0],
                    marker="o",
                    color=theme_color("w"),
                    markerfacecolor=theme_color("#1f77b4"),
                    label="River",
                ),
            ]
            plt.legend(handles=legend_elements, loc="center")

    plt.show()

We can quantify this separation by computing the ratio of between-class to within-class distances at each layer. The idea behind this metric is intuitive: if the two senses of "bank" are well-separated in representation space, then the average distance between a financial-bank representation and a river-bank representation should be large, while the average distance between two financial-bank representations (or two river-bank representations) should be small. A ratio greater than 1.0 means the senses are more different from each other than they are internally variable, which is exactly what we want for effective disambiguation.

In[6]:
Code
# Quantify the separation of "bank" meanings across layers
separation_ratios = []

for layer_idx in range(13):
    layer_reps = reps[layer_idx]
    if len(layer_reps) >= 6:
        X = np.array(layer_reps)
        # Financial bank: sentences 0-2, River bank: sentences 3-5
        financial = X[:3]
        river = X[3:]

        # Compute mean distance between classes
        between_dists = []
        for f in financial:
            for r in river:
                between_dists.append(np.linalg.norm(f - r))
        between_mean = np.mean(between_dists)

        # Compute mean distance within each class
        within_financial = []
        for i, f1 in enumerate(financial):
            for j, f2 in enumerate(financial):
                if i < j:
                    within_financial.append(np.linalg.norm(f1 - f2))

        within_river = []
        for i, r1 in enumerate(river):
            for j, r2 in enumerate(river):
                if i < j:
                    within_river.append(np.linalg.norm(r1 - r2))

        within_mean = (
            np.mean(within_financial + within_river)
            if (within_financial + within_river)
            else 1e-8
        )

        separation_ratios.append(between_mean / (within_mean + 1e-8))
    else:
        separation_ratios.append(np.nan)
In[7]:
Code
import matplotlib.pyplot as plt

use_book_style()
plt.rcParams["figure.figsize"] = (6.0, 4.0)

plt.figure()
plt.plot(range(13), separation_ratios, "o-", linewidth=1, markersize=8)
plt.axhline(y=1.0, color=PALETTE["muted"], linestyle="--", alpha=0.5)
plt.xlabel("Layer")
plt.ylabel("Between/Within Class Distance Ratio")
plt.title("Word Sense Separation Across BERT Layers")
plt.xticks(range(13), ["Emb"] + [str(i) for i in range(1, 13)])
plt.show()
Out[7]:
Visualization
Line chart showing the ratio of between-class to within-class distance for BERT representations of the word bank across 13 layers. The ratio rises steeply in the middle layers, surpassing 1.0, showing that financial and river senses become more separable than the variation within each sense.
Ratio of between-class to within-class Euclidean distances for 'bank' representations across BERT layers. A ratio exceeding 1.0 indicates that context-specific clusters (financial vs. river) are more distinct than the internal variation within each sense. The steep rise in middle layers quantifies the network's increasing ability to disambiguate word senses based on syntactic and semantic context.

The visualization reveals how word sense disambiguation emerges across layers. In lower layers, representations of "bank" are relatively similar regardless of context. This shows the fact that these layers primarily encode the token's identity and local patterns rather than its contextual meaning. As we progress through the middle layers, the representations begin to diverge. This shows the integration of syntactic context. By upper layers, the financial and geographical senses have separated in representation space, forming distinct clusters that reflect their different meanings.

This contextual disambiguation, which the model learned during pre-training without any explicit word sense labels, directly benefits any downstream task involving ambiguous words. A sentiment classifier analyzing "The bank's customer service was terrible" benefits from knowing that "bank" refers to a financial institution, because financial institutions can have customer service while river banks cannot. This disambiguation happens automatically, as a natural consequence of the rich contextual representations learned during pre-training.

Key Parameters

The key parameters for the visualization code are:

  • output_hidden_states (AutoModel): Set to True to retrieve hidden states from all layers rather than just the final layer.
  • n_components (PCA): The number of principal components to keep (2) for reducing the high-dimensional representations to a plotable 2D space.