Browse Source

[FIX] fix optional in docstring

pull/1/head
troyyyyy 2 years ago
parent
commit
051cda961d
8 changed files with 70 additions and 176 deletions
  1. +5
    -5
      abl/bridge/simple_bridge.py
  2. +25
    -6
      abl/learning/basic_nn.py
  3. +0
    -136
      abl/learning/readme.md
  4. +2
    -2
      abl/learning/torch_dataset/classification_dataset.py
  5. +2
    -2
      abl/learning/torch_dataset/prediction_dataset.py
  6. +17
    -14
      abl/reasoning/kb.py
  7. +10
    -6
      abl/utils/logger.py
  8. +9
    -5
      abl/utils/utils.py

+ 5
- 5
abl/bridge/simple_bridge.py View File

@@ -170,7 +170,7 @@ class SimpleBridge(BaseBridge):
----------
unlabel_data_examples : ListData
Unlabeled data examples to concatenate.
label_data_examples : Optional[ListData]
label_data_examples : ListData, optional
Labeled data examples to concatenate, if available.

Returns
@@ -215,11 +215,11 @@ class SimpleBridge(BaseBridge):
- ``gt_pseudo_label`` is only used to evaluate the performance of the ``ABLModel`` but not
to train. ``gt_pseudo_label`` can be ``None``.
- ``Y`` is a list representing the ground truth reasoning result for each sublist in ``X``.
label_data : Optional[Union[ListData, Tuple[List[List[Any]], List[List[Any]], List[Any]]]]
label_data : Union[ListData, Tuple[List[List[Any]], List[List[Any]], List[Any]]], optional
Labeled data should be in the same format as ``train_data``. The only difference is
that the ``gt_pseudo_label`` in ``label_data`` should not be ``None`` and will be
utilized to train the model. Defaults to None.
val_data : Optional[Union[ListData, Tuple[List[List[Any]], Optional[List[List[Any]]], Optional[List[Any]]]]]
val_data : Union[ListData, Tuple[List[List[Any]], Optional[List[List[Any]]], Optional[List[Any]]]], optional
Validation data should be in the same format as ``train_data``. Both ``gt_pseudo_label``
and ``Y`` can be either None or not, which depends on the evaluation metircs in
``self.metric_list``. If ``val_data`` is None, ``train_data`` will be used to validate the
@@ -233,10 +233,10 @@ class SimpleBridge(BaseBridge):
eval_interval : int
The model will be evaluated every ``eval_interval`` loops during training,
by default 1.
save_interval : Optional[int]
save_interval : int, optional
The model will be saved every ``eval_interval`` loops during training, by
default None.
save_dir : Optional[str]
save_dir : str, optional
Directory to save the model, by default None.
"""
data_examples = self.data_preprocess("train", train_data)


+ 25
- 6
abl/learning/basic_nn.py View File

@@ -163,7 +163,10 @@ class BasicNN:
return self

def fit(
self, data_loader: DataLoader = None, X: List[Any] = None, y: List[int] = None
self,
data_loader: Optional[DataLoader] = None,
X: Optional[List[Any]] = None,
y: Optional[List[int]] = None,
) -> BasicNN:
"""
Train the model for self.num_epochs times or until the average loss on one epoch
@@ -267,7 +270,11 @@ class BasicNN:

return torch.cat(results, axis=0)

def predict(self, data_loader: DataLoader = None, X: List[Any] = None) -> numpy.ndarray:
def predict(
self,
data_loader: Optional[DataLoader] = None,
X: Optional[List[Any]] = None,
) -> numpy.ndarray:
"""
Predict the class of the input data. This method supports prediction with either
a DataLoader object (data_loader) or a list of input data (X). If both data_loader
@@ -304,7 +311,11 @@ class BasicNN:
)
return self._predict(data_loader).argmax(axis=1).cpu().numpy()

def predict_proba(self, data_loader: DataLoader = None, X: List[Any] = None) -> numpy.ndarray:
def predict_proba(
self,
data_loader: Optional[DataLoader] = None,
X: Optional[List[Any]] = None,
) -> numpy.ndarray:
"""
Predict the probability of each class for the input data. This method supports
prediction with either a DataLoader object (data_loader) or a list of input data (X).
@@ -392,7 +403,10 @@ class BasicNN:
return mean_loss, accuracy

def score(
self, data_loader: DataLoader = None, X: List[Any] = None, y: List[int] = None
self,
data_loader: Optional[DataLoader] = None,
X: Optional[List[Any]] = None,
y: Optional[List[int]] = None,
) -> float:
"""
Validate the model. It supports validation with either a DataLoader object (data_loader)
@@ -431,7 +445,12 @@ class BasicNN:
print_log(f"mean loss: {mean_loss:.3f}, accuray: {accuracy:.3f}", logger="current")
return accuracy

def _data_loader(self, X: List[Any], y: List[int] = None, shuffle: bool = True) -> DataLoader:
def _data_loader(
self,
X: Optional[List[Any]],
y: Optional[List[int]] = None,
shuffle: Optional[bool] = True,
) -> DataLoader:
"""
Generate a DataLoader for user-provided input data and target labels.

@@ -467,7 +486,7 @@ class BasicNN:
)
return data_loader

def save(self, epoch_id: int = 0, save_path: str = None) -> None:
def save(self, epoch_id: int = 0, save_path: Optional[str] = None) -> None:
"""
Save the model and the optimizer. User can either provide a save_path or specify
the epoch_id at which the model and optimizer is saved. if both save_path and


+ 0
- 136
abl/learning/readme.md View File

@@ -1,136 +0,0 @@
# `basic_model.py`

可以使用`basic_model.py`中实现的`BasicModel`类将`pytorch`神经网络模型包装成`sklearn`模型的形式.

## BasicModel 类提供的接口

| 方法 | 功能 |
| ---- | ---- |
| fit(X, y) | 训练神经网络 |
| predict(X) | 预测 X 的类别 |
| predict_proba(X) | 预测 X 的类别概率 |
| score(X, y) | 计算模型在测试数据上的准确率 |
| save() | 保存模型 |
| load() | 加载模型 |


## BasicModel 类的参数

**model : torch.nn.Module**
+ The PyTorch model to be trained or used for prediction.

**batch_size : int**
+ The batch size used for training.

**num_epochs : int**
+ The number of epochs used for training.

**stop_loss : Optional[float]**
+ The loss value at which to stop training.

**num_workers : int**
+ The number of workers used for loading data.

**loss_fn : torch.nn.Module**
+ The loss function used for training.

**optimizer : torch.nn.Module**
+ The optimizer used for training.

**transform : Callable[..., Any]**
+ The transformation function used for data augmentation.

**device : torch.device**
+ The device on which the model will be trained or used for prediction.

**recorder : Any**
+ The recorder used to record training progress.

**save_interval : Optional[int]**
+ The interval at which to save the model during training.

**save_dir : Optional[str]**
+ The directory in which to save the model during training.

**collate_fn : Callable[[List[T]], Any]**
+ The function used to collate data.

## 例子
>
> ```python
> # Three necessary component
> cls = LeNet5()
> loss_fn = nn.CrossEntropyLoss()
> optimizer = torch.optim.Adam(cls.parameters())
>
> # Initialize base_model
> base_model = BasicModel(
> cls,
> loss_fn,
> optimizer,
> torch.device("cuda:0"),
> batch_size=32,
> num_epochs=10,
> )
>
> # Prepare data
> train_X, train_y = get_train_data()
> test_X, test_y = get_test_data()
>
> # Train model
> base_model.fit(train_X, train_y)
>
> # Predict
> base_model.predict(test_X)
>
> # Validation
> base_model.score(test_X, test_y)
> ```

# `wabl_models.py`

`wabl_models.py`中实现的`WABLBasicModel`能够序列化数据并为不同的机器学习模型提供统一的接口.

## WABLBasicModel 类提供的接口

| 方法 | 功能 |
| ---- | ---- |
| train(X, Y) | 利用训练数据训练机器学习模型(不涉及反绎) |
| predict(X) | 预测 X 的类别和概率 |
| valid(X, Y) | 计算模型在测试数据上的准确率 |

## WABLBasicModel 类的参数
**base_model : Machine Learning Model**
+ The base model to use for training and prediction.

**pseudo_label_list : List[Any]**
+ A list of pseudo-labels to use for training.

## 序列化数据
考虑到训练数据可能多种组织形式,比如:\
`X: List[List[img]], Y: List[List[label]]`\
`X: List[List[img]], Y: List[label]`\
`X: List[img], Y: List[label]`
... \
不便于训练. 因此先将形式统一为:`X: List[img], Y: List[label]`,也就是所谓的序列化数据.

## 例子
>
> ```python
> # Three necessary component
> # 'ml_model' is no longer limited to NN models
> model = WABLBasicModel(ml_model, kb.pseudo_label_list)
>
> # Prepare data
> train_X, train_y = get_train_data()
> test_X, test_y = get_test_data()
>
> # Train model
> model.train(train_X, train_y)
>
> # Predict
> model.predict(test_X)
>
> # Validation
> model.valid(test_X, test_y)
> ```

+ 2
- 2
abl/learning/torch_dataset/classification_dataset.py View File

@@ -1,4 +1,4 @@
from typing import Any, Callable, List, Tuple
from typing import Any, Callable, List, Tuple, Optional

import torch
from torch.utils.data import Dataset
@@ -19,7 +19,7 @@ class ClassificationDataset(Dataset):
Defaults to None.
"""

def __init__(self, X: List[Any], Y: List[int], transform: Callable[..., Any] = None):
def __init__(self, X: List[Any], Y: List[int], transform: Optional[Callable[..., Any]] = None):
if (not isinstance(X, list)) or (not isinstance(Y, list)):
raise ValueError("X and Y should be of type list.")
if len(X) != len(Y):


+ 2
- 2
abl/learning/torch_dataset/prediction_dataset.py View File

@@ -1,4 +1,4 @@
from typing import Any, Callable, List, Tuple
from typing import Any, Callable, List, Tuple, Optional

import torch
from torch.utils.data import Dataset
@@ -17,7 +17,7 @@ class PredictionDataset(Dataset):
Defaults to None.
"""

def __init__(self, X: List[Any], transform: Callable[..., Any] = None):
def __init__(self, X: List[Any], transform: Optional[Callable[..., Any]] = None):
if not isinstance(X, list):
raise ValueError("X should be of type list.")



+ 17
- 14
abl/reasoning/kb.py View File

@@ -21,7 +21,7 @@ class KBBase(ABC):

Parameters
----------
pseudo_label_list : list
pseudo_label_list : List[Any]
List of possible pseudo-labels. It's recommended to arrange the pseudo-labels in this
list so that each aligns with its corresponding index in the base model: the first with
the 0th index, the second with the 1st, and so forth.
@@ -51,11 +51,11 @@ class KBBase(ABC):

def __init__(
self,
pseudo_label_list: list,
max_err: float = 1e-10,
use_cache: bool = True,
key_func: Callable = to_hashable,
cache_size: int = 4096,
pseudo_label_list: List[Any],
max_err: Optional[float] = 1e-10,
use_cache: Optional[bool] = True,
key_func: Optional[Callable] = to_hashable,
cache_size: Optional[int] = 4096,
):
if not isinstance(pseudo_label_list, list):
raise TypeError(f"pseudo_label_list should be list, got {type(pseudo_label_list)}")
@@ -88,7 +88,7 @@ class KBBase(ABC):
----------
pseudo_label : List[Any]
Pseudo-labels of an example.
x : Optional[List[Any]]
x : List[Any], optional
The example. If deductive logical reasoning does not require any
information from the example, the overridden function provided by the user can omit
this parameter.
@@ -288,9 +288,9 @@ class GroundKB(KBBase):

Parameters
----------
pseudo_label_list : list
pseudo_label_list : List[Any]
Refer to class ``KBBase``.
GKB_len_list : list
GKB_len_list : List[int]
List of possible lengths for pseudo-labels of an example.
max_err : float, optional
Refer to class ``KBBase``.
@@ -304,7 +304,12 @@ class GroundKB(KBBase):
abductive reasoning) will be automatically set up.
"""

def __init__(self, pseudo_label_list, GKB_len_list, max_err=1e-10):
def __init__(
self,
pseudo_label_list: List[Any],
GKB_len_list: List[int],
max_err: Optional[float] = 1e-10,
):
super().__init__(pseudo_label_list, max_err)
if not isinstance(GKB_len_list, list):
raise TypeError("GKB_len_list should be list, but got {type(GKB_len_list)}")
@@ -445,12 +450,10 @@ class PrologKB(KBBase):

Parameters
----------
pseudo_label_list : list
pseudo_label_list : List[Any]
Refer to class ``KBBase``.
pl_file :
pl_file : str
Prolog file containing the KB.
max_err : float, optional
Refer to class ``KBBase``.

Notes
-----


+ 10
- 6
abl/utils/logger.py View File

@@ -24,7 +24,7 @@ class FilterDuplicateWarning(logging.Filter):
The name of the filter, by default "abl".
"""

def __init__(self, name: str = "abl"):
def __init__(self, name: Optional[str] = "abl"):
super().__init__(name)
self.seen: set = set()

@@ -85,7 +85,7 @@ class ABLFormatter(logging.Formatter):
self.info_format = f"%(asctime)s - %(name)s - {info_prefix} - %(" "message)s"
self.debug_format = f"%(asctime)s - %(name)s - {debug_prefix} - %(" "message)s"

def _get_prefix(self, level: str, color: bool, blink=False) -> str:
def _get_prefix(self, level: str, color: bool, blink: Optional[bool] = False) -> str:
"""
Get the prefix of the target log level.

@@ -192,8 +192,8 @@ class ABLLogger(Logger, ManagerMixin):
name: str,
logger_name="abl",
log_file: Optional[str] = None,
log_level: Union[int, str] = "INFO",
file_mode: str = "w",
log_level: Optional[Union[int, str]] = "INFO",
file_mode: Optional[str] = "w",
):
Logger.__init__(self, logger_name)
ManagerMixin.__init__(self, name)
@@ -286,7 +286,11 @@ class ABLLogger(Logger, ManagerMixin):
_release_lock()


def print_log(msg, logger: Optional[Union[Logger, str]] = None, level=logging.INFO) -> None:
def print_log(
msg,
logger: Optional[Union[Logger, str]] = None,
level: Optional[int] = logging.INFO,
) -> None:
"""
Print a log message using the specified logger or a default method.

@@ -297,7 +301,7 @@ def print_log(msg, logger: Optional[Union[Logger, str]] = None, level=logging.IN
----------
msg : str
The message to be logged.
logger : Optional[Union[Logger, str]], optional
logger : Union[Logger, str], optional
The logger to use for logging the message. It can be a `logging.Logger` instance, a string
specifying the logger name, 'silent', 'current', or None. If None, the `print`
method is used.


+ 9
- 5
abl/utils/utils.py View File

@@ -1,4 +1,4 @@
from typing import List, Any, Union, Tuple
from typing import List, Any, Union, Tuple, Optional

import numpy as np

@@ -62,7 +62,7 @@ def reform_list(
return reformed_list


def hamming_dist(pred_pseudo_label, candidates):
def hamming_dist(pred_pseudo_label: List[Any], candidates: List[List[Any]]) -> np.ndarray:
"""
Compute the Hamming distance between two arrays.

@@ -87,7 +87,7 @@ def hamming_dist(pred_pseudo_label, candidates):
return np.sum(pred_pseudo_label != candidates, axis=1)


def confidence_dist(pred_prob, candidates_idxs):
def confidence_dist(pred_prob: List[np.ndarray], candidates_idxs: List[List[Any]]) -> np.ndarray:
"""
Compute the confidence distance between prediction probabilities and candidates.

@@ -109,7 +109,7 @@ def confidence_dist(pred_prob, candidates_idxs):
return 1 - np.prod(pred_prob[cols, candidates_idxs], axis=1)


def to_hashable(x):
def to_hashable(x: Union[List[Any], Any]) -> Union[Tuple[Any, ...], Any]:
"""
Convert a nested list to a nested tuple so it is hashable.

@@ -148,7 +148,11 @@ def restore_from_hashable(x):
return [restore_from_hashable(item) for item in x]
return x

def tab_data_to_tuple(X, y, reasoning_result = 0):
def tab_data_to_tuple(
X: Union[List[Any], Any],
y: Union[List[Any], Any],
reasoning_result: Optional[Any] = 0
) -> Tuple[List[List[Any]], List[List[Any]], List[Any]]:
'''
Convert a tabular data to a tuple by adding a dimension to each element of
X and y. The tuple contains three elements: data, label, and reasoning result.


Loading…
Cancel
Save