Matrixmultiplikation für die Vorwärtspropagation neuronaler Netze

Schreibe \(y = Wx + b\) von Hand, gib Matrizen unterschiedlicher Formen ein und beobachte, wie sich die Dimensionen ändern und zusammenpassen.

Nach Abschluss dieser Fallstudie wirst du verstehen:Wenn beim Training neuronaler Netze ein Fehler wegen nicht übereinstimmender Formen gemeldet wird, ist der Kern, dass die Dimensionen der Matrixmultiplikation nicht zusammenpassen.


Einführung in den Alltag

Express-Sortierzentrum

Eine Charge Pakete kommt vom Förderband (Eingabe), wird von Sortiermaschinen auf verschiedene Lastwagen umgeleitet (versteckte Schicht) und schließlich an verschiedene Wohnsiedlungen geliefert (Ausgabe).

Jede Sortiermaschine ist ein "Neuron" — sie empfängt alle Pakete und entscheidet nach Regeln, welche Pakete ihren eigenen Weg nehmen. Die Regeln der Sortiermaschine sind die "Gewichte": mehr Pakete in die eine Richtung verteilen und weniger in die andere.

Die Funktionsweise des gesamten Sortierzentrums ist:Matrixmultiplikation + Aktivierungsfunktion + Bias。


Intuitive Vorstellung

Eine Schicht eines neuronalen Netzes = drei Schritte, in einer Codezeile erledigt:

\( z = X @ W + b \)

Jeder Teil hat eine klare Rolle:

X
Eingabedaten
(batch, in)
W
Gewichtsmatrix
(in, out)
b
Bias
(out,)
z
Ausgabe
(batch, out)
Die eiserne Regel der Dimensionsübereinstimmung:Die Anzahl der Spalten von A muss gleich der Anzahl der Zeilen von B sein! \(A_{(m \times n)} \cdot B_{(n \times p)} = C_{(m \times p)}\)

Die Anzahl der Eingabemerkmale (in_features) muss gleich der Zeilenanzahl der Gewichtsmatrix sein. Die Anzahl der Ausgabemerkmale (out_features) ist gleich der Spaltenanzahl der Gewichtsmatrix. batch_size bleibt während des gesamten Prozesses unverändert.


Mathematische Definition

Einschichtige Vorwärtspropagation

\[ z_j = \sum_{i=1}^{n} x_i \cdot W_{ij} + b_j \]

Jede Ausgabe \(z_j\) ist das Skalarprodukt des Eingabevektors mit der \(j\)-ten Spalte der Gewichtsmatrix plus dem Bias.

Zweischichtige Netzwerk-Kaskade

\[ \begin{aligned} h &= \text{ReLU}(X W_1 + b_1) \quad & (m \times 4) \cdot (4 \times 6) &= (m \times 6) \\ o &= \text{Sigmoid}(h W_2 + b_2) \quad & (m \times 6) \cdot (6 \times 2) &= (m \times 2) \end{aligned} \]

Hinweis: Die Anzahl der Ausgabemerkmale (6) der ersten Schicht muss gleich der Zeilenanzahl (6) der Gewichtsmatrix der zweiten Schicht sein. Dies ist die "dimensionale Verbindung zwischen Schichten".


Python-Praxisübung

Verwenden Sie eine generische dense_layer-Funktion, um drei Szenarien zu demonstrieren: einzelne Stichprobe, Batch-Verarbeitung und zweischichtiges Netzwerk.

Beispiel

import numpy as np

def dense_layer(X, W, b, activation=None):
    """
Vorwärtspropagation einer einzelnen vollständig verbundenen Schicht
X: Eingabematrix (batch_size, in_features)
W: Gewichtsmatrix (in_features, out_features)
b: Bias-Vektor (out_features,)
    """

    z = X @ W + b   # Matrixmultiplikation + Broadcast-Addition
    if activation == "relu":
        return np.maximum(0, z)          # ReLU: negative Werte werden zu 0
    if activation == "sigmoid":
        return 1 / (1 + np.exp(-z))      # Sigmoid: staucht auf (0,1)
    return z

print("=" * 55)
print("BEISPIEL Szenario 1: einzelne Stichprobe, 4 Dimensionen -> 3 Dimensionen")
print("=" * 55)
X = np.array([[1.0, 2.0, 0.5, -1.0]])     # (1, 4)
W = np.random.randn(4, 3) * 0.5            # (4, 3)
b = np.zeros(3)                            # (3,)
y = dense_layer(X, W, b, activation="relu")
print("X.shape:", X.shape, " W.shape:", W.shape,
      " -> y.shape:", y.shape)

print("\n" + "=" * 55)
print("BEISPIEL Szenario 2: Batch von 8 Stichproben, gleiche Gewichte")
print("=" * 55)
X_batch = np.random.randn(8, 4)            # (8, 4)
y_batch = dense_layer(X_batch, W, b, activation="relu")
print("X_batch.shape:", X_batch.shape,
      " -> y_batch.shape:", y_batch.shape)
print("Batch-Größe 8 unverändert, Merkmalsdimension 4 -> 3")

print("\n" + "=" * 55)
print("BEISPIEL Szenario 3: Stapeln eines zweischichtigen Netzwerks")
print("=" * 55)
# Erste Schicht: 4 Dimensionen -> 6 Dimensionen + ReLU
W1 = np.random.randn(4, 6) * 0.5
b1 = np.zeros(6)
# Zweite Schicht: 6 Dimensionen -> 2 Dimensionen + Sigmoid
W2 = np.random.randn(6, 2) * 0.5
b2 = np.zeros(2)

h = dense_layer(X_batch, W1, b1, activation="relu")
out = dense_layer(h, W2, b2, activation="sigmoid")

print(f"Eingabeschicht: {X_batch.shape}")
print(f"Versteckte Schicht: {h.shape} (4->6, W1=(4,6))")
print(f"Ausgabeschicht: {out.shape} (6->2, W2=(6,2))")

# Überprüfung: Was passiert, wenn die Dimensionen nicht übereinstimmen?
print("\n" + "=" * 55)
print("BEISPIEL Szenario 4: Dimensionskonflikt verursacht einen Fehler")
print("=" * 55)
try:
    W_wrong = np.random.randn(5, 3) * 0.5  # Anzahl der Zeilen ist falsch
    dense_layer(X_batch, W_wrong, b)
except ValueError as e:
    print("Fehlergrund: X_batch hat 4 Spalten,"
          "W_wrong hat 5 Zeilen -> kann nicht multipliziert werden")
    print(f" Richtiger Ansatz: Die Anzahl der Zeilen von W ({W_wrong.shape[0]})"
          f" sollte gleich der Anzahl der Spalten von X ({X_batch.shape[1]}) sein")
=======================================================
EXAMPLE 场景 1:单样本,4 维 -> 3 维
=======================================================
X.shape: (1, 4)   W.shape: (4, 3)   ->  y.shape: (1, 3)

=======================================================
EXAMPLE 场景 2:8 个样本批量,同权重
=======================================================
X_batch.shape: (8, 4)   ->  y_batch.shape: (8, 3)
批大小 8 不变,特征维度 4 -> 3

=======================================================
EXAMPLE 场景 3:堆叠两层网络
=======================================================
输入层: (8, 4)
隐藏层: (8, 6)  (4->6, W1=(4,6))
输出层: (8, 2)  (6->2, W2=(6,2))

=======================================================
EXAMPLE 场景 4:维度不匹配会报错
=======================================================
报错原因:X_batch 有 4 列,W_wrong 有 5 行 -> 无法相乘
  正确做法:W 的行数 (5) 应等于 X 的列数 (4)

Anwendungsszenarien in der KI

KI-SzenarioBeispiel für DimensionsänderungBeschreibung
Vollständig verbundene Schicht(32, 784) @ (784, 128) = (32, 128)MNIST-Klassifikation: 28x28=784 Pixel → 128-dimensionale Merkmale
QKV des Transformers(B, L, D) @ (D, D) = (B, L, D)Self-Attention: Eingabe- und Ausgabe-Token-Dimensionen bleiben unverändert
Embedding-Lookup-Tabelle(B, L) → (B, L, D)Wort-ID-Sequenz → Wortvektor-Sequenz
Klassifikationskopf(B, 768) @ (768, 10) = (B, 10)Klassifikationsausgabe der letzten Schicht von BERT
Weitere Erweiterungen