Content from Ausführen von Befehlen mit Snakemake
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie führe ich einen einfachen Befehl mit Snakemake aus?”
Ziele
- “Erstelle ein Snakemake-Rezept (eine Snake-Datei)”
Für welchen Arbeitsablauf interessiere ich mich?
In dieser Lektion werden wir ein Experiment durchführen, bei dem wir eine parallel laufende Anwendung auf ihre Skalierbarkeit hin untersuchen. Dazu müssen wir Daten sammeln. In diesem Fall bedeutet das, dass wir die Anwendung mehrmals mit einer unterschiedlichen Anzahl von CPU-Kernen ausführen und die Ausführungszeit aufzeichnen. Danach müssen wir eine Visualisierung der Daten erstellen, um zu sehen, wie sie sich im Vergleich zum Idealfall verhalten.
Anhand der Visualisierung können wir dann entscheiden, in welchem Maßstab es am sinnvollsten ist, die Anwendung in der Produktion laufen zu lassen, um die CPU-Zuweisung auf dem System optimal zu nutzen.
Wir könnten all dies manuell tun, aber es gibt nützliche Tools, die uns bei der Verwaltung von Datenanalyse-Pipelines, wie wir sie in unserem Experiment haben, helfen. Heute werden wir eines dieser Tools kennenlernen: Snakemake.
Um mit Snakemake zu beginnen, nehmen wir zunächst einen einfachen
Befehl und sehen, wie wir ihn mit Snakemake ausführen können. Wählen wir
den Befehl hostname
, der den Namen des Rechners ausgibt,
auf dem der Befehl ausgeführt wird:
AUSGABE
node1.int.jetstream2.hpc-carpentry.org
Das gibt das Ergebnis aus, aber Snakemake verlässt sich auf Dateien, um den Status Ihres Workflows zu kennen, also leiten wir die Ausgabe in eine Datei um:
Erstellen einer Snake-Datei
Bearbeiten Sie eine neue Textdatei mit dem Namen
Snakefile
.
Inhalt von Snakefile
:
PYTHON
rule hostname_login:
output: "hostname_login.txt"
input:
shell:
"hostname > hostname_login.txt"
Wichtige Punkte zu dieser Datei
- Die Datei heißt
Snakefile
- mit einem großenS
und ohne Dateierweiterung. - Einige Zeilen sind eingerückt. Einrückungen müssen mit Leerzeichen, nicht mit Tabulatoren erfolgen. Wie Sie Ihren Texteditor dazu bringen, dies zu tun, erfahren Sie im Abschnitt “Setup”.
- Die Regeldefinition beginnt mit dem Schlüsselwort
rule
, gefolgt von dem Namen der Regel und einem Doppelpunkt. - Wir haben die Regel
hostname_login
genannt. Sie können Buchstaben, Zahlen oder Unterstriche verwenden, aber der Name der Regel muss mit einem Buchstaben beginnen und darf kein Schlüsselwort sein. - Die Schlüsselwörter
input
,output
undshell
werden alle von einem Doppelpunkt (“:”) gefolgt. - Die Dateinamen und der Shell-Befehl sind alle in
"quotes"
. - Der Name der Ausgabedatei wird vor dem Namen der Eingabedatei angegeben. Eigentlich ist es Snakemake egal, in welcher Reihenfolge sie erscheinen, aber wir geben in diesem Kurs die Ausgabe zuerst an. Wir werden gleich sehen, warum.
- In diesem Anwendungsfall gibt es keine Eingabedatei für den Befehl, also lassen wir dieses Feld leer.
Zurück in der Shell werden wir unsere neue Regel ausführen. An diesem Punkt, wenn es irgendwelche fehlenden Anführungszeichen, falsche Einrückungen, etc. gab, werden wir einen Fehler sehen.
bash: snakemake: command not found...
Wenn Ihre Shell Ihnen mitteilt, dass sie den Befehl
snakemake
nicht finden kann, müssen wir die Software
irgendwie verfügbar machen. In unserem Fall bedeutet das, dass wir nach
dem Modul suchen müssen, das wir laden wollen:
AUSGABE
[ocaisa@node1 ~]$ module spider snakemake
--------------------------------------------------------------------------------------------------------
snakemake:
--------------------------------------------------------------------------------------------------------
Versions:
snakemake/8.2.1-foss-2023a
snakemake/8.2.1 (E)
Names marked by a trailing (E) are extensions provided by another module.
--------------------------------------------------------------------------------------------------------
For detailed information about a specific "snakemake" package (including how to load the modules) use the module's full name.
Note that names that have a trailing (E) are extensions provided by other modules.
For example:
$ module spider snakemake/8.2.1
--------------------------------------------------------------------------------------------------------
Jetzt wollen wir das Modul, also laden wir es, um das Paket verfügbar zu machen
und dann stellen Sie sicher, dass der Befehl snakemake
verfügbar ist
AUSGABE
/cvmfs/software.eessi.io/host_injections/2023.06/software/linux/x86_64/amd/zen3/software/snakemake/8.2.1-foss-2023a/bin/snakemake
Ausführen von Snakemake
Führen Sie snakemake --help | less
aus, um die Hilfe für
alle verfügbaren Optionen zu sehen. Was bewirkt die Option
-p
in dem obigen Befehl snakemake
?
- Schützt bestehende Ausgabedateien
- Gibt die Shell-Befehle, die gerade ausgeführt werden, auf dem Terminal aus
- Sagt Snakemake, dass es nur einen Prozess auf einmal ausführen soll
- Fordert den Benutzer auf, die richtige Eingabedatei zu wählen
Sie können im Text suchen, indem Sie / drücken, und mit q zur Shell zurückkehren.
- Gibt die Shell-Befehle, die gerade ausgeführt werden, auf dem Terminal aus
Dies ist so nützlich, dass wir nicht wissen, warum es nicht die
Standardeinstellung ist! Die Option -j1
sagt Snakemake,
dass es immer nur einen Prozess auf einmal ausführen soll, und wir
bleiben vorerst dabei, da es die Dinge einfacher macht. Antwort 4 ist
ein totales Ablenkungsmanöver, da Snakemake niemals interaktiv nach
Benutzereingaben fragt.
Hauptpunkte
- “Bevor Sie Snakemake starten, müssen Sie ein Snakefile schreiben”
- “Ein Snakefile ist eine Textdatei, die eine Liste von Regeln definiert”
- “Regeln haben Eingänge, Ausgänge und Shell-Befehle, die ausgeführt werden sollen”
- “Du sagst Snakemake, welche Datei es erstellen soll, und es wird den in der entsprechenden Regel definierten Shell-Befehl ausführen”
Content from Ausführen von Snakemake auf dem Cluster
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie führe ich meine Snakemake-Regel auf dem Cluster aus?”
Ziele
- “Definieren Sie Regeln, die lokal und auf dem Cluster ausgeführt werden”
Was passiert, wenn wir unsere Regel auf dem Cluster und nicht auf dem Anmeldeknoten laufen lassen wollen? Der Cluster, den wir verwenden, benutzt Slurm, und es ist so, dass Snakemake eine eingebaute Unterstützung für Slurm hat, wir müssen ihm nur sagen, dass wir es benutzen wollen.
Snakemake verwendet die Option executor
, um Ihnen die
Möglichkeit zu geben, das Plugin auszuwählen, mit dem Sie die Regel
ausführen möchten. Der schnellste Weg, dies auf Ihr Snakefile
anzuwenden, ist, dies auf der Kommandozeile zu definieren. Probieren wir
es aus
AUSGABE
Building DAG of jobs...
Retrieving input from storage.
Nothing to be done (all requested files are present and up to date).
Nichts passiert! Warum nicht? Wenn Snakemake aufgefordert wird, ein Ziel zu erstellen, prüft es die “letzte Änderungszeit” sowohl des Ziels als auch seiner Abhängigkeiten. Wenn eine der Abhängigkeiten seit dem Ziel aktualisiert wurde, werden die Aktionen erneut ausgeführt, um das Ziel zu aktualisieren. Auf diese Weise weiß Snakemake, dass es nur die Dateien neu erstellen muss, die entweder direkt oder indirekt von der geänderten Datei abhängen. Dies wird inkrementeller Build genannt.
Inkrementelle Builds verbessern die Effizienz
Indem Snakemake Dateien nur bei Bedarf neu erstellt, macht es Ihre Verarbeitung effizienter.
Läuft auf dem Cluster
Wir brauchen jetzt eine weitere Regel, die die hostname
auf dem Cluster ausführt. Erstellen Sie eine neue Regel in
Ihrem Snakefile und versuchen Sie, sie auf dem Cluster mit der Option
--executor slurm
bis snakemake
auszuführen.
Die Regel ist fast identisch mit der vorherigen Regel, abgesehen vom Namen der Regel und der Ausgabedatei:
PYTHON
rule hostname_remote:
output: "hostname_remote.txt"
input:
shell:
"hostname > hostname_remote.txt"
Sie können die Regel dann ausführen mit
AUSGABE
Building DAG of jobs...
Retrieving input from storage.
Using shell: /cvmfs/software.eessi.io/versions/2023.06/compat/linux/x86_64/bin/bash
Provided remote nodes: 1
Job stats:
job count
--------------- -------
hostname_remote 1
total 1
Select jobs to execute...
Execute 1 jobs...
[Mon Jan 29 18:03:46 2024]
rule hostname_remote:
output: hostname_remote.txt
jobid: 0
reason: Missing output files: hostname_remote.txt
resources: tmpdir=<TBD>
hostname > hostname_remote.txt
No SLURM account given, trying to guess.
Guessed SLURM account: def-users
No wall time information given. This might or might not work on your cluster.
If not, specify the resource runtime in your rule or as a reasonable default
via --default-resources. No job memory information ('mem_mb' or
'mem_mb_per_cpu') is given - submitting without.
This might or might not work on your cluster.
Job 0 has been submitted with SLURM jobid 326 (log: /home/ocaisa/.snakemake/slurm_logs/rule_hostname_remote/326.log).
[Mon Jan 29 18:04:26 2024]
Finished job 0.
1 of 1 steps (100%) done
Complete log: .snakemake/log/2024-01-29T180346.788174.snakemake.log
Beachten Sie die Warnungen, die Snakemake ausgibt, dass die Regel
möglicherweise nicht auf unserem Cluster ausgeführt werden kann, da wir
nicht genügend Informationen angegeben haben. Zum Glück für uns
funktioniert dies auf unserem Cluster und wir können einen Blick in die
Ausgabedatei werfen, die die neue Regel erzeugt,
hostname_remote.txt
:
AUSGABE
tmpnode1.int.jetstream2.hpc-carpentry.org
Snakemake-Profil
Das Anpassen von Snakemake an eine bestimmte Umgebung kann viele Flags und Optionen mit sich bringen. Daher ist es möglich, ein Konfigurationsprofil anzugeben, das verwendet wird, um Standardoptionen zu erhalten. Das sieht dann so aus
Der Profilordner muss eine Datei namens config.yaml
enthalten, in der unsere Optionen gespeichert werden. Der Ordner kann
auch andere Dateien enthalten, die für das Profil erforderlich sind.
Erstellen wir die Datei cluster_profile/config.yaml
und
fügen wir einige unserer bestehenden Optionen ein:
Wir sollten nun in der Lage sein, unseren Workflow erneut
auszuführen, indem wir auf das Profil verweisen, anstatt die Optionen
aufzulisten. Um die erneute Ausführung unseres Arbeitsablaufs zu
erzwingen, müssen wir zuerst die Ausgabedatei
hostname_remote.txt
entfernen, und dann können wir unser
neues Profil ausprobieren
BASH
[ocaisa@node1 ~]$ rm hostname_remote.txt
[ocaisa@node1 ~]$ snakemake --profile cluster_profile hostname_remote
Das Profil ist im Kontext unseres Clusters sehr nützlich, da der Slurm-Executor viele Optionen hat, die man manchmal benutzen muss, um Jobs an den Cluster zu übermitteln, auf den man Zugriff hat. Leider sind die Namen der Optionen in Snakemake nicht exakt dieselben wie die von Slurm, so dass wir die Hilfe einer Übersetzungstabelle benötigen:
SLURM | Snakemake | Description |
---|---|---|
--partition |
slurm_partition |
the partition a rule/job is to use |
--time |
runtime |
the walltime per job in minutes |
--constraint |
constraint |
may hold features on some clusters |
--mem |
mem, mem_mb |
memory a cluster node must |
provide (mem: string with unit), mem_mb: int | ||
--mem-per-cpu |
mem_mb_per_cpu |
memory per reserved CPU |
--ntasks |
tasks |
number of concurrent tasks / ranks |
--cpus-per-task |
cpus_per_task |
number of cpus per task (in case of SMP, rather use
threads ) |
--nodes |
nodes |
number of nodes |
Die von Snakemake ausgegebenen Warnungen wiesen darauf hin, dass wir
diese Optionen möglicherweise bereitstellen müssen. Eine Möglichkeit,
dies zu tun, ist, sie als Teil der Snakemake-Regel mit dem Schlüsselwort
resources
anzugeben, z.B,
und wir können das Profil auch verwenden, um Standardwerte für diese
Optionen zu definieren, die wir für unser Projekt verwenden, indem wir
das Schlüsselwort default-resources
verwenden. Der
verfügbare Arbeitsspeicher unseres Clusters beträgt beispielsweise etwa
4 GB pro Kern, so dass wir dies zu unserem Profil hinzufügen können:
Aufgabe
Wir wissen, dass unser Problem in einer sehr kurzen Zeit abläuft. Ändern Sie die Standardlänge unserer Jobs auf zwei Minuten für Slurm.
Es gibt verschiedene sbatch
Optionen, die nicht direkt
von den Ressourcendefinitionen in der obigen Tabelle unterstützt werden.
Du kannst die slurm_extra
Ressource benutzen, um jede
dieser zusätzlichen Flags für sbatch
anzugeben:
Lokale Regelausführung
Unsere ursprüngliche Regel war es, den Hostnamen des Anmeldeknotens zu ermitteln. Wir wollen diese Regel immer auf dem Login-Knoten ausführen, damit sie Sinn macht. Wenn wir Snakemake anweisen, alle Regeln über den Slurm-Executor auszuführen (was wir über unser neues Profil tun), wird dies nicht mehr geschehen. Wie können wir also erzwingen, dass die Regel auf dem Anmeldeknoten ausgeführt wird?
Nun, in dem Fall, in dem eine Snakemake-Regel eine triviale Aufgabe
ausführt, könnte die Übermittlung eines Jobs ein Overkill sein (z.B.
weniger als 1 Minute Rechenzeit). Ähnlich wie in unserem Fall wäre es
eine bessere Idee, diese Regeln lokal auszuführen (d.h. dort, wo der
Befehl snakemake
ausgeführt wird), anstatt sie als Job zu
übermitteln. In Snakemake können Sie mit dem Schlüsselwort
localrules
angeben, welche Regeln immer lokal ausgeführt
werden sollen. Definieren wir hostname_login
als lokale
Regel nahe dem Anfang unseres Snakefile
.
Hauptpunkte
- “Snakemake generiert und übermittelt seine eigenen Batch-Skripte für Ihren Scheduler.”
- “Sie können Standardkonfigurationseinstellungen in einem Snakemake-Profil speichern”
- “
localrules
definiert Regeln, die lokal ausgeführt werden und nie an einen Cluster übermittelt werden.”
Content from Platzhalter
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie kann ich eine generische Regel erstellen?”
Ziele
- “Sehen Sie, wie Snakemake mit einigen Fehlern umgeht”
Unser Snakefile hat einige Duplikate. Zum Beispiel werden die Namen von Textdateien an einigen Stellen in den Snakefile-Regeln wiederholt. Snakefiles sind eine Form von Code, und in jedem Code können Wiederholungen zu Problemen führen (z. B. wenn wir eine Datendatei in einem Teil des Snakefiles umbenennen, aber vergessen, sie an anderer Stelle umzubenennen).
D.R.Y. (Don’t Repeat Yourself)
In vielen Programmiersprachen ist der Großteil der Sprachfunktionen dazu da, dem Programmierer die Möglichkeit zu geben, langatmige Berechnungsroutinen als kurzen, ausdrucksstarken und schönen Code zu beschreiben. Funktionen in Python, R oder Java, wie z. B. benutzerdefinierte Variablen und Funktionen, sind zum Teil deshalb nützlich, weil sie bedeuten, dass wir nicht alle Details immer und immer wieder ausschreiben (oder darüber nachdenken) müssen. Diese gute Angewohnheit, Dinge nur einmal auszuschreiben, ist bekannt als das “Don’t Repeat Yourself”-Prinzip oder D.R.Y.
Machen wir uns daran, einige der Wiederholungen aus unserem Snakefile zu entfernen.
Platzhalter
Um eine allgemeinere Regel zu erstellen, brauchen wir Platzhalter. Schauen wir uns mal an, wie ein Platzhalter aussieht
Zur Erinnerung, hier ist die vorherige Version aus der letzten Folge:
PYTHON
rule hostname_remote:
output: "hostname_remote.txt"
input:
shell:
"hostname > hostname_remote.txt"
Die neue Regel hat explizite Dateinamen durch Dinge in
{curly brackets}
ersetzt, speziell {output}
(aber es hätte auch {input}
sein können…wenn das einen Wert
hätte und nützlich wäre).
{input}
und {output}
sind
Platzhalter
Platzhalter werden im Abschnitt shell
einer Regel
verwendet, und Snakemake ersetzt sie durch entsprechende Werte -
{input}
durch den vollständigen Namen der Eingabedatei und
{output}
durch den vollständigen Namen der Ausgabedatei –
bevor der Befehl ausgeführt wird.
{resources}
ist auch ein Platzhalter, und wir können auf
ein benanntes Element des {resources}
mit der Notation
{resources.runtime}
zugreifen (zum Beispiel).
Hauptpunkte
- “Snakemake-Regeln werden mit Platzhaltern generischer gestaltet”
- “Platzhalter im Shell-Teil der Regel werden durch Werte ersetzt, die auf den gewählten Platzhaltern basieren”
Content from MPI-Anwendungen und Snakemake
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie kann ich eine MPI-Anwendung über Snakemake auf dem Cluster laufen lassen?”
Ziele
- “Definieren Sie Regeln, die lokal und im Cluster ausgeführt werden sollen”
Jetzt ist es an der Zeit, sich wieder unserem eigentlichen
Arbeitsablauf zuzuwenden. Wir können einen Befehl auf dem Cluster
ausführen, aber was ist mit der Ausführung der MPI-Anwendung, an der wir
interessiert sind? Unsere Anwendung heißt amdahl
und ist
als Umgebungsmodul verfügbar.
Aufgabe
Suchen und laden Sie das Modul amdahl
und
ersetzen Sie dann unsere hostname_remote
-Regel
durch eine Version, die amdahl
ausführt. (Machen Sie sich
noch keine Gedanken über paralleles MPI, lassen Sie es mit einer
einzelnen CPU laufen, mpiexec -n 1 amdahl
).
Wurde Ihre Regel korrekt ausgeführt? Wenn nicht, sehen Sie sich die Protokolldateien an, um herauszufinden, warum?
findet und lädt das Modul amdahl
. Wir können dann unsere
Regel aktualisieren/ersetzen, um die Anwendung amdahl
auszuführen:
Wenn wir jedoch versuchen, die Regel auszuführen, erhalten wir eine
Fehlermeldung (es sei denn, Sie haben bereits eine andere Version von
amdahl
in Ihrem Pfad verfügbar). Snakemake meldet den
Speicherort der Protokolle und wenn wir darin nachsehen, finden wir
(eventuell)
AUSGABE
...
mpiexec -n 1 amdahl > amdahl_run.txt
--------------------------------------------------------------------------
mpiexec was unable to find the specified executable file, and therefore
did not launch the job. This error was first reported for process
rank 0; it may have occurred for other processes as well.
NOTE: A common cause for this error is misspelling a mpiexec command
line parameter option (remember that mpiexec interprets the first
unrecognized command line token as the executable).
Node: tmpnode1
Executable: amdahl
--------------------------------------------------------------------------
...
Obwohl wir das Modul vor der Ausführung des Workflows geladen haben, hat unsere Snakemake-Regel die ausführbare Datei nicht gefunden. Das liegt daran, dass die Snakemake-Regel in einer sauberen Laufzeitumgebung läuft, und wir müssen ihr irgendwie sagen, dass sie das notwendige Umgebungsmodul laden soll, bevor wir versuchen, die Regel auszuführen.
Snakemake und Umgebungsmodule
Unsere Anwendung heißt amdahl
und ist auf dem System
über ein Umgebungsmodul verfügbar, also müssen wir Snakemake sagen, dass
es das Modul laden soll, bevor es versucht, die Regel auszuführen.
Snakemake kennt Umgebungsmodule, und diese können über eine (weitere)
Option angegeben werden:
PYTHON
rule amdahl_run:
output: "amdahl_run.txt"
input:
envmodules:
"mpi4py",
"amdahl"
input:
shell:
"mpiexec -n 1 amdahl > {output}"
Das Hinzufügen dieser Zeilen reicht jedoch nicht aus, damit die Regel ausgeführt wird. Sie müssen Snakemake nicht nur mitteilen, welche Module geladen werden sollen, sondern auch, dass es generell Umgebungsmodule verwenden soll (da die Verwendung von Umgebungsmodulen Ihre Laufzeitumgebung weniger reproduzierbar macht, da sich die verfügbaren Module von Cluster zu Cluster unterscheiden können). Dazu müssen Sie Snakemake eine zusätzliche Option geben
Aufgabe
Wir werden im weiteren Verlauf des Tutorials Umgebungsmodule
verwenden, also machen Sie diese Option zu einer Standardoption unseres
Profils (indem Sie den Wert auf True
setzen)
Snakemake und MPI
Im letzten Abschnitt haben wir nicht wirklich eine MPI-Anwendung laufen lassen, da wir nur auf einem Kern gearbeitet haben. Wie können wir für eine einzelne Regel die Ausführung auf mehreren Kernen anfordern?
Snakemake bietet allgemeine Unterstützung für MPI, aber der einzige Executor, der MPI derzeit explizit unterstützt, ist der Slurm-Executor (ein Glück für uns!). Wenn wir uns unsere Übersetzungstabelle von Slurm nach Snakemake ansehen, stellen wir fest, dass die relevanten Optionen am unteren Rand erscheinen:
SLURM | Snakemake | Description |
---|---|---|
… | … | … |
--ntasks |
tasks |
number of concurrent tasks / ranks |
--cpus-per-task |
cpus_per_task |
number of cpus per task (in case of SMP, rather use
threads ) |
--nodes |
nodes |
number of nodes |
Diejenige, die uns interessiert, ist tasks
, da wir nur
die Anzahl der Ränge erhöhen wollen. Wir können diese in einem
resources
-Abschnitt unserer Regel definieren und mit
Platzhaltern auf sie verweisen:
PYTHON
rule amdahl_run:
output: "amdahl_run.txt"
input:
envmodules:
"amdahl"
resources:
mpi='mpiexec',
tasks=2
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl > {output}"
Das hat funktioniert, aber jetzt haben wir ein kleines Problem. Wir
wollen dies für einige verschiedene Werte von tasks
machen,
was bedeuten würde, dass wir für jeden Lauf eine andere Ausgabedatei
benötigen. Es wäre großartig, wenn wir irgendwie in output
den Wert angeben könnten, den wir für tasks
verwenden
wollen… und Snakemake das übernehmen könnte.
Wir koennten eine Wildcard in output
benutzen,
um das tasks
zu definieren, das wir benutzen wollen. Die
Syntax für einen solchen Platzhalter sieht wie folgt aus
wobei parallel_tasks
unser Platzhalter ist.
Wildcards
Wildcards werden in den Zeilen input
und
output
der Regel verwendet, um Teile von Dateinamen zu
repräsentieren. Ähnlich wie das Muster *
in der Shell kann
der Platzhalter für jeden beliebigen Text stehen, um den gewünschten
Dateinamen zu bilden. Wie bei der Benennung Ihrer Regeln können Sie auch
für Ihre Platzhalter einen beliebigen Namen wählen, hier also
parallel_tasks
. Durch die Verwendung der gleichen
Platzhalter in der Eingabe und der Ausgabe wird Snakemake mitgeteilt,
wie die Eingabedateien den Ausgabedateien zugeordnet werden sollen.
Wenn zwei Regeln einen Platzhalter mit demselben Namen verwenden, werden sie von Snakemake als unterschiedliche Entitäten behandelt - Regeln in Snakemake sind auf diese Weise in sich geschlossen.
In der Zeile shell
kann man den Platzhalter mit
{wildcards.parallel_tasks}
referenzieren
Snakemake Reihenfolge der Operationen
Wir fangen gerade erst mit ein paar einfachen Regeln an, aber es lohnt sich, darüber nachzudenken, was Snakemake genau macht, wenn Sie es ausführen. Es gibt drei verschiedene Phasen:
- Bereitet sich auf die Ausführung vor:
- Liest alle Regeldefinitionen aus dem Snakefile ein
- Planen Sie, was zu tun ist:
- Zeigt an, welche Datei(en) Sie erstellen möchten
- Sucht nach einer passenden Regel, indem es die
output
aller ihm bekannten Regeln betrachtet - Füllt die Platzhalter aus, um die
input
für diese Regel zu berechnen - Prüft, ob diese Eingabedatei (falls erforderlich) tatsächlich vorhanden ist
- Führt die Schritte aus:
- Erzeugt das Verzeichnis für die Ausgabedatei, falls erforderlich
- Entfernt die alte Ausgabedatei, wenn sie bereits vorhanden ist
- Nur dann wird der Shell-Befehl mit den ersetzten Platzhaltern ausgeführt
- Prüft, ob der Befehl ohne Fehler gelaufen ist und die neue Ausgabedatei wie erwartet erstellt hat
Die Anzahl der Überprüfungen mag im Moment noch pedantisch erscheinen, aber wenn der Arbeitsablauf mehr Schritte umfasst, wird dies in der Tat sehr nützlich für uns werden.
Verwendung von Wildcards in unserer Regel
Wir möchten einen Platzhalter in output
verwenden, um
die Anzahl der tasks
zu definieren, die wir verwenden
möchten. Ausgehend von dem, was wir bisher gesehen haben, könnten Sie
sich vorstellen, dass dies wie folgt aussehen könnte
PYTHON
rule amdahl_run:
output: "amdahl_run_{parallel_tasks}.txt"
input:
envmodules:
"amdahl"
resources:
mpi="mpiexec",
tasks="{parallel_tasks}"
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl > {output}"
aber es gibt zwei Probleme damit:
- Die einzige Möglichkeit für Snakemake, den Wert des Platzhalters zu erfahren, besteht darin, dass der Benutzer explizit eine konkrete Ausgabedatei anfordert (anstatt die Regel aufzurufen):
Dies ist absolut gültig, da Snakemake herausfinden kann, dass es eine Regel hat, die auf diesen Dateinamen passt.
-
Das größere Problem ist, dass selbst das nicht funktioniert, es scheint, dass wir keinen Platzhalter für
tasks
verwenden können:AUSGABE
WorkflowError: SLURM job submission failed. The error message was sbatch: error: Invalid numeric value "{parallel_tasks}" for --ntasks.
Leider gibt es für uns keine direkte Möglichkeit, auf die Platzhalter
für tasks
zuzugreifen. Der Grund dafür ist, dass Snakemake
versucht, den Wert von tasks
während seiner
Initialisierungsphase zu verwenden, also bevor wir den Wert des
Platzhalters kennen. Wir müssen die Bestimmung von tasks
auf einen späteren Zeitpunkt verschieben. Dies kann erreicht werden,
indem für dieses Szenario eine Eingabefunktion anstelle eines Wertes
angegeben wird. Die Lösung besteht also darin, eine einmalig zu
verwendende Funktion zu schreiben, die Snakemake dazu bringt, dies für
uns zu tun. Da die Funktion speziell für die Regel gedacht ist, können
wir eine einzeilige Funktion ohne Namen verwenden. Diese Art von
Funktionen werden entweder anonyme Funktionen oder Lamdba-Funktionen
genannt (beide bedeuten dasselbe) und sind ein Merkmal von Python (und
anderen Programmiersprachen).
Um eine Lambda-Funktion in Python zu definieren, ist die allgemeine Syntax wie folgt:
Da unsere Funktion die Platzhalter als Argumente benutzen kann,
können wir damit den Wert für tasks
setzen:
PYTHON
rule amdahl_run:
output: "amdahl_run_{parallel_tasks}.txt"
input:
envmodules:
"amdahl"
resources:
mpi="mpiexec",
# No direct way to access the wildcard in tasks, so we need to do this
# indirectly by declaring a short function that takes the wildcards as an
# argument
tasks=lambda wildcards: int(wildcards.parallel_tasks)
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl > {output}"
Jetzt haben wir eine Regel, die verwendet werden kann, um die Ausgabe von Läufen einer beliebigen Anzahl von parallelen Aufgaben zu erzeugen.
Kommentare in Snakefiles
Im obigen Code ist die Zeile, die mit #
beginnt, eine
Kommentarzeile. Hoffentlich haben Sie sich bereits angewöhnt, Kommentare
in Ihre eigenen Skripte einzufügen. Gute Kommentare machen jedes Skript
besser lesbar, und das gilt auch für Snakefiles.
Da unsere Regel nun in der Lage ist, eine beliebige Anzahl von
Ausgabedateien zu erzeugen, könnte es in unserem aktuellen Verzeichnis
sehr voll werden. Es ist daher wahrscheinlich am besten, die Läufe in
einen separaten Ordner zu legen, um Ordnung zu schaffen. Wir können den
Ordner direkt zu unserem output
hinzufügen und Snakemake
wird die Erstellung des Verzeichnisses für uns übernehmen:
PYTHON
rule amdahl_run:
output: "runs/amdahl_run_{parallel_tasks}.txt"
input:
envmodules:
"amdahl"
resources:
mpi="mpiexec",
# No direct way to access the wildcard in tasks, so we need to do this
# indirectly by declaring a short function that takes the wildcards as an
# argument
tasks=lambda wildcards: int(wildcards.parallel_tasks)
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl > {output}"
Aufgabe
Erzeugt eine Ausgabedatei (unter dem Ordner runs
) für
den Fall, dass wir 6 parallele Aufgaben haben
(TIPP: Denken Sie daran, dass Snakemake in der Lage sein muss, die
angeforderte Datei mit dem output
einer Regel
abzugleichen)
Ein weiterer Punkt bei unserer Anwendung amdahl
ist,
dass wir letztendlich die Ausgabe verarbeiten wollen, um unsere
Skalierungsdarstellung zu erzeugen. Die derzeitige Ausgabe ist zwar
nützlich zum Lesen, erschwert aber die Verarbeitung. amdahl
hat eine Option, die dies für uns einfacher macht. Um die
amdahl
Optionen zu sehen, können wir verwenden
AUSGABE
usage: amdahl [-h] [-p [PARALLEL_PROPORTION]] [-w [WORK_SECONDS]] [-t] [-e]
options:
-h, --help show this help message and exit
-p [PARALLEL_PROPORTION], --parallel-proportion [PARALLEL_PROPORTION]
Parallel proportion should be a float between 0 and 1
-w [WORK_SECONDS], --work-seconds [WORK_SECONDS]
Total seconds of workload, should be an integer greater than 0
-t, --terse Enable terse output
-e, --exact Disable random jitter
Die Option, nach der wir suchen, ist --terse
, und die
bewirkt, dass amdahl
die Ausgabe in einem Format ausgibt,
das viel einfacher zu verarbeiten ist, nämlich JSON. Das JSON-Format in
einer Datei verwendet normalerweise die Dateierweiterung
.json
, also fügen wir diese Option zu unserem
shell
-Befehl hinzu und ändern das Dateiformat von
output
, damit es zu unserem neuen Befehl passt:
PYTHON
rule amdahl_run:
output: "runs/amdahl_run_{parallel_tasks}.json"
input:
envmodules:
"amdahl"
resources:
mpi="mpiexec",
# No direct way to access the wildcard in tasks, so we need to do this
# indirectly by declaring a short function that takes the wildcards as an
# argument
tasks=lambda wildcards: int(wildcards.parallel_tasks)
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl --terse > {output}"
Es gab einen weiteren Parameter für amdahl
, der mir
aufgefallen ist. amdahl
hat eine Option
--parallel-proportion
(oder -p
), an deren
Änderung wir interessiert sein könnten, da sie das Verhalten des Codes
verändert und sich somit auf die Werte auswirkt, die wir in unseren
Ergebnissen erhalten. Fügen wir eine weitere Verzeichnisebene zu unserem
Ausgabeformat hinzu, um eine bestimmte Wahl für diesen Wert
wiederzugeben. Wir können einen Platzhalter verwenden, damit wir den
Wert gleich auswählen müssen:
PYTHON
rule amdahl_run:
output: "p_{parallel_proportion}/runs/amdahl_run_{parallel_tasks}.json"
input:
envmodules:
"amdahl"
resources:
mpi="mpiexec",
# No direct way to access the wildcard in tasks, so we need to do this
# indirectly by declaring a short function that takes the wildcards as an
# argument
tasks=lambda wildcards: int(wildcards.parallel_tasks)
input:
shell:
"{resources.mpi} -n {resources.tasks} amdahl --terse -p {wildcards.parallel_proportion} > {output}"
Aufgabe
Erstellt eine Ausgabedatei für einen Wert von -p
von
0,999 (der Standardwert ist 0,8) für den Fall, dass wir 6 parallele
Aufgaben haben.
Hauptpunkte
- “Snakemake wählt die passende Regel durch Ersetzen von Platzhaltern, so dass die Ausgabe mit dem Ziel übereinstimmt”
- “Snakemake prüft auf verschiedene Fehlerbedingungen und hält an, wenn es ein Problem sieht”
Content from Verkettung von Regeln
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie kombiniere ich Regeln zu einem Workflow?”
- “Wie erstelle ich eine Regel mit mehreren Eingaben und Ausgaben?”
Ziele
- “”
Eine Pipeline mit mehreren Regeln
Wir haben jetzt eine Regel, die eine Ausgabe für jeden Wert von
-p
und eine beliebige Anzahl von Aufgaben erzeugen kann,
wir müssen Snakemake nur mit den gewünschten Parametern aufrufen:
Das ist allerdings nicht gerade praktisch, denn um einen vollständigen Datensatz zu erzeugen, müssen wir Snakemake viele Male mit verschiedenen Ausgabedateien ausführen. Lassen Sie uns stattdessen eine Regel erstellen, die diese Dateien für uns generieren kann.
Die Verkettung von Regeln in Snakemake ist eine Frage der Wahl von Dateinamensmustern, die die Regeln verbinden. Das ist eine Kunst für sich - meistens gibt es mehrere Möglichkeiten, die funktionieren:
PYTHON
rule generate_run_files:
output: "p_{parallel_proportion}_runs.txt"
input: "p_{parallel_proportion}/runs/amdahl_run_6.json"
shell:
"echo {input} done > {output}"
Aufgabe
Die neue Regel macht keine Arbeit, sie stellt nur sicher, dass wir die gewünschte Datei erzeugen. Sie ist es nicht wert, auf dem Cluster ausgeführt zu werden. Wie kann man sicherstellen, dass sie nur auf dem Anmeldeknoten ausgeführt wird?
Führen wir nun die neue Regel aus (denken Sie daran, dass wir die
Ausgabedatei mit dem Namen anfordern müssen, da das output
in unserer Regel ein Platzhaltermuster enthält):
AUSGABE
Using profile cluster_profile/ for setting default command line arguments.
Building DAG of jobs...
Retrieving input from storage.
Using shell: /cvmfs/software.eessi.io/versions/2023.06/compat/linux/x86_64/bin/bash
Provided remote nodes: 3
Job stats:
job count
------------------ -------
amdahl_run 1
generate_run_files 1
total 2
Select jobs to execute...
Execute 1 jobs...
[Tue Jan 30 17:39:29 2024]
rule amdahl_run:
output: p_0.999/runs/amdahl_run_6.json
jobid: 1
reason: Missing output files: p_0.999/runs/amdahl_run_6.json
wildcards: parallel_proportion=0.999, parallel_tasks=6
resources: mem_mb=1000, mem_mib=954, disk_mb=1000, disk_mib=954,
tmpdir=<TBD>, mem_mb_per_cpu=3600, runtime=2, mpi=mpiexec, tasks=6
mpiexec -n 6 amdahl --terse -p 0.999 > p_0.999/runs/amdahl_run_6.json
No SLURM account given, trying to guess.
Guessed SLURM account: def-users
Job 1 has been submitted with SLURM jobid 342 (log: /home/ocaisa/.snakemake/slurm_logs/rule_amdahl_run/342.log).
[Tue Jan 30 17:47:31 2024]
Finished job 1.
1 of 2 steps (50%) done
Select jobs to execute...
Execute 1 jobs...
[Tue Jan 30 17:47:31 2024]
localrule generate_run_files:
input: p_0.999/runs/amdahl_run_6.json
output: p_0.999_runs.txt
jobid: 0
reason: Missing output files: p_0.999_runs.txt;
Input files updated by another job: p_0.999/runs/amdahl_run_6.json
wildcards: parallel_proportion=0.999
resources: mem_mb=1000, mem_mib=954, disk_mb=1000, disk_mib=954,
tmpdir=/tmp, mem_mb_per_cpu=3600, runtime=2
echo p_0.999/runs/amdahl_run_6.json done > p_0.999_runs.txt
[Tue Jan 30 17:47:31 2024]
Finished job 0.
2 of 2 steps (100%) done
Complete log: .snakemake/log/2024-01-30T173929.781106.snakemake.log
Schauen Sie sich die Logging-Meldungen an, die Snakemake im Terminal ausgibt. Was ist hier passiert?
- Snakemake sucht nach einer Regel, die
p_0.999_runs.txt
erzeugt - Es bestimmt, dass “generate_run_files” dies machen kann, wenn
parallel_proportion=0.999
- Es sieht, dass die benötigte Eingabe also
p_0.999/runs/amdahl_run_6.json
ist - Snakemake sucht nach einer Regel, die
p_0.999/runs/amdahl_run_6.json
erzeugt - Es wird festgestellt, dass “amdahl_run” dies machen kann, wenn
parallel_proportion=0.999
undparallel_tasks=6
- Nachdem Snakemake eine verfügbare Eingabedatei erreicht hat (in diesem Fall ist eigentlich keine Eingabedatei erforderlich), führt es beide Schritte aus, um die endgültige Ausgabe zu erhalten
Dies ist, kurz gesagt, wie wir Arbeitsabläufe in Snakemake aufbauen.
- Definieren Sie Regeln für alle Verarbeitungsschritte
- Wählen Sie
input
undoutput
Namensmuster, die es Snakemake erlauben, die Regeln zu verknüpfen - Sagt Snakemake, dass es die endgültige(n) Ausgabedatei(en) erzeugen soll
Wenn Sie es gewohnt sind, reguläre Skripte zu schreiben, ist dies ein wenig gewöhnungsbedürftig. Anstatt die Schritte in der Reihenfolge ihrer Ausführung aufzulisten, arbeiten Sie immer rückwärts vom gewünschten Endergebnis aus. Die Reihenfolge der Operationen wird durch die Anwendung der Mustervergleichsregeln auf die Dateinamen bestimmt, nicht durch die Reihenfolge der Regeln in der Snakefile.
Outputs first?
Der Ansatz von Snakemake, von der gewünschten Ausgabe rückwärts zu
arbeiten, um den Arbeitsablauf zu bestimmen, ist der Grund, warum wir
die output
-Zeilen an den Anfang all unserer Regeln setzen -
um uns daran zu erinnern, dass es diese sind, die Snakemake zuerst
betrachtet!
Viele Benutzer von Snakemake, und auch die offizielle Dokumentation,
bevorzugen es, die input
an erster Stelle zu haben, also
sollten Sie in der Praxis die Reihenfolge verwenden, die für Sie
sinnvoll ist.
log
Ausgaben in Snakemake
Snakemake hat ein eigenes Regelfeld für Ausgaben, die [Logdateien]
(https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#log-files)
sind, und diese werden größtenteils wie reguläre Ausgaben behandelt,
außer dass Logdateien nicht entfernt werden, wenn der Job einen Fehler
produziert. Das bedeutet, dass Sie sich das Protokoll ansehen können, um
den Fehler zu diagnostizieren. In einem echten Arbeitsablauf kann dies
sehr nützlich sein, aber um die Grundlagen von Snakemake zu erlernen,
bleiben wir hier bei den regulären input
und
output
Feldern.
Fehler sind normal
Lassen Sie sich nicht entmutigen, wenn Sie beim ersten Testen Ihrer neuen Snakemake-Pipelines Fehler sehen. Beim Schreiben eines neuen Arbeitsablaufs kann eine Menge schief gehen, und Sie werden normalerweise mehrere Iterationen benötigen, um alles richtig zu machen. Ein Vorteil des Snakemake-Ansatzes im Vergleich zu normalen Skripten ist, dass Snakemake bei Problemen schnell abbricht, anstatt weiterzumachen und möglicherweise unbrauchbare Berechnungen mit unvollständigen oder beschädigten Daten durchzuführen. Ein weiterer Vorteil besteht darin, dass wir bei einem fehlgeschlagenen Schritt sicher dort weitermachen können, wo wir aufgehört haben.
Hauptpunkte
- “Snakemake verknüpft Regeln, indem es iterativ nach Regeln sucht, die fehlende Eingaben machen”
- “Regeln können mehrere benannte Eingänge und/oder Ausgänge haben”
- “Wenn ein Shell-Befehl nicht die erwartete Ausgabe liefert, wird Snakemake dies als Fehler betrachten
Content from Verarbeitung von Listen von Eingaben
Zuletzt aktualisiert am 2025-04-05 | Diese Seite bearbeiten
Übersicht
Fragen
- “Wie kann ich mehrere Dateien auf einmal verarbeiten?”
- “Wie kombiniere ich mehrere Dateien miteinander?”
Ziele
- “Verwenden Sie Snakemake, um alle unsere Proben auf einmal zu verarbeiten”
- “Erstellen Sie ein Skalierbarkeitsdiagramm, das unsere Ergebnisse zusammenfasst”
Wir haben eine Regel erstellt, die eine einzige Ausgabedatei erzeugen kann, aber wir werden nicht mehrere Regeln für jede Ausgabedatei erstellen. Wir wollen alle Ausführungsdateien mit einer einzigen Regel erzeugen, wenn es möglich ist, und Snakemake kann tatsächlich eine Liste von Eingabedateien annehmen:
PYTHON
rule generate_run_files:
output: "p_{parallel_proportion}_runs.txt"
input: "p_{parallel_proportion}/runs/amdahl_run_2.json", "p_{parallel_proportion}/runs/amdahl_run_6.json"
shell:
"echo {input} done > {output}"
Das ist großartig, aber wir wollen nicht alle Dateien, an denen wir interessiert sind, einzeln auflisten müssen. Wie können wir dies tun?
Definieren einer Liste von zu verarbeitenden Proben
Um dies zu tun, können wir einige Listen als Snakemake globale Variablen definieren.
Globale Variablen sollten vor den Regeln in der Snakefile hinzugefügt werden.
- Anders als bei Variablen in Shell-Skripten können wir Leerzeichen um
das
=
-Zeichen setzen, aber sie sind nicht zwingend erforderlich. - Die Listen der in Anführungszeichen gesetzten Zeichenketten werden in eckige Klammern gesetzt und durch Kommata getrennt. Wenn Sie Python kennen, werden Sie dies als Python-Listensyntax erkennen.
- Eine gute Konvention ist die Verwendung von großgeschriebenen Namen für diese Variablen, aber das ist nicht zwingend.
- Obwohl diese als Variablen bezeichnet werden, können Sie die Werte nicht mehr ändern, sobald der Arbeitsablauf läuft, so dass auf diese Weise definierte Listen eher Konstanten sind.
Verwendung einer Snakemake-Regel zur Definition eines Stapels von Ausgaben
Nun wollen wir unser Snakefile aktualisieren, um die neue globale Variable zu nutzen und eine Liste von Dateien zu erstellen:
PYTHON
rule generate_run_files:
output: "p_{parallel_proportion}_runs.txt"
input: expand("p_{{parallel_proportion}}/runs/amdahl_run_{count}.json", count=NTASK_SIZES)
shell:
"echo {input} done > {output}"
Die Funktion expand(...)
in dieser Regel erzeugt eine
Liste von Dateinamen, indem sie das erste Element in den einfachen
Klammern als Vorlage nimmt und {count}
durch alle
NTASK_SIZES
ersetzt. Da die Liste 5 Elemente enthält,
ergibt dies 5 Dateien, die wir erstellen wollen. Beachten Sie, dass wir
unseren Platzhalter in einem zweiten Satz von Klammern schützen mussten,
damit er nicht als etwas interpretiert wird, das erweitert werden
muss.
In unserem aktuellen Fall verlassen wir uns immer noch auf den
Dateinamen, um den Wert des Platzhalters
parallel_proportion
zu definieren, also können wir die
Regel nicht direkt aufrufen, sondern müssen immer noch eine bestimmte
Datei anfordern:
Wenn Sie beim Ausführen von Snakemake auf der Befehlszeile keinen Namen für eine Zielregel oder Dateinamen angeben, wird standardmäßig die erste Regel in der Snake-Datei als Ziel verwendet.
Regeln als Ziele
Wenn Sie Snakemake den Namen einer Regel auf der Kommandozeile geben, funktioniert das nur, wenn diese Regel keine Platzhalter in den Ausgaben hat, weil Snakemake keine Möglichkeit hat, zu wissen, was die gewünschten Platzhalter sein könnten. Sie erhalten die Fehlermeldung “Target rules may not contain wildcards” Dies kann auch passieren, wenn Sie in der Befehlszeile keine expliziten Ziele angeben und Snakemake versucht, die erste im Snakefile definierte Regel auszuführen.
Regeln, die mehrere Eingaben kombinieren
Unsere generate_run_files
Regel ist eine Regel, die eine
Liste von Eingabedateien annimmt. Die Länge dieser Liste ist nicht durch
die Regel festgelegt, sondern kann sich je nach NTASK_SIZES
ändern.
In unserem Arbeitsablauf besteht der letzte Schritt darin, alle
generierten Dateien in einem Plot zu kombinieren. Vielleicht haben Sie
schon gehört, dass einige Leute dafür eine Python-Bibliothek namens
matplotlib
verwenden. Es würde den Rahmen dieses Tutorials
sprengen, das Python-Skript zu schreiben, um einen endgültigen Plot zu
erstellen, daher stellen wir Ihnen das Skript als Teil dieser Lektion
zur Verfügung. Sie können es herunterladen mit
Das Skript plot_terse_amdahl_results.py
benötigt eine
Befehlszeile, die wie folgt aussieht:
BASH
python plot_terse_amdahl_results.py --output <output image filename> <1st input file> <2nd input file> ...
Lass uns das in unsere generate_run_files
Regel
einfügen:
PYTHON
rule generate_run_files:
output: "p_{parallel_proportion}_runs.txt"
input: expand("p_{{parallel_proportion}}/runs/amdahl_run_{count}.json", count=NTASK_SIZES)
shell:
"python plot_terse_amdahl_results.py --output {output} {input}"
Aufgabe
Dieses Skript verlässt sich auf matplotlib
, ist es als
Umgebungsmodul verfügbar? Fügen Sie diese Bedingung zu unserer Regel
hinzu.
Jetzt können wir endlich ein Skalierungsdiagramm erstellen! Führen Sie den letzten Snakemake-Befehl aus:
Aufgabe
Erzeugen Sie das Skalierbarkeitsdiagramm für alle Werte von 1 bis 10 Kernen.
Aufgabe
Wiederholung des Arbeitsablaufs für einen p
-Wert von
0,8
Bonusrunde
Erstellen Sie eine endgültige Regel, die direkt aufgerufen werden
kann und ein Skalierungsdiagramm für 3 verschiedene Werte von
p
erzeugt.
Hauptpunkte
- “Verwenden Sie die Funktion
expand()
, um Listen von Dateinamen zu erzeugen, die Sie kombinieren wollen” - “Jede
{input}
zu einer Regel kann eine Liste variabler Länge sein”