Weight Initialization › Empirical Comparison of Initialization Methods

Michael BrenndoerferApril 25, 20253 min read
Language AI HandbookAll chapters
Part 10 of 67Neural Network Foundations
Chapter 70Weight Initialization › Empirical Comparison of Initialization Methods
Reading section 11 of 19 · Empirical Comparison of Initialization Methods · 3 minSection 11 of 19 · 3 min

Book contents

Section 11 of 19 · 3 min read

Weight Initialization › Empirical Comparison of Initialization MethodsOne section · Sections in this chapter11 / 19 ↓
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

Theory tells us which initialization should work best for a given activation function, but practice sometimes differs from theory. Let's run a controlled empirical comparison to see how the different methods perform during training.

In[24]:
Code
import torch
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset


def create_network_with_init(
    hidden_sizes, activation="relu", init_method="he_normal"
):
    """Create a sequential network with the specified initialization method."""
    layers = []
    for i in range(len(hidden_sizes) - 1):
        linear = nn.Linear(hidden_sizes[i], hidden_sizes[i + 1])

        if init_method == "xavier_uniform":
            nn.init.xavier_uniform_(linear.weight)
        elif init_method == "xavier_normal":
            nn.init.xavier_normal_(linear.weight)
        elif init_method == "he_normal":
            nn.init.kaiming_normal_(linear.weight, nonlinearity="relu")
        elif init_method == "he_uniform":
            nn.init.kaiming_uniform_(linear.weight, nonlinearity="relu")
        elif init_method == "orthogonal":
            nn.init.orthogonal_(linear.weight, gain=np.sqrt(2))
        elif init_method == "zeros":
            nn.init.zeros_(linear.weight)
        elif init_method == "bert":
            nn.init.normal_(linear.weight, mean=0.0, std=0.02)

        nn.init.zeros_(linear.bias)
        layers.append(linear)

        if i < len(hidden_sizes) - 2:
            if activation == "relu":
                layers.append(nn.ReLU())
            elif activation == "tanh":
                layers.append(nn.Tanh())

    return nn.Sequential(*layers)


def train_model(model, train_loader, epochs=60, lr=0.01):
    """Train model and return loss history."""
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), lr=lr)
    losses = []
    for epoch in range(epochs):
        epoch_loss = 0
        for X, y in train_loader:
            optimizer.zero_grad()
            outputs = model(X)
            loss = criterion(outputs, y)
            loss.backward()
            optimizer.step()
            epoch_loss += loss.item()
        losses.append(epoch_loss / len(train_loader))
    return losses


# Create a structured 5-class classification dataset
torch.manual_seed(42)
np.random.seed(42)

n_samples = 2000
n_features = 100
n_classes = 5

# Gaussian clusters with realistic overlap
centers = np.random.randn(n_classes, n_features) * 3
X_np = np.vstack(
    [
        centers[c] + np.random.randn(n_samples // n_classes, n_features) * 1.8
        for c in range(n_classes)
    ]
)
y_np = np.repeat(np.arange(n_classes), n_samples // n_classes)

X = torch.FloatTensor(X_np)
y = torch.LongTensor(y_np)
dataset = TensorDataset(X, y)
train_loader = DataLoader(dataset, batch_size=64, shuffle=True)

hidden_sizes = [100, 128, 128, 128, n_classes]
Out[25]:
Visualization
Line plot showing training loss over 60 epochs for six initialization methods, with zero init flat and all others converging.
Training loss over 60 epochs for six initialization methods on a 4-layer ReLU network. Zero initialization fails completely (flat high-loss curve) because the symmetry problem prevents any learning. Xavier, He, and orthogonal initialization all enable convergence. He initialization shows slightly faster initial descent on this ReLU network, as expected from its derivation. The BERT-style fixed std=0.02 is suboptimal here because the standard deviation is not adapted to the actual layer dimensions.
Out[26]:
Console
Final training loss after 60 epochs:
--------------------------------------------------
  Zero init                : 1.6095
  Xavier normal            : 0.0003
  He normal                : 0.0001
  He uniform               : 0.0001
  Orthogonal               : 0.0001
  BERT (std=0.02)          : 0.0010

The comparison shows a clear hierarchy. Zero initialization fails completely. Xavier performs well but converges slightly more slowly than He on this ReLU network, because it was designed for tanh. He and orthogonal initialization both perform well and converge at similar rates. The BERT-style fixed standard deviation (0.02) underperforms because it is not calibrated to these layer dimensions.