### Setup Conda Environment Source: https://github.com/shikiw/pointcat/blob/main/README.md Use these commands to create and activate a conda environment for the project. Ensure you have the 'environment.yaml' file. ```bash conda env create -f environment.yaml conda activate pointcat ``` -------------------------------- ### Evaluate Pretrained Models Source: https://github.com/shikiw/pointcat/blob/main/README.md Run this command to evaluate the released pretrained models. Replace '/PATH/TO/YOUR/DATASET/' with the actual dataset path. This example uses PointNet on ModelNet40. ```bash python tester.py \ --data_path /PATH/TO/YOUR/DATASET/ \ --dataset ModelNet40 \ --defended_model pointnet_cls \ --batch_size 16 \ --mode test_normal \ --checkpoint_dir ./checkpoints/pointnet_pointcat_mn.pth ``` -------------------------------- ### Iterative FGM (I-FGM) Attack Setup Source: https://context7.com/shikiw/pointcat/llms.txt Imports necessary components for the Iterative FGM (I-FGM) attack, including the attack class itself and utility functions for adversarial loss and clipping. It also loads a classifier model. ```python from baselines.attack.FGM import IFGM from baselines.attack.util.adv_utils import LogitsAdvLoss from baselines.attack.util.clip_utils import ClipPointsL2 import torch import importlib # Load classifier MODEL = importlib.import_module('model.classifier.dgcnn') classifier = MODEL.get_model(output_channels=40, normal_channel=False).cuda().eval() ``` -------------------------------- ### Compute Adversarial Loss for Noise Generator Source: https://context7.com/shikiw/pointcat/llms.txt Initializes and computes the NTAdvLoss to guide noise generation by pushing adversarial features away from clean features and class peaks. ```python from loss.nt_adv import NTAdvLoss import torch # Initialize adversarial loss adv_loss = NTAdvLoss( device=torch.device('cuda'), batch_size=64, temperature=0.1, beta=0.5, # Weight for feature peak distance use_cosine_similarity=True ) # Compute adversarial loss for noise generator training ori = torch.randn(64, 256).cuda() # Original clean features [B, C] adv = torch.randn(64, 256).cuda() # Adversarial features [B, C] fp = torch.randn(64, 256).cuda() # Per-sample feature peaks [B, C] loss, loss1, loss2 = adv_loss(ori=ori, adv=adv, fp=fp) print(f"Total loss: {loss.item():.4f}") print(f"Ori-Adv distance loss: {loss1.item():.4f}") print(f"Adv-FP distance loss: {loss2.item():.4f}") # Expected output: # Total loss: -1.2345 # Ori-Adv distance loss: -0.8234 # Adv-FP distance loss: -0.4111 ``` -------------------------------- ### FGM Adversarial Attack Source: https://context7.com/shikiw/pointcat/llms.txt Sets up and performs a Fast Gradient Method (FGM) attack on a classifier. It loads a model, defines an adversarial loss function and budget, and generates adversarial examples using a single gradient step. ```python from baselines.attack.FGM import FGM, IFGM, MIFGM, PGD from baselines.attack.util.adv_utils import LogitsAdvLoss, CrossEntropyAdvLoss from baselines.attack.util.clip_utils import ClipPointsL2 import torch import importlib # Load a classifier model MODEL = importlib.import_module('model.classifier.pointnet_cls') classifier = MODEL.get_model(k=40, normal_channel=False).cuda().eval() # Setup attack functions adv_func = LogitsAdvLoss(kappa=0., mode='untargeted') budget = 0.02 * (1024 * 3) ** 0.5 # epsilon ball # Initialize FGM attack fgm_attack = FGM( source_model=classifier, target_model=None, # Use same model for white-box attack adv_func=adv_func, budget=budget, dist_metric='l2' ) # Generate adversarial examples data = torch.randn(16, 1024, 3).cuda() # [B, N, 3] target = torch.randint(0, 40, (16,)).cuda() # [B] adv_data, success_num = fgm_attack.attack( data=data, target=target, mode='untargeted' ) print(f"Attack success: {success_num}/{data.shape[0]}") # Expected output: Attack success: 12/16 ``` -------------------------------- ### Initialize and Run PointNet Classifier Source: https://context7.com/shikiw/pointcat/llms.txt Sets up the PointNet model for classification and performs a forward pass to obtain features and logits. ```python import torch from model.classifier.pointnet_cls import get_model # Initialize PointNet classifier model = get_model( k=40, # Number of classes (ModelNet40) normal_channel=False, # Use only XYZ coordinates use_pre_defense=False # Optional pre-defense module ).cuda() # Forward pass points = torch.randn(16, 3, 1024).cuda() # [B, C, N] features, logits = model(points) print(f"Feature shape: {features.shape}") # [B, 256] print(f"Logits shape: {logits.shape}") # [B, 40] # Get predictions pred = torch.argmax(logits, dim=-1) print(f"Predictions shape: {pred.shape}") # [B] # Expected output: # Feature shape: torch.Size([16, 256]) ``` -------------------------------- ### PointCAT Solver Training Loop Source: https://context7.com/shikiw/pointcat/llms.txt Initializes the PointCAT model, sets up optimizers and loss functions, searches for initial feature peaks, and performs a single training step. It also includes steps for updating feature peaks dynamically and fine-tuning the classification layer. ```python from solver import PointCAT import torch class Args: experiment_dir = 'test' dataset = 'ModelNet40' defended_model = 'pointnet_cls' normal = False input_point_nums = 1024 use_multi_gpu = False decoder_type = 'normal_conv' device = torch.device('cuda') batch_size = 64 optimizer = 'Adam' lr_c = 0.001 lr_ng = 0.001 lr_fp = 0.001 decay_rate = 1e-4 eps = 0.04 temperature_xent = 0.1 temperature_cent = 0.25 temperature_adv = 0.1 use_cosine_similarity = True beta = 0.5 alpha = 8.0 inner_loop_nums = 4 init_search_iters = 500 update_search_iters = 10 DEGREE = [1, 2, 2, 2, 2, 2, 64] G_FEAT = [96, 256, 256, 256, 128, 128, 128, 3] D_FEAT = [3, 64, 128, 256, 256, 512] support = 10 loop_non_linear = False args = Args() # Initialize PointCAT model model = PointCAT(args) model.build_optimizers() model.set_loss_function() # Search for initial feature peaks (class prototypes) model.get_feature_peak(mode='init') # Setup projection head for contrastive learning model.get_projection_head(mode='add') # Single training step with batch data points = torch.randn(64, 3, 1024).cuda() # [B, C, N] target = torch.randint(0, 40, (64,)).cuda() # [B] model.set_target(pc=points, target=target) model.run(mode='train') # Update feature peaks dynamically model.get_projection_head(mode='reverse') model.get_feature_peak(mode='update') model.get_projection_head(mode='reverse') # Fine-tune the final classification layer model.run(mode='finetune', ii=True) ``` -------------------------------- ### Apply Point Cloud Data Augmentation Source: https://context7.com/shikiw/pointcat/llms.txt Demonstrates various augmentation techniques including dropout, scaling, shifting, jittering, and rotation for point cloud batches. ```python import numpy as np from utils.provider import ( random_point_dropout, random_scale_point_cloud, shift_point_cloud, jitter_point_cloud, rotate_point_cloud ) # Sample batch of point clouds [B, N, 3] batch_data = np.random.randn(32, 1024, 3).astype(np.float32) # Apply random point dropout (simulates occlusion) augmented = random_point_dropout(batch_data.copy(), max_dropout_ratio=0.875) print(f"After dropout: {augmented.shape}") # Apply random scaling augmented = random_scale_point_cloud(batch_data.copy(), scale_low=0.8, scale_high=1.25) print(f"After scaling: {augmented.shape}") # Apply random shift augmented = shift_point_cloud(batch_data.copy(), shift_range=0.1) print(f"After shift: {augmented.shape}") # Apply jittering (Gaussian noise) augmented = jitter_point_cloud(batch_data.copy(), sigma=0.01, clip=0.05) print(f"After jitter: {augmented.shape}") # Apply random rotation along up-axis augmented = rotate_point_cloud(batch_data.copy()) print(f"After rotation: {augmented.shape}") # Expected output: # After dropout: (32, 1024, 3) # After scaling: (32, 1024, 3) # After shift: (32, 1024, 3) # After jitter: (32, 1024, 3) # After rotation: (32, 1024, 3) ``` -------------------------------- ### Train PointNet Model Source: https://github.com/shikiw/pointcat/blob/main/README.md Command to initiate training for the PointNet model. Adjust parameters such as dataset path, experiment directory, and adversarial training settings as needed. ```bash python trainer.py \ --experiment_dir pn_test \ --data_path /PATH/TO/YOUR/DATASET/ \ --dataset ModelNet40 \ --defended_model pointnet_cls \ --eps 0.04 \ --alpha 8. \ --beta 0.5 \ --use_cosine_similarity \ --inner_loop_nums 4 \ --batch_size 64 \ --init_search_iters 500 \ --update_search_iters 10 \ --lr_fp 0.001 \ --use_multi_gpu ``` -------------------------------- ### Download Dataset Script Source: https://github.com/shikiw/pointcat/blob/main/README.md Execute this script to download the ModelNet40 and ShapeNetPart datasets. Datasets will be saved in the './data' directory by default. ```bash sh download.sh ``` -------------------------------- ### Load ModelNet40 Point Cloud Datasets Source: https://context7.com/shikiw/pointcat/llms.txt Initializes the ModelNetDataLoader for efficient loading and preprocessing of ModelNet40 data. It supports options for sampling, normal channels, and creates a PyTorch DataLoader for batch iteration. ```python from data_utils.ModelNetDataLoader import ModelNetDataLoader import torch # Initialize dataset dataset = ModelNetDataLoader( root='./data/modelnet40_normal_resampled/', npoint=1024, split='train', # or 'test' uniform=False, # Use FPS for uniform sampling normal_channel=False # Include surface normals ) # Create data loader dataloader = torch.utils.data.DataLoader( dataset, batch_size=32, shuffle=True, num_workers=4, drop_last=True ) # Iterate through batches for points, labels in dataloader: print(f"Points shape: {points.shape}") # [B, N, 3] or [B, N, 6] print(f"Labels shape: {labels.shape}") # [B, 1] break # Expected output: # Points shape: torch.Size([32, 1024, 3]) # Labels shape: torch.Size([32, 1]) ``` -------------------------------- ### Initialize DGCNN Classifier Source: https://context7.com/shikiw/pointcat/llms.txt Instantiates a DGCNN model with specified output channels and graph construction parameters for point cloud classification. ```python import torch from model.classifier.dgcnn import get_model # Initialize DGCNN classifier model = get_model( output_channels=40, # Number of classes k=20, # Number of nearest neighbors for graph construction emb_dims=1024, # Embedding dimension dropout=0.5, normal_channel=False ).cuda() # Forward pass points = torch.randn(16, 3, 1024).cuda() # [B, C, N] features, logits = model(points) print(f"Feature shape: {features.shape}") # [B, 256] print(f"Logits shape: {logits.shape}") # [B, 40] # Expected output: # Feature shape: torch.Size([16, 256]) # Logits shape: torch.Size([16, 40]) ``` -------------------------------- ### Train Model with PointCAT Source: https://context7.com/shikiw/pointcat/llms.txt Orchestrates the contrastive adversarial training pipeline, handling data loading, model initialization, and training loops. Ensure the correct data path and dataset are specified. ```python from arguments import Arguments from trainer import Trainer from utils.utils import set_seed import torch # Parse training arguments args = Arguments(stage='train').parser().parse_args([ '--experiment_dir', 'my_experiment', '--data_path', './data/modelnet40_normal_resampled/', '--dataset', 'ModelNet40', '--defended_model', 'pointnet_cls', '--eps', '0.04', '--alpha', '8.0', '--beta', '0.5', '--use_cosine_similarity', '--inner_loop_nums', '4', '--batch_size', '64', '--init_search_iters', '500', '--update_search_iters', '10', '--lr_fp', '0.001', '--epochs', '200' ]) args.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # Set random seed for reproducibility set_seed(2022) # Initialize trainer and run training trainer = Trainer(args) trainer.run() # Expected output during training: # Start Loading Dataset... # Finish Loading Dataset... # Start PointCAT Training Phase... # Epoch_c 1, Epoch_ng 1, (1/200): # Start CAT Training Step... # Loss ng: 0.123456 (Loss 1: 0.089123 Loss 2: 0.034333) # Loss cls: 0.234567 (Loss cent 1: 0.112345 Loss cent 2: 0.122222) # Current Acc: 0.891234 ``` -------------------------------- ### Evaluate Model Robustness Source: https://context7.com/shikiw/pointcat/llms.txt Runs robustness evaluations against normal, AutoAttack, and black-box transfer scenarios using the tester script. ```bash # Test model robustness against white-box attacks python tester.py \ --data_path ./data/modelnet40_normal_resampled/ \ --dataset ModelNet40 \ --defended_model pointnet_cls \ --batch_size 16 \ --mode test_normal \ --checkpoint_dir ./checkpoints/pointnet_pointcat_mn.pth # Test against AutoAttack (stronger evaluation) python tester.py \ --data_path ./data/modelnet40_normal_resampled/ \ --dataset ModelNet40 \ --defended_model pointnet_cls \ --batch_size 16 \ --mode test_aa \ --checkpoint_dir ./checkpoints/pointnet_pointcat_mn.pth # Test black-box transferability python tester.py \ --data_path ./data/modelnet40_normal_resampled/ \ --dataset ModelNet40 \ --defended_model dgcnn \ --source_model pointnet_cls \ --batch_size 16 \ --mode test_ba \ --checkpoint_dir ./checkpoints/dgcnn_pointcat_mn.pth \ --source_model_dir ./checkpoints/pointnet_vanilla.pth ``` -------------------------------- ### Train PointNet with PointCAT Source: https://context7.com/shikiw/pointcat/llms.txt Executes the training process for a PointNet classifier on the ModelNet40 dataset using specified adversarial training hyperparameters. ```bash # Train PointNet with PointCAT on ModelNet40 python trainer.py \ --experiment_dir pn_modelnet40 \ --data_path ./data/modelnet40_normal_resampled/ \ --dataset ModelNet40 \ --defended_model pointnet_cls \ --eps 0.04 \ --alpha 8.0 \ --beta 0.5 \ --use_cosine_similarity \ --inner_loop_nums 4 \ --batch_size 64 \ --init_search_iters 500 \ --update_search_iters 10 \ --lr_fp 0.001 \ --lr_c 0.001 \ --lr_ng 0.001 \ --epochs 200 \ --use_multi_gpu # Expected output: # Start Loading Dataset... # The size of train data is 9843 # The size of test data is 2468 # Finish Loading Dataset... # Start PointCAT Training Phase... ``` -------------------------------- ### Initialize and Use AutoEncoder Noise Generator Source: https://context7.com/shikiw/pointcat/llms.txt Configures the AutoEncoder network to generate adversarial perturbations and applies them to point clouds with epsilon constraints. ```python from model.networks import AutoEncoder import torch class Args: DEGREE = [1, 2, 2, 2, 2, 2, 64] G_FEAT = [96, 256, 256, 256, 128, 128, 128, 3] support = 10 loop_non_linear = False args = Args() # Initialize noise generator noise_generator = AutoEncoder( k=40, # Number of classes input_point_nums=1024, decoder_type='normal_conv', # or 'treegcn' args=args ).cuda() # Generate perturbations pc = torch.randn(16, 3, 1024).cuda() # Point cloud [B, C, N] labels = torch.randint(0, 40, (16,)).cuda() # Class labels [B] perturbation = noise_generator(pc, labels) print(f"Perturbation shape: {perturbation.shape}") # Apply perturbation with epsilon constraint eps = 0.04 norm = torch.sum(perturbation ** 2, dim=[1, 2]) ** 0.5 perturbation = perturbation / (norm[:, None, None] + 1e-9) perturbation = perturbation * (pc.size(1) * pc.size(2)) ** 0.5 * eps # Create adversarial point cloud adversarial_pc = torch.clamp(pc + perturbation, min=-1, max=1) print(f"Adversarial PC shape: {adversarial_pc.shape}") # Expected output: # Perturbation shape: torch.Size([16, 3, 1024]) # Adversarial PC shape: torch.Size([16, 3, 1024]) ``` -------------------------------- ### Execute I-FGM Targeted Attack Source: https://context7.com/shikiw/pointcat/llms.txt Configures and runs an Iterative Fast Gradient Sign Method attack on a point cloud classifier. ```python budget = 0.02 * (1024 * 3) ** 0.5 num_iter = 10 step_size = budget / num_iter adv_func = LogitsAdvLoss(kappa=0., mode='targeted') clip_func = ClipPointsL2(budget=budget) # Initialize I-FGM attack ifgm_attack = IFGM( source_model=classifier, adv_func=adv_func, clip_func=clip_func, budget=budget, step_size=step_size, num_iter=num_iter, dist_metric='l2' ) # Execute targeted attack data = torch.randn(16, 1024, 3).cuda() target_label = torch.randint(0, 40, (16,)).cuda() adv_data, success_num = ifgm_attack.attack( data=data, target=target_label, mode='targeted' ) print(f"Targeted attack success: {success_num}/{data.shape[0]}") ``` -------------------------------- ### Execute PGD Untargeted Attack Source: https://context7.com/shikiw/pointcat/llms.txt Performs a Projected Gradient Descent attack, which incorporates random initialization for increased robustness. ```python from baselines.attack.FGM import PGD from baselines.attack.util.adv_utils import LogitsAdvLoss from baselines.attack.util.clip_utils import ClipPointsL2 import torch import importlib # Load classifier MODEL = importlib.import_module('model.classifier.pointnet_cls') classifier = MODEL.get_model(k=40, normal_channel=False).cuda().eval() # Attack configuration budget = 0.08 * (1024 * 3) ** 0.5 num_iter = 50 step_size = budget / num_iter adv_func = LogitsAdvLoss(kappa=0., mode='untargeted') clip_func = ClipPointsL2(budget=budget) # Initialize PGD attack pgd_attack = PGD( source_model=classifier, adv_func=adv_func, clip_func=clip_func, budget=budget, step_size=step_size, num_iter=num_iter, dist_metric='l2' ) # Execute attack data = torch.randn(16, 1024, 3).cuda() labels = torch.randint(0, 40, (16,)).cuda() adv_data, success_num = pgd_attack.attack( data=data, target=labels, mode='untargeted' ) print(f"PGD attack success rate: {success_num/16:.2%}") ``` -------------------------------- ### Apply SOR Defense Source: https://context7.com/shikiw/pointcat/llms.txt Uses Statistical Outlier Removal to filter adversarial noise from point clouds based on k-nearest neighbor distances. ```python from baselines.defense.drop_points.SOR import SORDefense import torch # Initialize SOR defense sor_defense = SORDefense( k=2, # k-NN for outlier detection alpha=1.1, # threshold = mean + alpha * std npoint=1024 # target number of points after processing ) # Apply defense to potentially adversarial point cloud # Input shape: [B, 3, N] (channels first) adversarial_pc = torch.randn(16, 3, 1024).cuda() # Defense removes outliers and resamples to fixed size defended_pc = sor_defense(adversarial_pc) print(f"Input shape: {adversarial_pc.shape}") print(f"Output shape: {defended_pc.shape}") ``` -------------------------------- ### Compute Supervised Contrastive Loss Source: https://context7.com/shikiw/pointcat/llms.txt Calculates loss to cluster representations of the same class while separating different classes. ```python from loss.nt_supcon import SupConLoss import torch # Initialize loss function sup_con_loss = SupConLoss( device=torch.device('cuda'), batch_size=64, temperature=0.1, use_cosine_similarity=True ) # Compute loss for clean and adversarial feature pairs zis = torch.randn(64, 256).cuda() # Clean features [B, C] zjs = torch.randn(64, 256).cuda() # Adversarial features [B, C] labels = torch.randint(0, 40, (64,)).cuda() # Class labels [B] loss = sup_con_loss(zis=zis, zjs=zjs, labels=labels) print(f"Supervised contrastive loss: {loss.item():.4f}") ``` -------------------------------- ### Test Model Robustness Source: https://context7.com/shikiw/pointcat/llms.txt Evaluates trained models against various attacks, including clean accuracy, random noise, point dropping, and white-box adversarial attacks. Specify the checkpoint directory for the model to be tested. ```python from arguments import Arguments from tester import Tester from utils.utils import set_seed import torch # Parse testing arguments args = Arguments(stage='test').parser().parse_args([ '--data_path', './data/modelnet40_normal_resampled/', '--dataset', 'ModelNet40', '--defended_model', 'pointnet_cls', '--batch_size', '16', '--mode', 'test_normal', '--checkpoint_dir', './checkpoints/pointnet_pointcat_mn.pth' ]) args.device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # Set seed and initialize tester set_seed(2022) tester = Tester(args) tester.run(mode=args.mode) # Expected output: # Without any attacks: # Clean ACC (2048/2468): 0.8892 # # Input preprocessing attacks: # Random noisy ACC (1956/2468): 0.7925 # Random dropping ACC (1823/2468): 0.7385 # # Untargeted adversarial attacks: # FGM attack ASR (423/2468): 0.1714 # I-FGM attack ASR (512/2468): 0.2075 # MI-FGM attack ASR (489/2468): 0.1981 # PGD attack ASR (534/2468): 0.2164 ``` -------------------------------- ### PointCAT Citation Source: https://github.com/shikiw/pointcat/blob/main/README.md BibTeX entry for citing the PointCAT paper. Use this in your academic work if you utilize this implementation. ```bibtex @article{huang2022pointcat, title={PointCAT: Contrastive Adversarial Training for Robust Point Cloud Recognition}, author={Huang, Qidong and Dong, Xiaoyi and Chen, Dongdong and Zhou, Hang and Zhang, Weiming and Zhang, Kui and Hua, Gang and Yu, Nenghai}, journal={arXiv preprint arXiv:2209.07788}, year={2022} } ``` -------------------------------- ### Compute Centralizing Loss Source: https://context7.com/shikiw/pointcat/llms.txt Calculates loss to pull feature representations toward class-specific prototypes. ```python from loss.nt_cent import NTCentLoss import torch # Initialize centralizing loss cent_loss = NTCentLoss( device=torch.device('cuda'), batch_size=64, temperature=0.25, use_cosine_similarity=True ) # Compute loss to pull representations toward class feature peaks rep = torch.randn(64, 256).cuda() # Sample representations [B, C] fp = torch.randn(40, 256).cuda() # Feature peaks for 40 classes [M, C] target = torch.randint(0, 40, (64,)).cuda() # Class labels [B] loss = cent_loss(rep=rep, fp=fp, target=target) print(f"Centralizing loss: {loss.item():.4f}") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.