FGSM: 'tuple' object has no attribute 'log_softmax'

I am testing an fgsm function i a trained modell.
When I call the function I get the following error:

'tuple' object has no attribute 'log_softmax'

I hope that you can guide me to fix the problem.

Here the entire code:

# Define the transformations.
data_transforms = transforms.Compose([
    transforms.Resize([112, 112]),
    transforms.ToTensor()
    ])

# Defining hyperparameters
BATCH_SIZE = 256
learning_rate = 0.001
EPOCHS = 15
numClasses = 43

# Define path of training data

train_data_path = "../GTSRB/Train"
train_data = torchvision.datasets.ImageFolder(root = train_data_path, transform = data_transforms)

test_data_path = "../GTSRB/Test"
test_data = torchvision.datasets.ImageFolder(root = test_data_path, transform = data_transforms)

# Divide data into training and validation (0.8 and 0.2)
ratio = 0.8
n_train_examples = int(len(train_data) * ratio)
n_val_examples = len(train_data) - n_train_examples

train_data, val_data = data.random_split(train_data, [n_train_examples, n_val_examples])

# Create data loader for training and validation

train_loader = data.DataLoader(train_data, shuffle=True, batch_size = BATCH_SIZE)
val_loader = data.DataLoader(val_data, shuffle=True, batch_size = BATCH_SIZE)
test_loader = data.DataLoader(test_data, shuffle=False, batch_size = BATCH_SIZE)

# Initialize the model
# The model is defined in the class AlexnetTS in the file class_alexnetTS.py

from class_alexnetTS import AlexnetTS
model = AlexnetTS(numClasses)

# If CUDA is available, convert model and loss to cuda variables

if torch.cuda.is_available():
    model = model.cuda()
    criterion = criterion.cuda()

# Function to calculate accuracy

def calculate_accuracy(y_pred, y):
    top_pred = y_pred.argmax(1, keepdim = True)
    correct = top_pred.eq(y.view_as(top_pred)).sum()
    acc = correct.float() / y.shape[0]
    return acc

# Function to perform training of the model

def train(model, loader, opt, criterion):
    epoch_loss = 0
    epoch_acc = 0
    
    # Train the model
    model.train()
    
    for (images, labels) in loader:
        images = images.cuda()
        labels = labels.cuda()
        
        # Training pass
        opt.zero_grad()
        
        output, _ = model(images)
        loss = criterion(output, labels)
        
        # Backpropagation
        loss.backward()
        
        # Calculate accuracy
        acc = calculate_accuracy(output, labels)
        
        # Optimizing weights
        opt.step()
        
        epoch_loss += loss.item()
        epoch_acc += acc.item()
        
    return epoch_loss / len(loader), epoch_acc / len(loader)

# Function to perform evaluation on the trained model

def evaluate(model, loader, opt, criterion):
    epoch_loss = 0
    epoch_acc = 0
    
    # Evaluate the model
    model.eval()
    
    with torch.no_grad():
        for (images, labels) in loader:
            images = images.cuda()
            labels = labels.cuda()
            
            # Run predictions
            output, _ = model(images)
            loss = criterion(output, labels)
            
            # Calculate accuracy
            acc = calculate_accuracy(output, labels)
            
            epoch_loss += loss.item()
            epoch_acc += acc.item()
    
    return epoch_loss / len(loader), epoch_acc / len(loader)

# Perform training

# List to save training and val loss and accuracies
train_loss_list = [0]*EPOCHS
train_acc_list = [0]*EPOCHS
val_loss_list = [0]*EPOCHS
val_acc_list = [0]*EPOCHS

for epoch in range(EPOCHS):
    print("Epoch-%d: " % (epoch))

    train_start_time = time.monotonic()
    train_loss, train_acc = train(model, train_loader, optimizer, criterion)
    train_end_time = time.monotonic()

    val_start_time = time.monotonic()
    val_loss, val_acc = evaluate(model, val_loader, optimizer, criterion)
    val_end_time = time.monotonic()
    
    train_loss_list[epoch] = train_loss
    train_acc_list[epoch] = train_acc
    val_loss_list[epoch] = val_loss
    val_acc_list[epoch] = val_acc

# Load the model
model.load_state_dict(torch.load(PATH_TO_MODEL))

# FGSM
def fgsm(model, X, y, epsilon):
    """ Construct FGSM adversarial examples on the examples X"""
    delta = torch.zeros_like(X, requires_grad=True)
    loss = nn.CrossEntropyLoss()(model(X + delta), y)
    loss.backward()
    return epsilon * delta.grad.detach().sign()

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

for X,y in test_loader:
    X,y = X.to(device), y.to(device)
    break
    
def plot_images(X,y,yp,M,N):
    f,ax = plt.subplots(M,N, sharex=True, sharey=True, figsize=(N,M*1.3))
    for i in range(M):
        for j in range(N):
            ax[i][j].imshow(1-X[i*N+j][0].cpu().numpy(), cmap="gray")
            plt.setp("",color=('r'))
            ax[i][j].set_axis_off()
    plt.tight_layout()

### Illustrate original predictions
yp = model(X)
plot_images(X, y, yp, 3, 6)

### Illustrate attacked images
delta = fgsm(model, X, y, 0.1)
yp = model(X + delta)
plot_images(X+delta, y, yp, 3, 6)

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-81-f7858e70b6bd> in <module>
      4 
      5 ### Illustrate attacked images
----> 6 delta = fgsm(model, X, y, 0.1)
      7 yp = model(X + delta)
      8 plot_images(X+delta, y, yp, 3, 6)

<ipython-input-79-118c481d1e37> in fgsm(model, X, y, epsilon)
      2     """ Construct FGSM adversarial examples on the examples X"""
      3     delta = torch.zeros_like(X, requires_grad=True)
----> 4     loss = nn.CrossEntropyLoss()(model(X + delta), y)
      5     loss.backward()
      6     return epsilon * delta.grad.detach().sign()

~\anaconda3\envs\lab01\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
    887             result = self._slow_forward(*input, **kwargs)
    888         else:
--> 889             result = self.forward(*input, **kwargs)
    890         for hook in itertools.chain(
    891                 _global_forward_hooks.values(),

~\anaconda3\envs\lab01\lib\site-packages\torch\nn\modules\loss.py in forward(self, input, target)
   1046         assert self.weight is None or isinstance(self.weight, Tensor)
   1047         return F.cross_entropy(input, target, weight=self.weight,
-> 1048                                ignore_index=self.ignore_index, reduction=self.reduction)
   1049 
   1050 

~\anaconda3\envs\lab01\lib\site-packages\torch\nn\functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce, reduction)
   2691     if size_average is not None or reduce is not None:
   2692         reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 2693     return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
   2694 
   2695 

~\anaconda3\envs\lab01\lib\site-packages\torch\nn\functional.py in log_softmax(input, dim, _stacklevel, dtype)
   1670         dim = _get_softmax_dim("log_softmax", input.dim(), _stacklevel)
   1671     if dtype is None:
-> 1672         ret = input.log_softmax(dim)
   1673     else:
   1674         ret = input.log_softmax(dim, dtype=dtype)

AttributeError: 'tuple' object has no attribute 'log_softmax'

Hi,

In the quoted part, I would check what’s the return value of model(x + delta), and I guess model(x+delta) returns a tuple of Tensors.

Therefore, I’d reference the implementation of AlexnetTS.forward.

The model looks like:

print(model)

AlexnetTS(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
    (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (2): ReLU(inplace=True)
    (3): Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): ReLU(inplace=True)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (12): ReLU(inplace=True)
  )
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=12544, out_features=1000, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=1000, out_features=256, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=256, out_features=43, bias=True)
  )
)

Therefore, I’d reference the implementation of AlexnetTS.forward .

Do you mean that there is another implementation of Alexnet with the name AlexnetTS.forward?

No, I don’t think so.

But, I’d first check

as model(X + delta) might return a tuple.


x = torch.randn(4, 1)
y = torch.randn(4, 1)

nn.CrossEntropyLoss()((x, x), y)

The above snippet raises an error as follows.

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-21-5f2ffb16d2b6> in <module>()
      2 y = torch.randn(4, 1)
      3 
----> 4 nn.CrossEntropyLoss()((x, x), y)

3 frames
/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py in log_softmax(input, dim, _stacklevel, dtype)
   1670         dim = _get_softmax_dim("log_softmax", input.dim(), _stacklevel)
   1671     if dtype is None:
-> 1672         ret = input.log_softmax(dim)
   1673     else:
   1674         ret = input.log_softmax(dim, dtype=dtype)

AttributeError: 'tuple' object has no attribute 'log_softmax'