

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Execute cargas de trabalho híbridas com PennyLane simuladores incorporados
<a name="pennylane-embedded-simulators"></a>

Vamos ver como você pode usar simuladores incorporados do PennyLane Amazon Braket Hybrid Jobs para executar cargas de trabalho híbridas. O simulador incorporado baseado em GPU da Pennylane, `lightning.gpu`, usa a biblioteca [Nvidia CuQuantum](https://developer.nvidia.com/cuquantum-sdk) para acelerar as simulações de circuitos. O simulador de GPU incorporado é pré-configurado em todos os [contêineres de trabalho](https://github.com/amazon-braket/amazon-braket-containers) do Braket que os usuários podem usar imediatamente. Nesta página, mostraremos como usar `lightning.gpu` para acelerar suas workloads híbrida.

## Usando `lightning.gpu` para workloads QAOA
<a name="lightning-gpu-qaoa"></a>

Considere os exemplos do Algoritmo de Otimização Aproximada Quântica (QAOA) deste [caderno](https://github.com/amazon-braket/amazon-braket-examples/tree/main/examples/hybrid_jobs/2_Using_PennyLane_with_Braket_Hybrid_Jobs). Para selecionar um simulador incorporado, você especifica o argumento `device` para ser uma string no formato: `"local:<provider>/<simulator_name>"`. Por exemplo, você definiria `"local:pennylane/lightning.gpu"` para `lightning.gpu`. A string do dispositivo que você fornece ao Hybrid Job ao iniciar é passada para o trabalho como a variável de ambiente `"AMZN_BRAKET_DEVICE_ARN"`.

```
device_string = os.environ["AMZN_BRAKET_DEVICE_ARN"]
prefix, device_name = device_string.split("/")
device = qml.device(simulator_name, wires=n_wires)
```

Nesta página, compare os dois simuladores de vetores de PennyLane estado incorporados `lightning.qubit` (que são baseados em CPU) e `lightning.gpu` (que são baseados em GPU). Forneça aos simuladores decomposições de portas personalizadas para calcular vários gradientes.

Agora você está pronto para preparar o script híbrido de lançamento de tarefas. Execute o algoritmo QAOA usando dois tipos de instância: `ml.m5.2xlarge` e `ml.g4dn.xlarge`. O tipo `ml.m5.2xlarge` de instância é comparável a um laptop padrão para desenvolvedores. `ml.g4dn.xlarge`É uma instância de computação acelerada que tem uma única GPU NVIDIA T4 com 16 GB de memória.

Para executar a GPU, primeiro precisamos especificar uma imagem compatível e a instância correta (cujo padrão é uma `ml.m5.2xlarge` instância).

```
from braket.aws import AwsSession
from braket.jobs.image_uris import Framework, retrieve_image

image_uri = retrieve_image(Framework.PL_PYTORCH, AwsSession().region)
instance_config = InstanceConfig(instanceType="ml.g4dn.xlarge")
```

Em seguida, precisamos inseri-los no decorador de trabalho híbrido, junto com os parâmetros atualizados do dispositivo nos argumentos do sistema e do trabalho híbrido.

```
@hybrid_job(
        device="local:pennylane/lightning.gpu",
        input_data=input_file_path,
        image_uri=image_uri,
        instance_config=instance_config)
def run_qaoa_hybrid_job_gpu(p=1, steps=10):
    params = np.random.rand(2, p)

    braket_task_tracker = Tracker()

    graph = nx.read_adjlist(input_file_path, nodetype=int)
    wires = list(graph.nodes)
    cost_h, _mixer_h = qaoa.maxcut(graph)

    device_string = os.environ["AMZN_BRAKET_DEVICE_ARN"]
    prefix, device_name = device_string.split("/")
    dev= qml.device(simulator_name, wires=len(wires))
    ...
```

**nota**  
Se você especificar o `instance_config` como usando uma instância baseada em GPU, mas `device` escolher o como simulador baseado em CPU incorporado (`lightning.qubit`), a GPU não será usada. Certifique-se de usar o simulador incorporado baseado em GPU se quiser atingir a GPU\!

O tempo médio de iteração para a `m5.2xlarge` instância é de cerca de 73 segundos, enquanto para a `ml.g4dn.xlarge` instância é de cerca de 0,6 segundos. Para esse fluxo de trabalho de 21 qubits, a instância da GPU nos dá uma aceleração de 100x. Se você olhar a página de [preços do Amazon Braket Hybrid Jobs](https://aws.amazon.com/braket/pricing/), verá que o custo por minuto para `m5.2xlarge` uma instância é de 0,00768 USD, enquanto para a instância é de 0,01227 USD. `ml.g4dn.xlarge` Nesse caso, é mais rápido e barato executar na instância da GPU.

## Aprendizado de máquina quântico e paralelismo de dados
<a name="quantumML-data-parallelism"></a>

Se seu tipo de workload for aprendizado de máquina quântico (QML) treinado em conjuntos de dados, você poderá acelerar ainda mais sua workload usando o paralelismo de dados. No QML, o modelo contém um ou mais circuitos quânticos. O modelo também pode ou não conter redes neurais clássicas. Ao treinar o modelo com o conjunto de dados, os parâmetros no modelo são atualizados para minimizar a função de perda. Uma função de perda geralmente é definida para um único ponto de dados e a perda total para a perda média em todo o conjunto de dados. Em QML, as perdas geralmente são calculadas em série antes da média da perda total para cálculos de gradiente. Esse procedimento é demorado, especialmente quando há centenas de pontos de dados.

Como a perda de um ponto de dados não depende de outros pontos de dados, as perdas podem ser avaliadas paralelamente\! Perdas e gradientes associados a diferentes pontos de dados podem ser avaliados ao mesmo tempo. Isso é conhecido como paralelismo de dados. Com SageMaker a biblioteca paralela de dados distribuídos, o Amazon Braket Hybrid Jobs facilita o uso do paralelismo de dados para acelerar seu treinamento.

Considere a seguinte workload QML para paralelismo de dados, que usa o [conjunto de dados Sonar](https://archive.ics.uci.edu/dataset/151/connectionist+bench+sonar+mines+vs+rocks) do conhecido repositório UCI como exemplo de classificação binária. O conjunto de dados Sonar tem 208 pontos de dados, cada um com 60 características que são coletadas de sinais de sonar refletidos em materiais. Cada ponto de dados é rotulado como “M” para minas ou “R” para rochas. Nosso modelo QML consiste em uma camada de entrada, um circuito quântico como camada oculta e uma camada de saída. As camadas de entrada e saída são redes neurais clássicas implementadas em PyTorch. O circuito quântico é integrado às PyTorch redes neurais usando PennyLane o módulo qml.qnn. Veja nossos [exemplos de cadernos](https://github.com/aws/amazon-braket-examples) para obter mais detalhes sobre a workload. Como no exemplo de QAOA acima, você pode aproveitar o poder da GPU usando simuladores incorporados baseados em GPU, como PennyLane os nossos, `lightning.gpu` para melhorar o desempenho em relação aos simuladores baseados em CPU incorporada.

Para criar uma tarefa híbrida, você pode chamar `AwsQuantumJob.create` e especificar o script do algoritmo, o dispositivo e outras configurações por meio de seus argumentos de palavra-chave.

```
instance_config = InstanceConfig(instanceType='ml.g4dn.xlarge')

hyperparameters={"nwires": "10",
                 "ndata": "32",
                 ...
}

job = AwsQuantumJob.create(
    device="local:pennylane/lightning.gpu",
    source_module="qml_source",
    entry_point="qml_source.train_single",
    hyperparameters=hyperparameters,
    instance_config=instance_config,
    ...
)
```

Para usar o paralelismo de dados, você precisa modificar algumas linhas de código no script do algoritmo da biblioteca SageMaker distribuída para paralelizar corretamente o treinamento. Primeiro, você importa o `smdistributed` pacote que faz a maior parte do trabalho pesado para distribuir suas cargas de trabalho em várias e várias GPUs instâncias. Este pacote é pré-configurado no Braket PyTorch e nos contêineres. TensorFlow O `dist` módulo informa ao nosso script de algoritmo qual é o número total de GPUs para o treinamento (`world_size`), bem como o final `rank` `local_rank` de um núcleo de GPU. `rank`é o índice absoluto de uma GPU em todas as instâncias, enquanto `local_rank` é o índice de uma GPU dentro de uma instância. Por exemplo, se houver quatro instâncias, cada uma com oito GPUs alocadas para o treinamento, `rank` elas variam de 0 a 31 e as `local_rank` de 0 a 7.

```
import smdistributed.dataparallel.torch.distributed as dist

dp_info = {
    "world_size": dist.get_world_size(),
    "rank": dist.get_rank(),
    "local_rank": dist.get_local_rank(),
}
batch_size //= dp_info["world_size"] // 8
batch_size = max(batch_size, 1)
```

Em seguida, você define um `DistributedSampler` de acordo com `world_size` e `rank` e, em seguida, o passa para o carregador de dados. Esse amostrador evita GPUs acessar a mesma fatia de um conjunto de dados.

```
train_sampler = torch.utils.data.distributed.DistributedSampler(
    train_dataset,
    num_replicas=dp_info["world_size"],
    rank=dp_info["rank"]
)
train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=batch_size,
    shuffle=False,
    num_workers=0,
    pin_memory=True,
    sampler=train_sampler,
)
```

Em seguida, você usa a classe `DistributedDataParallel` para ativar o paralelismo de dados.

```
from smdistributed.dataparallel.torch.parallel.distributed import DistributedDataParallel as DDP

model = DressedQNN(qc_dev).to(device)
model = DDP(model)
torch.cuda.set_device(dp_info["local_rank"])
model.cuda(dp_info["local_rank"])
```

As alterações acima são necessárias para usar o paralelismo de dados. Em QML, você geralmente deseja salvar os resultados e imprimir o progresso do treinamento. Se cada GPU executar o comando de salvar e imprimir, o log será inundado com as informações repetidas e os resultados se substituirão. Para evitar isso, você só pode salvar e imprimir a partir da GPU que tenha `rank` 0.

```
if dp_info["rank"]==0:
    print('elapsed time: ', elapsed)
    torch.save(model.state_dict(), f"{output_dir}/test_local.pt")
    save_job_result({"last loss": loss_before})
```

 O Amazon Braket Hybrid Jobs `ml.g4dn.12xlarge` oferece suporte a tipos de instância para a biblioteca paralela de dados SageMaker distribuídos. Você configura o tipo de instância por meio do argumento `InstanceConfig` em Hybrid Jobs. Para que a biblioteca paralela de dados SageMaker distribuídos saiba que o paralelismo de dados está ativado, você precisa adicionar dois hiperparâmetros adicionais, `"sagemaker_distributed_dataparallel_enabled"` configurando `"true"` e `"sagemaker_instance_type"` configurando o tipo de instância que você está usando. Esses dois hiperparâmetros são usados por pacote `smdistributed`. Seu script de algoritmo não precisa usá-los explicitamente. No Amazon Braket SDK, ele fornece um argumento `distribution` de palavra-chave conveniente. Com `distribution="data_parallel"` de empregos híbridos, o Amazon Braket SDK insere automaticamente os dois hiperparâmetros para você. Se você usa a API Amazon Braket, precisa incluir esses dois hiperparâmetros.

Com o paralelismo de instâncias e dados configurados, agora você pode enviar seu trabalho híbrido. Há 4 GPUs em uma `ml.g4dn.12xlarge` instância. Quando você define`instanceCount=1`, a carga de trabalho é distribuída entre os 8 GPUs na instância. Quando você define `instanceCount` mais de um, a carga de trabalho é distribuída entre os GPUs disponíveis em todas as instâncias. Ao usar várias instâncias, cada instância incorre em uma cobrança com base no tempo de uso. Por exemplo, quando você usa quatro instâncias, o tempo faturável é quatro vezes o tempo de execução por instância, pois há quatro instâncias executando suas workloads ao mesmo tempo.

```
instance_config = InstanceConfig(instanceType='ml.g4dn.12xlarge',
                                 instanceCount=1,
)

hyperparameters={"nwires": "10",
                 "ndata": "32",
                 ...,
}

job = AwsQuantumJob.create(
    device="local:pennylane/lightning.gpu",
    source_module="qml_source",
    entry_point="qml_source.train_dp",
    hyperparameters=hyperparameters,
    instance_config=instance_config,
    distribution="data_parallel",
    ...
)
```

**nota**  
Na criação de empregos híbridos acima, `train_dp.py` é o script de algoritmo modificado para usar o paralelismo de dados. Lembre-se de que o paralelismo de dados só funciona corretamente quando você modifica seu script de algoritmo de acordo com a seção acima. Se a opção de paralelismo de dados for ativada sem um script de algoritmo modificado corretamente, a tarefa híbrida poderá gerar erros ou cada GPU poderá processar repetidamente a mesma fatia de dados, o que é ineficiente.

Se usado corretamente, o uso de várias instâncias pode levar a uma redução de ordens de magnitude no tempo e no custo. Consulte o [exemplo de caderno para obter mais detalhes](https://github.com/amazon-braket/amazon-braket-examples/blob/main/examples/hybrid_jobs/5_Parallelize_training_for_QML/Parallelize_training_for_QML.ipynb).