learnergy 2.0.1__tar.gz → 2.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. learnergy-2.0.2/AGENTS.md +5 -0
  2. learnergy-2.0.2/CONVENTIONS.md +75 -0
  3. learnergy-2.0.2/MANIFEST.in +1 -0
  4. {learnergy-2.0.1 → learnergy-2.0.2}/PKG-INFO +3 -1
  5. {learnergy-2.0.1 → learnergy-2.0.2}/README.md +2 -0
  6. learnergy-2.0.2/learnergy/__init__.py +6 -0
  7. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/core/__init__.py +3 -0
  8. learnergy-2.0.2/learnergy/core/dataset.py +68 -0
  9. learnergy-2.0.2/learnergy/core/model.py +74 -0
  10. learnergy-2.0.2/learnergy/math/__init__.py +4 -0
  11. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/math/metrics.py +11 -2
  12. learnergy-2.0.2/learnergy/math/scale.py +27 -0
  13. learnergy-2.0.2/learnergy/models/__init__.py +4 -0
  14. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/bernoulli/__init__.py +3 -0
  15. learnergy-2.0.2/learnergy/models/bernoulli/conv_rbm.py +346 -0
  16. learnergy-2.0.2/learnergy/models/bernoulli/discriminative_rbm.py +400 -0
  17. learnergy-2.0.2/learnergy/models/bernoulli/dropout_rbm.py +164 -0
  18. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/bernoulli/e_dropout_rbm.py +61 -77
  19. learnergy-2.0.2/learnergy/models/bernoulli/rbm.py +357 -0
  20. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/deep/__init__.py +3 -0
  21. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/deep/conv_dbn.py +95 -42
  22. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/deep/dbn.py +94 -38
  23. learnergy-2.0.2/learnergy/models/deep/residual_dbn.py +167 -0
  24. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/extra/__init__.py +3 -0
  25. learnergy-2.0.2/learnergy/models/extra/sigmoid_rbm.py +63 -0
  26. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/models/gaussian/__init__.py +3 -0
  27. learnergy-2.0.2/learnergy/models/gaussian/_normalization.py +13 -0
  28. learnergy-2.0.2/learnergy/models/gaussian/gaussian_conv_rbm.py +195 -0
  29. learnergy-2.0.2/learnergy/models/gaussian/gaussian_rbm.py +506 -0
  30. learnergy-2.0.2/learnergy/utils/__init__.py +4 -0
  31. learnergy-2.0.2/learnergy/utils/constants.py +6 -0
  32. learnergy-2.0.2/learnergy/utils/exception.py +99 -0
  33. learnergy-2.0.2/learnergy/utils/logging.py +67 -0
  34. learnergy-2.0.2/learnergy/visual/__init__.py +4 -0
  35. learnergy-2.0.2/learnergy/visual/convergence.py +65 -0
  36. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy/visual/image.py +43 -14
  37. learnergy-2.0.2/learnergy/visual/tensor.py +66 -0
  38. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy.egg-info/PKG-INFO +3 -1
  39. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy.egg-info/SOURCES.txt +3 -0
  40. {learnergy-2.0.1 → learnergy-2.0.2}/pyproject.toml +2 -1
  41. {learnergy-2.0.1 → learnergy-2.0.2}/tests/test_bernoulli.py +4 -3
  42. {learnergy-2.0.1 → learnergy-2.0.2}/tests/test_core.py +9 -1
  43. {learnergy-2.0.1 → learnergy-2.0.2}/tests/test_deep.py +3 -0
  44. {learnergy-2.0.1 → learnergy-2.0.2}/tests/test_gaussian.py +9 -20
  45. {learnergy-2.0.1 → learnergy-2.0.2}/tests/test_utilities.py +22 -5
  46. learnergy-2.0.1/learnergy/__init__.py +0 -5
  47. learnergy-2.0.1/learnergy/core/dataset.py +0 -48
  48. learnergy-2.0.1/learnergy/core/model.py +0 -58
  49. learnergy-2.0.1/learnergy/math/__init__.py +0 -1
  50. learnergy-2.0.1/learnergy/math/scale.py +0 -14
  51. learnergy-2.0.1/learnergy/models/__init__.py +0 -1
  52. learnergy-2.0.1/learnergy/models/bernoulli/conv_rbm.py +0 -359
  53. learnergy-2.0.1/learnergy/models/bernoulli/discriminative_rbm.py +0 -403
  54. learnergy-2.0.1/learnergy/models/bernoulli/dropout_rbm.py +0 -167
  55. learnergy-2.0.1/learnergy/models/bernoulli/rbm.py +0 -359
  56. learnergy-2.0.1/learnergy/models/deep/residual_dbn.py +0 -130
  57. learnergy-2.0.1/learnergy/models/extra/sigmoid_rbm.py +0 -34
  58. learnergy-2.0.1/learnergy/models/gaussian/_normalization.py +0 -13
  59. learnergy-2.0.1/learnergy/models/gaussian/gaussian_conv_rbm.py +0 -128
  60. learnergy-2.0.1/learnergy/models/gaussian/gaussian_rbm.py +0 -554
  61. learnergy-2.0.1/learnergy/utils/__init__.py +0 -1
  62. learnergy-2.0.1/learnergy/utils/constants.py +0 -3
  63. learnergy-2.0.1/learnergy/utils/exception.py +0 -40
  64. learnergy-2.0.1/learnergy/utils/logging.py +0 -37
  65. learnergy-2.0.1/learnergy/visual/__init__.py +0 -1
  66. learnergy-2.0.1/learnergy/visual/convergence.py +0 -41
  67. learnergy-2.0.1/learnergy/visual/tensor.py +0 -38
  68. {learnergy-2.0.1 → learnergy-2.0.2}/LICENSE +0 -0
  69. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy.egg-info/dependency_links.txt +0 -0
  70. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy.egg-info/requires.txt +0 -0
  71. {learnergy-2.0.1 → learnergy-2.0.2}/learnergy.egg-info/top_level.txt +0 -0
  72. {learnergy-2.0.1 → learnergy-2.0.2}/setup.cfg +0 -0
@@ -0,0 +1,5 @@
1
+ # Contributor and agent guidance
2
+
3
+ Read and follow [CONVENTIONS.md](CONVENTIONS.md) before changing this repository.
4
+ Preserve public behavior and checkpoint compatibility unless the task explicitly changes them.
5
+ Use the existing validation tools and keep unrelated or concurrent work intact.
@@ -0,0 +1,75 @@
1
+ # Learnergy conventions
2
+
3
+ Learnergy adopts the applicable code-style rules from cpmux's phitrain-derived conventions.
4
+ These rules govern new code and convention updates without authorizing unrelated algorithm or API changes.
5
+
6
+ ## Compatibility and scope
7
+
8
+ - Keep the current Python 3.11 minimum. Use the requested modern Python idioms where they are compatible with it.
9
+ - Preserve public imports, model names, constructor options, return values, normalization policies, and checkpoint state.
10
+ - Keep Learnergy's domain-oriented package layout and public package exports. cpmux's empty package initializers,
11
+ CLI architecture, Pydantic choices, and test-layout migration are not part of this adoption.
12
+ - Tests remain grouped by the existing model families. Runtime validation rules do not prohibit test assertions.
13
+
14
+ ## Code style
15
+
16
+ - Use `X | None`, builtin generics such as `list[str]`, and ABCs from `collections.abc`.
17
+ Import only typing-specific constructs such as `Any` and `Literal` from `typing`. (R2)
18
+ - Start every Python file with the project header:
19
+
20
+ ```python
21
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
22
+ # Licensed under the Apache License, Version 2.0.
23
+ ```
24
+
25
+ - Keep imports top-level, absolute, and grouped as standard library, third-party, then Learnergy imports.
26
+ - Use double-quoted strings. Code formatting and readable prose use a 120-character limit. (R9)
27
+ - Public functions, regular classes, and explicit constructors have Google-style docstrings.
28
+ Use a single-sentence summary and one-line `Args:`, `Returns:`, and `Raises:` entries as applicable.
29
+ Do not put semicolons or `defaults to ...` tails in entries. (R3, R13)
30
+ - A regular class has a one-sentence class summary. Constructor arguments belong on `__init__`, not the class.
31
+ Preserve mathematical references and substantive behavioral notes in module or operation documentation.
32
+ - Multiline docstrings have one blank line before the closing triple quotes and one blank line after them
33
+ before code or fields. Keep class and module summaries on one line when they need no other content,
34
+ matching cpmux's examples and Black's normalization.
35
+ - Private helpers have no docstrings. Framework-dispatched overrides such as `forward`, `__getitem__`, and
36
+ `__len__` have no docstrings. Document their relevant contracts in public sampling methods, constructors,
37
+ module documentation, or the user guide instead.
38
+ - Data classes without an explicit constructor document each field on one line in an `Attributes:` section.
39
+ This rule does not require introducing data classes into existing models.
40
+ - Public contracts describe tensor shapes, tuple element order, mutation, history, normalization, gradient
41
+ boundaries, and failure behavior where relevant. An annotation is not runtime validation.
42
+ - Obtain library loggers with `get_logger(__name__)` from `learnergy.utils.logging`.
43
+ Do not use `print()` in library code. Application examples may print their results.
44
+ - Warning and error diagnostics identify a backticked offender and end with a period, for example
45
+ `` f"`name={value}` could not be loaded." ``. Info and debug messages stay plain. (R14)
46
+ - Raised messages use `` "`name` <verb phrase>[, but got <value>]." ``.
47
+ Use `is None` and `is True` prose rather than comparison operators in messages. (R1)
48
+ - Validate with `if` and a specific raised exception, never a runtime `assert`. Do not use bare `except:`.
49
+ - Comments explain why rather than narrating the next statement. Prefer no comment or one line, with a
50
+ three-line maximum, no banners, and no trailing period. Copyright and license notices are exempt. (R8)
51
+ - Separate logical phases with one blank line in function bodies of at least 12 lines. (R11)
52
+ - Inline new single-use implementation details. Extract a helper, constant, or configurable parameter when
53
+ a second call-site establishes reuse. Do not delete published APIs or required callbacks by counting only
54
+ their internal call-sites. (R16)
55
+
56
+ ## Tests and review
57
+
58
+ - Test functions and fixtures are plain functions without docstrings. Test functions have no type annotations.
59
+ - Use bare assertions without failure-message strings. Names should describe the observable behavior.
60
+ - Preserve seeded behavior when claiming a behavior-preserving refactor. Treat deliberate numerical changes
61
+ as separate, explicit changes rather than hiding them in a style pass.
62
+ - Regression tests compare actual model output with an independently justified expectation and should fail
63
+ for the defect they claim to prevent.
64
+
65
+ ## Tooling
66
+
67
+ Use the existing pinned Black, isort, and flake8 tools at line length 120.
68
+ The supported interpreter range, dependencies, and build backend do not change as part of this style adoption.
69
+
70
+ ```text
71
+ uv sync --locked --extra docs
72
+ uv run pre-commit run --all-files
73
+ uv run pytest
74
+ uv run python -m sphinx -W -b html docs build
75
+ ```
@@ -0,0 +1 @@
1
+ include AGENTS.md CONVENTIONS.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: learnergy
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: Energy-based machine learners built with PyTorch
5
5
  Author-email: Mateus Roder <mateus.roder@unesp.br>, Gustavo de Rosa <gustavo.rosa@unesp.br>
6
6
  License-Expression: Apache-2.0
@@ -140,6 +140,8 @@ can change training trajectories, including with a fixed random seed.
140
140
 
141
141
  ## Development
142
142
 
143
+ Follow [the coding conventions](CONVENTIONS.md) when changing the library or its examples.
144
+
143
145
  The repository uses [uv](https://docs.astral.sh/uv/) for reproducible
144
146
  environments and packaging:
145
147
 
@@ -103,6 +103,8 @@ can change training trajectories, including with a fixed random seed.
103
103
 
104
104
  ## Development
105
105
 
106
+ Follow [the coding conventions](CONVENTIONS.md) when changing the library or its examples.
107
+
106
108
  The repository uses [uv](https://docs.astral.sh/uv/) for reproducible
107
109
  environments and packaging:
108
110
 
@@ -0,0 +1,6 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Provide energy-based learning models built with PyTorch."""
5
+
6
+ __version__ = "2.0.2"
@@ -1,3 +1,6 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
1
4
  """Core model primitives."""
2
5
 
3
6
  from learnergy.core.dataset import Dataset
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Adapt array-backed samples to the PyTorch dataset interface."""
5
+
6
+ from collections.abc import Callable
7
+ from typing import Any
8
+
9
+ import torch
10
+
11
+ import learnergy.utils.exception as e
12
+ from learnergy.core.model import _validated_property
13
+ from learnergy.utils.logging import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class Dataset(torch.utils.data.Dataset):
19
+ """Expose samples and targets with an optional sample transform."""
20
+
21
+ data = _validated_property("data", doc="Backing sample collection, retained without copying.")
22
+ targets = _validated_property("targets", doc="Targets indexed alongside the sample collection.")
23
+ transform = _validated_property(
24
+ "transform",
25
+ lambda _, value: value is None or callable(value),
26
+ e.TypeError,
27
+ "`transform` should be callable or None.",
28
+ doc="Optional transformation applied when a sample is accessed.",
29
+ )
30
+
31
+ def __init__(
32
+ self,
33
+ data: Any,
34
+ targets: Any,
35
+ transform: Callable[[Any], Any] | None = None,
36
+ show_log: bool = True,
37
+ ) -> None:
38
+ """Store sample and target references for indexed access.
39
+
40
+ Data is not copied and transforms are applied on access rather than during initialization.
41
+
42
+ Args:
43
+ data: Indexable sample collection.
44
+ targets: Indexable target collection aligned with the samples.
45
+ transform: Optional callable that transforms an individual sample.
46
+ show_log: Whether to log dataset creation.
47
+
48
+ Raises:
49
+ TypeError: The transform is neither callable nor None.
50
+
51
+ """
52
+
53
+ self.data = data
54
+ self.targets = targets
55
+ self.transform = transform
56
+
57
+ if show_log:
58
+ logger.info("Creating class: Dataset.")
59
+ logger.info("Class created.")
60
+
61
+ def __getitem__(self, idx: int) -> tuple[Any, Any]:
62
+ sample = self.data[idx]
63
+ if self.transform:
64
+ sample = self.transform(sample)
65
+ return sample, self.targets[idx]
66
+
67
+ def __len__(self) -> int:
68
+ return len(self.data)
@@ -0,0 +1,74 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Provide shared model state and validated attributes."""
5
+
6
+ from collections.abc import Callable
7
+ from typing import Any
8
+
9
+ import torch
10
+
11
+ import learnergy.utils.exception as e
12
+
13
+
14
+ def _validated_property(
15
+ name: str,
16
+ validator: Callable[[Any, Any], bool] | None = None,
17
+ error: type[Exception] = ValueError,
18
+ message: str = "`value` is invalid.",
19
+ *,
20
+ doc: str | None = None,
21
+ ) -> property:
22
+ storage_name = f"_{name}"
23
+
24
+ def _get(instance: Any) -> Any:
25
+ return getattr(instance, storage_name)
26
+
27
+ def _set(instance: Any, value: Any) -> None:
28
+ if validator is not None and not validator(instance, value):
29
+ raise error(message)
30
+
31
+ setattr(instance, storage_name, value)
32
+
33
+ return property(_get, _set, doc=doc)
34
+
35
+
36
+ class Model(torch.nn.Module):
37
+ """Provide device selection and metric history for energy-based models."""
38
+
39
+ device = _validated_property(
40
+ "device",
41
+ lambda _, value: value in ("cpu", "cuda"),
42
+ e.TypeError,
43
+ "`device` should be `cpu` or `cuda`.",
44
+ doc="Computation device selected during initialization.",
45
+ )
46
+ history = _validated_property("history", doc="Recorded values grouped into lists by metric name.")
47
+
48
+ def __init__(self, use_gpu: bool = False) -> None:
49
+ """Initialize device selection and an empty metric history.
50
+
51
+ Initialization sets PyTorch's process-wide default floating-point dtype to float32.
52
+
53
+ Args:
54
+ use_gpu: Whether to select CUDA when it is available.
55
+
56
+ """
57
+
58
+ super().__init__()
59
+ torch.set_default_dtype(torch.float32)
60
+ self.device = "cuda" if use_gpu and torch.cuda.is_available() else "cpu"
61
+ self.history = {}
62
+
63
+ def dump(self, **kwargs: Any) -> None:
64
+ """Append values to their per-metric history lists.
65
+
66
+ Existing history is retained and values are stored without conversion or copying.
67
+
68
+ Args:
69
+ **kwargs: Values keyed by the metric names to update.
70
+
71
+ """
72
+
73
+ for k, v in kwargs.items():
74
+ self.history.setdefault(k, []).append(v)
@@ -0,0 +1,4 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Mathematical helpers."""
@@ -1,4 +1,7 @@
1
- """Image similarity metrics."""
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Calculate image similarity metrics."""
2
5
 
3
6
  import torch
4
7
  from skimage.metrics import structural_similarity
@@ -7,12 +10,18 @@ from skimage.metrics import structural_similarity
7
10
  def calculate_ssim(v: torch.Tensor, x: torch.Tensor) -> float:
8
11
  """Calculate the mean structural similarity of reconstructed images.
9
12
 
13
+ Tensors are detached and copied to CPU as needed before comparison.
14
+ Each original image supplies its own intensity range to the SSIM calculation.
15
+
10
16
  Args:
11
17
  v: Reconstructed images, with each image flattened or shaped like its original.
12
18
  x: Original grayscale images with shape (batch, height, width).
13
19
 
20
+ Returns:
21
+ Mean SSIM over the paired images.
22
+
14
23
  Raises:
15
- ValueError: The batches contain different numbers of images.
24
+ ValueError: Batch lengths, image shapes, or SSIM window requirements are incompatible.
16
25
 
17
26
  """
18
27
 
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """Normalize numerical arrays."""
5
+
6
+ import numpy as np
7
+
8
+ from learnergy.utils.constants import EPSILON
9
+
10
+
11
+ def unitary_scale(x: np.ndarray) -> np.ndarray:
12
+ """Return a float32 copy scaled by its value range.
13
+
14
+ The input is not modified and finite constant arrays become zero arrays.
15
+
16
+ Args:
17
+ x: Numeric array to scale.
18
+
19
+ Returns:
20
+ Float32 array of the same shape, normalized with an epsilon guard.
21
+
22
+ """
23
+
24
+ scaled = x.astype("float32")
25
+ scaled -= scaled.min()
26
+ scaled /= scaled.max() + EPSILON
27
+ return scaled
@@ -0,0 +1,4 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
4
+ """A package contaning subpackages of models for all common learnergy modules."""
@@ -1,3 +1,6 @@
1
+ # Copyright (c) 2020-2026 Mateus Roder and Gustavo de Rosa.
2
+ # Licensed under the Apache License, Version 2.0.
3
+
1
4
  """Bernoulli-valued RBM variants."""
2
5
 
3
6
  from learnergy.models.bernoulli.conv_rbm import ConvRBM