In den vorherigen Artikeln haben wir darüber gesprochen, was wir mit Learning To Rank (LTR) erreichen wollen. In diesem Artikel geben wir einige Einblicke in die Entwicklung der Judgement Pipeline, die als Grundlage für zukünftige LTR-Pipelines dienen soll. Was macht eine Beurteilungspipeline im LTR-Kontext? Sie berechnet Beurteilungen auf der Grundlage von Benutzerdaten für einen bestimmten Zeitraum. Diese Beurteilungen dienen als Labels, auf denen ein Ranking-Modell trainiert wird. Derzeit exportieren wir diese Bewertungen auch zur Live-Validierung für ausgewählte Abfragen.
In diesem Blogbeitrag sollen die folgenden Fragen beantwortet werden:
Lass uns die erste Frage aus dem Weg räumen und darüber nachdenken, wie unsere endgültige Pipeline aussehen sollte. Die komplette Pipeline würde aus den folgenden Schritten bestehen:
Wenn wir mit LTR live gehen, wird der Output von Schritt 3 in unser Ranking-Modell eingespeist, um es täglich neu zu trainieren.
Wie haben wir begonnen?
Wir haben eine Proof-of-Concept-Phase für LTR mit einer sehr großen EC2-Instanz durchgeführt, die all diese Anforderungen erfüllen konnte. Dann erstellten wir Skripte für jeden einzelnen Schritt, die wir über ein einfaches Orchestrierungsskript ausführten. Das war zwar einigermaßen flexibel, aber Zuverlässigkeit und Skalierbarkeit waren bei weitem nicht so, wie wir es uns gewünscht hatten.
Da die Ergebnisse unserer POC vielversprechend waren, bestand unser nächster Schritt darin, eine flexible und skalierbare Pipeline in AWS zu erstellen.
Wir wollten von der POC direkt zu einer produktionsreifen Pipeline übergehen. Daher entschieden wir uns für ein AWS-Prototyping, bei dem wir Unterstützung von erfahrenen Beratern erhielten.
Das Ergebnis ist eine flexible und skalierbare Pipeline, die schnelle Iterationen auf unkomplizierte Art und Weise ermöglicht. In den nächsten Abschnitten werden wir beschreiben, wie diese Pipeline aussieht.
Werfen wir einen Blick darauf, wie unsere Services die notwendigen Schritte für unsere Beurteilungspipeline handhaben. Wir orchestrieren die Schritte über Dark Knight, einen AWS Step Functions-Workflow:
Im Folgenden erhalten Sie einen tieferen Einblick in die Technologie, die unsere Dienste und die Pipeline nutzen.
Die meisten Entwickler in unserem Team kommen mit Python gut zurecht, daher haben wir Python als Hauptsprache gewählt. Wenn wir eine große Datenmenge umwandeln müssen, verwenden wir Pyspark. Wir glauben fest an den Infrastructure-as-Code-Ansatz zum Aufbau einer nachhaltigen und wartbaren Cloud-Infrastruktur. Der größte Teil unserer Infrastruktur wird über Terraform bereitgestellt, für kompliziertere Orchestrationen verwenden wir AWS Step Functions.
Im Allgemeinen handelt es sich bei unseren Services um AWS Sagemaker Processing Jobs, die auf einem Elastic Map Reduce (EMR)-Cluster laufen. Dadurch können wir die Verarbeitungszeiten und -kosten kontrollieren, indem wir die Größe des Clusters je nach Bedarf einfach nach oben oder unten skalieren.
Zur Orchestrierung unserer Services haben wir mit dem AWS Step Functions Data Science SDK einen Workflow-Graphen in Python erstellt. Dadurch können wir jeden Parameter eines beliebigen Dienstes ändern, indem wir einfach eine json-Datei bearbeiten und diese Änderungen hochladen, ohne die gesamte Pipeline neu bereitstellen zu müssen.
Let’s take a look at a JSON snippet which configures the solrizer step in our pipeline:
{
"solrizer": {
"job_name": "solrizer-{job_id}",
"input": {
"relevant_queries_file": "s3://path",
"tesla_bucket": "bucket-path",
"judgements_path": "s3://path/{context}/{version}/{job_id}/output/judgement_scores.parquet"
},
"runtime": {
"execute": true,
"top_offers_per_query_limit": 100,
"min_variations_per_offer_warning_threshold": 1000,
"instance_count": 1,
"instance_type": "ml.m5.4xlarge",
"filter_by_availability": false,
"judgement_col_name": "weighted_click_judgement_score",
"image_uri": "ecr:latest"
},
"output": {
"config": "s3://bucket/temp/{context}/{version}/{job_id}/config.json",
"path": "s3://bucket/temp/{context}/{version}/{job_id}/elevate-judgements.xml",
"logs": "s3://bucket/temp/{context}/{version}/{job_id}/logs"
}
}
}
Das Codeschnipsel beschreibt alle notwendigen Parameter für den Solrizer-Schritt in unserem Workflow. Das JSON besteht aus 4 Feldern: job_name, input, runtime und output. Der job_name wird programmatisch auf die ID des gesamten Workflows gesetzt, damit wir die einzelnen Schritte in der AWS-Konsole leichter überprüfen können.
Im Eingabefeld legen wir alle erforderlichen Datenquellen fest, die dieser Schritt benötigt. Beachten Sie, dass der Beurteilungspfad kontextsensitiv ist, so dass dieser Schritt automatisch die richtigen Daten für diese Workflow-ID und Version abruft.
Über die zur Laufzeit eingestellten Parameter können wir einzelne Schritte einfach ein- oder ausschalten, Feature-Toggles setzen oder die Instanzgröße für den entsprechenden Schritt ändern. Der image_uri-Wert beschreibt, welche Version des Docker-Images verwendet werden soll, so dass wir schnell verschiedene Versionen unseres Codes für diesen Schritt auswählen können.
Das Feld output teilt dem "Schritt" mit, wo die Informationen über den Lauf protokolliert werden sollen und wo die resultierenden Daten zu speichern sind. Wir machen regelmäßig Gebrauch davon, indem wir Ad-hoc-Analysen der Ausgabe von Schritten in unseren Pipelines durchführen. Es ermöglicht uns auch, nur Teile der Pipeline erneut auszuführen und dabei Daten zu verwenden, die von verschiedenen Läufen stammen.
Normalerweise ist dieser Ausgabepfad dann der Eingabepfad für den nächsten Schritt im Arbeitsablauf.
Die vollständige Konfiguration für einen Dark Knight-Lauf besteht dann aus einer Kette von Konfigurationen wie der obigen. Sobald eine beendet ist, wird die nächste ausgelöst und so weiter.
Das ist im Grunde alles 😉
Mit diesen Konzepten haben wir eine Datenpipeline aufgebaut, die skalierbar, flexibel und robust ist. Wir sind sehr zufrieden mit dem Ergebnis 😊.
Wir haben viel über die Funktionen gelernt, die bestimmte AWS-Dienste bieten können, und darüber, welche anderen Dienste es gibt. Seit dem Aufbau dieser Pipeline haben wir viel Erfahrung mit dieser Art von Infrastruktur gesammelt und hatten bisher keine größeren Probleme.
Dennoch war es nicht immer so einfach, wie es hätte sein können. Auch AWS-Dienste haben ihre Grenzen. Einige sind relativ neu oder befinden sich noch in der Entwicklung. Alle Probleme, mit denen wir konfrontiert wurden, konnten jedoch recht schnell gelöst werden; entweder dank unseres sehr guten Supports, dank der gründlichen Dokumentation oder durch Durchsicht des Codes selbst.
Wie geht es weiter?
Ein großer nächster Schritt wird sein, unsere gesamte LTR-Pipeline live zu schalten. Wir freuen uns darauf, alles, was wir bei der Entwicklung der Judgement-Pipeline gelernt haben, in unsere erste Pipeline für maschinelles Lernen einfließen zu lassen. Sie sollte genauso skalierbar und flexibel sein wie unsere Datenverarbeitungspipeline.
Wenn diese Themen für dich interessant klingen und/oder du Erfahrung im Aufbau von ML-Pipelines hast, würden wir uns gerne mit dir austauschen oder dich in unserem Team willkommen heißen -> kontaktiere uns einfach unter JARVISttd
We have received your feedback.