BorealisAI / advertorch

A Toolbox for Adversarial Robustness Research
GNU Lesser General Public License v3.0
1.31k stars 198 forks source link

could i produce ensemble attacks using this code? #17

Closed codingwolfman closed 5 years ago

codingwolfman commented 5 years ago

the parameter of attack is like MomentumIterativeAttack(model,F.nll_loss),could i pass a list of model to this???

gwding commented 5 years ago

Hi, yeah it is possible, you'll need define a ensemble_predict function like this and pass it to the adversary's predict

def ensemble_predict(data):
    return model_1(data) + model_2(data) + model_3(data)

here I assume model_i (data) outputs the logits (layer before softmax)

Is this something that you're looking for? @codingwolfman

codingwolfman commented 5 years ago

@gwding yeah, i see, thanks a lot

codingwolfman commented 5 years ago

@gwding when i try to use ensemble attack , i meet this error, RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

i can't understand this, i think i just backward through the graph once, my code is as follows class EnsembleModel(torch.nn.Module): def init(self,models): super(EnsembleModel,self).init() self.models = models self.out = torch.zeros((1,110)).to('cuda:0') def forward(self, x): for model in self.models: self.out += model(x) return self.out/len(self.models)

def generate_data(models, device, test_loader):

# Accuracy counter
correct = 0
init_correct = 0
widgets = ['test:',Percentage(), ' ', Bar('#'),' ', Timer(),
       ' ', ETA(), ' ', FileTransferSpeed()]
pbar = ProgressBar(widgets=widgets)

ensemble_model = EnsembleModel(models)
ensemble_model.to(device)
#momentums = [MomentumIterativeAttack(model,F.nll_loss) for model in models]
attack = FGSM(predict=ensemble_model,loss_fn=F.cross_entropy,clip_min=-1,clip_max=1)

#attacks = [LinfBasicIterativeAttack(model, F.nll_loss) for model in models]
# Loop over all examples in test set
for data, target, image_path in pbar(test_loader):

    # Send the data and label to the device
    data, target = data.to(device), target.to(device)

    # Set requires_grad attribute of tensor. Important for Attack
    data.requires_grad = True

    # Forward pass the data through the model
    output = ensemble_model(data)

    init_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability

    image_path = image_path[0].replace('/origin_examples/', '/ifgsm_incepv3_incepv1_data/')
    _dir, filename = os.path.split(image_path)
    if not os.path.exists(_dir):
        os.makedirs(_dir)

    if init_pred.item() != target.item():
        perturbed_data = data
    else:
        init_correct += 1
        perturbed_data = attack.perturb(data,target)
        image = Image.fromarray(np.uint8((perturbed_data.squeeze().detach().cpu().numpy() * 0.5 + 0.5) * 255).transpose((1, 2, 0)))
        image.save(image_path)
    output = ensemble_model(perturbed_data)

    # Check for success
    final_pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
    if final_pred.item() == target.item():
        correct += 1

# Calculate final accuracy for this epsilon
final_acc = correct/float(len(test_loader))
origin_acc = init_correct/float(len(test_loader))
print("Test Accuracy = {} / {} = {}".format(correct, len(test_loader), final_acc))
print("Origin Accuracy = {} / {} = {}".format(init_correct, len(test_loader), origin_acc))
gwding commented 5 years ago

@codingwolfman it looks ok for me, unless you have repeated a model in models?

could you make a script that I can directly run and reproduce the error? (doesn't involve loading files and etc) so i can try to reproduce the problem

gwding commented 5 years ago

@codingwolfman I'm closing this issue for now. Please reopen if the problem persists.