Direkt zum Inhalt
HeimAnleitungenKünstliche Intelligenz (KI)

Ein einführender Leitfaden zur Feinabstimmung von LLMs

Die Feinabstimmung großer Sprachmodelle (Large Language Models, LLMs) hat die Verarbeitung natürlicher Sprache (Natural Language Processing, NLP) revolutioniert und bietet nie dagewesene Möglichkeiten für Aufgaben wie Sprachübersetzung, Stimmungsanalyse und Texterstellung. Dieser transformative Ansatz nutzt vortrainierte Modelle wie GPT-2 und verbessert ihre Leistung in bestimmten Bereichen durch den Prozess der Feinabstimmung.
Aktualisierte 11. Sept. 2024  · 12 Min. lesen

In den letzten anderthalb Jahren hat sich der Bereich der Verarbeitung natürlicher Sprache (NLP) durch die Popularisierung von Large Language Models (LLMs) stark verändert. Die natürlichen Sprachkenntnisse, die diese Modelle mitbringen, haben Anwendungen ermöglicht, die noch vor ein paar Jahren unmöglich schienen.

LLMs verschieben die Grenzen dessen, was bisher als machbar galt, mit Fähigkeiten, die von der Sprachübersetzung bis hin zur Stimmungsanalyse und Texterstellung reichen.

Wir alle wissen jedoch, dass die Ausbildung solcher Modelle zeitaufwändig und teuer ist. Aus diesem Grund ist die Feinabstimmung großer Sprachmodelle wichtig, um diese fortschrittlichen Algorithmen auf bestimmte Aufgaben oder Bereiche zuzuschneiden.

Dieser Prozess verbessert die Leistung des Modells bei speziellen Aufgaben und erweitert seine Anwendbarkeit in verschiedenen Bereichen erheblich. Das bedeutet, dass wir die Natural Language Processing-Kapazitäten von vortrainierten und Open-Source-LLMs nutzen und sie weiter trainieren können, um unsere spezifischen Aufgaben zu erfüllen.

Heute erforschen wir das Wesen von vortrainierten Sprachmodellen und gehen näher auf den Feinabstimmungsprozess ein.

Gehen wir also durch die praktischen Schritte zur Feinabstimmung eines Modells wie GPT-2 mit Hugging Face.

Verstehen, wie vortrainierte Sprachmodelle funktionieren

Das Sprachmodell ist eine Art maschineller Lernalgorithmus, der das nächste Wort in einem Satz anhand der vorangegangenen Segmente vorhersagt. Sie basiert auf der Transformers-Architektur, die in unserem Artikel über die Funktionsweise von Transformers ausführlich erklärt wird .

Vorgefertigte Sprachmodelle wie GPT (Generative Pre-trained Transformer) werden auf großen Mengen von Textdaten trainiert. Dies ermöglicht es den LLMs, die grundlegenden Prinzipien der Verwendung von Wörtern und ihrer Anordnung in der natürlichen Sprache zu verstehen.

Bild vom Autor. LLM Input und Output.

Bild vom Autor. LLM-Eingang und -Ausgang.

Das Wichtigste ist, dass diese Modelle nicht nur gut darin sind, natürliche Sprache zu verstehen, sondern auch in der Lage sind, auf der Grundlage der Eingaben, die sie erhalten, menschenähnlichen Text zu erzeugen.

Und was ist das Beste daran?

Diese Modelle sind bereits über APIs für die breite Masse zugänglich. Wenn du lernen willst, wie du die leistungsfähigsten LLMs von OpenAI nutzen kannst, kannst du das mit diesem Spickzettel über die API von OpenAI tun.

Was ist Feinabstimmung und warum ist sie wichtig?

Bei der Feinabstimmung wird ein bereits trainiertes Modell auf einem domänenspezifischen Datensatz weiter trainiert.

Die meisten LLM-Modelle haben heute eine sehr gute globale Leistung, versagen aber bei spezifischen aufgabenorientierten Problemen. Der Feinabstimmungsprozess bietet erhebliche Vorteile, wie z.B. einen geringeren Rechenaufwand und die Möglichkeit, modernste Modelle zu nutzen, ohne sie von Grund auf neu erstellen zu müssen.

Transformers ermöglichen den Zugriff auf eine umfangreiche Sammlung von vortrainierten Modellen, die für verschiedene Aufgaben geeignet sind. Die Feinabstimmung dieser Modelle ist ein entscheidender Schritt, um die Fähigkeit des Modells zu verbessern, bestimmte Aufgaben wie Stimmungsanalyse, Fragenbeantwortung oder Dokumentenzusammenfassung mit höherer Genauigkeit durchzuführen.

Bild vom Autor. Visualisierung des Fine-Tuning-Prozesses.

Bild vom Autor. Visualisierung des Fine-Tuning-Prozesses.

Durch die Feinabstimmung wird das Modell so angepasst, dass es für bestimmte Aufgaben besser geeignet ist, wodurch es in der Praxis effektiver und vielseitiger eingesetzt werden kann. Dieser Prozess ist wichtig, um ein bestehendes Modell auf eine bestimmte Aufgabe oder einen bestimmten Bereich zuzuschneiden.

Ob du eine Feinabstimmung vornehmen solltest, hängt von deinen Zielen ab, die in der Regel von dem jeweiligen Bereich oder der Aufgabe abhängen.

Die verschiedenen Arten der Feinabstimmung

Das Feintuning kann auf verschiedene Arten angegangen werden, die vor allem von den Schwerpunkten und spezifischen Zielen abhängen.

Überwachte Feinabstimmung

Der einfachste und gängigste Ansatz für die Feinabstimmung. Das Modell wird dann auf einem gelabelten Datensatz trainiert, der für die jeweilige Aufgabe spezifisch ist, z. B. Textklassifizierung oder Named-Entity-Erkennung.

Wir würden unser Modell zum Beispiel auf einem Datensatz trainieren, der Textproben enthält, die für die Sentiment-Analyse mit den entsprechenden Gefühlen gekennzeichnet sind.

Lernen mit wenigen Schüssen

Es gibt einige Fälle, in denen es unpraktisch ist, einen großen markierten Datensatz zu sammeln. Das Few-Shot-Lernen versucht, dieses Problem zu lösen, indem es zu Beginn der Eingabeaufforderungen einige Beispiele (oder Aufnahmen) der geforderten Aufgabe liefert. Das hilft dem Modell, einen besseren Kontext für die Aufgabe zu haben, ohne dass ein umfangreicher Feinabstimmungsprozess erforderlich ist.

Lernen übertragen

Obwohl alle Feinabstimmungstechniken eine Form des Transferlernens sind, zielt diese Kategorie speziell darauf ab, dass ein Modell eine andere Aufgabe ausführen kann als die, für die es ursprünglich trainiert wurde. Die Hauptidee ist, das Wissen, das das Modell aus einem großen, allgemeinen Datensatz gewonnen hat, zu nutzen und auf eine spezifischere oder verwandte Aufgabe anzuwenden.

Domänenspezifische Feinabstimmung

Bei dieser Art der Feinabstimmung wird versucht, das Modell so anzupassen, dass es Texte versteht und erzeugt, die für einen bestimmten Bereich oder eine bestimmte Branche spezifisch sind. Das Modell wird anhand eines Datensatzes mit Texten aus der Zieldomäne feinabgestimmt, um seinen Kontext und sein Wissen über domänenspezifische Aufgaben zu verbessern.

Um zum Beispiel einen Chatbot für eine medizinische App zu entwickeln, würde das Modell mit Krankenakten trainiert werden, um seine Sprachverständnisfähigkeiten an den Gesundheitsbereich anzupassen.

Eine Schritt-für-Schritt-Anleitung zum Feinschliff eines LLM

Führe den Code aus diesem Tutorial online aus und bearbeite ihn

Code ausführen

Wir wissen bereits, dass das Feintuning ein Prozess ist, bei dem man ein bereits trainiertes Modell nimmt und seine Parameter aktualisiert, indem man es auf einem für deine Aufgabe spezifischen Datensatz trainiert. Veranschaulichen wir uns dieses Konzept also anhand eines echten Modells.

Stell dir vor, wir arbeiten mit GPT-2, aber wir stellen fest, dass es ziemlich schlecht darin ist, die Stimmung von Tweets zu erkennen.

Eine Frage, die sich natürlich aufdrängt, ist: Können wir etwas tun, um seine Leistung zu verbessern?

Wir können uns die Feinabstimmung zunutze machen, indem wir unser vortrainiertes GPT-2-Modell aus dem Hugging Face-Modell mit einem Datensatz trainieren, der Tweets und die dazugehörigen Stimmungen enthält, damit sich die Leistung verbessert. Hier ist ein einfaches Beispiel für die Feinabstimmung eines Modells zur Sequenzklassifizierung:

Schritt 1: Wähle ein vortrainiertes Modell und einen Datensatz

Für die Feinabstimmung eines Modells müssen wir immer ein bereits trainiertes Modell im Kopf haben. In unserem Fall werden wir eine einfache Feinabstimmung mit GPT-2 durchführen.

Screenshot des Hugging Face Datasets Hub. Auswahl des GPT2-Modells von OpenAI.

Screenshot des Hugging Face Datasets Hub. Wähle das GPT2-Modell von OpenAI.

Denke immer daran, eine für deine Aufgabe geeignete Modellarchitektur auszuwählen.

Schritt 2: Lade die zu verwendenden Daten

Jetzt, wo wir unser Modell haben, brauchen wir Daten von guter Qualität, mit denen wir arbeiten können, und genau hier kommt die datasets Bibliothek ins Spiel.

In meinem Fall verwende ich die Hugging Face Datasets Library, um einen Datensatz mit Tweets zu importieren, die nach ihrer Stimmung (positiv, neutral oder negativ) segmentiert sind.

from datasets import load_dataset

dataset = load_dataset("mteb/tweet_sentiment_extraction")
df = pd.DataFrame(dataset['train'])

Wenn wir uns den Datensatz ansehen, den wir gerade heruntergeladen haben, ist es ein Datensatz, der eine Teilmenge zum Trainieren und eine Teilmenge zum Testen enthält. Wenn wir die Trainingsuntermenge in einen Datenrahmen umwandeln, sieht er wie folgt aus.

Der zu verwendende Datensatz.

Der zu verwendende Datensatz.

Schritt 3: Tokenizer

Jetzt, wo wir unseren Datensatz haben, brauchen wir einen Tokenizer, um ihn für das Parsen durch unser Modell vorzubereiten.

Da LLMs mit Token arbeiten, benötigen wir einen Tokenizer, um den Datensatz zu verarbeiten. Um deinen Datensatz in einem Schritt zu verarbeiten, wendest du mit der Methode Datensätze zuordnen eine Vorverarbeitungsfunktion auf den gesamten Datensatz an.

Deshalb laden wir im zweiten Schritt einen vortrainierten Tokenizer und tokenisieren unseren Datensatz, damit er für die Feinabstimmung verwendet werden kann.

from transformers import GPT2Tokenizer

# Loading the dataset to train our model
dataset = load_dataset("mteb/tweet_sentiment_extraction")

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
tokenizer.pad_token = tokenizer.eos_token
def tokenize_function(examples):
   return tokenizer(examples["text"], padding="max_length", truncation=True)

tokenized_datasets = dataset.map(tokenize_function, batched=True)

BONUS: Um unsere Anforderungen an die Verarbeitung zu verbessern, können wir eine kleinere Teilmenge des gesamten Datensatzes erstellen, um unser Modell fein abzustimmen. Die Trainingsmenge wird zur Feinabstimmung unseres Modells verwendet, während die Testmenge dazu dient, es zu bewerten.

small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

Schritt 4: Unser Basismodell initialisieren

Lade zunächst dein Modell und gib die Anzahl der erwarteten Beschriftungen an. Aus der Karte des Tweet-Sentiment-Datensatzes weißt du, dass es drei Labels gibt:

from transformers import GPT2ForSequenceClassification

model = GPT2ForSequenceClassification.from_pretrained("gpt2", num_labels=3)

Schritt 5: Methode auswerten

Transformers bietet eine für die Ausbildung optimierte Trainerklasse. Diese Methode beinhaltet jedoch nicht, wie das Modell zu bewerten ist. Deshalb müssen wir vor Beginn des Trainings Trainer eine Funktion übergeben, um die Leistung unseres Modells zu bewerten.

import evaluate

metric = evaluate.load("accuracy")

def compute_metrics(eval_pred):
   logits, labels = eval_pred
   predictions = np.argmax(logits, axis=-1)
   return metric.compute(predictions=predictions, references=labels)

Schritt 6: Feinabstimmung mit der Trainer-Methode

Unser letzter Schritt besteht darin, die Trainingsargumente festzulegen und den Trainingsprozess zu starten. Die Transformers-Bibliothek enthält die Klasse Trainer, die eine Vielzahl von Trainingsoptionen und Funktionen wie Protokollierung, Gradientenakkumulation und gemischte Präzision unterstützt. Zuerst definieren wir die Trainingsargumente zusammen mit der Bewertungsstrategie. Sobald alles definiert ist, können wir das Modell ganz einfach mit dem Befehl train() trainieren.

from transformers import TrainingArguments, Trainer

training_args = TrainingArguments(
   output_dir="test_trainer",
   #evaluation_strategy="epoch",
   per_device_train_batch_size=1,  # Reduce batch size here
   per_device_eval_batch_size=1,    # Optionally, reduce for evaluation as well
   gradient_accumulation_steps=4
   )


trainer = Trainer(
   model=model,
   args=training_args,
   train_dataset=small_train_dataset,
   eval_dataset=small_eval_dataset,
   compute_metrics=compute_metrics,

)

trainer.train()

Nach dem Training bewertest du die Leistung des Modells anhand eines Validierungs- oder Testsatzes. Auch hier enthält die Trainerklasse bereits eine Evaluierungsmethode, die sich um diese Aufgabe kümmert.

import evaluate

trainer.evaluate()

Dies sind die grundlegendsten Schritte, um eine Feinabstimmung eines LLM durchzuführen. Denk daran, dass die Feinabstimmung eines LLM sehr rechenintensiv ist und dein lokaler Computer dafür möglicherweise nicht genug Leistung hat.

Du kannst lernen, wie du leistungsstärkere LLMs direkt auf der OpenAI-Oberfläche feinabstimmen kannst, indem du diesem Tutorial über die Feinabstimmung von GPT 3.5 folgst .

Verdiene eine Top-KI-Zertifizierung

Zeige, dass du KI effektiv und verantwortungsbewusst einsetzen kannst.

Feinabstimmung der Best Practices

Um eine erfolgreiche Feinabstimmung zu gewährleisten, solltest du die folgenden Best Practices beachten:

Datenqualität und -quantität

Die Qualität deines Feinabstimmungsdatensatzes wirkt sich erheblich auf die Leistung des Modells aus. Wir alle kennen den Satz:

"Garbage In, Garbage Out"

Achte also immer darauf, dass die Daten sauber, relevant und ausreichend groß sind.

Hyperparameter-Abstimmung

Die Feinabstimmung ist in der Regel ein langer Prozess, der immer wieder wiederholt werden muss. Probiere immer verschiedene Einstellungen für Lernraten, Stapelgrößen und die Anzahl der Trainingsepochen aus, um die beste Einstellung für dein Projekt zu finden.

Präzise Anpassungen sind der Schlüssel, um sicherzustellen, dass das Modell effizient lernt und sich gut an die ungesehenen Daten anpasst, damit es nicht zu einer Überanpassung kommt.

Regelmäßige Bewertung

Überprüfe regelmäßig die Fortschritte des Modells während der Ausbildung, um seine Effektivität zu verfolgen und notwendige Änderungen vorzunehmen. Dabei wird die Leistung des Modells während des gesamten Trainingszeitraums anhand eines bestimmten Validierungsdatensatzes bewertet.

Eine solche Bewertung ist wichtig, um die Leistung des Modells für die jeweilige Aufgabe und seine mögliche Überanpassung an den Trainingsdatensatz zu bestimmen. Anhand der Ergebnisse aus der Validierungsphase können bei Bedarf Anpassungen vorgenommen werden, um die Leistung zu optimieren.

LLM-Feinschliff-Fallen vermeiden

Die Feinabstimmung kann manchmal zu suboptimalen Ergebnissen führen. Hüte dich vor den folgenden Fallstricken:

Überanpassung

Die Verwendung eines kleinen Datensatzes für das Training oder eine zu große Anzahl von Epochen kann zu einer Überanpassung führen. Dies ist in der Regel dadurch gekennzeichnet, dass das Modell in unserem Trainingsdatensatz eine hohe Genauigkeit aufweist, aber nicht auf neue Daten verallgemeinert werden kann.

Underfitting

Umgekehrt kann ein unzureichendes Training oder eine niedrige Lernrate zu einer Unteranpassung führen, bei der das Modell die Aufgabe nicht ausreichend lernt.

Katastrophisches Vergessen

Bei der Feinabstimmung für eine bestimmte Aufgabe besteht die Gefahr, dass das Modell das breite Wissen, das es ursprünglich erworben hat, verliert. Dieses Problem, das als katastrophales Vergessen bezeichnet wird, kann die Fähigkeit des Modells beeinträchtigen, bei einer Vielzahl von Aufgaben der natürlichen Sprachverarbeitung gut abzuschneiden.

Datenleck

Achte immer darauf, dass Trainings- und Validierungsdatensätze getrennt sind und sich nicht überschneiden, da dies zu irreführenden Leistungskennzahlen führen kann.

Feinabstimmung vs. RAG

RAG kombiniert die Stärken von Retrieval-basierten Modellen und generativen Modellen. In RAG durchsucht eine Retriever-Komponente eine große Datenbank oder Wissensbasis, um relevante Informationen auf der Grundlage der eingegebenen Anfrage zu finden. Diese abgerufenen Informationen werden dann von einem generativen Modell verwendet, um eine genauere und kontextbezogene Antwort zu geben. Die wichtigsten Vorteile der RAG sind:

  • Dynamische Wissensintegration: Bezieht Echtzeitinformationen aus externen Quellen mit ein und eignet sich daher für Aufgaben, die aktuelles oder spezifisches Wissen erfordern.
  • Kontextuelle Relevanz: Verbessert die Antworten des generativen Modells, indem es zusätzlichen Kontext aus den abgerufenen Dokumenten liefert.
  • Vielseitigkeit: Kann eine größere Bandbreite an Abfragen bearbeiten, einschließlich solcher, die spezielle oder seltene Informationen erfordern, auf die das Modell möglicherweise nicht trainiert wurde.

Die Wahl zwischen Feinabstimmung und RAG

Wenn du entscheidest, ob du die Feinabstimmung oder die RAG nutzen willst, solltest du die folgenden Faktoren berücksichtigen:

  • Art der Aufgabe: Bei Aufgaben, die von hochspezialisierten Modellen profitieren (z. B. bei domänenspezifischen Anwendungen), ist die Feinabstimmung oft der bevorzugte Ansatz. RAG ist ideal für Aufgaben, die die Integration von externem Wissen oder das Abrufen von Informationen in Echtzeit erfordern.
  • Datenverfügbarkeit: Die Feinabstimmung erfordert eine beträchtliche Menge an beschrifteten Daten für die jeweilige Aufgabe. Wenn solche Daten knapp sind, kann die Abrufkomponente der RAG dies ausgleichen, indem sie relevante Informationen aus externen Quellen bereitstellt.
  • Ressourcenbeschränkungen: Die Feinabstimmung kann sehr rechenintensiv sein, wohingegen RAG bestehende Datenbanken nutzt, um das generative Modell zu ergänzen, wodurch der Bedarf an umfangreichem Training reduziert werden kann.

Fazit

Der Einstieg in die Feinabstimmung großer Sprachmodelle eröffnet eine Welt voller Möglichkeiten für KI-Anwendungen.

Wenn du die beschriebenen Konzepte, Praktiken und Vorsichtsmaßnahmen verstehst und anwendest, kannst du diese leistungsstarken Modelle effektiv an deine spezifischen Bedürfnisse anpassen und dabei ihr volles Potenzial ausschöpfen.

Um mehr über die Feinabstimmung zu lernen, empfehle ich dir, einige fortgeschrittene Feinabstimmungen durchzuführen. Du kannst mit dem Kurs "LLM-Konzepte" von DataCamp beginnen, der viele der wichtigsten Schulungsmethoden und die neuesten Forschungsergebnisse abdeckt. Einige andere gute Quellen sind:

FAQs

Was ist der Hauptzweck der Feinabstimmung von Large Language Models (LLMs)?

Die Feinabstimmung von LLMs zielt darauf ab, vortrainierte Modelle an bestimmte Aufgaben oder Domänen anzupassen. Dabei wird das Modell auf einem aufgabenspezifischen Datensatz weiter trainiert, um seine Leistung zu verbessern und es für bestimmte Anwendungen wie Sentimentanalyse, Fragenbeantwortung oder domänenspezifische Texterstellung effektiver zu machen.

Wie unterscheidet sich die Feinabstimmung vom Training eines Modells von Grund auf?

Bei der Feinabstimmung wird ein vortrainiertes Modell verwendet, das bereits allgemeine Sprachmuster aus einem großen Datensatz gelernt hat. Dies reduziert die Rechenkosten und den Zeitaufwand im Vergleich zum Training eines Modells von Grund auf, das mit einer zufälligen Initialisierung beginnt und deutlich mehr Daten und Rechenressourcen benötigt, um eine vergleichbare Leistung zu erzielen.

Was sind die häufigsten Fallstricke, die man bei der Feinabstimmung von LLMs vermeiden sollte?

Zu den häufigen Fallstricken gehören die Überanpassung, bei der das Modell in den Trainingsdaten gut, in den neuen Daten aber schlecht abschneidet, die Unteranpassung, bei der das Modell die Aufgabe nicht angemessen erlernt, das katastrophale Vergessen, bei dem das Modell das ursprünglich erworbene breite Wissen verliert, und das Datenleck, bei dem sich überlappende Trainings- und Validierungsdatensätze zu irreführenden Leistungsmetriken führen.

Welche Arten von Datensätzen sind für die Feinabstimmung von LLMs geeignet?

Geeignete Datensätze für die Feinabstimmung sollten qualitativ hochwertig, für die jeweilige Aufgabe relevant und ausreichend groß sein, um dem Modell genügend Beispiele zum Lernen zu liefern. Beispiele dafür sind gelabelte Datensätze für die überwachte Feinabstimmung (z. B. mit Gefühlen gelabelte Tweets für die Stimmungsanalyse) oder domänenspezifische Textsammlungen für die Domänenanpassung (z. B. Krankenakten für einen Chatbot im Gesundheitswesen).

Was ist der Unterschied zwischen Fine-Tuning und Retrieval-Augmented Generation (RAG)?

Bei der Feinabstimmung werden die Parameter eines vorab trainierten Modells anhand eines bestimmten Datensatzes angepasst, um seine Leistung bei bestimmten Aufgaben zu verbessern. RAG hingegen kombiniert eine Retrieval-Komponente, um relevante Dokumente zu finden, und ein generatives Modell, um Antworten zu erzeugen, wobei externes Wissen während der Inferenz dynamisch einbezogen wird. Die Feinabstimmung verbessert das bereits vorhandene Wissen des Modells, während RAG die Echtzeitabfrage nutzt, um kontextbezogene Antworten zu geben.

KI-Anwendungen entwickeln

Lerne, wie man KI-Anwendungen mit der OpenAI API erstellt.

Start Upskilling for Free

Photo of Josep Ferrer
Author
Josep Ferrer
LinkedIn
Twitter

Josep ist Data Scientist und Projektmanager beim katalanischen Fremdenverkehrsamt und nutzt Daten, um die Erfahrungen von Touristen in Katalonien zu verbessern. Sein Fachwissen umfasst das Management von Datenspeicherung und -verarbeitung, gekoppelt mit fortschrittlichen Analysen und der effektiven Kommunikation von Datenerkenntnissen.

Er ist auch ein engagierter Pädagoge, der den Big-Data-Masterstudiengang an der Universität von Navarra unterrichtet und regelmäßig aufschlussreiche Artikel über Datenwissenschaft auf Medium und KDNuggets veröffentlicht.

Er hat einen BS in technischer Physik von der Polytechnischen Universität von Katalonien und einen MS in intelligenten interaktiven Systemen von der Universität Pompeu Fabra.

Derzeit engagiert er sich leidenschaftlich dafür, datenbezogene Technologien durch die Medium-Publikation ForCode'Sake einem breiteren Publikum zugänglich zu machen.

Themen

Beginne deine KI-Reise noch heute!

Zertifizierung verfügbar

Course

Einführung in LLMs in Python

4 hr
7.4K
Erfahre alles über LLMs und die revolutionäre Transformatorarchitektur, auf der sie basieren!
See DetailsRight Arrow
Start Course
Mehr anzeigenRight Arrow