Aufgabe 2

Fine-Tuning eines vortrainierten Modells (ResNet18)

Transfer Learning statt Training von Grund auf: ein fertig vortrainiertes Modell wird auf deine Pizza-Aufgabe angepasst. Ca. 45 Minuten.

Aufgabe 1 Aufgabe 2 Aufgabe 3 Aufgabe 4 Aufgabe 5 Aufgabe 6
i

Was du lernst

  • Ein vortrainiertes Modell auf deine eigene Aufgabe anpassen (Fine-Tuning).
  • Vier Modelle aus zwei Datensätzen und zwei Trainingslängen vergleichen.
  • Sehen, was Fine-Tuning gegenüber Training von Grund auf bringt.
  • Prüfen, ob ein besseres Modell den Grenzfall Flammkuchen löst.

Wie das System aufgebaut ist

PC bpm-pizza-ml train-pizza-*.py torchvision *.pth data/v1 · data/v2 Windows + WSL2 .venv python3 ResNet18 weights, ~44 MB 4 trained models test_images/

ResNet18 hat 18 Schichten und ~11,2M auf ImageNet vortrainierte Parameter. Nur der neue Klassifikationskopf wird auf deinen Daten trainiert:

Pretrained Backbone (Layers 1-17)            New Classifier Head
+-----------------------------------------+  +---------------------+
|                                         |  |                     |
| Layer 1-4:   Low-level features         |  |  Linear: 512 -> 256 |
|              (edges, colors, textures)  |  |  ReLU               |
|                                         |  |  Dropout(0.3)       |
| Layer 5-10:  Mid-level features         |  |  Linear: 256 -> 1   |
|              (shapes, patterns)         |  |  Sigmoid            |
|                                         |  |                     |
| Layer 11-17: High-level features        |  |  Output:            |
|              (objects, scenes)          |  |  0 = not pizza       |
|                                         |  |  1 = pizza           |
+-----------------------------------------+  +---------------------+
   Frozen (pretrained on ImageNet)              Trained on your data
0

Schritt 0 — Setup prüfen

Bei jedem neuen Terminal: diese zwei Zeilen zuerst (Bash, WSL2/Linux).

cd ~/projects/bpm-pizza-ml
source .venv/bin/activate

Der Check prüft Abhängigkeiten, data/v1, data/v2 und test_images/:

python3 check_environment.py

Die Ausgabe endet mit:

All dependencies and data are present. You are ready to start.

Neu in WSL? Kurze Einführung („Was ist WSL und wie starte ich es?“): siehe Aufgabe 1

Etwas davon fehlt oder schlägt fehl? Erst Claude oder Codex fragen, im Browser oder Terminal, mit der Fehlermeldung im Wortlaut. Hilft das nicht, beim Trainer melden — Installieren ist Trainersache.
1

Die Aufgabe

Vier ResNet18-Modelle, EIN Block: ein Trainingslauf pro Zeile (v1 oder v2, 10 oder 50 Epochs):

python3 train-pizza-finetuning.py --data-dir ./data/v1 --epochs 10 --output pizza_resnet18_v1_10.pth
python3 train-pizza-finetuning.py --data-dir ./data/v1 --epochs 50 --output pizza_resnet18_v1_50.pth
python3 train-pizza-finetuning.py --data-dir ./data/v2 --epochs 10 --output pizza_resnet18_v2_10.pth
python3 train-pizza-finetuning.py --data-dir ./data/v2 --epochs 50 --output pizza_resnet18_v2_50.pth
Warum v1 UND v2? v1 ist der Rohdatensatz, v2 der bereinigte aus Aufgabe 1 — beide, damit du den Unterschied direkt siehst.

So sieht die Ausgabe eines einzelnen Trainingslaufs typischerweise aus (Beispiel, gekürzt):

Loading ResNet18 (pretrained=True)...
Trainable parameters: N,NNN (0.NNM)

Starting training for 10 epochs...
======================================================================
Epoch  1/10 | Train Loss: 0.NNNN, Acc: NN.NN% | Test Loss: 0.NNNN, Acc: NN.NN%
  -> Saved best model (acc: NN.NN%)
...
Epoch 10/10 | Train Loss: 0.NNNN, Acc: NN.NN% | Test Loss: 0.NNNN, Acc: NN.NN%
======================================================================
Training complete! Best accuracy: NN.NN%
Model saved to: pizza_resnet18_v1_10.pth

Lesehilfe: Links Train Loss und Acc auf den Trainingsbildern, rechts Test Loss und Acc auf zurückgehaltenen Testbildern. Nur die rechte zählt — sie steht am Ende als Best accuracy, und diese Zahl trägst du unten ein. Trainable parameters ist klein: nur der neue Kopf wird trainiert. Beim ersten Lauf lädt torchvision die ResNet18-Gewichte einmalig (~44 MB).

Notiere deine Trainingsergebnisse:

Modell Daten Epochs Trainingsdauer Testgenauigkeit
pizza_resnet18_v1_10.pth v1 10 ___ ___%
pizza_resnet18_v1_50.pth v1 50 ___ ___%
pizza_resnet18_v2_10.pth v2 10 ___ ___%
pizza_resnet18_v2_50.pth v2 50 ___ ___%
2

Alle 4 Modelle testen

EIN Block statt 16 Befehlen: pro Testbild eine Tabelle mit allen vier Modellen untereinander.

if [ -t 1 ]; then GREEN=$'\033[32m'; RED=$'\033[31m'; RESET=$'\033[0m'
else GREEN=""; RED=""; RESET=""; fi

declare -A EXPECTED=(
  [pizza_margherita]="PIZZA"
  [pizza_supreme]="PIZZA"
  [ice]="NOT PIZZA"
  [flammkuchen]="NOT PIZZA"
)

for img in pizza_margherita pizza_supreme ice flammkuchen; do
  echo "======================================================="
  echo "Image: $img.jpg   (expected: ${EXPECTED[$img]})"
  echo "======================================================="
  printf '%-26s %-12s %-12s %s\n' "MODEL" "RESULT" "CONFIDENCE" "STATUS"
  printf '%.0s-' {1..64}; echo
  for model in pizza_resnet18_v1_10 pizza_resnet18_v1_50 \
               pizza_resnet18_v2_10 pizza_resnet18_v2_50; do
    out=$(python3 train-pizza-finetuning.py --predict test_images/$img.jpg --output $model.pth)
    result=$(echo "$out" | grep -i '^Result:'     | sed 's/^Result: *//')
    conf=$(  echo "$out" | grep -i '^Confidence:' | sed 's/^Confidence: *//')
    if [ -z "$result" ]; then
      result="-"; conf="-"
      status=$(printf '%-6s' "ERROR"); color=$RED
    elif [ "$result" = "${EXPECTED[$img]}" ]; then
      status=$(printf '%-6s' "OK");    color=$GREEN
    else
      status=$(printf '%-6s' "WRONG"); color=$RED
    fi
    printf '%-26s %-12s %-12s %s%s%s\n' \
      "$model" "$result" "$conf" "$color" "$status" "$RESET"
  done
  echo
done
Das schwerste Testbild: flammkuchen.jpg sieht Pizza sehr ähnlich. Achte darauf, welche Modelle sich täuschen lassen.

RESULT, NN.NN% und OK|WRONG stehen für deine eigenen Werte:

=======================================================
Image: pizza_margherita.jpg   (expected: PIZZA)
=======================================================
MODEL                      RESULT       CONFIDENCE   STATUS
----------------------------------------------------------------
pizza_resnet18_v1_10       RESULT       NN.NN%       OK|WRONG
pizza_resnet18_v1_50       RESULT       NN.NN%       OK|WRONG
pizza_resnet18_v2_10       RESULT       NN.NN%       OK|WRONG
pizza_resnet18_v2_50       RESULT       NN.NN%       OK|WRONG

Lesehilfe: RESULT ist das Urteil, CONFIDENCE die Konfidenz in genau dieses Urteil — daher immer mindestens 50 Prozent; Werte knapp darüber heißen: das Modell rät fast. STATUS vergleicht das Urteil mit dem erwarteten Label aus der Kopfzeile: OK grün, WRONG rot. Grün heißt „richtig“, nicht „Pizza“ — ein korrektes NOT PIZZA bei ice.jpg ist grün. ERROR heißt: Vorhersage fehlgeschlagen.

Woher die Werte kommen: jede Vorhersage druckt diese zwei Zeilen.

Loading ResNet18 model from pizza_resnet18_v1_10.pth...

Result: PIZZA
Confidence: NN.NN%

Du willst sehen, was klassifiziert wird? Testbilder & Trainingsdaten: Galerie in Aufgabe 1

Optional: Alles in einem Lauf

Ein fertiges Skript macht alles auf einmal:

./run_all_tests_finetuning.sh

Trainieren, testen, Vergleichstabelle — hier maskiert:

============================================================
  Running Inference
============================================================

--- v1_10 ---
  pizza_margherita: RESULT NN.NN% [OK|WRONG]
  pizza_supreme: RESULT NN.NN% [OK|WRONG]
  ice: RESULT NN.NN% [OK|WRONG]
  flammkuchen: RESULT NN.NN% [OK|WRONG]

--- v1_50 ---
...

============================================================
  COMPARISON TABLE
============================================================

Image                | v1+10ep                | v1+50ep                | v2+10ep                | v2+50ep
---------------------+------------------------+------------------------+------------------------+-----------------------
pizza_margherita     | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)
pizza_supreme        | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)
ice                  | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)
flammkuchen          | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)        | RESULT (NN.NN%)
Hinweis: Der Lauf dauert länger als die Einzelblöcke. RESULT und NN.NN oben sind Platzhalter — der Lauf trägt deine eigenen Werte ein.
3

Alle vier ResNet18-Modelle vergleichen

Trage deine Ergebnisse in die folgende Tabelle ein:

Metrik v1+10 Ep. v1+50 Ep. v2+10 Ep. v2+50 Ep.
Testgenauigkeit ___%___%___%___%
pizza_margherita.jpg ____________
pizza_supreme.jpg ____________
ice.jpg ____________
flammkuchen.jpg ____________
Fragen:
  • Welches ResNet18-Modell ist das beste?
  • Macht Datenqualität bei einem vortrainierten Modell noch einen Unterschied?
  • Wie verhält sich der Effekt von mehr Epochs im Vergleich zu Aufgabe 1?
4

Der grosse Vergleich — TinyVGG vs. ResNet18

🖨️ Leere Vergleichstabelle zum Ausdrucken

Kombiniere deine Ergebnisse aus Aufgabe 1 (TinyVGG, von Grund auf) und Aufgabe 2 (ResNet18, Fine-Tuning):

Metrik TinyVGG (Aufgabe 1) ResNet18 (Aufgabe 2)
v1+10 v1+50 v2+10 v2+50 v1+10 v1+50 v2+10 v2+50
Architektur TinyVGG (~8,6M) ResNet18 (~11,2M)
Ansatz Von Grund auf Fine-Tuning
Daten v1 v1 v2 v2 v1 v1 v2 v2
Epochs 10501050 10501050
Testgenauigkeit ___%___%___%___% ___%___%___%___%
pizza_margherita.jpg ____________ ____________
pizza_supreme.jpg ____________ ____________
ice.jpg ____________ ____________
flammkuchen.jpg ____________ ____________

TinyVGG-Referenzwerte stehen nur dort: Zur Lösung in Aufgabe 1

Referenzdaten anzeigen (falls eigene Ergebnisse fehlen)
Testgenauigkeit
ResNet18
v1+10v1+50v2+10v2+50
Testgenauigkeit 85.60%84.80%95.00%95.40%
Bildvorhersagen
ResNet18
v1+10v1+50v2+10v2+50
pizza_margherita.jpg PIZZA 76%PIZZA 78%PIZZA 98%PIZZA 100%
pizza_supreme.jpg PIZZA 78%PIZZA 77%PIZZA 71%PIZZA 94%
ice.jpg NOT PIZZA 84%NOT PIZZA 67%NOT PIZZA 100%NOT PIZZA 100%
flammkuchen.jpg PIZZA 61%PIZZA 74%NOT PIZZA 74%PIZZA 64%
Diskussionsfragen:
  • Welcher Ansatz (von Grund auf vs. Fine-Tuning) liefert bessere Ergebnisse?
  • Wie gross ist der Unterschied zwischen Datensatz v1 und v2?
  • Kann Transfer Learning schlechte Datenqualität kompensieren?
  • Was ist wichtiger: mehr Daten, bessere Daten oder ein besseres Modell?
Lösung — erst öffnen, wenn alle Aufgaben erledigt sind
ResNet18 erwartete Genauigkeiten
Modell Erwartete Genauigkeit
ResNet18 v1+10 ~80–85%
ResNet18 v1+50 ~82–88%
ResNet18 v2+10 ~92–96%
ResNet18 v2+50 ~94–98%
Vergleich: TinyVGG vs. ResNet18
Modell TinyVGG (Aufgabe 1) ResNet18 (Aufgabe 2)
v1+10 (unsauber, wenig Training) ~65–70% ~80–85%
v1+50 (unsauber, mehr Training) ~65–75% ~82–88%
v2+10 (sauber, wenig Training) ~75–80% ~92–96%
v2+50 (sauber, mehr Training) ~80–90% ~94–98%
Erkenntnisse
Erkenntnis 1: ResNet18 v2+10 übertrifft TinyVGG v2+50

Bereits mit 10 Epochs und sauberen Daten erreicht ResNet18 (~92–96%) bessere Ergebnisse als TinyVGG mit 50 Epochs (~80–90%). Transfer Learning kompensiert fehlende Trainingszeit massiv.

Erkenntnis 2: Warum Transfer Learning so gut funktioniert
  • ResNet18 wurde auf ImageNet (1.2 Mio. Bilder, 1000 Klassen) vortrainiert
  • Es kennt bereits Kanten, Texturen, Formen und Farben
  • Beim Fine-Tuning muss es nur noch lernen: „Wie sehen Pizzen aus?“ — nicht: „Was ist ein Kreis?“
  • TinyVGG dagegen startet bei null und muss alles von Grund auf lernen
Erkenntnis 3: Das Flammkuchen-Problem gilt auch hier
  • Auch ResNet18 klassifiziert Flammkuchen als Pizza — mit noch höherer Confidence
  • Das bessere Modell macht den gleichen „Fehler“, weil es kein Datenproblem ist, sondern ein Klassenproblem
  • Lösung: „Flatbread/Flammkuchen“-Klasse oder Negativbeispiele im Trainingsset
Erkenntnis 4: Datenqualität bleibt entscheidend

Selbst mit unsauberen Daten schlägt ResNet18 das TinyVGG mit sauberen Daten. Aber der Sprung von v1 zu v2 ist bei beiden Modellen signifikant. Transfer Learning macht schlechte Daten nicht irrelevant — es verschiebt nur die Baseline nach oben.

Kernaussagen:
  • Transfer Learning übertrifft Training von Grund auf in allen Szenarien deutlich.
  • Die zwei wichtigsten Entscheidungen: (1) Datenqualität sicherstellen und (2) vortrainierte Modelle nutzen statt von Grund auf zu trainieren.