| @@ -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) | |||
| @@ -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 | |||
| @@ -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) | |||
| > ``` | |||
| @@ -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): | |||
| @@ -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.") | |||
| @@ -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 | |||
| ----- | |||
| @@ -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. | |||
| @@ -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. | |||