From 6ac383adb5abb6b3dce8499a35dfc862bea22256 Mon Sep 17 00:00:00 2001 From: UltralyticsAssistant Date: Sun, 25 Feb 2024 18:23:24 +0000 Subject: [PATCH] Auto-format by https://ultralytics.com/actions --- .../conv_visdrone_2_yolo_fmt.py | 7 ++++--- adv_patch_gen/utils/common.py | 16 ++++---------- adv_patch_gen/utils/config_parser.py | 12 +++-------- adv_patch_gen/utils/dataset.py | 18 +++++++--------- adv_patch_gen/utils/loss.py | 12 +++++------ adv_patch_gen/utils/median_pool.py | 3 ++- adv_patch_gen/utils/patch.py | 2 +- adv_patch_gen/utils/scheduler.py | 5 +++-- adv_patch_gen/utils/video.py | 12 +++-------- detect_oak.py | 9 +++++--- explainer.py | 5 ++--- test_patch.py | 21 +++++++------------ train.py | 7 +++++-- train_patch.py | 20 ++++++------------ utils/dataloaders.py | 13 +++++++----- 15 files changed, 66 insertions(+), 96 deletions(-) diff --git a/adv_patch_gen/conv_visdrone_2_yolo/conv_visdrone_2_yolo_fmt.py b/adv_patch_gen/conv_visdrone_2_yolo/conv_visdrone_2_yolo_fmt.py index 7ee7cdfb2dff..64ec3db81ffd 100644 --- a/adv_patch_gen/conv_visdrone_2_yolo/conv_visdrone_2_yolo_fmt.py +++ b/adv_patch_gen/conv_visdrone_2_yolo/conv_visdrone_2_yolo_fmt.py @@ -1,7 +1,8 @@ """ -Convert VisDrone annotation format to YOLO labels format -Works for training of YOLOv5 and YOLOv7. -YOLOv7 requires an additional txt file (Same name as the first parent directory) with paths to the images for the train, val & test splits +Convert VisDrone annotation format to YOLO labels format Works for training of YOLOv5 and YOLOv7. + +YOLOv7 requires an additional txt file (Same name as the first parent directory) with paths to the images for the train, +val & test splits """ import os import os.path as osp diff --git a/adv_patch_gen/utils/common.py b/adv_patch_gen/utils/common.py index 2ed6c67e47a5..97f02beb6947 100644 --- a/adv_patch_gen/utils/common.py +++ b/adv_patch_gen/utils/common.py @@ -1,6 +1,4 @@ -""" -Common utils -""" +"""Common utils.""" import socket from typing import Tuple, Union @@ -30,17 +28,13 @@ class BColors: def is_port_in_use(port: int) -> bool: - """ - Checks if a port is free for use - """ + """Checks if a port is free for use.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as stream: return stream.connect_ex(("localhost", int(port))) == 0 def pad_to_square(img: Image, pad_rgb: Tuple[int, int, int] = (127, 127, 127)) -> Image: - """ - Pads a PIL image to a square with pad_rgb values to the longest side - """ + """Pads a PIL image to a square with pad_rgb values to the longest side.""" w, h = img.size if w == h: padded_img = img @@ -57,9 +51,7 @@ def pad_to_square(img: Image, pad_rgb: Tuple[int, int, int] = (127, 127, 127)) - def calc_mean_and_std_err(arr: Union[list, np.ndarray]) -> Tuple[float, float]: - """ " - Calculate mean and standard error - """ + """" Calculate mean and standard error.""" mean = np.mean(arr) std_err = np.std(arr, ddof=1) / np.sqrt(len(arr)) return mean, std_err diff --git a/adv_patch_gen/utils/config_parser.py b/adv_patch_gen/utils/config_parser.py index 290cc00e41a1..459d6b7d9fc5 100644 --- a/adv_patch_gen/utils/config_parser.py +++ b/adv_patch_gen/utils/config_parser.py @@ -1,15 +1,11 @@ -""" -Create argparse options for config files -""" +"""Create argparse options for config files.""" import json import argparse from easydict import EasyDict as edict def load_config_object(cfg_path: str) -> edict: - """ - Loads a config json and returns a edict object - """ + """Loads a config json and returns a edict object.""" with open(cfg_path, "r", encoding="utf-8") as json_file: cfg_dict = json.load(json_file) @@ -17,9 +13,7 @@ def load_config_object(cfg_path: str) -> edict: def get_argparser(desc="Config file load for training adv patches") -> argparse.ArgumentParser: - """ - Get parser with the default config argument - """ + """Get parser with the default config argument.""" parser = argparse.ArgumentParser(description=desc) parser.add_argument( "--cfg", diff --git a/adv_patch_gen/utils/dataset.py b/adv_patch_gen/utils/dataset.py index e7a48379cf70..123416c8c035 100644 --- a/adv_patch_gen/utils/dataset.py +++ b/adv_patch_gen/utils/dataset.py @@ -1,6 +1,5 @@ -""" -Dataset Class for loading YOLO format datasets where the source data dir has the image and labels subdirs -where each image must have a corresponding label file with the same name +"""Dataset Class for loading YOLO format datasets where the source data dir has the image and labels subdirs where each +image must have a corresponding label file with the same name. """ import glob import os.path as osp @@ -18,7 +17,8 @@ class YOLODataset(Dataset): - """Create a dataset for adversarial-yolt. + """ + Create a dataset for adversarial-yolt. Attributes: image_dir: Directory containing the images of the YOLO format dataset. @@ -106,10 +106,8 @@ def __getitem__(self, idx): return image, label def pad_and_scale(self, img, lab): - """ - Pad image and adjust label - img is a PIL image - lab is of fmt class x_center y_center width height with normalized coords + """Pad image and adjust label img is a PIL image lab is of fmt class x_center y_center width height with + normalized coords. """ img_w, img_h = img.size if img_w == img_h: @@ -132,9 +130,7 @@ def pad_and_scale(self, img, lab): return padded_img, lab def pad_label(self, label: torch.Tensor) -> torch.Tensor: - """ - Pad labels with zeros if fewer labels than max_n_labels present - """ + """Pad labels with zeros if fewer labels than max_n_labels present.""" pad_size = self.max_n_labels - label.shape[0] if pad_size > 0: padded_lab = F.pad(label, (0, 0, 0, pad_size), value=0) diff --git a/adv_patch_gen/utils/loss.py b/adv_patch_gen/utils/loss.py index e53642a91974..52f9c452eb9e 100644 --- a/adv_patch_gen/utils/loss.py +++ b/adv_patch_gen/utils/loss.py @@ -1,6 +1,4 @@ -""" -Loss functions used in patch generation -""" +"""Loss functions used in patch generation.""" from typing import Tuple import torch @@ -19,9 +17,7 @@ def __init__(self, config): self.config = config def forward(self, output: torch.Tensor): - """ - output must be of the shape [batch, -1, 5 + num_cls] - """ + """Output must be of the shape [batch, -1, 5 + num_cls]""" # get values necessary for transformation assert output.size(-1) == (5 + self.config.n_classes) @@ -43,7 +39,9 @@ def forward(self, output: torch.Tensor): class SaliencyLoss(nn.Module): - """Implementation of the colorfulness metric as the saliency loss. + """ + Implementation of the colorfulness metric as the saliency loss. + The smaller the value, the less colorful the image. Reference: https://infoscience.epfl.ch/record/33994/files/HaslerS03.pdf """ diff --git a/adv_patch_gen/utils/median_pool.py b/adv_patch_gen/utils/median_pool.py index 70aca4924411..150de2a709cc 100644 --- a/adv_patch_gen/utils/median_pool.py +++ b/adv_patch_gen/utils/median_pool.py @@ -4,7 +4,8 @@ class MedianPool2d(nn.Module): - """Median pool (usable as median filter when stride=1) module. + """ + Median pool (usable as median filter when stride=1) module. Args: kernel_size: size of pooling kernel, int or 2-tuple diff --git a/adv_patch_gen/utils/patch.py b/adv_patch_gen/utils/patch.py index 47e3716ce091..d00ea64fcc42 100644 --- a/adv_patch_gen/utils/patch.py +++ b/adv_patch_gen/utils/patch.py @@ -1,4 +1,4 @@ -""" Modules for creating adversarial object patch """ +"""Modules for creating adversarial object patch.""" import math from typing import Union, Tuple diff --git a/adv_patch_gen/utils/scheduler.py b/adv_patch_gen/utils/scheduler.py index d6f7094854b5..4750123427ab 100644 --- a/adv_patch_gen/utils/scheduler.py +++ b/adv_patch_gen/utils/scheduler.py @@ -17,8 +17,9 @@ class GradualWarmupScheduler(_LRScheduler): - """Sets the learning rate of parameter group to gradually increase for num_epochs from start_lr - to the original lr set for the optimizer + """ + Sets the learning rate of parameter group to gradually increase for num_epochs from start_lr to the original lr set + for the optimizer. Args: optimizer (Optimizer): Wrapped optimizer. diff --git a/adv_patch_gen/utils/video.py b/adv_patch_gen/utils/video.py index 728b307eca98..42da72101db5 100644 --- a/adv_patch_gen/utils/video.py +++ b/adv_patch_gen/utils/video.py @@ -10,9 +10,7 @@ def ffmpeg_create_video_from_image_dir( title_text: Optional[str] = None, framerate: int = 25, ) -> None: - """ - Create a video from images in source_image_dir - """ + """Create a video from images in source_image_dir.""" source = osp.join(source_image_dir, f"*{etxn}") cmd = ["ffmpeg", "-y", "-framerate", str(framerate), "-pattern_type", "glob", "-i", source] if title_text is not None: @@ -23,17 +21,13 @@ def ffmpeg_create_video_from_image_dir( def ffmpeg_combine_two_vids(vid1: str, vid2: str, target_video_path: str) -> None: - """ - Attaches two videos side by side horizontally and saves to target_video_path - """ + """Attaches two videos side by side horizontally and saves to target_video_path.""" cmd = ["ffmpeg", "-y", "-i", vid1, "-i", vid2, "-filter_complex", "hstack", target_video_path] output, error = Popen(cmd, universal_newlines=True, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() def ffmpeg_combine_three_vids(vid1: str, vid2: str, vid3: str, target_video_path: str) -> None: - """ - Attaches three videos side by side horizontally and saves to target_video_path - """ + """Attaches three videos side by side horizontally and saves to target_video_path.""" filter_pat = "[1:v][0:v]scale2ref=oh*mdar:ih[1v][0v];[2:v][0v]scale2ref=oh*mdar:ih[2v][0v];[0v][1v][2v]hstack=3,scale='2*trunc(iw/2)':'2*trunc(ih/2)'" cmd = ["ffmpeg", "-y", "-i", vid1, "-i", vid2, "-i", vid3, "-filter_complex", filter_pat, target_video_path] output, error = Popen(cmd, universal_newlines=True, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() diff --git a/detect_oak.py b/detect_oak.py index 7d4ec2294c19..8f5dbb3fc1e4 100644 --- a/detect_oak.py +++ b/detect_oak.py @@ -118,7 +118,8 @@ def inference( debug: bool = False, **kwrags, ) -> None: - """Run Object Detection Application + """ + Run Object Detection Application. Args: weights: str = path to yolov5 model @@ -234,7 +235,8 @@ def inference_threaded( debug: bool = False, **kwrags, ) -> None: - """Run Object Detection Application + """ + Run Object Detection Application. Args: weights: str = path to yolov5 model @@ -319,7 +321,8 @@ def inference_threaded_with_defense( cam_fps: int = 20, debug: bool = False, ) -> None: - """Run Object Detection Application + """ + Run Object Detection Application. Args: weights: str = path to yolov5 model diff --git a/explainer.py b/explainer.py index 1e8d647ae5ec..f21d31519bfc 100644 --- a/explainer.py +++ b/explainer.py @@ -164,9 +164,8 @@ def __init__(self, model): self.model = model def forward(self, x): - """ - first one is a 3 dim array which contains predictions - second one is a list of heads with their corresponding predictions + """First one is a 3 dim array which contains predictions second one is a list of heads with their corresponding + predictions. """ total_prediction, _ = self.model(x) return total_prediction diff --git a/test_patch.py b/test_patch.py index aec574329494..61ebe56cbe66 100644 --- a/test_patch.py +++ b/test_patch.py @@ -1,6 +1,4 @@ -""" -Testing code for evaluating Adversarial patches against object detection -""" +"""Testing code for evaluating Adversarial patches against object detection.""" import io import os import os.path as osp @@ -47,9 +45,7 @@ def eval_coco_metrics(anno_json: str, pred_json: str, txt_save_path: str, w_mode: str = "a") -> np.ndarray: - """ - Compare and eval pred json producing coco metrics - """ + """Compare and eval pred json producing coco metrics.""" anno = COCO(anno_json) # init annotations api pred = anno.loadRes(pred_json) # init predictions api evaluator = COCOeval(anno, pred, "bbox") @@ -69,9 +65,7 @@ def eval_coco_metrics(anno_json: str, pred_json: str, txt_save_path: str, w_mode class PatchTester: - """ - Module for testing patches on dataset against object detection models - """ + """Module for testing patches on dataset against object detection models.""" def __init__(self, cfg: edict) -> None: self.cfg = cfg @@ -96,8 +90,9 @@ def calc_asr( recompute_asr_all: bool = False, ) -> Tuple[float, float, float, float]: """ - Calculate attack success rate (How many bounding boxes were hidden from the detector) - for all predictions and for different bbox areas. + Calculate attack success rate (How many bounding boxes were hidden from the detector) for all predictions and + for different bbox areas. + Note cls_id is None, misclassifications are ignored and only missing detections are considered attack success. Args: boxes: torch.Tensor, first pass boxes (gt unpatched boxes) [class, x1, y1, x2, y2] @@ -172,9 +167,7 @@ def calc_asr( @staticmethod def draw_bbox_on_pil_image(bbox: np.ndarray, padded_img_pil: Image, class_list: List[str]) -> Image: - """ - Draw bounding box on a PIL image and return said image after drawing - """ + """Draw bounding box on a PIL image and return said image after drawing.""" padded_img_np = np.ascontiguousarray(padded_img_pil) label_2_class = dict(enumerate(class_list)) diff --git a/train.py b/train.py index 9b243d8d91a9..dfc45d78e5ce 100644 --- a/train.py +++ b/train.py @@ -262,7 +262,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio prefix=colorstr("train: "), shuffle=True, seed=opt.seed, - patch_dir=opt.patch_dir) + patch_dir=opt.patch_dir, + ) labels = np.concatenate(dataset.labels, 0) mlc = int(labels[:, 0].max()) # max label class assert mlc < nc, f"Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}" @@ -544,7 +545,9 @@ def parse_opt(known=False): parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2") parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)") parser.add_argument("--seed", type=int, default=0, help="Global training seed") - parser.add_argument('--patch_dir', type=str, default='', help='Directory with images to apply as patch augmentation in train imgs') + parser.add_argument( + "--patch_dir", type=str, default="", help="Directory with images to apply as patch augmentation in train imgs" + ) parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify") # Logger arguments diff --git a/train_patch.py b/train_patch.py index 530be087068d..7ee0afc420ef 100644 --- a/train_patch.py +++ b/train_patch.py @@ -1,5 +1,5 @@ """ -Training code for Adversarial patch training +Training code for Adversarial patch training. python train_patch.py --cfg config_json_file """ @@ -48,9 +48,7 @@ class PatchTrainer: - """ - Module for training on dataset to generate adv patches - """ + """Module for training on dataset to generate adv patches.""" def __init__(self, cfg: edict): self.cfg = cfg @@ -111,9 +109,7 @@ def __init__(self, cfg: edict): self.epoch_length = len(self.train_loader) def init_tensorboard(self, log_dir: str = None, port: int = 6006, run_tb=True): - """ - Initialize tensorboard with optional name - """ + """Initialize tensorboard with optional name.""" if run_tb: while is_port_in_use(port) and port < 65535: port += 1 @@ -146,7 +142,7 @@ def generate_patch(self, patch_type: str, pil_img_mode: str = "RGB") -> torch.Te def read_image(self, path, pil_img_mode: str = "RGB") -> torch.Tensor: """ - Read an input image to be used as a patch + Read an input image to be used as a patch. Arguments: path: Path to the image to be read. @@ -157,9 +153,7 @@ def read_image(self, path, pil_img_mode: str = "RGB") -> torch.Tensor: return adv_patch_cpu def train(self) -> None: - """ - Optimize a patch to generate an adversarial example. - """ + """Optimize a patch to generate an adversarial example.""" # make output dirs patch_dir = osp.join(self.cfg.log_dir, "patches") os.makedirs(patch_dir, exist_ok=True) @@ -284,9 +278,7 @@ def train(self) -> None: print(f"Total training time {time.time() - start_time:.2f}s") def val(self, epoch: int, patchfile: str, conf_thresh: float = 0.4, nms_thresh: float = 0.4) -> None: - """ - Calculates the attack success rate according for the patch with respect to different bounding box areas - """ + """Calculates the attack success rate according for the patch with respect to different bounding box areas.""" # load patch from file patch_img = Image.open(patchfile).convert(self.cfg.patch_img_mode) patch_img = T.Resize(self.cfg.patch_size)(patch_img) diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 0b6287e1f966..c930095f452d 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -27,7 +27,8 @@ from tqdm import tqdm from utils.augmentations import ( - BboxPatcher, Albumentations, + BboxPatcher, + Albumentations, augment_hsv, classify_albumentations, classify_transforms, @@ -173,7 +174,8 @@ def create_dataloader( prefix="", shuffle=False, seed=0, - patch_dir=''): + patch_dir="", +): if rect and shuffle: LOGGER.warning("WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False") shuffle = False @@ -552,7 +554,8 @@ def __init__( prefix="", rank=-1, seed=0, - patch_dir=''): + patch_dir="", + ): self.img_size = img_size self.augment = augment self.hyp = hyp @@ -803,9 +806,9 @@ def __getitem__(self, index): ) # bbox patch augmentation - if hyp and random.random() < hyp.get('bbox_patch', 0.0) and self.bbox_patcher.patches: + if hyp and random.random() < hyp.get("bbox_patch", 0.0) and self.bbox_patcher.patches: img = self.bbox_patcher(img, labels) - + nl = len(labels) # number of labels if nl: labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3)