Roku
Roku

Reputation: 11

Tensorflow GradientTape Error "inside its context is signficantly less efficient than calling it outside the context"?

I am currently working on Adversarial Attacks on Image dataset. The most important libraries in my project are :

With certains attacks, like DeepFool, Elastic Net (EAD) for examples, I got this error :

WARNING:tensorflow: Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.

And here is my code :

import torch
import tensorflow as tf
import numpy as np

from tensorflow.keras.preprocessing.image import load_img, img_to_array
from tensorflow.keras.applications.inception_v3 import InceptionV3

from art.attacks.evasion import FastGradientMethod, BasicIterativeMethod, CarliniL2Method, CarliniLInfMethod, \
    ProjectedGradientDescent, DeepFool, ThresholdAttack, PixelAttack, SpatialTransformation, SquareAttack, ZooAttack, \
    BoundaryAttack, HopSkipJump, SaliencyMapMethod, SimBA, AutoProjectedGradientDescent, HopSkipJump, ElasticNet

from art.estimators.classification import TensorFlowV2Classifier


for i, image_path in enumerate(imagenet_stubs.get_image_paths()):
    im = tf.keras.preprocessing.image.load_img(image_path, target_size=(299, 299))
    im = tf.keras.preprocessing.image.img_to_array(im)
    if 'tractor.jpg' in image_path:
        x = np.array(im)
x = (np.expand_dims(x, axis=0) / 255.0).astype(np.float32)
y = np.array([name_to_label("tractor")])

model = InceptionV3(include_top=True, weights='imagenet', classifier_activation='softmax')
loss = tf.keras.losses.CategoricalCrossentropy(from_logits=False)

classifier = TensorFlowV2Classifier(model=model,
                                    nb_classes=nb_classes,
                                    loss_object=loss,
                                    preprocessing=preprocessing,
                                    preprocessing_defences=None,
                                    clip_values=clip_values,
                                    input_shape=input_shape)

# DeepFool is an Untargeted Attack ONLY
attack = DeepFool(classifier=classifier,
                  epsilon=0.02,
                  max_iter=100,
                 )

# Generate adversarial examples (DeepFool is untargeted only)
x_adv = attack.generate(x=x) # UNTARGETED ATTACK

It's not an error, I know that the code is compiling. But it's SO LONG. With DeepFool, I can wait 20 minutes, but with EAD for example, after 2h, no results appearing. Always loading.

Summary:
I tried to generate adversarial attacks, (DeepFool / EAD), but instead of having a quick attack on one picture, I got a GradientTape error, which results that the code is compiling for a few hours before getting some results, which is way too long.
How can I resolve this WARNING to be able to generate this attack quickly?

Upvotes: 1

Views: 24

Answers (1)

Roku
Roku

Reputation: 11

if you met the same problem as me, I have found a solution. Please find below some explaination. and the code needed to solve this problem.

This error :

WARNING:tensorflow:Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.

appears because by default, TensorFlow try to keep in memory the GradientTape as long as it can. But in some case, for example in some complex Adversarials Attacks, it's not good because it costs too much ressources to our computer.

So firstly, we can free the memory used by tensorflow at the start of our code:

import gc
import tensorflow as tf

gc.collect()
tf.keras.backend.clear_session()

It will avoid memory accumulation through different sessions.

Then, add this line to avoid that TensorFlow stock too much operation in the GradientTape (not mandatory):

tf.config.run_functions_eagerly(False)

Finally, because GradientTape(persistent=True) by default on the source code, and it's preferrable to not touch the source code of the tensorflow library, we will create our own GradientTape, using this code:

import tensorflow as tf

# Create another version of GradientTape without persistent=True
class CustomGradientTape(tf.GradientTape):
    def __init__(self, persistent=False, *args, **kwargs):
        super().__init__(persistent=persistent, *args, **kwargs)

# Replace the GradientTape by our Custom Version
tf.GradientTape = CustomGradientTape

Now, the parameter persistent is equal to False.

It works for me. So I hope it will works for you. Sincerely, Roku.

Upvotes: 0

Related Questions