Atk Hairy Hairy Review
[ATK Hairy/Subject] has garnered attention due to [state reason for interest or significance]. This report seeks to [state purpose of report, e.g., provide an update, assess performance, or explore potential].
The most striking feature of ATK Hairy is, undoubtedly, their hair. Described as "hairy," this entity sports a luxuriant coat of hair that can vary in length, texture, and color, depending on the narrative or artistic interpretation. The hair could range from being wild and unruly to meticulously groomed and styled, adding a layer of complexity to their character. atk hairy hairy
The presence of ATK Hairy within a community or story can have various implications, reflecting broader themes or societal attitudes towards appearance, identity, and diversity. [ATK Hairy/Subject] has garnered attention due to [state
Test and evaluate the "atk_hairy_hairy" adversarial attack against an image classifier (ResNet-50), measure success rate, perturbation size, and perceptual quality. Described as "hairy," this entity sports a luxuriant
import os, torch, numpy as np
from PIL import Image
import torchvision.transforms as T
from torchvision.models import resnet50
import foolbox as fb
from foolbox.attacks import LinfPGD
from torchvision.utils import save_image
device = "cuda" if torch.cuda.is_available() else "cpu"
model = resnet50(pretrained=True).eval().to(device)
preprocess = T.Compose([T.Resize(256), T.CenterCrop(224), T.ToTensor(),
T.Normalize(mean=[0.485,0.456,0.406],
std=[0.229,0.224,0.225])])
# Helper: load images
def load_images(folder, maxn=50):
paths = [os.path.join(folder,f) for f in os.listdir(folder) if f.lower().endswith(('.jpg','.png'))]
imgs=[]
for p in paths[:maxn]:
img = Image.open(p).convert('RGB')
imgs.append((p, preprocess(img).unsqueeze(0)))
return imgs
images = load_images("./images/", maxn=50)
# Wrap model for Foolbox
fmodel = fb.PyTorchModel(model, bounds=(0,1), preprocessing=dict(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]))
# Define atk_hairy_hairy: as PGD but adding a high-frequency "hair" mask
def generate_hair_mask(shape, density=0.02):
# shape: (1,3,H,W) in [0,1] tensor
_,_,H,W = shape
mask = torch.zeros(1,1,H,W)
rng = torch.Generator().manual_seed(0)
num_strands = max(1,int(H*W*density/50))
for _ in range(num_strands):
x = torch.randint(0,W,(1,), generator=rng).item()
y = torch.randint(0,H,(1,), generator=rng).item()
length = torch.randint(int(H*0.05), int(H*0.3),(1,), generator=rng).item()
thickness = torch.randint(1,4,(1,), generator=rng).item()
for t in range(length):
xx = min(W-1, max(0, x + int((t/length-0.5)*10)))
yy = min(H-1, max(0, y + t))
mask[0,0,yy:yy+thickness, xx:xx+thickness] = 1.0
return mask.to(device)
# Use PGD but restrict updates to mask locations and add high-frequency noise pattern
attack = LinfPGD(steps=40, abs_stepsize=0.01)
results=[]
for path, x in images:
x = x.to(device)
# get label
logits = model((x - torch.tensor([0.485,0.456,0.406],device=device).view(1,3,1,1)) /
torch.tensor([0.229,0.224,0.225],device=device).view(1,3,1,1))
orig_label = logits.argmax(dim=1).cpu().item()
mask = generate_hair_mask(x.shape, density=0.03)
# define custom attack loop: PGD steps, but project and apply only where mask==1
adv = x.clone().detach()
adv.requires_grad_(True)
eps = 8/255.0
alpha = 2/255.0
for i in range(40):
logits_adv = model((adv - torch.tensor([0.485,0.456,0.406],device=device).view(1,3,1,1)) /
torch.tensor([0.229,0.224,0.225],device=device).view(1,3,1,1))
loss = torch.nn.functional.cross_entropy(logits_adv, torch.tensor([orig_label],device=device))
loss.backward()
grad = adv.grad.data
step = alpha * grad.sign()
# create hair-patterned perturbation: alternate sign per-pixel high freq
hf_pattern = torch.rand_like(adv) * 2 - 1
perturb = step * mask + 0.002 * hf_pattern * mask
adv = adv.detach() + perturb
# clip per-pixel to eps within L_inf of x
adv = torch.max(torch.min(adv, x + eps), x - eps)
adv = torch.clamp(adv, 0.0, 1.0).requires_grad_(True)
logits_final = model((adv - torch.tensor([0.485,0.456,0.406],device=device).view(1,3,1,1)) /
torch.tensor([0.229,0.224,0.225],device=device).view(1,3,1,1))
adv_label = logits_final.argmax(dim=1).cpu().item()
success = adv_label != orig_label
delta = (adv - x).abs().view(3,-1).max().cpu().item()
l2 = torch.norm((adv-x).view(-1)).item()
# save
save_image(adv.squeeze().cpu(), path.replace("./images/","./advs/"))
results.append(dict(path=path, orig=orig_label, adv=adv_label, success=success, linf=delta, l2=l2))
# summary
succ = sum(1 for r in results if r['success'])
print(f"Attack success: succ/len(results) (succ/len(results):.2%)")
print("Average L_inf", np.mean([r['linf'] for r in results]))
print("Average L2", np.mean([r['l2'] for r in results]))