Das Training verteilter Deep-Learning-Modelle wird immer wichtiger, da die Datenmengen in vielen Branchen wachsen. Viele Anwendungen in der Computer Vision und der Verarbeitung natürlicher Sprache erfordern jetzt das Training von Deep-Learning-Modellen, die exponentiell an Komplexität zunehmen und oft mit Hunderten von Terabyte an Daten trainiert werden. Dann wird es wichtig, eine riesige Cloud-Infrastruktur zu verwenden, um das Training solch großer Modelle zu skalieren.
Entwickler können Open-Source-Frameworks wie PyTorch verwenden, um auf einfache Weise intuitive Modellarchitekturen zu entwerfen. Das Skalieren des Trainings dieser Modelle über mehrere Knoten hinweg kann jedoch aufgrund der erhöhten Orchestrierungskomplexität eine Herausforderung darstellen.
Das verteilte Modelltraining besteht hauptsächlich aus zwei Paradigmen:
- Modell parallel – Beim modellparallelen Training ist das Modell selbst so groß, dass es nicht in den Speicher einer einzelnen GPU passt, und es werden mehrere GPUs benötigt, um das Modell zu trainieren. Das GPT-3-Modell von Open AI mit 175 Milliarden trainierbaren Parametern (ca. 350 GB groß) ist ein gutes Beispiel dafür.
- Daten parallel – Beim datenparallelen Training kann sich das Modell in einer einzelnen GPU befinden, aber da die Daten so groß sind, kann es Tage oder Wochen dauern, ein Modell zu trainieren. Die Verteilung der Daten auf mehrere GPU-Knoten kann die Trainingszeit erheblich verkürzen.
In diesem Beitrag stellen wir eine Beispielarchitektur zum Trainieren von PyTorch-Modellen mit der Fackel verteilt elastisch Rahmen in einer verteilten Datenparallelweise unter Verwendung Amazon Elastic Kubernetes-Service (Amazon EKS).
Voraussetzungen:
Um die in diesem Beitrag gemeldeten Ergebnisse zu replizieren, ist die einzige Voraussetzung ein AWS-Konto. In diesem Konto erstellen wir einen EKS-Cluster und eine Amazon FSx für Lustre Dateisystem. Wir pushen Container-Images auch in eine Amazon Elastic Container-Registrierung (Amazon ECR)-Repository im Konto. Anweisungen zum Einrichten dieser Komponenten werden nach Bedarf im gesamten Beitrag bereitgestellt.
EKS-Cluster
Amazon EKS ist ein verwalteter Container-Service zum Ausführen und Skalieren von Kubernetes-Anwendungen auf AWS. Mit Amazon EKS können Sie verteilte Schulungsaufträge mit den neuesten effizient ausführen Amazon Elastic Compute-Cloud (Amazon EC2)-Instances, ohne dass Sie Ihre eigene Steuerungsebene oder Knoten installieren, betreiben und warten müssen. Es ist ein beliebtes Orchestrator für maschinelles Lernen (ML) und KI-Workflows. Ein typischer EKS-Cluster in AWS sieht wie in der folgenden Abbildung aus.
Wir haben ein Open-Source-Projekt veröffentlicht, AWS DevOps für EKS (aws-do-eks), das eine große Sammlung benutzerfreundlicher und konfigurierbarer Skripts und Tools zum Bereitstellen von EKS-Clustern und zum Ausführen verteilter Trainingsjobs bereitstellt. Dieses Projekt ist nach den Prinzipien des aufgebaut Rahmen tun: Einfachheit, Flexibilität und Universalität. Sie können Ihren gewünschten Cluster mithilfe von konfigurieren eks.conf Datei und starten Sie sie dann, indem Sie die eks-create.sh Skript. Eine ausführliche Anleitung finden Sie in der GitHub Repo.
Trainieren Sie PyTorch-Modelle mit Torch Distributed Elastic
Torch Distributed Elastic (TDE) ist eine native PyTorch-Bibliothek zum Trainieren umfangreicher Deep-Learning-Modelle, bei denen es entscheidend ist, Rechenressourcen dynamisch je nach Verfügbarkeit zu skalieren. Das TorchElastic-Controller für Kubernetes ist eine native Kubernetes-Implementierung für TDE, die den Lebenszyklus der für das TDE-Training erforderlichen Pods und Dienste automatisch verwaltet. Es ermöglicht die dynamische Skalierung von Rechenressourcen während des Trainings nach Bedarf. Es bietet auch ein fehlertolerantes Training, indem Jobs nach einem Knotenausfall wiederhergestellt werden.
In diesem Beitrag besprechen wir die Schritte zum Trainieren von PyTorch EfficientNet-B7 und ResNet50 Modelle verwenden IMAGEnet Daten verteilt mit TDE. Wir verwenden die PyTorch VerteilteDatenParallel API und den Kubernetes TorchElastic-Controller und führen unsere Trainingsjobs auf einem EKS-Cluster aus, der mehrere GPU-Knoten enthält. Das folgende Diagramm zeigt das Architekturdiagramm für dieses Modelltraining.
TorchElastic for Kubernetes besteht hauptsächlich aus zwei Komponenten: dem TorchElastic Kubernetes Controller (TEC) und dem Parameterserver (etcd). Der Controller ist für die Überwachung und Verwaltung der Trainingsjobs verantwortlich, und der Parameterserver verfolgt die Worker-Knoten für die verteilte Synchronisation und Peer-Erkennung.
Damit die Trainings-Pods auf die Daten zugreifen können, benötigen wir ein gemeinsames Datenvolumen, das von jedem Pod gemountet werden kann. Einige Optionen für freigegebene Volumes durch Container-Storage-Schnittstelle (CSI)-Treiber enthalten in AWS DevOps für EKS sind Amazon Elastic File System (Amazon EFS) und FSx für Glanz.
Cluster-Einrichtung
In unserer Clusterkonfiguration verwenden wir eine c5.2xlarge-Instanz für System-Pods. Wir verwenden drei p4d.24xlarge-Instanzen als Worker-Pods, um ein EfficientNet-Modell zu trainieren. Für das ResNet50-Training verwenden wir p3.8xlarge-Instances als Worker-Pods. Darüber hinaus verwenden wir ein gemeinsam genutztes FSx-Dateisystem, um unsere Trainingsdaten und Modellartefakte zu speichern.
AWS p4d.24xlarge-Instanzen sind ausgestattet mit Adapter aus elastischem Stoff (EFA) zur Bereitstellung von Netzwerken zwischen Knoten. Wir diskutieren EFA später in der Post mehr. Um die Kommunikation über EFA zu ermöglichen, müssen wir das Cluster-Setup über eine .yaml-Datei konfigurieren. Ein Beispieldatei wird im GitHub-Repository bereitgestellt.
Nachdem diese .yaml-Datei ordnungsgemäß konfiguriert ist, können wir den Cluster mit dem im GitHub-Repository bereitgestellten Skript starten:
Siehe die GitHub Repo Detaillierte Anweisungen.
Es gibt praktisch keinen Unterschied zwischen der Ausführung von Jobs auf p4d.24xlarge und p3.8xlarge. Die in diesem Beitrag beschriebenen Schritte funktionieren für beide. Der einzige Unterschied besteht in der Verfügbarkeit von EFA auf p4d.24xlarge-Instanzen. Bei kleineren Modellen wie ResNet50 hat die Standardvernetzung im Vergleich zur EFA-Vernetzung nur minimale Auswirkungen auf die Trainingsgeschwindigkeit.
FSx für das Lustre-Dateisystem
FSx wurde für Hochleistungs-Computing-Workloads entwickelt und bietet eine Latenz von weniger als einer Millisekunde unter Verwendung von Solid-State-Drive-Speichervolumes. Wir haben uns für FSx entschieden, weil es bei der Skalierung auf eine große Anzahl von Knoten eine bessere Leistung bot. Ein wichtiges zu beachtendes Detail ist, dass FSx nur in einer einzigen Availability Zone existieren kann. Daher sollten sich alle Knoten, die auf das FSx-Dateisystem zugreifen, in derselben Availability Zone wie das FSx-Dateisystem befinden. Eine Möglichkeit, dies zu erreichen, besteht darin, die relevante Availability Zone in der .yaml-Datei des Clusters für die spezifischen Knotengruppen anzugeben, bevor der Cluster erstellt wird. Alternativ können wir den Netzwerkteil der Auto Scaling-Gruppe für diese Knoten ändern, nachdem der Cluster eingerichtet wurde, und ihn auf die Verwendung eines einzelnen Subnetzes beschränken. Dies kann einfach auf der Amazon EC2-Konsole durchgeführt werden.
Unter der Annahme, dass der EKS-Cluster betriebsbereit ist und die Subnetz-ID für die Availability Zone bekannt ist, können wir ein FSx-Dateisystem einrichten, indem wir die erforderlichen Informationen in der fsx.conf Datei wie in der beschrieben readme und laufen die bereitstellen.sh Skript in der fsx Mappe. Dadurch werden die richtige Richtlinie und Sicherheitsgruppe für den Zugriff auf das Dateisystem eingerichtet. Das Skript installiert auch die CSI-Treiber für FSx als Daemonset. Schließlich können wir den persistenten FSx-Volume-Claim in Kubernetes erstellen, indem wir eine einzelne .yaml-Datei anwenden:
Dadurch wird ein FSx-Dateisystem in der Availability Zone erstellt, die in der angegeben ist fsx.conf
-Datei und erstellt auch einen persistenten Volume-Claim fsx-pvc
, die von jedem der Pods im Cluster im Read-Write-Many-Modus (RWX) bereitgestellt werden kann.
In unserem Experiment haben wir vollständige ImageNet-Daten verwendet, die mehr als 12 Millionen Trainingsbilder enthalten, die in 1,000 Klassen unterteilt sind. Die Daten können unter heruntergeladen werden ImageNet-Website. Der ursprüngliche TAR-Ball hat mehrere Verzeichnisse, aber für unser Modelltraining interessieren uns nur die ILSVRC/Data/CLS-LOC/
, die die enthält train
und val
Unterverzeichnisse. Vor dem Training müssen wir die Bilder in neu anordnen val
Unterverzeichnis so, dass es der von PyTorch benötigten Verzeichnisstruktur entspricht Bildordner Klasse. Dies kann mit einem einfachen durchgeführt werden Python-Skript nachdem die Daten im nächsten Schritt auf das persistente Volume kopiert wurden.
Um die Daten von einem zu kopieren Amazon Simple Storage-Service (Amazon S3)-Bucket zum FSx-Dateisystem erstellen wir ein Docker-Image, das Skripte für diese Aufgabe enthält. Ein Beispiel-Dockerfile und ein Shell-Skript sind in der enthalten csi Ordner im GitHub-Repo. Wir können das Bild mit dem erstellen build.sh
-Skript und schieben Sie es dann mithilfe von an Amazon ECR push.sh
Skript. Bevor wir diese Skripte verwenden, müssen wir den korrekten URI für das ECR-Repository in der angeben .env
Datei im Stammordner des GitHub-Repos. Nachdem wir das Docker-Image an Amazon ECR gepusht haben, können wir einen Pod starten, um die Daten zu kopieren, indem wir die entsprechende .yaml-Datei anwenden:
Der Pod führt das Skript automatisch aus data-prep.sh um die Daten von Amazon S3 auf das freigegebene Volume zu kopieren. Da die ImageNet-Daten mehr als 12 Millionen Dateien umfassen, dauert der Kopiervorgang einige Stunden. Das Python-Skript imagenet_data_prep.py wird auch ausgeführt, um die neu zu ordnen val
Datensatz wie von PyTorch erwartet.
Netzwerkbeschleunigung
Wir können Elastic Fabric Adapter (EFA) in Kombination mit verwenden unterstützte EC2-Instance-Typen um den Netzwerkdatenverkehr zwischen den GPU-Knoten in Ihrem Cluster zu beschleunigen. Dies kann nützlich sein, wenn große verteilte Trainingsjobs ausgeführt werden, bei denen die Standardnetzwerkkommunikation ein Engpass sein kann. Skripte zum Bereitstellen und Testen des EFA-Geräte-Plugins im hier verwendeten EKS-Cluster sind in der enthalten efa-Geräte-Plugin Ordner im GitHub-Repo. Um einen Job mit EFA in Ihrem EKS-Cluster zu aktivieren, muss zusätzlich zu den Cluster-Knoten mit der erforderlichen Hardware und Software das EFA-Geräte-Plug-In im Cluster bereitgestellt werden, und Ihr Job-Container muss kompatibles CUDA und NCCL haben Versionen installiert.
Um die Ausführung von NCCL-Tests und die Bewertung der Leistung von EFA auf p4d.24xlarge-Instanzen zu demonstrieren, müssen wir zuerst den Kubeflow MPI-Operator bereitstellen, indem wir die entsprechende ausführen bereitstellen.sh Skript in der MPI-Operator Mappe. Dann führen wir die bereitstellen.sh Skript und aktualisieren Sie die test-efa-nccl.yaml manifestieren sich also Grenzen und Anfragen nach Ressourcen vpc.amazonaws.com
sind auf 4 gesetzt. Die vier verfügbaren EFA-Adapter in den p4d.24xlarge-Knoten werden gebündelt, um maximalen Durchsatz bereitzustellen.
Führen Sie kubectl apply -f ./test-efa-nccl.yaml
um den Test anzuwenden und dann die Protokolle des Test-Pods anzuzeigen. Die folgende Zeile in der Protokollausgabe bestätigt, dass EFA verwendet wird:
Die Testergebnisse sollten der folgenden Ausgabe ähneln:
Wir können in den Testergebnissen beobachten, dass der maximale Durchsatz etwa 42 GB/s beträgt und die durchschnittliche Busbandbreite etwa 8 GB beträgt.
Wir haben auch Experimente mit einem einzelnen aktivierten EFA-Adapter sowie ohne EFA-Adapter durchgeführt. Alle Ergebnisse sind in der folgenden Tabelle zusammengefasst.
Anzahl der EFA-Adapter | Net/OFI Ausgewählter Anbieter | Durchschn. Bandbreite (GB/s) | max. Bandbreite (GB/s) |
4 | efa | 8.24 | 42.04 |
1 | efa | 3.02 | 5.89 |
0 | Buchse | 0.97 | 2.38 |
Wir haben auch festgestellt, dass für relativ kleine Modelle wie ImageNet die Verwendung von beschleunigtem Netzwerk die Trainingszeit pro Epoche nur um 5–8 % bei einer Stapelgröße von 64 reduziert. Für größere Modelle und kleinere Stapelgrößen, wenn eine erhöhte Netzwerkkommunikation von Gewichten erforderlich ist , hat der Einsatz von Accelerated Networking eine größere Wirkung. Wir haben eine Verringerung der Epochen-Trainingszeit um 15–18 % für das Training von EfficientNet-B7 mit Stapelgröße 1 beobachtet. Die tatsächliche Auswirkung von EFA auf Ihr Training hängt von der Größe Ihres Modells ab.
GPU-Überwachung
Vor dem Ausführen des Trainingsjobs können wir auch einrichten Amazon CloudWatch Metriken zur Visualisierung der GPU-Auslastung während des Trainings. Es kann hilfreich sein zu wissen, ob die Ressourcen optimal genutzt werden, oder potenzielle Ressourcenknappheit und Engpässe im Trainingsprozess zu identifizieren.
Die relevanten Skripte zum Einrichten von CloudWatch befinden sich in der GPU-Metriken Mappe. Zuerst erstellen wir ein Docker-Image mit amazon-cloudwatch-agent
und nvidia-smi
. Wir können die Dockerfile in der verwenden gpu-metrics
Ordner, um dieses Bild zu erstellen. Angenommen, die ECR-Registrierung ist bereits in der .env
Datei aus dem vorherigen Schritt können wir das Image erstellen und pushen build.sh
und push.sh
. Danach läuft die deploy.sh
Das Skript schließt die Einrichtung automatisch ab. Es startet ein Daemonset mit amazon-cloudwatch-agent
und überträgt verschiedene Metriken an CloudWatch. Die GPU-Metriken werden unter angezeigt CWAgent
Namespace auf der CloudWatch-Konsole. Die restlichen Clustermetriken werden unter angezeigt ContainerInsights
Namespace.
Modelltraining
Alle für das PyTorch-Training benötigten Skripte befinden sich in der elastischer Job Ordner im GitHub-Repo. Bevor wir den Trainingsjob starten, müssen wir die ausführen etcd
Server, der vom TEC für Worker Discovery und Parameteraustausch verwendet wird. Das bereitstellen.sh Skript in der elasticjob
Ordner tut genau das.
Um EFA in p4d.24xlarge-Instanzen nutzen zu können, müssen wir ein bestimmtes Docker-Image verwenden, das in verfügbar ist Öffentliche Amazon ECR-Galerie das die NCCL-Kommunikation über EFA unterstützt. Wir müssen nur unseren Trainingscode in dieses Docker-Image kopieren. Das Dockerfile unter dem Proben Ordner erstellt ein Bild, das beim Ausführen von Trainingsjobs auf p4d-Instanzen verwendet werden soll. Wie immer können wir die verwenden build.sh und push.sh Skripte im Ordner, um das Image zu erstellen und zu pushen.
Das imagenet-efa.yaml Datei beschreibt den Trainingsjob. Diese .yaml-Datei richtet die Ressourcen ein, die zum Ausführen des Trainingsjobs erforderlich sind, und stellt auch das persistente Volume mit den im vorherigen Abschnitt eingerichteten Trainingsdaten bereit.
Ein paar Dinge sind hier erwähnenswert. Die Anzahl der Replikate sollte auf die Anzahl der im Cluster verfügbaren Knoten festgelegt werden. In unserem Fall setzen wir dies auf 3, weil wir drei p4d.24xlarge-Knoten hatten. In dem imagenet-efa.yaml
Datei, die nvidia.com/gpu
Parameter unter Ressourcen und nproc_per_node
für args
sollte auf die Anzahl der GPUs pro Knoten gesetzt werden, was im Fall von p4d.24xlarge 8 ist. Außerdem legt das Worker-Argument für das Python-Skript die Anzahl der CPUs pro Prozess fest. Wir haben den Wert 4 gewählt, da dies in unseren Experimenten eine optimale Leistung bei der Ausführung auf p4d.24xlarge-Instances bietet. Diese Einstellungen sind erforderlich, um die Nutzung aller im Cluster verfügbaren Hardwareressourcen zu maximieren.
Wenn der Job ausgeführt wird, können wir die GPU-Nutzung in CloudWatch für alle GPUs im Cluster beobachten. Das Folgende ist ein Beispiel aus einem unserer Trainingsjobs mit drei p4d.24xlarge-Knoten im Cluster. Hier haben wir eine GPU von jedem Knoten ausgewählt. Mit den zuvor erwähnten Einstellungen liegt die GPU-Nutzung während der Trainingsphase der Epoche für alle Knoten im Cluster bei nahezu 100 %.
Für das Training eines ResNet50-Modells mit p3.8xlarge-Instanzen benötigen wir genau die gleichen Schritte wie für das EfficientNet-Training mit p4d.24xlarge beschrieben. Wir können auch dasselbe Docker-Image verwenden. Wie bereits erwähnt, sind p3.8xlarge-Instanzen nicht mit EFA ausgestattet. Für das ResNet50-Modell ist dies jedoch kein wesentlicher Nachteil. Das imagenet-fsx.yaml Das im GitHub-Repository bereitgestellte Skript richtet den Trainingsjob mit geeigneten Ressourcen für den Knotentyp p3.8xlarge ein. Der Job verwendet denselben Datensatz aus dem FSx-Dateisystem.
GPU-Skalierung
Wir haben einige Experimente durchgeführt, um zu beobachten, wie sich die Trainingszeit für das EfficientNet-B7-Modell skaliert, indem die Anzahl der GPUs erhöht wird. Dazu haben wir die Anzahl der Replikate in unserer .yaml-Trainingsdatei für jeden Trainingslauf von 1 auf 3 geändert. Wir haben nur die Zeit für eine einzelne Epoche beobachtet, während wir den vollständigen ImageNet-Datensatz verwendet haben. Die folgende Abbildung zeigt die Ergebnisse für unser GPU-Skalierungsexperiment. Die rot gepunktete Linie stellt dar, wie die Trainingszeit von einem Lauf mit 8 GPUs durch Erhöhen der Anzahl von GPUs verringert werden sollte. Wie wir sehen können, liegt die Skalierung ziemlich nahe an dem, was erwartet wird.
Auf ähnliche Weise haben wir das GPU-Skalierungsdiagramm für das ResNet50-Training auf p3.8xlarge-Instances erhalten. Für diesen Fall haben wir die Replikate in unserer .yaml-Datei von 1 auf 4 geändert. Die Ergebnisse dieses Experiments sind in der folgenden Abbildung dargestellt.
Aufräumen
Es ist wichtig, Ressourcen nach dem Modelltraining herunterzufahren, um Kosten zu vermeiden, die mit dem Ausführen von Leerlaufinstanzen verbunden sind. Bei jedem Skript, das Ressourcen erstellt, wird die GitHub Repo stellt ein passendes Skript bereit, um sie zu löschen. Um unser Setup zu bereinigen, müssen wir das FSx-Dateisystem löschen, bevor wir den Cluster löschen, da es einem Subnetz in der VPC des Clusters zugeordnet ist. Um das FSx-Dateisystem zu löschen, müssen wir nur den folgenden Befehl ausführen (innerhalb der fsx Mappe):
Beachten Sie, dass dadurch nicht nur das persistente Volume, sondern auch das FSx-Dateisystem gelöscht wird und alle Daten im Dateisystem verloren gehen. Wenn dieser Schritt abgeschlossen ist, können wir den Cluster löschen, indem wir das folgende Skript in der verwenden ex Ordner:
Dadurch werden alle vorhandenen Pods gelöscht, der Cluster entfernt und die zu Beginn erstellte VPC gelöscht.
Zusammenfassung
In diesem Beitrag haben wir die Schritte beschrieben, die zum Ausführen des parallelen PyTorch-Modelltrainings für verteilte Daten auf EKS-Clustern erforderlich sind. Diese Aufgabe mag entmutigend erscheinen, aber die AWS DevOps für EKS Das vom ML Frameworks-Team bei AWS erstellte Projekt bietet alle erforderlichen Skripte und Tools, um den Prozess zu vereinfachen und das Training verteilter Modelle leicht zugänglich zu machen.
Weitere Informationen zu den in diesem Beitrag verwendeten Technologien finden Sie unter Amazon EX und Fackel verteilt elastisch. Wir empfehlen Ihnen, den hier beschriebenen Ansatz auf Ihre eigenen Anwendungsfälle für verteilte Schulungen anzuwenden.
Downloads
Über die Autoren
Imran Younus ist ein Principal Solutions Architect für ML Frameworks-Team bei AWS. Er konzentriert sich auf groß angelegte maschinelle Lern- und Deep-Learning-Workloads über AWS-Services wie Amazon EKS und AWS ParallelCluster. Er verfügt über umfangreiche Erfahrung in Anwendungen von Deep Leaning in Computer Vision und Industrial IoT. Imran promovierte in Hochenergieteilchenphysik, wo er an der Analyse experimenteller Daten im Petabyte-Maßstab beteiligt war.
Alex Iankoulski ist ein Full-Stack-Software- und Infrastrukturarchitekt, der gerne tiefgreifende, praktische Arbeit leistet. Derzeit ist er Principal Solutions Architect für selbstverwaltetes maschinelles Lernen bei AWS. In seiner Rolle konzentriert er sich darauf, Kunden bei der Containerisierung und Orchestrierung von ML- und KI-Workloads auf containergestützten AWS-Services zu unterstützen. Er ist auch der Autor der Open Source Rahmen tun und ein Docker-Kapitän, der es liebt, Containertechnologien einzusetzen, um das Innovationstempo zu beschleunigen und gleichzeitig die größten Herausforderungen der Welt zu lösen. In den letzten 10 Jahren hat Alex daran gearbeitet, den Klimawandel zu bekämpfen, KI und ML zu demokratisieren, Reisen sicherer, die Gesundheitsversorgung zu verbessern und Energie intelligenter zu machen.
- AI
- Kunst
- KI-Kunstgenerator
- KI-Roboter
- Amazon Elastic Kubernetes-Service
- künstliche Intelligenz
- Zertifizierung für künstliche Intelligenz
- Künstliche Intelligenz im Bankwesen
- Roboter mit künstlicher Intelligenz
- Roboter mit künstlicher Intelligenz
- Software für künstliche Intelligenz
- AWS Maschinelles Lernen
- Blockchain
- Blockchain-Konferenz ai
- Einfallsreichtum
- dialogorientierte künstliche Intelligenz
- Krypto-Konferenz ai
- Dalls
- tiefe Lernen
- Google Ai
- Mittel (200)
- Maschinelles Lernen
- Plato
- platon ai
- Datenintelligenz von Plato
- Plato-Spiel
- PlatoData
- Platogaming
- Skala ai
- Syntax
- Zephyrnet