Für die meisten Leute, mit denen ich interagiere, bin ich die meiste Zeit nur ein weiteres textbasiertes Programm. Wenn Input und Output so einfach sind, könnte ich dann durch das Modell ersetzt werden? Damit das funktioniert, müsste das Modell nicht nur meinen Schreibstil verstehen, sondern auch viel über mich wissen. Die beste Quelle dafür ist mein Telegram- Messenger, da ich ihn täglich benutze und er in Form von Chatverläufen fast alles über meine Gedanken und Handlungen enthält.
Der direkteste Ansatz wäre, alle meine Nachrichten zu extrahieren, sie in den Kontext von ChatGPT zu laden und es anzuweisen, diese Informationen zu verwenden, um meinen Stil beim Antworten auf neue Nachrichten nachzuahmen. Dieser Ansatz ist jedoch durch die Größe des Kontextfensters begrenzt, sodass ich Nachrichten vorverarbeiten muss, um wichtige Punkte zu extrahieren. Da ich diesen Aufwand vermeiden möchte, könnte vielleicht Retrieval Augmented Generation (RAG) verwendet werden, um bei Bedarf die erforderlichen Informationen abzurufen. Meiner Erfahrung nach erfordert das Abrufen aus unterschiedlichen Daten wie Chatsitzungen jedoch normalerweise eine überwachte Feinabstimmung des Abrufmodells, und ich bin nicht scharf darauf, einen solchen Datensatz zu erstellen. Daher scheint die Feinabstimmung die beste Option zu sein. Sie ist aus mehreren Gründen ideal: Sie sollte meinen Schreibstil erfassen und potenziell Wissen aus all meinen Nachrichten sammeln, ohne dass ich das Wichtige auswählen muss.
OpenAI bietet Feinabstimmungsmöglichkeiten , aber da ich meine privaten Nachrichten verwenden werde, möchte ich keine Feinabstimmungsdienste von Drittanbietern verwenden. Also muss ich ein Basismodell auswählen. Laut der Hugging Face Open LLM Leaderboard ist Mistral 7B eines der besten kleineren Modelle (≤13B Parameter). Es übertrifft sogar Llama 2 13B . Nun ist die Frage, ob LoRA ausreicht oder ob eine vollständige Feinabstimmung notwendig ist. Verschiedene Vergleiche [1] [2] legen nahe, dass LoRA etwas schlechter als eine vollständige Feinabstimmung, aber meistens immer noch gut ist. Für spezielle Aufgaben wie meine (russische Sprache + Chat) fand ich jedoch ein Dokument , in dem Forscher eine Feinabstimmung der Llama-Anweisungen auf Chinesisch durchführten, die von ähnlicher Komplexität wie mein Ziel war. Sie fanden heraus, dass eine LoRA-basierte Abstimmung eines Basismodells ohne vorherige Abstimmung der Anweisungen weniger effektiv ist als eine vollständige Feinabstimmung. Dennoch kann eine LoRA-basierte Abstimmung eines Modells, das bereits für Anweisungen feinabgestimmt ist, vergleichbare Ergebnisse liefern. In meinem Fall bedeutet dies entweder eine vollständige Feinabstimmung eines Basismodells oder LoRA auf einem Modell, das bereits für Chats auf Russisch feinabgestimmt ist. Da ich kein für Chats auf Russisch feinabgestimmtes Modell finden konnte, werde ich LoRA auf einem für Chats auf Englisch feinabgestimmten Modell ausprobieren, wie dem feinabgestimmten Mistral-Modell Dolphin .
Der Plan ist also:
Ein einzigartiger Aspekt beim Versenden von Nachrichten in Apps wie Telegram im Vergleich zu E-Mails ist der Gesprächsfluss. Nachrichten wechseln normalerweise nicht einzeln zwischen Ihnen und Ihrem Kontakt. Stattdessen senden Sie oft mehrere Nachrichten hintereinander, gefolgt von mehreren Antworten der anderen Person. Diese Nachrichten sind im Allgemeinen auch kurz. Ich wollte diesen natürlichen Gesprächsstil in meinen Daten beibehalten.
Telegram bietet eine integrierte Funktion zum Exportieren aller Chats in JSON. Nach einigem Filtern und Gruppieren von Nachrichten in Sitzungen habe ich Daten aus den letzten fünf Jahren der Nutzung von Telegram zusammengestellt. Dies ergab 15.789 Sitzungen aus 466 Chats mit einer durchschnittlichen Sitzungslänge von 8,51 Nachrichten. Zur Strukturierung der Daten habe ich das ChatML- Prompt-Format gewählt. Hier ist eine Beispielsitzung (übersetzt aus dem Russischen):
<|im_start|>John Smith
>>> verdammt, ich komme nicht um das Zeitlimit von 135 herum
>>> versuche alles super optimal zu machen, aber ohne Erfolg<|im_end|>
<|im_start|>Alexander Smirnov
>>> ja das gleiche
>>> verfolgen Sie immer noch die gleiche Idee?<|im_end|>
<|im_start|>John Smith
>>> keine Ahnung, ich glaube, wir sind einer Meinung
>>> wie du gesagt hast
>>> mit der umgekehrten Zeichenfolge einen Versuch starten und versuchen, dort etwas zu finden
>>> scheint echt Mist zu sein, weil die Z-Funktion alles ruiniert……………………<|im_end|>
<|im_start|>Alexander Smirnov
>>> verstehe nicht, was z hier zu sagen hat<|im_end|>
<|im_start|>John Smith
>>> weiß nicht, es scheint, als würde ich sowieso alles iterativ machen, aber ja, ich muss ein paar Strings umkehren, um die Z-Funktion zu erstellen
>>> und es ist nur eine zufällige Lösung
>>> aus Diskussionen<|im_end|>
<|im_start|>Alexander Smirnov
>>> verstanden<|im_end|>
Mein Datenkollektor stellt sicher, dass der Verlust nur auf Grundlage der Antwort einer Person berechnet wird. Die Vorhersage, wer als nächstes sprechen wird, ist relativ einfach, und wir möchten nicht, dass sich das Modell darauf konzentriert, dies zu lernen. Daher werden Teile des Gesprächs, in denen der Verlust berechnet wird, fett hervorgehoben.
Möglicherweise fällt Ihnen auf, dass nicht nur meine Antworten, sondern auch die anderer zur Berechnung des Verlusts herangezogen werden. Das ist Absicht. Auf diese Weise kann das Modell nicht nur mich, sondern auch meine häufigen Gesprächspartner in die Rolle schlüpfen!
Ich werde Modelle testen, indem ich Chats auf zwei Arten führe. Zuerst wird das Modell so tun, als wäre es ich, und ich werde mit mir selbst aus der Perspektive meiner verschiedenen Freunde chatten. Dann werde ich als ich selbst chatten, während das Modell als mein Freund auftritt. Mein Gesprächsstarter werden immer die gleichen 2 Nachrichten sein: „Hey“ und „Was geht?“ (auf Russisch „прив“ und „как дела?“). Generierte Phrasen und Personen, die das Modell spielt, werden hervorgehoben . Zum Testen werde ich oobabooga/text-generation-webui verwenden.
Zu Beginn möchte ich untersuchen, wie das auf generische Konversation abgestimmte Mistral-Modell diese Aufgabe bewältigt, ohne dass ich vorher eine Schulung dazu benötige.
Freund 1 gegen Alexander Smirnov
Alexander Smirnov vs. Freund 1
Ok, es ist in der Lage, zusammenhängende Sätze zu bilden. Das auffälligste Problem ist sein mangelndes Bewusstsein für den Kontext der Gespräche, was zu nichtssagenden und generischen Antworten führt. Den Nachrichten fehlte jeder ausgeprägte Stil und sie wirkten recht einfach. Ein weiteres Problem ist, dass das Modell nur dürftig Russisch spricht. Das ist zu erwarten, da das Modell zu klein ist, um gut auf andere Sprachen als die Hauptsprache Englisch zu verallgemeinern. Darüber hinaus neigte das Modell dazu, übermäßig proaktiv zu sein und fast jeden Satz mit einer Frage zu beenden, was nicht der Art und Weise entspricht, wie echte Menschen normalerweise in Messengern kommunizieren.
Versuchen wir, all diese Probleme zu beheben!
LoRA bietet einen Ansatz mit geringem Aufwand sowohl hinsichtlich der Trainingspipeline als auch der Hardwareanforderungen. Es trainiert etwa 1 % der Gesamtgewichte. Ich habe eine Sequenzlänge von 1024 und eine Batchgröße von 8 gewählt. Das Training, das 20 GB VRAM auf einer RTX 3090 verbrauchte, dauerte drei Epochen und 5,5 Stunden. Dafür habe ich vast.ai verwendet, wo die GPU-Kosten 0,362 USD pro Stunde betrugen, also insgesamt 2 USD für das gesamte Training, ohne die Zeit für Experimente und Fehlerbehebungen.
Hier sind die Ergebnisse:
Freund 1 gegen Alexander Smirnov
Freund 2 gegen Alexander Smirnov
Alexander Smirnov vs. Freund 1
Alexander Smirnov gegen Freund 2
Das ist viel besser. Es erfasst definitiv den Stil der Person, in deren Namen es antwortet. Es identifiziert auch die am häufigsten besprochenen Themen zwischen bestimmten Personenpaaren. Bei Freund 2 liegt der Fokus beispielsweise eindeutig mehr auf der Arbeit. Die Grammatik ist jedoch immer noch falsch und der Kontext des Gesprächs geht schnell verloren. Ich bin ziemlich zuversichtlich, dass LoRA auf Englisch mit angemessener Qualität funktionieren würde und eine vollständige Feinabstimmung möglicherweise nicht erforderlich ist. Da Russisch jedoch nicht die Muttersprache des Modells ist, versuchen wir eine vollständige Feinabstimmung.
Eine vollständige Feinabstimmung ist aufgrund der Notwendigkeit eines Multi-GPU-Trainings anspruchsvoller. Beliebte Methoden sind entweder ZeRO & DeepSpeed [3] oder FSDP [4] , wobei FSDP im Wesentlichen ein ZeRO3 [5] ist. Ich habe mich für FSDP entschieden.
Während der Implementierung der Trainingspipeline habe ich mich auf den Feinabstimmungscode „Stanford Alpaca“ und den Feinabstimmungscode „Mistral“ von Anton Bacaj bezogen.
Die Verwendung eines halbpräzisen FSDP-Full-Shards mit einer Sequenzlänge von 1024 und einer Mikro-Batchgröße von 2 erforderte 63 GB VRAM auf jeder der acht A100 80 GB GPUs. Das Training, das drei Epochen dauerte, dauerte nur 20 Minuten. Die Gesamtkosten für die VM betrugen 8,88 USD pro Stunde, also 3 USD, ohne die Zeit für Experimente und Fehlerbehebungen.
Gespräche:
Freund 1 gegen Alexander Smirnov
Freund 2 gegen Alexander Smirnov
Alexander Smirnov vs. Freund 1
Alexander Smirnov gegen Freund 2
Die Gespräche sind interessanter und spannender geworden, obwohl immer noch die Gefahr besteht, dass der Kontext verloren geht. Die Leistung in der russischen Sprache hat sich verbessert, aber es treten immer noch Fehler auf. Ich glaube, dass es vor der Feinabstimmung für eine bestimmte Aufgabe mit begrenzten Daten wie meiner von Vorteil wäre, das Modell zunächst unbeaufsichtigt anhand eines großen Korpus russischer Texte zu optimieren. Darüber hinaus könnte die Einbeziehung der Namen gängiger Gesprächspartner als separate Token die Qualität verbessern.
Ich würde nicht sagen, dass es sich als wesentlich besser als LoRA herausgestellt hat. Es könnte effektiver sein, sich ausschließlich auf eine einzelne Person zu konzentrieren und den Verlust nur auf Grundlage meiner Antworten (oder der Antworten einer anderen Person) zu berechnen, anstatt zu versuchen, etwas über jeden einzelnen Gesprächspartner zu erfahren.
Natürlich musste ich bei den Ergebnissen Rosinen herauspicken, nicht weil die meisten Antworten des Modells unzureichend waren, sondern weil es sich bei vielen um einfache Antworten wie „Ich ruf dich später an“, „Beschäftigt“ und „Okay“ handelte, die in Gesprächen natürlich häufig vorkommen. Trotzdem ist klar, dass das Modell den Stil der Person, die es imitiert, hervorragend nachahmt. Es erfasst auch die häufig besprochenen Themen zwischen zwei Personen. In Gesprächen fehlt es ihm jedoch erheblich an Kontext. Auf Fragen wie „Jo, und?“ oder „Was hast du am Wochenende vor?“ zu antworten, ist ohne den vollständigen Kontext eine Herausforderung. Vielleicht wäre die Verwendung eines Systems wie Rewind von Vorteil, das alles erfasst, was der Benutzer am Computer tut.
Code für dieses Projekt sowie Anweisungen, wie Sie es selbst in Ihrem eigenen Telegram-Dump replizieren können, finden Sie in meinem GitHub-Repo . Trainingsprotokolle können auf WandB abgerufen werden.
Titelbild von Christian Wiediger auf Unsplash