

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Ejecución del código local como un trabajo híbrido
<a name="braket-hybrid-job-decorator"></a>

Los trabajos híbridos de Amazon Braket proporcionan una orquestación totalmente administrada de algoritmos híbridos cuánticos-clásicos, combinando los recursos de computación de Amazon EC2 con el acceso a la unidad de procesamiento cuántico (QPU) de Amazon Braket. Las tareas cuánticas creadas en un trabajo híbrido tienen prioridad en la cola sobre las tareas cuánticas individuales, de modo que sus algoritmos no se verán interrumpidos por las fluctuaciones en la cola de tareas cuánticas. Cada QPU mantiene una cola de trabajos híbridos independiente, lo que garantiza que solo se pueda ejecutar un trabajo híbrido en un momento dado.

**Topics**
+ [Creación de un trabajo híbrido a partir de código de Python local](#create-hybrid-job-from-local-python-code)
+ [Instalación de paquetes y código fuente de Python adicionales](#install-python-packages-and-code)
+ [Guardar y cargar datos en una instancia de trabajo híbrido](#save-load-data-into-instance)
+ [Prácticas recomendadas para decoradores de trabajos híbridos](#best-practices)

## Creación de un trabajo híbrido a partir de código de Python local
<a name="create-hybrid-job-from-local-python-code"></a>

Puede ejecutar su código de Python local como un trabajo híbrido de Amazon Braket. Puede hacerlo anotando su código con un decorador `@hybrid_job`, como se muestra en el siguiente ejemplo de código. Para los entornos personalizados, puede optar por [utilizar un contenedor personalizado](braket-jobs-byoc.md) de Amazon Elastic Container Registry (ECR). 

**nota**  
De forma predeterminada, solo se admite Python 3.12.

 Puede usar el decorador `@hybrid_job` para anotar una función. Braket transforma el código dentro del decorador en un [script de algoritmo](braket-jobs-first.md) de trabajo híbrido de Braket. A continuación, el trabajo híbrido invoca la función dentro del decorador en una instancia de Amazon EC2. Puede supervisar el progreso del trabajo con `job.state()` o con la consola de Braket. El siguiente ejemplo de código muestra cómo ejecutar una secuencia de cinco estados en el State Vector Simulator (SV1) device. 

```
from braket.aws import AwsDevice
from braket.circuits import Circuit, FreeParameter, Observable
from braket.devices import Devices
from braket.jobs.hybrid_job import hybrid_job
from braket.jobs.metrics import log_metric

device_arn = Devices.Amazon.SV1


@hybrid_job(device=device_arn)  # Choose priority device
def run_hybrid_job(num_tasks=1):
    device = AwsDevice(device_arn)  # Declare AwsDevice within the hybrid job

    # Create a parametric circuit
    circ = Circuit()
    circ.rx(0, FreeParameter("theta"))
    circ.cnot(0, 1)
    circ.expectation(observable=Observable.X(), target=0)

    theta = 0.0  # Initial parameter

    for i in range(num_tasks):
        task = device.run(circ, shots=100, inputs={"theta": theta})  # Input parameters
        exp_val = task.result().values[0]

        theta += exp_val  # Modify the parameter (possibly gradient descent)

        log_metric(metric_name="exp_val", value=exp_val, iteration_number=i)

    return {"final_theta": theta, "final_exp_val": exp_val}
```

El trabajo híbrido se crea invocando la función como lo haría con las funciones normales de Python. Sin embargo, la función de decorador devuelve el identificador del trabajo híbrido en lugar del resultado de la función. Para recuperar los resultados una vez que se haya completado, utilice `job.result()`. 

```
job = run_hybrid_job(num_tasks=1)
result = job.result()
```

El argumento del dispositivo en el decorador `@hybrid_job` especifica el dispositivo al que el trabajo híbrido tiene acceso prioritario, en este caso, el simulador SV1. Para obtener la prioridad de la QPU, debe asegurarse de que el ARN del dispositivo utilizado en la función coincida con el especificado en el decorador. Para mayor comodidad, puede utilizar la función auxiliar `get_job_device_arn()` para capturar el ARN del dispositivo declarado en `@hybrid_job`. 

**nota**  
Cada trabajo híbrido tiene un tiempo de inicio de al menos un minuto, ya que crea un entorno en contenedor en Amazon EC2. Por lo tanto, para cargas de trabajo muy cortas, como un circuito único o un lote de circuitos, puede bastar con utilizar tareas cuánticas.

**Hiperparámetros** 

La función `run_hybrid_job()` utiliza el argumento `num_tasks` para controlar el número de tareas cuánticas creadas. El trabajo híbrido captura esto automáticamente como un [hiperparámetro](braket-jobs-hyperparameters.md).

**nota**  
Los hiperparámetros se muestran en la consola de Braket como cadenas, que tienen un límite de 2500 caracteres. 

**Métricas y registro** 

En la función `run_hybrid_job()`, las métricas de los algoritmos iterativos se registran con `log_metrics`. Las métricas se representan automáticamente en la página de la consola de Braket, en la pestaña de trabajos híbridos. Puede utilizar las métricas para realizar un seguimiento de los costos de las tareas cuánticas prácticamente en tiempo real durante la ejecución de un trabajo híbrido con el [Rastreador de costos de Braket](braket-pricing.md). En el ejemplo anterior, se utiliza el nombre de métrica «probabilidad», que registra la primera probabilidad del [tipo de resultado](braket-result-types.md).

**Recuperación de resultados** 

Una vez finalizado el trabajo híbrido, se utiliza `job.result()` para recuperar los resultados del trabajo híbrido. Braket captura automáticamente todos los objetos de la declaración de devolución. Tenga en cuenta que los objetos devueltos por la función deben ser una tupla y cada elemento debe ser serializable. Por ejemplo, el código siguiente muestra un ejemplo de funcionamiento correcto y otro incorrecto. 

```
import numpy as np


# Working example
@hybrid_job(device=Devices.Amazon.SV1)
def passing():
    np_array = np.random.rand(5)
    return np_array  # Serializable

# # Failing example
# @hybrid_job(device=Devices.Amazon.SV1)
# def failing():
#     return MyObject() # Not serializable
```

**Nombre del trabajo** 

De forma predeterminada, el nombre de este trabajo híbrido se deduce del nombre de la función. Puede especificar un nombre personalizado que tenga un máximo de 50 caracteres. Por ejemplo, en el código siguiente, el nombre del trabajo es "my-job-name».

```
@hybrid_job(device=Devices.Amazon.SV1, job_name="my-job-name")
def function():
    pass
```

**Modo local** 

Los [trabajos locales](braket-jobs-local-mode.md) se crean añadiendo el argumento `local=True` al decorador. Esto ejecuta el trabajo híbrido en un entorno en contenedor en su entorno de computación local, como un portátil. Los trabajos locales **no** tienen prioridad en las colas para las tareas cuánticas. En casos avanzados, como los de varios nodos o MPI, los trabajos locales pueden tener acceso a las variables de entorno de Braket requeridas. El código siguiente crea un trabajo híbrido local con el dispositivo como SV1 simulador. 

```
@hybrid_job(device=Devices.Amazon.SV1, local=True)
def run_hybrid_job(num_tasks=1):
    return ...
```

Todas las demás opciones de trabajo híbrido son compatibles. Para ver una lista de opciones, consulte el [módulo braket.jobs.quantum\$1job\$1creation](https://amazon-braket-sdk-python.readthedocs.io/en/stable/_apidoc/braket.jobs.quantum_job_creation.html). 

## Instalación de paquetes y código fuente de Python adicionales
<a name="install-python-packages-and-code"></a>

Puede personalizar su entorno de tiempo de ejecución para usar sus paquetes de Python preferidos. Puede usar un archivo `requirements.txt`, una lista de nombres de paquetes o [utilizar su propio contenedor (BYOC)](braket-jobs-byoc.md). Por ejemplo, el archivo `requirements.txt` puede incluir otros paquetes para instalar.

```
qiskit 
pennylane >= 0.31
mitiq == 0.29
```

Para personalizar un entorno de tiempo de ejecución utilizando un archivo `requirements.txt`, consulte el siguiente ejemplo de código.

```
@hybrid_job(device=Devices.Amazon.SV1, dependencies="requirements.txt")
def run_hybrid_job(num_tasks=1):
    return ...
```

Como alternativa, puede proporcionar los nombres de los paquetes como una lista de Python de la siguiente manera.

```
@hybrid_job(device=Devices.Amazon.SV1, dependencies=["qiskit", "pennylane>=0.31", "mitiq==0.29"])
def run_hybrid_job(num_tasks=1):
    return ...
```

El código fuente adicional se puede especificar como una lista de módulos o como un solo módulo, como en el siguiente ejemplo de código. 

```
@hybrid_job(device=Devices.Amazon.SV1, include_modules=["my_module1", "my_module2"])
def run_hybrid_job(num_tasks=1):
    return ...
```

## Guardar y cargar datos en una instancia de trabajo híbrido
<a name="save-load-data-into-instance"></a>

**Especificación de los datos de entrenamiento de entrada**

Al crear un trabajo híbrido, puede proporcionar conjuntos de datos de entrenamiento de entrada especificando un bucket de Amazon Simple Storage Service (Amazon S3). También puede especificar una ruta local y, a continuación, Braket carga automáticamente los datos en Amazon S3 en `s3://<default_bucket_name>/jobs/<job_name>/<timestamp>/data/<channel_name>`. Si especifica una ruta local, el nombre del canal predeterminado será «entrada». El siguiente código muestra un archivo numpy de la ruta local `data/file.npy`. 

```
import numpy as np


@hybrid_job(device=Devices.Amazon.SV1, input_data="data/file.npy")
def run_hybrid_job(num_tasks=1):
    data = np.load("data/file.npy")
    return ...
```

Para S3, debe usar la función auxiliar `get_input_data_dir()`.

```
import numpy as np
from braket.jobs import get_input_data_dir

s3_path = "s3://amazon-braket-us-east-1-123456789012/job-data/file.npy"


@hybrid_job(device=None, input_data=s3_path)
def job_s3_input():
    np.load(get_input_data_dir() + "/file.npy")


@hybrid_job(device=None, input_data={"channel": s3_path})
def job_s3_input_channel():
    np.load(get_input_data_dir("channel") + "/file.npy")
```

Puede especificar varias fuentes de datos de entrada proporcionando un diccionario de valores de canal y rutas S3 URIs o locales. 

```
import numpy as np
from braket.jobs import get_input_data_dir

input_data = {
    "input": "data/file.npy",
    "input_2": "s3://amzn-s3-demo-bucket/data.json"
}


@hybrid_job(device=None, input_data=input_data)
def multiple_input_job():
    np.load(get_input_data_dir("input") + "/file.npy")
    np.load(get_input_data_dir("input_2") + "/data.json")
```

**nota**  
Si los datos de entrada son grandes (>1 GB), habrá un largo tiempo de espera antes de que se cree el trabajo. Esto se debe a que los datos de entrada locales se cargan por primera vez en un bucket de S3 y, a continuación, se añade la ruta de S3 a la solicitud de trabajo. Por último, la solicitud de trabajo se envía al servicio de Braket.

**Guardar los resultados en S3**

Para guardar los resultados no incluidos en la declaración de devolución de la función decorada, debe añadir el directorio correcto a todas las operaciones de escritura de archivos. En el siguiente ejemplo, se muestra cómo guardar una matriz numpy y una figura de matplotlib.

```
import matplotlib.pyplot as plt
import numpy as np


@hybrid_job(device=Devices.Amazon.SV1)
def run_hybrid_job(num_tasks=1):
    result = np.random.rand(5)

    # Save a numpy array
    np.save("result.npy", result)

    # Save a matplotlib figure
    plt.plot(result)
    plt.savefig("fig.png")
    return ...
```

Todos los resultados se comprimen en un archivo denominado `model.tar.gz`. Puede descargar los resultados con la función `job.result()` de Python o yendo a la carpeta de resultados desde la página de trabajos híbridos de la consola de administración de Braket. 

**Guardar y reanudar desde los puntos de control**

Para trabajos híbridos de larga duración, se recomienda guardar periódicamente el estado intermedio del algoritmo. Puede utilizar la función auxiliar `save_job_checkpoint()` integrada o guardar los archivos en la ruta `AMZN_BRAKET_JOB_RESULTS_DIR`. Esta última opción está disponible con la función auxiliar `get_job_results_dir()`.

El siguiente es un ejemplo práctico mínimo para guardar y cargar puntos de control con un decorador de trabajo híbrido:

```
from braket.jobs import save_job_checkpoint, load_job_checkpoint, hybrid_job


@hybrid_job(device=None, wait_until_complete=True)
def function():
    save_job_checkpoint({"a": 1})


job = function()
job_name = job.name
job_arn = job.arn


@hybrid_job(device=None, wait_until_complete=True, copy_checkpoints_from_job=job_arn)
def continued_function():
    load_job_checkpoint(job_name)


continued_job = continued_function()
```

En el primer trabajo híbrido, `save_job_checkpoint()` se llama con un diccionario que contiene los datos que queremos guardar. De forma predeterminada, todos los valores deben poder serializarse como texto. Para comprobar objetos de Python más complejos, como matrices numpy, puede configurar `data_format = PersistedJobDataFormat.PICKLED_V4`. Este código crea y sobrescribe un archivo de puntos de control con el nombre predeterminado `<jobname>.json` en sus artefactos de trabajo híbrido, en una subcarpeta denominada «puntos de control».

Para crear un nuevo trabajo híbrido para continuar desde el punto de control, debemos pasar `copy_checkpoints_from_job=job_arn` dónde `job_arn` es el ARN del trabajo híbrido del trabajo anterior. A continuación, usamos `load_job_checkpoint(job_name)` para realizar la carga desde el punto de control.

## Prácticas recomendadas para decoradores de trabajos híbridos
<a name="best-practices"></a>

**Uso de la asincronicidad**

Los trabajos híbridos creados con la anotación de decorador son asíncronos: se ejecutan una vez que los recursos clásicos y cuánticos están disponibles. Usted monitorea el progreso del algoritmo utilizando Amazon Braket Management Console o Amazon CloudWatch. Cuando envía el algoritmo para su ejecución, Braket lo ejecuta en un entorno en contenedor escalable y los resultados se recuperan cuando se completa el algoritmo.

**Ejecución de algoritmos variacionales iterativos**

Los trabajos híbridos le proporcionan las herramientas necesarias para ejecutar algoritmos cuánticos-clásicos iterativos. Para problemas puramente cuánticos, utilice [tareas cuánticas](braket-submit-tasks.md) o un [lote de tareas cuánticas](braket-batching-tasks.md). El acceso prioritario a ciertos QPUs es más beneficioso para los algoritmos variacionales de larga duración que requieren múltiples llamadas iterativas QPUs con el procesamiento clásico en el medio. 

**Depuración utilizando el modo local**

Antes de ejecutar un trabajo híbrido en una QPU, se recomienda ejecutarlo primero en el simulador para confirmar SV1 que se ejecuta según lo esperado. En el caso de pruebas a pequeña escala, puede ejecutarlas con el modo local para una iteración y depuración rápidas. 

**Mejora de la reproducibilidad [utilizando su propio contenedor (BYOC)](braket-jobs-byoc.md)**

Cree un experimento reproducible encapsulando su software y sus dependencias en un entorno en contenedor. Al empaquetar todo su código, dependencias y configuración en un contenedor, evitará posibles conflictos y problemas de control de versiones. 

**Simuladores distribuidos multiinstancia**

Para ejecutar una gran cantidad de circuitos, considere la posibilidad de utilizar el soporte de MPI integrado para ejecutar simuladores locales en varias instancias en un solo trabajo híbrido. Para obtener más información, consulte [simuladores integrados](pennylane-embedded-simulators.md).

**Uso de circuitos paramétricos**

Los circuitos paramétricos que se envían a partir de un trabajo híbrido se compilan automáticamente en algunos casos QPUs mediante la [compilación paramétrica](braket-jobs-parametric-compilation.md) para mejorar los tiempos de ejecución de los algoritmos. 

**Punto de control periódico**

Para trabajos híbridos de larga duración, se recomienda guardar periódicamente el estado intermedio del algoritmo. 

**Para ver más ejemplos, casos de uso y mejores prácticas, consulta los ejemplos de [Amazon GitHub Braket](https://github.com/amazon-braket/amazon-braket-examples).**