ocsvm working

This commit is contained in:
Jan Kowalczyk
2025-06-13 10:24:54 +02:00
parent d88719e718
commit 9298dea329
6 changed files with 376 additions and 137 deletions

View File

@@ -167,6 +167,12 @@ from utils.visualization.plot_images_grid import plot_images_grid
default=1e-6,
help="Weight decay (L2 penalty) hyperparameter for Deep SAD objective.",
)
@click.option(
"--latent_space_dim",
type=int,
default=128,
help="Dimensionality of the latent space for the autoencoder.",
)
@click.option(
"--pretrain",
type=bool,
@@ -303,6 +309,7 @@ def main(
lr_milestone,
batch_size,
weight_decay,
latent_space_dim,
pretrain,
ae_optimizer_name,
ae_lr,
@@ -415,7 +422,7 @@ def main(
train_passes = range(k_fold_num) if k_fold else [None]
train_isoforest = True
train_ocsvm = False
train_ocsvm = True
train_deepsad = True
for fold_idx in train_passes:
@@ -424,10 +431,6 @@ def main(
else:
logger.info(f"Fold {fold_idx + 1}/{k_fold_num}")
# Initialize OC-SVM model
if train_ocsvm:
ocsvm = OCSVM(kernel=ocsvm_kernel, nu=ocsvm_nu, hybrid=False)
# Initialize Isolation Forest model
if train_isoforest:
Isoforest = IsoForest(
@@ -441,7 +444,7 @@ def main(
# Initialize DeepSAD model and set neural network phi
if train_deepsad:
deepSAD = DeepSAD(cfg.settings["eta"])
deepSAD = DeepSAD(latent_space_dim, cfg.settings["eta"])
deepSAD.set_network(net_name)
# If specified, load Deep SAD model (center c, network weights, and possibly autoencoder weights)
@@ -486,11 +489,32 @@ def main(
# Save pretraining results
if fold_idx is None:
deepSAD.save_ae_results(export_json=xp_path + "/ae_results.json")
deepSAD.save_ae_results(export_pkl=xp_path + "/ae_results.pkl")
ae_model_path = xp_path + "/ae_model.tar"
deepSAD.save_model(export_model=ae_model_path, save_ae=True)
else:
deepSAD.save_ae_results(
export_json=xp_path + f"/ae_results_{fold_idx}.json"
export_pkl=xp_path + f"/ae_results_{fold_idx}.pkl"
)
ae_model_path = xp_path + f"/ae_model_{fold_idx}.tar"
deepSAD.save_model(export_model=ae_model_path, save_ae=True)
# Initialize OC-SVM model (after pretraining to use autoencoder features)
if train_ocsvm:
ocsvm = OCSVM(
kernel=ocsvm_kernel,
nu=ocsvm_nu,
hybrid=True,
latent_space_dim=latent_space_dim,
)
if load_model and not pretrain:
ae_model_path = load_model
ocsvm.load_ae(
net_name=net_name, model_path=ae_model_path, device=device
)
logger.info(
f"Loaded pretrained autoencoder for features from {ae_model_path}."
)
# Log training details
logger.info("Training optimizer: %s" % cfg.settings["optimizer_name"])
@@ -525,7 +549,7 @@ def main(
device=device,
n_jobs_dataloader=n_jobs_dataloader,
k_fold_idx=fold_idx,
batch_size=8,
batch_size=256,
)
# Train model on dataset
@@ -553,7 +577,7 @@ def main(
device=device,
n_jobs_dataloader=n_jobs_dataloader,
k_fold_idx=fold_idx,
batch_size=8,
batch_size=256,
)
# Test model
@@ -730,7 +754,7 @@ def main(
logger.info("Known anomaly classes: %s" % (dataset.known_outlier_classes,))
# Initialize DeepSAD model and set neural network phi
deepSAD = DeepSAD(cfg.settings["eta"])
deepSAD = DeepSAD(latent_space_dim, cfg.settings["eta"])
deepSAD.set_network(net_name)
# If specified, load Deep SAD model (center c, network weights, and possibly autoencoder weights)
@@ -776,54 +800,87 @@ def main(
ratio_known_outlier,
ratio_pollution,
random_state=np.random.RandomState(cfg.settings["seed"]),
k_fold_num=k_fold_num,
)
# Dictionary to store results for each dimension
# ae_elbow_dims = [32, 64, 128, 256, 384, 512, 768, 1024]
ae_elbow_dims = [32, 64]
elbow_results = {"dimensions": list(ae_elbow_dims), "ae_results": {}}
# Set up k-fold passes
train_passes = range(k_fold_num) if k_fold else [None]
# Test dimensions
ae_elbow_dims = [32, 64, 128, 256, 384, 512, 768, 1024]
# Test each dimension
for rep_dim in ae_elbow_dims:
logger.info(f"Testing autoencoder with latent dimension: {rep_dim}")
# Initialize DeepSAD model with current dimension
deepSAD = DeepSAD(cfg.settings["eta"])
deepSAD.set_network(
net_name, rep_dim=rep_dim
) # Pass rep_dim to network builder
# Results dictionary for this dimension
dim_results = {
"dimension": rep_dim,
"ae_results": {},
"k_fold": k_fold,
"k_fold_num": k_fold_num,
}
# Pretrain autoencoder with current dimension
deepSAD.pretrain(
dataset,
optimizer_name=cfg.settings["ae_optimizer_name"],
lr=cfg.settings["ae_lr"],
n_epochs=cfg.settings["ae_n_epochs"],
lr_milestones=cfg.settings["ae_lr_milestone"],
batch_size=cfg.settings["ae_batch_size"],
weight_decay=cfg.settings["ae_weight_decay"],
device=device,
n_jobs_dataloader=n_jobs_dataloader,
# For each fold
for fold_idx in train_passes:
if fold_idx is None:
logger.info(f"Dimension {rep_dim}: Single training without k-fold")
else:
logger.info(
f"Dimension {rep_dim}: Fold {fold_idx + 1}/{k_fold_num}"
)
# Initialize DeepSAD model with current dimension
deepSAD = DeepSAD(rep_dim, cfg.settings["eta"])
deepSAD.set_network(net_name)
# Pretrain autoencoder with current dimension
deepSAD.pretrain(
dataset,
optimizer_name=cfg.settings["ae_optimizer_name"],
lr=cfg.settings["ae_lr"],
n_epochs=cfg.settings["ae_n_epochs"],
lr_milestones=cfg.settings["ae_lr_milestone"],
batch_size=cfg.settings["ae_batch_size"],
weight_decay=cfg.settings["ae_weight_decay"],
device=device,
n_jobs_dataloader=n_jobs_dataloader,
k_fold_idx=fold_idx,
)
# Store results for this fold
fold_key = "single" if fold_idx is None else f"fold_{fold_idx}"
dim_results["ae_results"][fold_key] = deepSAD.ae_results
logger.info(
f"Finished testing dimension {rep_dim} "
+ (
f"fold {fold_idx + 1}/{k_fold_num}"
if fold_idx is not None
else "single pass"
)
)
# Clear some memory
del deepSAD
torch.cuda.empty_cache()
# Save results for this dimension (includes all folds)
results_filename = (
f"ae_elbow_results_{net_name}_dim_{rep_dim}"
+ ("_kfold" if k_fold else "")
+ ".pkl"
)
results_path = Path(xp_path) / results_filename
# Store results for this dimension
elbow_results["ae_results"][rep_dim] = deepSAD.ae_results
with open(results_path, "wb") as f:
pickle.dump(dim_results, f)
logger.info(f"Finished testing dimension {rep_dim}")
# Clear some memory
del deepSAD
torch.cuda.empty_cache()
# Save all results
results_path = Path(xp_path) / f"ae_elbow_results_{net_name}.pkl"
with open(results_path, "wb") as f:
pickle.dump(elbow_results, f)
logger.info(f"Saved elbow test results to {results_path}")
else:
logger.error(f"Unknown action: {action}")
logger.info(
f"Saved elbow test results for dimension {rep_dim} to {results_path}"
)
else:
logger.error(f"Unknown action: {action}")
if __name__ == "__main__":