Ein einfaches LLM trainieren: Das Wikibert-Projekt

Ein einfaches LLM trainieren: Das Wikibert-Projekt

Es war ein Sonntagnachmittag wie jeder andere. Die Welt draußen war still, und ich saß mit einer Tasse Kaffee vor meinem Laptop, als mich eine Frage packte: Wie schwer kann es schon sein, ein eigenes Sprachmodell zu trainieren? So entstand Wikibert – ein persönliches Experiment, das sich von einer spontanen Idee zu einem greifbaren Ergebnis entwickelte.

🧠 Der Gedanke hinter Wikibert

Sprachmodelle wie GPT oder BERT scheinen auf den ersten Blick hochkomplex und unzugänglich. Doch der Reiz lag gerade darin, die Prozesse hinter diesen Technologien zu entschlüsseln – zumindest in einer vereinfachten Form. Ziel war es, ein Modell zu bauen, das englische Sätze generiert, vielleicht nicht perfekt, aber spannend genug, um sich selbst und andere zu beeindrucken.

🗞️ Die Datenbeschaffung: Wikipedia als Wissensfundament

Das Training eines Sprachmodells beginnt mit einer essenziellen Grundlage: den Daten. Doch wie gelangt man an eine geeignete Menge davon? In meinem Fall fiel die Wahl auf Wikipedia, eine der umfassendsten freien Textquellen der Welt – und damit perfekt für ein erstes Experiment geeignet.

Warum Wikipedia?

Wikipedia bietet nicht nur eine Fülle von frei zugänglichem Text, sondern auch strukturierte Inhalte, die durch Links thematisch vernetzt sind. Dadurch lassen sich vielfältige Datensätze für verschiedene Experimente erstellen – von reinem Text bis hin zu semantischen Bezügen zwischen Themen. Für ein Einstiegsprojekt wie Wikibert war diese Quelle daher ideal:

  • Freier Zugang: Wikipedia-Daten sind öffentlich verfügbar und können problemlos heruntergeladen werden.

  • Vielfältige Themen: Die Artikel decken eine riesige Bandbreite an Themen ab, von Technologie über Geschichte bis hin zu Popkultur.

  • Einheitlicher Stil: Wikipedia folgt gewissen Stilrichtlinien, was die Vorverarbeitung erleichtert.

Interessanterweise erinnert die Datenbasis an das bekannte BERT-Modell, das ebenfalls Wikipedia-Texte für sein Training nutzt. Dennoch sind Wikibert und BERT grundverschieden: Während BERT ein hochentwickeltes Modell mit Transformer-Architektur ist, bleibt Wikibert ein bescheidenes Experiment. Der Name ist eher ein Zufallstreffer als eine Hommage.

Daten abrufen: Vom Chaos zur Ordnung

Um Wikipedia-Artikel zu sammeln, schrieb ich ein eigenes Skript, das Artikel samt ihrer verlinkten Seiten abrufen und strukturiert abspeichern kann. Klingt einfach? In der Theorie schon. Doch es gab einige Stolpersteine, die zu beachten waren:

  1. Saubere Dateinamen: Klingt nach einer Nebensache, bis dein Skript plötzlich über einen Artikel über C++ stolpert und ihn nicht speichern will.
  • Datenstruktur: Die gesammelten Artikel mussten sinnvoll organisiert werden, um später leicht darauf zugreifen zu können.

Hier ein Ausschnitt des Codes, der diesen Prozess illustriert:

import wikipediaapi
import os
import re

# Funktion, um Wikipedia-Seiten abzurufen
def get_wiki_page(title):
    wiki_wiki = wikipediaapi.Wikipedia("en")  # Englische Wikipedia verwenden
    page = wiki_wiki.page(title)
    return page

# Funktion, um ungültige Zeichen aus Dateinamen zu entfernen
def sanitize_filename(filename):
    return re.sub(r'[<>:"/\\|?*]', "_", filename)

# Abruf und Speicherung der Inhalte
def save_wiki_page(title):
    page = get_wiki_page(title)
    sanitized_title = sanitize_filename(title)
    with open(f"data/{sanitized_title}.txt", "w", encoding="utf-8") as f:
        f.write(page.text)

# Beispielaufruf
if not os.path.exists("data"):
    os.makedirs("data")

save_wiki_page("Python (programming language)")

Dieses Skript verwendet die wikipediaapi-Bibliothek, um Texte aus Wikipedia abzurufen. Dabei sorgt die Funktion sanitize_filename dafür, dass problematische Zeichen wie : oder * durch Unterstriche ersetzt werden. Es fühlte sich fast so an, als würde ich ein kleines Netz aufspannen, um die verstreuten Informationen von Wikipedia zu sammeln.

Querverweise nutzen: Verlinkte Artikel

Wikipedia-Artikel stehen selten isoliert da – sie enthalten eine Vielzahl an Verlinkungen zu verwandten Themen. Diese Links waren wie kleine Schatztruhen voller neuer Daten. Deshalb erweiterte ich das Skript, sodass es nicht nur den Hauptartikel, sondern auch verlinkte Seiten (bis zu zwei Ebenen tief) abrufen konnte:

# Funktion, um Artikel rekursiv zu sammeln
def gather_pages_recursively(page, depth=0, max_depth=2):
    if depth > max_depth:  # Begrenzung der Rekursionstiefe
        return
    save_wiki_page(page.title)
    for link in page.links:
        gather_pages_recursively(page.links[link], depth + 1)

Nach Abschluss des Skripts hatte ich eine solide Sammlung von Wikipedia-Texten – die perfekte Grundlage für das Modelltraining.

💻 Das Training des Modells

Mit den Daten in der Hand ging es ans Eingemachte: der eigentliche Trainingsprozess. Dafür entschied ich mich, ein RNN (Recurrent Neural Network) mit GRU-Zellen zu bauen. Warum? Weil GRUs einfacher als LSTMs sind und für ein Projekt wie dieses völlig ausreichen.

Schritt 1: Vorbereitung der Textdaten

Vor dem Training mussten die Daten in eine geeignete Form gebracht werden:

# Textdaten laden 
file_path = './all_articles.txt' 
text = open(file_path, 'r', encoding='utf-8').read() 

# Alles in Kleinbuchstaben umwandeln 
text = text.lower() 

# Einzigartige Zeichen im Text sammeln 
vocab = sorted(set(text)) 

# Zeichen-zu-Index-Mapping erstellen 
char2idx = {char: idx for idx, char in enumerate(vocab)} 
idx2char = np.array(vocab)

# Text in Zahlen umwandeln 
text_as_int = np.array([char2idx[char] for char in text])

Hier entsteht aus normalem Text eine Zahlenfolge, die das Modell später verarbeiten kann.

Schritt 2: Das Modell aufsetzen

Das Herzstück des Projekts ist das Modell selbst. Es umfasst:

  • Eine Embedding-Schicht, die Zeichen in dichte Vektoren umwandelt.

  • Eine GRU-Schicht, die Sequenzen analysiert und sich an vorherige Eingaben erinnert.

  • Eine Dense-Schicht, die die Wahrscheinlichkeiten für jedes Zeichen vorhersagt.

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=256),
    tf.keras.layers.GRU(units=1024, return_sequences=True, stateful=True),
    tf.keras.layers.Dense(units=vocab_size)
])

Schritt 3: Training starten

Der Trainingsprozess selbst dauerte etwa eine halbe bis eine Stunde und speicherte regelmäßig Modell-Checkpoints.

# Training starten
model.fit(data, epochs=20, callbacks=[checkpoint_callback])

🔍 Das Ergebnis

Nach 20 Trainingsdurchläufen war es endlich soweit: Ich ließ das Modell einen Text mit dem Anfang "Windows 8 was" generieren. Die Ausgabe war kreativ, wenn auch ein wenig skurril:

"windows 8 was released in 1987 for development environments."

Natürlich war es nicht perfekt. Doch es war kohärent und – für ein Sonntagsprojekt – eine Leistung, die sich sehen lassen konnte.

🌟 Fazit: Ein Wochenende, ein Modell, eine Erfahrung

Wikibert hat mir gezeigt, wie zugänglich die Welt der Sprachmodelle mittlerweile ist. Mit ein wenig Neugier und Zeit kann man erstaunliche Ergebnisse erzielen – und vor allem viel lernen. Für alle, die sich für KI interessieren, kann ich nur empfehlen: Probiert es aus! Es ist einfacher, als ihr denkt.


📎Anhang

  1. GitHub Projekt: trbndev/wikibert: 👨🏻🏫🚧 Experiment: Training a Neural Network with Wikipedia Articles

  2. Text Generation Notebook: GoogleCloudPlatform/asl-ml-immersion: This repos contains notebooks for the Advanced Solutions Lab: ML Immersion