# Running VERONA with GPU Acceleration for Large-Scale Verification

> Accelerate large-scale verification with VERONA and GPU support. Automatically offload tasks to CUDA-enabled devices for faster, more efficient analysis without manual setup.

- Repository: [ADA research/verona](https://github.com/ada-research/verona)
- Tags: performance
- Published: 2026-02-23

---

**TLDR:** VERONA automatically detects CUDA-capable devices and routes tensors, models, and verification calls to GPU-accelerated backends like AB-CROWN without requiring manual device configuration.

VERONA (VERification Of Neural Architectures) is a modular Python library developed by ada-research/verona that streamlines robustness verification pipelines for neural networks. When executing large-scale experiments—such as verifying thousands of images or running computationally intensive verifiers like **AB-CROWN**—GPU acceleration is crucial for performance. The framework abstracts CUDA detection across its components, automatically placing tensors and models on `torch.device("cuda")` when available while delegating heavy computations to GPU-aware verification backends.

## How VERONA Automatically Detects CUDA Devices

The library implements automatic device selection at multiple stages of the verification pipeline. Each component checks `torch.cuda.is_available()` independently, ensuring seamless GPU utilization without manual intervention.

### Data Sampling on GPU

The `PredictionsBasedSampler` handles moving input tensors to the appropriate device before processing. In [`ada_verona/dataset_sampler/predictions_based_sampler.py`](https://github.com/ada-research/verona/blob/main/ada_verona/dataset_sampler/predictions_based_sampler.py) (line 54), the device selection logic initializes as:

```python
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

```

This ensures that sampled data points are immediately transferred to CUDA memory when hardware acceleration is present, reducing CPU-GPU transfer overhead during verification.

### Model Loading for GPU Execution

Neural network wrappers in VERONA automatically place models on the detected CUDA device. Both `PytorchNetwork` and `OnnxNetwork` implement identical device-selection patterns in [`ada_verona/database/machine_learning_model/pytorch_network.py`](https://github.com/ada-research/verona/blob/main/ada_verona/database/machine_learning_model/pytorch_network.py) (line 89) and [`.../onnx_network.py`](https://github.com/ada-research/verona/blob/main/.../onnx_network.py) (line 102). When the experiment repository loads a network, it resides on the same CUDA device as the input tensors, eliminating device mismatch errors during forward passes.

## Configuring GPU-Enabled Verification Backends

VERONA delegates GPU-intensive computations to specialized verification backends through the `AutoVerifyModule` wrapper, which inherits from the abstract `VerificationModule` base class in [`ada_verona/verification_module/verification_module.py`](https://github.com/ada-research/verona/blob/main/ada_verona/verification_module/verification_module.py).

### AutoVerifyModule and AB-CROWN Integration

The `AutoVerifyModule` class in [`ada_verona/verification_module/auto_verify_module.py`](https://github.com/ada-research/verona/blob/main/ada_verona/verification_module/auto_verify_module.py) serves as the primary interface for GPU-accelerated verifiers. When configured with **AB-CROWN**, the module forwards verification calls to the auto-verify framework, which automatically utilizes CUDA for underlying MILP/LP solves. The execution flow proceeds as follows:

1. **Property Generation**: `One2OnePropertyGenerator` or `One2AnyPropertyGenerator` creates VNN-LIB specifications describing the ε-ball (CPU-bound operation).
2. **Verification Dispatch**: `AutoVerifyModule.verify` hands the VNN-LIB and model path to the verifier.
3. **GPU Computation**: AB-CROWN executes linear programming operations on CUDA cores.
4. **Result Parsing**: SAT/UNSAT outcomes return as `CompleteVerificationData` objects.

### Adversarial Attacks on GPU

For optional adversarial robustness testing, the `AutoAttack` wrapper in [`ada_verona/verification_module/attacks/auto_attack_wrapper.py`](https://github.com/ada-research/verona/blob/main/ada_verona/verification_module/attacks/auto_attack_wrapper.py) defaults to CUDA execution:

```python
self.device = device

```

This allows fast adversarial attacks to run on GPU when available, providing rapid counter-example generation before formal verification begins.

## Complete GPU Verification Pipeline Example

The following minimal example demonstrates a full GPU-enabled verification loop using AB-CROWN. Install the GPU variant first:

```bash
uv pip install "ada-verona[gpu]"

```

Verify CUDA detection before running:

```python
import torch
print("CUDA available:", torch.cuda.is_available())

```

Execute the complete pipeline:

```python
from pathlib import Path
import torch, torchvision.transforms as transforms
import torchvision

from ada_verona.database.experiment_repository import ExperimentRepository
from ada_verona.dataset_sampler.predictions_based_sampler import PredictionsBasedSampler
from ada_verona.verification_module.auto_verify_module import AutoVerifyModule
from ada_verona.verification_module.property_generator.one2any_property_generator import One2AnyPropertyGenerator
from ada_verona.epsilon_value_estimator.binary_search_epsilon_value_estimator import BinarySearchEpsilonValueEstimator
from autoverify.verifier import AbCrown

# 1️⃣ Load dataset

mnist = torchvision.datasets.MNIST(root="./data", train=True, download=True,
                                 transform=transforms.ToTensor())

# 2️⃣ Prepare experiment repository

repo = ExperimentRepository(base_path=Path("./my_experiment"), network_folder=Path("./networks"))
repo.initialize_new_experiment("gpu_ab_crown_demo")

# 3️⃣ Configure components

prop_gen = One2AnyPropertyGenerator()
verifier = AutoVerifyModule(verifier=AbCrown(), timeout=600)
eps_estimator = BinarySearchEpsilonValueEstimator(
    epsilon_value_list=[0.001, 0.005, 0.01, 0.02], 
    verifier=verifier
)
sampler = PredictionsBasedSampler(sample_correct_predictions=True)

# 4️⃣ Run verification

network = repo.get_network_list()[0]
for data_point in sampler.sample(network, mnist):
    ctx = repo.create_verification_context(network, data_point, prop_gen)
    result = eps_estimator.compute_epsilon_value(ctx)
    repo.save_result(result)

repo.save_plots()

```

**Key implementation details:**

- `PredictionsBasedSampler` moves `data_point` to CUDA via `torch.device("cuda")`.
- `PytorchNetwork` loads onto the same CUDA device internally through the experiment repository.
- `AutoVerifyModule` forwards to AB-CROWN, which performs MILP computations on GPU.

## Scaling to Multi-Node GPU Clusters

For massive parallelization across multiple compute nodes, VERONA supports SLURM array jobs. The [`multiple_jobs/one_multiple_jobs.py`](https://github.com/ada-research/verona/blob/main/multiple_jobs/one_multiple_jobs.py) script dispatches individual verification contexts as separate tasks, with each node executing the same GPU detection logic:

```bash
python examples/scripts/multiple_jobs/one_multiple_jobs.py \
    --file_verification_context path/to/context.yaml \
    --base_path_experiment_repository ./my_experiment \
    --network_folder ./networks \
    --experiment_name gpu_ab_crown_demo \
    --epsilon_list 0.001 0.005 0.01 0.02

```

Each compute node independently loads the model onto its local GPU via [`pytorch_network.py`](https://github.com/ada-research/verona/blob/main/pytorch_network.py), runs AB-CROWN verification, and writes results back to the shared experiment repository. This architecture enables horizontal scaling from single-GPU workstations to multi-node clusters without code modification.

## Summary

- **Automatic detection**: VERONA checks `torch.cuda.is_available()` in `PredictionsBasedSampler` and model wrappers, eliminating manual device management.
- **Backend integration**: `AutoVerifyModule` in [`ada_verona/verification_module/auto_verify_module.py`](https://github.com/ada-research/verona/blob/main/ada_verona/verification_module/auto_verify_module.py) routes computations to GPU-enabled verifiers like AB-CROWN.
- **Full pipeline support**: Data loading, model placement, adversarial attacks ([`auto_attack_wrapper.py`](https://github.com/ada-research/verona/blob/main/auto_attack_wrapper.py)), and verification all respect CUDA availability.
- **Cluster scaling**: The [`one_multiple_jobs.py`](https://github.com/ada-research/verona/blob/main/one_multiple_jobs.py) script enables distributed GPU verification across SLURM-managed clusters.
- **Installation**: Use `pip install "ada-verona[gpu]"` to ensure GPU dependencies are present.

## Frequently Asked Questions

### Does VERONA require manual CUDA device management?

No. VERONA automatically detects CUDA-capable hardware in [`ada_verona/dataset_sampler/predictions_based_sampler.py`](https://github.com/ada-research/verona/blob/main/ada_verona/dataset_sampler/predictions_based_sampler.py) (line 54) and [`ada_verona/database/machine_learning_model/pytorch_network.py`](https://github.com/ada-research/verona/blob/main/ada_verona/database/machine_learning_model/pytorch_network.py) (line 89), placing tensors and models on the appropriate device without user intervention. You only need to ensure PyTorch with CUDA support is installed.

### Which verification backends support GPU acceleration in VERONA?

VERONA supports GPU acceleration through the `AutoVerifyModule` wrapper for any auto-verify compatible verifier. **AB-CROWN** is the primary GPU-accelerated backend, automatically utilizing CUDA for MILP/LP solves. The `AutoAttack` wrapper in [`ada_verona/verification_module/attacks/auto_attack_wrapper.py`](https://github.com/ada-research/verona/blob/main/ada_verona/verification_module/attacks/auto_attack_wrapper.py) also defaults to GPU execution for adversarial robustness testing.

### How do I verify that VERONA is using my GPU?

Run the sanity check shown in [`examples/scripts/create_robustness_dist_on_pytorch_dataset.py`](https://github.com/ada-research/verona/blob/main/examples/scripts/create_robustness_dist_on_pytorch_dataset.py):

```python
import torch
print("CUDA available:", torch.cuda.is_available())

```

Additionally, monitor GPU utilization during verification runs. AB-CROWN will show significant GPU activity when solving linear programs, while the `PredictionsBasedSampler` will allocate CUDA memory for model and tensor storage.

### Can I run CPU-only verification if CUDA is available?

Yes. While VERONA defaults to CUDA when detected, the device selection logic `torch.device("cuda" if torch.cuda.is_available() else "cpu")` in the sampler and model loaders will fall back to CPU if CUDA is unavailable or disabled. To force CPU execution on a CUDA-enabled system, modify the device assignment in the respective source files or set environment variables that hide CUDA devices from PyTorch.