Git Product home page Git Product logo

interval-bound-propagation's Introduction

Interval Bound Propagation for Training Verifiably Robust Models

This repository contains a simple implementation of Interval Bound Propagation (IBP) using TensorFlow: https://arxiv.org/abs/1810.12715. It also contains an implementation of CROWN-IBP: https://arxiv.org/abs/1906.06316. It also contains a sentiment analysis example under examples/language for https://arxiv.org/abs/1909.01492.

This is not an official Google product

Installation

IBP can be installed with the following command:

pip install git+https://github.com/deepmind/interval-bound-propagation

IBP will work with both the CPU and GPU version of tensorflow and dm-sonnet, but to allow for that it does not list Tensorflow as a requirement, so you need to install Tensorflow and Sonnet separately if you haven't already done so.

Usage

The following command trains a small model on MNIST with epsilon set to 0.3:

cd examples
python train.py --model=small --output_dir=/tmp/small_model

Pretrained Models

Models trained using IBP and CROWN-IBP can be downloaded here.

IBP models:

Dataset Test epsilon Model path Clean accuracy Verified accuracy Accuracy under attack
MNIST 0.1 ibp/mnist_0.2_medium 98.94% 97.08% 97.99%
MNIST 0.2 ibp/mnist_0.4_large_200 98.34% 95.47% 97.06%
MNIST 0.3 ibp/mnist_0.4_large_200 98.34% 91.79% 96.03%
MNIST 0.4 ibp/mnist_0.4_large_200 98.34% 84.99% 94.56%
CIFAR-10 2/255 ibp/cifar_2-255_large_200 70.21% 44.12% 56.53%
CIFAR-10 8/255 ibp/cifar_8-255_large 49.49% 31.56% 39.53%

CROWN-IBP models:

Dataset Test epsilon Model path Clean accuracy Verified accuracy Accuracy under attack
MNIST 0.1 crown-ibp/mnist_0.2_large 99.03% 97.75% 98.34%
MNIST 0.2 crown-ibp/mnist_0.4_large 98.38% 96.13% 97.28%
MNIST 0.3 crown-ibp/mnist_0.4_large 98.38% 93.32% 96.38%
MNIST 0.4 crown-ibp/mnist_0.4_large 98.38% 87.51% 94.95%
CIFAR-10 2/255 crown-ibp/cifar_2-255_large 71.52% 53.97% 59.72%
CIFAR-10 8/255 crown-ibp/cifar_8-255_large 47.14% 33.30% 36.81%
CIFAR-10 16/255 crown-ibp/cifar_16-255_large 34.19% 23.08% 26.55%

In these tables, we evaluated the verified accuracy using IBP only. We evaluted the accuracy under attack using a 20-step untargeted PGD attack. You can evaluate these models yourself using eval.py, for example:

cd examples
python eval.py --model_dir pretrained_models/ibp/mnist_0.4_large_200/ \
  --epsilon 0.3

Note that we evaluated the CIFAR-10 2/255 CROWN-IBP model using CROWN-IBP (instead of pure IBP). You can do so yourself by setting the flag --bound_method=crown-ibp:

python eval.py --model_dir pretrained_models/crown-ibp/cifar_2-255_large/ \
  --epsilon 0.00784313725490196 --bound_method=crown-ibp

Giving credit

If you use this code in your work, we ask that you cite this paper:

Sven Gowal, Krishnamurthy Dvijotham, Robert Stanforth, Rudy Bunel, Chongli Qin, Jonathan Uesato, Relja Arandjelovic, Timothy Mann, and Pushmeet Kohli. "On the Effectiveness of Interval Bound Propagation for Training Verifiably Robust Models." arXiv preprint arXiv:1810.12715 (2018).

If you use CROWN-IBP, we also ask that you cite:

Huan Zhang, Hongge Chen, Chaowei Xiao, Sven Gowal, Robert Stanforth, Bo Li, Duane Boning, Cho-Jui Hsieh. "Towards Stable and Efficient Training of Verifiably Robust Neural Networks." arXiv preprint arXiv:1906.06316 (2019).

If you use the sentiment analysis example, please cite:

Po-Sen Huang, Robert Stanforth, Johannes Welbl, Chris Dyer, Dani Yogatama, Sven Gowal, Krishnamurthy Dvijotham, Pushmeet Kohli. "Achieving Verified Robustness to Symbol Substitutions via Interval Bound Propagation." EMNLP 2019.

Acknowledgements

In addition to the people involved in the original IBP publication, we would like to thank Huan Zhang, Sumanth Dathathri and Johannes Welbl for their contributions.

interval-bound-propagation's People

Contributors

derpson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

interval-bound-propagation's Issues

Execution error

TensorFlow version 2.15.0
Sonnet version 2.0.2

predictor(test_data.image, override=True, is_training=False)
TypeError: 'VerifiableModelWrapper' object is not callable


# coding=utf-8
# Copyright 2019 The Interval Bound Propagation Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Evaluates a verifiable model on Mnist or CIFAR-10."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from absl import logging
import interval_bound_propagation as ibp
import tensorflow.compat.v1 as tf


def layers(model_size):
    """Returns the layer specification for a given model name."""
    if model_size == "tiny":
        return (("linear", 100), ("activation", "relu"))
    elif model_size == "small":
        return (
            ("conv2d", (4, 4), 16, "VALID", 2),
            ("activation", "relu"),
            ("conv2d", (4, 4), 32, "VALID", 1),
            ("activation", "relu"),
            ("linear", 100),
            ("activation", "relu"),
        )
    elif model_size == "medium":
        return (
            ("conv2d", (3, 3), 32, "VALID", 1),
            ("activation", "relu"),
            ("conv2d", (4, 4), 32, "VALID", 2),
            ("activation", "relu"),
            ("conv2d", (3, 3), 64, "VALID", 1),
            ("activation", "relu"),
            ("conv2d", (4, 4), 64, "VALID", 2),
            ("activation", "relu"),
            ("linear", 512),
            ("activation", "relu"),
            ("linear", 512),
            ("activation", "relu"),
        )
    elif model_size == "large_200":
        # Some old large checkpoints have 200 hidden neurons in the last linear
        # layer.
        return (
            ("conv2d", (3, 3), 64, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 64, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 2),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 1),
            ("activation", "relu"),
            ("linear", 200),
            ("activation", "relu"),
        )
    elif model_size == "large":
        return (
            ("conv2d", (3, 3), 64, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 64, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 2),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 1),
            ("activation", "relu"),
            ("conv2d", (3, 3), 128, "SAME", 1),
            ("activation", "relu"),
            ("linear", 512),
            ("activation", "relu"),
        )
    else:
        raise ValueError('Unknown model: "{}"'.format(model_size))


def show_metrics(metric_values, bound_method="ibp"):
    if bound_method == "crown-ibp":
        verified_accuracy = metric_values.crown_ibp_verified_accuracy
    else:
        verified_accuracy = metric_values.verified_accuracy
    print(
        "nominal accuracy = {:.2f}%, "
        "verified accuracy = {:.2f}%, "
        "accuracy under PGD attack = {:.2f}%".format(
            metric_values.nominal_accuracy * 100.0,
            verified_accuracy * 100.0,
            metric_values.attack_accuracy * 100.0,
        )
    )


# Test using while loop.
def get_test_metrics(batch_size, attack_builder=ibp.UntargetedPGDAttack):
    """Returns the test metrics."""
    num_test_batches = len(data_test[0]) // batch_size
    assert (
        len(data_test[0]) % batch_size == 0
    ), "Test data is not a multiple of batch size."

    def cond(i, *unused_args):
        return i < num_test_batches

    def body(i, metrics):
        """Compute the sum of all metrics."""
        test_data = ibp.build_dataset(data_test, batch_size=batch_size, sequential=True)
        predictor(test_data.image, override=True, is_training=False)
        input_interval_bounds = ibp.IntervalBounds(
            tf.maximum(test_data.image - cEPSILON, input_bounds[0]),
            tf.minimum(test_data.image + cEPSILON, input_bounds[1]),
        )
        predictor.propagate_bounds(input_interval_bounds)
        test_specification = ibp.ClassificationSpecification(
            test_data.label, num_classes
        )
        test_attack = attack_builder(
            predictor,
            test_specification,
            cEPSILON,
            input_bounds=input_bounds,
            optimizer_builder=ibp.UnrolledAdam,
        )

        # Use CROWN-IBP bound or IBP bound.
        if cBOUND_METHOD == "crown-ibp":
            test_losses = ibp.crown.Losses(
                predictor,
                test_specification,
                test_attack,
                use_crown_ibp=True,
                crown_bound_schedule=tf.constant(1.0),
            )
        else:
            test_losses = ibp.Losses(predictor, test_specification, test_attack)

        test_losses(test_data.label)
        new_metrics = []
        for m, n in zip(metrics, test_losses.scalar_metrics):
            new_metrics.append(m + n)
        return i + 1, new_metrics

    if cBOUND_METHOD == "crown-ibp":
        metrics = ibp.crown.ScalarMetrics
    else:
        metrics = ibp.ScalarMetrics
    total_count = tf.constant(0, dtype=tf.int32)
    total_metrics = [
        tf.constant(0, dtype=tf.float32) for _ in range(len(metrics._fields))
    ]
    total_count, total_metrics = tf.while_loop(
        cond,
        body,
        loop_vars=[total_count, total_metrics],
        back_prop=False,
        parallel_iterations=1,
    )
    total_count = tf.cast(total_count, tf.float32)
    test_metrics = []
    for m in total_metrics:
        test_metrics.append(m / total_count)
    return metrics(*test_metrics)


def main():
    test_metrics = get_test_metrics(200, ibp.UntargetedPGDAttack)

    # Prepare to load the pretrained-model.
    saver = tf.compat.v1.train.Saver(original_predictor.get_variables())

    # Run everything.
    tf_config = tf.ConfigProto()
    tf_config.gpu_options.allow_growth = True
    with tf.train.SingularMonitoredSession(config=tf_config) as sess:
        logging.info('Restoring from checkpoint "%s".', checkpoint_path)
        saver.restore(sess, checkpoint_path)
        logging.info("Evaluating at epsilon = %f.", cEPSILON)
        metric_values = sess.run(test_metrics)
        show_metrics(metric_values, cBOUND_METHOD)


if __name__ == "__main__":
    print("TensorFlow version {}".format(tf.__version__))
    # print("Sonnet version {}".format(snt.__version__))

    # python sg_eval.py --model_dir './Models/crown-ibp/cifar_2-255_large/' --epsilon 0.00784313725490196 --bound_method=crown-ibp

    cDATASET = "cifar10"
    cMODEL = "large"
    cEPSILON = 0.00784313725490196
    cBOUND_METHOD = "ibp"

    cMODEL_DIR = ".//Models//ibp//cifar_2-255_large_200//"
    checkpoint_path = tf.train.latest_checkpoint(cMODEL_DIR)
    if checkpoint_path is None:
        raise OSError("Cannot find a valid checkpoint in {}.".format(cMODEL_DIR))

    # Dataset.
    input_bounds = (0.0, 1.0)
    num_classes = 10
    if cDATASET == "mnist":
        data_train, data_test = tf.keras.datasets.mnist.load_data()
    else:
        assert cDATASET == "cifar10", 'Unknown dataset "{}"'.format(cDATASET)
        data_train, data_test = tf.keras.datasets.cifar10.load_data()
        data_train = (data_train[0], data_train[1].flatten())
        data_test = (data_test[0], data_test[1].flatten())

    # Base predictor network.
    original_predictor = ibp.DNN(num_classes, layers(cMODEL))
    predictor = original_predictor
    if cDATASET == "cifar10":
        mean = (0.4914, 0.4822, 0.4465)
        std = (0.2023, 0.1994, 0.2010)
        predictor = ibp.add_image_normalization(original_predictor, mean, std)
    if cBOUND_METHOD == "crown-ibp":
        predictor = ibp.crown.VerifiableModelWrapper(predictor)
    else:
        predictor = ibp.VerifiableModelWrapper(predictor)

    print(predictor)

    main()

Difficulty in reproducing Table 3 in the paper

Hi there,

Thanks for sharing the code. The technique you proposed in the paper sounds promising and the results are exciting to me! However, I have some difficulty in reproducing your results in Table 3 and I wonder if there's something wrong in my experimental setup.

It looks like the default program options in examples/train.py have already configured everything for the MNIST training procedure, except for the epsilon_train which you have presented in Table 3 separately.

I have tried all three models: small, medium and large as you didn't mention which one to use in Table 3. I have found that the large model always produced the best results. However, even the best results I have got are constantly worse than those reported in Table 3, in terms of both test error and verified error.

For the test error, the best I can get is 1.12% (over 1.06% in the paper, where eps_train=0.2) and 2.31% (over 1.66% in the paper, where eps_train=0.4).

For the verified error, the best results I have produced are [2.93%, 5.60%, 9.24%, 16.69%] respectively for the epsilon values 0.1, 0.2, 0.3, 0.4, which is always slightly worse than the reported results in Table 3: [2.23%, 4.48%, 8.05%, 14.88%].

Could you please advise me on how to correctly reproduce your results? I believe an exact verifier may help to narrow the gap for the verified error, but it won't help to reduce the test error.

BTW, I used your initial commit version 15340d3 for the experiment. I don't know if the latest commit 5fa09e7 of yesterday will change the results.

Best,
-Weilin

problem about environment setting

I have meet this problem.
SystemError: Sonnet requires tensorflow_probability (minimum version 0.4.0) to be installed. If using pip, run pip install tensorflow-probability or pip install tensorflow-probability-gpu
but,I have installed tensorflow-probability with version 0.6.0

Installation requirments are not provived explicitely in readme!

I am confused whether this requires Python2 or Python3. Also, installation goes without error but the test is throwing multiple errors. So it is not clear to me if I have installed it correctly. One of the things I want to check is what versions of dependency I am using but it is not mentioned explicitly (though setup.py has some info).

Dependency versions

Could you provide a list of dependencies, together with their respective versions, that allows for the code to run?
I've tried countless combinations of versions of tensorflow, tensorflow-probability and dm-sonnet and always end up with some import error.
Usually either:

AttributeError: module 'tensorflow.python.ops.linalg.linear_operator_util' has no attribute 'matmul_with_broadcast' in tensorflow-probability

or AttributeError: module 'tensorflow.compat.v1' has no attribute 'nest' in attacks.py

Different epsilon on different dimension?

Hi,

I am trying to create an input interval which has different epsilon on different dimensions.

For example, I want to have an interval representation, $x$, with x.center = [0.2, 0.0, 0.4, 0.0], x.width = [0.1, 0.0, 0.0, 0.8]. Is there a way to wrap this tensor representation with an existing function?

Thanks,
Chenxi

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.