Startseite / Artikel / Vom Basismodell zum Chatmodell: SFT-Tuning eines indonesischen LLM mit 102M

Vom Basismodell zum Chatmodell: SFT-Tuning eines indonesischen LLM mit 102M

Wie ein indonesisches Basismodell mit 102M Parametern in zwei SFT-Stufen zum Chatmodell wurde: ChatML-Format, Längenfilter, Gradientenakkumulation und ein Identitäts-Patch.

1980 Wörter

Nach dem Pretraining von NovAI Base 102M war der nächste Schritt nicht das Hochskalieren, sondern dem Modell beizubringen, Anweisungen zu befolgen. Das Basismodell ist ein Decoder-only-Transformer mit 102 Millionen Parametern, von Grund auf mit rund 2 Milliarden indonesischen Tokens trainiert, und es funktioniert: Es schreibt Indonesisch, setzt einen Prompt fort und hat genug statistische Struktur aufgenommen, um zusammenhängenden Text zu erzeugen. Ein echter Chatbot ist es aber nicht. Stellt man ihm eine Frage, ist eine Antwort nicht garantiert, denn es wurde darauf trainiert, das nächste Token vorherzusagen, und nicht darauf, dieses Gesprächsmuster zu erkennen:

User → question
Assistant → answer

Größere GPUs für ein größeres Modell standen nicht zur Verfügung, also behielt das Experiment dasselbe Modell und änderte stattdessen Trainingsziel und Daten. Die Methode war Supervised Fine-Tuning (SFT).

Ein Basismodell ist noch kein Assistent

Diese Lücke übersieht man leicht, wenn man ChatGPT, Claude, Gemini oder ähnliche Tools nutzt, denn diese Modelle haben mehrere Trainingsstufen durchlaufen. Ein vortrainiertes Sprachmodell beginnt mit etwas viel Einfacherem: das nächste Token vorhersagen. Zum Beispiel:

Indonesia adalah negara ...

Es lernt, was wahrscheinlich folgt. Das unterscheidet sich grundlegend von einem Austausch wie diesem:

User:
Apa itu machine learning?
Assistant:
Machine learning adalah ...

Die zweite Form enthält ein Interaktionsmuster: eine Rolle, eine Anweisung und eine erwartete Antwort. SFT ist eine Technik, um einem vortrainierten Modell dieses Verhalten beizubringen. Die Pipeline für dieses Experiment sah so aus:

Indonesian Corpus
       ↓
Pretraining
       ↓
NovAI Base 102M
       ↓
Supervised Fine-Tuning
       ↓
NovAI Chat 102M

Bemerkenswert ist, dass die Architektur unverändert blieb. Die Parameterzahl lag weiter bei rund 102 Millionen. Geändert hat sich, was das Modell nachahmen sollte.

Ausgangspunkt

Das SFT begann beim vortrainierten Checkpoint NovAI Base 102M V3. Der Pretraining-Lauf umfasste 2.000.027.648 Tokens in 15.259 Schritten, und die Logs zeigen BF16 auf CUDA während des A100-Laufs. Am Ende war das Modell ein brauchbares Sprachmodell, brauchte jetzt aber völlig andere Daten. Mehr Webtext hätte nicht geholfen, Beispiele der gewünschten Antworten schon.

Der SFT-Datensatz

Der Datensatz durchlief mehrere Iterationen. Die zweite Version startete mit einem bestehenden Satz von 30.084 SFT-Beispielen und ergänzte 324 Beispiele zu Persona und Fakten-QA, insgesamt also 30.408. Diese Ergänzung war wichtig. Die neuen Beispiele waren keine allgemeinen Frage-Antwort-Paare. Einige wurden gezielt geschrieben, um Fakten über das Modell selbst festzulegen: seine Identität, seine Rolle und zugehörige Antworten. Die Daten wurden als Gespräche gespeichert, konzeptionell so:

User:
Apa itu machine learning?
Assistant:
Machine learning adalah ...

Das Modell sieht allerdings keine sauber formatierten Gespräche. Es sieht Tokens, also musste entschieden werden, wie Gespräche serialisiert werden.

Das Gesprächsformat beibringen

Verwendet wurde eine Struktur im ChatML-Stil mit expliziten Gesprächsgrenzen:

<|im_start|>
<|im_end|>

Ein Gespräch sieht dann ungefähr so aus:

<|im_start|>user
Apa itu machine learning?
<|im_end|>
<|im_start|>assistant
Machine learning adalah ...
<|im_end|>

Das sagt dem Modell, wo eine Nachricht beginnt, wo sie endet und welche Rolle sie erzeugt hat. Der Tokenizer wurde außerdem mit einem Chat-Template konfiguriert, sodass dieselbe Struktur im Code sowohl beim Training als auch bei der Inferenz erzeugt werden kann. Das wirkt wie ein kleines Implementierungsdetail, ist es aber nicht. Unterscheiden sich Trainings- und Inferenzformat, hat das Modell womöglich ein Gesprächsprotokoll gelernt und soll mit einem anderen arbeiten. Bei einem kleinen Modell hatte es Priorität, diese Schnittstelle einfach und deterministisch zu halten.

Lange Gespräche aussortieren

Als Nächstes ging es um die Sequenzlänge. Für diesen Lauf wurde das Maximum des Tokenizers auf 512 Tokens gesetzt. Das Notebook tokenisiert jedes gerenderte Gespräch ohne Kürzung und filtert Beispiele über diesem Limit heraus. Die Filterlogik war im Kern:

def filter_long_sequences(example):
    text = tokenizer.apply_chat_template(
        example["messages"],
        tokenize=False
    )
    tokens = tokenizer(
        text,
        truncation=False
    )    return len(tokens["input_ids"]) <= 512

Warum nicht einfach kürzen? Weil eine Kürzung genau den Teil abschneiden kann, auf den es ankommt. Schneidet man ein Trainingsbeispiel mitten in der Antwort des Assistenten ab, lernt das Modell an einer unvollständigen Antwort. Man entschied sich, zu lange Sequenzen zu verwerfen, statt still ihre Bedeutung zu verändern. Eine kleine technische Entscheidung, aber bei kleinen Modellen zählen solche Entscheidungen.

Der Trainingslauf

Trainiert wurde mit dem Hugging-Face-Stack: PyTorch, Transformers, TRL und dessen SFTTrainer. Der Trainer wurde direkt auf dem vortrainierten Modell und dem zusammengeführten SFT-Datensatz eingerichtet. Die effektive Batchgröße ergibt sich so:

16 × 2 = 32

Gradientenakkumulation kam zum Einsatz, weil es nicht das Ziel war, den ganzen effektiven Batch auf einmal in den GPU-Speicher zu bekommen. Das funktioniert so:

Batch 1
   ↓
forward / backward
Batch 2
   ↓
forward / backward
   ↓
optimizer update

Ergebnis ist ein effektiver Batch von 32, ohne dass die GPU alle 32 Beispiele gleichzeitig halten muss. Im Notebook wird max_steps aus Datensatzgröße und effektiver Batchgröße abgeleitet, sodass der Hauptlauf ungefähr einem Durchgang durch die Daten entspricht und nicht einer willkürlich hohen Zahl von Epochen.

Das erste Ergebnis war nicht das Ende

Nach der ersten SFT-Stufe gab es ein neues Modell, NovAI Chat 102M, das im Chatformat nutzbar war. Tests zeigten Verhalten, das so nicht ganz erwartet worden war. Das Modell gab Antworten, aber nicht immer sauber. In einem interaktiven Test übersprang es eine knappe Antwort und driftete in fremden Text ab, bis es schließlich Fragmente wie dieses reproduzierte:

<Kata-kata yang menggambarkan kehidupan seorang wanita...

und später ein unvollständiges Spezialtoken ausgab:

<|im_

Das war nicht beabsichtigt, und es zeigt, warum Experimente mit kleinen Modellen nützlich sind. Seltsame Ausgaben eines Frontier-Modells kann man leicht jemand anderem anlasten. Bei einem selbst gebauten Modell muss man herausfinden, welcher Teil der Pipeline sie verursacht hat. Der Datensatz? Das Chat-Template? Das Trainingsziel? Die Sampling-Einstellungen? Die begrenzte Kapazität des Modells? Zu wenige Beispiele für das erwartete Verhalten? Eine einzige Antwort gab es nicht unbedingt, aber ein konkretes Problem ließ sich angehen.

Das Identitätsproblem

Das Modell sollte eine konsistente Identität haben. Fragt jemand:

Siapa kamu?

sollte die Antwort vorhersehbar sein und vom Modell selbst handeln. Das klingt trivial, ist es aber nicht für ein Modell, das vor allem allgemeine Sprachmuster aufgesogen hat. Sind die Trainingsdaten voller verschiedener KI-Assistenten, Namen, Personas und Gesprächsstile, lernt ein kleines Modell leicht widersprüchliche Assoziationen.

Von Grund auf neu zu trainieren wäre übertrieben gewesen, also fiel die Lösung viel kleiner aus: ein eigener Identitätsdatensatz und eine weitere SFT-Stufe als Identitäts-Patch. Das Notebook kennzeichnet die Stufe mit der Meldung PATCH TRAINING IDENTITAS (LLM-NOVA) DIMULAI („Identitäts-Patch-Training gestartet“). Sie sollte kein neues Allgemeinwissen vermitteln. Das Ziel war eng: die Identität und das Verhalten festigen, die das Modell mit sich selbst verbinden soll.

Eine zweite SFT-Stufe

Die zweite Stufe startete beim bereits feinabgestimmten Chatmodell und nicht beim ursprünglichen Basismodell. Die Pipeline wurde zu:

NovAI Base 102M
       │
       │ General SFT
       ▼
NovAI Chat 102M
       │
       │ Identity SFT
       ▼
NovAI Chat 102M + Identity

Die Identitätsstufe nutzte bewusst eine vorsichtigere Konfiguration. Allgemeines SFT versucht, das Gesprächsverhalten des Modells auf ganzer Linie zu verändern. Die Identitätsstufe ist viel enger, Ziel war eine kleine Verhaltenskorrektur und nicht noch eine aggressive Überarbeitung.

Warum nicht in den ersten Lauf integrieren?

Naheliegend ist die Frage, warum die Identitätsbeispiele nicht einfach in den Hauptdatensatz kamen und alles zusammen trainiert wurde. Dafür gibt es vernünftige Argumente. Getrennte Stufen erlauben es aber, den Effekt zu isolieren. Statt so:

30K+ examples
      ↓
one opaque training run

kann man über zwei Stufen nachdenken:

General instruction data
        ↓
Chat behavior
thenIdentity examples
        ↓
Identity behavior

Die Trennung der Stufen macht das Experiment leichter lesbar. Sie spiegelt auch eine Lehre wider, die bei kleineren Modellen immer mehr Gewicht bekommt: Nicht jedes Problem braucht einen weiteren großen Trainingslauf. Manchmal ist ein gezielter Eingriff die richtige Antwort.

Die Parameterzahl hat sich nie bewegt

Zählen Sie die Parameter bei jedem Schritt. Vor SFT: 102M. Nach SFT: 102M. Nach dem Identitätsdurchlauf: immer noch 102M. Die Architektur wurde nicht leistungsfähiger, und es tauchten keine Milliarden Parameter auf. Geändert haben sich die Gewichte und das, worauf sie trainiert wurden. Das Pretraining optimierte auf Sprachmodellierung. SFT optimierte auf das Nachahmen von Beispielen, die Anweisungen befolgen. Die Identitätsstufe schob das Modell dann zu einem bestimmten Verhaltensmuster.

Was das Experiment zeigt

Man sollte das Ergebnis nicht überinterpretieren. Ein 102M-Modell kann nicht mit Frontier-Modellen der GPT-Klasse mithalten, und nichts hier behauptet etwas anderes. Es beweist auch nicht, dass SFT das Schlussfolgern eines kleinen Modells magisch verbessert, denn das tut es nicht. Das Ergebnis ist praktischer: Ein vortrainiertes indonesisches Sprachmodell kann eine weitere Trainingsstufe durchlaufen, die ihm ausdrücklich die Form eines Gesprächs beibringt, wie man auf eine Anweisung antwortet, wie eine gute Assistentenantwort aussieht und, über gezielte Beispiele, wie es sich selbst beschreibt. Das ist eine ganz andere Fähigkeit als bloße Next-Token-Prediction.

SFT hat Grenzen

SFT leistet viel, ist aber nicht die letzte Stufe. Allein beseitigt es keine Halluzinationen, garantiert keine sachliche Richtigkeit, schafft keine unbegrenzte Denkfähigkeit und gibt dem Modell keinen Zugang zu Informationen außerhalb seiner Parameter. Und es bringt nicht bei, welche Antwort Menschen bevorzugen, wenn mehrere möglich sind. Diese Lücken verlangen andere Techniken:

Pretraining
     ↓
SFT
     ↓
Preference Optimization
     ↓
RAG / External Knowledge
     ↓
Tools / Agents

Jede Schicht behandelt eine andere Einschränkung, und deshalb sieht der Bau eines LLM nicht mehr wie ein einzelner Trainingslauf aus, sondern wie eine Pipeline.

Warum kleine Modelle interessant sind

Interessant an dieser Arbeit ist nicht, dass ein 102M-Modell trainiert wurde. Interessant ist, dass sich die ganze Pipeline untersuchen lässt, vom Korpus über den Tokenizer und weiter:

Corpus
  ↓
Tokenizer
  ↓
Architecture
  ↓
Pretraining
  ↓
Checkpoint
  ↓
SFT Dataset
  ↓
Chat Template
  ↓
SFT
  ↓
Identity Patch
  ↓
Inference

Wenn etwas schiefgeht, kann man zurückgehen und die verantwortliche Schicht untersuchen, was etwas ganz anderes ist, als eine API aufzurufen. Genau da zahlt sich der Bau von Grund auf aus.

Erst bauen, dann verbessern

Die Serie begann mit der Frage, ob Indonesien ein eigenes Foundation Model bauen kann. Ein 102M-Modell liegt weit unter Frontier-Maßstab, beantwortet aber eine kleinere Version dieser Frage: Ein kleines Sprachmodell lässt sich tatsächlich lokal bauen und trainieren. Die nächste Frage war, ob man daraus etwas machen kann, das sich wie ein Assistent verhält. SFT bot einen Weg, und das Identitätsexperiment fügte eine Lehre hinzu: Einem Modell, das sprechen kann, muss man noch beibringen, wie es sich verhalten soll.

Was noch offen ist

Einiges bleibt zu testen:

  • Würde ein stärkerer indonesischer Instruktionsdatensatz die Ergebnisse spürbar heben?
  • Zählt die Qualität der Daten mehr als ihre Menge, und wie viel mehr?
  • Würde Preference Optimization die Antworten schärfen?
  • Könnte ein enger Spezialist für eine einzige Domäne in dieser Größe unerwartet nützlich sein, statt eines Generalisten, der alles wissen will?
  • Wo liegt die Obergrenze für ein kleines indonesisches Modell, wenn Daten, Ziel und Evaluation ganz auf indonesische Anwendungsfälle zugeschnitten sind?

Diese Antworten hat noch niemand, deshalb geht die Arbeit weiter. Nichts hier behauptet, dass ein Modell dieser Größe Frontier-KI verdrängen wird. Ziel ist zu verstehen, was tatsächlich passiert, wenn man die ganze Pipeline von Hand baut, Stufe für Stufe. Das Pretraining war Meilenstein eins, SFT Meilenstein zwei.