Skip to content

Commit

Permalink
refactor: rename transform to normalize in attacks, reorder args
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerwooo committed Jan 20, 2024
1 parent b00f19c commit a9d1d57
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 68 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "torchattack"
version = "0.2.2"
version = "0.3.0"
description = "A set of adversarial attacks implemented in PyTorch"
authors = [{ name = "spencerwooo", email = "[email protected]" }]
requires-python = ">=3.10,<3.12"
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/admix.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Admix(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
steps: int = 10,
alpha: float | None = None,
Expand All @@ -33,7 +33,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: The maximum perturbation. Defaults to 8/255.
steps: Number of steps. Defaults to 10.
alpha: Step size, `eps / steps` if None. Defaults to None.
Expand All @@ -47,7 +47,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand Down Expand Up @@ -91,7 +91,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
x_admixs = torch.cat([x_admix * scale for scale in scales])

# Compute loss
outs = self.model(self.transform(x_admixs))
outs = self.model(self.normalize(x_admixs))

# One-hot encode labels for all admixed images
one_hot = nn.functional.one_hot(y, self.num_classes)
Expand Down
11 changes: 6 additions & 5 deletions src/torchattack/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ class Attack(ABC):

def __init__(
self,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
device: torch.device | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
) -> None:
super().__init__()
# If transform is None, use identity transform.
self.transform = transform if transform else lambda x: x

# Set device to given or defaults to cuda if available.
# Set device to given or defaults to cuda if available
is_cuda = torch.cuda.is_available()
self.device = device if device else torch.device('cuda' if is_cuda else 'cpu')

# If normalize is None, use identity function
self.normalize = normalize if normalize else lambda x: x

def __call__(self, *args: Any, **kwds: Any) -> Any:
return self.forward(*args, **kwds)

Expand All @@ -29,7 +30,7 @@ def __repr__(self) -> str:
def repr_map(k, v):
if isinstance(v, float):
return f'{k}={v:.3f}'
if k in ['model', 'transform']:
if k in ['model', 'normalize']:
return f'{k}={v.__class__.__name__}'
if isinstance(v, torch.Tensor):
return f'{k}={v.shape}'
Expand Down
15 changes: 7 additions & 8 deletions src/torchattack/dataset.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import csv
from typing import Callable
from typing import Any, Callable

import numpy as np
import torch
from PIL import Image
from torch.utils.data import DataLoader, Dataset
Expand Down Expand Up @@ -38,7 +37,7 @@ def __init__(
Args:
image_root: Path to the folder containing the images.
pairs_path: Path to the csv file containing the image names and labels.
transform: An optional transform to apply to the images. Defaults to None.
normalize: An optional transform to apply to the images. Defaults to None.
max_samples: Maximum number of samples to load. Defaults to None.
"""

Expand Down Expand Up @@ -70,13 +69,13 @@ def __init__(
def __len__(self) -> int:
return len(self.labels)

def __getitem__(self, index: int) -> tuple[torch.Tensor, int, str]:
def __getitem__(self, index: int) -> tuple[Any, int, str]:
name = self.names[index]
label = int(self.labels[index]) - 1

image = Image.open(f'{self.image_root}/{name}.png').convert('RGB')
image = np.array(image, dtype=np.uint8)
image = torch.from_numpy(image).permute((2, 0, 1)).contiguous().float().div(255)
# image = np.array(image, dtype=np.uint8)
# image = torch.from_numpy(image).permute((2, 0, 1)).contiguous().float().div(255)
image = self.transform(image) if self.transform else image
return image, label, name

Expand Down Expand Up @@ -108,7 +107,7 @@ def __init__(
batch_size: int = 1,
shuffle: bool = False,
num_workers: int = 4,
transform: Callable[[torch.Tensor], torch.Tensor] | None = None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None = None,
max_samples: int | None = None,
):
# Specifing a custom image root directory is useful when evaluating
Expand All @@ -118,7 +117,7 @@ def __init__(
dataset=NIPSDataset(
image_root=image_root if image_root else f'{path}/images',
pairs_path=pairs_path if pairs_path else f'{path}/images.csv',
transform=transform,
transform=normalize,
max_samples=max_samples,
),
batch_size=batch_size,
Expand Down
10 changes: 5 additions & 5 deletions src/torchattack/deepfool.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class DeepFool(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
steps: int = 100,
overshoot: float = 0.02,
num_classes: int = 10,
Expand All @@ -28,7 +28,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
steps: Number of steps. Defaults to 100.
overshoot: Overshoot parameter for noise control. Defaults to 0.02.
num_classes: Number of classes to consider. Defaults to 10.
Expand All @@ -37,7 +37,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.steps = steps
Expand All @@ -58,7 +58,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
"""

x.requires_grad_()
logits = self.model(self.transform(x))
logits = self.model(self.normalize(x))

# Get the classes
classes = logits.argsort(axis=-1).flip(-1).detach()
Expand Down Expand Up @@ -140,7 +140,7 @@ def _get_deltas_logits(
rows = range(n)
i0 = classes[:, 0]

logits = self.model(self.transform(x))
logits = self.model(self.normalize(x))
ik = classes[:, k]
l0 = logits[rows, i0]
lk = logits[rows, ik]
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/difgsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class DIFGSM(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
steps: int = 10,
alpha: float | None = None,
Expand All @@ -39,7 +39,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: The maximum perturbation. Defaults to 8/255.
steps: Number of steps. Defaults to 10.
alpha: Step size, `eps / steps` if None. Defaults to None.
Expand All @@ -52,7 +52,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand Down Expand Up @@ -90,7 +90,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
x_adv = input_diversity(x + delta, self.resize_rate, self.diversity_prob)

# Compute loss
outs = self.model(self.transform(x_adv))
outs = self.model(self.normalize(x_adv))
loss = self.lossfn(outs, y)

if self.targeted:
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/fgsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class FGSM(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
clip_min: float = 0.0,
clip_max: float = 1.0,
Expand All @@ -27,15 +27,15 @@ def __init__(
Args:
model: A torch.nn.Module network model.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: Maximum perturbation measured by Linf. Defaults to 8/255.
clip_min: Minimum value for clipping. Defaults to 0.0.
clip_max: Maximum value for clipping. Defaults to 1.0.
targeted: Targeted attack if True. Defaults to False.
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand All @@ -59,7 +59,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
# The original implementation of FGSM is not written in this way.
delta = torch.zeros_like(x, requires_grad=True)

outs = self.model(self.transform(x + delta))
outs = self.model(self.normalize(x + delta))
loss = self.lossfn(outs, y)

if self.targeted:
Expand Down
6 changes: 3 additions & 3 deletions src/torchattack/geoda.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class GeoDA(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
input_shape: tuple = (3, 224, 224),
epsilon: int = 5,
p: str = 'l2',
Expand All @@ -109,7 +109,7 @@ def __init__(
clip_max: float = 1.0,
device: torch.device | None = None,
):
super().__init__(transform, device)
super().__init__(device, normalize)
self.model = model

self.epsilon = epsilon
Expand Down Expand Up @@ -341,7 +341,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:

def predict(self, xs: torch.Tensor) -> torch.Tensor:
xs = xs.to(self.device)
out = self.model(self.transform(xs))
out = self.model(self.normalize(xs))
return out.argmax(dim=1).detach()

def distance(
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/mifgsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class MIFGSM(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
steps: int = 10,
alpha: float | None = None,
Expand All @@ -30,7 +30,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: The maximum perturbation. Defaults to 8/255.
steps: Number of steps. Defaults to 10.
alpha: Step size, `eps / steps` if None. Defaults to None.
Expand All @@ -41,7 +41,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand Down Expand Up @@ -74,7 +74,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
# Perform MI-FGSM
for _ in range(self.steps):
# Compute loss
outs = self.model(self.transform(x + delta))
outs = self.model(self.normalize(x + delta))
loss = self.lossfn(outs, y)

if self.targeted:
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/nifgsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class NIFGSM(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
steps: int = 10,
alpha: float | None = None,
Expand All @@ -34,7 +34,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: The maximum perturbation. Defaults to 8/255.
steps: Number of steps. Defaults to 10.
alpha: Step size, `eps / steps` if None. Defaults to None.
Expand All @@ -45,7 +45,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand Down Expand Up @@ -82,7 +82,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
x_nes = x + delta + nes

# Compute loss
outs = self.model(self.transform(x_nes))
outs = self.model(self.normalize(x_nes))
loss = self.lossfn(outs, y)

if self.targeted:
Expand Down
8 changes: 4 additions & 4 deletions src/torchattack/pgd.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PGD(Attack):
def __init__(
self,
model: nn.Module,
transform: Callable[[torch.Tensor], torch.Tensor] | None,
normalize: Callable[[torch.Tensor], torch.Tensor] | None,
eps: float = 8 / 255,
steps: int = 10,
alpha: float | None = None,
Expand All @@ -30,7 +30,7 @@ def __init__(
Args:
model: The model to attack.
transform: A transform to normalize images.
normalize: A transform to normalize images.
eps: The maximum perturbation. Defaults to 8/255.
steps: Number of steps. Defaults to 10.
alpha: Step size, `eps / steps` if None. Defaults to None.
Expand All @@ -41,7 +41,7 @@ def __init__(
device: Device to use for tensors. Defaults to cuda if available.
"""

super().__init__(transform, device)
super().__init__(device, normalize)

self.model = model
self.eps = eps
Expand Down Expand Up @@ -80,7 +80,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
# Perform PGD
for _ in range(self.steps):
# Compute loss
outs = self.model(self.transform(x + delta))
outs = self.model(self.normalize(x + delta))
loss = self.lossfn(outs, y)

if self.targeted:
Expand Down
Loading

0 comments on commit a9d1d57

Please sign in to comment.