From d5610c782117435b5d6e9be3c1b4d01d9e89d56f Mon Sep 17 00:00:00 2001 From: Alejandro Moreo Date: Thu, 20 Aug 2026 11:40:55 +0200 Subject: [PATCH] adding histnet --- docs/source/quapy.method.rst | 2 +- quapy/__init__.py | 2 +- quapy/method/_histnet.py | 21 ++++++++++++++++----- quapy/method/{_neural.py => _quanet.py} | 0 quapy/method/meta.py | 8 ++++---- quapy/tests/test_methods.py | 1 + 6 files changed, 23 insertions(+), 11 deletions(-) rename quapy/method/{_neural.py => _quanet.py} (100%) diff --git a/docs/source/quapy.method.rst b/docs/source/quapy.method.rst index 88fcc7d..379b6d5 100644 --- a/docs/source/quapy.method.rst +++ b/docs/source/quapy.method.rst @@ -17,7 +17,7 @@ quapy.method.aggregative module :undoc-members: :show-inheritance: -.. automodule:: quapy.method._neural +.. automodule:: quapy.method._quanet :members: :undoc-members: :show-inheritance: diff --git a/quapy/__init__.py b/quapy/__init__.py index 3cf5fc3..4ed6726 100644 --- a/quapy/__init__.py +++ b/quapy/__init__.py @@ -17,7 +17,7 @@ try: except ImportError: plot = None -__version__ = '0.2.1.post1' +__version__ = '0.2.2' def _default_cls(): diff --git a/quapy/method/_histnet.py b/quapy/method/_histnet.py index ce2420c..ac4cc40 100644 --- a/quapy/method/_histnet.py +++ b/quapy/method/_histnet.py @@ -1,17 +1,21 @@ """ -HistNetQ implementation. +HistNetQ implementation, see the original paper: + +Pérez-Mon, O., Moreo, A., Coz, JJ del, & González, P. (2025). +Quantification using permutation-invariant networks based on histograms. +Neural Computing and Applications, 37(5), 3505-3520. Ported from the reference implementation at https://github.com/pglez84/histnetq (the `HistNet`/ `DLQuantification` classes in that repo), adapted to QuaPy's own protocol-based sample generation (replacing that repo's custom, `quantificationlib`-backed bag generators) and restricted, for now, to -the "hard" differentiable histogram variant: +the "hard" differentiable histogram variant by: Yusuf, I., Igwegbe, G., and Azeez, O. "Differentiable Histogram with Hard-Binning." arXiv preprint arXiv:2012.06311 (2020). The overall architecture is: feature_extraction -> Sigmoid -> histogram layer -> small MLP -> softmax, trained by minimizing a quantification loss over samples ("bags") of known prevalence, rather than -over individually labeled instances (in the spirit of QuaNet, see method/_neural.py). +over individually labeled instances (in the spirit of QuaNet, see method/_quanet.py). """ import copy import os @@ -177,10 +181,17 @@ class HistNetQ(BaseQuantifier): Implementation of `HistNetQ `_, a neural network for quantification that learns a differentiable histogram-based representation of a sample, trained end-to-end by minimizing a quantification loss over many samples ("bags") of known prevalence. + The method was proposed in `Pérez-Mon, O., Moreo, A., Coz, JJ del, & González, P. (2025). + Quantification using permutation-invariant networks based on histograms. + Neural Computing and Applications, 37(5), 3505-3520. + `_ HistNetQ does not follow the classify-then-aggregate pattern of :class:`quapy.method.aggregative. - AggregativeQuantifier`; like :class:`quapy.method.meta.QuaNet`, it is trained and evaluated - end-to-end on whole samples rather than on individually labeled instances. + AggregativeQuantifier`. Such classical approach is termed asymmetric, in the sense that quantifiers + learn from labelled instances and perform inference over bags. + Like :class:`quapy.method.meta.QuaNet`, HistNetQ is trained and evaluated + end-to-end on whole samples rather than on individually labeled instances, following a symmetric problem setting + (learning from bags, predicting on bags). Training data can be provided in two ways: diff --git a/quapy/method/_neural.py b/quapy/method/_quanet.py similarity index 100% rename from quapy/method/_neural.py rename to quapy/method/_quanet.py diff --git a/quapy/method/meta.py b/quapy/method/meta.py index 4d1d4ae..7d15b7c 100644 --- a/quapy/method/meta.py +++ b/quapy/method/meta.py @@ -16,13 +16,13 @@ from quapy.method.base import BaseQuantifier, BinaryQuantifier from quapy.method.aggregative import CC, ACC, PACC, HDy, EMQ, AggregativeQuantifier, AggregativeSoftQuantifier try: - from . import _neural + from . import _quanet except ModuleNotFoundError: - _neural = None + _quanet = None -if _neural: - QuaNet = _neural.QuaNetTrainer +if _quanet: + QuaNet = _quanet.QuaNetTrainer else: QuaNet = "QuaNet is not available due to missing torch package" diff --git a/quapy/tests/test_methods.py b/quapy/tests/test_methods.py index fd7b2c8..dfd3b12 100644 --- a/quapy/tests/test_methods.py +++ b/quapy/tests/test_methods.py @@ -126,6 +126,7 @@ class TestMethods(unittest.TestCase): estim_prevalences2 = model2.predict(dataset.test.X) self.assertTrue(check_prevalence_vector(estim_prevalences2)) + def test_composable(self): try: from quapy.method.composable import check_compatible_qunfold_version