Cargando...
 

Python en el clúster

Contenido

Acceso al clúster

Para ingresar al clúster desde una máquina windows puede revisar el tutorial:
http://clusteri.itm.edu.co/wiki/tiki-index.php?page=Acceso+windows
O desde una máquina tipo unix (linux/mac)
http://clusteri.itm.edu.co/wiki/tiki-index.php?page=Acceso+linux

Una vez tengamos acceso a una terminal, para ingresar al clúster ejecutamos el comando

ssh usuario@clusteri.itm.edu.co

Donde el usuario es su usuario asignado por el administrador (suele ser el mismo del correo institucional). Si no posee usuario o no recuerda la clave puede escribir al administrador a admonclusterparquei en itm.edu.co

Sistema de colas

El sistema de colas consta de un conjunto de programas que nos permiten visualizar los recursos de cómputo disponibles y ejecutar nuestros programas en ellos. Este sistema utiliza una serie de comandos y opciones que agruparemos en unos archivos o scripts.

Para mirar qué recursos tenemos disponibles y cuales son sus características podemos ejecutar el comando:

pbsnodes -a


El primer script que vamos a realizar nos permitirá revisar que los procesos se realizan en algún nodo de trabajo (wn#) y los registros de ejecución en el sistema de colas. El siguiente código usa el comando de linux echo para imprimir en pantalla el nombre del nodo enq ue se está ejecutando y el coando sleep que en nuestro caso esperará 60 segundos antes de terminar. La opción de PBS -N es el nombre que le daremos a la tarea:

#!/bin/bash
#PBS -N mitrabajo	

echo $(hostname)
sleep 60


Puedo llamar este archivo sleep.job y lanzo la tarea con

qsub sleep.job


Para mirar si el proceso está corriendo podemos ejecutar un par de comandos:

qstat -a
showq


Cuando termine la ejecución, si ocurrió algún error podremos observarlos en los archivos de salida de error (.e); y si todo se ejecutó correctamente veremos en archivos de salida (.o) el nombre del nodo en el que se ejecutó nuestra tarea. Lo podemos hacer con el comando:

cat mitrabajo.o####

Donde #### es un número de identificación de la tarea lanzada.

Una introducción más extensa al sistema de colas que usamos en el clúster la puede encontrar en: http://clusteri.itm.edu.co/wiki/tiki-index.php?page=Tutorial+TorquePBS

Ejemplo de uso: montecarlo

Supongamo una empresa de ventas por catálogo que dentro de su fuerza de trabajo tiene 10.000 vendedores. Tienen un histórico de las ventas de cada uno de ellos y quieren estimar las comisiones para el siguietne periodo.

Las comisiones se calculan dependiendo si el vendedor llegó a uno de 3 objetivos

Si superó los 2 millones la comisión es del 2%
Si superó los 5 millones la comisión es del 3%
Si supero los 10 millones, la comisión es del 4%

De los datos históricos previamente se ha observado que la distribución de probabilidad dentro de las comisiones es discreta:

2% p = 0.6
3% p = 0.3
4% p = 0.1

También de los datos históricos tomamos la distancia entre las ventas logradas y el objetivo más cercano y ajustamos una distribución normal con los parámetros

media = 1
desviación = 0.1

Con estos datos podemos simular 10.000 vendedores, el valor de sus ventas y la comisión a la que accede con el siguiente código

def fun_tasa_comision(x):
    if x<2:
        return 0
    elif x>=2 and x<5:
        return 0.02
    elif x>=5 and x<10:
        return 0.03
    else:
        return 0.04

avg=1
std=0.1
num_vendedores=500
val_objetivos=[2,5,10]
prob_objetivos=[0.6,0.3,0.1]

#Distancia al objetivo
pct_objetivo=np.random.normal(avg, std, num_vendedores).round(2)

#Objetivo
objetivos=np.random.choice(val_objetivos,num_vendedores,p=prob_objetivos)

#Total de ventas por vendedor
ventas=objetivos*pct_objetivo

#multiplicador de la comisión por vendedor
pct_comision=[fun_tasa_comision(i) for i in ventas]

#Comisión total por vendedor
comision=pct_comision*ventas

print("Las ventas totales fueron: ",sum(ventas).round(2))
print("Las comisiones totales fueron: ",sum(comision).round(2))


En este código hemos definido una función que nos retorna el multiplicador de la comisión dado el total de las ventas del vendedor en cuestión.



Para poder concluir la simulación sólo nos resta repetir ese proceso las suficientes veces y calcular algunos estadísticos. Eso lo hacemos con el siguiente ciclo:

for i in range(simulaciones):
    pct_objetivo=np.random.normal(avg, std, num_vendedores).round(2)

    # escogemos aleatoriamente los objetivos logrados de todos los vendedores
    objetivos=np.random.choice(val_objetivos,num_vendedores,p=prob_objetivos)

    # Con esto ya podemos calcular las ventas
    ventas=objetivos*pct_objetivo

    # Calculamos el porcentaje de comisiones de todos los vendedores
    perc_comision=[fun_tasa_comision(i) for i in ventas]

    # y las comisiones
    comision=perc_comision*ventas

    # imprimimos la suma de las comisiones y las ventas
    datos.append([sum(comision).round(2),sum(ventas).round(2)])


print(datos)


Agrupando todos los retazos del código y aumentando el número de vendedores y el número de simulaciones, concluimos nuestro programa así:

import numpy as np

num_vendedores=1000
simulaciones=1000

# Creamos una función que nos calcule cuál es la comisión
def fun_tasa_comision(x):
    '''
    Si las ventas logradas son menores a 2' la comisión es del 0
    Si están entre 2' y 5' la comisión es 2%
    Si está entre 5' y 10' la comisión es 3%
    Si está por encima de 10' la comisión es del 4%
    '''
    if x<2:
        return 0
    elif x>=2 and x<5:
        return 0.02
    elif x>=5 and x<10:
        return 0.03
    else:
        return 0.04

# Asumimos que de los datos históricos de ventas ajustamos una
# distribución normal de las distancias del valor de las ventas logradas
# al objetivo. Puede ser que se acercó al objetivo y no lo logró o puede que lo haya superado un poco
avg=1
std=0.1

# Valores trimestrales de los objetivos en millones
val_objetivos=[2,5,10]

# La distribución de los objetivos a través de los vendedores no es ubiforme
# Mientras mayor sea el objetivo la probabilidad de encontrar un vendedor que lo logre es menor
prob_objetivos=[0.6,0.3,0.1]

datos=[]

for i in range(simulaciones):
    pct_objetivo=np.random.normal(avg, std, num_vendedores).round(2)

    # escogemos aleatoriamente los objetivos logrados de todos los vendedores
    objetivos=np.random.choice(val_objetivos,num_vendedores,p=prob_objetivos)

    # Con esto ya podemos calcular las ventas
    ventas=objetivos*pct_objetivo

    # Calculamos el porcentaje de comisiones de todos los vendedores
    perc_comision=[fun_tasa_comision(i) for i in ventas]

    # y las comisiones
    comision=perc_comision*ventas

    # imprimimos la suma de las comisiones y las ventas
    datos.append([sum(comision).round(2),sum(ventas).round(2)])


print(datos)


Este código ejecuta 1000 simulaciones estadísticamente independientes, y queremos ejecutar una versión del código., al mismo tiempo, en cada uno de los nodos del clúster .
Para esto debemos contruir un script de torquepbs para lanzar este código al sistema de colas. Tomando como base el script introductorio podemos simplemente modificar la línea de ejecución para que corra nuestro código en python:

#!/bin/bash
#PBS -N montecarlo
#PBS -l walltime=1:00:00
#PBS -t 1-10

python3 $PBS_O_WORKDIR/montecarlo.py


Recordando las variables y opciones de torque aplicadas a este caso tenemos:

  • El nombre de nuestro trabajo será "montecarlo" con la opción -N,
  • correremos 10 tareas en el clúster con la opción -t
  • y ejecutaremos un programa de python3 llamado montecarlo.py ubicado en $PBS_O_WORKDIR que es la misma ruta donde se encuentra nuestro script de ejcución.