Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fcd944d3ff | ||
|
054720dd7b | ||
|
d16a0de202 | ||
|
76fea3f881 | ||
|
c00513ae0d | ||
|
bccef8bef0 | ||
|
29ee326b85 | ||
|
055568dc86 | ||
|
3a7328e290 |
@@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.5.0
|
current_version = 0.5.2
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.1.0
|
rev: v4.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
@@ -23,7 +23,7 @@ repos:
|
|||||||
- id: isort
|
- id: isort
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v0.931
|
rev: v0.950
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
files: prototorch
|
files: prototorch
|
||||||
@@ -42,7 +42,7 @@ repos:
|
|||||||
- id: python-check-blanket-noqa
|
- id: python-check-blanket-noqa
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.31.0
|
rev: v2.32.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ author = "Jensun Ravichandran"
|
|||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
#
|
#
|
||||||
release = "0.5.0"
|
release = "0.5.2"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
@@ -1,12 +1,22 @@
|
|||||||
"""CBC example using the Iris dataset."""
|
"""CBC example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
from prototorch.models import CBC, VisCBC2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -15,11 +25,8 @@ if __name__ == "__main__":
|
|||||||
# Dataset
|
# Dataset
|
||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
|
|
||||||
# Reproducibility
|
|
||||||
pl.utilities.seed.seed_everything(seed=42)
|
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=32)
|
train_loader = DataLoader(train_ds, batch_size=32)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -30,23 +37,30 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.CBC(
|
model = CBC(
|
||||||
hparams,
|
hparams,
|
||||||
components_initializer=pt.initializers.SSCI(train_ds, noise=0.01),
|
components_initializer=pt.initializers.SSCI(train_ds, noise=0.1),
|
||||||
reasonings_iniitializer=pt.initializers.
|
reasonings_initializer=pt.initializers.
|
||||||
PurePositiveReasoningsInitializer(),
|
PurePositiveReasoningsInitializer(),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisCBC2D(data=train_ds,
|
vis = VisCBC2D(
|
||||||
title="CBC Iris Example",
|
data=train_ds,
|
||||||
resolution=100,
|
title="CBC Iris Example",
|
||||||
axis_off=True)
|
resolution=100,
|
||||||
|
axis_off=True,
|
||||||
|
)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
|
vis,
|
||||||
|
],
|
||||||
|
detect_anomaly=True,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
max_epochs=1000,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,12 +1,29 @@
|
|||||||
"""Dynamically prune 'loser' prototypes in GLVQ-type models."""
|
"""Dynamically prune 'loser' prototypes in GLVQ-type models."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
CELVQ,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisGLVQ2D,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -16,15 +33,17 @@ if __name__ == "__main__":
|
|||||||
num_classes = 4
|
num_classes = 4
|
||||||
num_features = 2
|
num_features = 2
|
||||||
num_clusters = 1
|
num_clusters = 1
|
||||||
train_ds = pt.datasets.Random(num_samples=500,
|
train_ds = pt.datasets.Random(
|
||||||
num_classes=num_classes,
|
num_samples=500,
|
||||||
num_features=num_features,
|
num_classes=num_classes,
|
||||||
num_clusters=num_clusters,
|
num_features=num_features,
|
||||||
separation=3.0,
|
num_clusters=num_clusters,
|
||||||
seed=42)
|
separation=3.0,
|
||||||
|
seed=42,
|
||||||
|
)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=256)
|
train_loader = DataLoader(train_ds, batch_size=256)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
prototypes_per_class = num_clusters * 5
|
prototypes_per_class = num_clusters * 5
|
||||||
@@ -34,7 +53,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.CELVQ(
|
model = CELVQ(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.FVCI(2, 3.0),
|
prototypes_initializer=pt.initializers.FVCI(2, 3.0),
|
||||||
)
|
)
|
||||||
@@ -43,18 +62,18 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(train_ds)
|
vis = VisGLVQ2D(train_ds)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.01, # prune prototype if it wins less than 1%
|
threshold=0.01, # prune prototype if it wins less than 1%
|
||||||
idle_epochs=20, # pruning too early may cause problems
|
idle_epochs=20, # pruning too early may cause problems
|
||||||
prune_quota_per_epoch=2, # prune at most 2 prototypes per epoch
|
prune_quota_per_epoch=2, # prune at most 2 prototypes per epoch
|
||||||
frequency=1, # prune every epoch
|
frequency=1, # prune every epoch
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_loss",
|
monitor="train_loss",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=20,
|
patience=20,
|
||||||
@@ -71,10 +90,9 @@ if __name__ == "__main__":
|
|||||||
pruning,
|
pruning,
|
||||||
es,
|
es,
|
||||||
],
|
],
|
||||||
progress_bar_refresh_rate=0,
|
detect_anomaly=True,
|
||||||
terminate_on_nan=True,
|
log_every_n_steps=1,
|
||||||
weights_summary="full",
|
max_epochs=1000,
|
||||||
accelerator="ddp",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,13 +1,24 @@
|
|||||||
"""GLVQ example using the Iris dataset."""
|
"""GLVQ example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import GLVQ, VisGLVQ2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
from torch.optim.lr_scheduler import ExponentialLR
|
from torch.optim.lr_scheduler import ExponentialLR
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -17,7 +28,7 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=64)
|
train_loader = DataLoader(train_ds, batch_size=64, num_workers=4)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -29,7 +40,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GLVQ(
|
model = GLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
@@ -41,14 +52,17 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
accelerator="ddp",
|
],
|
||||||
|
max_epochs=100,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
@@ -58,8 +72,8 @@ if __name__ == "__main__":
|
|||||||
trainer.save_checkpoint("./glvq_iris.ckpt")
|
trainer.save_checkpoint("./glvq_iris.ckpt")
|
||||||
|
|
||||||
# Load saved model
|
# Load saved model
|
||||||
new_model = pt.models.GLVQ.load_from_checkpoint(
|
new_model = GLVQ.load_from_checkpoint(
|
||||||
checkpoint_path="./glvq_iris.ckpt",
|
checkpoint_path="./glvq_iris.ckpt",
|
||||||
strict=False,
|
strict=False,
|
||||||
)
|
)
|
||||||
print(new_model)
|
logging.info(new_model)
|
||||||
|
@@ -1,13 +1,25 @@
|
|||||||
"""GMLVQ example using the Iris dataset."""
|
"""GMLVQ example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import GMLVQ, VisGMLVQ2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
from torch.optim.lr_scheduler import ExponentialLR
|
from torch.optim.lr_scheduler import ExponentialLR
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -17,7 +29,7 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris()
|
train_ds = pt.datasets.Iris()
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=64)
|
train_loader = DataLoader(train_ds, batch_size=64)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -32,7 +44,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GMLVQ(
|
model = GMLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
@@ -44,14 +56,17 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 4)
|
model.example_input_array = torch.zeros(4, 4)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGMLVQ2D(data=train_ds)
|
vis = VisGMLVQ2D(data=train_ds)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
accelerator="ddp",
|
],
|
||||||
|
max_epochs=100,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,14 +1,29 @@
|
|||||||
"""GMLVQ example using the MNIST dataset."""
|
"""GMLVQ example using the MNIST dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
ImageGMLVQ,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisImgComp,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
from torchvision import transforms
|
from torchvision import transforms
|
||||||
from torchvision.datasets import MNIST
|
from torchvision.datasets import MNIST
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -33,12 +48,8 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds,
|
train_loader = DataLoader(train_ds, num_workers=4, batch_size=256)
|
||||||
num_workers=0,
|
test_loader = DataLoader(test_ds, num_workers=4, batch_size=256)
|
||||||
batch_size=256)
|
|
||||||
test_loader = torch.utils.data.DataLoader(test_ds,
|
|
||||||
num_workers=0,
|
|
||||||
batch_size=256)
|
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
num_classes = 10
|
num_classes = 10
|
||||||
@@ -52,14 +63,14 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.ImageGMLVQ(
|
model = ImageGMLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisImgComp(
|
vis = VisImgComp(
|
||||||
data=train_ds,
|
data=train_ds,
|
||||||
num_columns=10,
|
num_columns=10,
|
||||||
show=False,
|
show=False,
|
||||||
@@ -69,14 +80,14 @@ if __name__ == "__main__":
|
|||||||
embedding_data=200,
|
embedding_data=200,
|
||||||
flatten_data=False,
|
flatten_data=False,
|
||||||
)
|
)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.01,
|
threshold=0.01,
|
||||||
idle_epochs=1,
|
idle_epochs=1,
|
||||||
prune_quota_per_epoch=10,
|
prune_quota_per_epoch=10,
|
||||||
frequency=1,
|
frequency=1,
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_loss",
|
monitor="train_loss",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=15,
|
patience=15,
|
||||||
@@ -90,11 +101,11 @@ if __name__ == "__main__":
|
|||||||
callbacks=[
|
callbacks=[
|
||||||
vis,
|
vis,
|
||||||
pruning,
|
pruning,
|
||||||
# es,
|
es,
|
||||||
],
|
],
|
||||||
terminate_on_nan=True,
|
max_epochs=1000,
|
||||||
weights_summary=None,
|
log_every_n_steps=1,
|
||||||
# accelerator="ddp",
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,12 +1,28 @@
|
|||||||
"""GMLVQ example using the spiral dataset."""
|
"""GMLVQ example using the spiral dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
GMLVQ,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisGLVQ2D,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -16,7 +32,7 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Spiral(num_samples=500, noise=0.5)
|
train_ds = pt.datasets.Spiral(num_samples=500, noise=0.5)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=256)
|
train_loader = DataLoader(train_ds, batch_size=256)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
num_classes = 2
|
num_classes = 2
|
||||||
@@ -32,19 +48,19 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GMLVQ(
|
model = GMLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=1e-2),
|
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=1e-2),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(
|
vis = VisGLVQ2D(
|
||||||
train_ds,
|
train_ds,
|
||||||
show_last_only=False,
|
show_last_only=False,
|
||||||
block=False,
|
block=False,
|
||||||
)
|
)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.01,
|
threshold=0.01,
|
||||||
idle_epochs=10,
|
idle_epochs=10,
|
||||||
prune_quota_per_epoch=5,
|
prune_quota_per_epoch=5,
|
||||||
@@ -53,7 +69,7 @@ if __name__ == "__main__":
|
|||||||
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=1e-1),
|
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=1e-1),
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_loss",
|
monitor="train_loss",
|
||||||
min_delta=1.0,
|
min_delta=1.0,
|
||||||
patience=5,
|
patience=5,
|
||||||
@@ -69,7 +85,9 @@ if __name__ == "__main__":
|
|||||||
es,
|
es,
|
||||||
pruning,
|
pruning,
|
||||||
],
|
],
|
||||||
terminate_on_nan=True,
|
max_epochs=1000,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,19 @@
|
|||||||
"""Growing Neural Gas example using the Iris dataset."""
|
"""Growing Neural Gas example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import GrowingNeuralGas, VisNG2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@@ -13,11 +22,11 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=42)
|
seed_everything(seed=42)
|
||||||
|
|
||||||
# Prepare the data
|
# Prepare the data
|
||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=64)
|
train_loader = DataLoader(train_ds, batch_size=64)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -27,7 +36,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GrowingNeuralGas(
|
model = GrowingNeuralGas(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.ZCI(2),
|
prototypes_initializer=pt.initializers.ZCI(2),
|
||||||
)
|
)
|
||||||
@@ -36,17 +45,20 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Model summary
|
# Model summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisNG2D(data=train_loader)
|
vis = VisNG2D(data=train_loader)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
|
callbacks=[
|
||||||
|
vis,
|
||||||
|
],
|
||||||
max_epochs=100,
|
max_epochs=100,
|
||||||
callbacks=[vis],
|
log_every_n_steps=1,
|
||||||
weights_summary="full",
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,14 +1,30 @@
|
|||||||
"""GTLVQ example using the MNIST dataset."""
|
"""GTLVQ example using the MNIST dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
ImageGTLVQ,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisImgComp,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
from torchvision import transforms
|
from torchvision import transforms
|
||||||
from torchvision.datasets import MNIST
|
from torchvision.datasets import MNIST
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -33,12 +49,8 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds,
|
train_loader = DataLoader(train_ds, num_workers=0, batch_size=256)
|
||||||
num_workers=0,
|
test_loader = DataLoader(test_ds, num_workers=0, batch_size=256)
|
||||||
batch_size=256)
|
|
||||||
test_loader = torch.utils.data.DataLoader(test_ds,
|
|
||||||
num_workers=0,
|
|
||||||
batch_size=256)
|
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
num_classes = 10
|
num_classes = 10
|
||||||
@@ -52,7 +64,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.ImageGTLVQ(
|
model = ImageGTLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
@@ -61,7 +73,7 @@ if __name__ == "__main__":
|
|||||||
next(iter(train_loader))[0].reshape(256, 28 * 28)))
|
next(iter(train_loader))[0].reshape(256, 28 * 28)))
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisImgComp(
|
vis = VisImgComp(
|
||||||
data=train_ds,
|
data=train_ds,
|
||||||
num_columns=10,
|
num_columns=10,
|
||||||
show=False,
|
show=False,
|
||||||
@@ -71,14 +83,14 @@ if __name__ == "__main__":
|
|||||||
embedding_data=200,
|
embedding_data=200,
|
||||||
flatten_data=False,
|
flatten_data=False,
|
||||||
)
|
)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.01,
|
threshold=0.01,
|
||||||
idle_epochs=1,
|
idle_epochs=1,
|
||||||
prune_quota_per_epoch=10,
|
prune_quota_per_epoch=10,
|
||||||
frequency=1,
|
frequency=1,
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_loss",
|
monitor="train_loss",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=15,
|
patience=15,
|
||||||
@@ -93,11 +105,11 @@ if __name__ == "__main__":
|
|||||||
callbacks=[
|
callbacks=[
|
||||||
vis,
|
vis,
|
||||||
pruning,
|
pruning,
|
||||||
# es,
|
es,
|
||||||
],
|
],
|
||||||
terminate_on_nan=True,
|
max_epochs=1000,
|
||||||
weights_summary=None,
|
log_every_n_steps=1,
|
||||||
accelerator="ddp",
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,20 @@
|
|||||||
"""Localized-GTLVQ example using the Moons dataset."""
|
"""Localized-GTLVQ example using the Moons dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import GTLVQ, VisGLVQ2D
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@@ -13,33 +23,35 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=2)
|
seed_everything(seed=2)
|
||||||
|
|
||||||
# Dataset
|
# Dataset
|
||||||
train_ds = pt.datasets.Moons(num_samples=300, noise=0.2, seed=42)
|
train_ds = pt.datasets.Moons(num_samples=300, noise=0.2, seed=42)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds,
|
train_loader = DataLoader(
|
||||||
batch_size=256,
|
train_ds,
|
||||||
shuffle=True)
|
batch_size=256,
|
||||||
|
shuffle=True,
|
||||||
|
)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
# Latent_dim should be lower than input dim.
|
# Latent_dim should be lower than input dim.
|
||||||
hparams = dict(distribution=[1, 3], input_dim=2, latent_dim=1)
|
hparams = dict(distribution=[1, 3], input_dim=2, latent_dim=1)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GTLVQ(
|
model = GTLVQ(hparams,
|
||||||
hparams, prototypes_initializer=pt.initializers.SMCI(train_ds))
|
prototypes_initializer=pt.initializers.SMCI(train_ds))
|
||||||
|
|
||||||
# Compute intermediate input and output sizes
|
# Compute intermediate input and output sizes
|
||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_acc",
|
monitor="train_acc",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=20,
|
patience=20,
|
||||||
@@ -55,8 +67,9 @@ if __name__ == "__main__":
|
|||||||
vis,
|
vis,
|
||||||
es,
|
es,
|
||||||
],
|
],
|
||||||
weights_summary="full",
|
max_epochs=1000,
|
||||||
accelerator="ddp",
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,12 +1,19 @@
|
|||||||
"""k-NN example using the Iris dataset from scikit-learn."""
|
"""k-NN example using the Iris dataset from scikit-learn."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import KNN, VisGLVQ2D
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
from sklearn.datasets import load_iris
|
from sklearn.datasets import load_iris
|
||||||
from sklearn.model_selection import train_test_split
|
from sklearn.model_selection import train_test_split
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@@ -16,34 +23,36 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Dataset
|
# Dataset
|
||||||
X, y = load_iris(return_X_y=True)
|
X, y = load_iris(return_X_y=True)
|
||||||
X = X[:, [0, 2]]
|
X = X[:, 0:3:2]
|
||||||
|
|
||||||
X_train, X_test, y_train, y_test = train_test_split(X,
|
X_train, X_test, y_train, y_test = train_test_split(
|
||||||
y,
|
X,
|
||||||
test_size=0.5,
|
y,
|
||||||
random_state=42)
|
test_size=0.5,
|
||||||
|
random_state=42,
|
||||||
|
)
|
||||||
|
|
||||||
train_ds = pt.datasets.NumpyDataset(X_train, y_train)
|
train_ds = pt.datasets.NumpyDataset(X_train, y_train)
|
||||||
test_ds = pt.datasets.NumpyDataset(X_test, y_test)
|
test_ds = pt.datasets.NumpyDataset(X_test, y_test)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=16)
|
train_loader = DataLoader(train_ds, batch_size=16)
|
||||||
test_loader = torch.utils.data.DataLoader(test_ds, batch_size=16)
|
test_loader = DataLoader(test_ds, batch_size=16)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(k=5)
|
hparams = dict(k=5)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.KNN(hparams, data=train_ds)
|
model = KNN(hparams, data=train_ds)
|
||||||
|
|
||||||
# Compute intermediate input and output sizes
|
# Compute intermediate input and output sizes
|
||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(
|
vis = VisGLVQ2D(
|
||||||
data=(X_train, y_train),
|
data=(X_train, y_train),
|
||||||
resolution=200,
|
resolution=200,
|
||||||
block=True,
|
block=True,
|
||||||
@@ -53,8 +62,11 @@ if __name__ == "__main__":
|
|||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
max_epochs=1,
|
max_epochs=1,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
|
],
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
@@ -63,7 +75,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Recall
|
# Recall
|
||||||
y_pred = model.predict(torch.tensor(X_train))
|
y_pred = model.predict(torch.tensor(X_train))
|
||||||
print(y_pred)
|
logging.info(y_pred)
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
trainer.test(model, dataloaders=test_loader)
|
trainer.test(model, dataloaders=test_loader)
|
||||||
|
@@ -1,12 +1,21 @@
|
|||||||
"""Kohonen Self Organizing Map."""
|
"""Kohonen Self Organizing Map."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
from prototorch.models import KohonenSOM
|
||||||
from prototorch.utils.colors import hex_to_rgb
|
from prototorch.utils.colors import hex_to_rgb
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader, TensorDataset
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
|
|
||||||
class Vis2DColorSOM(pl.Callback):
|
class Vis2DColorSOM(pl.Callback):
|
||||||
@@ -18,7 +27,7 @@ class Vis2DColorSOM(pl.Callback):
|
|||||||
self.data = data
|
self.data = data
|
||||||
self.pause_time = pause_time
|
self.pause_time = pause_time
|
||||||
|
|
||||||
def on_epoch_end(self, trainer, pl_module):
|
def on_train_epoch_end(self, trainer, pl_module: KohonenSOM):
|
||||||
ax = self.fig.gca()
|
ax = self.fig.gca()
|
||||||
ax.cla()
|
ax.cla()
|
||||||
ax.set_title(self.title)
|
ax.set_title(self.title)
|
||||||
@@ -31,12 +40,14 @@ class Vis2DColorSOM(pl.Callback):
|
|||||||
d = pl_module.compute_distances(self.data)
|
d = pl_module.compute_distances(self.data)
|
||||||
wp = pl_module.predict_from_distances(d)
|
wp = pl_module.predict_from_distances(d)
|
||||||
for i, iloc in enumerate(wp):
|
for i, iloc in enumerate(wp):
|
||||||
plt.text(iloc[1],
|
plt.text(
|
||||||
iloc[0],
|
iloc[1],
|
||||||
cnames[i],
|
iloc[0],
|
||||||
ha="center",
|
color_names[i],
|
||||||
va="center",
|
ha="center",
|
||||||
bbox=dict(facecolor="white", alpha=0.5, lw=0))
|
va="center",
|
||||||
|
bbox=dict(facecolor="white", alpha=0.5, lw=0),
|
||||||
|
)
|
||||||
|
|
||||||
if trainer.current_epoch != trainer.max_epochs - 1:
|
if trainer.current_epoch != trainer.max_epochs - 1:
|
||||||
plt.pause(self.pause_time)
|
plt.pause(self.pause_time)
|
||||||
@@ -51,7 +62,7 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=42)
|
seed_everything(seed=42)
|
||||||
|
|
||||||
# Prepare the data
|
# Prepare the data
|
||||||
hex_colors = [
|
hex_colors = [
|
||||||
@@ -59,15 +70,15 @@ if __name__ == "__main__":
|
|||||||
"#00ff00", "#ff0000", "#00ffff", "#ff00ff", "#ffff00", "#ffffff",
|
"#00ff00", "#ff0000", "#00ffff", "#ff00ff", "#ffff00", "#ffffff",
|
||||||
"#545454", "#7f7f7f", "#a8a8a8", "#808000", "#800080", "#ffa500"
|
"#545454", "#7f7f7f", "#a8a8a8", "#808000", "#800080", "#ffa500"
|
||||||
]
|
]
|
||||||
cnames = [
|
color_names = [
|
||||||
"black", "blue", "darkblue", "skyblue", "greyblue", "lilac", "green",
|
"black", "blue", "darkblue", "skyblue", "greyblue", "lilac", "green",
|
||||||
"red", "cyan", "magenta", "yellow", "white", "darkgrey", "mediumgrey",
|
"red", "cyan", "magenta", "yellow", "white", "darkgrey", "mediumgrey",
|
||||||
"lightgrey", "olive", "purple", "orange"
|
"lightgrey", "olive", "purple", "orange"
|
||||||
]
|
]
|
||||||
colors = list(hex_to_rgb(hex_colors))
|
colors = list(hex_to_rgb(hex_colors))
|
||||||
data = torch.Tensor(colors) / 255.0
|
data = torch.Tensor(colors) / 255.0
|
||||||
train_ds = torch.utils.data.TensorDataset(data)
|
train_ds = TensorDataset(data)
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=8)
|
train_loader = DataLoader(train_ds, batch_size=8)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -78,7 +89,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.KohonenSOM(
|
model = KohonenSOM(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.RNCI(3),
|
prototypes_initializer=pt.initializers.RNCI(3),
|
||||||
)
|
)
|
||||||
@@ -87,7 +98,7 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 3)
|
model.example_input_array = torch.zeros(4, 3)
|
||||||
|
|
||||||
# Model summary
|
# Model summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = Vis2DColorSOM(data=data)
|
vis = Vis2DColorSOM(data=data)
|
||||||
@@ -96,8 +107,11 @@ if __name__ == "__main__":
|
|||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
max_epochs=500,
|
max_epochs=500,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
|
],
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,20 @@
|
|||||||
"""Localized-GMLVQ example using the Moons dataset."""
|
"""Localized-GMLVQ example using the Moons dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import LGMLVQ, VisGLVQ2D
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@@ -13,15 +23,13 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=2)
|
seed_everything(seed=2)
|
||||||
|
|
||||||
# Dataset
|
# Dataset
|
||||||
train_ds = pt.datasets.Moons(num_samples=300, noise=0.2, seed=42)
|
train_ds = pt.datasets.Moons(num_samples=300, noise=0.2, seed=42)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds,
|
train_loader = DataLoader(train_ds, batch_size=256, shuffle=True)
|
||||||
batch_size=256,
|
|
||||||
shuffle=True)
|
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -31,7 +39,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.LGMLVQ(
|
model = LGMLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
)
|
)
|
||||||
@@ -40,11 +48,11 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
print(model)
|
logging.info(model)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_acc",
|
monitor="train_acc",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=20,
|
patience=20,
|
||||||
@@ -60,8 +68,9 @@ if __name__ == "__main__":
|
|||||||
vis,
|
vis,
|
||||||
es,
|
es,
|
||||||
],
|
],
|
||||||
weights_summary="full",
|
log_every_n_steps=1,
|
||||||
accelerator="ddp",
|
max_epochs=1000,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,22 @@
|
|||||||
"""LVQMLN example using all four dimensions of the Iris dataset."""
|
"""LVQMLN example using all four dimensions of the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
LVQMLN,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisSiameseGLVQ2D,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
|
|
||||||
class Backbone(torch.nn.Module):
|
class Backbone(torch.nn.Module):
|
||||||
@@ -34,10 +46,10 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris()
|
train_ds = pt.datasets.Iris()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=42)
|
seed_everything(seed=42)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=150)
|
train_loader = DataLoader(train_ds, batch_size=150)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -50,7 +62,7 @@ if __name__ == "__main__":
|
|||||||
backbone = Backbone()
|
backbone = Backbone()
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.LVQMLN(
|
model = LVQMLN(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.SSCI(
|
prototypes_initializer=pt.initializers.SSCI(
|
||||||
train_ds,
|
train_ds,
|
||||||
@@ -59,18 +71,15 @@ if __name__ == "__main__":
|
|||||||
backbone=backbone,
|
backbone=backbone,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Model summary
|
|
||||||
print(model)
|
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisSiameseGLVQ2D(
|
vis = VisSiameseGLVQ2D(
|
||||||
data=train_ds,
|
data=train_ds,
|
||||||
map_protos=False,
|
map_protos=False,
|
||||||
border=0.1,
|
border=0.1,
|
||||||
resolution=500,
|
resolution=500,
|
||||||
axis_off=True,
|
axis_off=True,
|
||||||
)
|
)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.01,
|
threshold=0.01,
|
||||||
idle_epochs=20,
|
idle_epochs=20,
|
||||||
prune_quota_per_epoch=2,
|
prune_quota_per_epoch=2,
|
||||||
@@ -85,6 +94,9 @@ if __name__ == "__main__":
|
|||||||
vis,
|
vis,
|
||||||
pruning,
|
pruning,
|
||||||
],
|
],
|
||||||
|
log_every_n_steps=1,
|
||||||
|
max_epochs=1000,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,12 +1,23 @@
|
|||||||
"""Median-LVQ example using the Iris dataset."""
|
"""Median-LVQ example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import MedianLVQ, VisGLVQ2D
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -16,13 +27,13 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(
|
train_loader = DataLoader(
|
||||||
train_ds,
|
train_ds,
|
||||||
batch_size=len(train_ds), # MedianLVQ cannot handle mini-batches
|
batch_size=len(train_ds), # MedianLVQ cannot handle mini-batches
|
||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.MedianLVQ(
|
model = MedianLVQ(
|
||||||
hparams=dict(distribution=(3, 2), lr=0.01),
|
hparams=dict(distribution=(3, 2), lr=0.01),
|
||||||
prototypes_initializer=pt.initializers.SSCI(train_ds),
|
prototypes_initializer=pt.initializers.SSCI(train_ds),
|
||||||
)
|
)
|
||||||
@@ -31,8 +42,8 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_acc",
|
monitor="train_acc",
|
||||||
min_delta=0.01,
|
min_delta=0.01,
|
||||||
patience=5,
|
patience=5,
|
||||||
@@ -44,8 +55,13 @@ if __name__ == "__main__":
|
|||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis, es],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
|
es,
|
||||||
|
],
|
||||||
|
max_epochs=1000,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,15 +1,26 @@
|
|||||||
"""Neural Gas example using the Iris dataset."""
|
"""Neural Gas example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import NeuralGas, VisNG2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
from sklearn.datasets import load_iris
|
from sklearn.datasets import load_iris
|
||||||
from sklearn.preprocessing import StandardScaler
|
from sklearn.preprocessing import StandardScaler
|
||||||
from torch.optim.lr_scheduler import ExponentialLR
|
from torch.optim.lr_scheduler import ExponentialLR
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
|
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -17,7 +28,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Prepare and pre-process the dataset
|
# Prepare and pre-process the dataset
|
||||||
x_train, y_train = load_iris(return_X_y=True)
|
x_train, y_train = load_iris(return_X_y=True)
|
||||||
x_train = x_train[:, [0, 2]]
|
x_train = x_train[:, 0:3:2]
|
||||||
scaler = StandardScaler()
|
scaler = StandardScaler()
|
||||||
scaler.fit(x_train)
|
scaler.fit(x_train)
|
||||||
x_train = scaler.transform(x_train)
|
x_train = scaler.transform(x_train)
|
||||||
@@ -25,7 +36,7 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.NumpyDataset(x_train, y_train)
|
train_ds = pt.datasets.NumpyDataset(x_train, y_train)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=150)
|
train_loader = DataLoader(train_ds, batch_size=150)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -35,7 +46,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.NeuralGas(
|
model = NeuralGas(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.core.ZCI(2),
|
prototypes_initializer=pt.core.ZCI(2),
|
||||||
lr_scheduler=ExponentialLR,
|
lr_scheduler=ExponentialLR,
|
||||||
@@ -45,17 +56,18 @@ if __name__ == "__main__":
|
|||||||
# Compute intermediate input and output sizes
|
# Compute intermediate input and output sizes
|
||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Model summary
|
|
||||||
print(model)
|
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisNG2D(data=train_ds)
|
vis = VisNG2D(data=train_ds)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
weights_summary="full",
|
vis,
|
||||||
|
],
|
||||||
|
max_epochs=1000,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,18 @@
|
|||||||
"""RSLVQ example using the Iris dataset."""
|
"""RSLVQ example using the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import RSLVQ, VisGLVQ2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@@ -13,13 +21,13 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=42)
|
seed_everything(seed=42)
|
||||||
|
|
||||||
# Dataset
|
# Dataset
|
||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=64)
|
train_loader = DataLoader(train_ds, batch_size=64)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -33,7 +41,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.RSLVQ(
|
model = RSLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=0.2),
|
prototypes_initializer=pt.initializers.SSCI(train_ds, noise=0.2),
|
||||||
@@ -42,19 +50,18 @@ if __name__ == "__main__":
|
|||||||
# Compute intermediate input and output sizes
|
# Compute intermediate input and output sizes
|
||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Summary
|
|
||||||
print(model)
|
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
terminate_on_nan=True,
|
vis,
|
||||||
weights_summary="full",
|
],
|
||||||
accelerator="ddp",
|
detect_anomaly=True,
|
||||||
|
max_epochs=100,
|
||||||
|
log_every_n_steps=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,18 @@
|
|||||||
"""Siamese GLVQ example using all four dimensions of the Iris dataset."""
|
"""Siamese GLVQ example using all four dimensions of the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import SiameseGLVQ, VisSiameseGLVQ2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
|
|
||||||
class Backbone(torch.nn.Module):
|
class Backbone(torch.nn.Module):
|
||||||
@@ -34,10 +42,10 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris()
|
train_ds = pt.datasets.Iris()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=2)
|
seed_everything(seed=2)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=150)
|
train_loader = DataLoader(train_ds, batch_size=150)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(
|
hparams = dict(
|
||||||
@@ -50,23 +58,25 @@ if __name__ == "__main__":
|
|||||||
backbone = Backbone()
|
backbone = Backbone()
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.SiameseGLVQ(
|
model = SiameseGLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
backbone=backbone,
|
backbone=backbone,
|
||||||
both_path_gradients=False,
|
both_path_gradients=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Model summary
|
|
||||||
print(model)
|
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisSiameseGLVQ2D(data=train_ds, border=0.1)
|
vis = VisSiameseGLVQ2D(data=train_ds, border=0.1)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
|
vis,
|
||||||
|
],
|
||||||
|
max_epochs=1000,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,10 +1,18 @@
|
|||||||
"""Siamese GTLVQ example using all four dimensions of the Iris dataset."""
|
"""Siamese GTLVQ example using all four dimensions of the Iris dataset."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import SiameseGTLVQ, VisSiameseGLVQ2D
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning)
|
||||||
|
|
||||||
|
|
||||||
class Backbone(torch.nn.Module):
|
class Backbone(torch.nn.Module):
|
||||||
@@ -34,39 +42,43 @@ if __name__ == "__main__":
|
|||||||
train_ds = pt.datasets.Iris()
|
train_ds = pt.datasets.Iris()
|
||||||
|
|
||||||
# Reproducibility
|
# Reproducibility
|
||||||
pl.utilities.seed.seed_everything(seed=2)
|
seed_everything(seed=2)
|
||||||
|
|
||||||
# Dataloaders
|
# Dataloaders
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=150)
|
train_loader = DataLoader(train_ds, batch_size=150)
|
||||||
|
|
||||||
# Hyperparameters
|
# Hyperparameters
|
||||||
hparams = dict(distribution=[1, 2, 3],
|
hparams = dict(
|
||||||
proto_lr=0.01,
|
distribution=[1, 2, 3],
|
||||||
bb_lr=0.01,
|
proto_lr=0.01,
|
||||||
input_dim=2,
|
bb_lr=0.01,
|
||||||
latent_dim=1)
|
input_dim=2,
|
||||||
|
latent_dim=1,
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize the backbone
|
# Initialize the backbone
|
||||||
backbone = Backbone(latent_size=hparams["input_dim"])
|
backbone = Backbone(latent_size=hparams["input_dim"])
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.SiameseGTLVQ(
|
model = SiameseGTLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
prototypes_initializer=pt.initializers.SMCI(train_ds),
|
||||||
backbone=backbone,
|
backbone=backbone,
|
||||||
both_path_gradients=False,
|
both_path_gradients=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Model summary
|
|
||||||
print(model)
|
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisSiameseGLVQ2D(data=train_ds, border=0.1)
|
vis = VisSiameseGLVQ2D(data=train_ds, border=0.1)
|
||||||
|
|
||||||
# Setup trainer
|
# Setup trainer
|
||||||
trainer = pl.Trainer.from_argparse_args(
|
trainer = pl.Trainer.from_argparse_args(
|
||||||
args,
|
args,
|
||||||
callbacks=[vis],
|
callbacks=[
|
||||||
|
vis,
|
||||||
|
],
|
||||||
|
max_epochs=1000,
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -1,13 +1,30 @@
|
|||||||
"""Warm-starting GLVQ with prototypes from Growing Neural Gas."""
|
"""Warm-starting GLVQ with prototypes from Growing Neural Gas."""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import warnings
|
||||||
|
|
||||||
import prototorch as pt
|
import prototorch as pt
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.models import (
|
||||||
|
GLVQ,
|
||||||
|
KNN,
|
||||||
|
GrowingNeuralGas,
|
||||||
|
PruneLoserPrototypes,
|
||||||
|
VisGLVQ2D,
|
||||||
|
)
|
||||||
|
from pytorch_lightning.callbacks import EarlyStopping
|
||||||
|
from pytorch_lightning.utilities.seed import seed_everything
|
||||||
|
from pytorch_lightning.utilities.warnings import PossibleUserWarning
|
||||||
from torch.optim.lr_scheduler import ExponentialLR
|
from torch.optim.lr_scheduler import ExponentialLR
|
||||||
|
from torch.utils.data import DataLoader
|
||||||
|
|
||||||
|
warnings.filterwarnings("ignore", category=PossibleUserWarning)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# Reproducibility
|
||||||
|
seed_everything(seed=4)
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = pl.Trainer.add_argparse_args(parser)
|
parser = pl.Trainer.add_argparse_args(parser)
|
||||||
@@ -15,10 +32,10 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Prepare the data
|
# Prepare the data
|
||||||
train_ds = pt.datasets.Iris(dims=[0, 2])
|
train_ds = pt.datasets.Iris(dims=[0, 2])
|
||||||
train_loader = torch.utils.data.DataLoader(train_ds, batch_size=64)
|
train_loader = DataLoader(train_ds, batch_size=64, num_workers=0)
|
||||||
|
|
||||||
# Initialize the gng
|
# Initialize the gng
|
||||||
gng = pt.models.GrowingNeuralGas(
|
gng = GrowingNeuralGas(
|
||||||
hparams=dict(num_prototypes=5, insert_freq=2, lr=0.1),
|
hparams=dict(num_prototypes=5, insert_freq=2, lr=0.1),
|
||||||
prototypes_initializer=pt.initializers.ZCI(2),
|
prototypes_initializer=pt.initializers.ZCI(2),
|
||||||
lr_scheduler=ExponentialLR,
|
lr_scheduler=ExponentialLR,
|
||||||
@@ -26,7 +43,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="loss",
|
monitor="loss",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=20,
|
patience=20,
|
||||||
@@ -37,9 +54,12 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Setup trainer for GNG
|
# Setup trainer for GNG
|
||||||
trainer = pl.Trainer(
|
trainer = pl.Trainer(
|
||||||
max_epochs=100,
|
max_epochs=1000,
|
||||||
callbacks=[es],
|
callbacks=[
|
||||||
weights_summary=None,
|
es,
|
||||||
|
],
|
||||||
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
@@ -52,12 +72,12 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Warm-start prototypes
|
# Warm-start prototypes
|
||||||
knn = pt.models.KNN(dict(k=1), data=train_ds)
|
knn = KNN(dict(k=1), data=train_ds)
|
||||||
prototypes = gng.prototypes
|
prototypes = gng.prototypes
|
||||||
plabels = knn.predict(prototypes)
|
plabels = knn.predict(prototypes)
|
||||||
|
|
||||||
# Initialize the model
|
# Initialize the model
|
||||||
model = pt.models.GLVQ(
|
model = GLVQ(
|
||||||
hparams,
|
hparams,
|
||||||
optimizer=torch.optim.Adam,
|
optimizer=torch.optim.Adam,
|
||||||
prototypes_initializer=pt.initializers.LCI(prototypes),
|
prototypes_initializer=pt.initializers.LCI(prototypes),
|
||||||
@@ -70,15 +90,15 @@ if __name__ == "__main__":
|
|||||||
model.example_input_array = torch.zeros(4, 2)
|
model.example_input_array = torch.zeros(4, 2)
|
||||||
|
|
||||||
# Callbacks
|
# Callbacks
|
||||||
vis = pt.models.VisGLVQ2D(data=train_ds)
|
vis = VisGLVQ2D(data=train_ds)
|
||||||
pruning = pt.models.PruneLoserPrototypes(
|
pruning = PruneLoserPrototypes(
|
||||||
threshold=0.02,
|
threshold=0.02,
|
||||||
idle_epochs=2,
|
idle_epochs=2,
|
||||||
prune_quota_per_epoch=5,
|
prune_quota_per_epoch=5,
|
||||||
frequency=1,
|
frequency=1,
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
es = pl.callbacks.EarlyStopping(
|
es = EarlyStopping(
|
||||||
monitor="train_loss",
|
monitor="train_loss",
|
||||||
min_delta=0.001,
|
min_delta=0.001,
|
||||||
patience=10,
|
patience=10,
|
||||||
@@ -95,8 +115,9 @@ if __name__ == "__main__":
|
|||||||
pruning,
|
pruning,
|
||||||
es,
|
es,
|
||||||
],
|
],
|
||||||
weights_summary="full",
|
max_epochs=1000,
|
||||||
accelerator="ddp",
|
log_every_n_steps=1,
|
||||||
|
detect_anomaly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Training loop
|
# Training loop
|
||||||
|
@@ -36,4 +36,4 @@ from .unsupervised import (
|
|||||||
)
|
)
|
||||||
from .vis import *
|
from .vis import *
|
||||||
|
|
||||||
__version__ = "0.5.0"
|
__version__ = "0.5.2"
|
||||||
|
@@ -1,15 +1,24 @@
|
|||||||
"""Abstract classes to be inherited by prototorch models."""
|
"""Abstract classes to be inherited by prototorch models."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
import torch.nn.functional as F
|
||||||
import torchmetrics
|
import torchmetrics
|
||||||
|
from prototorch.core.competitions import WTAC
|
||||||
from ..core.competitions import WTAC
|
from prototorch.core.components import (
|
||||||
from ..core.components import Components, LabeledComponents
|
AbstractComponents,
|
||||||
from ..core.distances import euclidean_distance
|
Components,
|
||||||
from ..core.initializers import LabelsInitializer, ZerosCompInitializer
|
LabeledComponents,
|
||||||
from ..core.pooling import stratified_min_pooling
|
)
|
||||||
from ..nn.wrappers import LambdaLayer
|
from prototorch.core.distances import euclidean_distance
|
||||||
|
from prototorch.core.initializers import (
|
||||||
|
LabelsInitializer,
|
||||||
|
ZerosCompInitializer,
|
||||||
|
)
|
||||||
|
from prototorch.core.pooling import stratified_min_pooling
|
||||||
|
from prototorch.nn.wrappers import LambdaLayer
|
||||||
|
|
||||||
|
|
||||||
class ProtoTorchBolt(pl.LightningModule):
|
class ProtoTorchBolt(pl.LightningModule):
|
||||||
@@ -30,7 +39,7 @@ class ProtoTorchBolt(pl.LightningModule):
|
|||||||
self.lr_scheduler_kwargs = kwargs.get("lr_scheduler_kwargs", dict())
|
self.lr_scheduler_kwargs = kwargs.get("lr_scheduler_kwargs", dict())
|
||||||
|
|
||||||
def configure_optimizers(self):
|
def configure_optimizers(self):
|
||||||
optimizer = self.optimizer(self.parameters(), lr=self.hparams.lr)
|
optimizer = self.optimizer(self.parameters(), lr=self.hparams["lr"])
|
||||||
if self.lr_scheduler is not None:
|
if self.lr_scheduler is not None:
|
||||||
scheduler = self.lr_scheduler(optimizer,
|
scheduler = self.lr_scheduler(optimizer,
|
||||||
**self.lr_scheduler_kwargs)
|
**self.lr_scheduler_kwargs)
|
||||||
@@ -43,7 +52,10 @@ class ProtoTorchBolt(pl.LightningModule):
|
|||||||
return optimizer
|
return optimizer
|
||||||
|
|
||||||
def reconfigure_optimizers(self):
|
def reconfigure_optimizers(self):
|
||||||
self.trainer.strategy.setup_optimizers(self.trainer)
|
if self.trainer:
|
||||||
|
self.trainer.strategy.setup_optimizers(self.trainer)
|
||||||
|
else:
|
||||||
|
logging.warning("No trainer to reconfigure optimizers!")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
surep = super().__repr__()
|
surep = super().__repr__()
|
||||||
@@ -53,6 +65,7 @@ class ProtoTorchBolt(pl.LightningModule):
|
|||||||
|
|
||||||
|
|
||||||
class PrototypeModel(ProtoTorchBolt):
|
class PrototypeModel(ProtoTorchBolt):
|
||||||
|
proto_layer: AbstractComponents
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
@@ -75,16 +88,17 @@ class PrototypeModel(ProtoTorchBolt):
|
|||||||
|
|
||||||
def add_prototypes(self, *args, **kwargs):
|
def add_prototypes(self, *args, **kwargs):
|
||||||
self.proto_layer.add_components(*args, **kwargs)
|
self.proto_layer.add_components(*args, **kwargs)
|
||||||
self.hparams.distribution = self.proto_layer.distribution
|
self.hparams["distribution"] = self.proto_layer.distribution
|
||||||
self.reconfigure_optimizers()
|
self.reconfigure_optimizers()
|
||||||
|
|
||||||
def remove_prototypes(self, indices):
|
def remove_prototypes(self, indices):
|
||||||
self.proto_layer.remove_components(indices)
|
self.proto_layer.remove_components(indices)
|
||||||
self.hparams.distribution = self.proto_layer.distribution
|
self.hparams["distribution"] = self.proto_layer.distribution
|
||||||
self.reconfigure_optimizers()
|
self.reconfigure_optimizers()
|
||||||
|
|
||||||
|
|
||||||
class UnsupervisedPrototypeModel(PrototypeModel):
|
class UnsupervisedPrototypeModel(PrototypeModel):
|
||||||
|
proto_layer: Components
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
@@ -93,7 +107,7 @@ class UnsupervisedPrototypeModel(PrototypeModel):
|
|||||||
prototypes_initializer = kwargs.get("prototypes_initializer", None)
|
prototypes_initializer = kwargs.get("prototypes_initializer", None)
|
||||||
if prototypes_initializer is not None:
|
if prototypes_initializer is not None:
|
||||||
self.proto_layer = Components(
|
self.proto_layer = Components(
|
||||||
self.hparams.num_prototypes,
|
self.hparams["num_prototypes"],
|
||||||
initializer=prototypes_initializer,
|
initializer=prototypes_initializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -108,6 +122,7 @@ class UnsupervisedPrototypeModel(PrototypeModel):
|
|||||||
|
|
||||||
|
|
||||||
class SupervisedPrototypeModel(PrototypeModel):
|
class SupervisedPrototypeModel(PrototypeModel):
|
||||||
|
proto_layer: LabeledComponents
|
||||||
|
|
||||||
def __init__(self, hparams, skip_proto_layer=False, **kwargs):
|
def __init__(self, hparams, skip_proto_layer=False, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
@@ -127,13 +142,13 @@ class SupervisedPrototypeModel(PrototypeModel):
|
|||||||
labels_initializer=labels_initializer,
|
labels_initializer=labels_initializer,
|
||||||
)
|
)
|
||||||
proto_shape = self.proto_layer.components.shape[1:]
|
proto_shape = self.proto_layer.components.shape[1:]
|
||||||
self.hparams.initialized_proto_shape = proto_shape
|
self.hparams["initialized_proto_shape"] = proto_shape
|
||||||
else:
|
else:
|
||||||
# when restoring a checkpointed model
|
# when restoring a checkpointed model
|
||||||
self.proto_layer = LabeledComponents(
|
self.proto_layer = LabeledComponents(
|
||||||
distribution=distribution,
|
distribution=distribution,
|
||||||
components_initializer=ZerosCompInitializer(
|
components_initializer=ZerosCompInitializer(
|
||||||
self.hparams.initialized_proto_shape),
|
self.hparams["initialized_proto_shape"]),
|
||||||
)
|
)
|
||||||
self.competition_layer = WTAC()
|
self.competition_layer = WTAC()
|
||||||
|
|
||||||
@@ -154,7 +169,7 @@ class SupervisedPrototypeModel(PrototypeModel):
|
|||||||
distances = self.compute_distances(x)
|
distances = self.compute_distances(x)
|
||||||
_, plabels = self.proto_layer()
|
_, plabels = self.proto_layer()
|
||||||
winning = stratified_min_pooling(distances, plabels)
|
winning = stratified_min_pooling(distances, plabels)
|
||||||
y_pred = torch.nn.functional.softmin(winning, dim=1)
|
y_pred = F.softmin(winning, dim=1)
|
||||||
return y_pred
|
return y_pred
|
||||||
|
|
||||||
def predict_from_distances(self, distances):
|
def predict_from_distances(self, distances):
|
||||||
@@ -207,8 +222,10 @@ class NonGradientMixin(ProtoTorchMixin):
|
|||||||
|
|
||||||
class ImagePrototypesMixin(ProtoTorchMixin):
|
class ImagePrototypesMixin(ProtoTorchMixin):
|
||||||
"""Mixin for models with image prototypes."""
|
"""Mixin for models with image prototypes."""
|
||||||
|
proto_layer: Components
|
||||||
|
components: torch.Tensor
|
||||||
|
|
||||||
def on_train_batch_end(self, outputs, batch, batch_idx, dataloader_idx):
|
def on_train_batch_end(self, outputs, batch, batch_idx):
|
||||||
"""Constrain the components to the range [0, 1] by clamping after updates."""
|
"""Constrain the components to the range [0, 1] by clamping after updates."""
|
||||||
self.proto_layer.components.data.clamp_(0.0, 1.0)
|
self.proto_layer.components.data.clamp_(0.0, 1.0)
|
||||||
|
|
||||||
|
@@ -1,25 +1,30 @@
|
|||||||
"""Lightning Callbacks."""
|
"""Lightning Callbacks."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.core.initializers import LiteralCompInitializer
|
||||||
|
|
||||||
from ..core.components import Components
|
|
||||||
from ..core.initializers import LiteralCompInitializer
|
|
||||||
from .extras import ConnectionTopology
|
from .extras import ConnectionTopology
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from prototorch.models import GLVQ, GrowingNeuralGas
|
||||||
|
|
||||||
|
|
||||||
class PruneLoserPrototypes(pl.Callback):
|
class PruneLoserPrototypes(pl.Callback):
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
threshold=0.01,
|
self,
|
||||||
idle_epochs=10,
|
threshold=0.01,
|
||||||
prune_quota_per_epoch=-1,
|
idle_epochs=10,
|
||||||
frequency=1,
|
prune_quota_per_epoch=-1,
|
||||||
replace=False,
|
frequency=1,
|
||||||
prototypes_initializer=None,
|
replace=False,
|
||||||
verbose=False):
|
prototypes_initializer=None,
|
||||||
|
verbose=False,
|
||||||
|
):
|
||||||
self.threshold = threshold # minimum win ratio
|
self.threshold = threshold # minimum win ratio
|
||||||
self.idle_epochs = idle_epochs # epochs to wait before pruning
|
self.idle_epochs = idle_epochs # epochs to wait before pruning
|
||||||
self.prune_quota_per_epoch = prune_quota_per_epoch
|
self.prune_quota_per_epoch = prune_quota_per_epoch
|
||||||
@@ -28,7 +33,7 @@ class PruneLoserPrototypes(pl.Callback):
|
|||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.prototypes_initializer = prototypes_initializer
|
self.prototypes_initializer = prototypes_initializer
|
||||||
|
|
||||||
def on_epoch_end(self, trainer, pl_module):
|
def on_train_epoch_end(self, trainer, pl_module: "GLVQ"):
|
||||||
if (trainer.current_epoch + 1) < self.idle_epochs:
|
if (trainer.current_epoch + 1) < self.idle_epochs:
|
||||||
return None
|
return None
|
||||||
if (trainer.current_epoch + 1) % self.frequency:
|
if (trainer.current_epoch + 1) % self.frequency:
|
||||||
@@ -43,27 +48,29 @@ class PruneLoserPrototypes(pl.Callback):
|
|||||||
prune_labels = prune_labels[:self.prune_quota_per_epoch]
|
prune_labels = prune_labels[:self.prune_quota_per_epoch]
|
||||||
|
|
||||||
if len(to_prune) > 0:
|
if len(to_prune) > 0:
|
||||||
if self.verbose:
|
logging.debug(f"\nPrototype win ratios: {ratios}")
|
||||||
print(f"\nPrototype win ratios: {ratios}")
|
logging.debug(f"Pruning prototypes at: {to_prune}")
|
||||||
print(f"Pruning prototypes at: {to_prune}")
|
logging.debug(f"Corresponding labels are: {prune_labels.tolist()}")
|
||||||
print(f"Corresponding labels are: {prune_labels.tolist()}")
|
|
||||||
cur_num_protos = pl_module.num_prototypes
|
cur_num_protos = pl_module.num_prototypes
|
||||||
pl_module.remove_prototypes(indices=to_prune)
|
pl_module.remove_prototypes(indices=to_prune)
|
||||||
|
|
||||||
if self.replace:
|
if self.replace:
|
||||||
labels, counts = torch.unique(prune_labels,
|
labels, counts = torch.unique(prune_labels,
|
||||||
sorted=True,
|
sorted=True,
|
||||||
return_counts=True)
|
return_counts=True)
|
||||||
distribution = dict(zip(labels.tolist(), counts.tolist()))
|
distribution = dict(zip(labels.tolist(), counts.tolist()))
|
||||||
if self.verbose:
|
|
||||||
print(f"Re-adding pruned prototypes...")
|
logging.info(f"Re-adding pruned prototypes...")
|
||||||
print(f"distribution={distribution}")
|
logging.debug(f"distribution={distribution}")
|
||||||
|
|
||||||
pl_module.add_prototypes(
|
pl_module.add_prototypes(
|
||||||
distribution=distribution,
|
distribution=distribution,
|
||||||
components_initializer=self.prototypes_initializer)
|
components_initializer=self.prototypes_initializer)
|
||||||
new_num_protos = pl_module.num_prototypes
|
new_num_protos = pl_module.num_prototypes
|
||||||
if self.verbose:
|
|
||||||
print(f"`num_prototypes` changed from {cur_num_protos} "
|
logging.info(f"`num_prototypes` changed from {cur_num_protos} "
|
||||||
f"to {new_num_protos}.")
|
f"to {new_num_protos}.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -74,11 +81,11 @@ class PrototypeConvergence(pl.Callback):
|
|||||||
self.idle_epochs = idle_epochs # epochs to wait
|
self.idle_epochs = idle_epochs # epochs to wait
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
|
||||||
def on_epoch_end(self, trainer, pl_module):
|
def on_train_epoch_end(self, trainer, pl_module):
|
||||||
if (trainer.current_epoch + 1) < self.idle_epochs:
|
if (trainer.current_epoch + 1) < self.idle_epochs:
|
||||||
return None
|
return None
|
||||||
if self.verbose:
|
|
||||||
print("Stopping...")
|
logging.info("Stopping...")
|
||||||
# TODO
|
# TODO
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -96,12 +103,16 @@ class GNGCallback(pl.Callback):
|
|||||||
self.reduction = reduction
|
self.reduction = reduction
|
||||||
self.freq = freq
|
self.freq = freq
|
||||||
|
|
||||||
def on_epoch_end(self, trainer: pl.Trainer, pl_module):
|
def on_train_epoch_end(
|
||||||
|
self,
|
||||||
|
trainer: pl.Trainer,
|
||||||
|
pl_module: "GrowingNeuralGas",
|
||||||
|
):
|
||||||
if (trainer.current_epoch + 1) % self.freq == 0:
|
if (trainer.current_epoch + 1) % self.freq == 0:
|
||||||
# Get information
|
# Get information
|
||||||
errors = pl_module.errors
|
errors = pl_module.errors
|
||||||
topology: ConnectionTopology = pl_module.topology_layer
|
topology: ConnectionTopology = pl_module.topology_layer
|
||||||
components: Components = pl_module.proto_layer.components
|
components = pl_module.proto_layer.components
|
||||||
|
|
||||||
# Insertion point
|
# Insertion point
|
||||||
worst = torch.argmax(errors)
|
worst = torch.argmax(errors)
|
||||||
@@ -121,8 +132,9 @@ class GNGCallback(pl.Callback):
|
|||||||
|
|
||||||
# Add component
|
# Add component
|
||||||
pl_module.proto_layer.add_components(
|
pl_module.proto_layer.add_components(
|
||||||
None,
|
1,
|
||||||
initializer=LiteralCompInitializer(new_component.unsqueeze(0)))
|
initializer=LiteralCompInitializer(new_component.unsqueeze(0)),
|
||||||
|
)
|
||||||
|
|
||||||
# Adjust Topology
|
# Adjust Topology
|
||||||
topology.add_prototype()
|
topology.add_prototype()
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import torch
|
import torch
|
||||||
import torchmetrics
|
import torchmetrics
|
||||||
|
from prototorch.core.competitions import CBCC
|
||||||
|
from prototorch.core.components import ReasoningComponents
|
||||||
|
from prototorch.core.initializers import RandomReasoningsInitializer
|
||||||
|
from prototorch.core.losses import MarginLoss
|
||||||
|
from prototorch.core.similarities import euclidean_similarity
|
||||||
|
from prototorch.nn.wrappers import LambdaLayer
|
||||||
|
|
||||||
from ..core.competitions import CBCC
|
|
||||||
from ..core.components import ReasoningComponents
|
|
||||||
from ..core.initializers import RandomReasoningsInitializer
|
|
||||||
from ..core.losses import MarginLoss
|
|
||||||
from ..core.similarities import euclidean_similarity
|
|
||||||
from ..nn.wrappers import LambdaLayer
|
|
||||||
from .abstract import ImagePrototypesMixin
|
from .abstract import ImagePrototypesMixin
|
||||||
from .glvq import SiameseGLVQ
|
from .glvq import SiameseGLVQ
|
||||||
|
|
||||||
|
@@ -5,8 +5,7 @@ Modules not yet available in prototorch go here temporarily.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.core.similarities import gaussian
|
||||||
from ..core.similarities import gaussian
|
|
||||||
|
|
||||||
|
|
||||||
def rank_scaled_gaussian(distances, lambd):
|
def rank_scaled_gaussian(distances, lambd):
|
||||||
|
@@ -1,22 +1,22 @@
|
|||||||
"""Models based on the GLVQ framework."""
|
"""Models based on the GLVQ framework."""
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from torch.nn.parameter import Parameter
|
from prototorch.core.competitions import wtac
|
||||||
|
from prototorch.core.distances import (
|
||||||
from ..core.competitions import wtac
|
|
||||||
from ..core.distances import (
|
|
||||||
lomega_distance,
|
lomega_distance,
|
||||||
omega_distance,
|
omega_distance,
|
||||||
squared_euclidean_distance,
|
squared_euclidean_distance,
|
||||||
)
|
)
|
||||||
from ..core.initializers import EyeLinearTransformInitializer
|
from prototorch.core.initializers import EyeLinearTransformInitializer
|
||||||
from ..core.losses import (
|
from prototorch.core.losses import (
|
||||||
GLVQLoss,
|
GLVQLoss,
|
||||||
lvq1_loss,
|
lvq1_loss,
|
||||||
lvq21_loss,
|
lvq21_loss,
|
||||||
)
|
)
|
||||||
from ..core.transforms import LinearTransform
|
from prototorch.core.transforms import LinearTransform
|
||||||
from ..nn.wrappers import LambdaLayer, LossLayer
|
from prototorch.nn.wrappers import LambdaLayer, LossLayer
|
||||||
|
from torch.nn.parameter import Parameter
|
||||||
|
|
||||||
from .abstract import ImagePrototypesMixin, SupervisedPrototypeModel
|
from .abstract import ImagePrototypesMixin, SupervisedPrototypeModel
|
||||||
from .extras import ltangent_distance, orthogonalization
|
from .extras import ltangent_distance, orthogonalization
|
||||||
|
|
||||||
@@ -34,9 +34,9 @@ class GLVQ(SupervisedPrototypeModel):
|
|||||||
|
|
||||||
# Loss
|
# Loss
|
||||||
self.loss = GLVQLoss(
|
self.loss = GLVQLoss(
|
||||||
margin=self.hparams.margin,
|
margin=self.hparams["margin"],
|
||||||
transfer_fn=self.hparams.transfer_fn,
|
transfer_fn=self.hparams["transfer_fn"],
|
||||||
beta=self.hparams.transfer_beta,
|
beta=self.hparams["transfer_beta"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# def on_save_checkpoint(self, checkpoint):
|
# def on_save_checkpoint(self, checkpoint):
|
||||||
@@ -48,7 +48,7 @@ class GLVQ(SupervisedPrototypeModel):
|
|||||||
"prototype_win_ratios",
|
"prototype_win_ratios",
|
||||||
torch.zeros(self.num_prototypes, device=self.device))
|
torch.zeros(self.num_prototypes, device=self.device))
|
||||||
|
|
||||||
def on_epoch_start(self):
|
def on_train_epoch_start(self):
|
||||||
self.initialize_prototype_win_ratios()
|
self.initialize_prototype_win_ratios()
|
||||||
|
|
||||||
def log_prototype_win_ratios(self, distances):
|
def log_prototype_win_ratios(self, distances):
|
||||||
@@ -125,11 +125,11 @@ class SiameseGLVQ(GLVQ):
|
|||||||
|
|
||||||
def configure_optimizers(self):
|
def configure_optimizers(self):
|
||||||
proto_opt = self.optimizer(self.proto_layer.parameters(),
|
proto_opt = self.optimizer(self.proto_layer.parameters(),
|
||||||
lr=self.hparams.proto_lr)
|
lr=self.hparams["proto_lr"])
|
||||||
# Only add a backbone optimizer if backbone has trainable parameters
|
# Only add a backbone optimizer if backbone has trainable parameters
|
||||||
bb_params = list(self.backbone.parameters())
|
bb_params = list(self.backbone.parameters())
|
||||||
if (bb_params):
|
if (bb_params):
|
||||||
bb_opt = self.optimizer(bb_params, lr=self.hparams.bb_lr)
|
bb_opt = self.optimizer(bb_params, lr=self.hparams["bb_lr"])
|
||||||
optimizers = [proto_opt, bb_opt]
|
optimizers = [proto_opt, bb_opt]
|
||||||
else:
|
else:
|
||||||
optimizers = [proto_opt]
|
optimizers = [proto_opt]
|
||||||
@@ -199,12 +199,13 @@ class GRLVQ(SiameseGLVQ):
|
|||||||
TODO Make a RelevanceLayer. `bb_lr` is ignored otherwise.
|
TODO Make a RelevanceLayer. `bb_lr` is ignored otherwise.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
_relevances: torch.Tensor
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
|
|
||||||
# Additional parameters
|
# Additional parameters
|
||||||
relevances = torch.ones(self.hparams.input_dim, device=self.device)
|
relevances = torch.ones(self.hparams["input_dim"], device=self.device)
|
||||||
self.register_parameter("_relevances", Parameter(relevances))
|
self.register_parameter("_relevances", Parameter(relevances))
|
||||||
|
|
||||||
# Override the backbone
|
# Override the backbone
|
||||||
@@ -233,8 +234,8 @@ class SiameseGMLVQ(SiameseGLVQ):
|
|||||||
omega_initializer = kwargs.get("omega_initializer",
|
omega_initializer = kwargs.get("omega_initializer",
|
||||||
EyeLinearTransformInitializer())
|
EyeLinearTransformInitializer())
|
||||||
self.backbone = LinearTransform(
|
self.backbone = LinearTransform(
|
||||||
self.hparams.input_dim,
|
self.hparams["input_dim"],
|
||||||
self.hparams.latent_dim,
|
self.hparams["latent_dim"],
|
||||||
initializer=omega_initializer,
|
initializer=omega_initializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -244,7 +245,7 @@ class SiameseGMLVQ(SiameseGLVQ):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def lambda_matrix(self):
|
def lambda_matrix(self):
|
||||||
omega = self.backbone.weight # (input_dim, latent_dim)
|
omega = self.backbone.weights # (input_dim, latent_dim)
|
||||||
lam = omega @ omega.T
|
lam = omega @ omega.T
|
||||||
return lam.detach().cpu()
|
return lam.detach().cpu()
|
||||||
|
|
||||||
@@ -257,6 +258,9 @@ class GMLVQ(GLVQ):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
_omega: torch.Tensor
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
distance_fn = kwargs.pop("distance_fn", omega_distance)
|
distance_fn = kwargs.pop("distance_fn", omega_distance)
|
||||||
super().__init__(hparams, distance_fn=distance_fn, **kwargs)
|
super().__init__(hparams, distance_fn=distance_fn, **kwargs)
|
||||||
@@ -264,8 +268,8 @@ class GMLVQ(GLVQ):
|
|||||||
# Additional parameters
|
# Additional parameters
|
||||||
omega_initializer = kwargs.get("omega_initializer",
|
omega_initializer = kwargs.get("omega_initializer",
|
||||||
EyeLinearTransformInitializer())
|
EyeLinearTransformInitializer())
|
||||||
omega = omega_initializer.generate(self.hparams.input_dim,
|
omega = omega_initializer.generate(self.hparams["input_dim"],
|
||||||
self.hparams.latent_dim)
|
self.hparams["latent_dim"])
|
||||||
self.register_parameter("_omega", Parameter(omega))
|
self.register_parameter("_omega", Parameter(omega))
|
||||||
self.backbone = LambdaLayer(lambda x: x @ self._omega,
|
self.backbone = LambdaLayer(lambda x: x @ self._omega,
|
||||||
name="omega matrix")
|
name="omega matrix")
|
||||||
@@ -299,8 +303,8 @@ class LGMLVQ(GMLVQ):
|
|||||||
# Re-register `_omega` to override the one from the super class.
|
# Re-register `_omega` to override the one from the super class.
|
||||||
omega = torch.randn(
|
omega = torch.randn(
|
||||||
self.num_prototypes,
|
self.num_prototypes,
|
||||||
self.hparams.input_dim,
|
self.hparams["input_dim"],
|
||||||
self.hparams.latent_dim,
|
self.hparams["latent_dim"],
|
||||||
device=self.device,
|
device=self.device,
|
||||||
)
|
)
|
||||||
self.register_parameter("_omega", Parameter(omega))
|
self.register_parameter("_omega", Parameter(omega))
|
||||||
@@ -316,23 +320,27 @@ class GTLVQ(LGMLVQ):
|
|||||||
omega_initializer = kwargs.get("omega_initializer")
|
omega_initializer = kwargs.get("omega_initializer")
|
||||||
|
|
||||||
if omega_initializer is not None:
|
if omega_initializer is not None:
|
||||||
subspace = omega_initializer.generate(self.hparams.input_dim,
|
subspace = omega_initializer.generate(
|
||||||
self.hparams.latent_dim)
|
self.hparams["input_dim"],
|
||||||
omega = torch.repeat_interleave(subspace.unsqueeze(0),
|
self.hparams["latent_dim"],
|
||||||
self.num_prototypes,
|
)
|
||||||
dim=0)
|
omega = torch.repeat_interleave(
|
||||||
|
subspace.unsqueeze(0),
|
||||||
|
self.num_prototypes,
|
||||||
|
dim=0,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
omega = torch.rand(
|
omega = torch.rand(
|
||||||
self.num_prototypes,
|
self.num_prototypes,
|
||||||
self.hparams.input_dim,
|
self.hparams["input_dim"],
|
||||||
self.hparams.latent_dim,
|
self.hparams["latent_dim"],
|
||||||
device=self.device,
|
device=self.device,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Re-register `_omega` to override the one from the super class.
|
# Re-register `_omega` to override the one from the super class.
|
||||||
self.register_parameter("_omega", Parameter(omega))
|
self.register_parameter("_omega", Parameter(omega))
|
||||||
|
|
||||||
def on_train_batch_end(self, outputs, batch, batch_idx, dataloader_idx):
|
def on_train_batch_end(self, outputs, batch, batch_idx):
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
self._omega.copy_(orthogonalization(self._omega))
|
self._omega.copy_(orthogonalization(self._omega))
|
||||||
|
|
||||||
@@ -389,7 +397,7 @@ class ImageGTLVQ(ImagePrototypesMixin, GTLVQ):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def on_train_batch_end(self, outputs, batch, batch_idx, dataloader_idx):
|
def on_train_batch_end(self, outputs, batch, batch_idx):
|
||||||
"""Constrain the components to the range [0, 1] by clamping after updates."""
|
"""Constrain the components to the range [0, 1] by clamping after updates."""
|
||||||
self.proto_layer.components.data.clamp_(0.0, 1.0)
|
self.proto_layer.components.data.clamp_(0.0, 1.0)
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
|
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from ..core.competitions import KNNC
|
from prototorch.core.competitions import KNNC
|
||||||
from ..core.components import LabeledComponents
|
from prototorch.core.components import LabeledComponents
|
||||||
from ..core.initializers import (
|
from prototorch.core.initializers import (
|
||||||
LiteralCompInitializer,
|
LiteralCompInitializer,
|
||||||
LiteralLabelsInitializer,
|
LiteralLabelsInitializer,
|
||||||
)
|
)
|
||||||
from ..utils.utils import parse_data_arg
|
from prototorch.utils.utils import parse_data_arg
|
||||||
|
|
||||||
from .abstract import SupervisedPrototypeModel
|
from .abstract import SupervisedPrototypeModel
|
||||||
|
|
||||||
|
|
||||||
@@ -36,10 +37,7 @@ class KNN(SupervisedPrototypeModel):
|
|||||||
def training_step(self, train_batch, batch_idx, optimizer_idx=None):
|
def training_step(self, train_batch, batch_idx, optimizer_idx=None):
|
||||||
return 1 # skip training step
|
return 1 # skip training step
|
||||||
|
|
||||||
def on_train_batch_start(self,
|
def on_train_batch_start(self, train_batch, batch_idx):
|
||||||
train_batch,
|
|
||||||
batch_idx,
|
|
||||||
dataloader_idx=None):
|
|
||||||
warnings.warn("k-NN has no training, skipping!")
|
warnings.warn("k-NN has no training, skipping!")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
"""LVQ models that are optimized using non-gradient methods."""
|
"""LVQ models that are optimized using non-gradient methods."""
|
||||||
|
|
||||||
from ..core.losses import _get_dp_dm
|
import logging
|
||||||
from ..nn.activations import get_activation
|
|
||||||
from ..nn.wrappers import LambdaLayer
|
from prototorch.core.losses import _get_dp_dm
|
||||||
|
from prototorch.nn.activations import get_activation
|
||||||
|
from prototorch.nn.wrappers import LambdaLayer
|
||||||
|
|
||||||
from .abstract import NonGradientMixin
|
from .abstract import NonGradientMixin
|
||||||
from .glvq import GLVQ
|
from .glvq import GLVQ
|
||||||
|
|
||||||
@@ -29,8 +32,8 @@ class LVQ1(NonGradientMixin, GLVQ):
|
|||||||
self.proto_layer.load_state_dict({"_components": updated_protos},
|
self.proto_layer.load_state_dict({"_components": updated_protos},
|
||||||
strict=False)
|
strict=False)
|
||||||
|
|
||||||
print(f"dis={dis}")
|
logging.debug(f"dis={dis}")
|
||||||
print(f"y={y}")
|
logging.debug(f"y={y}")
|
||||||
# Logging
|
# Logging
|
||||||
self.log_acc(dis, y, tag="train_acc")
|
self.log_acc(dis, y, tag="train_acc")
|
||||||
|
|
||||||
@@ -73,8 +76,7 @@ class MedianLVQ(NonGradientMixin, GLVQ):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, hparams, verbose=True, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
self.verbose = verbose
|
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
|
|
||||||
self.transfer_layer = LambdaLayer(
|
self.transfer_layer = LambdaLayer(
|
||||||
@@ -115,8 +117,7 @@ class MedianLVQ(NonGradientMixin, GLVQ):
|
|||||||
_protos[i] = xk
|
_protos[i] = xk
|
||||||
_lower_bound = self.lower_bound(x, y, _protos, plabels, gamma)
|
_lower_bound = self.lower_bound(x, y, _protos, plabels, gamma)
|
||||||
if _lower_bound > lower_bound:
|
if _lower_bound > lower_bound:
|
||||||
if self.verbose:
|
logging.debug(f"Updating prototype {i} to data {k}...")
|
||||||
print(f"Updating prototype {i} to data {k}...")
|
|
||||||
self.proto_layer.load_state_dict({"_components": _protos},
|
self.proto_layer.load_state_dict({"_components": _protos},
|
||||||
strict=False)
|
strict=False)
|
||||||
break
|
break
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
"""Probabilistic GLVQ methods"""
|
"""Probabilistic GLVQ methods"""
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.core.losses import nllr_loss, rslvq_loss
|
||||||
|
from prototorch.core.pooling import (
|
||||||
|
stratified_min_pooling,
|
||||||
|
stratified_sum_pooling,
|
||||||
|
)
|
||||||
|
from prototorch.nn.wrappers import LossLayer
|
||||||
|
|
||||||
from ..core.losses import nllr_loss, rslvq_loss
|
|
||||||
from ..core.pooling import stratified_min_pooling, stratified_sum_pooling
|
|
||||||
from ..nn.wrappers import LambdaLayer, LossLayer
|
|
||||||
from .extras import GaussianPrior, RankScaledGaussianPrior
|
from .extras import GaussianPrior, RankScaledGaussianPrior
|
||||||
from .glvq import GLVQ, SiameseGMLVQ
|
from .glvq import GLVQ, SiameseGMLVQ
|
||||||
|
|
||||||
@@ -34,17 +37,24 @@ class ProbabilisticLVQ(GLVQ):
|
|||||||
def __init__(self, hparams, rejection_confidence=0.0, **kwargs):
|
def __init__(self, hparams, rejection_confidence=0.0, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
|
|
||||||
self.conditional_distribution = None
|
|
||||||
self.rejection_confidence = rejection_confidence
|
self.rejection_confidence = rejection_confidence
|
||||||
|
self._conditional_distribution = None
|
||||||
|
|
||||||
def forward(self, x):
|
def forward(self, x):
|
||||||
distances = self.compute_distances(x)
|
distances = self.compute_distances(x)
|
||||||
|
|
||||||
conditional = self.conditional_distribution(distances)
|
conditional = self.conditional_distribution(distances)
|
||||||
prior = (1. / self.num_prototypes) * torch.ones(self.num_prototypes,
|
prior = (1. / self.num_prototypes) * torch.ones(self.num_prototypes,
|
||||||
device=self.device)
|
device=self.device)
|
||||||
posterior = conditional * prior
|
posterior = conditional * prior
|
||||||
|
|
||||||
plabels = self.proto_layer._labels
|
plabels = self.proto_layer._labels
|
||||||
y_pred = stratified_sum_pooling(posterior, plabels)
|
if isinstance(plabels, torch.LongTensor) or isinstance(
|
||||||
|
plabels, torch.cuda.LongTensor): # type: ignore
|
||||||
|
y_pred = stratified_sum_pooling(posterior, plabels) # type: ignore
|
||||||
|
else:
|
||||||
|
raise ValueError("Labels must be LongTensor.")
|
||||||
|
|
||||||
return y_pred
|
return y_pred
|
||||||
|
|
||||||
def predict(self, x):
|
def predict(self, x):
|
||||||
@@ -61,6 +71,12 @@ class ProbabilisticLVQ(GLVQ):
|
|||||||
loss = batch_loss.sum()
|
loss = batch_loss.sum()
|
||||||
return loss
|
return loss
|
||||||
|
|
||||||
|
def conditional_distribution(self, distances):
|
||||||
|
"""Conditional distribution of distances."""
|
||||||
|
if self._conditional_distribution is None:
|
||||||
|
raise ValueError("Conditional distribution is not set.")
|
||||||
|
return self._conditional_distribution(distances)
|
||||||
|
|
||||||
|
|
||||||
class SLVQ(ProbabilisticLVQ):
|
class SLVQ(ProbabilisticLVQ):
|
||||||
"""Soft Learning Vector Quantization."""
|
"""Soft Learning Vector Quantization."""
|
||||||
@@ -72,7 +88,7 @@ class SLVQ(ProbabilisticLVQ):
|
|||||||
self.hparams.setdefault("variance", 1.0)
|
self.hparams.setdefault("variance", 1.0)
|
||||||
variance = self.hparams.get("variance")
|
variance = self.hparams.get("variance")
|
||||||
|
|
||||||
self.conditional_distribution = GaussianPrior(variance)
|
self._conditional_distribution = GaussianPrior(variance)
|
||||||
self.loss = LossLayer(nllr_loss)
|
self.loss = LossLayer(nllr_loss)
|
||||||
|
|
||||||
|
|
||||||
@@ -86,7 +102,7 @@ class RSLVQ(ProbabilisticLVQ):
|
|||||||
self.hparams.setdefault("variance", 1.0)
|
self.hparams.setdefault("variance", 1.0)
|
||||||
variance = self.hparams.get("variance")
|
variance = self.hparams.get("variance")
|
||||||
|
|
||||||
self.conditional_distribution = GaussianPrior(variance)
|
self._conditional_distribution = GaussianPrior(variance)
|
||||||
self.loss = LossLayer(rslvq_loss)
|
self.loss = LossLayer(rslvq_loss)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
|
from prototorch.core.competitions import wtac
|
||||||
|
from prototorch.core.distances import squared_euclidean_distance
|
||||||
|
from prototorch.core.losses import NeuralGasEnergy
|
||||||
|
|
||||||
from ..core.competitions import wtac
|
|
||||||
from ..core.distances import squared_euclidean_distance
|
|
||||||
from ..core.losses import NeuralGasEnergy
|
|
||||||
from ..nn.wrappers import LambdaLayer
|
|
||||||
from .abstract import NonGradientMixin, UnsupervisedPrototypeModel
|
from .abstract import NonGradientMixin, UnsupervisedPrototypeModel
|
||||||
from .callbacks import GNGCallback
|
from .callbacks import GNGCallback
|
||||||
from .extras import ConnectionTopology
|
from .extras import ConnectionTopology
|
||||||
@@ -18,6 +17,7 @@ class KohonenSOM(NonGradientMixin, UnsupervisedPrototypeModel):
|
|||||||
TODO Allow non-2D grids
|
TODO Allow non-2D grids
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
_grid: torch.Tensor
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
h, w = hparams.get("shape")
|
h, w = hparams.get("shape")
|
||||||
@@ -93,10 +93,10 @@ class NeuralGas(UnsupervisedPrototypeModel):
|
|||||||
self.hparams.setdefault("age_limit", 10)
|
self.hparams.setdefault("age_limit", 10)
|
||||||
self.hparams.setdefault("lm", 1)
|
self.hparams.setdefault("lm", 1)
|
||||||
|
|
||||||
self.energy_layer = NeuralGasEnergy(lm=self.hparams.lm)
|
self.energy_layer = NeuralGasEnergy(lm=self.hparams["lm"])
|
||||||
self.topology_layer = ConnectionTopology(
|
self.topology_layer = ConnectionTopology(
|
||||||
agelimit=self.hparams.age_limit,
|
agelimit=self.hparams["age_limit"],
|
||||||
num_prototypes=self.hparams.num_prototypes,
|
num_prototypes=self.hparams["num_prototypes"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def training_step(self, train_batch, batch_idx):
|
def training_step(self, train_batch, batch_idx):
|
||||||
@@ -109,12 +109,9 @@ class NeuralGas(UnsupervisedPrototypeModel):
|
|||||||
self.log("loss", loss)
|
self.log("loss", loss)
|
||||||
return loss
|
return loss
|
||||||
|
|
||||||
# def training_epoch_end(self, training_step_outputs):
|
|
||||||
# print(f"{self.trainer.lr_schedulers}")
|
|
||||||
# print(f"{self.trainer.lr_schedulers[0]['scheduler'].optimizer}")
|
|
||||||
|
|
||||||
|
|
||||||
class GrowingNeuralGas(NeuralGas):
|
class GrowingNeuralGas(NeuralGas):
|
||||||
|
errors: torch.Tensor
|
||||||
|
|
||||||
def __init__(self, hparams, **kwargs):
|
def __init__(self, hparams, **kwargs):
|
||||||
super().__init__(hparams, **kwargs)
|
super().__init__(hparams, **kwargs)
|
||||||
@@ -124,7 +121,10 @@ class GrowingNeuralGas(NeuralGas):
|
|||||||
self.hparams.setdefault("insert_reduction", 0.1)
|
self.hparams.setdefault("insert_reduction", 0.1)
|
||||||
self.hparams.setdefault("insert_freq", 10)
|
self.hparams.setdefault("insert_freq", 10)
|
||||||
|
|
||||||
errors = torch.zeros(self.hparams.num_prototypes, device=self.device)
|
errors = torch.zeros(
|
||||||
|
self.hparams["num_prototypes"],
|
||||||
|
device=self.device,
|
||||||
|
)
|
||||||
self.register_buffer("errors", errors)
|
self.register_buffer("errors", errors)
|
||||||
|
|
||||||
def training_step(self, train_batch, _batch_idx):
|
def training_step(self, train_batch, _batch_idx):
|
||||||
@@ -139,7 +139,7 @@ class GrowingNeuralGas(NeuralGas):
|
|||||||
dp = d * mask
|
dp = d * mask
|
||||||
|
|
||||||
self.errors += torch.sum(dp * dp)
|
self.errors += torch.sum(dp * dp)
|
||||||
self.errors *= self.hparams.step_reduction
|
self.errors *= self.hparams["step_reduction"]
|
||||||
|
|
||||||
self.topology_layer(d)
|
self.topology_layer(d)
|
||||||
self.log("loss", loss)
|
self.log("loss", loss)
|
||||||
@@ -148,7 +148,7 @@ class GrowingNeuralGas(NeuralGas):
|
|||||||
def configure_callbacks(self):
|
def configure_callbacks(self):
|
||||||
return [
|
return [
|
||||||
GNGCallback(
|
GNGCallback(
|
||||||
reduction=self.hparams.insert_reduction,
|
reduction=self.hparams["insert_reduction"],
|
||||||
freq=self.hparams.insert_freq,
|
freq=self.hparams["insert_freq"],
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
"""Visualization Callbacks."""
|
"""Visualization Callbacks."""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
from typing import Sized
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pytorch_lightning as pl
|
import pytorch_lightning as pl
|
||||||
import torch
|
import torch
|
||||||
import torchvision
|
import torchvision
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
from prototorch.utils.colors import get_colors, get_legend_handles
|
||||||
|
from prototorch.utils.utils import mesh2d
|
||||||
|
from pytorch_lightning.loggers import TensorBoardLogger
|
||||||
from torch.utils.data import DataLoader, Dataset
|
from torch.utils.data import DataLoader, Dataset
|
||||||
|
|
||||||
from ..utils.colors import get_colors, get_legend_handles
|
|
||||||
from ..utils.utils import mesh2d
|
|
||||||
|
|
||||||
|
|
||||||
class Vis2DAbstract(pl.Callback):
|
class Vis2DAbstract(pl.Callback):
|
||||||
|
|
||||||
@@ -34,8 +37,13 @@ class Vis2DAbstract(pl.Callback):
|
|||||||
|
|
||||||
if data:
|
if data:
|
||||||
if isinstance(data, Dataset):
|
if isinstance(data, Dataset):
|
||||||
x, y = next(iter(DataLoader(data, batch_size=len(data))))
|
if isinstance(data, Sized):
|
||||||
elif isinstance(data, torch.utils.data.DataLoader):
|
x, y = next(iter(DataLoader(data, batch_size=len(data))))
|
||||||
|
else:
|
||||||
|
# TODO: Add support for non-sized datasets
|
||||||
|
raise NotImplementedError(
|
||||||
|
"Data must be a dataset with a __len__ method.")
|
||||||
|
elif isinstance(data, DataLoader):
|
||||||
x = torch.tensor([])
|
x = torch.tensor([])
|
||||||
y = torch.tensor([])
|
y = torch.tensor([])
|
||||||
for x_b, y_b in data:
|
for x_b, y_b in data:
|
||||||
@@ -123,7 +131,7 @@ class Vis2DAbstract(pl.Callback):
|
|||||||
else:
|
else:
|
||||||
plt.show(block=self.block)
|
plt.show(block=self.block)
|
||||||
|
|
||||||
def on_epoch_end(self, trainer, pl_module):
|
def on_train_epoch_end(self, trainer, pl_module):
|
||||||
if not self.precheck(trainer):
|
if not self.precheck(trainer):
|
||||||
return True
|
return True
|
||||||
self.visualize(pl_module)
|
self.visualize(pl_module)
|
||||||
@@ -132,6 +140,9 @@ class Vis2DAbstract(pl.Callback):
|
|||||||
def on_train_end(self, trainer, pl_module):
|
def on_train_end(self, trainer, pl_module):
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
||||||
|
def visualize(self, pl_module):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class VisGLVQ2D(Vis2DAbstract):
|
class VisGLVQ2D(Vis2DAbstract):
|
||||||
|
|
||||||
@@ -292,30 +303,45 @@ class VisImgComp(Vis2DAbstract):
|
|||||||
self.add_embedding = add_embedding
|
self.add_embedding = add_embedding
|
||||||
self.embedding_data = embedding_data
|
self.embedding_data = embedding_data
|
||||||
|
|
||||||
def on_train_start(self, trainer, pl_module):
|
def on_train_start(self, _, pl_module):
|
||||||
tb = pl_module.logger.experiment
|
if isinstance(pl_module.logger, TensorBoardLogger):
|
||||||
if self.add_embedding:
|
tb = pl_module.logger.experiment
|
||||||
ind = np.random.choice(len(self.x_train),
|
|
||||||
size=self.embedding_data,
|
|
||||||
replace=False)
|
|
||||||
data = self.x_train[ind]
|
|
||||||
tb.add_embedding(data.view(len(ind), -1),
|
|
||||||
label_img=data,
|
|
||||||
global_step=None,
|
|
||||||
tag="Data Embedding",
|
|
||||||
metadata=self.y_train[ind],
|
|
||||||
metadata_header=None)
|
|
||||||
|
|
||||||
if self.random_data:
|
# Add embedding
|
||||||
ind = np.random.choice(len(self.x_train),
|
if self.add_embedding:
|
||||||
size=self.random_data,
|
if self.x_train is not None and self.y_train is not None:
|
||||||
replace=False)
|
ind = np.random.choice(len(self.x_train),
|
||||||
data = self.x_train[ind]
|
size=self.embedding_data,
|
||||||
grid = torchvision.utils.make_grid(data, nrow=self.num_columns)
|
replace=False)
|
||||||
tb.add_image(tag="Data",
|
data = self.x_train[ind]
|
||||||
img_tensor=grid,
|
tb.add_embedding(data.view(len(ind), -1),
|
||||||
global_step=None,
|
label_img=data,
|
||||||
dataformats=self.dataformats)
|
global_step=None,
|
||||||
|
tag="Data Embedding",
|
||||||
|
metadata=self.y_train[ind],
|
||||||
|
metadata_header=None)
|
||||||
|
else:
|
||||||
|
raise ValueError("No data for add embedding flag")
|
||||||
|
|
||||||
|
# Random Data
|
||||||
|
if self.random_data:
|
||||||
|
if self.x_train is not None:
|
||||||
|
ind = np.random.choice(len(self.x_train),
|
||||||
|
size=self.random_data,
|
||||||
|
replace=False)
|
||||||
|
data = self.x_train[ind]
|
||||||
|
grid = torchvision.utils.make_grid(data,
|
||||||
|
nrow=self.num_columns)
|
||||||
|
tb.add_image(tag="Data",
|
||||||
|
img_tensor=grid,
|
||||||
|
global_step=None,
|
||||||
|
dataformats=self.dataformats)
|
||||||
|
else:
|
||||||
|
raise ValueError("No data for random data flag")
|
||||||
|
|
||||||
|
else:
|
||||||
|
warnings.warn(
|
||||||
|
f"TensorBoardLogger is required, got {type(pl_module.logger)}")
|
||||||
|
|
||||||
def add_to_tensorboard(self, trainer, pl_module):
|
def add_to_tensorboard(self, trainer, pl_module):
|
||||||
tb = pl_module.logger.experiment
|
tb = pl_module.logger.experiment
|
||||||
|
4
setup.py
4
setup.py
@@ -25,6 +25,7 @@ INSTALL_REQUIRES = [
|
|||||||
"prototorch>=0.7.3",
|
"prototorch>=0.7.3",
|
||||||
"pytorch_lightning>=1.6.0",
|
"pytorch_lightning>=1.6.0",
|
||||||
"torchmetrics",
|
"torchmetrics",
|
||||||
|
"protobuf<3.20.0",
|
||||||
]
|
]
|
||||||
CLI = [
|
CLI = [
|
||||||
"jsonargparse",
|
"jsonargparse",
|
||||||
@@ -54,7 +55,7 @@ ALL = CLI + DEV + DOCS + EXAMPLES + TESTS
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=safe_name("prototorch_" + PLUGIN_NAME),
|
name=safe_name("prototorch_" + PLUGIN_NAME),
|
||||||
version="0.5.0",
|
version="0.5.2",
|
||||||
description="Pre-packaged prototype-based "
|
description="Pre-packaged prototype-based "
|
||||||
"machine learning models using ProtoTorch and PyTorch-Lightning.",
|
"machine learning models using ProtoTorch and PyTorch-Lightning.",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
@@ -80,6 +81,7 @@ setup(
|
|||||||
"Intended Audience :: Science/Research",
|
"Intended Audience :: Science/Research",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Natural Language :: English",
|
"Natural Language :: English",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
|
Reference in New Issue
Block a user