Skip to content

Commit

Permalink
Merge branch dev into branch (refactor)random_walk
Browse files Browse the repository at this point in the history
  • Loading branch information
WenjieDu committed Sep 12, 2024
2 parents bdcbace + e20ede8 commit 2f4413c
Show file tree
Hide file tree
Showing 189 changed files with 4,146 additions and 2,267 deletions.
Binary file added .idea/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
repos:
# hooks for checking files
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml

# hooks for linting code
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 24.8.0
hooks:
- id: black
args: [
--line-length=120, # refer to pyproject.toml
]

- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 7.1.1
hooks:
- id: flake8
args: [
--max-line-length=120, # refer to pyproject.toml
--extend-ignore=E203, # why ignore E203? Refer to https://github.com/PyCQA/pycodestyle/issues/373
--extend-ignore=E203,E231
]
372 changes: 240 additions & 132 deletions README.md

Large diffs are not rendered by default.

322 changes: 216 additions & 106 deletions README_zh.md

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@
html_context["READTHEDOCS"] = True

html_favicon = (
"https://raw.githubusercontent.com/"
"PyPOTS/pypots.github.io/main/static/figs/pypots_logos/PyPOTS/logo_FFBG.svg"
"https://raw.githubusercontent.com/PyPOTS/pypots.github.io/main/static/figs/pypots_logos/PyPOTS/logo_FFBG.svg"
)

html_sidebars = {
Expand Down
10 changes: 8 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,16 @@ The paper references are all listed at the bottom of this readme file.
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Type | Algorithm | IMPU | FORE | CLAS | CLUS | ANOD | Year - Venue |
+================+===========================================================+======+======+======+======+======+=======================+
| Neural Net | ImputeFormer :cite:`nie2024imputeformer` || | | | | ``2024 - KDD`` |
| Neural Net | TEFN🧑‍🔧 :cite:`zhan2024tefn` || | | | | ``2024 - arXiv`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | TimeMixer :cite:`wang2024timemixer` || | | | | ``2024 - ICLR`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | iTransformer🧑‍🔧 :cite:`liu2024itransformer` || | | | | ``2024 - ICLR`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | ModernTCN :cite:`luo2024moderntcn` || | | | | ``2024 - ICLR`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | ImputeFormer :cite:`nie2024imputeformer` || | | | | ``2024 - KDD`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | SAITS :cite:`du2023SAITS` || | | | | ``2023 - ESWA`` |
+----------------+-----------------------------------------------------------+------+------+------+------+------+-----------------------+
| Neural Net | FreTS🧑‍🔧 :cite:`yi2023frets` || | | | | ``2023 - NeurIPS`` |
Expand Down Expand Up @@ -333,7 +339,7 @@ By committing your code, you'll
`pypots/imputation/template <https://github.com/WenjieDu/PyPOTS/tree/main/pypots/imputation/template>`_) to quickly start;
2. become one of `PyPOTS contributors <https://github.com/WenjieDu/PyPOTS/graphs/contributors>`_ and
be listed as a volunteer developer `on the PyPOTS website <https://pypots.com/about/#volunteer-developers>`_;
3. get mentioned in our `release notes <https://github.com/WenjieDu/PyPOTS/releases>`_;
3. get mentioned in PyPOTS `release notes <https://github.com/WenjieDu/PyPOTS/releases>`_;

You can also contribute to PyPOTS by simply staring🌟 this repo to help more people notice it.
Your star is your recognition to PyPOTS, and it matters!
Expand Down
18 changes: 18 additions & 0 deletions docs/pypots.imputation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ pypots.imputation.transformer
:show-inheritance:
:inherited-members:

pypots.imputation.timemixer
------------------------------------

.. automodule:: pypots.imputation.timemixer
:members:
:undoc-members:
:show-inheritance:
:inherited-members:

pypots.imputation.moderntcn
------------------------------------

.. automodule:: pypots.imputation.moderntcn
:members:
:undoc-members:
:show-inheritance:
:inherited-members:

pypots.imputation.imputeformer
------------------------------------

Expand Down
7 changes: 7 additions & 0 deletions docs/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -763,3 +763,10 @@ @article{bai2018tcn
journal={arXiv preprint arXiv:1803.01271},
year={2018}
}

@article{zhan2024tefn,
title={Time Evidence Fusion Network: Multi-source View in Long-Term Time Series Forecasting},
author={Zhan, Tianxiang and He, Yuanpeng and Li, Zhen and Deng, Yong},
journal={arXiv preprint arXiv:2405.06419},
year={2024}
}
24 changes: 6 additions & 18 deletions pypots/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ def _setup_device(self, device: Union[None, str, torch.device, list]) -> None:
self.device = device
elif isinstance(device, list):
if len(device) == 0:
raise ValueError(
"The list of devices should have at least 1 device, but got 0."
)
raise ValueError("The list of devices should have at least 1 device, but got 0.")
elif len(device) == 1:
return self._setup_device(device[0])
# parallely training on multiple CUDA devices
Expand Down Expand Up @@ -179,18 +177,14 @@ def _setup_path(self, saving_path) -> None:
logger.info(f"Model files will be saved to {self.saving_path}")
logger.info(f"Tensorboard file will be saved to {tb_saving_path}")
else:
logger.warning(
"‼️ saving_path not given. Model files and tensorboard file will not be saved."
)
logger.warning("‼️ saving_path not given. Model files and tensorboard file will not be saved.")

def _send_model_to_given_device(self) -> None:
if isinstance(self.device, list):
# parallely training on multiple devices
self.model = torch.nn.DataParallel(self.model, device_ids=self.device)
self.model = self.model.cuda()
logger.info(
f"Model has been allocated to the given multiple devices: {self.device}"
)
logger.info(f"Model has been allocated to the given multiple devices: {self.device}")
else:
self.model = self.model.to(self.device)

Expand Down Expand Up @@ -291,9 +285,7 @@ def save(

if os.path.exists(saving_path):
if overwrite:
logger.warning(
f"‼️ File {saving_path} exists. Argument `overwrite` is True. Overwriting now..."
)
logger.warning(f"‼️ File {saving_path} exists. Argument `overwrite` is True. Overwriting now...")
else:
logger.error(
f"❌ File {saving_path} exists. Saving operation aborted. "
Expand All @@ -309,9 +301,7 @@ def save(
torch.save(self.model, saving_path)
logger.info(f"Saved the model to {saving_path}")
except Exception as e:
raise RuntimeError(
f'Failed to save the model to "{saving_path}" because of the below error! \n{e}'
)
raise RuntimeError(f'Failed to save the model to "{saving_path}" because of the below error! \n{e}')

def load(self, path: str) -> None:
"""Load the saved model from a disk file.
Expand Down Expand Up @@ -519,9 +509,7 @@ def __init__(

def _print_model_size(self) -> None:
"""Print the number of trainable parameters in the initialized NN model."""
self.num_params = sum(
p.numel() for p in self.model.parameters() if p.requires_grad
)
self.num_params = sum(p.numel() for p in self.model.parameters() if p.requires_grad)
logger.info(
f"{self.__class__.__name__} initialized with the given hyperparameters, "
f"the number of trainable parameters: {self.num_params:,}"
Expand Down
20 changes: 5 additions & 15 deletions pypots/classification/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,7 @@ def _train_model(
for idx, data in enumerate(val_loader):
inputs = self._assemble_input_for_validating(data)
results = self.model.forward(inputs)
epoch_val_loss_collector.append(
results["loss"].sum().item()
)
epoch_val_loss_collector.append(results["loss"].sum().item())

mean_val_loss = np.mean(epoch_val_loss_collector)

Expand All @@ -333,15 +331,11 @@ def _train_model(
)
mean_loss = mean_val_loss
else:
logger.info(
f"Epoch {epoch:03d} - training loss: {mean_train_loss:.4f}"
)
logger.info(f"Epoch {epoch:03d} - training loss: {mean_train_loss:.4f}")
mean_loss = mean_train_loss

if np.isnan(mean_loss):
logger.warning(
f"‼️ Attention: got NaN loss in Epoch {epoch}. This may lead to unexpected errors."
)
logger.warning(f"‼️ Attention: got NaN loss in Epoch {epoch}. This may lead to unexpected errors.")

if mean_loss < self.best_loss:
self.best_epoch = epoch
Expand All @@ -363,9 +357,7 @@ def _train_model(
nni.report_final_result(self.best_loss)

if self.patience == 0:
logger.info(
"Exceeded the training patience. Terminating the training procedure..."
)
logger.info("Exceeded the training patience. Terminating the training procedure...")
break

except KeyboardInterrupt: # if keyboard interrupt, only warning
Expand All @@ -386,9 +378,7 @@ def _train_model(
if np.isnan(self.best_loss):
raise ValueError("Something is wrong. best_loss is Nan after training.")

logger.info(
f"Finished training. The best model is from epoch#{self.best_epoch}."
)
logger.info(f"Finished training. The best model is from epoch#{self.best_epoch}.")

@abstractmethod
def fit(
Expand Down
8 changes: 2 additions & 6 deletions pypots/classification/grud/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,15 @@ def forward(self, inputs: dict, training: bool = True) -> dict:
empirical_mean = inputs["empirical_mean"]
X_filledLOCF = inputs["X_filledLOCF"]

_, hidden_state = self.model(
X, missing_mask, deltas, empirical_mean, X_filledLOCF
)
_, hidden_state = self.model(X, missing_mask, deltas, empirical_mean, X_filledLOCF)

logits = self.classifier(hidden_state)
classification_pred = torch.softmax(logits, dim=1)
results = {"classification_pred": classification_pred}

# if in training mode, return results with losses
if training:
classification_loss = F.nll_loss(
torch.log(classification_pred), inputs["label"]
)
classification_loss = F.nll_loss(torch.log(classification_pred), inputs["label"])
results["loss"] = classification_loss

return results
10 changes: 4 additions & 6 deletions pypots/classification/grud/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ def __init__(
self.X_filledLOCF = locf_torch(self.X)
self.X = torch.nan_to_num(self.X)
self.deltas = _parse_delta_torch(self.missing_mask)
self.empirical_mean = torch.sum(
self.missing_mask * self.X, dim=[0, 1]
) / torch.sum(self.missing_mask, dim=[0, 1])
self.empirical_mean = torch.sum(self.missing_mask * self.X, dim=[0, 1]) / torch.sum(
self.missing_mask, dim=[0, 1]
)
# fill nan with 0, in case some features have no observations
self.empirical_mean = torch.nan_to_num(self.empirical_mean, 0)

Expand Down Expand Up @@ -134,9 +134,7 @@ def _fetch_data_from_file(self, idx: int) -> Iterable:
X_filledLOCF = locf_torch(X.unsqueeze(dim=0)).squeeze()
X = torch.nan_to_num(X)
deltas = _parse_delta_torch(missing_mask)
empirical_mean = torch.sum(missing_mask * X, dim=[0]) / torch.sum(
missing_mask, dim=[0]
)
empirical_mean = torch.sum(missing_mask * X, dim=[0]) / torch.sum(missing_mask, dim=[0])

sample = [
torch.tensor(idx),
Expand Down
21 changes: 5 additions & 16 deletions pypots/classification/raindrop/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
and takes over the forward progress of the algorithm.
"""


# Created by Wenjie Du <[email protected]>
# License: BSD-3-Clause

Expand Down Expand Up @@ -84,21 +83,13 @@ def forward(self, inputs, training=True):
lengths2 = lengths.unsqueeze(1).to(device)
mask2 = mask.permute(1, 0).unsqueeze(2).long()
if self.sensor_wise_mask:
output = torch.zeros(
[batch_size, self.n_features, self.d_ob + 16], device=device
)
output = torch.zeros([batch_size, self.n_features, self.d_ob + 16], device=device)
extended_missing_mask = missing_mask.view(-1, batch_size, self.n_features)
for se in range(self.n_features):
representation = representation.view(
-1, batch_size, self.n_features, (self.d_ob + 16)
)
representation = representation.view(-1, batch_size, self.n_features, (self.d_ob + 16))
out = representation[:, :, se, :]
l_ = torch.sum(extended_missing_mask[:, :, se], dim=0).unsqueeze(
1
) # length
out_sensor = torch.sum(
out * (1 - extended_missing_mask[:, :, se].unsqueeze(-1)), dim=0
) / (l_ + 1)
l_ = torch.sum(extended_missing_mask[:, :, se], dim=0).unsqueeze(1) # length
out_sensor = torch.sum(out * (1 - extended_missing_mask[:, :, se].unsqueeze(-1)), dim=0) / (l_ + 1)
output[:, se, :] = out_sensor
output = output.view([-1, self.n_features * (self.d_ob + 16)])
elif self.aggregation == "mean":
Expand All @@ -116,9 +107,7 @@ def forward(self, inputs, training=True):

# if in training mode, return results with losses
if training:
classification_loss = F.nll_loss(
torch.log(classification_pred), inputs["label"]
)
classification_loss = F.nll_loss(torch.log(classification_pred), inputs["label"])
results["loss"] = classification_loss

return results
1 change: 0 additions & 1 deletion pypots/classification/raindrop/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"""


# Created by Wenjie Du <[email protected]>
# License: BSD-3-Clause

Expand Down
17 changes: 5 additions & 12 deletions pypots/cli/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,9 @@ def checkup(self):
)

if self._cleanup:
assert not self._run_tests and not self._lint_code, (
"Argument `--cleanup` should be used alone. "
"Try `pypots-cli dev --cleanup`"
)
assert (
not self._run_tests and not self._lint_code
), "Argument `--cleanup` should be used alone. Try `pypots-cli dev --cleanup`"

def run(self):
"""Execute the given command."""
Expand All @@ -149,14 +148,8 @@ def run(self):
elif self._build:
self.execute_command("python -m build")
elif self._run_tests:
pytest_command = (
f"pytest -k {self._k}" if self._k is not None else "pytest"
)
command_to_run_test = (
f"coverage run -m {pytest_command}"
if self._show_coverage
else pytest_command
)
pytest_command = f"pytest -k {self._k}" if self._k is not None else "pytest"
command_to_run_test = f"coverage run -m {pytest_command}" if self._show_coverage else pytest_command
self.execute_command(command_to_run_test)
if self._show_coverage and os.path.exists(".coverage"):
self.execute_command("coverage report -m")
Expand Down
Loading

0 comments on commit 2f4413c

Please sign in to comment.