Converting Neural Networks to VNNLib Format with VERONA: A Complete Guide

VERONA converts ONNX neural networks into VNNLib property files using modular property generators, enabling formal verification of model robustness against adversarial perturbations.

VERONA (from the ada-research/verona repository) provides a streamlined pipeline for converting neural network classifiers into VNNLib specifications. Converting neural networks to VNNLib format for VERONA involves three core components that transform an input image, its true label, and a perturbation radius into a formal property file ready for verification tools like Marabou or ERAN.

The VERONA Conversion Architecture

The conversion pipeline relies on three interconnected components implemented in the VERONA source code:

This modular design allows you to take any ONNX-compatible network, specify an input data point and epsilon radius, and obtain a .vnnlib file that encodes the robustness property.

Property Generators: Creating VNNLib Specifications

Property generators inherit from the abstract PropertyGenerator base class defined in ada_verona/verification_module/property_generator/property_generator.py. Each generator implements the create_vnnlib_property method to produce platform-agnostic verification constraints.

One2OnePropertyGenerator (Targeted Verification)

The One2OnePropertyGenerator creates properties that check whether a specific target class can outrank the true class under perturbation. Located in ada_verona/verification_module/property_generator/one2one_property_generator.py, this generator produces assertions like:

(assert (or (and (>= Y_target Y_true))))

Use this when verifying whether an adversary can force a specific misclassification (e.g., making the network classify a "7" as a "3").

One2AnyPropertyGenerator (Untargeted Verification)

The One2AnyPropertyGenerator in ada_verona/verification_module/property_generator/one2any_property_generator.py creates untargeted properties that are violated when any non-true class beats the true class:

(assert (or
    (and (>= Y_i Y_true))   ; for every i ≠ true class
))

Both generators perform the same preprocessing steps: clipping and normalizing the image with epsilon bounds, declaring input variables X_i and output variables Y_i, and adding bound constraints for each input dimension before appending the output condition.

The VNNLibProperty Dataclass

Generated specifications are wrapped in the VNNLibProperty dataclass from ada_verona/database/vnnlib_property.py:

@dataclass
class VNNLibProperty:
    name: str                # e.g. "property_3_0_01"

    content: str             # raw VNNLib script

    path: Path = None        # populated after saving to disk

This lightweight structure is serializable and database-friendly, allowing properties to persist across process boundaries without losing their raw VNNLib text content.

Managing Workflows with VerificationContext

The VerificationContext class in ada_verona/database/verification_context.py bundles all verification metadata:

Key methods include save_vnnlib_property(vnnlib_property), which writes the content to <tmp>/<name>.vnnlib and updates the path attribute, and get_dict_for_epsilon_result(), which merges context metadata with generator-specific dictionaries for epsilon-search logging.

The context is fully serializable via to_dict() and from_dict(), using dynamic imports to reconstruct the correct property generator class.

Step-by-Step: Converting an ONNX Model to VNNLib

Follow these steps to convert a neural network to VNNLib format using VERONA.

1. Load the ONNX Network

from pathlib import Path
from ada_verona.database.machine_learning_model.onnx_network import ONNXNetwork

network_path = Path("examples/example_experiment/data/networks/mnist-net_256x2.onnx")
network = ONNXNetwork(network_path)  # lazy loading; model read on demand

2. Prepare the Data Point

from ada_verona.database.dataset.data_point import DataPoint
import numpy as np

image = np.load("examples/example_experiment/data/images/0.npy")  # shape (1, 28, 28)

image = image.astype(np.float32)
data_point = DataPoint(id="img_0", label=7, data=image)

3. Select a Property Generator

from ada_verona.verification_module.property_generator.one2one_property_generator import One2OnePropertyGenerator

# Targeted: force misclassification to class 3

prop_gen = One2OnePropertyGenerator(target_class=3, number_classes=10)

# For untargeted verification, use:

# from ada_verona.verification_module.property_generator.one2any_property_generator import One2AnyPropertyGenerator

# prop_gen = One2AnyPropertyGenerator(number_classes=10)

4. Create the Verification Context

from ada_verona.database.verification_context import VerificationContext

tmp_dir = Path("tmp_verification")
ctx = VerificationContext(
    network=network,
    data_point=data_point,
    tmp_path=tmp_dir,
    property_generator=prop_gen,
    save_epsilon_results=False
)

5. Generate and Save the Property

epsilon = 0.02
vnnlib = prop_gen.create_vnnlib_property(
    image=data_point.data,
    image_class=data_point.label,
    epsilon=epsilon,
)

ctx.save_vnnlib_property(vnnlib)  # writes tmp_verification/property_7_0_02.vnnlib

print(f"VNNLib file saved at: {vnnlib.path}")

6. Verify with a VNNLib-Compatible Tool

marabou tmp_verification/property_7_0_02.vnnlib network.onnx

7. Serialize for Later Reuse (Optional)

import json

ctx_dict = ctx.to_dict()
json.dump(ctx_dict, open("verif_config.json", "w"), indent=2)

# Reload later

loaded_ctx = VerificationContext.from_dict(json.load(open("verif_config.json")))

Summary

  • VERONA's conversion pipeline uses property generators to create VNNLib text, VNNLibProperty to package results, and VerificationContext to handle file operations and serialization
  • One2OnePropertyGenerator creates targeted properties for specific misclassifications, while One2AnyPropertyGenerator handles untargeted robustness verification
  • Generated .vnnlib files comply with the VNNLib specification and work with verifiers like Marabou and ERAN
  • The entire verification configuration can be serialized and deserialized using the context's to_dict() and from_dict() methods

Frequently Asked Questions

What is the VNNLib format used for in VERONA?

VNNLib is a standardized format for encoding neural network verification properties using SMT-LIB syntax. In VERONA, it expresses constraints that define whether a neural network is robust to epsilon-bounded perturbations for a specific input, allowing external verification engines to formally prove or disprove safety properties.

How does VERONA handle targeted versus untargeted verification?

VERONA handles targeted verification through One2OnePropertyGenerator, which generates properties asserting that a specific target class exceeds the true class score. For untargeted verification, One2AnyPropertyGenerator creates properties asserting that any non-true class can exceed the true class score, representing general adversarial robustness without specifying the destination class.

Can I reuse verification configurations across different machines?

Yes. The VerificationContext class provides to_dict() and from_dict() methods that serialize the entire verification setup, including the network reference, data point, property generator type, and parameters. The deserialization process dynamically imports the correct generator class, making configurations fully portable.

Which neural network formats does VERONA support for conversion?

VERONA primarily supports ONNX format through the ONNXNetwork wrapper in ada_verona/database/machine_learning_model/onnx_network.py. The system uses lazy loading and can convert ONNX models to PyTorch internally, but the VNNLib conversion pipeline accepts any network format that VERONA's Network abstract base class can wrap.

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 →