Una breve descripción de las opciones de automatización y paralelización en UNIX/en un HPC

mar 31 enero 2023

Por C. Titus Brown

En la ciencia.

Etiquetas: scripts paraleloslurmhpcsnakemakeshell

¿Qué hace si tiene muchos trabajos informáticos para ejecutar y muchos recursos informáticos para ejecutarlos?

¡Juguemos con algunas opciones! Ejecutaremos un conjunto simple de análisis bioinformáticos como ejemplo, pero todos los enfoques a continuación deberían funcionar para una amplia variedad de necesidades de línea de comando.

La mayoría de los comandos a continuación deberían funcionar como copiar/pegar directamente. Por favor, hágamelo saber si no lo hacen!

Configuración y preparación de archivos.

Descargue algunos ensamblajes de metagenomas de nuestro proyecto de evaluación del ensamblaje del metagenoma. Estos son todos los archivos generados a partir de Shakya et al., 2014 – en concreto, montajes de SRR606249.

mkdir queries/
cd queries/
curl -JLO https://osf.io/download/q8h97/
curl -JLO https://osf.io/download/7bzrc/
curl -JLO https://osf.io/download/3kgvd/
cd ..
mkdir -p database/
cd database/
curl -JLO https://osf.io/download/4kfv9/
cd ../

Ahora deberías tener tres archivos en queries/

>idba.scaffold.fa.gz
>megahit.final.contigs.fa.gz
>spades.scaffolds.fasta.gz

y un archivo en la base de datos/

>podar-complete-genomes-17.2.2018.tar.gz

Bosquejemos las consultas con sourmash:

for i in queries/*.gz
do
    sourmash sketch dna -p k=31,scaled=10000 $i -o $i.sig
done

A continuación, descomprima la base de datos y cree database.zip:

cd database/
tar xzf podar*.tar.gz
sourmash sketch dna -p k=31,scaled=10000 *.fa --name-from-first -o ../database.zip
cd ../

Finalmente, haga que todas sus entradas sean de solo lectura:

chmod a-w queries/* database.zip database/*

Esto evita que se sobrescriban accidentalmente los archivos.

Ejecutando sus consultas básicas

vamos a correr reunión de puré de agria para los tres archivos de ensamblaje en queries/ contra los 64 genomas en database.zip. Estos comandos específicos se ejecutarán rápidamente, pero tenga en cuenta que son un proxy para un análisis mucho más grande en bases de datos más grandes.

Podrías hacer estas consultas en serie:

sourmash gather queries/idba.scaffold.fa.gz.sig 
    database.zip -o idba.scaffold.fa.gz.csv

sourmash gather queries/megahit.final.contigs.fa.gz.sig 
    database.zip -o megahit.final.contigs.fa.gz.csv

sourmash gather queries/spades.scaffolds.fasta.gz.sig 
    database.zip -o spades.scaffolds.fasta.gz.csv

pero entonces su tiempo de cómputo total sería la suma de los tiempos de cómputo individuales. ¿Y si cada consulta es súper lenta y/o grande, y tienes docenas o cientos de ellas? ¿ENTONCES QUE?

¡Sigue leyendo!

Automatización y paralelización

1. Escriba un script de shell.

Comencemos por automatizar las consultas para que solo pueda ejecutar un comando y hacer que realice las tres (o N) consultas.

Cree el siguiente script de shell:

run1.sh:

sourmash gather queries/idba.scaffold.fa.gz.sig database.zip -o idba.scaffold.fa.gz.csv

sourmash gather queries/megahit.final.contigs.fa.gz.sig database.zip -o megahit.final.contigs.fa.gz.csv

sourmash gather queries/spades.scaffolds.fasta.gz.sig database.zip -o spades.scaffolds.fasta.gz.csv

y ejecutarlo:

Esto automatiza los comandos, pero nada más.

Notas:

  • todos sus comandos se ejecutarán en serie, uno tras otro;
  • el uso de memoria del script será el mismo que el uso de memoria del comando más grande;

2. Agregue un bucle for a su script de shell.

Hay mucha duplicación en el script anterior. La duplicación conduce a errores tipográficos, lo que conduce al miedo, la ira, el odio y el sufrimiento.

Hagamos un guion run2.sh que contiene un bucle for en su lugar.

run2.sh:

for query in queries/*.sig
do
output=$(basename $query .sig).csv
sourmash gather $query database.zip -o $output
done

Si bien esto hace exactamente lo mismo computacionalmente como run1.shes un poco mejor porque es menos repetitivo y te permite ejecutar tantas consultas como tengas.

Notas:

  • sí, estructuramos cuidadosamente los nombres de archivo para que el for el bucle funcionaría 🙂
  • el output= usos de línea basename para quitar el queries/ prefijo y .sig sufijo de cada nombre de archivo de consulta.

3. Escriba un bucle for que cree un script de shell.

A veces es agradable generar un script que puede editar para ajustar y personalizar los comandos. ¡Probemos eso!

En el indicador de shell, ejecute

for query in queries/*.sig
do
output=$(basename $query .sig).csv
echo sourmash gather $query database.zip -o $output
done > run3.sh

Esto crea un archivo run3.sh que contiene los comandos a ejecutar. Neato! Ahora puede editar este archivo si desea cambiar individualmente los comandos. O bien, puede ajustar el bucle for si desea cambiar todo los comandos

Notas:

  • mismos parámetros de tiempo de ejecución que el anterior: todo se ejecuta en serie.
  • cuidado con sobrescribir run3.sh ¡por accidente después de haberlo editado!

4. Uso parallel para ejecutar los comandos en su lugar.

Una vez que tengamos este archivo de script listo, podemos ejecutar los comandos en paralelo, usando
ÑU parallel:

Esto ejecuta hasta dos comandos desde run3.sh a la vez (-j 2). Genial, ¿verdad?

Notas:

  • dependiendo del parámetro a -jesto puede ser mucho más rápido – ¡aquí, el doble de rápido!
  • también usará el doble de memoria…!
  • parallel ejecuta cada línea por sí sola. Entonces, si tiene varias cosas que desea ejecutar en cada sesión paralela, debe hacer algo diferente, como escribir un script de shell para realizar cada acción de cómputo, y entonces ejecutarlos en paralelo.

5. Escriba un segundo script de shell que tome un parámetro.

Cambiemos las cosas: escribamos un script de shell genérico que haga el cálculo. ¡Tenga en cuenta que es el mismo conjunto de comandos que en los bucles for anteriores!

do-gather.sh:

output=$(basename $1 .sig).csv
sourmash gather $1 database.zip -o $output

Ahora puedes ejecutar esto en un bucle así:

for i in queries/*.sig
do
   bash do-gather.sh $i
done

Notas:

  • aquí, $1 es el primer parámetro de la línea de comandos después del nombre del script de shell.
  • esto es volver al procesamiento en serie, no en paralelo.

Sería fácil convertir esto en algo que pueda ejecutar en paralelo, proporcionando una lista de do-gather.sh comandos como en (4), arriba.

6. Cambie el segundo script de shell para que sea un script de muestra.

Suponga que tiene acceso a un HPC que tiene muchas computadoras diferentes y desea ejecutar un montón de trabajos grandes al otro lado de esas computadoras. ¿Como hacemos eso?

Todos (¿la mayoría?) de los clústeres tienen un sistema de colas; el nuestro se llama slurm. (Puedes ver un tutorial aquí.)

Para enviar trabajos a muchas computadoras diferentes, puede escribir un script de shell que ejecute un trabajo en particular y luego ejecutar muchos de esos.

Cambiar do-gather.sh para parecerse a lo siguiente.

#SBATCH -c 1     # cpus per task
#SBATCH --mem=5Gb     # memory needed
#SBATCH --time=00-00:05:00     # time needed
#SBATCH -p med2 

output=$(basename $1 .sig).csv
sourmash gather $1 database.zip -o $output

Este es ahora un script que puede enviar al HPC para que lo ejecute, usando sbatch:

for i in queries/*.sig
do
    sbatch do-gather.sh $i
done

La ventaja aquí es que HPC puede programar estos comandos para que se ejecuten cuando y donde haya “espacio” computacional para ejecutarlos. (Aquí el #SBATCH Las líneas en el script de shell especifican cuánto tiempo de cómputo/memoria se necesita).

Notas:

  • esto distribuye su trabajo a través del HPC;
  • ¡estos trabajos solo ocupan tanto tiempo/memoria como cada trabajo individualmente! ¡pero ahora se ejecutan en paralelo en varias máquinas!
  • do-gather.sh en realidad sigue siendo un script bash, por lo que también puede ejecutarlo de esa manera.

7. Escriba un archivo de creación de serpientes.

Una alternativa a todo lo anterior es hacer que Snakemake ejecute las cosas por usted. Aquí hay un archivo de serpiente simple para ejecutar cosas en paralelo:

Snakefile:

QUERY, = glob_wildcards("queries/.sig")

rule all:
    input:
        expand(".csv", q=QUERY)

rule run_query:
    input:
        sig = "queries/.sig",
    output:
        csv = ".csv"
    shell: """
        sourmash gather  database.zip -o 
    """

y ejecutarlo en paralelo:

Notas:

  • esto ejecutará las cosas en paralelo como en el ejemplo anterior (4).

Estrategias de prueba y evaluación

Estas son las tres estrategias que uso cuando trato de escalar algo para ejecutarlo en múltiples trabajos y en múltiples computadoras:

  1. Construir alrededor de un ejemplo existente.
  2. Submuestree los datos de su consulta.
  3. Prueba en una versión más pequeña de tu problema.

Apéndice: hacer que sus scripts de shell sean más agradables

¡Los scripts de shell anteriores no son en realidad la forma en que recomiendo escribir scripts de shell! Aquí hay algunos pensamientos adicionales para usted:

1. Hágalos ejecutables sin un explícito bash

Poner #! /bin/bash en la parte superior del script de shell y ejecute chmod +x <scriptname>y ahora podrás ejecutarlos directamente:

2. Establecer salida de error

Agregar set -e en la parte superior de su script de shell y dejará de ejecutarse cuando haya un error.

Fuente del artículo

Deja un comentario