Running VERONA with GPU Acceleration for Large-Scale Verification

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 (line 54), the device selection logic initializes as:

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 (line 89) and .../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.

AutoVerifyModule and AB-CROWN Integration

The AutoVerifyModule class in 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 defaults to CUDA execution:

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:

uv pip install "ada-verona[gpu]"

Verify CUDA detection before running:

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

Execute the complete pipeline:

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 script dispatches individual verification contexts as separate tasks, with each node executing the same GPU detection logic:

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, 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 routes computations to GPU-enabled verifiers like AB-CROWN.
  • Full pipeline support: Data loading, model placement, adversarial attacks (auto_attack_wrapper.py), and verification all respect CUDA availability.
  • Cluster scaling: The 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 (line 54) and 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 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:

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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →