From 15c95b2b6eef145f2e97f4165ef8786e07e85ffd Mon Sep 17 00:00:00 2001 From: Jan Siwiec <jan.siwiec@vsb.cz> Date: Wed, 24 Apr 2024 10:52:16 +0200 Subject: [PATCH] Update 3 files --- docs.it4i/img/cudaq.png | Bin 0 -> 30971 bytes docs.it4i/software/nvidia-cuda-q.md | 68 +++++++ docs.it4i/src/qnn_example | 269 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 338 insertions(+) create mode 100644 docs.it4i/img/cudaq.png create mode 100644 docs.it4i/software/nvidia-cuda-q.md create mode 100644 docs.it4i/src/qnn_example diff --git a/docs.it4i/img/cudaq.png b/docs.it4i/img/cudaq.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec8dee0c8550f567d1b2499be0450eb11a2ce87 GIT binary patch literal 30971 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 literal 0 HcmV?d00001 diff --git a/docs.it4i/software/nvidia-cuda-q.md b/docs.it4i/software/nvidia-cuda-q.md new file mode 100644 index 000000000..ea710db66 --- /dev/null +++ b/docs.it4i/software/nvidia-cuda-q.md @@ -0,0 +1,68 @@ +# CUDA Quantum for Python on Barbora + +## What Is CUDA Quantum? + +CUDA Quantum streamlines hybrid application development and promotes productivity and scalability in quantum computing. It offers a unified programming model designed for a hybrid setting—that is, CPUs, GPUs, and QPUs working together. + +For more information, see the [official documentation][1]. + +## How to Install Version Without GPU Acceleration + +Use (preferably in conda environment) + +```bash +pip install cuda-quantum +``` + +## How to Install Version With GPU Acceleration Using Conda + +Run: + +```bash +conda create -y -n cuda-quantum python=3.10 pip +conda install -y -n cuda-quantum -c "nvidia/label/cuda-11.8.0" cuda +conda install -y -n cuda-quantum -c conda-forge mpi4py openmpi cxx-compiler cuquantum +conda env config vars set -n cuda-quantum +LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$CONDA_PREFIX/envs/cuda-quantum/lib" +conda env config vars set -n cuda-quantum +MPI_PATH=$CONDA_PREFIX/envs/cuda-quantum +conda run -n cuda-quantum pip install cuda-quantum +conda activate cuda-quantum +source $CONDA_PREFIX/lib/python3.10/site-packages/distributed_interfaces/activate_custom_mpi.sh +``` + +Then configure the MPI: + +``` bash +export OMPI_MCA_opal_cuda_support=true OMPI_MCA_btl='^openib' +``` + +## How to Test Your Installation? + +You can test your installation by running the following script: + +```bash +import cudaq + +kernel = cudaq.make_kernel() +qubit = kernel.qalloc() +kernel.x(qubit) +kernel.mz(qubit) + +result = cudaq.sample(kernel) +``` + +## Further Questions Considering the Installation? + +See the Cuda Quantum PyPI website at [https://pypi.org/project/cuda-quantum/][2]. + +## Example QNN: + +In the *qnn_example.py* you find a script that loads FashionMNIST dataset, chooses two data type (shirts and pants), then we create a Neural Network with quantum layer.This network is then trained on our data and later tested on the test dataset. You are free to try it on your own. Download the [QNN example][a] and rename it to `qnn_example.py`. + + + +[1]: https://nvidia.github.io/cuda-quantum/latest/index.html +[2]: https://pypi.org/project/cuda-quantum/ + +[a]: ../src/qnn_example \ No newline at end of file diff --git a/docs.it4i/src/qnn_example b/docs.it4i/src/qnn_example new file mode 100644 index 000000000..9ffee3e37 --- /dev/null +++ b/docs.it4i/src/qnn_example @@ -0,0 +1,269 @@ +#!/usr/bin/env python + + +import numpy as np +import matplotlib.pyplot as plt + +import torch +from torch.autograd import Function +from torchvision import datasets, transforms +import torch.optim as optim +import torch.nn as nn +import torch.nn.functional as F + +import cudaq +from cudaq import spin + + + + +# GPU utilities +for tar in cudaq.get_targets(): + print(f'{tar.description} {tar.name} {tar.platform} {tar.simulator} {tar.num_qpus}') +cudaq.set_target("default") # Set CUDAQ to run on GPU's +torch.cuda.is_available( +) # If this is True then the NVIDIA drivers are correctly installed + +torch.cuda.device_count() # Counts the number of GPU's available + +torch.cuda.current_device() + +torch.cuda.get_device_name(0) + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + + + +# Training set +sample_count = 140 + +X_train = datasets.FashionMNIST( + root="./data", + train=True, + download=True, + transform=transforms.Compose([transforms.ToTensor()]), +) + +# Leaving only labels 0 and 1 +idx = np.append( + np.where(X_train.targets == 0)[0][:sample_count], + np.where(X_train.targets == 1)[0][:sample_count], +) +X_train.data = X_train.data[idx] +X_train.targets = X_train.targets[idx] +train_loader = torch.utils.data.DataLoader(X_train, batch_size=1, shuffle=True) + +# Test set +sample_count = 70 + +X_test = datasets.FashionMNIST( + root="./data", + train=False, + download=True, + transform=transforms.Compose([transforms.ToTensor()]), +) +idx = np.append( + np.where(X_test.targets == 0)[0][:sample_count], + np.where(X_test.targets == 1)[0][:sample_count], +) + +X_test.data = X_test.data[idx] +X_test.targets = X_test.targets[idx] + +test_loader = torch.utils.data.DataLoader(X_test, batch_size=1, shuffle=True) + + +class QuantumCircuit: + """This class defines the quantum circuit structure and the run method which is used to calculate an expectation value""" + + def __init__(self, qubit_count: int): + """Define the quantum circuit in CUDA Quantum""" + + kernel, thetas = cudaq.make_kernel(list) + + self.kernel = kernel + + self.theta = thetas + + qubits = kernel.qalloc(qubit_count) + + self.kernel.h(qubits) + + # Variational gate parameters which are optimised during training + kernel.ry(thetas[0], qubits[0]) + kernel.rx(thetas[1], qubits[0]) + + def run(self, thetas: torch.tensor) -> torch.tensor: + """Excetute the quantum circuit to output an expectation value""" + + expectation = torch.tensor(cudaq.observe(self.kernel, spin.z(0), + thetas).expectation_z(), + device=device) + + return expectation + + + + +class QuantumFunction(Function): + """Allows the quantum circuit to pass data through it and compute the gradients""" + + @staticmethod + def forward(ctx, thetas: torch.tensor, quantum_circuit, + shift) -> torch.tensor: + # Save shift and quantum_circuit in context to use in backward + ctx.shift = shift + ctx.quantum_circuit = quantum_circuit + + # Calculate exp_val + expectation_z = ctx.quantum_circuit.run(thetas) + + ctx.save_for_backward(thetas, expectation_z) + + return expectation_z + + @staticmethod + def backward(ctx, grad_output): + """Backward pass computation via finite difference parameter shift""" + + thetas, expectation_z = ctx.saved_tensors + + gradients = torch.zeros(len(thetas), device=device) + + for i in range(len(thetas)): + shift_right = torch.clone(thetas) + + shift_right[i] += ctx.shift + + shift_left = torch.clone(thetas) + + shift_left[i] -= ctx.shift + + expectation_right = ctx.quantum_circuit.run(shift_right) + expectation_left = ctx.quantum_circuit.run(shift_left) + + gradients[i] = 0.5 * (expectation_right - expectation_left) + + return gradients * grad_output.float(), None, None + + + +class QuantumLayer(nn.Module): + """Encapsulates a quantum circuit and a quantum function into a quantum layer""" + + def __init__(self, shift: torch.tensor): + super(QuantumLayer, self).__init__() + self.quantum_circuit = QuantumCircuit(1) # 1 qubit quantum circuit + self.shift = shift + + def forward(self, input): + ans = QuantumFunction.apply(input, self.quantum_circuit, self.shift) + + return ans + + + +class Net(nn.Module): + + def __init__(self): + super(Net, self).__init__() + + # Neural network structure + self.conv1 = nn.Conv2d(1, 6, kernel_size=5) + self.conv2 = nn.Conv2d(6, 16, kernel_size=5) + self.dropout = nn.Dropout2d() + self.fc1 = nn.Linear(256, 64) + self.fc2 = nn.Linear( + 64, 2 + ) # Output a 2D tensor since we have 2 variational parameters in our quantum circuit + self.hybrid = QuantumLayer( + torch.tensor(np.pi / 2) + ) # Input is the magnitude of the parameter shifts to calculate gradients + + def forward(self, x): + x = F.relu(self.conv1(x)) + x = F.max_pool2d(x, 2) + x = F.relu(self.conv2(x)) + x = F.max_pool2d(x, 2) + x = self.dropout(x) + x = x.view(1, -1) + x = F.relu(self.fc1(x)) + x = self.fc2(x).reshape( + -1) # Reshapes required to satisfy input dimensions to CUDAQ + x = self.hybrid(x).reshape(-1) + + return torch.cat((x, 1 - x), -1).unsqueeze(0) + + + + +# We move our model to the CUDA device to minimise data transfer between GPU and CPU + +model = Net().to(device) +print(model) +optimizer = optim.Adam(model.parameters(), lr=0.001) + +loss_func = nn.NLLLoss().to(device) + +epochs = 20 + +epoch_loss = [] + +model.train() +for epoch in range(epochs): + batch_loss = 0.0 + for batch_idx, (data, target) in enumerate(train_loader): # batch training + optimizer.zero_grad() + + data, target = data.to(device), target.to(device) + + # Forward pass + output = model(data).to(device) + # Calculating loss + loss = loss_func(output, target).to(device) + + # Backward pass + loss.backward() + + # Optimize the weights + optimizer.step() + + batch_loss += loss.item() + + epoch_loss.append(batch_loss / batch_idx) + + print("Training [{:.0f}%]\tLoss: {:.4f}".format( + 100.0 * (epoch + 1) / epochs, epoch_loss[-1])) + + + + +plt.plot(epoch_loss) +plt.title("Hybrid NN Training Convergence") +plt.xlabel("Training Iterations") + +plt.ylabel("Neg Log Likelihood Loss") + + + + +# Testing on the test set + +model.eval() +with torch.no_grad(): + correct = 0 + for batch_idx, (data, target) in enumerate(test_loader): + data, target = data.to(device), target.to(device) + + output = model(data).to(device) + + pred = output.argmax(dim=1, keepdim=True) + correct += pred.eq(target.view_as(pred)).sum().item() + + loss = loss_func(output, target) + epoch_loss.append(loss.item()) + + print("Performance on test data:\n\tAccuracy: {:.1f}%".format( + correct / len(test_loader) * 100)) + diff --git a/mkdocs.yml b/mkdocs.yml index 8ea6d9ef5..699a4d125 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -233,6 +233,7 @@ nav: - EESSI: software/eessi.md - GPU: - NVIDIA CUDA: software/nvidia-cuda.md + - NVIDIA CUDA Quantum: software/nvidia-cuda-q.md - ROCm HIP: software/nvidia-hip.md - Intel Suite: - Introduction: software/intel/intel-suite/intel-parallel-studio-introduction.md -- GitLab