Arbeiten mit kontinuierlichen Aktionen
Beginnen wir mit dem Projekt aus unserem vorherigen Tutorial und fügen kontinuierliche Aktionen hinzu. Sie können entweder mit dem Starterprojekt folgen oder das vollständige Projekt nutzen, wenn Sie dies bevorzugen.
Diskrete vs. kontinuierliche Aktionen
Im vorherigen Leitfaden haben wir mit diskreten Aktionen gearbeitet - unser Agent musste zwischen einer endlichen Menge von Optionen (0 oder 1) wählen, um ein Muster abzugleichen. In realen Szenarien könnten wir eine Vielzahl von Sensordaten und visuellen Eingaben erhalten, um zu entscheiden, welche Taste zu drücken ist.
In vielen realen Anwendungen ist dies jedoch nicht immer möglich. Für die Steuerung von Dingen wie:
- Lenkwinkel in Fahrzeugen
- Gelenkdrehmomente in Roboterarmen
- Leistungsstufen in Motoren
Unser Agent muss kontinuierliche Aktionen ausgeben - präzise Gleitkommazahlen anstelle von kategorischen Auswahlmöglichkeiten.
Hinzufügen kontinuierlicher Aktionen zu unserer Umgebung
Ändern wir unsere Umgebung, um sowohl diskrete als auch kontinuierliche Aktionen einzubeziehen. Wir behalten unsere ursprüngliche Musterabgleichsaufgabe bei, fügen aber ein zweites Muster hinzu, bei dem wir erwarten, dass die KI die Quadratwurzel dieses neuen Wertes ausgibt.
Beachten Sie, wie wir nichts außer unseren ERWARTUNGEN ändern - der Agent muss durch Versuch und Irrtum herausfinden, was wir wollen, nur geleitet durch Belohnungssignale!
Fügen Sie zunächst neue Felder hinzu, um das zweite Muster und die kontinuierliche Aktion in PatternMatchingEnvironment.cs
zu verfolgen:
private int pattern = 0;private int pattern2 = 0;private int aiChoice = 0;private float aicontinuousChoice = 0f;private bool roundFinished = false;
Fügen Sie als Nächstes eine zweite Beobachtungsmethode und unsere kontinuierliche Aktionsmethode hinzu:
[RLMatrixObservation]public float SeePattern() => pattern;
[RLMatrixObservation]public float SeePattern2() => pattern2;
[RLMatrixActionContinuous]public void MakeChoiceContinuous(float input){ aicontinuousChoice = input;}
Jetzt erstellen wir unsere Belohnungsfunktionen:
[RLMatrixReward]public float GiveReward() => aiChoice == pattern ? 1.0f : -1.0f;
// Füge +2 Belohnung hinzu, wenn die kontinuierliche Ausgabe der KI nahe an der Quadratwurzel// des zweiten Musters liegt[RLMatrixReward]public float ExtraRewards() => Math.Abs(aicontinuousChoice - Math.Sqrt(pattern2)) < 0.1f ? 2f : 0.0f;
Schließlich müssen wir unsere StartNewRound
-Methode aktualisieren, um beide Muster zu generieren:
[RLMatrixReset]public void StartNewRound(){ pattern = Random.Shared.Next(2); pattern2 = Random.Shared.Next(10); aiChoice = 0; roundFinished = false;}
Beachten Sie, dass wir einen Bereich von 0-9 für pattern2 verwenden, was unserem Agenten eine interessantere Herausforderung bietet, verschiedene Quadratwurzeln vorherzusagen.
Beheben von Kompilierungsfehlern
Wenn Sie versuchen, die Lösung zu erstellen, werden Sie auf eine Reihe von Fehlern stoßen. Dies ist tatsächlich hilfreich - RLMatrix verwendet starke Typisierung, um Laufzeitfehler zu verhindern und Sie zur korrekten Implementierung für kontinuierliche Aktionen zu führen.
Fehler 1: Umgebungstyp stimmt nicht überein
Argument 1: cannot convert from 'PatternMatchingExample.PatternMatchingEnvironment' to 'RLMatrix.IEnvironmentAsync<float[]>'
Dies tritt auf, weil RLMatrix unterschiedliche Schnittstellen für kontinuierliche und diskrete Umgebungen hat, um Typsicherheit zu gewährleisten. Aktualisieren wir unseren Code in Program.cs
:
var env = new List<IEnvironmentAsync<float[]>> {var env = new List<IContinuousEnvironmentAsync<float[]>> { environment, //new PatternMatchingEnvironment().RLInit() //you can add more than one to train in parallel};
Fehler 2: Agententyp stimmt nicht überein
Nach dieser Änderung erhalten wir einen zweiten Fehler:
Argument 2: cannot convert from 'System.Collections.Generic.List<RLMatrix.IContinuousEnvironmentAsync<float[]>>' to 'System.Collections.Generic.IEnumerable<RLMatrix.IEnvironmentAsync<float[]>>'
Das liegt daran, dass wir versuchen, einen diskreten Agenten mit einer kontinuierlichen Umgebung zu verwenden. Wir müssen den Agententyp ändern:
var agent = new LocalDiscreteRolloutAgent<float[]>(learningSetup, env);var agent = new LocalContinuousRolloutAgent<float[]>(learningSetup, env);
Fehler 3: Algorithmusoptionen stimmen nicht überein
Dies führt zu unserem dritten Fehler:
Argument 1: cannot convert from 'RLMatrix.DQNAgentOptions' to 'RLMatrix.PPOAgentOptions'
Dieser letzte Fehler zeigt, dass DQN mit kontinuierlichen Aktionen nicht kompatibel ist. Wir müssen zu PPO (Proximal Policy Optimization) wechseln, das sowohl diskrete als auch kontinuierliche Aktionsräume handhaben kann:
var learningSetup = new DQNAgentOptions( batchSize: 32, memorySize: 1000, gamma: 0.99f, epsStart: 1f, epsEnd: 0.05f, epsDecay: 150f);var learningSetup = new PPOAgentOptions( batchSize: 128, memorySize: 1000, gamma: 0.99f, width: 128, lr: 1E-03f);
Unser erster Trainingslauf
Führen wir nun das Training durch und sehen, was passiert:
Step 800/1000 - Last 50 steps accuracy: 42.0%Press Enter to continue...
Step 850/1000 - Last 50 steps accuracy: 38.0%Press Enter to continue...
Step 900/1000 - Last 50 steps accuracy: 40.0%Press Enter to continue...
Step 950/1000 - Last 50 steps accuracy: 38.0%Press Enter to continue...
Step 1000/1000 - Last 50 steps accuracy: 37.0%Press Enter to continue...
Überraschung! Die KI lernt kaum etwas. Die Genauigkeit kommt nicht über 50%, und wenn wir das Dashboard untersuchen, sehen wir, dass sie regelmäßig +1 Belohnungen für diskrete Aktionen (Musterabgleich) sammelt, aber selten die +2 Belohnungen für kontinuierliche Aktionen (Vorhersage von √pattern2) erhält.
Warum passiert das?
Fragen Sie sich: Warum lernt die KI den Abgleich der diskreten Aktion so viel leichter als die kontinuierliche?
Ihr erster Instinkt könnte die Lernrate (lr
) sein - vielleicht ist sie zu niedrig? Versuchen wir, sie auf 1E-02f
zu ändern und das Training erneut durchzuführen…
Hat das geholfen? Wahrscheinlich nicht. Tatsächlich könnten Sie bemerken, dass der Agent zwar die diskrete Aktion schneller lernt, aber den kontinuierlichen Aktionsraum kaum erkundet, und die Genauigkeit wird sogar schlechter, wenn das Training fortschreitet.
Was passiert also wirklich?
Hinzufügen eines Leitsignals
Versuchen wir, dies zu beheben, indem wir ein hilfreicheres Belohnungssignal bereitstellen. Wir fügen eine Belohnung hinzu, die zunimmt, wenn der Agent näher an der richtigen Quadratwurzel liegt, anstatt nur exakte Übereinstimmungen zu belohnen:
[RLMatrixReward]public float ExtraSupportingReward() => 0.5f / (1 + Math.Abs(aicontinuousChoice - (float)Math.Sqrt(pattern2)));
//Vergessen Sie nicht, Ihre lr zurück auf 1E-03f zu setzen!
Diese Belohnungsfunktion erzeugt einen Gradienten - ein kontinuierliches Signal, das stärker wird, wenn sich der Agent dem richtigen Wert nähert. Selbst wenn er nicht genau richtig liegt, erhält er Feedback darüber, ob er “wärmer” oder “kälter” wird.
Führen wir das Training mit dieser Änderung erneut durch und sehen, was passiert:
Step 850/1000 - Last 50 steps accuracy: 35.0%Press Enter to continue...
Step 900/1000 - Last 50 steps accuracy: 40.0%Press Enter to continue...
Step 950/1000 - Last 50 steps accuracy: 47.0%Press Enter to continue...
Step 1000/1000 - Last 50 steps accuracy: 36.0%Press Enter to continue...
Wir sehen einige kleine Verbesserungen, aber es ist immer noch nicht großartig. Das Dashboard könnte Hinweise darauf zeigen, dass das Lernen voranschreitet, aber es ist klar, dass wir für diese komplexere Aufgabe mehr Trainingszeit benötigen.
Verlängerung der Trainingszeit
Für komplexere Herausforderungen wie die Vorhersage kontinuierlicher Aktionen benötigen wir oft mehr Trainingsschritte. Ändern wir unser Programm, um 10.000 statt 1.000 Schritte zu trainieren:
for (int i = 0; i < 10000; i++){ await agent.Step();
if ((i + 1) % 500 == 0) { Console.WriteLine($"Step {i + 1}/10000 - Last 500 steps accuracy: {environment.RecentAccuracy:F1}%"); environment.ResetStats();
Console.WriteLine("\nPress Enter to continue..."); Console.ReadLine(); }}
Experiment: Auswirkung der Lernrate
Während Sie den längeren Trainingsfortschritt beobachten, experimentieren Sie mit verschiedenen Lernraten. Was passiert, wenn Sie sie noch weiter senken? Was, wenn Sie sie deutlich erhöhen?
In meinen Experimenten führt das Festlegen einer sehr hohen Lernrate dazu, dass das Modell stecken bleibt und nur die +1 Belohnungen für diskrete Aktionen sammelt, während es den kontinuierlichen Raum völlig unzureichend erkundet.
Wichtige Erkenntnisse
Durch diese Übung haben wir mehrere wichtige Lektionen gelernt:
-
Kontinuierliche Aktionen sind von Natur aus schwerer zu lernen als diskrete, aufgrund des Problems der spärlichen Belohnungen. Wenn möglich, diskretisieren Sie Ihren Aktionsraum!
-
Belohnungstechnik ist enorm wichtig für kontinuierliche Steuerungsprobleme. Das Bereitstellen eines Signals über “wärmer werden” verwandelt eine unmögliche Lernaufgabe in eine lösbare.
-
Komplexe Aufgaben erfordern mehr Trainingszeit. Wenn wir Dimensionen zu unserem Aktionsraum hinzufügen, müssen wir die Trainingsdauer entsprechend skalieren.
-
Algorithmusauswahl ist entscheidend. DQN kann kontinuierliche Aktionen überhaupt nicht handhaben, während PPO diskrete, kontinuierliche oder gemischte Aktionsräume bewältigen kann.
-
Die Abstimmung der Lernrate ist delikat, besonders bei PPO. Höher ist nicht immer besser und kann manchmal für die Erkundung schlechter sein.
Diese Prinzipien werden Ihnen gute Dienste leisten, wenn Sie komplexere Reinforcement-Learning-Herausforderungen mit RLMatrix bewältigen.
Testen Sie Ihr Verständnis
Kontinuierliche Aktionen verstehen
Nächste Schritte
Jetzt, da Sie die Herausforderungen kontinuierlicher Aktionsräume verstehen und wissen, wie Sie sie angehen können, sind Sie bereit, ein klassisches Reinforcement-Learning-Problem mit komplexeren Beobachtungen zu versuchen.