C&W L2 attack - Save adversarial examples as images - python

Once again I need your help.
I recently dipped into the realm of Machine Learning and read quite a few papers that got me curious :)
Now I wanted to recreate/execute the C&W L2 attack. I cloned the whole repo of Nicholas Carlini https://github.com/carlini/nn_robust_attacks and started training a network with the train_models.py - only MNIST, to speed things up a bit.
Next, I executed the 'test_attack.py'. I modified the output a bit so it made a bit more sense for me (like, showing the predicted class of the adversarial example), but now I am struggling a bit.
Instead of, or additionally to, having the adversarial example be shown in the console, I want to save it to a .png/.jpg file. I messed around quite a bit, but only got as far as getting a 28x28 black .png file.
My "modified" file looks like this right now:
import tensorflow as tf
import numpy as np
import time
from PIL import Image
from setup_cifar import CIFAR, CIFARModel
from setup_mnist import MNIST, MNISTModel
from setup_inception import ImageNet, InceptionModel
from l2_attack import CarliniL2
def show(img):
"""
Show MNSIT digits in the console.
"""
remap = " .*#"+"#"*100
print(type(img))
img2 = img.reshape((28,28)).astype('uint8')*255
img2 = Image.fromarray(img2)
img2.save('test.png')
img = (img.flatten()+.5)*3
if len(img) != 784: return
print("START")
for i in range(28):
print("".join([remap[int(round(x))] for x in img[i*28:i*28+28]]))
def generate_data(data, samples, targeted=True, start=0, inception=False):
"""
Generate the input data to the attack algorithm.
data: the images to attack
samples: number of samples to use
targeted: if true, construct targeted attacks, otherwise untargeted attacks
start: offset into data to use
inception: if targeted and inception, randomly sample 100 targets intead of 1000
"""
inputs = []
targets = []
for i in range(samples):
if targeted:
if inception:
seq = random.sample(range(1,1001), 10)
else:
#seq = range(2)
seq = range(data.test_labels.shape[1])
print(seq)
for j in seq:
if (j == np.argmax(data.test_labels[start+i])) and (inception == False):
continue
inputs.append(data.test_data[start+i])
targets.append(np.eye(data.test_labels.shape[1])[j])
else:
inputs.append(data.test_data[start+i])
targets.append(data.test_labels[start+i])
inputs = np.array(inputs)
targets = np.array(targets)
return inputs, targets
if __name__ == "__main__":
with tf.Session() as sess:
data, model = MNIST(), MNISTModel("models/mnist", sess)
attack = CarliniL2(sess, model, batch_size=9, max_iterations=1000, confidence=1)
inputs, targets = generate_data(data, samples=1, targeted=True,
start=0, inception=False)
timestart = time.time()
adv = attack.attack(inputs, targets)
timeend = time.time()
print("Took",timeend-timestart,"seconds to run",len(inputs),"samples.")
for i in range(len(adv)):
print(len(adv))
print("Valid:")
show(inputs[i])
print("Adversarial:")
show(adv[i])
pred = model.model.predict(inputs[i:i+1])
print("Classification (orig):", pred)
print("Prediction class original:", np.argmax(pred))
advpred = model.model.predict(adv[i:i+1])
print("Classification:", model.model.predict(adv[i:i+1]))
print("Adversarial example classification: ", np.argmax(advpred))
print("Total distortion:", np.sum((adv[i]-inputs[i])**2)**.5)
My questions would be:
Is there a way to get the images saved as .png files?
What exactly is the total distortion? It does not seem to be a % number. Like, I thought this would tell me how many pixels had to be changed, but I guess I am totally wrong here.
By default, it is always the image of a "7" that gets attacked. I have not figured out so far, how to choose by myself which number to create adversarial images for. Also, it does, by default, create an adversarial example for every class (like, one image of a 7 that gets classified as 0, another one for the 1,2,3 etc. - Is there a way I can specify the target class exactly? To only get one adversarial example, say a 7 that gets classified as a 9? Now I think that is something super simple I just dont see...
Since I would love to try this with CIFAR10 too (just takes ages to train on my super old Laptop, so thats gonna be an overnight action) - will there be a way to save the CIFAR adversarial examples to .img/.png too? Because as far as I can tell, the "show" function only covers the MNIST set?
Sorry if those are pretty basic questions, but I am super new to ML and not as experienced in Python as I would like to be! I googled quite a lot, but havent seen anyone who has implemented the attack with the original source code and did what I want to do.
Thank you very much in advance, I know its a lot to ask for!

To save a png file with Pillow, you have to specify the format as a second parameter:
img2.save('test.png', 'PNG')
You could also save files with matplotlib
import matplotlib.pyplot as plt
plt.imsave("test.png", np.array(img2))
I am not super familiar with the C&W attack, but after looking at their paper Towards Evaluating the Robustness
of Neural Networks and the code for the attack in l2_attack.py, it appears that the perturbation is bounded by the boxmin and boxmax parameters, and that the attack itself gradually changes the images and then selects the ones that are the most effective. It won't tell you how many pixels are changed because that is usually a hyperparameter that you decide for yourself.
To change the image attacked, change the inputs and targets in the attack initialization function:
adv = attack.attack(inputs, targets)
You will also want to load your desired data instead of MNIST beforehand. There are good tutorials online for this. Just search "Tensorflow" and "dataloading"
To make the show function compatible with CIFAR, change stuff like (28, 28) to (32,32,3), as CIFAR images are 32x32 color images. You'll also need to change the length accordingly. Alternatively, it might be easier to write your own show function based on whatever data you're using.

Related

keras custom metric for path planning neural network doesnt work

Firstly some info about the background of the problem. I am building an artificial neural network solving an AGV path planning problem. The input of the network is a 15x15 grid terrain of 0,1 , meaning that 0 is empty space for the robot to go and 1 is an obstacle. There are 5 fixed destinations for all samples. The only thing changing is the terrain. My output is path between the start and destinations. I want to use a custom metric that measures how many obstacles are being hit and evaluate the produced path. Below is the code. I have already made an obs list in which, obs[0][sample_index]->obstacles of the train_sample[index] and obs[1][sample_index]->obstacles of the test_sample[index]. However the after the compile the model doesnt fit. Can someone explain to me what is the problem with the custom metric?
def index(y):
if y in y_train:
a=y_train.index(y)
elif y in y_test:
a=y_test.index(y)
return a
def custom_metric(y_true, y_pred):
ind=index(y_true)
obs_in_ypred=0
if y_true in y_train:
for i in range(0,len(y_pred),2):
if y_pred[i]*15+y_pred[i+1] in obs[0][ind]:
obs_in_ypred=obs_in_ypred+1
elif y_true in y_test:
for i in range(0,len(y_pred),2):
if y_pred[i]*15+y_pred[i+1] in obs[1][ind]:
obs_in_ypred=obs_in_ypred+1
metric1=1-obs_in_ypred/(len(obs[0][ind]))
metric2=1-obs_in_ypred/(len(obs[1][ind]))
return tf.keras.backend.in_train_phase(metric1,metric2)
you can't have if statement inside you loss function, the if has no gradient, just think about what's the derivative of if, i'm also fairly sure the for is no good either.
If the output is a path consider reproducing this path on a 2D tensor ( where maybe cells put to 1 give the path)

How to make custom callback in keras to generate sample image in VAE training?

I'm training a simple VAE model on 64*64 images and I would like to see the images generated after every epoch or every couple batches to see the progress.
when I train the model I wait until the training is done and then I look at the results.
I tried to make a custom callback function in Keras that generates an image and saves it but couldn't do it. is it even possible? I couldn't find anything like it.
it would be awesome if you refer me to a source that explains how to do so or show me an example.
Note: I'm interested in a clean Keras.callback solution and not to iterate over every epoch, train and generate the sample
If you still need it, you can define custom callback in keras as a subclass of keras.callbacks.Callback:
class CustomCallback(keras.callbacks.Callback):
def __init__(self, save_path, VAE):
self.save_path = save_path
self.VAE = VAE
def on_epoch_end(self, epoch, logs={}):
#load the image
#get latent_space with self.VAE.encoder.predict(image)
#get reconstructed image wtih self.VAE.decoder.predict(latent_space)
#plot reconstructed image with matplotlib.pyplot
Then define callback as image_callback = CustomCallback(...)
and place image_callback in the list of callbacks
Yeah its actually possible, but i always use matplotlib and a self-defined function for that. For example something like that.
for steps in range (epochs):
Train,Test = YourDataGenerator() # load your images for one loop
model.fit(Train,Test,batch_size= ...)
result = model.predict(Test_image)
plt.imshow(result[0,:,:,:]) # keras always returns [batch.nr,heigth,width,channels]
filename1 = '/content/runde2/%s_generated_plot_%06d.png' % (test, (steps+1))
plt.savefig(filename1 )
plt.close()
I think there is also a clean keras.callback version, but i always used this approach because you can use other libraries for easier data augmentation per loop. But thats just my opinion, hope i could help you at least a bit.

Tensorflow - Training on condition

I am training a neural network with tensorflow (1.12) in a supervised fashion. I'd like to only train on specific examples. The examples are created on the fly by cutting out subsequences, hence I want to do the conditioning within tensorflow.
This is my original part of code:
train_step, gvs = minimize_clipped(optimizer, loss,
clip_value=FLAGS.gradient_clip,
return_gvs=True)
gradients = [g for (g,v) in gvs]
gradient_norm = tf.global_norm(gradients)
tf.summary.scalar('gradients/norm', gradient_norm)
eval_losses = {'loss1': loss1,
'loss2': loss2}
The training step is later executed as:
batch_eval, _ = sess.run([eval_losses, train_step])
I was thinking about inserting something like
train_step_fake = ????
eval_losses_fake = tf.zeros_like(tensor)
train_step_new = tf.cond(my_cond, train_step, train_step_fake)
eval_losses_new = tf.cond(my_cond, eval_losses, eval_losses_fake)
and then doing
batch_eval, _ = sess.run([eval_losses, train_step])
However, I am not sure how to create a fake train_step.
Also, is this a good idea in general or is there a smoother way of doing this? I am using a tfrecords pipeline, but no other high-level modules (like keras, tf.estimator, eager execution etc.).
Any help is obviously greatly appreciated!
Answering the specific question first. It's certainly possible to only perform your training step based on the tf.cond outcome. Note that the 2nd and 3rd params are lambdas though so more something like:
train_step_new = tf.cond(my_cond, lambda: train_step, lambda: train_step_fake)
eval_losses_new = tf.cond(my_cond, lambda: eval_losses, lambda: eval_losses_fake)
Your instinct that this may not be the right thing to do is correct though.
It's much more preferable (both in terms of efficiency and in terms of reading and reasoning about your code) to filter out the data you want to ignore before it gets to your model in the first place.
This is something you could achieve using the Dataset API. which has a really useful filter() method you could use. If you are using the dataset api to read your TFRecords right now then this should be as simple as adding something along the lines of:
dataset = dataset.filter(lambda x: {whatever op you were going to use in tf.cond})
If you are not yet using the dataset API, now is probably the time to have a little read up on it and consider it rather than butchering the model with that tf.cond() to act as a filter.

Python generator with Keras underperforming

I was trying to do a simple image classification exercise using CNN and Keras.
I have a list that stores the directions of the images (train_glob) and another list with the corresponding classification labels one hot encoded (dummy_y).
The function load_one() takes as arguments a path and some parameters for image resizing and augmentation and returns a transformed image as a numpy array.
When I run the code in batch mode though .fit(), creating a single file holding all the images called batch_features I achieved after 5 epochs a decent accuracy of 0.7.
The problem appears when I try to replicate the results using a python generator to feed the data and train using .fit_generator(), the performance results are really poor when in fact I would expected them to be slightly better since, to my understanding, more data is being fed.
Unlike the batch function, in the generator y am randomly altering the brightness of the images and looping more times over the data, so in theory If I understand correctly how the generator works I would expect the results to be better.
This is my generator function
def generate_arrays_from_file(paths,cat_list, batch_size = 128):
number = 0
max_len = len(paths)
while True:
batch_features = np.zeros((batch_size, 128, 64, 3),np.uint8)
batch_labels = np.zeros((batch_size,cat_list.shape[1]),np.uint8)
for i in range(number*batch_size, number*batch_size + batch_size):
#choose random index in features
#index= np.random.choice(len(paths))
batch_features[i % batch_size] = load_one(paths[i], final_size=(64,128), augment = True)
batch_labels[i % batch_size] = cat_list[i]
batch_features = normalize_data(batch_features)
yield batch_features, batch_labels
number += 1
if number*batch_size + batch_size > max_len:
number = 0
An this is the keras call to the generator
mod.fit_generator(generate_arrays_from_file(train_glob, dummy_y, 256),
samples_per_epoch=16368, nb_epoch=10)
Is this the right way of passing a generator?
Thanks
To match your accuracy you want to feed in the same data. Since you do some transformations on the images that you didn't do without the generator, it is normal for your accuracy not to match.
If you think the generator is the problem, you can test it out quite easily.
Fire up a python shell, import your package, make a generator and get a few samples to see if they're what you expected.
# say you save the generator in mygenerator.py
$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mygenerator
# initialise paths, cat_list here:
>>> paths = [...]
>>> cat_list = [...]
# use a small batch_size to be able to see the results
>>> g = mygenerator.generate_arrays_from_file(paths, cat_list, batch_size = 2)
>>> batch = g.__next__()
# now check if batch is what you expect
To save an image or display it (from this tutorial):
# Save:
from scipy import misc
misc.imsave('face.png', image_array) # uses the Image module (PIL)
# Display:
import matplotlib.pyplot as plt
plt.imshow(image_array)
plt.show()
More about accuracy and data augmentation
If you test the two models (one trained with the generator and one with the whole data preloaded) on different datasets the accuracies will clearly be different. Try to use the exact same test and train data for both models, turn off augmentation completely and you should see similar accuracies (for the same number of epochs, batch_sizes, etc). If you don't use the method above to fix the generator.
If there are only few data points the model will overfit (thus have high training accuracy) very quickly. Data augmentation helps reduce overfitting and makes models generalise better. This also means that the accuracy on training after very few epochs will be lower as the data is more varied.
Please note it is very easy to get image processing (data augmentation) things wrong and not realise it. Crop it wrongly, you get a black image. Zoom too much you only get noise. Confuse x and y and you get a totally wrong image. And so on... Test your generator to see if the images it outputs are what you expect and that the labels match.
On brightness. If you alter the brightness on the input images you make your model agnostic to brightness. You don't improve the generalisation on other things like rotations and zoom. Make sure you do not overdo the brightness changes: do not make your images fully white or fully black - if this happens it will explain the huge drop in accuracy.
As pointed in the comments by VMRuiz, if you have categorical data (which you do), use keras.preprocessing.image.ImageDataGenerator (docs). It will save you a lot of time. A very good example on Keras blog (code here). If you are interested in your own image processing have a look at the ImageDataGenerator source code.

TensorFlow: Node not found

I am training a neural network and have been running this code without any problems but sometimes (twice) I get an error Not Found: FetchOutputs node not found at the line y_1 = sess.run(get_labels(step)) (See below).
get_labels(step) is a function to return the correct labels of my training images which is in a text file.
def get_labels(step):
with open('labels.txt','r') as fin:
reader = csv.reader(fin)
c = [[int(s) for s in row] for i,row in enumerate(reader) if i==step]
label_numbers = np.array(c)
# Convert to one-hot vectors
numpy_label = np.zeros((BATCH_SIZE,5))
for i in range(BATCH_SIZE):
numpy_label[i,label_numbers[0][i]-1] = 1
# Convert to tensor
y_label = tf.convert_to_tensor(numpy_label,dtype=tf.float32)
return y_label
This is my main function:
def main():
# Placeholder for correct labels
y_label = tf.placeholder(tf.float32,shape=[BATCH_SIZE,5])
< Other functions etc. >
sess.run(tf.initialize_all_variables())
tf.train.start_queue_runners(sess=sess)
for step in range(1000):
# Get labels for current batch
y_1 = sess.run(get_labels(step))
# Train
sess.run([train_step],feed_dict={y_label:y_1})
< Other stuff like writing summaries, saving variables etc. >
sess.close()
From reading some of the issues on GitHub, I know this is to do with the fact that I call y_1 = sess.run(get_labels(step)) after tf.train.start_queue_runners(sess=sess) but I don't understand:
why it works most of the time, but occasionally doesn't?
Is y_1 = sess.run(get_labels(step)) adding or modifying nodes in the graph? I thought I was just running a node get_labels(step) that was already defined in the graph. I tried finalizing the graph before starting the queue runners but that gave me the error that finalized graphs cannot be modified.
What would be the proper way to write the code? Usually I just restart my program and it is fine - but clearly I am not doing it the proper way.
Thank you!
EDIT:
I think it might be important to mention that this happens when I am trying to run a TensorFlow script in a separate screen on a server i.e. I have one screen running a TensorFlow script and now I create a new screen to run a different TensorFlow script. I just started using screens so I might be missing something fundamental about how they work.

Categories

Resources