Neuronale Netze im Trading: Hierarchische Entdeckung von Skills für adaptives Agentenverhalten (HiSSD)
Einführung
Kooperatives Multi-Agent Reinforcement Learning (MARL) hat in den letzten Jahren zunehmend an Bedeutung gewonnen. Das Konzept hat Anwendungen in einer Vielzahl von Bereichen gefunden, von Gaming und autonomem Transport bis hin zu Logistik, sozialer Dynamik und vor allem Finanzmärkten. Wo immer koordiniertes Verhalten zwischen mehreren Strategien oder Agenten erforderlich ist, stoßen traditionelle Methoden oft an ihre Grenzen. In solchen Szenarien hat MARL bemerkenswerte Ergebnisse erzielt.
Dennoch bleiben eine Reihe von Herausforderungen bestehen. Die Entwicklung genauer Simulatoren oder die Aufrechterhaltung einer kontinuierlichen Online-Interaktion mit der Umgebung erfordert erhebliche Ressourcen. In realen Umgebungen müssen Agenten unter sich ständig ändernden Bedingungen agieren: Die Anzahl der Teilnehmer kann variieren, Ziele verändern sich und Umgebungsparameter verschieben sich im Laufe der Zeit. Infolgedessen wächst das Interesse an der Entwicklung von Systemen, die sich anpassen und Wissen so effizient wie möglich und ohne zusätzliche Kosten von einer Aufgabe auf eine andere übertragen können.
Der konventionelle Ansatz besteht darin, Agenten für eine Aufgabe zu trainieren und sie dann für eine andere feinabzustimmen. Diese Strategie hat jedoch mehrere Nachteile. Erstens erfordert sie eine kostspielige erneute Interaktion mit der neuen Umgebung. Zweitens skaliert ein Modell, das für eine feste Anzahl von Agenten trainiert wurde, nicht effektiv. Seine Leistung verschlechtert sich, wenn sich die Zusammensetzung der Agenten oder die Aufgabenparameter ändern.
Um diese Probleme anzugehen, begannen Forscher, Transformer-basierte Architekturen einzusetzen. Sie bieten eine größere Flexibilität: Das Modell ist nicht mehr an eine feste Anzahl von Agenten gebunden und kann sich an neue Bedingungen anpassen. Dies legte den Grundstein für die Entwicklung universeller kooperativer Verhaltensmuster – Skills (Fertigkeiten), die aufgabenübergreifend übertragen und in verschiedenen Umgebungen wiederverwendet werden können.
Zahlreiche Ansätze wurden für die Implementierung solcher Skills vorgeschlagen. Einige stützen sich auf einen zweistufigen Trainingsprozess, bei dem zunächst allgemeine Verhaltensmuster extrahiert und dann zum Erlernen einer Strategie verwendet werden. Andere kombinieren Offline- und Online-Lernen, was die Anpassung an neue Umgebungen beschleunigt.
Diese Methoden haben zu signifikanten Verbesserungen geführt, insbesondere bei der Senkung der Kosten für die Übertragung von Modellen auf verwandte Aufgaben. Sie haben jedoch auch Einschränkungen. Während allgemeine Skills nützlich sind, übersehen sie oft aufgabenspezifische Merkmale, die zum Erreichen bestimmter Ziele erforderlich sind. Doch der Erfolg liegt häufig genau in diesen Details. Darüber hinaus vernachlässigen viele Ansätze die zeitliche Struktur von Interaktionen. Zusammenarbeit entsteht nicht augenblicklich – sie entwickelt sich im Laufe der Zeit. Die Abfolge von Aktionen und die Konsistenz der Koordination sind beide von entscheidender Bedeutung.
Zur Lösung dieser Probleme stellt der Artikel „Learning Generalizable Skills from Offline Multi-Task Data for Multi-Agent Cooperation“ das Framework HiSSD (Hierarchical and Separable Skill Discovery) vor. Diese neuartige Architektur ermöglicht das gleichzeitige Erlernen sowohl allgemeiner als auch aufgabenspezifischer Skills ohne künstliche Trennung und ohne starre Einschränkungen. In der hierarchischen Struktur entwickeln sich beide Wissenskategorien parallel.
Allgemeine Skills erfassen universelle Muster der Zusammenarbeit. Sie ermöglichen es Agenten, auch in unbekannten Umgebungen koordiniert zu agieren. Diese Skills bilden die Grundlage des Agentenverhaltens – eine Reihe von Reaktionen, die in einem breiten Spektrum von Situationen anwendbar sind. Aufgabenspezifische Skills sind hingegen auf konkrete Aufgaben zugeschnitten. Sie ermöglichen präzise Verhaltensanpassungen basierend auf Zielen und Umgebungsbedingungen.
Die Kernidee hinter HiSSD ist das gleichzeitige hierarchische Lernen. Dieser Ansatz bietet ein tieferes Verständnis sowohl für die zeitlichen Aspekte von Interaktionen als auch für den Kontext spezifischer Aufgaben. Infolgedessen verbessert er nicht nur die Qualität des Agentenverhaltens, sondern erleichtert auch den zuverlässigen Transfer erlernter Strategien auf neue Umgebungen.
Die von den Autoren des Frameworks durchgeführten Experimente an den populären Benchmarks von SMAC und MuJoCo bestätigten die Effektivität des Ansatzes. Selbst bei zuvor unbekannten Aufgaben zeigten Agenten, die mit HiSSD trainiert wurden, ein starkes kooperatives Verhalten. Ihre Strategien erwiesen sich als flexibel, präzise und robust.
Der Algorithmus HiSSD
Der Algorithmus HiSSD (Hierarchical and Separable Skill Discovery) ist ein innovativer Ansatz zum Training von Agenten in Multi-Agenten-Umgebungen, der darauf ausgelegt ist, den Transfer von Skills über verschiedene Aufgaben hinweg zu ermöglichen und gleichzeitig ein robustes Verhalten in dezentralen Umgebungen aufrechtzuerhalten. Die zentrale Idee des Algorithmus besteht darin, das Verhalten jedes Agenten hierarchisch in zwei Schlüsselkomponenten zu zerlegen: gemeinsame Skills, die über Agenten und Aufgaben hinweg geteilt werden, und aufgabenspezifische Skills, die es ermöglichen, das Verhalten an eine bestimmte Rolle oder ein bestimmtes Ziel anzupassen.
Einer der Hauptunterschiede zwischen HiSSD und vielen bestehenden Ansätzen ist die Fähigkeit, alle Modellkomponenten gleichzeitig zu trainieren. Anstatt sequenzielles oder stufenweises Training einzusetzen, werden alle Module, einschließlich Planer, Controller, Encoder und Zustandswertmodell, gemeinsam optimiert. Dieser synchronisierte Trainingsprozess reduziert Inkonsistenzen zwischen den Hierarchieebenen und fördert ein kohärenteres und effektiveres Agentenverhalten.
Das Training erfolgt unter Verwendung eines Offline-Datensatzes DT = {Di}, wobei jedes Di einer separaten Aufgabe entspricht. Zu jedem Zeitschritt erhält Agent k eine Beobachtung ot,k. Basierend auf dieser Beobachtung generiert der Planer einen gemeinsamen Skill ct,k:
![]()
Dieser Skill repräsentiert eine übergeordnete Absicht und einen allgemeinen strategischen Verhaltensplan. Anschließend generiert der aufgabenspezifische Skill-Encoder gω aus denselben Beobachtungen einen aufgabenspezifischen Skill zt,k:
![]()
Der gemeinsame und der aufgabenspezifische Skill werden dann an den Controller weitergegeben, der sie mit der aktuellen Beobachtung kombiniert, um die Aktion des Agenten zu bestimmen:
![]()
Das Wertmodell der Umgebung wird mit einer modifizierten Version von Implicit Q-Learning (IQL) trainiert, die für Multi-Agenten-Umgebungen angepasst wurde. Der Zustandswert wird mithilfe der kollektiven Belohnung geschätzt, die alle Agenten erhalten:

wobei der gestutzte quadratische Fehler verwendet wird:
![]()
Basierend auf der Schätzung des Zustandswerts durch das Modell wird ein Planer trainiert. Sein Hauptziel ist die Auswahl von High-Level-Skills, die zu den vorteilhaftesten zukünftigen Zuständen führen. Dies wird durch die Minimierung einer Verlustfunktion erreicht, die sowohl den Wert des nächsten Zustands als auch die Wahrscheinlichkeit des vorhergesagten Zustands berücksichtigt:

Eine exponentielle Form der Verlustfunktion kann ebenfalls verwendet werden:

Der Controller und der aufgabenspezifische Skill-Encoder werden mithilfe eines variationalen Autoencoders für die Verhaltenskodierung trainiert. Die Kernidee besteht darin, den Controller darauf zu trainieren, Aktionen aus Demonstrationen zu reproduzieren und dabei die latente Struktur der Aufgaben zu berücksichtigen. Der Verlust umfasst die Log-Likelihood der Aktion sowie einen Regularisierungsterm in Form der Divergenz KL:
![]()
Um sicherzustellen, dass die Skills des Agenten über Aufgaben hinweg wirklich differenziert sind, wird zusätzlich kontrastives Lernen eingesetzt. Der Encoder wird so trainiert, dass für jede Aufgabe die Repräsentation gω(q) näher an positiven Beispielen k+ aus derselben Aufgabe liegt als an negativen Beispielen k- aus anderen Aufgaben:

wobei σ der Temperaturkoeffizient ist und gω† eine exponentiell geglättete Version des Encoders bezeichnet, die zur Stabilisierung des Trainings verwendet wird.
Die endgültige Verlustfunktion für den Controller kombiniert sowohl verhaltensbezogene als auch kontrastive Komponenten.
Als Ergebnis bildet HiSSD ein leistungsstarkes System, in dem alle Verhaltensebenen – von der strategischen Planung bis hin zu niedrigstufigen Taktiken – koordiniert trainiert werden und effektiv unter dezentraler Steuerung arbeiten.
Nachfolgend ist die von den Autoren erstellte Visualisierung des HiSSD-Frameworks dargestellt.

Die Implementierung in MQL5
Nachdem wir die theoretischen Grundlagen des Frameworks HiSSD erläutert haben, gehen wir nun zum praktischen Teil des Artikels über, in dem wir unsere Interpretation der vorgeschlagenen Methoden mit MQL5 umsetzen.
Kernprinzipien des Modelldesigns
Bevor wir zu den Implementierungsdetails übergehen, ist es wichtig, einige Schlüsselprinzipien zu skizzieren, die die Grundlage unserer Lösung bilden werden.
Zunächst ist anzumerken, dass das Framework HiSSD für Multi-Agenten-Lernen konzipiert ist. Dies unterscheidet sich von unserer Aufgabe, die sich auf das Erlernen einer Handelsstrategie für ein einzelnes Finanzinstrument konzentriert. Dieses Paradigma hat jedoch ein erhebliches Potenzial im Kontext der Multi-Task-Natur realer Finanzmärkte. Wir können die vorgeschlagene hierarchische Struktur erweitern, indem wir mehrere unabhängige Agenten trainieren, von denen jeder eine spezifische Teilmenge von Marktinformationen analysiert und prognostiziert. Um den endgültigen Entscheidungsprozess kohärenter und effektiver zu gestalten, führen wir ein übergeordnetes Manager-Modell ein, das Vorschläge verschiedener Agenten aggregiert und die optimale Strategie auswählt. Solche Multi-Task-Systeme sind in der künstlichen Intelligenz gut etabliert, und ihre Anwendung auf Finanzmärkte ermöglicht den effektiven Umgang mit vielfältigen Faktoren und Risiken.
Der zweite wichtige Aspekt ist, dass innerhalb des Frameworks HiSSD jeder Agent Aktionen auf der Grundlage lokaler Beobachtungen generiert. Auf Finanzmärkten, wo Kursdaten, Handelsvolumina und andere Indikatoren jedoch stark voneinander abhängig sind, bedarf diese Annahme einer Verfeinerung. Wir können jeden Agenten mit einer dedizierten univariaten Sequenz ausstatten, die aus einer multimodalen Zeitreihe von Rohmarktdaten extrahiert wurde. Gleichzeitig sind Marktvariablen oft korreliert. Zum Beispiel können Kursänderungen bei einem Vermögenswert andere beeinflussen. Um dies anzugehen, führen wir einen Datenanreicherungsmechanismus ein, der es jedem Agenten ermöglicht, auf gemeinsames Wissen über den Gesamtzustand des Marktes zuzugreifen, was fundiertere Entscheidungen ermöglicht.
Schließlich ist es wichtig, die Modularität hervorzuheben, die den Kern des Frameworks HiSSD bildet. Dieses Design ist besonders gut für komplexe Multi-Task-Systeme geeignet. Die Architektur kann in mehrere Komponenten zerlegt werden, von denen jede für ein separates Problem zuständig ist. Modularität ermöglicht nicht nur die effiziente Optimierung einzelner Komponenten, sondern erlaubt es dem System auch, sich flexibel an veränderte Marktbedingungen anzupassen. In unserem Fall ist dies besonders wertvoll, da Finanzmärkte hochdynamisch sind und die Fähigkeit, einzelne Teile des Modells schnell zu ändern oder zu verbessern, für erfolgreiches Handeln entscheidend sein kann.
Skill-Encoder
Das erste Modul, mit dem wir beginnen, ist der Skill-Encoder. Hier heben wir sofort ein wichtiges architektonisches Merkmal des Frameworks HiSSD hervor: Sowohl allgemeine als auch aufgabenspezifische Skills werden aus derselben Informationsquelle abgeleitet. Dies sind die lokalen Beobachtungen des Agenten. In unserem Fall entspricht dies univariaten Sequenzen, die aus einer multimodalen Zeitreihe extrahiert wurden, welche den Zustand der Umgebung repräsentiert.
Aufgrund dieser Eigenschaft haben wir uns entschieden, ein einheitliches architektonisches Design für beide Teilaufgaben zu verwenden. Dieser Ansatz hat mehrere Vorteile. Erstens vereinfacht es das Modelldesign und das Debugging. Zweitens ermöglicht es eine konsistente Methodik zur Bewertung der Merkmalsqualität. Schließlich reduziert die Wiederverwendung architektonischer Komponenten den Entwicklungsaufwand und erleichtert die Skalierung bei der Erweiterung des Modells auf neue Aufgaben oder Finanzinstrumente.
Der Skill-Encoder ist innerhalb des Objekts CNeuronSkillsEncoder implementiert, dessen Struktur unten dargestellt ist.
class CNeuronSkillsEncoder : public CNeuronSoftMaxOCL { protected: CNeuronCATCH cCrossObservAttention; CNeuronTransposeOCL cTranspose; CNeuronConvOCL cSkillsProjection[2]; CNeuronBaseOCL cPrevSkillsConcat; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer) override; public: CNeuronSkillsEncoder(void) {}; ~CNeuronSkillsEncoder(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint time_step, uint variables, uint skills, uint window, uint step, uint window_key, uint heads, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronSkillsEncoder; } //--- virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual void SetOpenCL(COpenCLMy *obj) override; };
Diese Struktur umfasst mehrere interne Komponenten, von denen jede eine spezifische Rolle erfüllt. Ihre Funktionsweise wird bei der Implementierung der Klassenmethoden ausführlich beschrieben. Wichtig ist jetzt, dass alle Objekte als statisch deklariert werden. Dadurch können wir den Konstruktor und Destruktor der Klasse leer lassen. Die Initialisierung aller internen Objekte wird in der Methode Init durchgeführt.
bool CNeuronSkillsEncoder::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint time_step, uint variables, uint skills, uint window, uint step, uint window_key, uint heads, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronSoftMaxOCL::Init(numOutputs, myIndex, open_cl, variables * skills, optimization_type, batch)) return false; SetHeads(variables);
Die Init-Methode empfängt eine Reihe von Konstanten, die die Architektur des konstruierten Objekts eindeutig definieren. Die meisten dieser Parameter sind aus früheren Arbeiten bereits bekannt und werden hier nicht im Detail beschrieben.
Im Methodenkörper rufen wir zunächst die entsprechende übergeordnete Klassenmethode auf, die bereits die minimal erforderlichen Kontrollpunkte sowie die Initialisierung der geerbten Komponenten und Schnittstellen implementiert.
Als übergeordnete Klasse verwenden wir die Funktionsschicht SoftMax. Dies ermöglicht es uns, die Ausgaben der Skill-Encoder einzelner Agenten zu normalisieren und sie auf eine vergleichbare Skala zu bringen. Die Anzahl der Skills pro Agent wird durch den Parameter skills definiert. Dementsprechend hat der vom Modul erzeugte Ausgabevektor diese Länge für jeden Agenten, wobei jedes Element die Bedeutung eines bestimmten Skills darstellt.
In unserem Aufbau entspricht die Anzahl der Agenten der Anzahl der univariaten Sequenzen in der multimodalen Zeitreihe. Dieser Wert wird daher als Anzahl der Normalisierungsköpfe SoftMax verwendet.
Nach erfolgreichem Abschluss der übergeordneten Initialisierung fahren wir mit der Initialisierung der neu eingeführten internen Komponenten fort. Die erste davon ist das Informationsaustauschmodul zwischen univariaten Sequenzen. In diesem Experiment wird diese Rolle von der zuvor entwickelten Framework-Komponente CATCH erfüllt.
int index = 0; if(!cCrossObservAttention.Init(0, index, OpenCL, time_step, variables, window, step, window_key, heads, optimization, iBatch)) return false;
Zur Erinnerung: Dieses Modul gleicht univariate Sequenzen im Frequenzbereich ab. Die Spektralzerlegung wird in Segmente unterteilt und die Analyse erfolgt innerhalb einzelner Frequenzbänder. Dieser Ansatz ermöglicht eine flexiblere Darstellung des Verhaltens von Marktsignalen. Anstatt das gesamte Frequenzspektrum als Ganzes zu analysieren, konzentrieren wir uns auf spezifische Bereiche. Dies ist besonders wichtig im Kontext der Finanzmärkte, wo hoch- und niederfrequente Schwankungen grundlegend unterschiedliche Informationen vermitteln können: Hochfrequente Komponenten spiegeln typischerweise kurzfristige Volatilität und Rauschen wider, während niederfrequente Komponenten Trends und langfristige Muster erfassen.
Dies ermöglicht die Entdeckung gemeinsamer Muster – wie Synchronität, Phasenverschiebungen und Korrelationen –, die dann als zusätzliche Informationen bei der Bildung von Skills verwendet werden können.
Wichtig ist, dass der Informationsaustausch nicht direkt erfolgt, sondern über einen maskierten Aufmerksamkeitsmechanismus. Dies verhindert einen übermäßigen Einfluss zwischen den Agenten und bewahrt die Dezentralisierung. Infolgedessen arbeitet jeder Agent weiterhin mit seiner eigenen univariaten Sequenz, während er gleichzeitig globale Muster auf Marktebene einbezieht.
Die Ausgabe des Moduls CATCH ist dieselbe multimodale Zeitreihe, jedoch angereichert mit kanalübergreifenden Abhängigkeiten.
Als Nächstes erhält jeder Agent seine entsprechende univariate Sequenz. Um die Daten in eine geeignetere Darstellung zu transformieren, wird eine Transpositionsschicht angewendet.
index++; if(!cTranspose.Init(0, index, OpenCL, time_step, variables, optimization, iBatch)) return false;
Danach werden unabhängige Heads verwendet, um den Skill-Vektor jedes Agenten zu generieren. Hier verwenden wir zwei sequentielle Faltungsschichten.
Es ist wichtig zu beachten, dass die Länge der analysierten Sequenz erheblich variieren kann. Die Verarbeitung der gesamten Sequenz in einem einzigen Block kann daher rechenintensiv sein. Um dies zu bewältigen, wird die Sequenz zunächst in Segmente unterteilt und die Dimensionalität mithilfe einer Faltungsschicht angepasst.
uint count = (time_step - window + step - 1) / step; if(count <= 1) { window = time_step; count = 1; } //--- index++; if(!cSkillsProjection[0].Init(0, index, OpenCL, window, step, window_key, count, variables, optimization, iBatch)) return false; cSkillsProjection[0].SetActivationFunction(SoftPlus);
Die zweite Faltungsschicht aggregiert dann alle Segmente, die einer bestimmten univariaten Sequenz entsprechen, und erzeugt einen einzelnen Skill-Vektor für jeden Agenten. Dies wird durch die Dimension „1“ der Sequenzlänge angezeigt.
index++; if(!cSkillsProjection[1].Init(0, index, OpenCL, window_key * count, window_key * count, skills, 1, variables, optimization, iBatch)) return false; cSkillsProjection[1].SetActivationFunction(None);
Es ist wichtig zu betonen, dass die Parameter der Faltungsschicht explizit die Anzahl der vom Modell verarbeiteten unabhängigen univariaten Sequenzen definieren. Dies ermöglicht es jedem Agenten, seine eigene Faltungskopie mit einem eindeutigen Satz von Gewichten beizubehalten. Gleichzeitig analysiert jeder Agent seinen eigenen lokalen Teil der multimodalen Zeitreihe.
Mit anderen Worten: Ein Agent beobachtet nicht einfach nur eindeutige Daten – er konzentriert sich auf eine eingeschränkte Teilmenge von Informationen. Dies bringt das Modell näher an reale Finanzmärkte, in denen jeder Händler (oder in unserem Fall Agent) mit unterschiedlichen Informationsquellen arbeitet und seine Entscheidungen entsprechend trifft.
Als Ergebnis erhalten wir nicht nur parallele Ausführungsinstanzen einer einzelnen Aufgabe, sondern ein koordiniertes Ensemble spezialisierter Agenten, von denen jeder in seiner eigenen Umgebung lernt, seine eigene Marktdarstellung bildet und seine eigene Verhaltensstrategie entwickelt. Dieses Design erhöht die Systemrobustheit, verbessert die Verhaltensvielfalt und ermöglicht die Kombination lokaler Strategien zur Erreichung eines globalen Ziels: effizienter und adaptiver Handel unter Unsicherheit.
Als Nächstes initialisieren wir ein zusätzliches Objekt, dessen Größe das Doppelte des Ausgabetensors beträgt. Wir werden seine Rolle später während der Implementierung der Methode zur Verteilung des Fehlergradienten diskutieren.
index++; if(!cPrevSkillsConcat.Init(0, index, OpenCL, 2 * Neurons(), optimization, iBatch)) return false; cPrevSkillsConcat.SetActivationFunction((ENUM_ACTIVATION)cSkillsProjection[1].Activation()); //--- return true; }
Nachdem alle internen Objekte initialisiert wurden, wird die Init-Methode beendet und ein logischer Erfolgsstatus an das aufrufende Programm zurückgegeben.
Der nächste Entwicklungsschritt ist die Implementierung der Algorithmen für den Vorwärtsdurchlauf in der Methode feedForward. Wie erwartet ist der Prozess relativ unkompliziert und linear.
bool CNeuronSkillsEncoder::feedForward(CNeuronBaseOCL *NeuronOCL) { if(!cCrossObservAttention.FeedForward(NeuronOCL)) return false;
Die Methode empfängt einen Zeiger auf das multimodale Eingabedatenobjekt, das sofort an das interne Modul für kanalübergreifende Abhängigkeiten weitergeleitet wird.
if(!cTranspose.FeedForward(cCrossObservAttention.AsObject())) return false;
Die resultierende Ausgabe wird dann transponiert und an den Block zur Generierung des Skill-Tensors weitergeleitet.
if(!cSkillsProjection[0].FeedForward(cTranspose.AsObject())) return false;
An dieser Stelle muss ein wichtiges Detail hervorgehoben werden. Vor dem Aufruf des Vorwärtsdurchlaufs der zweiten Faltungsschicht tauschen wir die Pufferzeiger aus, in denen die Zwischenergebnisse gespeichert sind. Diese einfache Operation ermöglicht es uns, zuvor berechnete Ausgaben zu bewahren. Die Bedeutung dieses Details wird während der Implementierung der Backpropagation erläutert.
if(!cSkillsProjection[1].SwapOutputs() || !cSkillsProjection[1].FeedForward(cSkillsProjection[0].AsObject())) return false; //--- return CNeuronSoftMaxOCL::feedForward(cSkillsProjection[1].AsObject()); }
Der resultierende Skill-Tensor wird dann mithilfe der Elternklasse in einen Wahrscheinlichkeitsraum abgebildet, woraufhin die Methode abgeschlossen wird und ein Erfolgs-Flag an den Aufrufer zurückgibt.
Wir fahren dann mit der Implementierung der Backpropagation-Algorithmen fort. Diese Arbeit besteht aus zwei Phasen:
- Verteilung der Fehlergradienten über alle Komponenten – calcInputGradients
- Parameteroptimierung zur Minimierung des Verlusts – updateInputWeights
Wir beginnen mit calcInputGradients, das für die Propagierung der Gradienten durch die internen Module gemäß ihrem Beitrag zum Endergebnis verantwortlich ist. Wir haben bereits früher auf seine Struktur hingewiesen. Nun untersuchen wir es endlich im Detail und erklären, warum es eine entscheidende Rolle beim Training des Modells spielt.
Die Methode erhält einen Zeiger auf das während des Vorwärtsdurchlaufs verwendete Eingangsdatenobjekt. Diesmal müssen wir jedoch den Fehlergradienten entsprechend dem Einfluss der Eingabe auf das Endergebnis des Modells zurück in das Modell propagieren.
bool CNeuronSkillsEncoder::calcInputGradients(CNeuronBaseOCL *prevLayer) { if(!prevLayer) return false;
Natürlich können wir Daten nur an ein gültiges Objekt übergeben. Daher überprüfen wir zu Beginn des Methodenkörpers sofort die Gültigkeit des empfangenen Zeigers. Wenn der Zeiger null oder anderweitig ungültig ist, wird die Methodenausführung sofort beendet, da weitere Berechnungen sinnlos wären. Eine solche Überprüfung ist eine grundlegende Sicherheitsmaßnahme, die eine korrekte Algorithmusausführung gewährleistet und vor unvorhersehbaren Fehlern während des Trainings schützt.
Wenn der Validierungsschritt erfolgreich bestanden wurde, fahren wir mit der nächsten Phase fort – der Gradientenverteilung. An diesem Punkt beginnt eine sequentielle Übertragung von Informationen über alle am Prozess beteiligten Objekte hinweg. Jede dieser Komponenten ist für ihren eigenen Teil der Modelllogik verantwortlich, und unsere Aufgabe ist es, den Fehlergradienten Schritt für Schritt sorgfältig in die entsprechenden Module zu propagieren.
Dieser Mechanismus ist von entscheidender Bedeutung: Er stellt dem Modell eine interne Rückkopplungsschleife zur Verfügung, die es jedem Block ermöglicht, seine Parameter entsprechend dem endgültigen Fehler anzupassen. Genau durch diesen Mechanismus lernt das Modell – indem es optimale Parameter entdeckt, die die Verlustfunktion minimieren.
In der ersten Phase propagieren wir unter Verwendung der von der Elternklasse bereitgestellten Mechanismen den von nachfolgenden Schichten der neuronalen Architektur empfangenen Fehlergradienten in die externen Schnittstellen des Objekts, bis zur letzten Schicht, die den Skill-Tensor der Agenten erzeugt.
if(!CNeuronSoftMaxOCL::calcInputGradients(cSkillsProjection[1].AsObject())) return false;
Dieser Prozess spielt eine Schlüsselrolle beim Training des Modells, da er die Generierung von Skills ermöglicht, die für die anstehende Aufgabe wirklich relevant sind. Durch die sequentielle Propagierung von Gradienten erhält das Modell direktes Feedback darüber, wie korrekt seine vorherigen Aktionen und Entscheidungen waren.
Unser Ziel ist es jedoch nicht nur, Agenten darin zu schulen, nützliche Skills zu generieren, sondern auch ihr Verhalten als koordiniertes System zu organisieren, um sicherzustellen, dass sie effektiv interagieren können, indem sie ihre Anstrengungen in verschiedene Richtungen lenken, um eine maximale Gesamtleistung zu erzielen. Dies ist nicht bloß ein unabhängiges Training jedes Agenten, sondern vielmehr die Schaffung von Synergien zwischen ihnen.
Um diesen Ansatz zu implementieren, verwenden wir kontrastive Lernalgorithmen, die es uns ermöglichen, Diversität in die Skill-Tensoren der Agenten einzuführen. Wichtig ist, dass diese Diversifizierung nicht nur über verschiedene Agenten zu einem einzigen Zeitschritt hinweg erfolgt, sondern auch über Skills hinweg, die zu unterschiedlichen Zeitschritten generiert wurden. Dies führt zu einer tieferen Trennung in der Repräsentation von Zuständen.
Infolgedessen ist jeder Agent gezwungen, nicht nur die Einzigartigkeit seines eigenen Skills zu erkennen, sondern auch den durch vorherige Aktionen gebildeten Kontext zu berücksichtigen. Dies ermutigt Agenten dazu, komplexere und sequenzielle Verhaltensstrategien zu entwickeln, wodurch sie sich an verändernde Bedingungen und Marktdynamiken anpassen können.
Im Kontext von Finanzmärkten, in denen sich Bedingungen schnell ändern können, wird diese Fähigkeit von Agenten, frühere Aktionen und Zustandsunterschiede zu berücksichtigen, besonders wichtig. Skill-Diversifizierung, kombiniert mit historischem Kontext, ermöglicht die Konstruktion robusterer und anpassungsfähigerer Strategien, die in der Lage sind, bei hoher Volatilität und Unsicherheit effektiv zu operieren.
Der kontrastive Lernalgorithmus spielt eine zentrale Rolle bei der Schaffung dieser Unterscheidungen und verbessert die Fähigkeit der Agenten, verschiedene Situationen zu differenzieren und zu interpretieren sowie bei jedem Schritt fundiertere Entscheidungen zu treffen.
Während des Vorwärtsdurchlaufs, vor der Generierung eines neuen Skill-Tensors, haben wir die Ergebnisse der vorherigen Vorwärtsberechnung gespeichert. Wir verketten nun die Ausgaben aus beiden Umgebungszuständen zu einem einzigen Tensor.
if(!Concat(cSkillsProjection[1].getOutput(), cSkillsProjection[1].getPrevOutput(), cPrevSkillsConcat.getOutput(), cSkillsProjection[1].GetFilters(), cSkillsProjection[1].GetFilters(), iHeads)) return false;
Anschließend rufen wir die Diversifizierungsmethode auf, die darauf ausgelegt ist, einzelne Vektoren innerhalb des Skill-Unterraums maximal zu trennen.
if(!DiversityLoss(cPrevSkillsConcat.AsObject(), 2 * iHeads, cSkillsProjection[1].GetFilters(), false)) return false;
Die resultierenden Fehlergradienten werden dann über ihre entsprechenden Sequenzen aufgeteilt.
if(!DeConcat(cPrevSkillsConcat.getOutput(), cPrevSkillsConcat.getPrevOutput(), cPrevSkillsConcat.getGradient(), cSkillsProjection[1].GetFilters(), cSkillsProjection[1].GetFilters(), iHeads)) return false;
Wir addieren dann die skill-bezogenen Fehlergradienten aus dem aktuellen Zeitschritt zu den zuvor akkumulierten Gradienten.
if(!SumAndNormilize(cSkillsProjection[1].getGradient(), cPrevSkillsConcat.getOutput(), cSkillsProjection[1].getGradient(), cSkillsProjection[1].GetFilters(), false, 0, 0, 0, 1)) return false;
Der Rest der Methode folgt einem linearen Ablauf. Wir propagieren den Fehlergradienten durch den Skill-Generierungsblock.
if(!cSkillsProjection[0].calcHiddenGradients(cSkillsProjection[1].AsObject())) return false;
Die resultierenden Werte werden transponiert und an das Modul zur Analyse der kanalübergreifenden Abhängigkeiten übergeben.
if(!cTranspose.calcHiddenGradients(cSkillsProjection[0].AsObject())) return false; if(!cCrossObservAttention.calcHiddenGradients(cTranspose.AsObject())) return false;
Schließlich wird der Fehlergradient entsprechend seinem Beitrag zum Endergebnis zurück in das Eingabedatenobjekt propagiert.
return prevLayer.calcHiddenGradients(cCrossObservAttention.AsObject());
}
Die Methode schließt mit der Rückgabe des logischen Ergebnisses der Operation an das aufrufende Programm ab.
Die Parameteraktualisierungsmethode updateInputWeights ist unkompliziert: Sie ruft einfach die entsprechenden Methoden der internen Komponenten auf. Es ist erwähnenswert, dass nicht alle internen Module trainierbare Parameter enthalten; daher nimmt nur eine Teilmenge von ihnen an diesem Aktualisierungsschritt teil.
bool CNeuronSkillsEncoder::updateInputWeights(CNeuronBaseOCL *NeuronOCL) { if(!cCrossObservAttention.UpdateInputWeights(NeuronOCL)) return false; if(!cSkillsProjection[0].UpdateInputWeights(cTranspose.AsObject())) return false; if(!cSkillsProjection[1].UpdateInputWeights(cSkillsProjection[0].AsObject())) return false; //--- return true; }
Ein paar Worte sollten auch zum Speichern und Wiederherstellen des Modells gesagt werden. Wie Sie vielleicht bemerkt haben, enthält die Komponente, die für die Verkettung der Ergebnisse aus zwei sequenziellen Feed-Forward-Durchläufen verantwortlich ist, keine trainierbaren Parameter. Sie dient nur einer Hilfsfunktion und führt Ausgaben aus verschiedenen Verarbeitungsströmen zusammen. Trotzdem verfügt das Verkettungsobjekt über Datenpuffer, deren Größe das Doppelte des Ausgabetensors des Encoders beträgt. Diese Puffer beeinträchtigen den Betrieb des Modells jedoch nicht kritisch, da sie nur als temporärer Speicher für Zwischenberechnungen verwendet werden. Folglich kann beim Speichern des trainierten Modells Speicherplatz auf der Festplatte gespart werden, indem diese Puffer weggelassen werden.
bool CNeuronSkillsEncoder::Save(const int file_handle) { if(!CNeuronSoftMaxOCL::Save(file_handle)) return false; if(!cCrossObservAttention.Save(file_handle)) return false; if(!cTranspose.Save(file_handle)) return false; for(uint i = 0; i < cSkillsProjection.Size(); i++) if(!cSkillsProjection[i].Save(file_handle)) return false; //--- return true; }
Beim Wiederherstellen des Modells kann die Konkatenationskomponente auf Basis der bekannten Ausgabetensor-Dimensionen des Skill-Encoders einfach neu initialisiert werden.
bool CNeuronSkillsEncoder::Load(const int file_handle) { if(!CNeuronSoftMaxOCL::Load(file_handle)) return false; if(!LoadInsideLayer(file_handle, cCrossObservAttention.AsObject())) return false; if(!LoadInsideLayer(file_handle, cTranspose.AsObject())) return false; for(uint i = 0; i < cSkillsProjection.Size(); i++) if(!LoadInsideLayer(file_handle, cSkillsProjection[i].AsObject())) return false; //--- if(!cPrevSkillsConcat.Init(0, 4, OpenCL, 2 * Neurons(), optimization, iBatch)) return false; cPrevSkillsConcat.SetActivationFunction((ENUM_ACTIVATION)cSkillsProjection[1].Activation()); //--- return true; }
Hiermit schließen wir die Beschreibung der Implementierung des Skill-Encoders ab. Der vollständige Quellcode des vorgestellten Objekts und seiner Methoden ist im Anhang enthalten.
Wir sind heute gut vorangekommen; der inhaltliche Rahmen dieses Artikels ist jedoch fast ausgeschöpft. Daher werden wir eine kurze Pause einlegen und im nächsten Teil fortfahren.
Schlussfolgerung
Wir haben die theoretischen Grundlagen des Frameworks HiSSD erörtert, das ein leistungsfähiges und flexibles System für das Training von Agenten in einer Multi-Agenten-Umgebung darstellt. Jeder Agent erlernt eine individuelle VerhaltensStrategie, während er eng mit anderen Teilnehmern im System interagiert. Diese Kombination aus gemeinsamem und aufgabenspezifischem Skill-Lernen ermöglicht die Entwicklung adaptiverer und robusterer Strategien, die in der Lage sind, unter Unsicherheit und dynamischen Bedingungen effektiv zu agieren.
Die modulare Natur des Ansatzes HiSSD sowie die Integration mehrerer Trainingsmechanismen wie kontrastives Lernen und variationale Verhaltenskodierung machen ihn zu einem äußerst flexiblen und vielversprechenden Framework zur Lösung von Problemen in Multi-Agenten-Systemen.
Im praktischen Teil des Artikels haben wir mit der Implementierung unserer Interpretation des vorgeschlagenen Ansatzes in MQL5 begonnen. Insbesondere haben wir eine Implementierung eines universellen Skill-Encoders vorgestellt. Im nächsten Artikel werden wir diese Arbeit fortsetzen und dazu übergehen, die Wirksamkeit der implementierten Methoden anhand realer historischer Marktdaten zu testen.
Referenzen
- Learning Generalizable Skills from Offline Multi-Task Data for Multi-Agent Cooperation
- Andere Artikel dieser Serie
In diesem Artikel verwendete Programme
| # | Name | Typ | Beschreibung |
|---|---|---|---|
| 1 | Research.mq5 | Expert Advisor | Expert Advisor für die Datenerfassung |
| 2 | ResearchRealORL.mq5 | Expert Advisor | Expert Advisor für die Datenerfassung mit der Methode Real-ORL |
| 3 | Study.mq5 | Expert Advisor | Expert Advisor für das Training des Modells |
| 4 | Test.mq5 | Expert Advisor | Expert Advisor zum Testen des Modells |
| 5 | Trajectory.mqh | Klassenbibliothek | Struktur der Beschreibung des Systemzustands und der Modellarchitektur |
| 6 | NeuroNet.mqh | Klassenbibliothek | Eine Bibliothek von Klassen zur Erstellung eines neuronalen Netzes |
| 7 | NeuroNet.cl | Codebibliothek | OpenCL-Programmcode |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/17729
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Exchange-Market-Algorithmus (EMA)
Saisonalitätsindikator nach Stunden, Wochentagen und Tagen des Monats
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Untersuchung von Regressionsmodellen für kausale Inferenz und algorithmischen Handel
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Neuer Artikel „Anwendung neuronaler Netze im Handel: Hierarchische Skill-Entdeckung (HiSSD) für adaptives Verhalten von Agenten“ veröffentlicht:
Autor: Dmitriy Gizlyk