diff --git a/abl/bridge/base_bridge.py b/abl/bridge/base_bridge.py index 4ea87ac..976c781 100644 --- a/abl/bridge/base_bridge.py +++ b/abl/bridge/base_bridge.py @@ -2,23 +2,23 @@ from abc import ABCMeta, abstractmethod from typing import Any, List, Optional, Tuple, Union from ..learning import ABLModel -from ..reasoning import ReasonerBase +from ..reasoning import Reasoner from ..structures import ListData DataSet = Tuple[List[List[Any]], Optional[List[List[Any]]], List[List[Any]]] class BaseBridge(metaclass=ABCMeta): - def __init__(self, model: ABLModel, reasoner: ReasonerBase) -> None: + def __init__(self, model: ABLModel, reasoner: Reasoner) -> None: if not isinstance(model, ABLModel): raise TypeError( "Expected an instance of ABLModel, but received type: {}".format( type(model) ) ) - if not isinstance(reasoner, ReasonerBase): + if not isinstance(reasoner, Reasoner): raise TypeError( - "Expected an instance of ReasonerBase, but received type: {}".format( + "Expected an instance of Reasoner, but received type: {}".format( type(reasoner) ) ) diff --git a/abl/bridge/simple_bridge.py b/abl/bridge/simple_bridge.py index 49daeab..1a66492 100644 --- a/abl/bridge/simple_bridge.py +++ b/abl/bridge/simple_bridge.py @@ -5,7 +5,7 @@ from numpy import ndarray from ..evaluation import BaseMetric from ..learning import ABLModel -from ..reasoning import ReasonerBase +from ..reasoning import Reasoner from ..structures import ListData from ..utils import print_log from .base_bridge import BaseBridge, DataSet @@ -15,7 +15,7 @@ class SimpleBridge(BaseBridge): def __init__( self, model: ABLModel, - reasoner: ReasonerBase, + reasoner: Reasoner, metric_list: List[BaseMetric], ) -> None: super().__init__(model, reasoner) diff --git a/abl/reasoning/__init__.py b/abl/reasoning/__init__.py index f2ff627..0df88c0 100644 --- a/abl/reasoning/__init__.py +++ b/abl/reasoning/__init__.py @@ -1,2 +1,2 @@ from .kb import KBBase, GroundKB, PrologKB -from .reasoner import ReasonerBase \ No newline at end of file +from .reasoner import Reasoner \ No newline at end of file diff --git a/abl/reasoning/kb.py b/abl/reasoning/kb.py index b8a8d4a..3254be6 100644 --- a/abl/reasoning/kb.py +++ b/abl/reasoning/kb.py @@ -34,8 +34,8 @@ class KBBase(ABC): key_func : func, optional A function employed for hashing in abl_cache. This is only operational when use_cache is set to True. Defaults to to_hashable. - max_cache_size: int, optional - The maximum cache size in abl_cache. This is only operational when use_cache is set to + cache_size: int, optional + The cache size in abl_cache. This is only operational when use_cache is set to True. Defaults to 4096. Notes @@ -53,7 +53,7 @@ class KBBase(ABC): max_err=1e-10, use_cache=True, key_func=to_hashable, - max_cache_size=4096, + cache_size=4096, ): if not isinstance(pseudo_label_list, list): raise TypeError("pseudo_label_list should be list") @@ -62,7 +62,7 @@ class KBBase(ABC): self.use_cache = use_cache self.key_func = key_func - self.max_cache_size = max_cache_size + self.cache_size = cache_size @abstractmethod def logic_forward(self, pseudo_label): diff --git a/abl/reasoning/reasoner.py b/abl/reasoning/reasoner.py index fd54286..9f250f5 100644 --- a/abl/reasoning/reasoner.py +++ b/abl/reasoning/reasoner.py @@ -8,7 +8,7 @@ from ..utils.utils import ( ) -class ReasonerBase: +class Reasoner: """ Base class for reasoner. @@ -35,7 +35,7 @@ class ReasonerBase: Specifies additional number of revisions permitted beyond the minimum required when performing abductive reasoning. Defaults to 0. use_zoopt : bool, optional - Whether to use the Zoopt library during abductive reasoning. Defaults to False. + Whether to use ZOOpt library during abductive reasoning. Defaults to False. """ def __init__(self, @@ -126,7 +126,7 @@ class ReasonerBase: self, symbol_num, data_sample, max_revision_num ): """ - Get the optimal solution using the Zoopt library. The solution is a list of + Get the optimal solution using ZOOpt library. The solution is a list of boolean values, where '1' (True) indicates the indices chosen to be revised. Parameters @@ -152,7 +152,7 @@ class ReasonerBase: def zoopt_revision_score(self, symbol_num, data_sample, sol): """ - Get the revision score for a solution. A lower score suggests that the Zoopt library + Get the revision score for a solution. A lower score suggests that ZOOpt library has a higher preference for this solution. """ revision_idx = np.where(sol.get_x() != 0)[0] diff --git a/abl/utils/cache.py b/abl/utils/cache.py index a927e1f..d308fba 100644 --- a/abl/utils/cache.py +++ b/abl/utils/cache.py @@ -36,7 +36,7 @@ class Cache(Generic[K, T]): self.cache = True self.cache_dict = dict() self.key_func = obj.key_func - self.max_size = obj.max_cache_size + self.max_size = obj.cache_size self.hits, self.misses = 0, 0 self.full = False diff --git a/docs/Examples/MNISTAdd.rst b/docs/Examples/MNISTAdd.rst index fc52de5..62b343f 100644 --- a/docs/Examples/MNISTAdd.rst +++ b/docs/Examples/MNISTAdd.rst @@ -1,7 +1,7 @@ -MNIST Add -================== +MNIST Addition +============== -MNIST Add was first introduced in [1] and the inputs of this task are pairs of MNIST images and the outputs are their sums. The dataset looks like this: +MNIST Addition was first introduced in [1] and the inputs of this task are pairs of MNIST images and the outputs are their sums. The dataset looks like this: .. image:: ../img/image_1.jpg :width: 350px diff --git a/docs/Intro/Basics.rst b/docs/Intro/Basics.rst index 93142b6..e1cfee2 100644 --- a/docs/Intro/Basics.rst +++ b/docs/Intro/Basics.rst @@ -41,7 +41,7 @@ learning. The class ``KBBase`` allows users to instantiate domain knowledge base. For diverse types of knowledge, we also offer implementations like ``GroundKB`` and ``PrologKB``, e.g., the latter enables knowledge base to be imported in the form of a Prolog files. -Upon building the knowledge base, the class ``ReasonerBase`` is +Upon building the knowledge base, the class ``Reasoner`` is responsible for minimizing the inconsistency between the knowledge base and learning models. @@ -81,7 +81,7 @@ To implement this process, the following five steps are necessary: Build a knowledge base by building a subclass of ``KBBase``, defining how to map pseudo labels to reasoning results. - Also, instantiate a ``ReasonerBase`` for minimizing of inconsistencies + Also, instantiate a ``Reasoner`` for minimizing of inconsistencies between the knowledge base and pseudo labels. 4. Define Evaluation Metrics diff --git a/docs/Intro/Bridge.rst b/docs/Intro/Bridge.rst index 12d59ce..241f7b8 100644 --- a/docs/Intro/Bridge.rst +++ b/docs/Intro/Bridge.rst @@ -15,7 +15,7 @@ Bridging machine learning and reasoning to train the model is the fundamental id ``BaseBridge`` is an abstract class with the following initialization parameters: - ``model``: an object of type ``ABLModel``. Machine Learning part are wrapped in this object. -- ``reasoner``: a object of type ``ReasonerBase``. Reasoning part are wrapped in this object. +- ``reasoner``: a object of type ``Reasoner``. Reasoning part are wrapped in this object. ``BaseBridge`` has the following important methods that need to be overridden in subclasses: diff --git a/docs/Intro/Datasets.rst b/docs/Intro/Datasets.rst index bd5587e..e50b32d 100644 --- a/docs/Intro/Datasets.rst +++ b/docs/Intro/Datasets.rst @@ -22,7 +22,7 @@ ABL-Package offers several `dataset classes <../API/abl.dataset.html>`_ for diff - ``Y``: List[Any] A list of objects representing the ground truth label of the reasoning result of each instance in ``X``. -In the MNIST Add example, the data used for training looks like: +In the MNIST Addition example, the data used for training looks like: .. image:: ../img/Datasets_1.png :width: 350px diff --git a/docs/Intro/Quick-Start.rst b/docs/Intro/Quick-Start.rst index 0eea012..eb35842 100644 --- a/docs/Intro/Quick-Start.rst +++ b/docs/Intro/Quick-Start.rst @@ -18,7 +18,7 @@ Working with Data ABL-Package assumes data to be in the form of ``(X, gt_pseudo_label, Y)`` where ``X`` is the input of the machine learning model, ``gt_pseudo_label`` is the ground truth label of each element in ``X`` and ``Y`` is the ground truth reasoning result of each instance in ``X``. -In the MNIST Add task, the data loading looks like +In the MNIST Addition task, the data loading looks like .. code:: python @@ -75,7 +75,7 @@ Read more about `preparing datasets `_. Building the Learning Part ---------------------------------- -To build the machine learning part, we need to wrap our machine learning model into the ``ABLModel`` class. The machine learning model can either be a scikit-learn model or a PyTorch neural network. We use a simple LeNet5 in the MNIST Add example. +To build the machine learning part, we need to wrap our machine learning model into the ``ABLModel`` class. The machine learning model can either be a scikit-learn model or a PyTorch neural network. We use a simple LeNet5 in the MNIST Addition example. .. code:: python @@ -143,15 +143,15 @@ function specifying how to perform (deductive) reasoning. kb = AddKB(pseudo_label_list=list(range(10))) Then, we create a reasoner by defining an instance of class -``ReasonerBase`` and passing the knowledge base as an parameter. +``Reasoner`` and passing the knowledge base as an parameter. The reasoner can be used to minimize inconsistencies between the knowledge base and the prediction from the learning part. .. code:: python - from abl.reasoning import ReasonerBase + from abl.reasoning import Reasoner - reasoner = ReasonerBase(kb) + reasoner = Reasoner(kb) Read more about `building the reasoning part `_. @@ -161,7 +161,7 @@ Building Evaluation Metrics ABL-Package provides two basic metrics, namely ``SymbolMetric`` and ``SemanticsMetric``, which are used to evaluate the accuracy of the machine learning model's predictions and the accuracy of the ``logic_forward`` results, respectively. -In the case of MNIST Add example, the metric definition looks like +In the case of MNIST Addition example, the metric definition looks like .. code:: python @@ -193,8 +193,8 @@ Training log would be similar to this: .. code-block:: none - 2023/12/02 21:26:57 - abl - INFO - Abductive Learning on the MNIST Add example. - 2023/12/02 21:32:20 - abl - INFO - Abductive Learning on the MNIST Add example. + 2023/12/02 21:26:57 - abl - INFO - Abductive Learning on the MNIST Addition example. + 2023/12/02 21:32:20 - abl - INFO - Abductive Learning on the MNIST Addition example. 2023/12/02 21:32:51 - abl - INFO - loop(train) [1/5] segment(train) [1/3] model loss is 1.85589 2023/12/02 21:32:56 - abl - INFO - loop(train) [1/5] segment(train) [2/3] model loss is 1.50332 2023/12/02 21:33:02 - abl - INFO - loop(train) [1/5] segment(train) [3/3] model loss is 1.17501 diff --git a/docs/Intro/Reasoning.rst b/docs/Intro/Reasoning.rst index a3af967..53a516f 100644 --- a/docs/Intro/Reasoning.rst +++ b/docs/Intro/Reasoning.rst @@ -14,7 +14,7 @@ In ABL-Package, constructing the reasoning part involves two steps: 1. Build a knowledge base by creating a subclass of ``KBBase``, which defines how to map pseudo labels to reasoning results. -2. Define a reasoner by creating an instance of class ``ReasonerBase`` +2. Define a reasoner by creating an instance of class ``Reasoner`` to minimize inconsistencies between the knowledge base and pseudo labels predicted by the learning part. @@ -25,34 +25,34 @@ Build your knowledge base from `KBBase` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Generally, users can inherit from class ``KBBase`` to build your own -knowledge base. For the user-built KB (an inherited subclass), it’s only +knowledge base. For the user-built KB (an inherited subclass), it's only required to initialize the ``pseudo_label_list`` parameter and override the ``logic_forward`` function: - **pseudo_label_list** is the list of possible pseudo labels (also, the output of the machine learning model). - **logic_forward** defines how to perform (deductive) reasoning, - i.e. matching each pseudo label to their reasoning result. + i.e. matching each pseudo label to their reasoning result. After that, other operations, including how to perform abductive reasoning, will be **automatically** set up. -MNIST Add example -^^^^^^^^^^^^^^^^^ +MNIST Addition example +^^^^^^^^^^^^^^^^^^^^^^ -As an example, the ``pseudo_label_list`` passed in MNIST Add is all the +As an example, the ``pseudo_label_list`` passed in MNIST Addition is all the possible digits, namely, ``[0,1,2,...,9]``, and the ``logic_forward`` is: “Add two pseudo labels to get the result.”. Therefore, the -construction of the KB (``add_kb``) of MNIST Add would be: +construction of the KB (``add_kb``) of MNIST Addition would be: .. code:: python class AddKB(KBBase): - def __init__(self, pseudo_label_list=list(range(10))): - super().__init__(pseudo_label_list) + def __init__(self, pseudo_label_list=list(range(10))): + super().__init__(pseudo_label_list) - def logic_forward(self, pseudo_labels): - return sum(pseudo_labels) + def logic_forward(self, pseudo_labels): + return sum(pseudo_labels) add_kb = AddKB() @@ -65,7 +65,7 @@ You can also initialize the following parameters when building your knowledge base: - **max_err** (float, optional), specifying the upper tolerance limit - when comparing the similarity between a candidate’s reasoning result + when comparing the similarity between a candidate's reasoning result and the ground truth during abductive reasoning. This is only applicable when the reasoning result is of a numerical type. This is particularly relevant for regression problems where exact matches @@ -73,7 +73,7 @@ knowledge base: - **use_cache** (bool, optional), indicating whether to use cache for previously abduced candidates to speed up subsequent abductive reasoning operations. Defaults to True. Defaults to True. -- **max_cache_size** (int, optional), specifying the maximum cache +- **cache_size** (int, optional), specifying the maximum cache size. This is only operational when ``use_cache`` is set to True. Defaults to 4096. @@ -82,13 +82,13 @@ Diverse choices for building knowledge base In addition to building your own knowledge base through inheriting from class ``KBBase``, ABL-Package also offers several predefined subclasses of ``KBBase``, -which you can utilize to construct your knowledge base. +which you can utilize to construct your knowledge base more conveniently. Build your Knowledge base from Prolog file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For users aiming to leverage knowledge base from an external Prolog file -(which contain how to perform reasoning), they may directly creating an +(which contains how to perform reasoning), they can directly create an instance of class ``PrologKB``. Specifically, upon instantiation of ``PrologKB``, users are required to provide the ``pseudo_label_list`` and ``pl_file`` (the Prolog file). @@ -104,10 +104,10 @@ abductive reasoning, will also be **automatically** set up. Otherwise, users might have to override ``logic_forward`` and ``get_query_string`` to allow for more adaptable usage. -MNIST Add example (cont.) -""""""""""""""""""""""""" +MNIST Addition example (cont.) +""""""""""""""""""""""""""""""" -As an example, one can first write a Prolog file for the MNISTAdd +As an example, one can first write a Prolog file for the MNIST Addition example as the following code, and then save it as ``add.pl``. .. code:: prolog @@ -132,7 +132,7 @@ knowledge base. In this way, the knowledge built will have a Ground KB .. admonition:: What is Ground KB? - Ground KB is a knowledge base prebuilt upon class initialization, + `Ground KB `_ is a knowledge base prebuilt upon class initialization, storing all potential candidates along with their respective reasoning result. The key advantage of having a Ground KB is that it may accelerate abductive reasoning. @@ -148,12 +148,12 @@ override the ``logic_forward`` function, and are allowed to pass other After that, other operations, including auto-construction of GKB, and how to perform abductive reasoning, will be **automatically** set up. -MNIST Add example (cont.) -""""""""""""""""""""""""" +MNIST Addition example (cont.) +""""""""""""""""""""""""""""""" -As an example, the ``GKB_len_list`` for MNISTAdd should be ``[2]``, +As an example, the ``GKB_len_list`` for MNIST Addition should be ``[2]``, since all pseudo labels in the example consist of two digits. Therefore, -the construction of KB with GKB (``add_ground_kb``) of MNISTAdd would be +the construction of KB with GKB (``add_ground_kb``) of MNIST Addition would be as follows. As mentioned, the difference between this and the previously built ``add_kb`` lies only in the base class from which it is inherited and whether an extra parameter ``GKB_len_list`` is passed. @@ -193,7 +193,7 @@ for conducting abductive reasoning, where the parameters are: - **max_revision_num**, an int value specifying the upper limit on the number of revised labels for each sample. - **require_more_revision**, an int value specifiying additional number - of revisions permitted beyond the minimum required. (e.g. If we set + of revisions permitted beyond the minimum required. (e.g., If we set it to 0, even if ``max_revision_num`` is set to a high value, the method will only output candidates with the minimum possible revisions.) @@ -201,29 +201,28 @@ for conducting abductive reasoning, where the parameters are: And it return a list of candidates (i.e., revised pseudo labels) that are all compatible with ``y``. -MNIST Add example (cont.) -^^^^^^^^^^^^^^^^^^^^^^^^^ +MNIST Addition example (cont.) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -As an example, with MNIST Add, the candidates returned by +As an example, with MNIST Addition, the candidates returned by ``add_kb.abduce_candidates`` would be as follows: -+--------------+-------+--------------+---------------+----------------+ -| ``pseudo_ | ``y`` | ``max_re | ``require_ | Output | -| label`` | | vision_num`` | more_address``| | -+==============+=======+==============+===============+================+ -| [1,1] | 8 | 1 | 0 | [[1,7], [7,1]] | -+--------------+-------+--------------+---------------+----------------+ -| [1,1] | 8 | 1 | 1 | [[1,7], [7,1]] | -+--------------+-------+--------------+---------------+----------------+ -| [1,1] | 8 | 2 | 0 | [[1,7], [7,1]] | -+--------------+-------+--------------+---------------+----------------+ -| [1,1] | 8 | 2 | 1 | [[1,7], | -| | | | | [7,1], [2,6], | -| | | | | [6,2], [3,5], | -| | | | | [5,3], [4,4]] | -+--------------+-------+--------------+---------------+----------------+ -| [1,1] | 11 | 1 | 0 | [] | -+--------------+-------+--------------+---------------+----------------+ ++------------------+-------+----------------------+--------------------------+----------------+ +| ``pseudo_label`` | ``y`` | ``max_revision_num`` | ``require_more_address`` | Output | ++==================+=======+======================+==========================+================+ +| [1,1] | 8 | 1 | 0 | [[1,7], [7,1]] | ++------------------+-------+----------------------+--------------------------+----------------+ +| [1,1] | 8 | 1 | 1 | [[1,7], [7,1]] | ++------------------+-------+----------------------+--------------------------+----------------+ +| [1,1] | 8 | 2 | 0 | [[1,7], [7,1]] | ++------------------+-------+----------------------+--------------------------+----------------+ +| [1,1] | 8 | 2 | 1 | [[1,7], | +| | | | | [7,1], [2,6], | +| | | | | [6,2], [3,5], | +| | | | | [5,3], [4,4]] | ++------------------+-------+----------------------+--------------------------+----------------+ +| [1,1] | 11 | 1 | 0 | [] | ++------------------+-------+----------------------+--------------------------+----------------+ .. _kb-abd-2: @@ -231,16 +230,15 @@ As another example, if we set the ``max_err`` of ``AddKB`` to be 1 instead of the default 1e-10, the tolerance limit for consistency will be higher, hence the candidates returned would be: -+--------------+-------+--------------+---------------+----------------+ -| ``pseudo_ | ``y`` | ``max_re | ``require_ | Output | -| label`` | | vision_num`` | more_address``| | -+==============+=======+==============+===============+================+ -| [1,1] | 8 | 1 | 0 | [[1,7], [7,1], | -| | | | | [1,6], [6,1], | -| | | | | [1,8], [8,1]] | -+--------------+-------+--------------+---------------+----------------+ -| [1,1] | 11 | 1 | 0 | [[1,9], [9,1]] | -+--------------+-------+--------------+---------------+----------------+ ++------------------+-------+----------------------+--------------------------+----------------+ +| ``pseudo_label`` | ``y`` | ``max_revision_num`` | ``require_more_address`` | Output | ++==================+=======+======================+==========================+================+ +| [1,1] | 8 | 1 | 0 | [[1,7], [7,1], | +| | | | | [1,6], [6,1], | +| | | | | [1,8], [8,1]] | ++------------------+-------+----------------------+--------------------------+----------------+ +| [1,1] | 11 | 1 | 0 | [[1,9], [9,1]] | ++------------------+-------+----------------------+--------------------------+----------------+ Step 2: Create a reasoner ------------------------- @@ -249,16 +247,16 @@ After building your knowledge base, the next step is defining a reasoner. Due to the indeterminism of abductive reasoning, there could be multiple candidates compatible to the knowledge base. When this happens, reasoner can minimize inconsistencies between the knowledge -base and pseudo labels predicted by the learning part and return **only +base and pseudo labels predicted by the learning part, and then return **only one** candidate which has highest consistency. You can create a reasoner simply by defining an instance of class -``ReasonerBase`` and passing your knowledge base as an parameter. As an -example for MNIST Add, the reasoner definition would be: +``Reasoner`` and passing your knowledge base as an parameter. As an +example for MNIST Addition, the reasoner definition would be: .. code:: python - reasoner_add = ReasonerBase(kb_add) + reasoner_add = Reasoner(kb_add) When instantiating, besides the required knowledge base, you may also specify: @@ -272,7 +270,7 @@ specify: number of revisions permitted beyond the minimum required when performing :ref:`abductive reasoning in the knowledge base `. Defaults to 0. -- **use_zoopt** (bool, optional), indicating whether to use the Zoopt. +- **use_zoopt** (bool, optional), indicating whether to use `ZOOpt library `_. It is a library for zeroth-order optimization that can be used to accelerate consistency minimization. Defaults to False. - **dist_func** (str, optional), specifying the distance function to be @@ -280,17 +278,17 @@ specify: candidate returned from knowledge base. Valid options include “confidence” (default) and “hamming”. For “confidence”, it calculates the distance between the prediction and candidate based on confidence - derived from the predicted probability in the data sample.For + derived from the predicted probability in the data sample. For “hamming”, it directly calculates the Hamming distance between the predicted pseudo label in the data sample and candidate. -The main method implemented by ``ReasonerBase`` is +The main method implemented by ``Reasoner`` is ``abduce(data_sample)``, which obtains the most consistent candidate. -MNIST Add example (cont.) -~~~~~~~~~~~~~~~~~~~~~~~~~ +MNIST Addition example (cont.) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -As an example, consider these data samples for MNIST Add: +As an example, consider these data samples for MNIST Addition: .. code:: python diff --git a/docs/conf.py b/docs/conf.py index 77d6661..f00e6ed 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,6 +28,7 @@ extensions = [ "recommonmark", "sphinx_markdown_tables", "sphinx.ext.napoleon", + "sphinx_copybutton", ] templates_path = ["_templates"] diff --git a/docs/requirements.txt b/docs/requirements.txt index 9a4b231..88bedfb 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,5 @@ sphinx sphinx-rtd-theme recommonmark -sphinx-markdown-tables \ No newline at end of file +sphinx-markdown-tables +sphinx-copybutton \ No newline at end of file