Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6714cb7915 | ||
|
a501ab6c3b | ||
|
37add944b1 | ||
|
0d10fc7e25 | ||
|
71a2e74eff | ||
|
85f75bb28c | ||
|
46ff1c4eb1 | ||
|
ed5b9b6c62 | ||
|
08b3f9bbb9 | ||
|
784a963527 | ||
|
236cbbc4d2 | ||
|
695559fd4a | ||
|
a54acdef22 | ||
|
bebd13868f | ||
|
62df3c0457 | ||
|
07a2d6caaa | ||
|
3d3d27fbab |
@@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.7.2
|
current_version = 0.7.3
|
||||||
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+)
|
||||||
|
12
.github/workflows/pythonapp.yml
vendored
12
.github/workflows/pythonapp.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.9
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: "3.10"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
@@ -27,13 +27,15 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.7", "3.8", "3.9"]
|
python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest]
|
||||||
exclude:
|
exclude:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: "3.7"
|
python-version: "3.7"
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: "3.8"
|
python-version: "3.8"
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@@ -55,10 +57,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python 3.9
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: "3.9"
|
python-version: "3.10"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
|
3
LICENSE
3
LICENSE
@@ -1,6 +1,7 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 si-cim
|
Copyright (c) 2020 Saxon Institute for Computational Intelligence and Machine
|
||||||
|
Learning (SICIM)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@@ -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.7.2"
|
release = "0.7.3"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ html_css_files = [
|
|||||||
# -- Options for HTMLHelp output ------------------------------------------
|
# -- Options for HTMLHelp output ------------------------------------------
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = "protoflowdoc"
|
htmlhelp_basename = "prototorchdoc"
|
||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ from .core import similarities # noqa: F401
|
|||||||
from .core import transforms # noqa: F401
|
from .core import transforms # noqa: F401
|
||||||
|
|
||||||
# Core Setup
|
# Core Setup
|
||||||
__version__ = "0.7.2"
|
__version__ = "0.7.3"
|
||||||
|
|
||||||
__all_core__ = [
|
__all_core__ = [
|
||||||
"competitions",
|
"competitions",
|
||||||
|
@@ -32,6 +32,12 @@ class LiteralCompInitializer(AbstractComponentsInitializer):
|
|||||||
|
|
||||||
def generate(self, num_components: int = 0):
|
def generate(self, num_components: int = 0):
|
||||||
"""Ignore `num_components` and simply return `self.components`."""
|
"""Ignore `num_components` and simply return `self.components`."""
|
||||||
|
provided_num_components = len(self.components)
|
||||||
|
if provided_num_components != num_components:
|
||||||
|
wmsg = f"The number of components ({provided_num_components}) " \
|
||||||
|
f"provided to {self.__class__.__name__} " \
|
||||||
|
f"does not match the expected number ({num_components})."
|
||||||
|
warnings.warn(wmsg)
|
||||||
if not isinstance(self.components, torch.Tensor):
|
if not isinstance(self.components, torch.Tensor):
|
||||||
wmsg = f"Converting components to {torch.Tensor}..."
|
wmsg = f"Converting components to {torch.Tensor}..."
|
||||||
warnings.warn(wmsg)
|
warnings.warn(wmsg)
|
||||||
@@ -231,6 +237,8 @@ class AbstractStratifiedCompInitializer(AbstractClassAwareCompInitializer):
|
|||||||
components = torch.tensor([])
|
components = torch.tensor([])
|
||||||
for k, v in distribution.items():
|
for k, v in distribution.items():
|
||||||
stratified_data = self.data[self.targets == k]
|
stratified_data = self.data[self.targets == k]
|
||||||
|
if len(stratified_data) == 0:
|
||||||
|
raise ValueError(f"No data available for class {k}.")
|
||||||
initializer = self.subinit_type(
|
initializer = self.subinit_type(
|
||||||
stratified_data,
|
stratified_data,
|
||||||
noise=self.noise,
|
noise=self.noise,
|
||||||
@@ -457,7 +465,15 @@ class OnesLinearTransformInitializer(AbstractLinearTransformInitializer):
|
|||||||
return self.generate_end_hook(weights)
|
return self.generate_end_hook(weights)
|
||||||
|
|
||||||
|
|
||||||
class EyeTransformInitializer(AbstractLinearTransformInitializer):
|
class RandomLinearTransformInitializer(AbstractLinearTransformInitializer):
|
||||||
|
"""Initialize a matrix with random values."""
|
||||||
|
|
||||||
|
def generate(self, in_dim: int, out_dim: int):
|
||||||
|
weights = torch.rand(in_dim, out_dim)
|
||||||
|
return self.generate_end_hook(weights)
|
||||||
|
|
||||||
|
|
||||||
|
class EyeLinearTransformInitializer(AbstractLinearTransformInitializer):
|
||||||
"""Initialize a matrix with the largest possible identity matrix."""
|
"""Initialize a matrix with the largest possible identity matrix."""
|
||||||
|
|
||||||
def generate(self, in_dim: int, out_dim: int):
|
def generate(self, in_dim: int, out_dim: int):
|
||||||
@@ -496,6 +512,13 @@ class PCALinearTransformInitializer(AbstractDataAwareLTInitializer):
|
|||||||
return self.generate_end_hook(weights)
|
return self.generate_end_hook(weights)
|
||||||
|
|
||||||
|
|
||||||
|
class LiteralLinearTransformInitializer(AbstractDataAwareLTInitializer):
|
||||||
|
"""'Generate' the provided weights."""
|
||||||
|
|
||||||
|
def generate(self, in_dim: int, out_dim: int):
|
||||||
|
return self.generate_end_hook(self.data)
|
||||||
|
|
||||||
|
|
||||||
# Aliases - Components
|
# Aliases - Components
|
||||||
CACI = ClassAwareCompInitializer
|
CACI = ClassAwareCompInitializer
|
||||||
DACI = DataAwareCompInitializer
|
DACI = DataAwareCompInitializer
|
||||||
@@ -524,7 +547,9 @@ RRI = RandomReasoningsInitializer
|
|||||||
ZRI = ZerosReasoningsInitializer
|
ZRI = ZerosReasoningsInitializer
|
||||||
|
|
||||||
# Aliases - Transforms
|
# Aliases - Transforms
|
||||||
Eye = EyeTransformInitializer
|
ELTI = Eye = EyeLinearTransformInitializer
|
||||||
OLTI = OnesLinearTransformInitializer
|
OLTI = OnesLinearTransformInitializer
|
||||||
|
RLTI = RandomLinearTransformInitializer
|
||||||
ZLTI = ZerosLinearTransformInitializer
|
ZLTI = ZerosLinearTransformInitializer
|
||||||
PCALTI = PCALinearTransformInitializer
|
PCALTI = PCALinearTransformInitializer
|
||||||
|
LLTI = LiteralLinearTransformInitializer
|
||||||
|
@@ -107,14 +107,24 @@ def margin_loss(y_pred, y_true, margin=0.3):
|
|||||||
|
|
||||||
class GLVQLoss(torch.nn.Module):
|
class GLVQLoss(torch.nn.Module):
|
||||||
|
|
||||||
def __init__(self, margin=0.0, transfer_fn="identity", beta=10, **kwargs):
|
def __init__(self,
|
||||||
|
margin=0.0,
|
||||||
|
transfer_fn="identity",
|
||||||
|
beta=10,
|
||||||
|
add_dp=False,
|
||||||
|
**kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.margin = margin
|
self.margin = margin
|
||||||
self.transfer_fn = get_activation(transfer_fn)
|
self.transfer_fn = get_activation(transfer_fn)
|
||||||
self.beta = torch.tensor(beta)
|
self.beta = torch.tensor(beta)
|
||||||
|
self.add_dp = add_dp
|
||||||
|
|
||||||
def forward(self, outputs, targets, plabels):
|
def forward(self, outputs, targets, plabels):
|
||||||
mu = glvq_loss(outputs, targets, prototype_labels=plabels)
|
# mu = glvq_loss(outputs, targets, plabels)
|
||||||
|
dp, dm = _get_dp_dm(outputs, targets, plabels)
|
||||||
|
mu = (dp - dm) / (dp + dm)
|
||||||
|
if self.add_dp:
|
||||||
|
mu = mu + dp
|
||||||
batch_loss = self.transfer_fn(mu + self.margin, beta=self.beta)
|
batch_loss = self.transfer_fn(mu + self.margin, beta=self.beta)
|
||||||
return batch_loss.sum()
|
return batch_loss.sum()
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ from torch.nn.parameter import Parameter
|
|||||||
|
|
||||||
from .initializers import (
|
from .initializers import (
|
||||||
AbstractLinearTransformInitializer,
|
AbstractLinearTransformInitializer,
|
||||||
EyeTransformInitializer,
|
EyeLinearTransformInitializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ class LinearTransform(torch.nn.Module):
|
|||||||
in_dim: int,
|
in_dim: int,
|
||||||
out_dim: int,
|
out_dim: int,
|
||||||
initializer:
|
initializer:
|
||||||
AbstractLinearTransformInitializer = EyeTransformInitializer()):
|
AbstractLinearTransformInitializer = EyeLinearTransformInitializer()):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.set_weights(in_dim, out_dim, initializer)
|
self.set_weights(in_dim, out_dim, initializer)
|
||||||
|
|
||||||
@@ -32,12 +32,15 @@ class LinearTransform(torch.nn.Module):
|
|||||||
in_dim: int,
|
in_dim: int,
|
||||||
out_dim: int,
|
out_dim: int,
|
||||||
initializer:
|
initializer:
|
||||||
AbstractLinearTransformInitializer = EyeTransformInitializer()):
|
AbstractLinearTransformInitializer = EyeLinearTransformInitializer()):
|
||||||
weights = initializer.generate(in_dim, out_dim)
|
weights = initializer.generate(in_dim, out_dim)
|
||||||
self._register_weights(weights)
|
self._register_weights(weights)
|
||||||
|
|
||||||
def forward(self, x):
|
def forward(self, x):
|
||||||
return x @ self.weights
|
return x @ self._weights
|
||||||
|
|
||||||
|
def extra_repr(self):
|
||||||
|
return f"weights: (shape: {tuple(self._weights.shape)})"
|
||||||
|
|
||||||
|
|
||||||
# Aliases
|
# Aliases
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
"""ProtoFlow utils module"""
|
"""ProtoTorch utils module"""
|
||||||
|
|
||||||
from .colors import hex_to_rgb, rgb_to_hex
|
from .colors import (
|
||||||
|
get_colors,
|
||||||
|
get_legend_handles,
|
||||||
|
hex_to_rgb,
|
||||||
|
rgb_to_hex,
|
||||||
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
mesh2d,
|
mesh2d,
|
||||||
parse_data_arg,
|
parse_data_arg,
|
||||||
|
@@ -1,4 +1,13 @@
|
|||||||
"""ProtoFlow color utilities"""
|
"""ProtoTorch color utilities"""
|
||||||
|
|
||||||
|
import matplotlib.lines as mlines
|
||||||
|
import torch
|
||||||
|
from matplotlib import cm
|
||||||
|
from matplotlib.colors import (
|
||||||
|
Normalize,
|
||||||
|
to_hex,
|
||||||
|
to_rgb,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def hex_to_rgb(hex_values):
|
def hex_to_rgb(hex_values):
|
||||||
@@ -13,3 +22,39 @@ def rgb_to_hex(rgb_values):
|
|||||||
for v in rgb_values:
|
for v in rgb_values:
|
||||||
c = "%02x%02x%02x" % tuple(v)
|
c = "%02x%02x%02x" % tuple(v)
|
||||||
yield c
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
def get_colors(vmax, vmin=0, cmap="viridis"):
|
||||||
|
cmap = cm.get_cmap(cmap)
|
||||||
|
colornorm = Normalize(vmin=vmin, vmax=vmax)
|
||||||
|
colors = dict()
|
||||||
|
for c in range(vmin, vmax + 1):
|
||||||
|
colors[c] = to_hex(cmap(colornorm(c)))
|
||||||
|
return colors
|
||||||
|
|
||||||
|
|
||||||
|
def get_legend_handles(colors, labels, marker="dots", zero_indexed=False):
|
||||||
|
handles = list()
|
||||||
|
for color, label in zip(colors.values(), labels):
|
||||||
|
if marker == "dots":
|
||||||
|
handle = mlines.Line2D(
|
||||||
|
xdata=[],
|
||||||
|
ydata=[],
|
||||||
|
label=label,
|
||||||
|
color="white",
|
||||||
|
markerfacecolor=color,
|
||||||
|
marker="o",
|
||||||
|
markersize=10,
|
||||||
|
markeredgecolor="k",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
handle = mlines.Line2D(
|
||||||
|
xdata=[],
|
||||||
|
ydata=[],
|
||||||
|
label=label,
|
||||||
|
color=color,
|
||||||
|
marker="",
|
||||||
|
markersize=15,
|
||||||
|
)
|
||||||
|
handles.append(handle)
|
||||||
|
return handles
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
"""ProtoFlow utilities"""
|
"""ProtoTorch utilities"""
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
from typing import (
|
from typing import (
|
||||||
|
9
setup.py
9
setup.py
@@ -20,9 +20,10 @@ with open("README.md", "r") as fh:
|
|||||||
|
|
||||||
INSTALL_REQUIRES = [
|
INSTALL_REQUIRES = [
|
||||||
"torch>=1.3.1",
|
"torch>=1.3.1",
|
||||||
"torchvision>=0.7.2",
|
"torchvision>=0.7.3",
|
||||||
"numpy>=1.9.1",
|
"numpy>=1.9.1",
|
||||||
"sklearn",
|
"sklearn",
|
||||||
|
"matplotlib",
|
||||||
]
|
]
|
||||||
DATASETS = [
|
DATASETS = [
|
||||||
"requests",
|
"requests",
|
||||||
@@ -40,7 +41,6 @@ DOCS = [
|
|||||||
"sphinx-autodoc-typehints",
|
"sphinx-autodoc-typehints",
|
||||||
]
|
]
|
||||||
EXAMPLES = [
|
EXAMPLES = [
|
||||||
"matplotlib",
|
|
||||||
"torchinfo",
|
"torchinfo",
|
||||||
]
|
]
|
||||||
TESTS = [
|
TESTS = [
|
||||||
@@ -51,7 +51,7 @@ ALL = DATASETS + DEV + DOCS + EXAMPLES + TESTS
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="prototorch",
|
name="prototorch",
|
||||||
version="0.7.2",
|
version="0.7.3",
|
||||||
description="Highly extensible, GPU-supported "
|
description="Highly extensible, GPU-supported "
|
||||||
"Learning Vector Quantization (LVQ) toolbox "
|
"Learning Vector Quantization (LVQ) toolbox "
|
||||||
"built using PyTorch and its nn API.",
|
"built using PyTorch and its nn API.",
|
||||||
@@ -62,7 +62,7 @@ setup(
|
|||||||
url=PROJECT_URL,
|
url=PROJECT_URL,
|
||||||
download_url=DOWNLOAD_URL,
|
download_url=DOWNLOAD_URL,
|
||||||
license="MIT",
|
license="MIT",
|
||||||
python_requires=">=3.7,<3.10",
|
python_requires=">=3.7",
|
||||||
install_requires=INSTALL_REQUIRES,
|
install_requires=INSTALL_REQUIRES,
|
||||||
extras_require={
|
extras_require={
|
||||||
"datasets": DATASETS,
|
"datasets": DATASETS,
|
||||||
@@ -88,6 +88,7 @@ setup(
|
|||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
],
|
],
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
@@ -245,20 +245,20 @@ def test_random_reasonings_init_channels_not_first():
|
|||||||
|
|
||||||
# Transform initializers
|
# Transform initializers
|
||||||
def test_eye_transform_init_square():
|
def test_eye_transform_init_square():
|
||||||
t = pt.initializers.EyeTransformInitializer()
|
t = pt.initializers.EyeLinearTransformInitializer()
|
||||||
I = t.generate(3, 3)
|
I = t.generate(3, 3)
|
||||||
assert torch.allclose(I, torch.eye(3))
|
assert torch.allclose(I, torch.eye(3))
|
||||||
|
|
||||||
|
|
||||||
def test_eye_transform_init_narrow():
|
def test_eye_transform_init_narrow():
|
||||||
t = pt.initializers.EyeTransformInitializer()
|
t = pt.initializers.EyeLinearTransformInitializer()
|
||||||
actual = t.generate(3, 2)
|
actual = t.generate(3, 2)
|
||||||
desired = torch.Tensor([[1, 0], [0, 1], [0, 0]])
|
desired = torch.Tensor([[1, 0], [0, 1], [0, 0]])
|
||||||
assert torch.allclose(actual, desired)
|
assert torch.allclose(actual, desired)
|
||||||
|
|
||||||
|
|
||||||
def test_eye_transform_init_wide():
|
def test_eye_transform_init_wide():
|
||||||
t = pt.initializers.EyeTransformInitializer()
|
t = pt.initializers.EyeLinearTransformInitializer()
|
||||||
actual = t.generate(2, 3)
|
actual = t.generate(2, 3)
|
||||||
desired = torch.Tensor([[1, 0, 0], [0, 1, 0]])
|
desired = torch.Tensor([[1, 0, 0], [0, 1, 0]])
|
||||||
assert torch.allclose(actual, desired)
|
assert torch.allclose(actual, desired)
|
||||||
|
Reference in New Issue
Block a user