Spaces:
Sleeping
Sleeping
Download detectors/PGC/upstream/utils/cli.py from Truebees/DeepShield-Detectors: direct link, hf CLI and curl.
- Browser
- Download file 11.6 kB
-
https://huggingface.co/spaces/Truebees/DeepShield-Detectors/resolve/main/detectors/PGC/upstream/utils/cli.py
- Command line
-
hf download hf://spaces/Truebees/DeepShield-Detectors/detectors/PGC/upstream/utils/cli.py
-
curl -L -o cli.py https://huggingface.co/spaces/Truebees/DeepShield-Detectors/resolve/main/detectors/PGC/upstream/utils/cli.py
11.6 kB
| import argparse | |
| import os | |
| from typing import List, Tuple | |
| import torch | |
| # Choices for ``--dino_variant``. Centralised so train and test cannot drift. | |
| DINO_CHOICES = [ | |
| "dinov2-base", | |
| "dinov2-large", | |
| "dinov2-giant", | |
| "dinov3-vitb16-pretrain-lvd1689m", | |
| ] | |
| # Choices for ``--optim``. | |
| OPTIM_CHOICES = ["adam", "sgd"] | |
| def build_train_parser() -> argparse.ArgumentParser: | |
| """Construct the training CLI parser. | |
| Every option used anywhere in the training pipeline is registered here | |
| with a sensible default; downstream modules access them directly via | |
| attribute lookup. | |
| """ | |
| parser = argparse.ArgumentParser( | |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter, | |
| description="PGC (Peak-Guided Calibration) training CLI", | |
| ) | |
| # ----- Identity / I/O ------------------------------------------------- | |
| parser.add_argument( | |
| "--name", | |
| type=str, | |
| default="pgc_train", | |
| help="Experiment name (also used as log filename stem).", | |
| ) | |
| parser.add_argument( | |
| "--checkpoints_dir", | |
| type=str, | |
| default="checkpoints", | |
| help="Directory under which logs and checkpoints are written.", | |
| ) | |
| parser.add_argument( | |
| "--devices", | |
| type=str, | |
| default="3", | |
| help=( | |
| "CUDA devices, e.g. '0' or '0,1'; '-1' for CPU. " | |
| "RTX 4090 #3 is the test box." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--num_threads", | |
| type=int, | |
| default=8, | |
| help="Number of DataLoader worker processes for training.", | |
| ) | |
| parser.add_argument( | |
| "--batch_size", | |
| type=int, | |
| default=32, | |
| help="Training batch size.", | |
| ) | |
| # ----- DINO backbone & LoRA ------------------------------------------- | |
| parser.add_argument( | |
| "--dino_variant", | |
| type=str, | |
| default="dinov2-large", | |
| choices=DINO_CHOICES, | |
| help="DINO backbone variant.", | |
| ) | |
| parser.add_argument( | |
| "--dino_pretrained_root", | |
| type=str, | |
| default=None, | |
| help=( | |
| "Root directory containing local DINO checkpoints. " | |
| "When set, the loader expects subfolders named after the variant. " | |
| "Required for training; entry-point validates explicitly." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--lora_rank", | |
| type=int, | |
| default=8, | |
| help="LoRA rank for adapter layers.", | |
| ) | |
| parser.add_argument( | |
| "--lora_alpha", | |
| type=float, | |
| default=1.0, | |
| help="LoRA scaling factor (alpha / rank determines effective scale).", | |
| ) | |
| parser.add_argument( | |
| "--lora_dropout", | |
| type=float, | |
| default=0.1, | |
| help="Dropout probability inside LoRA adapter layers.", | |
| ) | |
| # ----- Training data --------------------------------------------------- | |
| # ``--real_image_dir`` and ``--fake_image_dir`` both accept *one or more* | |
| # root directories (``nargs='+'``). ``RealFakeDataset`` scans every | |
| # supplied directory, concatenates the samples and performs a global | |
| # ``random.shuffle`` so that every mini-batch can freely mix sources. | |
| parser.add_argument( | |
| "--real_image_dir", | |
| type=str, | |
| nargs="+", | |
| default=None, | |
| help=( | |
| "One or more root directories of real training images. " | |
| "Example: --real_image_dir /path/A /path/B. All directories are " | |
| "scanned recursively and the resulting samples are merged + " | |
| "shuffled before training." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--fake_image_dir", | |
| type=str, | |
| nargs="+", | |
| default=None, | |
| help=( | |
| "One or more root directories of fake / generated training " | |
| "images. Example: --fake_image_dir /path/A /path/B. All " | |
| "directories are scanned recursively and the resulting samples " | |
| "are merged + shuffled before training." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--cropSize", | |
| type=int, | |
| default=224, | |
| help="Pad-then-crop input resolution (square).", | |
| ) | |
| # ----- Mid-training evaluation ---------------------------------------- | |
| parser.add_argument( | |
| "--test_root", | |
| type=str, | |
| default=None, | |
| help=( | |
| "Optional root directory of the evaluation dataset " | |
| "(UniversalFakeDetect layout: ``<root>/<subset>/{0_real,1_fake}``). " | |
| "If supplied the trainer evaluates on it periodically." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--eval_batch_size", | |
| type=int, | |
| default=32, | |
| help="Batch size used during mid-training evaluation.", | |
| ) | |
| parser.add_argument( | |
| "--eval_num_threads", | |
| type=int, | |
| default=8, | |
| help="DataLoader workers for mid-training evaluation.", | |
| ) | |
| # ----- Optimization ---------------------------------------------------- | |
| parser.add_argument( | |
| "--niter", | |
| type=int, | |
| default=100, | |
| help="Total number of training epochs.", | |
| ) | |
| parser.add_argument( | |
| "--lr", | |
| type=float, | |
| default=5e-5, | |
| help="Initial learning rate.", | |
| ) | |
| parser.add_argument( | |
| "--optim", | |
| type=str, | |
| default="adam", | |
| choices=OPTIM_CHOICES, | |
| help="Optimizer family.", | |
| ) | |
| parser.add_argument( | |
| "--accumulation_steps", | |
| type=int, | |
| default=4, | |
| help="Gradient accumulation steps.", | |
| ) | |
| parser.add_argument( | |
| "--weight_decay", | |
| type=float, | |
| default=0.05, | |
| help="L2 regularization strength.", | |
| ) | |
| parser.add_argument( | |
| "--label_smoothing", | |
| type=float, | |
| default=0.1, | |
| help="Label-smoothing epsilon for binary cross-entropy.", | |
| ) | |
| # ----- PGCM (Peak-Guided Calibration Module) hyper-parameters --------- | |
| parser.add_argument( | |
| "--tau_rgb", | |
| type=float, | |
| default=0.5, | |
| help="Temperature for the RGB-stream peak aggregation in PGCM.", | |
| ) | |
| parser.add_argument( | |
| "--tau_res", | |
| type=float, | |
| default=0.5, | |
| help="Temperature for the residual-stream peak aggregation in PGCM.", | |
| ) | |
| # ----- Stability / reproducibility ------------------------------------ | |
| parser.add_argument( | |
| "--max_grad_norm", | |
| type=float, | |
| default=1.0, | |
| help="Maximum L2 norm for gradient clipping (0 to disable).", | |
| ) | |
| parser.add_argument( | |
| "--seed", | |
| type=int, | |
| default=42, | |
| help="Random seed for Python, NumPy and PyTorch.", | |
| ) | |
| # ----- Bookkeeping ----------------------------------------------------- | |
| parser.add_argument( | |
| "--eval_every_steps", | |
| type=int, | |
| default=200, | |
| help=( | |
| "Run mid-training evaluation every N optimization steps. " | |
| "A checkpoint named " | |
| "``step{N}_acc{int}_ap{int}.pth`` is also saved right after " | |
| "each such evaluation (in addition to the best-AP ``best.pth``)." | |
| ), | |
| ) | |
| # Internal flag used by ``finalize_opt`` to know which parser produced | |
| # the namespace. Not exposed as a CLI option (no ``add_argument``). | |
| parser.set_defaults(isTrain=True) | |
| return parser | |
| def build_test_parser() -> argparse.ArgumentParser: | |
| """Construct the inference / evaluation CLI parser.""" | |
| parser = argparse.ArgumentParser( | |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter, | |
| description="PGC (Peak-Guided Calibration) test CLI", | |
| ) | |
| parser.add_argument( | |
| "--checkpoint", | |
| type=str, | |
| required=True, | |
| help="Path to the trained model checkpoint (.pth).", | |
| ) | |
| parser.add_argument( | |
| "--test_root", | |
| type=str, | |
| required=True, | |
| help="Root directory of the evaluation dataset.", | |
| ) | |
| parser.add_argument( | |
| "--checkpoints_dir", | |
| type=str, | |
| default="checkpoints", | |
| help="Directory under which the test log file is written.", | |
| ) | |
| parser.add_argument( | |
| "--name", | |
| type=str, | |
| default="pgc_test", | |
| help="Experiment name used to derive the test log filename.", | |
| ) | |
| parser.add_argument( | |
| "--batch_size", | |
| type=int, | |
| default=32, | |
| help="Evaluation batch size.", | |
| ) | |
| parser.add_argument( | |
| "--num_workers", | |
| type=int, | |
| default=8, | |
| help="DataLoader worker processes for evaluation.", | |
| ) | |
| parser.add_argument( | |
| "--devices", | |
| type=str, | |
| default="3", | |
| help=( | |
| "CUDA devices, e.g. '0' or '0,1'; '-1' for CPU. " | |
| "RTX 4090 #3 is the test box." | |
| ), | |
| ) | |
| parser.add_argument( | |
| "--cropSize", | |
| type=int, | |
| default=224, | |
| help="Pad-then-crop input resolution (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--dino_variant", | |
| type=str, | |
| default="dinov2-large", | |
| choices=DINO_CHOICES, | |
| help="DINO backbone variant (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--lora_rank", | |
| type=int, | |
| default=8, | |
| help="LoRA rank (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--lora_alpha", | |
| type=float, | |
| default=1.0, | |
| help="LoRA alpha (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--lora_dropout", | |
| type=float, | |
| default=0.1, | |
| help="LoRA dropout (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--dino_pretrained_root", | |
| type=str, | |
| default=None, | |
| help="Root directory containing local DINO checkpoints.", | |
| ) | |
| parser.add_argument( | |
| "--tau_rgb", | |
| type=float, | |
| default=0.5, | |
| help="PGCM RGB-stream temperature (must match training).", | |
| ) | |
| parser.add_argument( | |
| "--tau_res", | |
| type=float, | |
| default=0.5, | |
| help="PGCM residual-stream temperature (must match training).", | |
| ) | |
| parser.set_defaults(isTrain=False) | |
| return parser | |
| def parse_devices(devices_str: str) -> Tuple[List[int], torch.device]: | |
| str_ids = [s for s in devices_str.split(",") if s.strip() != ""] | |
| parsed_ids = [int(x) for x in str_ids] | |
| valid_ids = [i for i in parsed_ids if i >= 0] | |
| if torch.cuda.is_available() and len(valid_ids) > 0: | |
| return valid_ids, torch.device(f"cuda:{valid_ids[0]}") | |
| return [], torch.device("cpu") | |
| def cli_message_for_opt( | |
| parser: argparse.ArgumentParser, opt: argparse.Namespace | |
| ) -> str: | |
| message = "----------------- Options ---------------\n" | |
| for k, v in sorted(vars(opt).items()): | |
| if k.startswith("_"): | |
| continue | |
| default = parser.get_default(k) | |
| comment = f"\t[default: {default}]" if v != default else "" | |
| message += "{:>25}: {:<30}{}\n".format(str(k), str(v), comment) | |
| message += "----------------- End -------------------" | |
| return message | |
| def finalize_opt(opt: argparse.Namespace) -> str: | |
| parser = build_train_parser() if opt.isTrain else build_test_parser() | |
| message = cli_message_for_opt(parser, opt) | |
| expr_dir = os.path.join(opt.checkpoints_dir, opt.name) | |
| os.makedirs(expr_dir, exist_ok=True) | |
| with open(os.path.join(expr_dir, "opt.txt"), "wt") as opt_file: | |
| opt_file.write(message + "\n") | |
| devices_list, device = parse_devices(opt.devices) | |
| opt.devices = devices_list | |
| opt.device = device | |
| if torch.cuda.is_available() and len(devices_list) > 0: | |
| torch.cuda.set_device(devices_list[0]) | |
| return message | |