English 日本語
preview
Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen

Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen

MetaTrader 5Handel | 16 Dezember 2024, 11:41
133 0
Yuqiang Pan
Yuqiang Pan

Inhaltsverzeichnis



Einführung

Im vorangegangenen Artikel haben wir die Feinabstimmung des vortrainierten GPT-2-Modells anhand unserer eigenen Finanzdaten mit einer Vollparameter-Feinabstimmungsmethode vorgestellt und die Ausgabeergebnisse des Modells bewertet. In diesem und den folgenden Artikeln werden wir anhand von Code-Beispielen erörtern, wie andere Feinabstimmungsmethoden implementiert werden können (wir werden nur die im vorherigen Artikel vorgestellten Feinabstimmungsmethoden erörtern, und natürlich ist es unmöglich, jede Methode zu implementieren. Ich werde nur einige häufig verwendete Methoden zur Umsetzung auswählen). In diesem Artikel wird die LoRA-Tuning-Methode als Beispiel für die Diskussion herangezogen.

Außerdem müssen wir versuchen, die mit diesen verschiedenen Feinabstimmungsmethoden trainierten Modelle horizontal zu vergleichen und dann das Modell mit der besten Leistung für das aktuelle Währungspaar zu finden (natürlich kann die Leistung des Modells auch unter verschiedenen Marktbedingungen variieren, z. B. bei Aufwärtstrends, Abwärtstrends oder schwankenden Trends). Dies kann uns einen klareren Hinweis darauf geben, welche Methode der Modelltraining wir in der Praxis anwenden sollten, um bessere Ergebnisse zu erzielen. Wenn wir strenger sind, sollten wir natürlich nicht nur diese verschiedenen Verarbeitungsmethoden horizontal vergleichen, sondern auch die Leistung der Feinabstimmungsmodelle verschiedener Währungspaare unter verschiedenen Datenverarbeitungsmethoden und Feinabstimmungsmethoden vergleichen. Dies scheint eine einfache, aber äußerst mühsame Aufgabe zu sein. Ich persönlich glaube, dass dieser Schritt von entscheidender Bedeutung ist, wenn wir diese Reihe von Methoden im Handel wirklich anwenden wollen. Ich habe jedoch nicht die Absicht, diesen Teil in dieser Artikelserie im Detail vorzustellen, weil ich glaube, dass jeder anhand unserer Beispiele leicht erweitern kann. Ersetzen Sie einfach die Trainingsdaten durch verschiedene Währungspaare und vergleichen Sie dann die Modellleistung horizontal. Dies ist zwar mühsam, aber leicht zu bewerkstelligen.

Ein weiterer Punkt ist, dass ich in früheren Artikeln versäumt habe, die entsprechenden Umgebungskonfigurationen und Bibliotheksabhängigkeiten in den Beispielcode einzufügen, was dazu führen kann, dass einige Freunde beim Versuch, die Beispiele auszuführen, auf Fehler aufgrund fehlender Abhängigkeiten stoßen. In zukünftigen Artikeln werde ich die Umgebungskonfiguration und die Abhängigkeiten, die im aktuellen Code verwendet werden, ausführlich erläutern, um den Lesern die Ausführung der Beispiele zu erleichtern.

Kommen wir nun offiziell zum Thema dieses Artikels!


Umgebung Konfiguration

Nachfolgend finden Sie die Betriebsumgebung für die Codebeispiele in diesem Artikel. Das bedeutet natürlich nicht, dass Ihre Code-Umgebung die gleiche sein muss wie meine, aber wenn Sie beim Ausführen des Codes auf Probleme stoßen, können Sie sich an meiner Umgebungskonfiguration orientieren.

  • Betriebssystem: Ubuntu 22.04.5 LTS (oder die entsprechende Version von WSL)
  • Python-Version: 3.10.14
  • Erforderliche Python-Bibliotheken:

  1. torch-2.4.1
  2. numpy-1.26.3
  3. pandas-2.2.3
  4. transformers-4.45.1
  5. petf-0.13.0
  6. matplotlib-3.9.2

Wenn Sie mit der Konfiguration der Code-Ausführungsumgebung nicht vertraut sind, finden Sie in anderen Artikeln dieser Reihe ausführliche Einführungen:

Dieser Artikel wird keine detaillierte Einführung in diesen Teil geben.


LoRA-Konfiguration

Wir haben LoRA bereits im vorangegangenen Artikel vorgestellt, sodass wir die Beschreibung in diesem Artikel nicht wiederholen werden. Um den Prozess der Feinabstimmung einfacher und übersichtlicher zu gestalten, wird in diesem Artikel nicht das Codebeispiel des ursprünglichen LoRA-Autors reproduziert, sondern die einfachere peft-Bibliothek verwendet.

Diese Python-Bibliothek integriert verschiedene Konfigurationen, die wir benötigen, einschließlich der LoRA-Tuning-Parameter-Konfigurationsklasse (LoraConfig), der LoRA-Tuning-Initialisierungsmodellmethode (get_peft_model) und der LoRA-Feinabstimmungsmodell-Ladeklasse (PeftModel).

Als Nächstes werde ich sie Schritt für Schritt vorstellen, beginnend mit der Klasse LoraConfig.

1. LoraConfig-Klasse

Die Klasse LoraConfig gehört zur peft-Bibliothek und kann direkt aus der peft-Bibliothek importiert werden. Nachdem Sie die Klasse LoraConfig importiert haben, müssen Sie ihre Konfigurationsparameter festlegen.

Als Nächstes stellen wir die Parameterkonfiguration in der Klasse „LoraConfig“ vor

  • r (`int`):

Lora Aufmerksamkeitsdimension (der Rang bzw. „rank").

  • target_modules (`Optional[Union[List[str], str]]`):

Die Namen der Module, auf die der Adapter angewendet werden soll. Wenn dies angegeben wird, werden nur die Module mit den angegebenen Namen ersetzt. Bei Übergabe einer Zeichenkette wird eine Regex-Übereinstimmung durchgeführt. Bei der Übergabe einer Liste von Zeichenketten wird entweder eine exakte Übereinstimmung durchgeführt oder es wird geprüft, ob der Name des Moduls mit einer der übergebenen Zeichenketten endet. Wird hier „all-linear“ angegeben, werden alle linearen/Conv1D-Module ausgewählt, mit Ausnahme der Ausgabeschicht. Wenn dies nicht angegeben wird, werden die Module entsprechend der Modellarchitektur ausgewählt. Wenn die Architektur nicht bekannt ist, wird eine Fehlermeldung ausgegeben - in diesem Fall sollten Sie die Zielmodule manuell angeben.

  • lora_alpha (`int`):

Der Alpha-Parameter für die Lora-Skalierung.

  • lora_dropout (`float`):

Die Abbrecherwahrscheinlichkeit für Lora-Schichten.

  • fan_in_fan_out (`bool`):

Setzen Sie diesen Wert auf True, wenn die zu ersetzende Ebene Gewichtungen wie (fan_in, fan_out) enthält. Zum Beispiel verwendet gpt-2 „Conv1D“, das Gewichte wie (fan_in, fan_out) speichert und daher auf „True“ gesetzt werden sollte.

  • bias (`str`):

Das Bias für LoRA. Möglich sind: „none“, „all“ or „lora_only“. Bei „all“ oder „lora_only“ werden die entsprechenden Verzerrungen während des Trainings aktualisiert. Dies bedeutet, dass das Modell auch bei deaktivierten Adaptern nicht die gleiche Leistung erbringt wie das Basismodell ohne Anpassung.

  • use_rslora (`bool`):
 Wenn auf True gesetzt, wird <a href='https://doi.org/10.48550/arXiv.2312.03732'>Rank-Stabilized LoRA</a> verwendet, das den Skalierungsfaktor des Adapters auf „lora_alpha/math.sqrt(r)“ setzt, da es sich als besser erwiesen hat. Andernfalls wird der ursprüngliche Standardwert von „lora_alpha/r“ verwendet.
  • modules_to_save (`List[str]`):
 Liste der Module mit Ausnahme der Adapterschichten, die als trainierbar einzustufen und im letzten Checkpoint zu speichern sind.
  • init_lora_weights (`bool` | `Literal["gaussian", "olora", "pissa", "pissa_niter_[number of iters]", "loftq"]`):
Wie man die Gewichte der Adapterschichten initialisiert. Die Übergabe von True (der Standard) führt zu der Standardinitialisierung aus der Referenzimplementierung von Microsoft. Die Übergabe von „gaussian“ führt zu einer Gauß-Initialisierung, skaliert mit dem LoRA-Rang für linear und Schichten. Das Setzen der Initialisierung auf False führt zu einer völlig zufälligen Initialisierung und wird nicht empfohlen. Übergeben Sie „loftq“, um die LoftQ-Initialisierung zu verwenden. Übergeben Sie „olora“, um die OLoRA-Initialisierung zu verwenden. Die Übergabe von „pissa“ führt zur Initialisierung von <a
    href='https://arxiv.org/abs/2404.02948'>Principal Singular values and Singular vectors Adaptation (PiSSA)</a>, das schneller konvergiert als LoRA und letztlich eine bessere Leistung erzielt. Darüber hinaus reduziert PiSSA den Quantisierungsfehler im Vergleich zu QLoRA, was zu weiteren Verbesserungen führt. Übergabe
    „pissa_niter_[number of iters]'` leitet die Fast-SVD-basierte PiSSA-Initialisierung ein, wobei „[number of iters]“ die Anzahl der Unterraum-Iterationen für die Durchführung der FSVD angibt und eine nichtnegative ganze Zahl sein muss. Wenn „[number of iters]“ auf 16 gesetzt wird, kann die Initialisierung eines 7B-Modells innerhalb von Sekunden abgeschlossen werden, und der Trainingseffekt entspricht in etwa der Verwendung von SVD.
  • layers_to_transform (`Union[List[int], int]`):
Die zu transformierenden Ebenenindizes. Wenn eine Liste von Ints übergeben wird, wird der Adapter auf die in dieser Liste angegebenen Ebenenindizes angewendet. Wenn eine einzelne ganze Zahl übergeben wird, werden die Transformer auf die Ebene mit diesem Index angewendet.
  • layers_pattern (`str`):
Der Name des Ebenenmusters, der nur verwendet wird, wenn `layers_to_transform` anders als `None` ist.
  • rank_pattern (`dict`):
 Die Zuordnung von Ebenennamen oder Regexp-Ausdrücken zu Rängen, die sich von dem durch „r“ angegebenen Standardrang unterscheiden.
  • alpha_pattern (`dict`):
Die Zuordnung von Ebenennamen oder Regexp-Ausdrücken zu Alphas, die sich von dem durch „Lora_alpha“ festgelegten Standard-Alpha unterscheiden.
  • megatron_config (`Optional[dict]`):
Die TransformerConfig-Argumente für Megatron. Sie wird verwendet, um die parallele lineare Ebene von LoRA zu erstellen. Sie können es so erhalten, „core_transformer_config_from_args(get_args())“, diese beiden Funktionen sind von Megatron. Die Argumente werden verwendet, um die TransformerConfig von Megatron zu initialisieren. Sie müssen diesen Parameter angeben, wenn Sie LoRA auf die Ebenen ColumnParallelLinear und RowParallelLinear von megatron anwenden wollen.
  • megatron_core (`Optional[str]`):
Das zu verwendende Kernmodul von Megatron, Standardwert ist „megatron.core“.
  • loftq_config (`Optional[LoftQConfig]`):
Die Konfiguration von LoftQ. Wenn dies nicht None ist, wird LoftQ zur Quantisierung der Backbone-Gewichte und zur Initialisierung der Lora-Schichten verwendet. Übergeben Sie auch init_lora_weights='loftq'. Beachten Sie, dass Sie in diesem Fall kein quantisiertes Modell übergeben sollten, da LoftQ das Modell selbst quantisieren wird.
  • use_dora (`bool`):
Aktivieren Sie die „Weight-Decomposed Low-Rank Adaptation“ (DoRA). Bei dieser Technik werden die Aktualisierungen der Gewichte in zwei Teile zerlegt, nämlich in Größe und Richtung. Die Richtung wird durch die normale LoRA gehandhabt, während die Größe durch einen separaten lernbaren Parameter gehandhabt wird. Dies kann die Leistung von LoRA insbesondere bei niedrigen Rängen verbessern. Derzeit unterstützt DoRA nur lineare und Conv2D-Ebenen. DoRA führt zu einem größeren Overhead als reines LoRA, daher wird empfohlen, die Gewichte für die Inferenz zusammenzuführen. Weitere Informationen finden Sie unter https://arxiv.org/abs/2402.09353.
  • layer_replication (`List[Tuple[int, int]]`):
Wir erstellen einen neuen Stapel von Ebenen, indem wir die ursprünglichen Modellebenen entsprechend den angegebenen Bereichen stapeln. Dadurch kann das Modell erweitert (oder verkleinert) werden, ohne dass die Gewichte des Basismodells dupliziert werden. Die neuen Ebenen werden alle mit separaten LoRA-Adaptern ausgestattet.
  • runtime_config (`LoraRuntimeConfig`):
Laufzeitkonfigurationen (die nicht gespeichert oder wiederhergestellt werden).

Dies sind alle Parameter der Klasse LoraConfig. In der Praxis werden in der Regel nicht alle Werte eingestellt, sondern nur einige wichtige Parameter, die wir benötigen, und die anderen als Standardwerte beibehalten. In unserem Beispiel setzen wir nur die folgenden Parameter: lora_alpha=32, lora_dropout=0.1, und belassen die anderen Parameter als Standard. Natürlich stellen die in diesem Artikel genannten Einstellungen nicht die optimale Wahl dar. Sie können jederzeit einige Parameterkombinationen auswählen und verschiedene Einstellungen ausprobieren, um die optimale Parameterkombination zu finden.

peft_config = LoraConfig(
                         lora_alpha=32, 
                         lora_dropout=0.1)

2. Die Funktion get_peft_model()

Die Funktion get_peft_model() kann auch direkt aus der peft-Bibliothek importiert werden. Wir müssen es verwenden, um unser GPT-2-Modell als ein Modell zu laden, das die angegebene Konfiguration vor der Feinabstimmung erfüllt. Im Beispiel dieses Artikels werden wir GPT-2 als konfiguriertes LoRA-Modell laden.

Schauen wir uns zunächst die Parameterkonfiguration dieser Funktion an:

  • model ([`transformers.PreTrainedModel`]):

Das zu verpackende Modell.

  • peft_config ([`PeftConfig`]):

Konfigurationsobjekt, das die Parameter des Peft-Modells enthält.

  • adapter_name (`str`, `optional`, defaults to `"default"`):

Der Name des Adapters, der injiziert werden soll. Wenn er nicht angegeben wird, wird der Standardadaptername verwendet („default").

  • mixed (`bool`, `optional`, defaults to `False`):

Je nachdem, ob das Mischen verschiedener (kompatibler) Adaptertypen erlaubt werden soll.

  • autocast_adapter_dtype (`bool`, *optional*):

Ob der Adapter dtype automatisch übertragen werden soll. Der Standardwert ist „True“. Im Moment werden nur Adaptergewichte, die float16 oder bfloat16 verwenden, in float32 umgewandelt, da dies typischerweise für ein stabiles Training erforderlich ist und nur ausgewählte PEFT-Tuner betrifft.

  • revision (`str`, `optional`, defaults to `main`):

Die Überarbeitung des Basismodells. Wenn dies nicht eingestellt ist, wird das gespeicherte Postmodell die „Haupt"-Revision für das Basismodell laden.

In diesem Beispiel werden nur die Parameter model und peft_config verwendet, die anderen Parameter bleiben als Standardwerte erhalten. Das Modell wird verwendet, um das GPT-2-Modell zu übergeben, und peft_config wird verwendet, um unsere LoraConfig-Konfiguration zu empfangen.

model = get_peft_model(model, peft_config)

3. Die Klasse PeftModel

Die Klasse PeftModel ist die Basisklasse der Peft-Bibliothek. Sie kann jeden von dieser Bibliothek unterstützten Modelltyp initialisieren. Wir müssen die Klasse PeftModel verwenden, um die während der Feinabstimmung gespeicherten LoRA-Parameter und die ursprünglichen, von GPT-2 trainierten Modellparameter nach Abschluss des Trainings in ein Modell zu laden und dann das geladene Modell für Inferenztests zu verwenden. Schauen wir uns zunächst die Parameterkonfiguration dieser Klasse an.

  • Modell ([~transformers.PreTrainedModel`]): Das Basistransformermodell, das für Peft.
  • peft_config ([`PeftConfig`]): Die Konfiguration des Peft-Modells.
  • adapter_name (`str`,  *optional*): Der Name des Adapters, Standardwert ist „default“.
  • autocast_adapter_dtype (`bool`, *optional*):

Ob der Adapter dtype automatisch übertragen werden soll. Der Standardwert ist „True“. Im Moment werden nur Adaptergewichte, die float16 und bfloat16 verwenden, in float32 umgewandelt, da dies typischerweise für ein stabiles Training erforderlich ist und nur ausgewählte PEFT-Tuner betrifft.

  • low_cpu_mem_usage (`bool`, `optional`, defaults to `False`):

    Leere Adaptergewichte auf dem Meta-Gerät erstellen. Nützlich zur Beschleunigung des Ladevorgangs.

  • Attribute:

    - base_model ([`torch.nn.Module`]) -- Das für Peft verwendete Basis-Transformermodell.

    - peft_config ([`PeftConfig`]) -- Die Konfiguration des Peft-Modells.

    - modules_to_save (`list` of `str`) -- Die Liste der Namen von Untermodulen, die beim Speichern des Modells gespeichert werden sollen.

    - prompt_encoder ([`PromptEncoder`]) -- Der für Peft verwendete Prompt-Encoder, wenn [`PromptLearningConfig`] verwendet wird.

    - prompt_tokens (`torch.Tensor`) -- Die virtuellen Prompt-Token, die für Peft verwendet werden, wenn [`PromptLearningConfig`] verwendet wird.

    - transformer_backbone_name (`str`) -- Der Name des Transformer-Backbones im Basismodell, wenn [`PromptLearningConfig`] verwendet wird.

    - word_embeddings (`torch.nn.Embedding`) -- Die Worteinbettungen des Transformer-Backbones im Basismodell, wenn [`PromptLearningConfig`] verwendet wird.

Bei Verwendung der Klasse PeftModel wird das Modell direkt über die Klassenmethode PeftModel.from_pretrained(model, peft_model_id) geladen. Das Modell ist unser GPT-2-Modell, und peft_model_id sind die Parameter des LoRA-Modells, die wir feinabgestimmt haben.

model = PeftModel.from_pretrained(model, peft_model_id)

Anmerkung:

Verwenden Sie nicht `low_cpu_mem_usage=True`, wenn Sie einen neuen PEFT-Adapter für das Training erstellen.


LoRA-Tuning

Nach der Einführung in die Konfiguration des LoRA-Tunings mit Hilfe der Bibliothek `peft' wollen wir unser Codebeispiel vervollständigen.

1. Erforderliche Bibliotheken importieren

Hier gibt es nichts Besonderes zu beachten; wir importieren direkt die Bibliotheken, die wir in der Python-Umgebung benötigen:

import pandas as pd
from transformers import GPT2LMHeadModel, GPT2Tokenizer
from transformers import TextDataset, DataCollatorForLanguageModeling
from transformers import Trainer, TrainingArguments
import torch
from peft import get_peft_model, LoraConfig, PeftModel

2. Laden der Daten und Konfiguration des Modells

Zunächst prüfen wir, ob die GPU-Beschleunigung in der aktuellen Codeumgebung verfügbar ist, um sicherzustellen, dass unsere Umgebungskonfiguration korrekt ist. Wenn Sie eine GPU zur Verfügung haben, diese aber nicht genutzt wird, sollten Sie die Konfiguration Ihrer Codeumgebung überprüfen. Die CPU kann die Aufgabe zwar erledigen, aber sie ist sehr langsam.

dvc = 'cuda' if torch.cuda.is_available() else 'cpu'
print(dvc)

Als Nächstes konfigurieren wir die LoRA-Tuning-Parameter. Diese Parameter wurden bereits eingeführt, sodass wir sie direkt verwenden werden:

model_name_or_path = 'gpt2'
peft_config = LoraConfig(
    lora_alpha=32, 
    lora_dropout=0.1
)

„model_name_or_path“ ist unser vortrainiertes Modell. Als Nächstes legen wir den Pfad zum Speichern des fein abgestimmten LoRA-Modells „peft_model_id“ fest:

peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"

Laden wir nun die Datei „llm_data.csv". Wir werden die letzten 20 Schlusskurse dieses Datensatzes als Eingabe verwenden und die Ergebnisse des Modells mit den übrigen Schlusskursen vergleichen, um die Leistung des Modells zu überprüfen.

df = pd.read_csv('llm_data.csv')

Als Nächstes müssen wir die vorverarbeiteten Daten „train.txt“ laden (wir haben den Teil des Codes, der „llm_data.csv“ in „train.txt“ konvertiert, entfernt, da wir die Daten bereits im vorherigen Artikel konvertiert haben, sodass es nicht notwendig ist, sie erneut zu konvertieren). Definieren wir den Tokenizer, „train_dataset“ und „data_collator". Dieser Teil ist derselbe wie in unserem vorherigen Artikel, sodass wir hier nicht ins Detail gehen werden. Interessierte Leser können sich auf den vorherigen Artikel beziehen.

tokenizer = GPT2Tokenizer.from_pretrained(model_name_or_path)
train_dataset = TextDataset(tokenizer=tokenizer, file_path="train.txt", block_size=60)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

Wir müssen auch „TrainingArguments“ instanziieren. Hier haben wir die Parameter „save_steps“ und „save_total_limit“ entfernt. Diese Parameter verwalten hauptsächlich die Speicherung von Kontrollpunkten während des Trainings, aber für das LoRA-Tuning müssen wir nur die LoRA-Parameter speichern, nicht alle Parameter. Um Konflikte zu vermeiden, haben wir diese beiden Parameter entfernt und den Parameter save_strategy='no' hinzugefügt und die Methode „save_model“ in der Klasse „Trainer“ zum Speichern des Modells verwendet.

training_args = TrainingArguments(
    output_dir=peft_model_id,     
    overwrite_output_dir=True,    
    num_train_epochs=3,     
    per_device_train_batch_size=32,
    save_strategy='no'
)

3. Laden und Feinabstimmung des Modells

Zuerst laden wir das vortrainierte GPT-2-Modell als „HeadModel":

model = GPT2LMHeadModel.from_pretrained(model_name_or_path)

Dann müssen wir die konfigurierten LoRA-Einstellungen mit dem vortrainierten GPT-2-Modell zusammenführen. Dieser Prozess, der recht komplex war, erfordert jetzt nur noch eine Zeile Code unter Verwendung der Funktion „get_peft_model()“ aus der Bibliothek „peft“. Diese Bibliothek hat uns viel Komfort gebracht.

model = get_peft_model(model, peft_config)

Als Nächstes instanziieren wir den „Trainer", führen die Feinabstimmung des Trainings durch und speichern das Modell. Dieser Teil unterscheidet sich nicht vom Code im vorigen Artikel, sodass wir ihn nicht im Detail besprechen werden. Interessierte Leser können sich auf den vorherigen Artikel beziehen.

trainer = Trainer(
    model=model,
    args=training_args,
    data_collator=data_collator,
    train_dataset=train_dataset
)
trainer.train()
trainer.save_model(peft_model_id)

Dabei ist zu beachten, dass das mit „trainer.save_model(peft_model_id)“ gespeicherte Modell nicht mehr das vollständige Modell ist, sondern nur noch die LoRA-Gewichte enthält. Während der LoRA-Abstimmung werden die vortrainierten Gewichte des GPT-2 eingefroren und nur die LoRA-Gewichte feinabgestimmt. Daher müssen Sie beim Laden des fein abgestimmten Modells die Methode „from_pretrained()“ in der Klasse „PeftModel“ verwenden, um diese beiden Teile der Gewichte zusammen neu zu laden, damit das Modell korrekt funktioniert. Sie können nicht mehr „GPT2LMHeadModel.from_pretrained()“ zum Laden des Modells verwenden.

train

Nach der Feinabstimmung wird das Modell im Ordner „gpt2_LORA_None“ unter dem Verzeichnis gespeichert, in dem sich das Trainingsskript befindet (da wir den Parameter „task_type“ in der Klasse „LoraConfig“ nicht gesetzt haben, steht diese Option standardmäßig auf „None“, weshalb der Ordner mit „None“ endet).

4. Testen des Feinabstimmungsmodells

Nach der Feinabstimmung müssen wir das feinabgestimmte Modell laden und eine Inferenz durchführen, um zu prüfen, ob das feinabgestimmte Modell korrekt funktioniert. Wie bereits erwähnt, unterstützt das mit LoRA feinabgestimmte Modell das Laden mit „GPT2LMHeadModel.from_pretrained()“ nicht und muss die Methode „from_pretrained()“ in der Klasse „PeftModel“ verwenden, um das vortrainierte GPT-2-Modell und die LoRA-Gewichte zusammen zu laden. Die Parameter der Methode „PeftModel.from_pretrained()“ wurden bereits früher eingeführt, sodass wir sie hier nicht weiter erläutern werden. Nach dem Laden des Modells müssen wir es auf GPU-Beschleunigung einstellen und das Modell in den Inferenzmodus schalten.

model = GPT2LMHeadModel.from_pretrained(model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)
model.to(dvc)
model.eval()

Als Nächstes folgt der Inferenztest, um festzustellen, ob das Modell korrekt funktioniert. Dieser Vorgang ist derselbe wie im vorherigen Artikel. Ausführliche Informationen zur Interpretation des Codes finden Sie in einem früheren Artikel. Wir werden das hier nicht diskutieren.

prompt = ' '.join(map(str, df.iloc[:, 1:20].values[-1]))
generated = tokenizer.decode(model.generate(tokenizer.encode(prompt, return_tensors='pt').to(dvc), 
                                            do_sample=True, 
                                            max_length=200)[0], 
                                            skip_special_tokens=True)
print(f"test the model: {generated}")

Das Ergebnis sieht wie folgt aus:

Modelltest: 0.61163 0.61162 0.61191 0.61195 0.61209 0.61231 0.61224 0.61207 0.61187 0.61184 

0.6119 0.61169 0.61168 0.61162 0.61181 0.61184 0.61184 0.6118 0.61176 0.61174 0.61175 0.61169 

0.6119 0.61174 0.6116 0.61144 0.61155 0.61207 0.61192 0.61203 0.61158 0.61202 0.61158 0.61156 

0.61146 0.61196 0.61144 0.656 0.61142 0.61141 0.61137 0.60952 0.611

Das vollständige Skript für die Feinabstimmung ist „lora-tuning.py“.

import pandas as pd
from transformers import GPT2LMHeadModel, GPT2Tokenizer
from transformers import TextDataset, DataCollatorForLanguageModeling
from transformers import Trainer, TrainingArguments
import torch
from peft import get_peft_model, LoraConfig, PeftModel

dvc='cuda' if torch.cuda.is_available() else 'cpu'
print(dvc)
model_name_or_path='gpt2'

peft_config = LoraConfig(
                        #  task_type=None, 
                        #  inference_mode=False, 
                        #  r=8, 
                         lora_alpha=32, 
                         lora_dropout=0.1,
                         )

peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
df = pd.read_csv('llm_data.csv')

# sentences = [' '.join(map(str, prices)) for prices in df.iloc[:-10,1:].values]
# with open('train.txt', 'w') as f:
#     for sentence in sentences:
#         f.write(sentence + '\n')

tokenizer = GPT2Tokenizer.from_pretrained(model_name_or_path)
train_dataset = TextDataset(tokenizer=tokenizer,
                            file_path="train.txt", 
                            block_size=60)

data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
training_args = TrainingArguments(output_dir=peft_model_id,     
                                  overwrite_output_dir=True,    
                                  num_train_epochs=3,     
                                  per_device_train_batch_size=32,
                                  save_strategy= 'no',   
                                #   save_steps=10_000,    
                                #   save_total_limit=2,
                                #   load_best_model_at_end=True,
                                  )

model = GPT2LMHeadModel.from_pretrained(model_name_or_path)
model = get_peft_model(model, peft_config)

trainer = Trainer(model=model,
                  args=training_args,
                  data_collator=data_collator,
                  train_dataset=train_dataset,)

trainer.train()

# model.save_pretrained(peft_model_id)
trainer.save_model(peft_model_id)

# config = PeftConfig.from_pretrained(peft_model_id)
model = GPT2LMHeadModel.from_pretrained(model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)
model.to(dvc)
model.eval()

prompt = ' '.join(map(str, df.iloc[:,1:20].values[-1])) 
generated = tokenizer.decode(model.generate(tokenizer.encode(prompt, return_tensors='pt').to(dvc), 
                                            do_sample=True, 
                                            max_length=200)[0], 
                                            skip_special_tokens=True)

print(f"test the model:{generated}")

Die Datendateien werden am Ende angehängt, wobei die Originaldatendatei „llm_data.csv“ und die vorverarbeitete Datendatei „train.txt“ ist.


Vergleich verschiedener Feinsteuerungsmethoden

Nach dem Experimentieren mit verschiedenen Feinabstimmungsmethoden haben wir neue GPT-2-Modelle mit unterschiedlichen Leistungen erhalten. Dies erfordert einen Vergleich der Ergebnisse und der Trainingsgeschwindigkeiten verschiedener Methoden, um die am besten geeignete Methode für unsere EA-Strategie wissenschaftlich auszuwählen. Da das vortrainierte GPT-2-Modell unsere Eingabe nicht erkennen kann, brauchen wir das vortrainierte Modell nicht in die Vergleichssequenz aufzunehmen. Daher führen wir die Vollparameter-Feinabstimmung und die LoRA-Abstimmung nur zum Vergleich ein. Natürlich werde ich in den folgenden Artikeln weiterhin verschiedene Methoden vorstellen, sodass wir mehr Auswahlmöglichkeiten haben werden.

1. Effizienzvergleich

Zunächst müssen wir die Kosten des Trainings vergleichen. Wir bevorzugen Methoden mit hoher Trainingseffizienz und geringen Kosten. Hier vergleichen wir die Trainingszeit, den Speicherverbrauch und die Inferenzgeschwindigkeit. Obwohl die Unterschiede bei einem Modell mit kleinen Parametern wie GPT-2 nicht signifikant sein mögen, werden sie bei der Wahl größerer Modelle (z. B. 7B, 13B, 34B oder größer) sehr deutlich.


Train_runtime(s)
VRAM(GB)
Generate_runtime(s)
LoRA-Tuning Prozess
69.5605
4.1
1.242877
Vollparametrischer Feinabstimmungsprozess
101.7946
5.67
0.876525

2. Genauigkeitsvergleich

In Bezug auf die Genauigkeit vergleichen wir vorübergehend die Modelle, die durch verschiedene Feinabstimmungsmethoden erhalten wurden, anhand von MSE (mittlerer quadratischer Fehler), RMSE (Wurzel des mittleren quadratischen Fehlers) und NRMSE (normalisierte Wurzel des mittleren quadratischen Fehlers). Andere Metriken (wie Komplexität, Robustheit usw.) werden vorerst nicht berücksichtigt.

Als Nächstes laden wir die Schlusskurse der letzten 20 Zeilen der Originaldaten als Eingabe und verwenden die verbleibenden Daten als Ergebnis, um die mit den beiden Trainingsmethoden erhaltenen Modelle zu bewerten.

  • Eingabedaten: [0.61163, 0.61162, 0.61191, 0.61195, 0.61209, 0.61231, 0.61224, 0.61207, 0.61187, 0.61184, 0.6119, 0.61169, 0.61168, 0.61162, 0.61181, 0.61184, 0.61184, 0.6118, 0.61176]
  • Wahre Preise: [0.6119, 0.61197, 0.61201, 0.61242, 0.61237, 0.6123, 0.61229, 0.61242, 0.61212, 0.61197, 0.61201, 0.61213, 0.61212, 0.61206, 0.61203, 0.61206, 0.6119, 0.61193, 0.61191, 0.61202, 0.61197, 0.6121, 0.61211, 0.61214, 0.61203, 0.61203, 0.61213, 0.61218, 0.61227, 0.61226]

Als Nächstes werden die Modelle geladen (das feinabgestimmte Modell mit allen Parametern wird im Ordner gpt2_stock im aktuellen Verzeichnis gespeichert, das feinabgestimmte LoRA-Modell wird im Ordner gpt2_LORA_None im aktuellen Verzeichnis gespeichert) und die Inferenz ausgeführt. Anhand der Ergebnisse berechnen wir ihren MSE, RMSE und NRMSE. Diese Codes wurden bereits im vorigen Artikel vorgestellt, sodass sie hier nicht näher beschrieben werden.

import time
import pandas as pd
from transformers import GPT2LMHeadModel, GPT2Tokenizer, GPT2Config
from sklearn.metrics import mean_squared_error
import torch
import numpy as np
from peft import PeftModel
import matplotlib.pyplot as plt

# Load dataset
df = pd.read_csv('llm_data.csv')

# Set device (GPU or CPU)
dvc = 'cuda' if torch.cuda.is_available() else 'cpu'

# Define model paths
base_model = 'gpt2'
fine_tuning_path = './gpt2_stock'
lora_tuning_path = './gpt2_LORA_None'

# Initialize tokenizer and models
tokenizer = GPT2Tokenizer.from_pretrained(base_model)
model_fine_tuning = GPT2LMHeadModel.from_pretrained(fine_tuning_path).to(dvc)
model_lora_tuning = GPT2LMHeadModel.from_pretrained(base_model)
model_lora_tuning = PeftModel.from_pretrained(model_lora_tuning, lora_tuning_path).to(dvc)

# Extract input data and true prices
input_data = df.iloc[:, 1:20].values[-1]
true_prices = df.iloc[-1:, 21:].values.tolist()[0]

# Prepare prompt
prompt = ' '.join(map(str, input_data))

Wir kapseln den Prozess der Inferenz und der Berechnung von MSE, RMSE und NRMSE in einer Funktion „generater(model)“ und verwenden den vorhergesagten Wert, MSE, RMSE und NRMSE als Rückgabewerte. Wenn wir verschiedene Modelle für die Inferenzauswertung verwenden, geben wir das Modell einfach als Parameter an. An dieser Stelle sei darauf hingewiesen, dass die in unserer Funktion verwendete Variable true_prices eine globale Variable ist und wir ihren Wert in der Funktion ändern müssen. Daher sollten wir sie in der Funktion als globale Variable deklarieren, da sonst ein Fehler gemeldet wird.

def generater(model):
    global true_prices
    
    # Set the model to evaluation mode
    model.eval()
    
    # Tokenization and text generation using the model
    token = tokenizer.encode(prompt, return_tensors='pt').to(dvc)
    start_ = time.time()
    generated = tokenizer.decode(
        model.generate(token, do_sample=True, max_length=200)[0], 
        skip_special_tokens=True
    )
    end_ = time.time()
    
    print(f'Generate time: {end_ - start_} seconds')
    
    # Process the generated data
    generated_prices = generated.split('\n')[0]
    generated_prices = list(map(float, generated_prices.split()))
    generated_prices = generated_prices[:len(true_prices)]
    
    # Function to trim both lists to the same length
    def trim_lists(a, b):
        min_len = min(len(a), len(b))
        return a[:min_len], b[:min_len]
    
    # Trim the true_prices and generated_prices lists
    true_prices, generated_prices = trim_lists(true_prices, generated_prices)
    
    print(f"Input data: {input_data}")
    print(f"True prices: {true_prices}")
    print(f"Generated prices: {generated_prices}")
    
    # Calculate MSE, RMSE, NRMSE metrics
    mse = mean_squared_error(true_prices, generated_prices)
    print('MSE:', mse)
    
    rmse = np.sqrt(mse)
    nrmse = rmse / (np.max(true_prices) - np.min(generated_prices))
    
    print(f"RMSE: {rmse}, NRMSE: {nrmse}")
    
    return generated_prices, mse, rmse, nrmse
def generater(model):
    global true_prices
    
    # Set the model to evaluation mode
    model.eval()
    
    # Tokenization and text generation using the model
    token = tokenizer.encode(prompt, return_tensors='pt').to(dvc)
    start_ = time.time()
    generated = tokenizer.decode(
        model.generate(token, do_sample=True, max_length=200)[0], 
        skip_special_tokens=True
    )
    end_ = time.time()
    
    print(f'Generate time: {end_ - start_} seconds')
    
    # Process the generated data
    generated_prices = generated.split('\n')[0]
    generated_prices = list(map(float, generated_prices.split()))
    generated_prices = generated_prices[:len(true_prices)]
    
    # Function to trim both lists to the same length
    def trim_lists(a, b):
        min_len = min(len(a), len(b))
        return a[:min_len], b[:min_len]
    
    # Trim the true_prices and generated_prices lists
    true_prices, generated_prices = trim_lists(true_prices, generated_prices)
    
    print(f"Input data: {input_data}")
    print(f"True prices: {true_prices}")
    print(f"Generated prices: {generated_prices}")
    
    # Calculate MSE, RMSE, NRMSE metrics
    mse = mean_squared_error(true_prices, generated_prices)
    print('MSE:', mse)
    
    rmse = np.sqrt(mse)
    nrmse = rmse / (np.max(true_prices) - np.min(generated_prices))
    
    print(f"RMSE: {rmse}, NRMSE: {nrmse}")
    
    return generated_prices, mse, rmse, nrmse

Wir kapseln die Visualisierung des Inferenzergebnisses in eine Funktion „plot_(a, b, title)“:

def plot_(a, b, title):
    # Set up the figure size
    plt.figure(figsize=(10, 6))
    
    # Plot true_prices only if the title is 'prediction'
    if title == 'prediction':
        plt.plot(true_prices, label='True Values', marker='o')
    
    # Plot the fine-tuning and lora-tuning values
    plt.plot(a, label='fine_tuning', marker='x')
    plt.plot(b, label='lora_tuning', marker='s')
    
    # Set the title and labels for the axes
    plt.title(title)
    plt.xlabel('Index')
    plt.ylabel('Value')
    
    # Display the legend and save the plot to a file
    plt.legend()
    plt.savefig(f"{title}.png")

Kapseln wir die Effizienz des Modells und die bereits erwähnten Bewertungsmetriken in einer Funktion „groups_chart(a, b, models)“:

def groups_chart(a, b, models):
    # Define metrics for the chart
    metrics = ['Train Time(s)', 'Inference Time (s)', 'Memory Usage (GB)', 'MSE', 'RMSE', 'NRMSE']
    
    # Set figure size
    plt.figure(figsize=(10, 6))
    
    # Update values for model a and b
    a = [101.7946, 1.243, 5.67, a[1], a[2], a[3]]
    b = [69.5605, 0.877, 4.10, b[1], b[2], b[3]]
    
    # Bar width for each group of bars
    bar_width = 0.2
    
    # Set the positions of the bars
    r1 = np.arange(len(metrics))  # Positions for model a
    r2 = [x + bar_width for x in r1]  # Positions for model b
    
    # Plot bars for both models
    plt.bar(r1, a, color='r', width=bar_width, edgecolor='grey', label=models[0])
    plt.bar(r2, b, color='b', width=bar_width, edgecolor='grey', label=models[1])
    
    # Set log scale for y-axis
    plt.yscale('log')
    
    # Set labels and title
    plt.xlabel('Metrics', fontweight='bold')
    plt.xticks([r + bar_width / 2 for r in range(len(metrics))], metrics)  # Center the x-axis ticks
    plt.ylabel('Values (log scale)', fontweight='bold')
    plt.title('Model Comparison')
    
    # Display legend and save the plot
    plt.legend()
    # plt.show()  # Uncomment to display the plot
    plt.savefig('Comparison.png')

Anmerkung:

Das Problem dabei ist, dass die Größenordnung der von uns gemessenen Metriken nicht die gleiche ist, daher verwende ich hier eine logarithmische Skala :plt.yscale('log'). Auf diese Weise ist es möglich, Situationen, in denen die Datenmenge stark schwankt, effektiv zu bewältigen.

Verschiedene Modelle führen die Inferenz separat durch:

fine_tuning_result = generater(model_fine_tuning)
lora_tuning_result = generater(model_lora_tuning)

Die Ergebnisse der Inferenz des Vollparameter-Feinabstimmungsmodells:

  • generierte Preise:[0.61163, 0.61162, 0.61191, 0.61195, 0.61209, 0.61231, 0.61224, 0.61207, 0.61187, 0.61184, 0.6119, 0.61169, 0.61168, 0.61162, 0.61181, 0.61184, 0.61184, 0.6118, 0.61176, 0.61183, 0.61185, 0.61217, 0.61221, 0.61223, 0.61226, 0.61231, 0.61231, 0.61229, 0.61235, 0.61237, 0.61241, 0.61243, 0.61248, 0.61253, 0.61263, 0.61265, 0.61267, 0.61271, 0.61267, 0.61272]
  • MSE: 1.0064750000000609e-07
  • RMSE:0.0003172499014972362
  • NRMSE:0.3965623768715889

Ergebnisse der LoRA-Tuning-Modell-Inferenz:

  • generierte Preise:[0.61163, 0.61162, 0.61191, 0.61195, 0.61209, 0.61231, 0.61224, 0.61207, 0.61187, 0.61184, 0.6119, 0.61169, 0.61168, 0.61162, 0.61181, 0.61184, 0.61184, 0.6118, 0.61176, 0.6116, 0.6116, 0.61194, 0.6118, 0.61195, 0.61197, 0.61196, 0.6123, 0.61181, 0.61172, 0.6119, 0.61155, 0.61149, 0.61197, 0.61198, 0.61192, 0.61136, 0.61092, 0.61091, 0.61098, 0.61099]
  • MSE: 2.3278249999999242e-07
  • RMSE:0.00048247538797330626
  • NRMSE:0.3195201244856309

Die Ergebnisse visualisieren und als Bilder speichern:

plot_(fine_tuning_result[0],lora_tuning_result[0],title='predication')
groups_chart(fine_tuning_result,lora_tuning_result,models=['fine-tuning','lora-tuning'])

Chart-Visualisierung zum Vergleich:

pre

cmp

Anmerkung:

Ich habe das Skript viele Male zu Testzwecken ausgeführt, und die Ergebnisse sind bei jedem Durchlauf anders. Die von mir angegebenen Daten und Charts dienen also nur als Referenz, und es ist normal, dass Ihre Ergebnisse von meinen abweichen.

3. Die Wahl des richtigen Modells

Unter dem Gesichtspunkt der Effizienz ist es klar, dass die LoRA-Feinabstimmung im Vergleich zur Feinabstimmung mit allen Parametern in Bezug auf die Trainingsgeschwindigkeit, die Inferenzgeschwindigkeit und die Speichernutzung überlegen ist. Als Nächstes vergleichen wir die Genauigkeit der Schlussfolgerungen. Aus unseren Charts geht intuitiv hervor, dass die Ergebnisse der beiden Modelle bei den ersten 18 vorhergesagten Werten fast gleich sind, während der Fehler bei den übrigen Werten allmählich zunimmt. Die Vorhersagen des feinabgestimmten Modells mit allen Parametern sind insgesamt relativ stabil, wie die NRMSE-Werte zeigen.

Ich habe versucht, das Skript test.py mehrere Male auszuführen, um zu sehen, ob die Ergebnisse konsistent sind. Die Ergebnisse variierten, wobei der NRMSE des feinabgestimmten LoRA-Modells manchmal klein war (etwa 0,17, viel niedriger als der NRMSE des feinabgestimmten Modells mit vollständigen Parametern) und manchmal riesig (bis zu 0,76688). Der fein abgestimmte NRMSE für alle Parameter blieb stabil bei 0,4. Es ist wichtig anzumerken, dass diese Daten nicht notwendigerweise bedeuten, dass das feinabgestimmte Modell mit vollständigen Parametern besser abschneidet als das feinabgestimmte LoRA-Modell. Es ist möglich, dass das LoRA-Tuning nicht mit den gleichen Trainingseinstellungen konvergiert wie das Full-Parameter-Feintuning. Eine bessere Lösung ist die Konfiguration einer geeigneten Logik zum frühzeitigen Stoppen auf der Grundlage des Verlusts während des Trainings, um die Konvergenz des Modells sicherzustellen. Dieser Teil des Inhalts wird im Codebeispiel vorerst nicht bereitgestellt, aber interessierte Leser können ihn selbst implementieren.

Natürlich können sich auch unterschiedliche Einstellungen der Modellparameter auf die Leistung des Modells auswirken. Daher sollte ein wissenschaftlicherer Ansatz darin bestehen, zunächst die optimalen Parametereinstellungen für ein Modell oder eine Trainingsmethode auf demselben Datensatz zu finden und sicherzustellen, dass das Modell unter den optimalen Einstellungen konvergiert. Führen Sie dann einen horizontalen Vergleich verschiedener Trainingsmethoden oder -modelle durch, bewerten Sie verschiedene Metriken umfassend und wählen Sie die optimale Trainingsmethode oder das optimale Modell aus.

Das vollständige Testcode-Skript ist „test.py“:

import time
import pandas as pd
from transformers import GPT2LMHeadModel, GPT2Tokenizer, GPT2Config
from sklearn.metrics import mean_squared_error
import torch
import numpy as np
from peft import PeftModel
import matplotlib.pyplot as plt

# Load the dataset
df = pd.read_csv('llm_data.csv')

# Define the device (GPU if available)
dvc = 'cuda' if torch.cuda.is_available() else 'cpu'

# Model paths and base settings
base_model = 'gpt2'
fine_tuning_path = './gpt2_stock'
lora_tuning_path = './gpt2_LORA_None'

# Load the tokenizer and models
tokenizer = GPT2Tokenizer.from_pretrained(base_model)
model_fine_tuning = GPT2LMHeadModel.from_pretrained(fine_tuning_path).to(dvc)
model_lora_tuning = GPT2LMHeadModel.from_pretrained(base_model)
model_lora_tuning = PeftModel.from_pretrained(model_lora_tuning, lora_tuning_path).to(dvc)

# Extract the input data and true prices from the dataset
input_data = df.iloc[:, 1:20].values[-1]
true_prices = df.iloc[-1:, 21:].values.tolist()[0]
prompt = ' '.join(map(str, input_data))

# Function to generate predictions
def generater(model):
    global true_prices
    model.eval()
    
    # Tokenization and text generation
    token = tokenizer.encode(prompt, return_tensors='pt').to(dvc)
    start_ = time.time()
    generated = tokenizer.decode(
        model.generate(token, do_sample=True, max_length=200)[0], 
        skip_special_tokens=True
    )
    end_ = time.time()
    
    print(f'Generate time: {end_ - start_}')
    
    # Processing generated prices
    generated_prices = generated.split('\n')[0]
    generated_prices = list(map(float, generated_prices.split()))
    generated_prices = generated_prices[:len(true_prices)]
    
    # Function to trim lists to the same length
    def trim_lists(a, b):
        min_len = min(len(a), len(b))
        return a[:min_len], b[:min_len]
    
    # Trim the true prices and generated prices
    true_prices, generated_prices = trim_lists(true_prices, generated_prices)
    
    # Output metrics
    print(f"Input data: {input_data}")
    print(f"True prices: {true_prices}")
    print(f"Generated prices: {generated_prices}")
    
    mse = mean_squared_error(true_prices, generated_prices)
    print('MSE:', mse)
    
    rmse = np.sqrt(mse)
    nrmse = rmse / (np.max(true_prices) - np.min(generated_prices))
    
    print(f"RMSE: {rmse}, NRMSE: {nrmse}")
    
    return generated_prices, mse, rmse, nrmse

# Function to plot the comparison between true prices and predictions
def plot_(a, b, title):
    plt.figure(figsize=(10, 6))
    
    if title == 'prediction':
        plt.plot(true_prices, label='True Values', marker='o')
    
    plt.plot(a, label='fine_tuning', marker='x')
    plt.plot(b, label='lora_tuning', marker='s')
    
    plt.title(title)
    plt.xlabel('Index')
    plt.ylabel('Value')
    plt.legend()
    plt.savefig(f"{title}.png")

# Function to generate a bar chart comparing different metrics between models
def groups_chart(a, b, models):
    metrics = ['Train Time(s)', 'Inference Time (s)', 'Memory Usage (GB)', 'MSE', 'RMSE', 'NRMSE']
    plt.figure(figsize=(10, 6))
    
    # Data for the metrics
    a = [101.7946, 1.243, 5.67, a[1], a[2], a[3]]
    b = [69.5605, 0.877, 4.10, b[1], b[2], b[3]]
    
    bar_width = 0.2
    r1 = np.arange(len(metrics))
    r2 = [x + bar_width for x in r1]
    
    # Plotting bars for both models
    plt.bar(r1, a, color='r', width=bar_width, edgecolor='grey', label=models[0])
    plt.bar(r2, b, color='b', width=bar_width, edgecolor='grey', label=models[1])
    
    # Set y-axis to log scale for better visibility of differences
    plt.yscale('log')
    
    plt.xlabel('Metrics', fontweight='bold')
    plt.xticks([r + bar_width for r in range(len(metrics))], metrics)
    plt.ylabel('Values (log scale)', fontweight='bold')
    plt.title('Model Comparison')
    plt.legend()
    plt.savefig('Comparison.png')

# Generate results for both fine-tuned and LORA-tuned models
fine_tuning_result = generater(model_fine_tuning)
lora_tuning_result = generater(model_lora_tuning)

# Plot the prediction comparison
plot_(fine_tuning_result[0], lora_tuning_result[0], title='prediction')

# Generate the comparison chart for the models
groups_chart(fine_tuning_result, lora_tuning_result, models=['fine-tuning', 'lora-tuning'])


Schlussfolgerung

In diesem Artikel haben wir erörtert, wie das vortrainierte GPT-2-Modell mit Hilfe der LoRA-Tuning-Methode feinabgestimmt werden kann, und die vorgestellten Feinabstimmungsmethoden verglichen. So können wir intuitiv die Trainingsmethode und das Modell wählen, das am besten zu unserer Handelsstrategie passt. Natürlich werden wir weiterhin weitere Feinabstimmungsmethoden diskutieren und diese Methoden zur Feinabstimmung des vortrainierten GPT-2-Modells verwenden, um genauere Feinabstimmungsmethoden für unsere Handelsstrategie zu finden. In Anbetracht der Parameterskala des vortrainierten GPT-2-Modells kann das Endergebnis erheblich vom idealen Ergebnis abweichen, aber der Prozess der Suche nach dem Endergebnis ist derselbe. Sie fragen sich vielleicht, warum nicht horizontale Vergleiche zwischen verschiedenen Modellen? Das ist eine gute Frage, aber es gibt so viele Modelle, aus denen man wählen kann, und selbst ein und dasselbe Modell kann unterschiedliche Parameterskalen haben. Es ist klar, dass wir diese Aufgabe nicht mit ein paar einfachen Beispielen lösen können. Dies ist ein sehr mühsamer, aber nicht komplexer Prozess. Ich schlage daher vor, anhand der Methodenbeispiele in diesem Artikel zu untersuchen, wie man die besten Ergebnisse unter den verschiedenen Modellen finden kann.

Sind Sie bereit, weiter zu forschen? Wir sehen uns im nächsten Artikel!

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/13499

Beigefügte Dateien |
llm_data.csv (1139.04 KB)
train.txt (1123.41 KB)
lora-tuning.py (2.64 KB)
test.py (3.23 KB)
Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls
In diesem Artikel werden wir uns ansehen, wie wir das erste einer Reihe von wirklich funktionalen Modulen für die Verwendung im Replay-/Simulatorsystem zusammenstellen, die auch für andere Zwecke geeignet sein werden. Die Rede ist vom Mausmodul.
Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II) Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II)
In dieser Diskussion werden wir die bestehende Dialogbibliothek sorgfältig erweitern, um die Logik der Verwaltung der Farbmodi (Theme) zu integrieren. Darüber hinaus werden wir Methoden für den Theme-Wechsel in die Klassen CDialog, CEdit und CButton integrieren, die in unserem Admin-Panel-Projekt verwendet werden. Lesen Sie weiter für weitere aufschlussreiche Perspektiven.
Neuronale Netze leicht gemacht (Teil 94): Optimierung der Eingabereihenfolge Neuronale Netze leicht gemacht (Teil 94): Optimierung der Eingabereihenfolge
Wenn wir mit Zeitreihen arbeiten, verwenden wir die Quelldaten immer in ihrer historischen Reihenfolge. Aber ist das die beste Option? Es besteht die Meinung, dass eine Änderung der Reihenfolge der Eingabedaten die Effizienz der trainierten Modelle verbessern wird. In diesem Artikel lade ich Sie ein, sich mit einer der Methoden zur Optimierung der Eingabereihenfolge vertraut zu machen.
Ordinale Kodierung für Nominalvariablen Ordinale Kodierung für Nominalvariablen
In diesem Artikel erörtern und demonstrieren wir, wie man nominale Prädiktoren in numerische Formate umwandelt, die für Algorithmen des maschinellen Lernens geeignet sind, und zwar sowohl mit Python als auch mit MQL5.