

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# PennyLane 임베디드 시뮬레이터를 사용한 하이브리드 워크로드 실행
<a name="pennylane-embedded-simulators"></a>

Amazon Braket Hybrid Jobs에서 PennyLane의 임베디드 시뮬레이터를 사용하여 하이브리드 워크로드를 실행하는 방법을 살펴보겠습니다. Pennylane의 GPU 기반 임베디드 시뮬레이터인 `lightning.gpu`는 [Nvidia cuQuantum 라이브러리](https://developer.nvidia.com/cuquantum-sdk)를 사용하여 회로 시뮬레이션을 가속화합니다. 임베디드 GPU 시뮬레이터는 사용자가 즉시 사용할 수 있는 모든 Braket [작업 컨테이너](https://github.com/amazon-braket/amazon-braket-containers)에 미리 구성되어 있습니다. 이 페이지에서는 `lightning.gpu`를 사용하여 하이브리드 워크로드의 속도를 높이는 방법을 보여줍니다.

## QAOA 워크로드`lightning.gpu`에 사용
<a name="lightning-gpu-qaoa"></a>

이 [노트북](https://github.com/amazon-braket/amazon-braket-examples/tree/main/examples/hybrid_jobs/2_Using_PennyLane_with_Braket_Hybrid_Jobs)의 양자 근사 최적화 알고리즘(Quantum Approximate Optimization Algorithm, QAOA) 예제를 살펴보세요. 임베디드 시뮬레이터를 선택하려면 `device` 인수를 다음과 같은 형식의 문자열로 지정합니다. `"local:<provider>/<simulator_name>"` 예를 들어 `lightning.gpu`에 대해 `"local:pennylane/lightning.gpu"`를 설정합니다. 시작 시 하이브리드 작업에 제공하는 디바이스 문자열은 환경 변수 `"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)
```

이 페이지에서 2개의 임베디드 PennyLane 상태 벡터 시뮬레이터 `lightning.qubit`(CPU 기반)와 `lightning.gpu`(GPU 기반)를 비교합니다. 시뮬레이터에 사용자 지정 게이트 분해를 제공하여 다양한 기울기를 계산합니다.

이제 하이브리드 작업 시작 스크립트를 준비할 수 있습니다. `ml.m5.2xlarge` 및 `ml.g4dn.xlarge`의 두 가지 인스턴스 유형을 사용하여 QAOA 알고리즘을 실행합니다. `ml.m5.2xlarge` 인스턴스 유형은 표준 개발자 랩톱과 비슷합니다. 는 메모리가 16GB인 단일 NVIDIA T4 GPU가 있는 가속 컴퓨팅 인스턴스`ml.g4dn.xlarge`입니다.

GPU를 실행하려면 먼저 호환되는 이미지와 올바른 인스턴스(기본값은 `ml.m5.2xlarge` 인스턴스)를 지정해야 합니다.

```
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")
```

그런 다음 시스템 및 하이브리드 작업 인수 모두에서 업데이트된 디바이스 파라미터와 함께 하이브리드 작업 데코레이터에 이를 입력해야 합니다.

```
@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))
    ...
```

**참고**  
를 GPU 기반 인스턴스를 사용하는 `instance_config` 것으로 지정하지만를 임베디드 CPU 기반 시뮬레이터(`lightning.qubit`)`device`로 선택하면 GPU가 사용되지 않습니다. GPU를 대상으로 지정하려면 임베디드 GPU 기반 시뮬레이터를 사용해야 합니다\!

`m5.2xlarge` 인스턴스의 평균 반복 시간은 약 73초이고 `ml.g4dn.xlarge` 인스턴스의 경우 약 0.6초입니다. 이 21비트 워크플로의 경우 GPU 인스턴스는 100배의 속도 향상을 제공합니다. Amazon Braket Hybrid Jobs [요금 페이지를](https://aws.amazon.com/braket/pricing/) 보면 `m5.2xlarge` 인스턴스의 분당 비용이 0.00768 USD인 반면 `ml.g4dn.xlarge` 인스턴스의 경우 0.01227 USD임을 알 수 있습니다. 이 인스턴스에서는 GPU 인스턴스에서 실행하는 것이 더 빠르고 저렴합니다.

## 양자 기계 학습 및 데이터 병렬 처리
<a name="quantumML-data-parallelism"></a>

워크로드 유형이 데이터세트를 기반으로 훈련하는 양자 기계 학습(QML)인 경우 데이터 병렬 처리를 사용하여 워크로드를 더욱 가속화할 수 있습니다. QML에서 모델은 하나 이상의 양자 회로를 포함합니다. 모델은 고전 신경망을 포함할 수도 있고 포함하지 않을 수도 있습니다. 데이터세트로 모델을 훈련할 때 모델의 파라미터는 손실 함수를 최소화하도록 업데이트됩니다. 손실 함수는 일반적으로 단일 데이터 포인트에 대해 정의되며 총 손실은 전체 데이터세트에 대한 평균 손실에 대해 정의됩니다. QML에서 손실은 일반적으로 기울기 계산을 위한 총 손실로 평균화하기 전에 직렬로 계산됩니다. 이 절차는 특히 수백 개의 데이터 포인트가 있는 경우 시간이 많이 걸립니다.

한 데이터 포인트의 손실은 다른 데이터 포인트에 의존하지 않으므로 손실을 병렬로 평가할 수 있습니다. 서로 다른 데이터 포인트와 관련된 손실 및 기울기를 동시에 평가할 수 있습니다. 이를 데이터 병렬 처리라고 합니다. SageMaker의 분산 데이터 병렬 라이브러리를 통해, Amazon Braket Hybrid Jobs는 데이터 병렬 처리를 사용하여 훈련을 더욱 쉽게 가속화할 수 있습니다.

바이너리 분류의 예로 잘 알려진 UCI 리포지토리의 [Sonar 데이터세트](https://archive.ics.uci.edu/dataset/151/connectionist+bench+sonar+mines+vs+rocks) 데이터세트를 사용하는 데이터 병렬 처리를 위한 다음 QML 워크로드를 고려해 보세요. Sonar 데이터세트에는 각각 60개의 특징을 가진 208개의 데이터 포인트가 있으며, 이는 물질에서 반사되는 Sonar 신호로부터 수집됩니다. 각 데이터 포인트는 mines의 "M", rocks의 "R"로 표시됩니다. QML 모델은 입력 계층, 은닉 계층으로서 양자 회로 및 출력 계층으로 구성됩니다. 입력 및 출력 계층은 PyTorch에서 구현된 고전 신경망입니다. 양자 회로는 PennyLane의 qml.qnn 모듈을 사용하여 PyTorch 신경망과 통합됩니다. 워크로드에 대한 자세한 내용은 [예제 노트북](https://github.com/aws/amazon-braket-examples)을 참조하세요. 위의 QAOA 예제와 마찬가지로, PennyLane의 `lightning.gpu`와 같은 임베디드 GPU 기반 시뮬레이터를 사용하면 GPU의 성능을 활용하여 임베디드 CPU 기반 시뮬레이터보다 성능을 개선할 수 있습니다.

하이브리드 작업을 생성하려면 `AwsQuantumJob.create`를 직접적으로 호출하고 키워드 인수를 통해 알고리즘 스크립트, 디바이스 및 기타 구성을 지정할 수 있습니다.

```
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,
    ...
)
```

데이터 병렬 처리를 사용하려면, SageMaker 분산 라이브러리의 알고리즘 스크립트에서 몇 줄의 코드를 수정하여 훈련을 올바르게 병렬 처리해야 합니다. 먼저, 여러 GPU와 여러 인스턴스에 걸쳐 워크로드를 분산하는 데 필요한 대부분의 작업을 수행하는 `smdistributed` 패키지를 가져옵니다. 이 패키지는 Braket PyTorch 및 TensorFlow 컨테이너에 미리 구성되어 있습니다. `dist` 모듈은 알고리즘 스크립트에 훈련(`world_size`)을 위한 GPU의 총 수와 GPU 코어의 `rank` 및 `local_rank`를 알려줍니다. `rank`는 모든 인스턴스에서 GPU의 절대 인덱스이며, `local_rank`는 인스턴스 내 GPU의 인덱스입니다. 예를 들어 훈련에 각각 8개의 GPU가 할당된 인스턴스가 4개 있는 경우 `rank` 범위는 0\~31이고 `local_rank` 범위는 0\~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)
```

다음으로, `world_size`와 `rank`에 따라 `DistributedSampler`를 정의한 후 데이터 로더에 전달합니다. 이 샘플러는 GPU가 데이터세트의 동일한 조각에 액세스하는 것을 방지합니다.

```
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,
)
```

다음으로, `DistributedDataParallel` 클래스를 사용하여 데이터 병렬 처리를 활성화합니다.

```
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"])
```

위의 내용은 데이터 병렬 처리를 사용하는 데 필요한 변경 사항입니다. QML에서는 결과를 저장하고 훈련 진행 상황을 출력하고 싶은 경우가 종종 있습니다. 각 GPU가 저장 및 인쇄 명령을 실행하면 로그에 반복되는 정보가 넘쳐나고 결과가 서로 덮어쓰기됩니다. 이를 방지하기 위해 `rank` 0이 있는 GPU에서만 저장하고 출력할 수 있습니다.

```
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})
```

 Amazon Braket Hybrid Jobs는 SageMaker 분산 데이터 병렬 라이브러리를 위한 `ml.g4dn.12xlarge` 인스턴스 유형을 지원합니다. 하이브리드 작업의 `InstanceConfig` 인수를 통해 인스턴스 유형을 구성합니다. SageMaker 분산 데이터 병렬 라이브러리가 데이터 병렬 처리가 활성화되었음을 인식할 수 있게 하려면, 2개의 추가 하이퍼파라미터를 추가해야 합니다. `"sagemaker_distributed_dataparallel_enabled"`를 `"true"`로 설정하고 `"sagemaker_instance_type"`을 사용 중인 인스턴스 유형으로 설정합니다. 이 두 하이퍼파라미터는 `smdistributed` 패키지에서 사용됩니다. 알고리즘 스크립트에서 이를 명시적으로 사용할 필요는 없습니다. Amazon Braket SDK에서는 편리한 키워드 인수 `distribution`를 제공합니다. 하이브리드 작업 생성에서 `distribution="data_parallel"`을 사용하면 Amazon Braket SDK가 자동으로 2개의 하이퍼파라미터를 삽입합니다. Amazon Braket API를 사용하는 경우 이 두 하이퍼파라미터를 포함해야 합니다.

인스턴스 및 데이터 병렬 처리가 구성되었으므로 이제 하이브리드 작업을 제출할 수 있습니다. `ml.g4dn.12xlarge` 인스턴스에는 4개의 GPUs. `instanceCount=1`을 설정하면 워크로드가 인스턴스의 8개 GPU에 분산됩니다. `instanceCount`을 1보다 크게 설정하면 워크로드가 모든 인스턴스에서 사용 가능한 GPU에 분산됩니다. 여러 인스턴스를 사용하는 경우 사용 시간에 따라 각 인스턴스에 요금이 부과됩니다. 예를 들어, 4개의 인스턴스를 사용하는 경우 워크로드를 동시에 실행하는 인스턴스가 4개이므로 청구 가능한 시간은 인스턴스당 실행 시간의 4배입니다.

```
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",
    ...
)
```

**참고**  
위의 하이브리드 작업 생성에서 `train_dp.py`는 데이터 병렬 처리를 사용하기 위한 수정된 알고리즘 스크립트입니다. 데이터 병렬 처리는 위 섹션에 따라 알고리즘 스크립트를 수정할 때만 올바르게 작동합니다. 데이터 병렬 처리 옵션이 올바르게 수정된 알고리즘 스크립트 없이 활성화된 경우, 하이브리드 작업에서 오류가 발생하거나 각 GPU가 동일한 데이터 조각을 반복적으로 처리하게 되어 비효율적일 수 있습니다.

올바르게 사용하면 여러 인스턴스를 사용하면 시간과 비용이 크게 감소할 수 있습니다. [ 자세한 내용은 예제 노트북을 참조](https://github.com/amazon-braket/amazon-braket-examples/blob/main/examples/hybrid_jobs/5_Parallelize_training_for_QML/Parallelize_training_for_QML.ipynb)하세요.