Repository: sktime/sktime

Issue:
[ENH] add SCINet forecaster
Feature request to add SCINet: https://github.com/cure-lab/SCINet

There is no package release for this, only the research grade repository, so this would mean either:

* help progress source repo to package and direct interface (1st or 2nd party)
* copy code to an `sktime` native estimator, ensure to acknowledge authors (this option is probably easier)

Developer guide for adding estimators: https://www.sktime.net/en/latest/developer_guide/add_estimators.html

Discussion:
Sohaib-Ahmed21: Kindly can some maintainer approve the workflows.
fkiraly: I assume this is still work in progress?
Sohaib-Ahmed21: > I assume this is still work in progress?

Yes just minor things left.
Sohaib-Ahmed21: The PR is ready for review. Someone please review this.
Sohaib-Ahmed21: Thanks for the review! I will address these soon except wrapping of network
classes which needs discussion here.

On Fri, Nov 22, 2024, 7:48 PM Armaghan Shakir ***@***.***>
wrote:

> ***@***.**** requested changes on this pull request.
>
> Thank you for your contribution.
>
> I have requested some minor changes.
> ------------------------------
>
> In sktime/forecasting/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854024191>:
>
> > @@ -0,0 +1,286 @@
> +"""Deep Learning Forecaster using SCINet Forecaster."""
> +
> +from sktime.forecasting.base.adapters._pytorch import BaseDeepNetworkPyTorch
> +
> +
> +class SCINetForecaster(BaseDeepNetworkPyTorch):
> +    """SCINet-Linear Forecaster.
>
> """SCINet-Linear Forecaster.
>
> shouldn't this be just SCINet?
> ------------------------------
>
> In sktime/forecasting/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854025322>:
>
> > +    Implementation of the SCINet forecaster.
> +
> +    Core logic is directly copied from the curelab SCINet implementation
> +    at github.
>
> you should include citations, by adding superscript from links in
> references. take a look at LTSFLinearForecaster
> ------------------------------
>
> In sktime/forecasting/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854025475>:
>
> > +    in_channels : int, default=1
> +    Number of input channels passed to the network.
> +
> +    individual : bool, default=False
> +    Flag that controls whether the network treats each input channel independently.
> +
> +    If True, a separate linear layer is created for each input channel.
> +    If False, a single shared linear layer is used across all channels.
> +    criterion : torch.nn Loss Function, default=None
> +    Loss function to be used for training. If not provided, a default such as
> +    torch.nn.MSELoss is often used.
>
> I don't think you are using in_channels or individual, in that case you
> should remove these from all places.
> ------------------------------
>
> In sktime/forecasting/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854025703>:
>
> > +        params = [
> +            {
> +                "seq_len": 8,
> +                "pred_len": 1,
> +                "lr": 0.005,
> +                "optimizer": "Adam",
> +                "batch_size": 1,
> +                "num_epochs": 1,
> +                "individual": True,
> +            },
> +            {
> +                "seq_len": 16,
> +                "pred_len": 2,
> +                "lr": 0.005,
> +                "optimizer": "Adam",
> +                "batch_size": 1,
> +                "num_epochs": 1,
> +                "individual": False,
> +            },
> +        ]
>
> as said above, remove individual if not used
>
> keep the 2 test params different from each other, you can initialize 2
> different architectures from the config.
> ------------------------------
>
> In sktime/networks/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854026870>:
>
> > +class Splitting(nn_module):
> +    """
> +    A neural network module for splitting input into even and odd parts.
> +
> +    The `Splitting` class defines a PyTorch module that splits an input
> +    tensor into two parts: the even-indexed and odd-indexed elements.
> +    This can be used in various tasks requiring input splitting or masking.
> +    """
> +
> +    def __init__(self):
> +        """
> +        Initialize the Splitting module.
> +
> +        This function initializes the `Splitting` class by calling the
> +        `__init__` method of its superclass (`nn.Module`). No additional
> +        parameters are needed for initialization.
> +        """
> +        super().__init__()
>
> other models that use pytorch adapter, have network classes wrapped inside
> another class. I don't remember what was the purpose of that. @fkiraly
> <https://github.com/fkiraly> and @benHeid <https://github.com/benHeid> if
> that was just trivial, we can keep the network classes here as they are.
> ------------------------------
>
> In sktime/networks/scinet.py
> <https://github.com/sktime/sktime/pull/7400#discussion_r1854027342>:
>
> > +            max_length, dtype=torch.float32, device=x.device
> +        )  # tensor([0., 1., 2., 3., 4.], device='cuda:0')
> +        # temp1 = position.unsqueeze(1)  # 5 1
> +        # temp2 = self.inv_timescales.unsqueeze(0)  # 1 256
> +        scaled_time = position.unsqueeze(1) * self.inv_timescales.unsqueeze(0)  # 5 256
> +        signal = torch.cat(
> +            [torch.sin(scaled_time), torch.cos(scaled_time)], dim=1
> +        )  # [T, C]
> +        signal = F.pad(signal, (0, 0, 0, self.pe_hidden_size % 2))
> +        signal = signal.view(1, max_length, self.pe_hidden_size)
> +
> +        return signal
> +
> +    def forward(self, x):
> +        """Perform the forward pass through the network."""
> +        assert self.seq_len % (np.power(2, self.num_levels)) == 0
>
> also mention this in the docstring for seq_len
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/sktime/sktime/pull/7400#pullrequestreview-2454632591>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/A27P2VZRTNT4HOQK4HH7SSD2B474XAVCNFSM6AAAAABR6FY5UGVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDINJUGYZTENJZGE>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>

Sohaib-Ahmed21: Thanks for the review @geetu040! I will address these soon except wrapping of network classes which needs discussion here.
Sohaib-Ahmed21: @geetu040 I have addressed the reviews except wrapping of network classes which needs discussion here. Kindly approve the workflows.

Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 6490034f4..6fafabdb8 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -3191,6 +3191,14 @@
       "contributions": [
         "doc"
       ]
+     },
+     {
+      "login": "vagechirkov",
+      "name": "Valerii Chirkov",
+      "avatar_url": "https://avatars.githubusercontent.com/vagechirkov",
+      "profile": "https://github.com/vagechirkov",
+      "contributions": [
+        "code",
     },
     {
       "login": "tajir0",
@@ -3211,6 +3219,15 @@
         "doc"
       ]
     },
+    {
+        "login": "Sohaib-Ahmed21",
+        "name": "Sohaib Ahmed",
+        "avatar_url": "https://avatars.githubusercontent.com/Sohaib-Ahmed21",
+        "profile": "https://github.com/Sohaib-Ahmed21",
+        "contributions": [
+          "code"
+        ]
+    },
     {
       "login": "alyssadsouza",
       "name": "Alyssa D'Souza",
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d659cff6f..4b4109177 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.6.0
+    rev: v5.0.0
     hooks:
       - id: check-added-large-files
         args:
@@ -16,14 +16,14 @@ repos:
       - id: trailing-whitespace
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.6.4
+    rev: v0.8.0
     hooks:
       - id: ruff-format
       - id: ruff
         args: [--fix]
 
   - repo: https://github.com/mgedmin/check-manifest
-    rev: "0.49"
+    rev: "0.50"
     hooks:
       - id: check-manifest
         stages: [manual]
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index ad5a98913..1e61f4e8a 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -6,7 +6,7 @@ Contributors
 <!-- Please add your badges to .all-contibutorsrc -->
 
 <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
-[![All Contributors](https://img.shields.io/badge/all_contributors-316-orange.svg)](#contributors)
+[![All Contributors](https://img.shields.io/badge/all_contributors-317-orange.svg)](#contributors)
 <!-- ALL-CONTRIBUTORS-BADGE:END -->
 
 This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
@@ -173,6 +173,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Z-Fran"><img src="https://avatars.githubusercontent.com/u/49083766?v=4?s=100" width="100px;" alt="Jindong Zhang"/><br /><sub><b>Jindong Zhang</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Z-Fran" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/tajir0"><img src="https://avatars.githubusercontent.com/u/36022362?s=100" width="100px;" alt="Jinrong Tang"/><br /><sub><b>Jinrong Tang</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tajir0" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=tajir0" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/pirnerjonas"><img src="https://avatars.githubusercontent.com/u/48887249?v=4?s=100" width="100px;" alt="Jonas Pirner"/><br /><sub><b>Jonas Pirner</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pirnerjonas" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/JonathanBechtel"><img src="https://avatars.githubusercontent.com/u/481696?v=4?s=100" width="100px;" alt="JonathanBechtel"/><br /><sub><b>JonathanBechtel</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=JonathanBechtel" title="Code">💻</a> <a href="#ideas-JonathanBechtel" title="Ideas, Planning, & Feedback">🤔</a> <a href="#projectManagement-JonathanBechtel" title="Project Management">📆</a> <a href="#talk-JonathanBechtel" title="Talks">📢</a> <a href="https://github.com/sktime/sktime/commits?author=JonathanBechtel" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/jorenham"><img src="?s=100" width="100px;" alt="Joren Hammudoglu"/><br /><sub><b>Joren Hammudoglu</b></sub></a><br /><a href="#infra-jorenham" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
@@ -181,9 +182,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/jelc53"><img src="?s=100" width="100px;" alt="Julian Cooper"/><br /><sub><b>Julian Cooper</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jelc53" title="Code">💻</a> <a href="#ideas-jelc53" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/helloplayer1"><img src="https://avatars.githubusercontent.com/u/32032467?v=4?s=100" width="100px;" alt="Julian Haderlein"/><br /><sub><b>Julian Haderlein</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=helloplayer1" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/julnow"><img src="https://avatars.githubusercontent.com/u/21206185?v=4?s=100" width="100px;" alt="Julian Nowak"/><br /><sub><b>Julian Nowak</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ajulnow" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=julnow" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/julianarn/"><img src="https://avatars.githubusercontent.com/u/19613567?v=4?s=100" width="100px;" alt="Juliana"/><br /><sub><b>Juliana</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=julramos" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/julianarn/"><img src="https://avatars.githubusercontent.com/u/19613567?v=4?s=100" width="100px;" alt="Juliana"/><br /><sub><b>Juliana</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=julramos" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/jusssch"><img src="https://avatars.githubusercontent.com/jusssch?s=100" width="100px;" alt="Julius Schmid"/><br /><sub><b>Julius Schmid</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jusssch" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.justinshenk.com/"><img src="https://avatars.githubusercontent.com/u/10270308?v=4?s=100" width="100px;" alt="Justin Shenk"/><br /><sub><b>Justin Shenk</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=justinshenk" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/kcc-lion"><img src="?s=100" width="100px;" alt="Kai Lion"/><br /><sub><b>Kai Lion</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Documentation">📖</a></td>
@@ -192,9 +193,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/kevinlam2"><img src="https://avatars.githubusercontent.com/u/114420932?s=400&v=4?s=100" width="100px;" alt="Kevin Lam"/><br /><sub><b>Kevin Lam</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=klam-data" title="Code">💻</a> <a href="#example-klam-data" title="Examples">💡</a> <a href="https://github.com/sktime/sktime/commits?author=klam-data" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/kirilral"><img src="https://avatars.githubusercontent.com/u/34281484?v=4?s=100" width="100px;" alt="Kiril Ralinovski"/><br /><sub><b>Kiril Ralinovski</b></sub></a><br /><a href="#ideas-kirilral" title="Ideas, Planning, & Feedback">🤔</a> <a href="#mentoring-kirilral" title="Mentoring">🧑‍🏫</a> <a href="#projectManagement-kirilral" title="Project Management">📆</a> <a href="#talk-kirilral" title="Talks">📢</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://whitakerlab.github.io/"><img src="https://avatars1.githubusercontent.com/u/3626306?v=4?s=100" width="100px;" alt="Kirstie Whitaker"/><br /><sub><b>Kirstie Whitaker</b></sub></a><br /><a href="#ideas-KirstieJane" title="Ideas, Planning, & Feedback">🤔</a> <a href="#fundingFinding-KirstieJane" title="Funding Finding">🔍</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/kishmanani"><img src="https://avatars.githubusercontent.com/u/30973056?v=4?s=100" width="100px;" alt="Kishan Manani"/><br /><sub><b>Kishan Manani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AKishManani" title="Bug reports">🐛</a> <a href="#ideas-KishManani" title="Ideas, Planning, & Feedback">🤔</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/kishmanani"><img src="https://avatars.githubusercontent.com/u/30973056?v=4?s=100" width="100px;" alt="Kishan Manani"/><br /><sub><b>Kishan Manani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AKishManani" title="Bug reports">🐛</a> <a href="#ideas-KishManani" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ksharma6"><img src="https://avatars.githubusercontent.com/u/142558351?v=4?s=100" width="100px;" alt="Kishen Sharma"/><br /><sub><b>Kishen Sharma</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aksharma6" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=ksharma6" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/krumeto"><img src="https://avatars3.githubusercontent.com/u/11272436?v=4?s=100" width="100px;" alt="Krum Arnaudov"/><br /><sub><b>Krum Arnaudov</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Akrumeto" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=krumeto" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/koralturkk"><img src="https://avatars2.githubusercontent.com/u/18037789?s=460&v=4?s=100" width="100px;" alt="Kutay Koralturk"/><br /><sub><b>Kutay Koralturk</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=koralturkk" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Akoralturkk" title="Bug reports">🐛</a></td>
@@ -203,9 +204,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/chillerobscuro"><img src="https://avatars.githubusercontent.com/u/5232872?v=4?s=100" width="100px;" alt="Logan Duffy"/><br /><sub><b>Logan Duffy</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Achillerobscuro" title="Bug reports">🐛</a> <a href="#ideas-chillerobscuro" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="11.11%"><a href="http://lpantano.github.io/"><img src="https://avatars2.githubusercontent.com/u/1621788?v=4?s=100" width="100px;" alt="Lorena Pantano"/><br /><sub><b>Lorena Pantano</b></sub></a><br /><a href="#ideas-lpantano" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ltoniazzi"><img src="https://avatars.githubusercontent.com/u/61414566?s=100" width="100px;" alt="Lorenzo Toniazzi"/><br /><sub><b>Lorenzo Toniazzi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ltoniazzi" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Lovkush-A"><img src="https://avatars.githubusercontent.com/u/25344832?v=4?s=100" width="100px;" alt="Lovkush"/><br /><sub><b>Lovkush</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Tests">⚠️</a> <a href="#ideas-Lovkush-A" title="Ideas, Planning, & Feedback">🤔</a> <a href="#mentoring-Lovkush-A" title="Mentoring">🧑‍🏫</a> <a href="#projectManagement-Lovkush-A" title="Project Management">📆</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Lovkush-A"><img src="https://avatars.githubusercontent.com/u/25344832?v=4?s=100" width="100px;" alt="Lovkush"/><br /><sub><b>Lovkush</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Tests">⚠️</a> <a href="#ideas-Lovkush-A" title="Ideas, Planning, & Feedback">🤔</a> <a href="#mentoring-Lovkush-A" title="Mentoring">🧑‍🏫</a> <a href="#projectManagement-Lovkush-A" title="Project Management">📆</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/luca-miniati"><img src="https://avatars.githubusercontent.com/u/87467600?v=4?s=100" width="100px;" alt="Luca Miniati"/><br /><sub><b>Luca Miniati</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=luca-miniati" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=luca-miniati" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/lbventura"><img src="https://avatars.githubusercontent.com/u/68004282?s=96&v=4?s=100" width="100px;" alt="Luis Ventura"/><br /><sub><b>Luis Ventura</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lbventura" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/luiszugasti"><img src="https://avatars.githubusercontent.com/u/11198457?s=460&u=0645b72683e491824aca16db9702f1d3eb990389&v=4?s=100" width="100px;" alt="Luis Zugasti"/><br /><sub><b>Luis Zugasti</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=luiszugasti" title="Documentation">📖</a></td>
@@ -214,9 +215,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/manuel-munoz-aguirre"><img src="https://avatars.githubusercontent.com/u/5576458?v=4?s=100" width="100px;" alt="Manuel Muñoz Aguirre"/><br /><sub><b>Manuel Muñoz Aguirre</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=manuel-munoz-aguirre" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/manolotis"><img src="https://avatars.githubusercontent.com/manolotis?s=100" width="100px;" alt="Manuel Muñoz Sánchez"/><br /><sub><b>Manuel Muñoz Sánchez</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=manolotis" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/marrov"><img src="https://avatars.githubusercontent.com/u/54272586?v=4?s=100" width="100px;" alt="Marc Rovira"/><br /><sub><b>Marc Rovira</b></sub></a><br /><a href="#design-marrov" title="Design">🎨</a> <a href="https://github.com/sktime/sktime/commits?author=marrov" title="Documentation">📖</a> <a href="#ideas-marrov" title="Ideas, Planning, & Feedback">🤔</a> <a href="#mentoring-marrov" title="Mentoring">🧑‍🏫</a> <a href="#projectManagement-marrov" title="Project Management">📆</a> <a href="#talk-marrov" title="Talks">📢</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="http://marcelotryle.com"><img src="https://avatars3.githubusercontent.com/u/7353520?v=4?s=100" width="100px;" alt="Marcelo Trylesinski"/><br /><sub><b>Marcelo Trylesinski</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Kludex" title="Documentation">📖</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="http://marcelotryle.com"><img src="https://avatars3.githubusercontent.com/u/7353520?v=4?s=100" width="100px;" alt="Marcelo Trylesinski"/><br /><sub><b>Marcelo Trylesinski</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Kludex" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MarcoGorelli"><img src="https://avatars2.githubusercontent.com/u/33491632?v=4?s=100" width="100px;" alt="Marco Gorelli"/><br /><sub><b>Marco Gorelli</b></sub></a><br /><a href="#infra-MarcoGorelli" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/margaret-gorlin/"><img src="?s=100" width="100px;" alt="Margaret Gorlin"/><br /><sub><b>Margaret Gorlin</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mgorlin" title="Code">💻</a> <a href="#example-mgorlin" title="Examples">💡</a> <a href="https://github.com/sktime/sktime/commits?author=mgorlin" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/mariamjabara"><img src="?s=100" width="100px;" alt="Mariam Jabara"/><br /><sub><b>Mariam Jabara</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mariamjabara" title="Code">💻</a></td>
@@ -225,9 +226,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/markussagen"><img src="https://avatars.githubusercontent.com/u/20767068?v=4?s=100" width="100px;" alt="Markus Sagen"/><br /><sub><b>Markus Sagen</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=markussagen" title="Code">💻</a> <a href="#example-markussagen" title="Examples">💡</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/martin-walter-1a33b3114/"><img src="https://avatars0.githubusercontent.com/u/29627036?v=4?s=100" width="100px;" alt="Martin Walter"/><br /><sub><b>Martin Walter</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=aiwalter" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Aaiwalter" title="Bug reports">🐛</a> <a href="#projectManagement-aiwalter" title="Project Management">📆</a> <a href="#fundingFinding-aiwalter" title="Funding Finding">🔍</a> <a href="#mentoring-aiwalter" title="Mentoring">🧑‍🏫</a> <a href="#ideas-aiwalter" title="Ideas, Planning, & Feedback">🤔</a> <a href="#design-aiwalter" title="Design">🎨</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Aaiwalter" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sktime/sktime/commits?author=aiwalter" title="Documentation">📖</a> <a href="#talk-aiwalter" title="Talks">📢</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/martinagvilas"><img src="https://avatars2.githubusercontent.com/u/37339384?v=4?s=100" width="100px;" alt="Martina G. Vilas"/><br /><sub><b>Martina G. Vilas</b></sub></a><br /><a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Amartinagvilas" title="Reviewed Pull Requests">👀</a> <a href="#ideas-martinagvilas" title="Ideas, Planning, & Feedback">🤔</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/mateuszkasprowicz"><img src="https://avatars.githubusercontent.com/mateuszkasprowicz?s=100" width="100px;" alt="Mateusz Kasprowicz"/><br /><sub><b>Mateusz Kasprowicz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mateuszkasprowicz" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=mateuszkasprowicz" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/mateuszkasprowicz"><img src="https://avatars.githubusercontent.com/mateuszkasprowicz?s=100" width="100px;" alt="Mateusz Kasprowicz"/><br /><sub><b>Mateusz Kasprowicz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mateuszkasprowicz" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=mateuszkasprowicz" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MCRE-BE"><img src="https://avatars.githubusercontent.com/u/99316631?s=100" width="100px;" alt="Mathias Creemers"/><br /><sub><b>Mathias Creemers</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AMCRE-BE" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=MCRE-BE" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars0.githubusercontent.com/u/25731235?v=4?s=100" width="100px;" alt="Matthew Middlehurst"/><br /><sub><b>Matthew Middlehurst</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Tests">⚠️</a> <a href="#tutorial-MatthewMiddlehurst" title="Tutorials">✅</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3AMatthewMiddlehurst" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AMatthewMiddlehurst" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/tvdboom"><img src="https://avatars.githubusercontent.com/u/32366550?v=4?s=100" width="100px;" alt="Mavs"/><br /><sub><b>Mavs</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tvdboom" title="Code">💻</a></td>
@@ -236,9 +237,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/meraldoantonio"><img src="https://avatars.githubusercontent.com/u/37468543?v=4?s=100" width="100px;" alt="Meraldo Antonio"/><br /><sub><b>Meraldo Antonio</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ameraldoantonio" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=meraldoantonio" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=meraldoantonio" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=meraldoantonio" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Hephaest"><img src="https://avatars2.githubusercontent.com/u/37981444?v=4?s=100" width="100px;" alt="Miao Cai"/><br /><sub><b>Miao Cai</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AHephaest" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=Hephaest" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="michaelfeil.eu"><img src="https://avatars.githubusercontent.com/u/63565275?v=4?s=100" width="100px;" alt="Michael Feil"/><br /><sub><b>Michael Feil</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=michaelfeil" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=michaelfeil" title="Tests">⚠️</a> <a href="#ideas-michaelfeil" title="Ideas, Planning, & Feedback">🤔</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/mgazian000"><img src="https://avatars.githubusercontent.com/mgazian000?s=100" width="100px;" alt="Michael Gaziani"/><br /><sub><b>Michael Gaziani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mgazian000" title="Documentation">📖</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/mgazian000"><img src="https://avatars.githubusercontent.com/mgazian000?s=100" width="100px;" alt="Michael Gaziani"/><br /><sub><b>Michael Gaziani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mgazian000" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MMTrooper"><img src="https://avatars.githubusercontent.com/u/89777534?v=4?s=100" width="100px;" alt="Michael Mwimali"/><br /><sub><b>Michael Mwimali</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MMTrooper" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MichalChromcak"><img src="https://avatars1.githubusercontent.com/u/12393430?v=4?s=100" width="100px;" alt="Michal Chromcak"/><br /><sub><b>Michal Chromcak</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Tests">⚠️</a> <a href="#tutorial-MichalChromcak" title="Tutorials">✅</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/mjste"><img src="https://avatars.githubusercontent.com/mjste?s=100" width="100px;" alt="Michał Stefanik"/><br /><sub><b>Michał Stefanik</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mjste" title="Documentation">📖</a></td>
@@ -247,9 +248,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MBristle"><img src="https://avatars.githubusercontent.com/MBristle?s=100" width="100px;" alt="Mirko Bristle"/><br /><sub><b>Mirko Bristle</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AMBristle" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=MBristle" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=MBristle" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=MBristle" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://mo-saif.github.io/"><img src="https://avatars0.githubusercontent.com/u/27867617?v=4?s=100" width="100px;" alt="Mohammed Saif Kazamel"/><br /><sub><b>Mohammed Saif Kazamel</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AMo-Saif" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://moradabaz.github.io/"><img src="https://avatars.githubusercontent.com/u/29915156?v=4?s=100" width="100px;" alt="Morad :)"/><br /><sub><b>Morad :)</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Documentation">📖</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Multivin12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=100" width="100px;" alt="Multivin12"/><br /><sub><b>Multivin12</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Multivin12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=100" width="100px;" alt="Multivin12"/><br /><sub><b>Multivin12</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/marcio55afr"><img src="https://avatars.githubusercontent.com/u/42646282?v=4?s=100" width="100px;" alt="Márcio A. Freitas Jr"/><br /><sub><b>Márcio A. Freitas Jr</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=marcio55afr" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/niekvanderlaan"><img src="https://avatars.githubusercontent.com/u/9962825?v=4?s=100" width="100px;" alt="Niek van der Laan"/><br /><sub><b>Niek van der Laan</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=niekvanderlaan" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Dehelaan"><img src="https://avatars.githubusercontent.com/u/120308161?s=400&v=4?s=100" width="100px;" alt="Nihal Chaudhary"/><br /><sub><b>Nihal Chaudhary</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Dehelaan" title="Documentation">📖</a></td>
@@ -258,9 +259,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/nilesh05apr"><img src="https://avatars.githubusercontent.com/u/65773314?v=4?s=100" width="100px;" alt="Nilesh Kumar"/><br /><sub><b>Nilesh Kumar</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=nilesh05apr" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ninfueng"><img src="https://avatars2.githubusercontent.com/u/28499769?v=4?s=100" width="100px;" alt="Ninnart Fuengfusin"/><br /><sub><b>Ninnart Fuengfusin</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ninfueng" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/NoaBenAmi"><img src="https://avatars.githubusercontent.com/u/37590002?v=4?s=100" width="100px;" alt="Noa Ben Ami"/><br /><sub><b>Noa Ben Ami</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Documentation">📖</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/shchur"><img src="https://avatars.githubusercontent.com/u/6944857?v=4?s=100" width="100px;" alt="Oleksandr Shchur"/><br /><sub><b>Oleksandr Shchur</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ashchur" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=shchur" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/shchur"><img src="https://avatars.githubusercontent.com/u/6944857?v=4?s=100" width="100px;" alt="Oleksandr Shchur"/><br /><sub><b>Oleksandr Shchur</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ashchur" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=shchur" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/kachayev"><img src="https://avatars.githubusercontent.com/u/485647?v=4?s=100" width="100px;" alt="Oleksii Kachaiev"/><br /><sub><b>Oleksii Kachaiev</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kachayev" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=kachayev" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/olivermatthews"><img src="https://avatars.githubusercontent.com/u/31141490?v=4?s=100" width="100px;" alt="Oliver Matthews"/><br /><sub><b>Oliver Matthews</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=OliverMatthews" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/prockenschaub"><img src="https://avatars0.githubusercontent.com/u/15381732?v=4?s=100" width="100px;" alt="Patrick Rockenschaub"/><br /><sub><b>Patrick Rockenschaub</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=prockenschaub" title="Code">💻</a> <a href="#design-prockenschaub" title="Design">🎨</a> <a href="#ideas-prockenschaub" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/commits?author=prockenschaub" title="Tests">⚠️</a></td>
@@ -269,9 +270,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/paulyim97/"><img src="https://avatars.githubusercontent.com/pyyim?s=100" width="100px;" alt="Paul Yim"/><br /><sub><b>Paul Yim</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pyyim" title="Code">💻</a> <a href="#example-pyyim" title="Examples">💡</a> <a href="https://github.com/sktime/sktime/commits?author=pyyim" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.imes.uni-hannover.de/de/institut/team/m-sc-karl-philipp-kortmann/"><img src="https://avatars.githubusercontent.com/u/20466981?v=4?s=100" width="100px;" alt="Philipp Kortmann"/><br /><sub><b>Philipp Kortmann</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MrPr3ntice" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=MrPr3ntice" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Piyush1729"><img src="https://avatars2.githubusercontent.com/u/64950012?v=4?s=100" width="100px;" alt="Piyush Gade"/><br /><sub><b>Piyush Gade</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Piyush1729" title="Code">💻</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3APiyush1729" title="Reviewed Pull Requests">👀</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/rahulporuri"><img src="https://avatars.githubusercontent.com/u/1926457?v=4?s=100" width="100px;" alt="Poruri Sai Rahul"/><br /><sub><b>Poruri Sai Rahul</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=rahulporuri" title="Documentation">📖</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/rahulporuri"><img src="https://avatars.githubusercontent.com/u/1926457?v=4?s=100" width="100px;" alt="Poruri Sai Rahul"/><br /><sub><b>Poruri Sai Rahul</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=rahulporuri" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/pranav-prajapati-a5b413226/"><img src="https://avatars.githubusercontent.com/u/94780581?v=4?s=100" width="100px;" alt="Pranav Prajapati"/><br /><sub><b>Pranav Prajapati</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pranavvp16" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=pranavvp16" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Apranavvp16" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Prtm2110"><img src="https://avatars.githubusercontent.com/u/139000226?s=400&u=a2ef29514ad2780d1263ba9d724898132c8d18fb&v=4?s=100" width="100px;" alt="Pratham Hole"/><br /><sub><b>Pratham Hole</b></sub></a><br /><a href="#maintenance-Prtm2110" title="Maintenance">🚧</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/pul95"><img src="https://avatars.githubusercontent.com/pul95?s=100" width="100px;" alt="Pulkit Verma"/><br /><sub><b>Pulkit Verma</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pul95" title="Documentation">📖</a></td>
@@ -280,9 +281,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Ram0nB"><img src="https://avatars.githubusercontent.com/u/45173421?s=100" width="100px;" alt="Ramon Bussing"/><br /><sub><b>Ramon Bussing</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ram0nB" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=Ram0nB" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3ARam0nB" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=Ram0nB" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/RavenRudi"><img src="https://avatars.githubusercontent.com/u/46402968?v=4?s=100" width="100px;" alt="RavenRudi"/><br /><sub><b>RavenRudi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RavenRudi" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/wolph"><img src="?s=100" width="100px;" alt="Rick van Hattem"/><br /><sub><b>Rick van Hattem</b></sub></a><br /><a href="#infra-wolph" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/RigvedManoj"><img src="https://avatars.githubusercontent.com/u/28307990?v=4?s=100" width="100px;" alt="Rigved Manoj"/><br /><sub><b>Rigved Manoj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RigvedManoj" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/RigvedManoj"><img src="https://avatars.githubusercontent.com/u/28307990?v=4?s=100" width="100px;" alt="Rigved Manoj"/><br /><sub><b>Rigved Manoj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RigvedManoj" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Ris-Bali"><img src="https://avatars.githubusercontent.com/u/81592570?v=4?s=100" width="100px;" alt="Rishabh Bali"/><br /><sub><b>Rishabh Bali</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ris-Bali" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/VectorNd"><img src="https://avatars.githubusercontent.com/u/111004091?v=4?s=100" width="100px;" alt="Rishabh Kamboj"/><br /><sub><b>Rishabh Kamboj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=VectorNd" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/RishiKumarRay"><img src="https://avatars.githubusercontent.com/u/87641376?v=4?s=100" width="100px;" alt="Rishi Kumar Ray"/><br /><sub><b>Rishi Kumar Ray</b></sub></a><br /><a href="#infra-RishiKumarRay" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
@@ -291,9 +292,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://linkedin.com/in/robert-kuebler"><img src="https://avatars.githubusercontent.com/u/932327?v=4?s=100" width="100px;" alt="Robert Kübler"/><br /><sub><b>Robert Kübler</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AGarve" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=Garve" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/romanlutz/"><img src="https://avatars.githubusercontent.com/u/10245648?v=4?s=100" width="100px;" alt="Roman Lutz"/><br /><sub><b>Roman Lutz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=romanlutz" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ronnie-llamado"><img src="https://avatars.githubusercontent.com/ronnie-llamado?s=100" width="100px;" alt="Ronnie Llamado"/><br /><sub><b>Ronnie Llamado</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ronnie-llamado" title="Documentation">📖</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/rnkuhns"><img src="https://avatars0.githubusercontent.com/u/26907244?v=4?s=100" width="100px;" alt="Ryan Kuhns"/><br /><sub><b>Ryan Kuhns</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Documentation">📖</a> <a href="#tutorial-RNKuhns" title="Tutorials">✅</a> <a href="#example-RNKuhns" title="Examples">💡</a> <a href="#ideas-RNKuhns" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ARNKuhns" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/rnkuhns"><img src="https://avatars0.githubusercontent.com/u/26907244?v=4?s=100" width="100px;" alt="Ryan Kuhns"/><br /><sub><b>Ryan Kuhns</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Documentation">📖</a> <a href="#tutorial-RNKuhns" title="Tutorials">✅</a> <a href="#example-RNKuhns" title="Examples">💡</a> <a href="#ideas-RNKuhns" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ARNKuhns" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/achieveordie"><img src="https://avatars.githubusercontent.com/u/54197164?v=4?s=100" width="100px;" alt="Sagar Mishra"/><br /><sub><b>Sagar Mishra</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aachieveordie" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=achieveordie" title="Code">💻</a> <a href="#ideas-achieveordie" title="Ideas, Planning, & Feedback">🤔</a> <a href="#projectManagement-achieveordie" title="Project Management">📆</a> <a href="https://github.com/sktime/sktime/commits?author=achieveordie" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/SaiRevanth25"><img src="https://avatars.githubusercontent.com/SaiRevanth25?s=100" width="100px;" alt="Sai Revanth Gowravajhala"/><br /><sub><b>Sai Revanth Gowravajhala</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=SaiRevanth25" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3ASaiRevanth25" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://sajay.online"><img src="https://avatars2.githubusercontent.com/u/25329624?v=4?s=100" width="100px;" alt="Sajaysurya Ganesh"/><br /><sub><b>Sajaysurya Ganesh</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Documentation">📖</a> <a href="#design-sajaysurya" title="Design">🎨</a> <a href="#example-sajaysurya" title="Examples">💡</a> <a href="#ideas-sajaysurya" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Tests">⚠️</a> <a href="#tutorial-sajaysurya" title="Tutorials">✅</a></td>
@@ -302,9 +303,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/sanjayk0508"><img src="https://avatars.githubusercontent.com/u/102804548?v=4?s=100" width="100px;" alt="Sanjay Kumar"/><br /><sub><b>Sanjay Kumar</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sanjayk0508" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/deysanjeeb"><img src="https://avatars.githubusercontent.com/u/39940629?v=4?s=100" width="100px;" alt="Sanjeeb Dey"/><br /><sub><b>Sanjeeb Dey</b></sub></a><br /><a href="#maintenance-deysanjeeb" title="Maintenance">🚧</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/sssilvar"><img src="https://avatars.githubusercontent.com/u/16252054?v=4?s=100" width="100px;" alt="Santiago Smith Silva"/><br /><sub><b>Santiago Smith Silva</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sssilvar" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Saptarshi-Bandopadhyay"><img src="https://avatars.githubusercontent.com/u/88289395?v=4?s=100" width="100px;" alt="Saptarshi Bandopadhyay"/><br /><sub><b>Saptarshi Bandopadhyay</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Saptarshi-Bandopadhyay" title="Documentation">📖</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/Saptarshi-Bandopadhyay"><img src="https://avatars.githubusercontent.com/u/88289395?v=4?s=100" width="100px;" alt="Saptarshi Bandopadhyay"/><br /><sub><b>Saptarshi Bandopadhyay</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Saptarshi-Bandopadhyay" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Saransh-cpp"><img src="https://avatars.githubusercontent.com/u/74055102?v=4?s=100" width="100px;" alt="Saransh Chopra"/><br /><sub><b>Saransh Chopra</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Saransh-cpp" title="Documentation">📖</a> <a href="#infra-Saransh-cpp" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/satya-pattnaik-77a430144/"><img src="https://avatars.githubusercontent.com/u/22102468?v=4?s=100" width="100px;" alt="Satya Prakash Pattnaik"/><br /><sub><b>Satya Prakash Pattnaik</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=satya-pattnaik" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/dasgupsa"><img src="https://avatars2.githubusercontent.com/u/10398956?v=4?s=100" width="100px;" alt="Saurabh Dasgupta"/><br /><sub><b>Saurabh Dasgupta</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dasgupsa" title="Code">💻</a></td>
@@ -313,9 +314,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/bastisar"><img src="https://avatars.githubusercontent.com/u/142449680?v=4?s=100" width="100px;" alt="Sebastian Hien"/><br /><sub><b>Sebastian Hien</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=bastisar" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Abastisar" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=bastisar" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ShivamPathak99"><img src="https://avatars.githubusercontent.com/u/98941325?s=400&v=4?s=100" width="100px;" alt="Shivam Pathak"/><br /><sub><b>Shivam Pathak</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ShivamPathak99" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ShivamJ07"><img src="https://avatars.githubusercontent.com/ShivamJ07?s=100" width="100px;" alt="Shivam Singal"/><br /><sub><b>Shivam Singal</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AShivamJ07" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=ShivamJ07" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/AurumnPegasus"><img src="https://avatars.githubusercontent.com/u/54315149?v=4?s=100" width="100px;" alt="Shivansh Subramanian"/><br /><sub><b>Shivansh Subramanian</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/AurumnPegasus"><img src="https://avatars.githubusercontent.com/u/54315149?v=4?s=100" width="100px;" alt="Shivansh Subramanian"/><br /><sub><b>Shivansh Subramanian</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><img src="https://gravatar.com/avatar/cbdbaac712ae282d730cd3028e862d45?s=400&d=robohash&r=x?s=100" width="100px;" alt="Shlok Sabarwal"/><br /><sub><b>Shlok Sabarwal</b></sub><br /><a href="https://github.com/sktime/sktime/commits?author=ssabarwal" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ShreeshaM07"><img src="https://avatars.githubusercontent.com/u/120820143?s=400&v=4?s=100" width="100px;" alt="Shreesha M"/><br /><sub><b>Shreesha M</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AShreeshaM07" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=ShreeshaM07" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=ShreeshaM07" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/sbuse"><img src="https://avatars.githubusercontent.com/u/24408707?v=4?s=100" width="100px;" alt="Simon B."/><br /><sub><b>Simon B.</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sbuse" title="Code">💻</a></td>
@@ -324,9 +325,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/khrapovs"><img src="https://avatars.githubusercontent.com/u/3774663?v=4?s=100" width="100px;" alt="Stanislav Khrapov"/><br /><sub><b>Stanislav Khrapov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=khrapovs" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/steenrotsman"><img src="https://avatars.githubusercontent.com/u/78110080?s=400&v=4?s=100" width="100px;" alt="Stijn J. Rotman"/><br /><sub><b>Stijn J. Rotman</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=steenrotsman" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=steenrotsman" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/SveaMeyer13"><img src="https://avatars.githubusercontent.com/u/46671894?v=4?s=100" width="100px;" alt="Svea Marie Meyer"/><br /><sub><b>Svea Marie Meyer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=SveaMeyer13" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=SveaMeyer13" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/TNTran92"><img src="https://avatars.githubusercontent.com/u/55965636?v=4?s=100" width="100px;" alt="TNTran92"/><br /><sub><b>TNTran92</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TNTran92" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/TNTran92"><img src="https://avatars.githubusercontent.com/u/55965636?v=4?s=100" width="100px;" alt="TNTran92"/><br /><sub><b>TNTran92</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TNTran92" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/Taise228"><img src="https://avatars.githubusercontent.com/u/95762401?s=400&v=4?s=100" width="100px;" alt="Taisei Yamamoto"/><br /><sub><b>Taisei Yamamoto</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Taise228" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://thayeylolu.github.io/portfolio/"><img src="https://avatars.githubusercontent.com/u/13348874?v=4?s=100" width="100px;" alt="Taiwo Owoseni"/><br /><sub><b>Taiwo Owoseni</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=thayeylolu" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/lnthach"><img src="https://avatars0.githubusercontent.com/u/7788363?v=4?s=100" width="100px;" alt="Thach Le Nguyen"/><br /><sub><b>Thach Le Nguyen</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lnthach" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=lnthach" title="Tests">⚠️</a></td>
@@ -335,9 +336,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/xxl4tomxu98"><img src="https://avatars.githubusercontent.com/u/62292177?s=40&v=4?s=100" width="100px;" alt="Tom Xu"/><br /><sub><b>Tom Xu</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xxl4tomxu98" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=xxl4tomxu98" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/tpvasconcelos"><img src="https://avatars.githubusercontent.com/u/17701527?v=4?s=100" width="100px;" alt="Tomas P. de Vasconcelos"/><br /><sub><b>Tomas P. de Vasconcelos</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Atpvasconcelos" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=tpvasconcelos" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/tch"><img src="https://avatars3.githubusercontent.com/u/184076?v=4?s=100" width="100px;" alt="Tomasz Chodakowski"/><br /><sub><b>Tomasz Chodakowski</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tch" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=tch" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Atch" title="Bug reports">🐛</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/9594042?v=4?s=100" width="100px;" alt="Tony Bagnall"/><br /><sub><b>Tony Bagnall</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Code">💻</a> <a href="#business-TonyBagnall" title="Business development">💼</a> <a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Documentation">📖</a> <a href="#design-TonyBagnall" title="Design">🎨</a> <a href="#eventOrganizing-TonyBagnall" title="Event Organizing">📋</a> <a href="#fundingFinding-TonyBagnall" title="Funding Finding">🔍</a> <a href="#ideas-TonyBagnall" title="Ideas, Planning, & Feedback">🤔</a> <a href="#projectManagement-TonyBagnall" title="Project Management">📆</a> <a href="#question-TonyBagnall" title="Answering Questions">💬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ATonyBagnall" title="Reviewed Pull Requests">👀</a> <a href="#talk-TonyBagnall" title="Talks">📢</a> <a href="#data-TonyBagnall" title="Data">🔣</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/9594042?v=4?s=100" width="100px;" alt="Tony Bagnall"/><br /><sub><b>Tony Bagnall</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Code">💻</a> <a href="#business-TonyBagnall" title="Business development">💼</a> <a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Documentation">📖</a> <a href="#design-TonyBagnall" title="Design">🎨</a> <a href="#eventOrganizing-TonyBagnall" title="Event Organizing">📋</a> <a href="#fundingFinding-TonyBagnall" title="Funding Finding">🔍</a> <a href="#ideas-TonyBagnall" title="Ideas, Planning, & Feedback">🤔</a> <a href="#projectManagement-TonyBagnall" title="Project Management">📆</a> <a href="#question-TonyBagnall" title="Answering Questions">💬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ATonyBagnall" title="Reviewed Pull Requests">👀</a> <a href="#talk-TonyBagnall" title="Talks">📢</a> <a href="#data-TonyBagnall" title="Data">🔣</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/onyekaugochukwu"><img src="https://avatars.githubusercontent.com/u/92909501?v=4?s=100" width="100px;" alt="Ugochukwu Onyeka"/><br /><sub><b>Ugochukwu Onyeka</b></sub></a><br /><a href="#business-onyekaugochukwu" title="Business development">💼</a> <a href="https://github.com/sktime/sktime/commits?author=onyekaugochukwu" title="Documentation">📖</a> <a href="#ideas-onyekaugochukwu" title="Ideas, Planning, & Feedback">🤔</a> <a href="#mentoring-onyekaugochukwu" title="Mentoring">🧑‍🏫</a> <a href="#projectManagement-onyekaugochukwu" title="Project Management">📆</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/utsavcoding"><img src="https://avatars3.githubusercontent.com/u/55446385?v=4?s=100" width="100px;" alt="Utsav Kumar Tiwari"/><br /><sub><b>Utsav Kumar Tiwari</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=utsavcoding" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=utsavcoding" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/vandit98"><img src="https://avatars.githubusercontent.com/u/91458535?v=4?s=100" width="100px;" alt="Vandit Tyagi"/><br /><sub><b>Vandit Tyagi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vandit98" title="Documentation">📖</a></td>
@@ -346,9 +347,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/jgyfutub"><img src="https://avatars.githubusercontent.com/u/97391064?s=400&v=4?s=100" width="100px;" alt="Vedant Pandey"/><br /><sub><b>Vedant Pandey</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jgyfutub" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/victordremov"><img src="https://avatars.githubusercontent.com/u/32140716?s=100" width="100px;" alt="Viktor Dremov"/><br /><sub><b>Viktor Dremov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=victordremov" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ViktorKaz"><img src="https://avatars0.githubusercontent.com/u/33499138?v=4?s=100" width="100px;" alt="ViktorKaz"/><br /><sub><b>ViktorKaz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ViktorKaz" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=ViktorKaz" title="Documentation">📖</a> <a href="#design-ViktorKaz" title="Design">🎨</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/vnicholson1"><img src="?s=100" width="100px;" alt="Vincent Nicholson"/><br /><sub><b>Vincent Nicholson</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vnicholson1" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/vnicholson1"><img src="?s=100" width="100px;" alt="Vincent Nicholson"/><br /><sub><b>Vincent Nicholson</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vnicholson1" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/VyomkeshVyas"><img src="?s=100" width="100px;" alt="Vyomkesh Vyas"/><br /><sub><b>Vyomkesh Vyas</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Documentation">📖</a> <a href="#example-VyomkeshVyas" title="Examples">💡</a> <a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/wayneadams"><img src="https://avatars.githubusercontent.com/u/15034841?s=400&u=d717e9945910bcc844c5e64cd56d570c6cc4e8e6&v=4?s=100" width="100px;" alt="Wayne Adams"/><br /><sub><b>Wayne Adams</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=wayneadams" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/fr1ll"><img src="https://avatars.githubusercontent.com/u/29168593?v=4?s=100" width="100px;" alt="Will Sanger"/><br /><sub><b>Will Sanger</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=fr1ll" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=fr1ll" title="Documentation">📖</a></td>
@@ -357,9 +358,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/wirrywoo"><img src="https://avatars.githubusercontent.com/u/148647848?v=4?s=100?s=100" width="100px;" alt="Wilson Cheung"/><br /><sub><b>Wilson Cheung</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=wirrywoo" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=wirrywoo" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/wpdonders"><img src="https://avatars.githubusercontent.com/u/1868824?v=4?s=100?s=100" width="100px;" alt="Wouter Donders"/><br /><sub><b>Wouter Donders</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=wpdonders" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=wpdonders" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/XinyuWuu"><img src="https://avatars.githubusercontent.com/u/57612792?v=4?s=100" width="100px;" alt="Xinyu Wu"/><br /><sub><b>Xinyu Wu</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AXinyuWuu" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=XinyuWuu" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=XinyuWuu" title="Tests">⚠️</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/yairbeer"><img src="https://avatars.githubusercontent.com/yairbeer?s=100" width="100px;" alt="Yair Beer"/><br /><sub><b>Yair Beer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=yairbeer" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/yairbeer"><img src="https://avatars.githubusercontent.com/yairbeer?s=100" width="100px;" alt="Yair Beer"/><br /><sub><b>Yair Beer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=yairbeer" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/yann-hallouard/"><img src="https://avatars.githubusercontent.com/YHallouard?s=100" width="100px;" alt="Yann Hallouard"/><br /><sub><b>Yann Hallouard</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=YHallouard" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=YHallouard" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/MEMEO-PRO"><img src="https://avatars.githubusercontent.com/memeo-pro?s=100" width="100px;" alt="Yash Edake"/><br /><sub><b>Yash Edake</b></sub></a><br /><a href="#maintenance-memeo-pro" title="Maintenance">🚧</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Amemeo-pro" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/YashKhare20"><img src="https://avatars.githubusercontent.com/u/92680366?s=400?s=100" width="100px;" alt="Yash Khare"/><br /><sub><b>Yash Khare</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=YashKhare20" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=YashKhare20" title="Documentation">📖</a></td>
@@ -368,9 +369,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/sz85512678"><img src="https://avatars.githubusercontent.com/sz85512678?s=100" width="100px;" alt="Zhen Shao"/><br /><sub><b>Zhen Shao</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sz85512678" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/ZiyaoWei"><img src="https://avatars.githubusercontent.com/u/940823?v=4?s=100" width="100px;" alt="Ziyao Wei"/><br /><sub><b>Ziyao Wei</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ZiyaoWei" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/aa25desh"><img src="https://avatars1.githubusercontent.com/u/29518290?v=4?s=100" width="100px;" alt="aa25desh"/><br /><sub><b>aa25desh</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=aa25desh" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Aaa25desh" title="Bug reports">🐛</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/abandus"><img src="https://avatars2.githubusercontent.com/u/46486474?v=4?s=100" width="100px;" alt="abandus"/><br /><sub><b>abandus</b></sub></a><br /><a href="#ideas-abandus" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/commits?author=abandus" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/abandus"><img src="https://avatars2.githubusercontent.com/u/46486474?v=4?s=100" width="100px;" alt="abandus"/><br /><sub><b>abandus</b></sub></a><br /><a href="#ideas-abandus" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/commits?author=abandus" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/adoherty21"><img src="https://avatars.githubusercontent.com/u/52799751?s=400&v=4?s=100" width="100px;" alt="adoherty21"/><br /><sub><b>adoherty21</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aadoherty21" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/bethrice44"><img src="https://avatars.githubusercontent.com/u/11226988?v=4?s=100" width="100px;" alt="bethrice44"/><br /><sub><b>bethrice44</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Abethrice44" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=bethrice44" title="Code">💻</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Abethrice44" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sktime/sktime/commits?author=bethrice44" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/big-o"><img src="https://avatars1.githubusercontent.com/u/1134151?v=4?s=100" width="100px;" alt="big-o"/><br /><sub><b>big-o</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=big-o" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=big-o" title="Tests">⚠️</a> <a href="#design-big-o" title="Design">🎨</a> <a href="#ideas-big-o" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Abig-o" title="Reviewed Pull Requests">👀</a> <a href="#tutorial-big-o" title="Tutorials">✅</a> <a href="#mentoring-big-o" title="Mentoring">🧑‍🏫</a></td>
@@ -379,9 +380,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/btrtts"><img src="https://avatars3.githubusercontent.com/u/66252156?v=4?s=100" width="100px;" alt="btrtts"/><br /><sub><b>btrtts</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=btrtts" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/chizzi25"><img src="https://avatars3.githubusercontent.com/u/67911243?v=4?s=100" width="100px;" alt="chizzi25"/><br /><sub><b>chizzi25</b></sub></a><br /><a href="#blog-chizzi25" title="Blogposts">📝</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/chrisholder"><img src="https://avatars.githubusercontent.com/u/4674372?v=4?s=100" width="100px;" alt="chrisholder"/><br /><sub><b>chrisholder</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Tests">⚠️</a> <a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Documentation">📖</a> <a href="#design-chrisholder" title="Design">🎨</a> <a href="#example-chrisholder" title="Examples">💡</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/morestart"><img src="https://avatars.githubusercontent.com/u/35556811?s=100" width="100px;" alt="ctl"/><br /><sub><b>ctl</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Amorestart" title="Bug reports">🐛</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/morestart"><img src="https://avatars.githubusercontent.com/u/35556811?s=100" width="100px;" alt="ctl"/><br /><sub><b>ctl</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Amorestart" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/danbartl"><img src="https://avatars.githubusercontent.com/u/19947407?v=4?s=100" width="100px;" alt="danbartl"/><br /><sub><b>danbartl</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Adanbartl" title="Bug reports">🐛</a> <a href="https://github.com/sktime/sktime/commits?author=danbartl" title="Code">💻</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Adanbartl" title="Reviewed Pull Requests">👀</a> <a href="#talk-danbartl" title="Talks">📢</a> <a href="https://github.com/sktime/sktime/commits?author=danbartl" title="Tests">⚠️</a> <a href="#tutorial-danbartl" title="Tutorials">✅</a> <a href="#video-danbartl" title="Videos">📹</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/hamzahiqb"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=100" width="100px;" alt="hamzahiqb"/><br /><sub><b>hamzahiqb</b></sub></a><br /><a href="#infra-hamzahiqb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/hiqbal2"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=100" width="100px;" alt="hiqbal2"/><br /><sub><b>hiqbal2</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=hiqbal2" title="Documentation">📖</a></td>
@@ -390,9 +391,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/kkoziara"><img src="https://avatars1.githubusercontent.com/u/4346849?v=4?s=100" width="100px;" alt="kkoziara"/><br /><sub><b>kkoziara</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kkoziara" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Akkoziara" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/matteogales"><img src="https://avatars0.githubusercontent.com/u/9269326?v=4?s=100" width="100px;" alt="matteogales"/><br /><sub><b>matteogales</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=matteogales" title="Code">💻</a> <a href="#design-matteogales" title="Design">🎨</a> <a href="#ideas-matteogales" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/oleskiewicz"><img src="https://avatars1.githubusercontent.com/u/5682158?v=4?s=100" width="100px;" alt="oleskiewicz"/><br /><sub><b>oleskiewicz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Documentation">📖</a> <a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Tests">⚠️</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/pabworks"><img src="https://avatars.githubusercontent.com/u/32725127?v=4?s=100" width="100px;" alt="pabworks"/><br /><sub><b>pabworks</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/pabworks"><img src="https://avatars.githubusercontent.com/u/32725127?v=4?s=100" width="100px;" alt="pabworks"/><br /><sub><b>pabworks</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/xloem"><img src="?s=100" width="100px;" alt="patiently pending world peace"/><br /><sub><b>patiently pending world peace</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xloem" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/raishubham1"><img src="https://avatars3.githubusercontent.com/u/29356417?v=4?s=100" width="100px;" alt="raishubham1"/><br /><sub><b>raishubham1</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=raishubham1" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/simone-pignotti"><img src="https://avatars1.githubusercontent.com/u/44410066?v=4?s=100" width="100px;" alt="simone-pignotti"/><br /><sub><b>simone-pignotti</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=simone-pignotti" title="Code">💻</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Asimone-pignotti" title="Bug reports">🐛</a></td>
@@ -401,9 +402,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/tensorflow-as-tf"><img src="https://avatars.githubusercontent.com/u/51345718?v=4?s=100" width="100px;" alt="tensorflow-as-tf"/><br /><sub><b>tensorflow-as-tf</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tensorflow-as-tf" title="Code">💻</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/vedazeren"><img src="https://avatars3.githubusercontent.com/u/63582874?v=4?s=100" width="100px;" alt="vedazeren"/><br /><sub><b>vedazeren</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vedazeren" title="Code">💻</a> <a href="https://github.com/sktime/sktime/commits?author=vedazeren" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/vincent-nich12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=100" width="100px;" alt="vincent-nich12"/><br /><sub><b>vincent-nich12</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vincent-nich12" title="Code">💻</a></td>
-      <td align="center" valign="top" width="11.11%"><a href="https://github.com/vollmersj"><img src="https://avatars2.githubusercontent.com/u/12613127?v=4?s=100" width="100px;" alt="vollmersj"/><br /><sub><b>vollmersj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vollmersj" title="Documentation">📖</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="11.11%"><a href="https://github.com/vollmersj"><img src="https://avatars2.githubusercontent.com/u/12613127?v=4?s=100" width="100px;" alt="vollmersj"/><br /><sub><b>vollmersj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vollmersj" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="11.11%"><a href="https://github.com/xiaobenbenecho"><img src="https://avatars.githubusercontent.com/u/17461849?v=4?s=100" width="100px;" alt="xiaobenbenecho"/><br /><sub><b>xiaobenbenecho</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xiaobenbenecho" title="Code">💻</a></td>
     </tr>
   </tbody>
diff --git a/docs/source/api_reference/clustering.rst b/docs/source/api_reference/clustering.rst
index df71ad238..19da29bed 100644
--- a/docs/source/api_reference/clustering.rst
+++ b/docs/source/api_reference/clustering.rst
@@ -1,4 +1,3 @@
-
 .. _clustering_ref:
 
 Time series clustering
@@ -65,6 +64,20 @@ Density-based
 
     TimeSeriesDBSCAN
 
+Spatio-temporal clustering
+--------------------------
+
+Spatio-temporal clusterers assume that the time series are, or include,
+observations of locations in space.
+
+.. currentmodule:: sktime.clustering.spatio_temporal
+
+.. autosummary::
+    :toctree: auto_generated/
+    :template: class.rst
+
+    STDBSCAN
+
 Base
 ----
 
diff --git a/docs/source/api_reference/detection.rst b/docs/source/api_reference/detection.rst
index f55ae14f2..5c115a23c 100644
--- a/docs/source/api_reference/detection.rst
+++ b/docs/source/api_reference/detection.rst
@@ -25,6 +25,31 @@ Composition
     DetectorPipeline
     DetectorAsTransformer
 
+Change Point Detection
+----------------------
+
+.. currentmodule:: sktime.detection.skchange_cp
+
+.. autosummary::
+    :toctree: auto_generated/
+    :template: class.rst
+
+    MovingWindow
+    PELT
+    SeededBinarySegmentation
+
+Naive Baselines
+^^^^^^^^^^^^^^^
+
+.. currentmodule:: sktime.detection.dummy
+
+.. autosummary::
+    :toctree: auto_generated/
+    :template: class.rst
+
+    DummyRegularChangepoints
+    ZeroChangepoints
+
 Time Series Segmentation
 ------------------------
 
@@ -127,22 +152,6 @@ Naive Baselines
 
     ZeroSegments
 
-Change Point Detection
-----------------------
-
-Naive Baselines
-^^^^^^^^^^^^^^^
-
-.. currentmodule:: sktime.detection.dummy
-
-.. autosummary::
-    :toctree: auto_generated/
-    :template: class.rst
-
-    DummyRegularChangepoints
-    ZeroChangepoints
-
-
 Time Series Anomaly Detection
 -----------------------------
 
diff --git a/docs/source/api_reference/forecasting.rst b/docs/source/api_reference/forecasting.rst
index 05af3689c..a606ee914 100644
--- a/docs/source/api_reference/forecasting.rst
+++ b/docs/source/api_reference/forecasting.rst
@@ -472,6 +472,14 @@ Deep learning based forecasters
     LTSFNLinearForecaster
     LTSFTransformerForecaster
 
+.. currentmodule:: sktime.forecasting.scinet
+
+.. autosummary::
+    :toctree: auto_generated/
+    :template: class.rst
+
+    SCINetForecaster
+
 .. currentmodule:: sktime.forecasting.conditional_invertible_neural_network
 
 .. autosummary::
diff --git a/sktime/clustering/spatio_temporal/__init__.py b/sktime/clustering/spatio_temporal/__init__.py
new file mode 100644
index 000000000..6520fd2c5
--- /dev/null
+++ b/sktime/clustering/spatio_temporal/__init__.py
@@ -0,0 +1,5 @@
+"""Module for spatio-temporal clustering algorithms."""
+
+from sktime.clustering.spatio_temporal._st_dbscan import STDBSCAN
+
+__all__ = ["STDBSCAN"]
diff --git a/sktime/clustering/spatio_temporal/_st_dbscan.py b/sktime/clustering/spatio_temporal/_st_dbscan.py
new file mode 100644
index 000000000..f75ae7f25
--- /dev/null
+++ b/sktime/clustering/spatio_temporal/_st_dbscan.py
@@ -0,0 +1,366 @@
+"""Spatiotemporal DBSCAN."""
+
+__author__ = ["eren-ck", "vagechirkov"]
+
+import warnings
+
+import numpy as np
+from scipy.sparse import coo_matrix
+from scipy.spatial.distance import pdist, squareform
+from sklearn.cluster import DBSCAN
+from sklearn.neighbors import NearestNeighbors
+
+from sktime.clustering import BaseClusterer
+from sktime.datatypes import update_data
+from sktime.utils.warnings import warn
+
+
+class STDBSCAN(BaseClusterer):
+    """Spatio-temporal DBSCAN clustering.
+
+    Implementation of STDBSCAN by Birant et al [1].
+    Partially based on the implementation of Cakmak et al [3].
+
+    Clusters data based on specified spatial and temporal proximity thresholds.
+
+    Assumes that all variables are spatial coordinates.
+
+    Parameters
+    ----------
+    eps1 : float, default=0.5
+        Maximum spatial distance for points to be considered related.
+    eps2 : float, default=10
+        Maximum temporal distance for points to be considered related [1].
+    min_samples : int, default=5
+        Minimum number of samples to form a core point.
+    metric : str, default='euclidean'
+        Distance metric to use; options include 'euclidean', 'manhattan',
+        'chebyshev', etc.
+    sparse_matrix_threshold : int, default=20_000
+        Sets the limit on the number of samples for which the algorithm can
+        efficiently compute distances with a full matrix approach. Datasets
+        exceeding this threshold will be handled using sparse matrix methods.
+    frame_size : float or None, default=None
+        If not None the dataset is split into frames [2, 3];
+        The frame_size is the number of time points in a frame.
+    frame_overlap : float or None, default=eps2
+        If frame_size is set - there will be an overlap between the frames
+        to merge the clusters afterward [2, 3]; Only used if frame_size is not None.
+    n_jobs : int or None, default=-1
+        Number of parallel jobs for distance computation; -1 uses all cores.
+
+    Attributes
+    ----------
+    labels_ : np.ndarray of shape (n_samples,)
+        Cluster labels for each point; noise is labeled as -1.
+
+    References
+    ----------
+    .. [1] Birant, D., & Kut, A. "ST-DBSCAN: An algorithm for clustering
+       spatial-temporal data." Data Knowl. Eng., vol. 60, no. 1, pp. 208-221, Jan. 2007,
+       doi: [10.1016/j.datak.2006.01.013](https://doi.org/10.1016/j.datak.2006.01.013).
+    .. [2] Peca, I., Fuchs, G., Vrotsou, K., Andrienko, N., and Andrienko, G.,
+       "Scalable Cluster Analysis of Spatial Events" 2012, The Eurographics Association
+       doi: [10.2312/PE/EUROVAST/EUROVA12/019-023](https://doi.org/10.2312/PE/EUROVAST/EUROVA12/019-023).
+    .. [3] Cakmak, E., Plank, M., Calovi, D. S., Jordan, A., & Keim, D. "Spatio-temporal
+       clustering benchmark for collective animal behavior." ACM, Nov. 2021, pp. 5-8.
+       doi: [10.1145/3486637.3489487](https://doi.org/10.1145/3486637.3489487).
+
+    Examples
+    --------
+    >>> from sktime.clustering.spatio_temporal import STDBSCAN
+    >>> from sktime.clustering.utils.toy_data_generation._make_moving_blobs import (
+    ... make_moving_blobs)
+    >>> X, y_true = make_moving_blobs(n_times=20)
+    >>> st_dbscan = STDBSCAN(
+    ...     eps1=0.5, eps2=3, min_samples=5, metric="euclidean", n_jobs=-1
+    ... )
+    >>> st_dbscan.fit(X)
+    >>> predicted_labels = st_dbscan.labels_
+    """
+
+    _tags = {
+        "maintainers": "vagechirkov",
+        "authors": ["eren-ck", "vagechirkov"],
+        "python_dependencies": ["scipy", "scikit-learn"],
+        "X_inner_mtype": "pd-multiindex",
+        "capability:multivariate": True,
+        "capability:unequal_length": False,
+        "capability:missing_values": False,
+        "capability:multithreading": True,
+        "capability:predict": True,
+        "capability:predict_proba": False,
+        "capability:out_of_sample": True,
+    }
+
+    DELEGATED_FITTED_PARAMS = ["core_sample_indices_", "components_ ", "labels_"]
+
+    def __init__(
+        self,
+        eps1=0.5,
+        eps2=10,
+        min_samples=5,
+        metric="euclidean",
+        sparse_matrix_threshold=20_000,
+        frame_size=None,
+        frame_overlap=None,
+        n_jobs=-1,
+    ):
+        self.eps1 = eps1
+        self.eps2 = eps2
+        self.min_samples = min_samples
+        self.metric = metric
+        self.sparse_matrix_threshold = sparse_matrix_threshold
+        self.frame_size = frame_size
+        self.frame_overlap = frame_overlap
+        self.n_jobs = n_jobs
+        self.dbscan_ = None
+
+        super().__init__()
+
+    def _fit(self, X, y=None):
+        """
+        Apply the ST-DBSCAN algorithm to cluster spatiotemporal data.
+
+        Parameters
+        ----------
+        X : sktime compatible Panel data container, mtype="pd-multiindex".
+            The first index level is time, the second is object (agent) ID.
+            Each row represents spatial coordinates of an object at a given time.
+            Example of X:
+                index object | index time | coordinates x | coordinates y
+                -------------|------------|---------------|---------------
+                0            | 0          | 0.1           | 0.2
+                1            | 0          | 0.3           | 0.4
+                0            | 1          | 0.2           | 0.3
+                1            | 1          | 0.4           | 0.5
+                2            | 1          | 0.5           | 0.6
+                0            | 2          | 0.3           | 0.4
+                3            | 2          | 0.6           | 0.7
+        y : ignored, exists for API consistency reasons
+
+        Returns
+        -------
+        self :
+            Fitted instance with cluster labels.
+        """
+        if not self.eps1 > 0.0 or not self.eps2 > 0.0 or not self.min_samples > 0.0:
+            raise ValueError("eps1, eps2, min_samples  must be positive")
+
+        # make sure that X is sorted by time
+        X = X.copy()
+        X.sort_index(inplace=True, ascending=True, level=1)
+
+        self._X = X
+
+        if self.frame_size is not None:
+            if self.frame_overlap is None:
+                self.frame_overlap = self.eps2
+            if (
+                not self.frame_size > 0.0
+                or not self.frame_overlap > 0.0
+                or self.frame_size < self.frame_overlap
+            ):
+                raise ValueError("frame_size, frame_overlap not correctly configured.")
+            return self._fit_frame_split(X)
+        else:
+            self._fit_one_frame(X)
+            for key in self.DELEGATED_FITTED_PARAMS:
+                if hasattr(self.dbscan_, key):
+                    setattr(self, key, getattr(self.dbscan_, key))
+
+        return self
+
+    def _fit_one_frame(self, X):
+        if len(X) < self.sparse_matrix_threshold:
+            self._fit_dense(X)
+        else:
+            self._fit_sparse(X)
+
+    def _fit_dense(self, X):
+        """Fit the dense distance matrix version of the ST-DBSCAN algorithm."""
+        n, m = X.values.shape
+        time_index = X.index.get_level_values(1).to_numpy()
+
+        # Compute squared form Distance Matrix
+        time_dist = pdist(time_index.reshape(n, 1), metric=self.metric)
+        spatial_dist = pdist(X.values, metric=self.metric)
+
+        # filter the spatial_dist matrix using the time_dist
+        dist = np.where(time_dist <= self.eps2, spatial_dist, 2 * self.eps1)
+
+        self.dbscan_ = DBSCAN(
+            eps=self.eps1, min_samples=self.min_samples, metric="precomputed"
+        )
+        self.dbscan_.fit(squareform(dist))
+
+    def _fit_sparse(self, X):
+        """Fit the sparse distance matrix version of the ST-DBSCAN algorithm."""
+        n, m = X.values.shape
+        time_index = X.index.get_level_values(1).to_numpy()
+
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore")
+
+            # compute with sparse matrices
+            # Compute sparse matrix for spatial distance
+            nn_spatial = NearestNeighbors(
+                metric=self.metric, radius=self.eps1, n_jobs=self.n_jobs
+            )
+            nn_spatial.fit(X.values)
+            euc_sp = nn_spatial.radius_neighbors_graph(X.values, mode="distance")
+
+            # Compute sparse matrix for temporal distance
+            nn_time = NearestNeighbors(
+                metric=self.metric, radius=self.eps2, n_jobs=self.n_jobs
+            )
+            nn_time.fit(time_index.reshape(n, 1))
+            time_sp = nn_time.radius_neighbors_graph(
+                time_index.reshape(n, 1), mode="distance"
+            )
+
+            # combine both sparse matrices and filter by time distance matrix
+            row = time_sp.nonzero()[0]
+            column = time_sp.nonzero()[1]
+            v = np.array(euc_sp[row, column])[0]
+
+            # create sparse distance matrix
+            dist_sp = coo_matrix((v, (row, column)), shape=(n, n))
+            dist_sp = dist_sp.tocsc()
+            dist_sp.eliminate_zeros()
+
+            self.dbscan_ = DBSCAN(
+                eps=self.eps1, min_samples=self.min_samples, metric="precomputed"
+            )
+            self.dbscan_.fit(dist_sp)
+
+    def _fit_frame_split(self, X):
+        """Apply the ST-DBSCAN algorithm with splitting it into frames.
+
+        References
+        ----------
+        .. [1] I. Peca, G. Fuchs, K. Vrotsou, N. Andrienko, and G. Andrienko, “Scalable
+           Cluster Analysis of Spatial Events,” 2012, The Eurographics Association. doi:
+           [10.2312/PE/EUROVAST/EUROVA12/019-023](https://doi.org/10.2312/PE/EUROVAST/EUROVA12/019-023).
+        """
+        # unique time points
+        time_index = X.index.get_level_values(1).to_numpy()
+        time = np.unique(time_index)
+        labels = None
+        right_overlap = 0
+        step = int(self.frame_size - self.frame_overlap + 1)
+
+        for i in range(0, len(time), step):
+            for period in [time[i : i + self.frame_size]]:
+                frame = X[np.isin(time_index, period)]
+
+                self._fit_one_frame(frame)
+
+                # Match the labels in the overlapped zone.
+                # Objects in the second frame are relabeled
+                # to match the cluster ID from the first frame.
+                if labels is None:
+                    labels = self.dbscan_.labels_
+                else:
+                    frame_1_overlap_labels = labels[len(labels) - right_overlap :]
+                    frame_2_overlap_labels = self.dbscan_.labels_[0:right_overlap]
+
+                    mapper = {}
+                    for i1, i2 in zip(frame_1_overlap_labels, frame_2_overlap_labels):
+                        mapper[i2] = i1
+                    mapper[-1] = -1  # avoiding outliers being mapped to cluster
+
+                    # clusters without overlapping points are given new cluster
+                    ignore_clusters = set(self.dbscan_.labels_) - set(
+                        frame_2_overlap_labels
+                    )
+                    # recode them to new cluster value
+                    if -1 in labels:
+                        labels_counter = len(set(labels)) - 1
+                    else:
+                        labels_counter = len(set(labels))
+
+                    for j in ignore_clusters:
+                        mapper[j] = labels_counter
+                        labels_counter += 1
+
+                    # Relabel objects in the second frame to match the cluster ID from
+                    # the first frame.
+                    # Assign new clusters to objects in clusters without overlap
+                    new_labels = np.array([mapper[j] for j in self.dbscan_.labels_])
+
+                    # delete the right overlap
+                    labels = labels[0 : len(labels) - right_overlap]
+                    # change the labels of the new clustering and concat
+                    labels = np.concatenate((labels, new_labels))
+
+                right_overlap = len(
+                    X.values[np.isin(time_index, period[-self.frame_overlap + 1 :])]
+                )
+        self.labels_ = labels
+
+    def _predict(self, X, y=None):
+        """Predict the closest cluster each sample in X belongs to.
+
+        Parameters
+        ----------
+        X : panel of time series, any sklearn Panel mtype
+            Time series instances to predict cluster indexes for
+        y: ignored, exists for API consistency reasons
+
+        Returns
+        -------
+        np.ndarray (1d array of shape (n_instances,))
+            Index of the cluster each time series in X belongs to
+        """
+        # if X is the same as seen in _fit, simply return the labels
+        if X is self._X:
+            return self.labels_
+        else:
+            all_X = update_data(X=self._X, X_new=X)
+            warn(
+                "sklearn and sktime DBSCAN estimators do not support different X "
+                "in fit and predict, but a new X was passed in predict. "
+                "Therefore, a clone of STDBSCAN will be fit, and results "
+                "returned, without updating the state of the fitted estimator.",
+                obj=self,
+            )
+            return self.clone().fit(all_X).labels_
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return `"default"` set.
+            There are currently no reserved values for clusterers.
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance.
+            `create_test_instance` uses the first (or only) dictionary in `params`
+        """
+        param1 = {}
+
+        param2 = {
+            "eps1": 0.3,
+            "eps2": 5,
+            "min_samples": 3,
+            "metric": "euclidean",
+            "n_jobs": 1,
+        }
+        param3 = {
+            "eps1": 0.5,
+            "eps2": 10,
+            "min_samples": 2,
+            "metric": "manhattan",
+            "n_jobs": 2,
+        }
+
+        return [param1, param2, param3]
diff --git a/sktime/clustering/utils/toy_data_generation/__init__.py b/sktime/clustering/utils/toy_data_generation/__init__.py
new file mode 100644
index 000000000..4e2c1db28
--- /dev/null
+++ b/sktime/clustering/utils/toy_data_generation/__init__.py
@@ -0,0 +1,1 @@
+"""Generate toy spatio-temporal data."""
diff --git a/sktime/clustering/utils/toy_data_generation/_make_moving_blobs.py b/sktime/clustering/utils/toy_data_generation/_make_moving_blobs.py
new file mode 100644
index 000000000..ecd738c3b
--- /dev/null
+++ b/sktime/clustering/utils/toy_data_generation/_make_moving_blobs.py
@@ -0,0 +1,70 @@
+import numpy as np
+import pandas as pd
+from sklearn.datasets import make_blobs
+
+__author__ = ["vagechirkov"]
+__all__ = ["make_moving_blobs"]
+
+
+def make_moving_blobs(
+    n_times=3,
+    n_samples=15,
+    cluster_std=0.10,
+    random_state=10,
+    centers_origin=np.array([[-1, -1], [0, 0], [1, 1]]),
+    movement_mode="constant",
+    movement_speed=0.1,
+):
+    """Generate spatio-temporal data."""
+    centers = np.array(centers_origin, dtype=float)
+    n_orig_clusters = centers.shape[0]
+    centers_ = centers.copy()
+    center_time_map = {i: 0 for i in range(n_orig_clusters)}
+    center_cluster_map = {i: i for i in range(n_orig_clusters)}
+    cluster_id = n_orig_clusters
+    for t in range(n_times - 1):
+        if movement_mode == "constant":
+            centers_ += movement_speed
+        elif movement_mode == "random":
+            # Brownian motion is not interesting for clustering
+            # TODO: replace with a levy walk
+            centers_ += np.random.uniform(
+                -movement_speed, movement_speed, centers_.shape
+            )
+        else:
+            raise ValueError(f"Unknown movement mode: {movement_mode}")
+        centers = np.vstack((centers, centers_))
+
+        for i in range(n_orig_clusters):
+            center_time_map[cluster_id] = t + 1
+            center_cluster_map[cluster_id] = i
+            cluster_id += 1
+
+    X, y_true_ = make_blobs(
+        n_samples=n_samples * n_times * n_orig_clusters,
+        centers=centers,
+        cluster_std=cluster_std,
+        random_state=random_state,
+    )
+
+    # use center_cluster_map to get true labels
+    y_true = np.array([center_cluster_map[i] for i in y_true_])
+    time = np.array([center_time_map[i] for i in y_true_])
+    X = np.column_stack([time, X])
+
+    # sort by time
+    sort_idx = np.argsort(time)
+    y_true = y_true[sort_idx]
+    X = X[sort_idx]
+
+    X = pd.DataFrame(
+        X,
+        index=pd.MultiIndex.from_arrays(
+            [np.int32(np.arange(X.shape[0])), np.int32(X[:, 0])],
+            names=["object_id", "time"],
+        ),
+        columns=["time", "x", "y"],
+    )
+    X.drop(columns=["time"], inplace=True)
+
+    return X, y_true
diff --git a/sktime/detection/base/_base.py b/sktime/detection/base/_base.py
index 4c75c1694..7ed2cc475 100644
--- a/sktime/detection/base/_base.py
+++ b/sktime/detection/base/_base.py
@@ -215,6 +215,7 @@ class BaseDetector(BaseEstimator):
         y : pd.Series with RangeIndex
             Labels for sequence ``X``, in sparse format.
             Values are ``iloc`` references to indices of ``X``.
+            The index is always a ``RangeIndex``.
 
             * If ``task`` is ``"anomaly_detection"`` or ``"change_point_detection"``,
               the values are integer indices of the changepoints/anomalies.
diff --git a/sktime/detection/compose/_pipeline.py b/sktime/detection/compose/_pipeline.py
index 1a0d66bb2..a633a1c6a 100644
--- a/sktime/detection/compose/_pipeline.py
+++ b/sktime/detection/compose/_pipeline.py
@@ -369,7 +369,7 @@ class DetectorPipeline(_HeterogenousMetaEstimator, BaseDetector):
 
         from sklearn.preprocessing import StandardScaler
 
-        from sktime.annotation.lof import SubLOF
+        from sktime.detection.lof import SubLOF
         from sktime.transformations.series.adapt import TabularToSeriesAdaptor
         from sktime.transformations.series.detrend import Detrender
         from sktime.transformations.series.exponent import ExponentTransformer
diff --git a/sktime/detection/lof.py b/sktime/detection/lof.py
index 3b3acef56..92bca1898 100644
--- a/sktime/detection/lof.py
+++ b/sktime/detection/lof.py
@@ -5,6 +5,7 @@ __author__ = ["Alex-JG3"]
 import datetime
 import math
 
+import numpy as np
 import pandas as pd
 from sklearn.neighbors import LocalOutlierFactor
 
@@ -92,8 +93,6 @@ class SubLOF(BaseDetector):
         on new unseen data and not on the training set; and note that the
         results obtained this way may differ from the standard LOF results.
 
-        .. versionadded:: 0.20
-
     n_jobs : int, default=None
         The number of parallel jobs to run for neighbors search.
         ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context.
@@ -193,9 +192,15 @@ class SubLOF(BaseDetector):
     @staticmethod
     def _split_into_intervals(x, interval_size):
         """Split the range of ``x`` into equally sized intervals."""
+        from sktime.utils.validation.series import is_integer_index
+
         x_max = x.max()
         x_min = x.min()
-        n_intervals = math.floor((x_max - x_min) / interval_size) + 1
+        x_span = x_max - x_min
+
+        if isinstance(interval_size, int) and not is_integer_index(x):
+            interval_size = x.freq * interval_size
+        n_intervals = math.floor(x_span / interval_size) + 1
 
         if x_max >= x_min + (n_intervals - 1) * interval_size:
             n_intervals += 1
@@ -214,11 +219,12 @@ class SubLOF(BaseDetector):
 
         Returns
         -------
-        Y : pd.Series or an IntervalSeries
+        y_pred : pd.Series or an IntervalSeries
             Change points in sequence X.
         """
         if isinstance(X, pd.Series):
             X = X.to_frame()
+        X["__id"] = pd.RangeIndex(len(X))
 
         y_all = []
         for interval, model in self.models.items():
@@ -227,67 +233,15 @@ class SubLOF(BaseDetector):
             if len(X_subset) == 0:
                 continue
 
-            y_subset = model.predict(X_subset)
-            anomaly_indexes = X_subset.index[y_subset == -1]
+            y_subset = model.predict(X_subset.iloc[:, [0]])
+            anomaly_indexes = np.where(y_subset == -1)[0] + X_subset["__id"].iloc[0]
             y_all.append(pd.Series(anomaly_indexes))
 
         if len(y_all) == 0:
-            return pd.Series()
+            return self._empty_sparse()
 
-        return pd.concat(y_all, ignore_index=True).reset_index(drop=True)
-
-    def fit_predict(self, X, Y=None):
-        """Fit to data, then predict it.
-
-        Fits model to X and Y with given annotation parameters
-        and returns the annotations made by the model.
-
-        Parameters
-        ----------
-        X : pd.DataFrame or pd.Series
-            Data to be transformed
-        Y : pd.Series or np.ndarray, optional (default=None)
-            Unused, defaults to none.
-
-        Returns
-        -------
-        self : pd.Series
-            Series containing the locations of the anomalies in X.
-        """
-        model_params = {
-            "n_neighbors": self.n_neighbors,
-            "algorithm": self.algorithm,
-            "leaf_size": self.leaf_size,
-            "metric": self.metric,
-            "p": self.p,
-            "metric_params": self.metric_params,
-            "contamination": self.contamination,
-            "novelty": self.novelty,
-            "n_jobs": self.n_jobs,
-        }
-        if isinstance(X, pd.Series):
-            X = X.to_frame()
-
-        intervals = self._split_into_intervals(X.index, self.window_size)
-        self.models = {
-            interval: LocalOutlierFactor(**model_params) for interval in intervals
-        }
-
-        y_all = []
-        for interval, model in self.models.items():
-            X_subset = X.loc[(X.index >= interval.left) & (X.index < interval.right)]
-
-            if len(X_subset) == 0:
-                continue
-
-            y_subset = model.fit_predict(X_subset)
-            anomaly_indexes = X_subset.index[y_subset == -1].tolist()
-            y_all += anomaly_indexes
-
-        if len(y_all) == 0:
-            return pd.Series()
-
-        return pd.Series(y_all)
+        y_pred = pd.concat(y_all, ignore_index=True).reset_index(drop=True)
+        return y_pred
 
     @classmethod
     def get_test_params(cls, parameter_set="default"):
@@ -303,9 +257,18 @@ class SubLOF(BaseDetector):
         -------
         params : dict or list of dict
         """
-        params = {
+        params0 = {
             "n_neighbors": 5,
             "window_size": datetime.timedelta(days=25),
             "novelty": True,
         }
-        return params
+        params1 = {
+            "n_neighbors": 3,
+            "window_size": 3,
+            "algorithm": "brute",
+            "leaf_size": 10,
+            "metric": "minkowski",
+            "novelty": True,
+            "p": 3,
+        }
+        return [params0, params1]
diff --git a/sktime/detection/skchange_cp/__init__.py b/sktime/detection/skchange_cp/__init__.py
new file mode 100644
index 000000000..ae70d3a88
--- /dev/null
+++ b/sktime/detection/skchange_cp/__init__.py
@@ -0,0 +1,11 @@
+"""Placeholders for skchange change point detectors."""
+
+from sktime.detection.skchange_cp.moving_window import MovingWindow
+from sktime.detection.skchange_cp.pelt import PELT
+from sktime.detection.skchange_cp.seeded_binseg import SeededBinarySegmentation
+
+__all__ = [
+    "MovingWindow",
+    "PELT",
+    "SeededBinarySegmentation",
+]
diff --git a/sktime/detection/skchange_cp/moving_window.py b/sktime/detection/skchange_cp/moving_window.py
new file mode 100644
index 000000000..40473e9ac
--- /dev/null
+++ b/sktime/detection/skchange_cp/moving_window.py
@@ -0,0 +1,91 @@
+"""The Moving Window algorithm for multiple changepoint detection."""
+
+from sktime.detection.base import BaseDetector
+from sktime.utils.dependencies import _placeholder_record
+
+
+@_placeholder_record("skchange.change_detectors.moving_window")
+class MovingWindow(BaseDetector):
+    """Moving window algorithm for multiple changepoint detection, from skchange.
+
+    Redirects to ``skchange.change_detectors.moving_window``.
+
+    A generalized version of the MOSUM (moving sum) algorithm [1]_ for changepoint
+    detection. It runs a test statistic for a single changepoint at the midpoint in a
+    moving window of length ``2 * bandwidth`` over the data. Efficiently implemented
+    using numba.
+
+    Parameters
+    ----------
+    change_score : BaseChangeScore or BaseCost, optional (default=``L2Cost``)
+        The change score to use in the algorithm. If a cost function is given, it is
+        converted to a change score using the ``ChangeScore`` class.
+    bandwidth : int, default=30
+        The bandwidth is the number of samples on either side of a candidate
+        changepoint. The minimum bandwidth depends on the
+        test statistic. For ``"mean"``, the minimum bandwidth is 1.
+    threshold_scale : float, default=2.0
+        Scaling factor for the threshold. The threshold is set to
+        ``threshold_scale * default_threshold``, where the default threshold depends on
+        the number of samples, the number of variables, ``bandwidth`` and ``level``.
+        If None, the threshold is tuned on the input data to ``fit``.
+    level : float, default=0.01
+        If ``threshold_scale`` is ``None``, the threshold is set to the
+        (1-``level``)-quantile of the changepoint score on the training data. For this
+        to be correct, the training data must contain no changepoints. If
+        ``threshold_scale`` is a number, ``level`` is used in the default threshold,
+        _before_ scaling.
+    min_detection_interval : int, default=1
+        Minimum number of consecutive scores above the threshold to be considered a
+        changepoint. Must be between 1 and ``bandwidth/2``.
+
+    References
+    ----------
+    .. [1] Eichinger, B., & Kirch, C. (2018). A MOSUM procedure for the estimation of
+    multiple random change points.
+
+    Examples
+    --------
+    >>> from skchange.change_detectors import MovingWindow
+    >>> from skchange.datasets.generate import generate_alternating_data
+    >>> df = generate_alternating_data(
+            n_segments=4, mean=10, segment_length=100, p=5
+        )
+    >>> detector = MovingWindow()
+    >>> detector.fit_predict(df)
+    0    100
+    1    200
+    2    300
+    Name: changepoint, dtype: int64
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": ["Tveten"],
+        "maintainers": ["Tveten"],
+        "python_dependencies": "skchange>=0.6.0",
+        # estimator type
+        # --------------
+        "task": "change_point_detection",
+        "learning_type": "unsupervised",
+        "capability:missing_values": False,
+        "capability:multivariate": True,
+        "fit_is_empty": False,
+    }
+
+    def __init__(
+        self,
+        change_score=None,
+        bandwidth: int = 30,
+        threshold_scale=2.0,
+        level: float = 0.01,
+        min_detection_interval: int = 1,
+    ):
+        self.change_score = change_score
+        self.bandwidth = bandwidth
+        self.threshold_scale = threshold_scale
+        self.level = level
+        self.min_detection_interval = min_detection_interval
+
+        super().__init__()
diff --git a/sktime/detection/skchange_cp/pelt.py b/sktime/detection/skchange_cp/pelt.py
new file mode 100644
index 000000000..e1ac83f42
--- /dev/null
+++ b/sktime/detection/skchange_cp/pelt.py
@@ -0,0 +1,69 @@
+"""The pruned exact linear time (PELT) algorithm."""
+
+from sktime.detection.base import BaseDetector
+from sktime.utils.dependencies import _placeholder_record
+
+
+@_placeholder_record("skchange.change_detectors.pelt")
+class PELT(BaseDetector):
+    """Pruned exact linear time changepoint detection, from skchange.
+
+    Redirects to ``skchange.change_detectors.pelt``.
+
+    An efficient implementation of the PELT algorithm [1]_ for changepoint detection.
+
+    Parameters
+    ----------
+    cost : BaseCost, optional (default=``L2Cost``)
+        The cost function to use for the changepoint detection.
+    penalty_scale : float, optional (default=2.0)
+        Scaling factor for the penalty. The penalty is set to
+        ``penalty_scale * 2 * p * np.log(n)``, where ``n`` is the sample size
+        and ``p`` is the number of variables. If None, the penalty is tuned on the data
+        input to ``fit``.
+    min_segment_length : int, optional (default=2)
+        Minimum length of a segment.
+
+    References
+    ----------
+    .. [1] Killick, R., Fearnhead, P., & Eckley, I. A. (2012). Optimal detection of
+    changepoints with a linear computational cost. Journal of the American Statistical
+    Association, 107(500), 1590-1598.
+
+    Examples
+    --------
+    >>> from skchange.change_detectors import PELT
+    >>> from skchange.datasets.generate import generate_alternating_data
+    >>> df = generate_alternating_data(n_segments=2, mean=10, segment_length=100, p=5)
+    >>> detector = PELT()
+    >>> detector.fit_predict(df)
+    0    100
+    Name: changepoint, dtype: int64
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": ["Tveten", "johannvk"],
+        "maintainers": ["Tveten", "johannvk"],
+        "python_dependencies": "skchange>=0.6.0",
+        # estimator type
+        # --------------
+        "task": "change_point_detection",
+        "learning_type": "unsupervised",
+        "capability:missing_values": False,
+        "capability:multivariate": True,
+        "fit_is_empty": False,
+    }
+
+    def __init__(
+        self,
+        cost=None,
+        penalty_scale=2.0,
+        min_segment_length=2,
+    ):
+        self.cost = cost
+        self.penalty_scale = penalty_scale
+        self.min_segment_length = min_segment_length
+
+        super().__init__()
diff --git a/sktime/detection/skchange_cp/seeded_binseg.py b/sktime/detection/skchange_cp/seeded_binseg.py
new file mode 100644
index 000000000..9b1e9f971
--- /dev/null
+++ b/sktime/detection/skchange_cp/seeded_binseg.py
@@ -0,0 +1,101 @@
+"""Seeded binary segmentation algorithm for multiple changepoint detection."""
+
+from sktime.detection.base import BaseDetector
+from sktime.utils.dependencies import _placeholder_record
+
+
+@_placeholder_record("skchange.change_detectors.seeded_binseg")
+class SeededBinarySegmentation(BaseDetector):
+    """Seeded binary segmentation algorithm for changepoint detection, from skchange.
+
+    Redirects to ``skchange.change_detectors.seeded_binseg``.
+
+    Binary segmentation type changepoint detection algorithms recursively split the data
+    into two segments, and test whether the two segments are different. The seeded
+    binary segmentation algorithm is an efficient version of such algorithms, which
+    tests for changepoints in intervals of exponentially growing length. It has the same
+    theoretical guarantees as the original binary segmentation algorithm, but runs
+    in log-linear time no matter the changepoint configuration.
+
+    Efficiently implemented using numba.
+
+    Parameters
+    ----------
+    change_score : BaseChangeScore or BaseCost, default=L2Cost()
+        The change score to use in the algorithm. If a cost function is given, it is
+        converted to a change score using the ``ChangeScore`` class.
+    threshold_scale : float, default=2.0
+        Scaling factor for the threshold. The threshold is set to
+        ``threshold_scale * 2 * p * np.sqrt(np.log(n))``, where ``n`` is the sample size
+        and ``p`` is the number of variables. If None, the threshold is tuned on the
+        data input to ``fit``.
+    level : float, default=0.01
+        If ``threshold_scale`` is None, the threshold is set to the
+        (1-`level`)-quantile of the changepoint scores of all the seeded intervals on
+        the training data. For this to be correct, the training data must contain no
+        changepoints.
+    min_segment_length : int, default=5
+        Minimum length between two changepoints. Must be greater than or equal to 1.
+    max_interval_length : int, default=200
+        The maximum length of an interval to estimate a changepoint in. Must be greater
+        than or equal to ``2 * min_segment_length``.
+    growth_factor : float, default=1.5
+        The growth factor for the seeded intervals. Intervals grow in size according to
+        ``interval_len=max(interval_len + 1, np.floor(growth_factor * interval_len))``,
+        starting at ``interval_len=min_interval_length``. It also governs the amount
+        of overlap between intervals of the same length, as the start of each interval
+        is shifted by a factor of ``1 + 1 / growth_factor``. Must be a float in (1, 2].
+
+    References
+    ----------
+    .. [1] Kovács, S., Bühlmann, P., Li, H., & Munk, A. (2023). Seeded binary
+    segmentation: a general methodology for fast and optimal changepoint detection.
+    Biometrika, 110(1), 249-256.
+
+    Examples
+    --------
+    >>> from skchange.change_detectors import SeededBinarySegmentation
+    >>> from skchange.datasets.generate import generate_alternating_data
+    >>> df = generate_alternating_data(
+            n_segments=4, mean=10, segment_length=100, p=5
+        )
+    >>> detector = SeededBinarySegmentation()
+    >>> detector.fit_predict(df)
+    0    100
+    1    200
+    2    300
+    Name: changepoint, dtype: int64
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": ["Tveten"],
+        "maintainers": ["Tveten"],
+        "python_dependencies": "skchange>=0.6.0",
+        # estimator type
+        # --------------
+        "task": "change_point_detection",
+        "learning_type": "unsupervised",
+        "capability:missing_values": False,
+        "capability:multivariate": True,
+        "fit_is_empty": False,
+    }
+
+    def __init__(
+        self,
+        change_score=None,
+        threshold_scale=2.0,
+        level: float = 1e-8,
+        min_segment_length: int = 5,
+        max_interval_length: int = 200,
+        growth_factor: float = 1.5,
+    ):
+        self.change_score = change_score
+        self.threshold_scale = threshold_scale  # Just holds the input value.
+        self.level = level
+        self.min_segment_length = min_segment_length
+        self.max_interval_length = max_interval_length
+        self.growth_factor = growth_factor
+
+        super().__init__()
diff --git a/sktime/forecasting/neuralforecast.py b/sktime/forecasting/neuralforecast.py
index 0acf9ae41..6e5deb3f9 100644
--- a/sktime/forecasting/neuralforecast.py
+++ b/sktime/forecasting/neuralforecast.py
@@ -804,7 +804,1214 @@ class NeuralForecastLSTM(_NeuralForecastAdapter):
         return params_broadcasting + params_no_broadcasting
 
 
+class NeuralForecastGRU(_NeuralForecastAdapter):
+    """NeuralForecast GRU model.
+
+    Interface to ``neuralforecast.models.GRU`` [1]_
+    through ``neuralforecast.NeuralForecast`` [2]_,
+    from ``neuralforecast`` [3]_ by Nixtla.
+
+    Multi Layer Recurrent Network with Gated Units (GRU), and
+    MLP decoder. The network has non-linear activation functions, it is trained
+    using ADAM stochastic gradient descent. The network accepts static, historic
+    and future exogenous data, flattens the inputs.
+
+    Parameters
+    ----------
+    freq : Union[str, int] (default="auto")
+        frequency of the data, see available frequencies [4]_ from ``pandas``
+        use int freq when using RangeIndex in ``y``
+
+        default ("auto") interprets freq from ForecastingHorizon in ``fit``
+    local_scaler_type : str (default=None)
+        scaler to apply per-series to all features before fitting, which is inverted
+        after predicting
+
+        can be one of the following:
+
+        - 'standard'
+        - 'robust'
+        - 'robust-iqr'
+        - 'minmax'
+        - 'boxcox'
+    futr_exog_list : str list, (default=None)
+        future exogenous variables
+    verbose_fit : bool (default=False)
+        print processing steps during fit
+    verbose_predict : bool (default=False)
+        print processing steps during predict
+    input_size : int (default=-1)
+        maximum sequence length for truncated train backpropagation
+
+        default (-1) uses all history
+    inference_input_size : int (default=-1)
+        maximum sequence length for truncated inference
+
+        default (-1) uses all history
+    encoder_n_layers : int (default=2)
+        number of layers for the GRU
+    encoder_hidden_size : int (default=200)
+        units for the GRU's hidden state size
+    encoder_bias : bool (default=True)
+        whether or not to use biases b_ih, b_hh within GRU units
+    encoder_dropout : float (default=0.0)
+        dropout regularization applied to GRU outputs
+    context_size : int (default=10)
+        size of context vector for each timestamp on the forecasting window
+    decoder_hidden_size : int (default=200)
+        size of hidden layer for the MLP decoder
+    decoder_layers : int (default=2)
+        number of layers for the MLP decoder
+    loss : pytorch module (default=None)
+        instantiated train loss class from losses collection [5]_
+    valid_loss : pytorch module (default=None)
+        instantiated validation loss class from losses collection [5]_
+    max_steps : int (default=1000)
+        maximum number of training steps
+    learning_rate : float (default=1e-3)
+        learning rate between (0, 1)
+    num_lr_decays : int (default=-1)
+        number of learning rate decays, evenly distributed across max_steps
+    early_stop_patience_steps : int (default=-1)
+        number of validation iterations before early stopping
+    val_check_steps : int (default=100)
+        number of training steps between every validation loss check
+    batch_size : int (default=32)
+        number of different series in each batch
+    valid_batch_size : Optional[int] (default=None)
+        number of different series in each validation and test batch
+    scaler_type : str (default="robust")
+        type of scaler for temporal inputs normalization
+    random_seed : int (default=1)
+        random_seed for pytorch initializer and numpy generators
+    num_workers_loader : int (default=0)
+        workers to be used by ``TimeSeriesDataLoader``
+    drop_last_loader : bool (default=False)
+        whether ``TimeSeriesDataLoader`` drops last non-full batch
+    optimizer : pytorch optimizer (default=None) [7]_
+        optimizer to use for training, if passed with None defaults to ``Adam``
+    optimizer_kwargs : dict (default=None) [8]_
+        dict of parameters to pass to the user defined optimizer
+    lr_scheduler : pytorch learning rate scheduler (default=None) [9]_
+        user specified lr_scheduler instead of the default choice ``StepLR`` [10]_
+    lr_scheduler_kwargs : dict (default=None)
+        list of parameters used by the user specified ``lr_scheduler``
+    trainer_kwargs : dict (default=None)
+        keyword trainer arguments inherited from PyTorch Lighning's trainer [6]_
+    broadcasting : bool (default=False)
+        multiindex data input will be broadcasted to single series, and for each single series,
+        one copy of this forecaster will try to fit and predict on it. The broadcasting is
+        happening inside automatically, from the outerside api perspective, the input and
+        output are the same, only one multiindex output from `predict`.
+
+    Notes
+    -----
+    * If ``loss`` is unspecified, MAE is used as the loss function for training.
+    * Only ``futr_exog_list`` will be considered as exogenous variables.
+
+    Examples
+    --------
+    >>>
+    >>> # importing necessary libraries
+    >>> from sktime.datasets import load_longley
+    >>> from sktime.forecasting.neuralforecast import NeuralForecastGRU
+    >>> from sktime.split import temporal_train_test_split
+    >>>
+    >>> # loading the Longley dataset and splitting it into train and test subsets
+    >>> y, X = load_longley()
+    >>> y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=4)
+    >>>
+    >>> # creating model instance configuring the hyperparameters
+    >>> model = NeuralForecastGRU(  # doctest: +SKIP
+    ...     "A-DEC", futr_exog_list=["ARMED", "POP"], max_steps=5
+    ... )
+    >>>
+    >>> # fitting the model
+    >>> model.fit(y_train, X=X_train, fh=[1, 2, 3, 4])  # doctest: +SKIP
+    Seed set to 1
+    Epoch 4: 100%|████████████████████████████| 1/1 [00:00<00:00, 20.71it/s, v_num=0, train_loss_step=0.745, train_loss_epoch=0.745]
+    NeuralForecastGRU(freq='A-DEC', futr_exog_list=['ARMED', 'POP'], max_steps=5)
+    >>>
+    >>> # getting point predictions
+    >>> model.predict(X=X_test)  # doctest: +SKIP
+    Predicting DataLoader 0: 100%|██████████████████████████████████| 1/1 [00:00<00:00,
+    198.64it/s]
+    1959    64516.003906
+    1960    63966.054688
+    1961    64432.593750
+    1962    64210.609375
+    Freq: A-DEC, Name: TOTEMP, dtype: float64
+    >>>
+
+    References
+    ----------
+    .. [1] https://nixtlaverse.nixtla.io/neuralforecast/models.gru.html#gru
+    .. [2] https://nixtlaverse.nixtla.io/neuralforecast/core.html#neuralforecast
+    .. [3] https://github.com/Nixtla/neuralforecast/
+    .. [4]
+    https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases
+    .. [5] https://nixtlaverse.nixtla.io/neuralforecast/losses.pytorch.html
+    .. [6]
+    https://lightning.ai/docs/pytorch/stable/api/pytorch_lightning.trainer.trainer.Trainer.html#lightning.pytorch.trainer.trainer.Trainer
+    .. [7] https://pytorch.org/docs/stable/optim.html
+    .. [8] https://pytorch.org/docs/stable/optim.html#algorithms
+    .. [9] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.LRScheduler.html
+    .. [10] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.StepLR.html
+    """  # noqa: E501
+
+    _tags = {
+        # packaging info
+        # --------------
+        # "authors": ["yarnabrina"],
+        # "maintainers": ["yarnabrina"],
+        # "python_dependencies": "neuralforecast"
+        # inherited from _NeuralForecastAdapter
+        # estimator type
+        # --------------
+        "python_dependencies": ["neuralforecast>=1.6.4"],
+        "capability:global_forecasting": True,
+    }
+
+    def __init__(
+        self: "NeuralForecastGRU",
+        freq: Union[str, int] = "auto",
+        local_scaler_type: Optional[_SUPPORTED_LOCAL_SCALAR_TYPES] = None,
+        futr_exog_list: Optional[list[str]] = None,
+        verbose_fit: bool = False,
+        verbose_predict: bool = False,
+        input_size: int = -1,
+        inference_input_size: int = -1,
+        encoder_n_layers: int = 2,
+        encoder_hidden_size: int = 200,
+        encoder_bias: bool = True,
+        encoder_dropout: float = 0.0,
+        context_size: int = 10,
+        decoder_hidden_size: int = 200,
+        decoder_layers: int = 2,
+        loss=None,
+        valid_loss=None,
+        max_steps: int = 1000,
+        learning_rate: float = 1e-3,
+        num_lr_decays: int = -1,
+        early_stop_patience_steps: int = -1,
+        val_check_steps: int = 100,
+        batch_size=32,
+        valid_batch_size: Optional[int] = None,
+        scaler_type: str = "robust",
+        random_seed=1,
+        num_workers_loader=0,
+        drop_last_loader=False,
+        optimizer=None,
+        optimizer_kwargs: Optional[dict] = None,
+        lr_scheduler=None,
+        lr_scheduler_kwargs: Optional[dict] = None,
+        trainer_kwargs: Optional[dict] = None,
+        broadcasting: bool = False,
+    ):
+        self.input_size = input_size
+        self.inference_input_size = inference_input_size
+        self.encoder_n_layers = encoder_n_layers
+        self.encoder_hidden_size = encoder_hidden_size
+        self.encoder_bias = encoder_bias
+        self.encoder_dropout = encoder_dropout
+        self.context_size = context_size
+        self.decoder_hidden_size = decoder_hidden_size
+        self.decoder_layers = decoder_layers
+        self.loss = loss
+        self.valid_loss = valid_loss
+        self.max_steps = max_steps
+        self.learning_rate = learning_rate
+        self.num_lr_decays = num_lr_decays
+        self.early_stop_patience_steps = early_stop_patience_steps
+        self.val_check_steps = val_check_steps
+        self.batch_size = batch_size
+        self.valid_batch_size = valid_batch_size
+        self.scaler_type = scaler_type
+        self.random_seed = random_seed
+        self.num_workers_loader = num_workers_loader
+        self.drop_last_loader = drop_last_loader
+        self.optimizer = optimizer
+        self.optimizer_kwargs = optimizer_kwargs
+        self.lr_scheduler = lr_scheduler
+        self.lr_scheduler_kwargs = lr_scheduler_kwargs
+        self.trainer_kwargs = trainer_kwargs
+
+        super().__init__(
+            freq,
+            local_scaler_type=local_scaler_type,
+            futr_exog_list=futr_exog_list,
+            verbose_fit=verbose_fit,
+            verbose_predict=verbose_predict,
+            broadcasting=broadcasting,
+        )
+
+        # initiate internal variables to avoid AttributeError in future
+        self._trainer_kwargs = None
+        self._loss = None
+        self._valid_loss = None
+
+    @functools.cached_property
+    def algorithm_exogenous_support(self: "NeuralForecastGRU") -> bool:
+        """Set support for exogenous features."""
+        return True
+
+    @functools.cached_property
+    def algorithm_name(self: "NeuralForecastGRU") -> str:
+        """Set custom model name."""
+        return "GRU"
+
+    @functools.cached_property
+    def algorithm_class(self: "NeuralForecastGRU"):
+        """Import underlying NeuralForecast algorithm class."""
+        from neuralforecast.models import GRU
+
+        return GRU
+
+    @functools.cached_property
+    def algorithm_parameters(self: "NeuralForecastGRU") -> dict:
+        """Get keyword parameters for the underlying NeuralForecast algorithm class.
+
+        Returns
+        -------
+        dict
+            keyword arguments for the underlying algorithm class
+        """
+        self._trainer_kwargs = (
+            {} if self.trainer_kwargs is None else self.trainer_kwargs
+        )
+
+        if self.loss:
+            self._loss = self.loss
+        else:
+            from neuralforecast.losses.pytorch import MAE
+
+            self._loss = MAE()
+
+        if self.valid_loss:
+            self._valid_loss = self.valid_loss
+
+        return {
+            "input_size": self.input_size,
+            "inference_input_size": self.inference_input_size,
+            "encoder_n_layers": self.encoder_n_layers,
+            "encoder_hidden_size": self.encoder_hidden_size,
+            "encoder_bias": self.encoder_bias,
+            "encoder_dropout": self.encoder_dropout,
+            "context_size": self.context_size,
+            "decoder_hidden_size": self.decoder_hidden_size,
+            "decoder_layers": self.decoder_layers,
+            "loss": self._loss,
+            "valid_loss": self._valid_loss,
+            "max_steps": self.max_steps,
+            "learning_rate": self.learning_rate,
+            "num_lr_decays": self.num_lr_decays,
+            "early_stop_patience_steps": self.early_stop_patience_steps,
+            "val_check_steps": self.val_check_steps,
+            "batch_size": self.batch_size,
+            "valid_batch_size": self.valid_batch_size,
+            "scaler_type": self.scaler_type,
+            "random_seed": self.random_seed,
+            "num_workers_loader": self.num_workers_loader,
+            "drop_last_loader": self.drop_last_loader,
+            "optimizer": self.optimizer,
+            "optimizer_kwargs": self.optimizer_kwargs,
+            "lr_scheduler": self.lr_scheduler,
+            "lr_scheduler_kwargs": self.lr_scheduler_kwargs,
+            "trainer_kwargs": self._trainer_kwargs,
+        }
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return ``"default"`` set.
+            There are currently no reserved values for forecasters.
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test
+            instance.
+            ``create_test_instance`` uses the first (or only) dictionary in ``params``
+        """
+        del parameter_set  # to avoid being detected as unused by ``vulture`` etc.
+
+        try:
+            _check_soft_dependencies("neuralforecast", severity="error")
+            _check_soft_dependencies("torch", severity="error")
+        except ModuleNotFoundError:
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                },
+            ]
+        else:
+            from neuralforecast.losses.pytorch import SMAPE, QuantileLoss
+            from torch.optim import Adam
+            from torch.optim.lr_scheduler import ConstantLR
+
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                    "lr_scheduler": ConstantLR,
+                    "lr_scheduler_kwargs": {"factor": 0.5},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "loss": QuantileLoss(0.5),
+                    "valid_loss": SMAPE(),
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                    "optimizer": Adam,
+                    "optimizer_kwargs": {"lr": 0.001},
+                },
+            ]
+
+        params_broadcasting = [{**param, "broadcasting": True} for param in params]
+        params_no_broadcasting = [{**param, "broadcasting": False} for param in params]
+
+        return params_broadcasting + params_no_broadcasting
+
+
+class NeuralForecastDilatedRNN(_NeuralForecastAdapter):
+    """NeuralForecast DilatedRNN model.
+
+    Interface to ``neuralforecast.models.DilatedRNN`` [1]_
+    through ``neuralforecast.NeuralForecast`` [2]_,
+    from ``neuralforecast`` [3]_ by Nixtla.
+
+    Multi Layer Elman DilatedRNN (DilatedRNN), with MLP decoder.
+    The network has ``tanh`` or ``relu`` non-linearities, it is trained using
+    ADAM stochastic gradient descent.
+
+    Parameters
+    ----------
+    freq : Union[str, int] (default="auto")
+        frequency of the data, see available frequencies [4]_ from ``pandas``
+        use int freq when using RangeIndex in ``y``
+
+        default ("auto") interprets freq from ForecastingHorizon in ``fit``
+    local_scaler_type : str (default=None)
+        scaler to apply per-series to all features before fitting, which is inverted
+        after predicting
+
+        can be one of the following:
+
+        - 'standard'
+        - 'robust'
+        - 'robust-iqr'
+        - 'minmax'
+        - 'boxcox'
+    futr_exog_list : str list, (default=None)
+        future exogenous variables
+    verbose_fit : bool (default=False)
+        print processing steps during fit
+    verbose_predict : bool (default=False)
+        print processing steps during predict
+    input_size : int (default=-1)
+        maximum sequence length for truncated train backpropagation
+
+        default (-1) uses all history
+    inference_input_size : int (default=-1)
+        maximum sequence length for truncated inference
+
+        default (-1) uses all history
+    cell_type : str (default="LSTM")
+        type of RNN cell to use. can be one of the following:
+
+        - 'GRU'
+        - 'RNN'
+        - 'LSTM'
+        - 'ResLSTM'
+        - 'AttentiveLSTM'
+    dilations : list of int list (default=None)
+        dilations betweem layers, by default set to ``[[1, 2], [4, 8]]``
+    encoder_hidden_size : int (default=200)
+        units for the DilatedRNN's hidden state size
+    context_size : int (default=10)
+        size of context vector for each timestamp on the forecasting window
+    decoder_hidden_size : int (default=200)
+        size of hidden layer for the MLP decoder
+    decoder_layers : int (default=2)
+        number of layers for the MLP decoder
+    loss : pytorch module (default=None)
+        instantiated train loss class from losses collection [5]_
+    valid_loss : pytorch module (default=None)
+        instantiated validation loss class from losses collection [5]_
+    max_steps : int (default=1000)
+        maximum number of training steps
+    learning_rate : float (default=1e-3)
+        learning rate between (0, 1)
+    num_lr_decays : int (default=3)
+        number of learning rate decays, evenly distributed across max_steps
+    early_stop_patience_steps : int (default=-1)
+        number of validation iterations before early stopping
+    val_check_steps : int (default=100)
+        number of training steps between every validation loss check
+    batch_size : int (default=32)
+        number of different series in each batch
+    valid_batch_size : Optional[int] (default=None)
+        number of different series in each validation and test batch
+    step_size : int (default=1)
+        step size between each window of temporal data
+    scaler_type : str (default="robust")
+        type of scaler for temporal inputs normalization
+    random_seed : int (default=1)
+        random_seed for pytorch initializer and numpy generators
+    num_workers_loader : int (default=0)
+        workers to be used by ``TimeSeriesDataLoader``
+    drop_last_loader : bool (default=False)
+        whether ``TimeSeriesDataLoader`` drops last non-full batch
+    trainer_kwargs : dict (default=None)
+        keyword trainer arguments inherited from PyTorch Lighning's trainer [6]_
+    optimizer : pytorch optimizer (default=None) [7]_
+        optimizer to use for training, if passed with None defaults to ``Adam``
+    optimizer_kwargs : dict (default=None) [8]_
+        dict of parameters to pass to the user defined optimizer
+    broadcasting : bool (default=True)
+        DeprecationWarning: default value will be changed to False in v0.35.0
+        multiindex data input will be broadcasted to single series, and for each single series,
+        one copy of this forecaster will try to fit and predict on it. The broadcasting is
+        happening inside automatically, from the outerside api perspective, the input and
+        output are the same, only one multiindex output from `predict`.
+    lr_scheduler : pytorch learning rate scheduler (default=None) [9]_
+        user specified lr_scheduler instead of the default choice ``StepLR`` [10]_
+    lr_scheduler_kwargs : dict (default=None)
+        list of parameters used by the user specified ``lr_scheduler``
+
+    Notes
+    -----
+    * If ``loss`` is unspecified, MAE is used as the loss function for training.
+    * Only ``futr_exog_list`` will be considered as exogenous variables.
+
+    Examples
+    --------
+    >>>
+    >>> # importing necessary libraries
+    >>> from sktime.datasets import load_longley
+    >>> from sktime.forecasting.neuralforecast import NeuralForecastDilatedRNN
+    >>> from sktime.split import temporal_train_test_split
+    >>>
+    >>> # loading the Longley dataset and splitting it into train and test subsets
+    >>> y, X = load_longley()
+    >>> y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=4)
+    >>>
+    >>> # creating model instance configuring the hyperparameters
+    >>> model = NeuralForecastDilatedRNN(  # doctest: +SKIP
+    ...     "A-DEC", futr_exog_list=["ARMED", "POP"], max_steps=5
+    ... )
+    >>>
+    >>> # fitting the model
+    >>> model.fit(y_train, X=X_train, fh=[1, 2, 3, 4])  # doctest: +SKIP
+    Seed set to 1
+    Epoch 4: 100%|████████████████████████████| 1/1 [00:00<00:00, 48.76it/s, v_num=2, train_loss_step=0.798, train_loss_epoch=0.798]
+    NeuralForecastDilatedRNN(freq='A-DEC', futr_exog_list=['ARMED', 'POP'], max_steps=5)
+    >>>
+    >>> # getting point predictions
+    >>> model.predict(X=X_test)  # doctest: +SKIP
+    Predicting DataLoader 0: 100%|████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 51.84it/s]
+    1959    63867.414062
+    1960    64041.445312
+    1961    64116.046875
+    1962    64220.585938
+    Freq: A-DEC, Name: TOTEMP, dtype: float64
+    >>>
+
+    References
+    ----------
+    .. [1] https://nixtlaverse.nixtla.io/neuralforecast/models.dilated_rnn.html#dilatedrnn
+    .. [2] https://nixtlaverse.nixtla.io/neuralforecast/core.html#neuralforecast
+    .. [3] https://github.com/Nixtla/neuralforecast/
+    .. [4]
+    https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases
+    .. [5] https://nixtlaverse.nixtla.io/neuralforecast/losses.pytorch.html
+    .. [6]
+    https://lightning.ai/docs/pytorch/stable/api/pytorch_lightning.trainer.trainer.Trainer.html#lightning.pytorch.trainer.trainer.Trainer
+    .. [7] https://pytorch.org/docs/stable/optim.html
+    .. [8] https://pytorch.org/docs/stable/optim.html#algorithms
+    .. [9] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.LRScheduler.html
+    .. [10] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.StepLR.html
+    """  # noqa: E501
+
+    _tags = {
+        # packaging info
+        # --------------
+        # "authors": ["yarnabrina"],
+        # "maintainers": ["yarnabrina"],
+        # "python_dependencies": "neuralforecast"
+        # inherited from _NeuralForecastAdapter
+        # estimator type
+        # --------------
+        "python_dependencies": ["neuralforecast>=1.6.4"],
+        "capability:global_forecasting": True,
+    }
+
+    def __init__(
+        self: "NeuralForecastDilatedRNN",
+        freq: Union[str, int] = "auto",
+        local_scaler_type: Optional[_SUPPORTED_LOCAL_SCALAR_TYPES] = None,
+        futr_exog_list: Optional[list[str]] = None,
+        verbose_fit: bool = False,
+        verbose_predict: bool = False,
+        input_size: int = -1,
+        inference_input_size: int = -1,
+        cell_type: str = "LSTM",
+        dilations: Optional[list[list[int]]] = None,
+        encoder_hidden_size: int = 200,
+        context_size: int = 10,
+        decoder_hidden_size: int = 200,
+        decoder_layers: int = 2,
+        loss=None,
+        valid_loss=None,
+        max_steps: int = 1000,
+        learning_rate: float = 1e-3,
+        num_lr_decays: int = 3,
+        early_stop_patience_steps: int = -1,
+        val_check_steps: int = 100,
+        batch_size=32,
+        valid_batch_size: Optional[int] = None,
+        step_size: int = 1,
+        scaler_type: str = "robust",
+        random_seed: int = 1,
+        num_workers_loader: int = 0,
+        drop_last_loader: bool = False,
+        optimizer=None,
+        optimizer_kwargs: Optional[dict] = None,
+        lr_scheduler=None,
+        lr_scheduler_kwargs: Optional[dict] = None,
+        broadcasting: bool = False,
+        trainer_kwargs: Optional[dict] = None,
+    ):
+        self.input_size = input_size
+        self.inference_input_size = inference_input_size
+        self.cell_type = cell_type
+        self.dilations = dilations
+        self.encoder_hidden_size = encoder_hidden_size
+        self.context_size = context_size
+        self.decoder_hidden_size = decoder_hidden_size
+        self.decoder_layers = decoder_layers
+        self.loss = loss
+        self.valid_loss = valid_loss
+        self.max_steps = max_steps
+        self.learning_rate = learning_rate
+        self.num_lr_decays = num_lr_decays
+        self.early_stop_patience_steps = early_stop_patience_steps
+        self.val_check_steps = val_check_steps
+        self.batch_size = batch_size
+        self.valid_batch_size = valid_batch_size
+        self.step_size = step_size
+        self.scaler_type = scaler_type
+        self.random_seed = random_seed
+        self.num_workers_loader = num_workers_loader
+        self.drop_last_loader = drop_last_loader
+        self.optimizer = optimizer
+        self.optimizer_kwargs = optimizer_kwargs
+        self.lr_scheduler = lr_scheduler
+        self.lr_scheduler_kwargs = lr_scheduler_kwargs
+        self.trainer_kwargs = trainer_kwargs
+
+        super().__init__(
+            freq,
+            local_scaler_type=local_scaler_type,
+            futr_exog_list=futr_exog_list,
+            verbose_fit=verbose_fit,
+            verbose_predict=verbose_predict,
+            broadcasting=broadcasting,
+        )
+
+        # initiate internal variables to avoid AttributeError in future
+        self._dilations = None
+        self._trainer_kwargs = None
+        self._loss = None
+        self._valid_loss = None
+
+    @functools.cached_property
+    def algorithm_exogenous_support(self: "NeuralForecastDilatedRNN") -> bool:
+        """Set support for exogenous features."""
+        return True
+
+    @functools.cached_property
+    def algorithm_name(self: "NeuralForecastDilatedRNN") -> str:
+        """Set custom model name."""
+        return "DilatedRNN"
+
+    @functools.cached_property
+    def algorithm_class(self: "NeuralForecastDilatedRNN"):
+        """Import underlying NeuralForecast algorithm class."""
+        from neuralforecast.models import DilatedRNN
+
+        return DilatedRNN
+
+    @functools.cached_property
+    def algorithm_parameters(self: "NeuralForecastDilatedRNN") -> dict:
+        """Get keyword parameters for the underlying NeuralForecast algorithm class.
+
+        Returns
+        -------
+        dict
+            keyword arguments for the underlying algorithm class
+        """
+        self._dilations = [[1, 2], [4, 8]] if self.dilations is None else self.dilations
+
+        self._trainer_kwargs = (
+            {} if self.trainer_kwargs is None else self.trainer_kwargs
+        )
+
+        if self.loss:
+            self._loss = self.loss
+        else:
+            from neuralforecast.losses.pytorch import MAE
+
+            self._loss = MAE()
+
+        if self.valid_loss:
+            self._valid_loss = self.valid_loss
+
+        return {
+            "input_size": self.input_size,
+            "inference_input_size": self.inference_input_size,
+            "cell_type": self.cell_type,
+            "dilations": self._dilations,
+            "encoder_hidden_size": self.encoder_hidden_size,
+            "context_size": self.context_size,
+            "decoder_hidden_size": self.decoder_hidden_size,
+            "decoder_layers": self.decoder_layers,
+            "loss": self._loss,
+            "valid_loss": self._valid_loss,
+            "max_steps": self.max_steps,
+            "learning_rate": self.learning_rate,
+            "num_lr_decays": self.num_lr_decays,
+            "early_stop_patience_steps": self.early_stop_patience_steps,
+            "val_check_steps": self.val_check_steps,
+            "batch_size": self.batch_size,
+            "valid_batch_size": self.valid_batch_size,
+            "step_size": self.step_size,
+            "scaler_type": self.scaler_type,
+            "random_seed": self.random_seed,
+            "num_workers_loader": self.num_workers_loader,
+            "drop_last_loader": self.drop_last_loader,
+            "optimizer": self.optimizer,
+            "optimizer_kwargs": self.optimizer_kwargs,
+            "lr_scheduler": self.lr_scheduler,
+            "lr_scheduler_kwargs": self.lr_scheduler_kwargs,
+            "trainer_kwargs": self._trainer_kwargs,
+        }
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return ``"default"`` set.
+            There are currently no reserved values for forecasters.
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test
+            instance.
+            ``create_test_instance`` uses the first (or only) dictionary in ``params``
+        """
+        del parameter_set  # to avoid being detected as unused by ``vulture`` etc.
+
+        try:
+            _check_soft_dependencies("neuralforecast", severity="error")
+            _check_soft_dependencies("torch", severity="error")
+        except ModuleNotFoundError:
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                },
+            ]
+        else:
+            from neuralforecast.losses.pytorch import SMAPE, QuantileLoss
+            from torch.optim import Adam
+            from torch.optim.lr_scheduler import ConstantLR
+
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                    "lr_scheduler": ConstantLR,
+                    "lr_scheduler_kwargs": {"factor": 0.5},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "loss": QuantileLoss(0.5),
+                    "valid_loss": SMAPE(),
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                    "optimizer": Adam,
+                    "optimizer_kwargs": {"lr": 0.001},
+                },
+            ]
+        params_broadcasting = [{**param, "broadcasting": True} for param in params]
+        params_no_broadcasting = [{**param, "broadcasting": False} for param in params]
+
+        return params_broadcasting + params_no_broadcasting
+
+
+class NeuralForecastTCN(_NeuralForecastAdapter):
+    """NeuralForecast TCN model.
+
+    Interface to ``neuralforecast.models.TCN`` [1]_
+    through ``neuralforecast.NeuralForecast`` [2]_,
+    from ``neuralforecast`` [3]_ by Nixtla.
+
+    Temporal Convolution Network (TCN), with MLP decoder.
+    The historical encoder uses dilated skip connections to obtain efficient long memory,
+    while the rest of the architecture allows for future exogenous alignment.
+
+    Parameters
+    ----------
+    freq : Union[str, int] (default="auto")
+        frequency of the data, see available frequencies [4]_ from ``pandas``
+        use int freq when using RangeIndex in ``y``
+
+        default ("auto") interprets freq from ForecastingHorizon in ``fit``
+    local_scaler_type : str (default=None)
+        scaler to apply per-series to all features before fitting, which is inverted
+        after predicting
+
+        can be one of the following:
+
+        - 'standard'
+        - 'robust'
+        - 'robust-iqr'
+        - 'minmax'
+        - 'boxcox'
+    futr_exog_list : str list, (default=None)
+        future exogenous variables
+    verbose_fit : bool (default=False)
+        print processing steps during fit
+    verbose_predict : bool (default=False)
+        print processing steps during predict
+    input_size : int (default=-1)
+        maximum sequence length for truncated train backpropagation
+
+        default (-1) uses all history
+    inference_input_size : int (default=-1)
+        maximum sequence length for truncated inference
+
+        default (-1) uses all history
+    kernel_size : int (default=2)
+        size of the convolving kernel
+    dilations : int list (default=None)
+        controls the temporal spacing between the kernel points
+        also known as the à trous algorithm
+        by default set to ``[1, 2, 4, 8, 16]``
+    encoder_hidden_size : int (default=200)
+        units for the TCN's hidden state size
+    encoder_activation : str (default="ReLU")
+        type of TCN activation from `tanh` or `relu`
+    context_size : int (default=10)
+        size of context vector for each timestamp on the forecasting window
+    decoder_hidden_size : int (default=200)
+        size of hidden layer for the MLP decoder
+    decoder_layers : int (default=2)
+        number of layers for the MLP decoder
+    loss : pytorch module (default=None)
+        instantiated train loss class from losses collection [5]_
+    valid_loss : pytorch module (default=None)
+        instantiated validation loss class from losses collection [5]_
+    max_steps : int (default=1000)
+        maximum number of training steps
+    learning_rate : float (default=1e-3)
+        learning rate between (0, 1)
+    num_lr_decays : int (default=-1)
+        number of learning rate decays, evenly distributed across max_steps
+    early_stop_patience_steps : int (default=-1)
+        number of validation iterations before early stopping
+    val_check_steps : int (default=100)
+        number of training steps between every validation loss check
+    batch_size : int (default=32)
+        number of different series in each batch
+    valid_batch_size : Optional[int] (default=None)
+        number of different series in each validation and test batch
+    scaler_type : str (default="robust")
+        type of scaler for temporal inputs normalization
+    random_seed : int (default=1)
+        random_seed for pytorch initializer and numpy generators
+    num_workers_loader : int (default=0)
+        workers to be used by ``TimeSeriesDataLoader``
+    drop_last_loader : bool (default=False)
+        whether ``TimeSeriesDataLoader`` drops last non-full batch
+    optimizer : pytorch optimizer (default=None) [7]_
+        optimizer to use for training, if passed with None defaults to ``Adam``
+    optimizer_kwargs : dict (default=None) [8]_
+        dict of parameters to pass to the user defined optimizer
+    lr_scheduler : pytorch learning rate scheduler (default=None) [9]_
+        user specified lr_scheduler instead of the default choice ``StepLR`` [10]_
+    lr_scheduler_kwargs : dict (default=None)
+        list of parameters used by the user specified ``lr_scheduler``
+    trainer_kwargs : dict (default=None)
+        keyword trainer arguments inherited from PyTorch Lighning's trainer [6]_
+    broadcasting : bool (default=False)
+        multiindex data input will be broadcasted to single series, and for each single series,
+        one copy of this forecaster will try to fit and predict on it. The broadcasting is
+        happening inside automatically, from the outerside api perspective, the input and
+        output are the same, only one multiindex output from `predict`.
+
+    Notes
+    -----
+    * If ``loss`` is unspecified, MAE is used as the loss function for training.
+    * Only ``futr_exog_list`` will be considered as exogenous variables.
+
+    Examples
+    --------
+    >>>
+    >>> # importing necessary libraries
+    >>> from sktime.datasets import load_longley
+    >>> from sktime.forecasting.neuralforecast import NeuralForecastTCN
+    >>> from sktime.split import temporal_train_test_split
+    >>>
+    >>> # loading the Longley dataset and splitting it into train and test subsets
+    >>> y, X = load_longley()
+    >>> y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=4)
+    >>>
+    >>> # creating model instance configuring the hyperparameters
+    >>> model = NeuralForecastTCN(  # doctest: +SKIP
+    ...     "A-DEC", futr_exog_list=["ARMED", "POP"], max_steps=5
+    ... )
+    >>>
+    >>> # fitting the model
+    >>> model.fit(y_train, X=X_train, fh=[1, 2, 3, 4])  # doctest: +SKIP
+    Seed set to 1
+    Epoch 4: 100%|████████████████████████████| 1/1 [00:00<00:00, 48.19it/s, v_num=5, train_loss_step=0.833, train_loss_epoch=0.833]
+    NeuralForecastTCN(freq='A-DEC', futr_exog_list=['ARMED', 'POP'], max_steps=5)
+    >>>
+    >>> # getting point predictions
+    >>> model.predict(X=X_test)  # doctest: +SKIP
+    Predicting DataLoader 0: 100%|███████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 183.39it/s]
+    1959    63611.593750
+    1960    63528.542969
+    1961    63529.167969
+    1962    63718.667969
+    Freq: A-DEC, Name: TOTEMP, dtype: float64
+    >>>
+
+    References
+    ----------
+    .. [1] https://nixtlaverse.nixtla.io/neuralforecast/models.tcn.html#tcn
+    .. [2] https://nixtlaverse.nixtla.io/neuralforecast/core.html#neuralforecast
+    .. [3] https://github.com/Nixtla/neuralforecast/
+    .. [4]
+    https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases
+    .. [5] https://nixtlaverse.nixtla.io/neuralforecast/losses.pytorch.html
+    .. [6]
+    https://lightning.ai/docs/pytorch/stable/api/pytorch_lightning.trainer.trainer.Trainer.html#lightning.pytorch.trainer.trainer.Trainer
+    .. [7] https://pytorch.org/docs/stable/optim.html
+    .. [8] https://pytorch.org/docs/stable/optim.html#algorithms
+    .. [9] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.LRScheduler.html
+    .. [10] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.StepLR.html
+    """  # noqa: E501
+
+    _tags = {
+        # packaging info
+        # --------------
+        # "authors": ["yarnabrina"],
+        # "maintainers": ["yarnabrina"],
+        # "python_dependencies": "neuralforecast"
+        # inherited from _NeuralForecastAdapter
+        # estimator type
+        # --------------
+        "python_dependencies": ["neuralforecast>=1.6.4"],
+        "capability:global_forecasting": True,
+    }
+
+    def __init__(
+        self: "NeuralForecastTCN",
+        freq: Union[str, int] = "auto",
+        local_scaler_type: Optional[_SUPPORTED_LOCAL_SCALAR_TYPES] = None,
+        futr_exog_list: Optional[list[str]] = None,
+        verbose_fit: bool = False,
+        verbose_predict: bool = False,
+        input_size: int = -1,
+        inference_input_size: int = -1,
+        kernel_size: int = 2,
+        dilations: Optional[list[int]] = None,
+        encoder_hidden_size: int = 200,
+        encoder_activation: str = "ReLU",
+        context_size: int = 10,
+        decoder_hidden_size: int = 200,
+        decoder_layers: int = 2,
+        loss=None,
+        valid_loss=None,
+        max_steps: int = 1000,
+        learning_rate: float = 1e-3,
+        num_lr_decays: int = -1,
+        early_stop_patience_steps: int = -1,
+        val_check_steps: int = 100,
+        batch_size: int = 32,
+        valid_batch_size: Optional[int] = None,
+        scaler_type: str = "robust",
+        random_seed: int = 1,
+        num_workers_loader=0,
+        drop_last_loader=False,
+        optimizer=None,
+        optimizer_kwargs: Optional[dict] = None,
+        lr_scheduler=None,
+        lr_scheduler_kwargs: Optional[dict] = None,
+        trainer_kwargs: Optional[dict] = None,
+        broadcasting: bool = False,
+    ):
+        self.input_size = input_size
+        self.inference_input_size = inference_input_size
+        self.kernel_size = kernel_size
+        self.dilations = dilations
+        self.encoder_hidden_size = encoder_hidden_size
+        self.encoder_activation = encoder_activation
+        self.context_size = context_size
+        self.decoder_hidden_size = decoder_hidden_size
+        self.decoder_layers = decoder_layers
+        self.loss = loss
+        self.valid_loss = valid_loss
+        self.max_steps = max_steps
+        self.learning_rate = learning_rate
+        self.num_lr_decays = num_lr_decays
+        self.early_stop_patience_steps = early_stop_patience_steps
+        self.val_check_steps = val_check_steps
+        self.batch_size = batch_size
+        self.valid_batch_size = valid_batch_size
+        self.scaler_type = scaler_type
+        self.random_seed = random_seed
+        self.num_workers_loader = num_workers_loader
+        self.drop_last_loader = drop_last_loader
+        self.optimizer = optimizer
+        self.optimizer_kwargs = optimizer_kwargs
+        self.lr_scheduler = lr_scheduler
+        self.lr_scheduler_kwargs = lr_scheduler_kwargs
+        self.trainer_kwargs = trainer_kwargs
+
+        super().__init__(
+            freq,
+            local_scaler_type=local_scaler_type,
+            futr_exog_list=futr_exog_list,
+            verbose_fit=verbose_fit,
+            verbose_predict=verbose_predict,
+            broadcasting=broadcasting,
+        )
+
+        # initiate internal variables to avoid AttributeError in future
+        self._dilations = None
+        self._trainer_kwargs = None
+        self._loss = None
+        self._valid_loss = None
+
+    @functools.cached_property
+    def algorithm_exogenous_support(self: "NeuralForecastTCN") -> bool:
+        """Set support for exogenous features."""
+        return True
+
+    @functools.cached_property
+    def algorithm_name(self: "NeuralForecastTCN") -> str:
+        """Set custom model name."""
+        return "TCN"
+
+    @functools.cached_property
+    def algorithm_class(self: "NeuralForecastTCN"):
+        """Import underlying NeuralForecast algorithm class."""
+        from neuralforecast.models import TCN
+
+        return TCN
+
+    @functools.cached_property
+    def algorithm_parameters(self: "NeuralForecastTCN") -> dict:
+        """Get keyword parameters for the underlying NeuralForecast algorithm class.
+
+        Returns
+        -------
+        dict
+            keyword arguments for the underlying algorithm class
+        """
+        self._dilations = [1, 2, 4, 8, 16] if self.dilations is None else self.dilations
+
+        self._trainer_kwargs = (
+            {} if self.trainer_kwargs is None else self.trainer_kwargs
+        )
+
+        if self.loss:
+            self._loss = self.loss
+        else:
+            from neuralforecast.losses.pytorch import MAE
+
+            self._loss = MAE()
+
+        if self.valid_loss:
+            self._valid_loss = self.valid_loss
+
+        return {
+            "input_size": self.input_size,
+            "inference_input_size": self.inference_input_size,
+            "kernel_size": self.kernel_size,
+            "dilations": self._dilations,
+            "encoder_hidden_size": self.encoder_hidden_size,
+            "encoder_activation": self.encoder_activation,
+            "context_size": self.context_size,
+            "decoder_hidden_size": self.decoder_hidden_size,
+            "decoder_layers": self.decoder_layers,
+            "loss": self._loss,
+            "valid_loss": self._valid_loss,
+            "max_steps": self.max_steps,
+            "learning_rate": self.learning_rate,
+            "num_lr_decays": self.num_lr_decays,
+            "early_stop_patience_steps": self.early_stop_patience_steps,
+            "val_check_steps": self.val_check_steps,
+            "batch_size": self.batch_size,
+            "valid_batch_size": self.valid_batch_size,
+            "scaler_type": self.scaler_type,
+            "random_seed": self.random_seed,
+            "num_workers_loader": self.num_workers_loader,
+            "drop_last_loader": self.drop_last_loader,
+            "optimizer": self.optimizer,
+            "optimizer_kwargs": self.optimizer_kwargs,
+            "lr_scheduler": self.lr_scheduler,
+            "lr_scheduler_kwargs": self.lr_scheduler_kwargs,
+            "trainer_kwargs": self._trainer_kwargs,
+        }
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return ``"default"`` set.
+            There are currently no reserved values for forecasters.
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test
+            instance.
+            ``create_test_instance`` uses the first (or only) dictionary in ``params``
+        """
+        del parameter_set  # to avoid being detected as unused by ``vulture`` etc.
+
+        try:
+            _check_soft_dependencies("neuralforecast", severity="error")
+            _check_soft_dependencies("torch", severity="error")
+        except ModuleNotFoundError:
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                },
+            ]
+        else:
+            from neuralforecast.losses.pytorch import SMAPE, QuantileLoss
+            from torch.optim import Adam
+            from torch.optim.lr_scheduler import ConstantLR
+
+            params = [
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "max_steps": 4,
+                    "trainer_kwargs": {"logger": False},
+                    "lr_scheduler": ConstantLR,
+                    "lr_scheduler_kwargs": {"factor": 0.5},
+                },
+                {
+                    "freq": "auto",
+                    "inference_input_size": 2,
+                    "encoder_hidden_size": 2,
+                    "decoder_hidden_size": 3,
+                    "loss": QuantileLoss(0.5),
+                    "valid_loss": SMAPE(),
+                    "max_steps": 4,
+                    "val_check_steps": 2,
+                    "trainer_kwargs": {"logger": False},
+                    "optimizer": Adam,
+                    "optimizer_kwargs": {"lr": 0.001},
+                },
+            ]
+
+        params_broadcasting = [{**param, "broadcasting": True} for param in params]
+        params_no_broadcasting = [{**param, "broadcasting": False} for param in params]
+
+        return params_broadcasting + params_no_broadcasting
+
+
 __all__ = [
     "NeuralForecastRNN",
     "NeuralForecastLSTM",
+    "NeuralForecastGRU",
+    "NeuralForecastDilatedRNN",
+    "NeuralForecastTCN",
 ]
diff --git a/sktime/forecasting/scinet.py b/sktime/forecasting/scinet.py
new file mode 100644
index 000000000..d96964105
--- /dev/null
+++ b/sktime/forecasting/scinet.py
@@ -0,0 +1,263 @@
+"""Deep Learning Forecaster using SCINet Forecaster."""
+
+from sktime.forecasting.base.adapters._pytorch import BaseDeepNetworkPyTorch
+
+
+class SCINetForecaster(BaseDeepNetworkPyTorch):
+    """SCINet Forecaster.
+
+    Implementation of the SCINet forecaster,  by Minhao Liu* [1]_.
+
+    Core logic is directly copied from the curelab SCINet implementation
+    [2]_, which is unfortunately not available as a package.
+
+    Parameters
+    ----------
+    seq_len : int
+        Length of the input sequence.
+        Ensure seq_len is divisible by 2^num_levels.
+
+    num_epochs : int, default=16
+        Number of epochs to train the model.
+
+    batch_size : int, default=8
+        Number of training examples in each batch.
+
+    criterion : torch.nn Loss Function, default=None
+        Loss function to be used for training. If not provided, a default such as
+        torch.nn.MSELoss is often used.
+
+    criterion_kwargs : dict, default=None
+        Keyword arguments to pass to the criterion (loss function).
+
+    optimizer : torch.optim.Optimizer, default=None
+        Optimizer to be used for training. If not provided, a default such as
+        torch.optim.Adam is commonly used.
+
+    optimizer_kwargs : dict, default=None
+        Keyword arguments to pass to the optimizer.
+
+    lr : float, default=0.001
+        Learning rate for the optimizer.
+
+    custom_dataset_train : Dataset, default=None
+        A custom dataset to be used for training. If not provided, the default dataset
+        structure is used.
+
+    custom_dataset_pred : Dataset, default=None
+        A custom dataset to be used for prediction.
+
+    hid_size : int, default=1
+        Size of the hidden layers in the model.
+
+    num_stacks : int, default=1
+        Number of SCINet stacks to use in the model.
+
+    num_levels : int, default=3
+        Number of levels (depth) in each stack.
+
+    num_decoder_layer : int, default=1
+        Number of layers in the decoder portion of the model.
+
+    concat_len : int, default=0
+        Length of input to be concatenated in the skip connection.
+
+    groups : int, default=1
+        Number of groups in convolution layers for grouped convolutions.
+
+    kernel : int, default=5
+        Kernel size for convolution layers.
+
+    dropout : float, default=0.5
+        Dropout rate to apply in the network.
+
+    single_step_output_One : int, default=0
+        Determines whether to output a single step (1) or multiple steps (0).
+
+    positionalE : bool, default=False
+        Enables or disables the use of positional encoding.
+
+    modified : bool, default=True
+        Indicates whether to use the modified version of the SCINet model.
+
+    RIN : bool, default=False
+        Flag to enable or disable the use of RevIN (Reversible Instance Normalization).
+
+    Raises
+    ------
+    AssertionError
+        If seq_len is not divisible by 2^num_levels.
+
+    References
+    ----------
+    .. [1] Minhao Liu*, Ailing Zeng, Muxi Chen, Zhijian Xu, Qiuxia Lai,
+    Lingna Ma, Qiang Xu*
+    SCINet: Time Series Modeling and Forecasting with Sample Convolution and Interaction
+
+    .. [2] https://github.com/cure-lab/SCINet
+
+    Examples
+    --------
+    >>> from sktime.forecasting.scinet import SCINetForecaster # doctest: +SKIP
+    >>> from sktime.datasets import load_airline # doctest: +SKIP
+    >>> model = SCINetForecaster(seq_len=8) # doctest: +SKIP
+    >>> y = load_airline() # doctest: +SKIP
+    >>> model.fit(y, fh=[1, 2, 3]) # doctest: +SKIP
+    SCINetForecaster(seq_len=8)
+    >>> y_pred = model.predict() # doctest: +SKIP
+    >>> y_pred # doctest: +SKIP
+    1961-01    759.448425
+    1961-02    291.098541
+    1961-03    566.977295
+    Freq: M, Name: Number of airline passengers, dtype: float32
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": [
+            "ailingzengzzz",
+            "AlexMinhao",
+            "VEWOXIC",
+            "mixiancmx",
+            "Sohaib-Ahmed21",
+        ],
+        # mixiancmx, ailingzengzzz, AlexMinhao, VEWOXIC for cure-lab code
+        "maintainers": ["Sohaib-Ahmed21"],
+        # "python_dependencies": "pytorch" - inherited from BaseDeepNetworkPyTorch
+        # estimator type vars inherited from BaseDeepNetworkPyTorch
+    }
+
+    def __init__(
+        self,
+        seq_len,
+        *,
+        num_epochs=16,
+        batch_size=8,
+        criterion=None,
+        criterion_kwargs=None,
+        optimizer=None,
+        optimizer_kwargs=None,
+        lr=0.001,
+        custom_dataset_train=None,
+        custom_dataset_pred=None,
+        hid_size=1,
+        num_stacks=1,
+        num_levels=3,
+        num_decoder_layer=1,
+        concat_len=0,
+        groups=1,
+        kernel=5,
+        dropout=0.5,
+        single_step_output_One=0,
+        positionalE=False,
+        modified=True,
+        RIN=False,
+    ):
+        self.seq_len = seq_len
+        self.criterion = criterion
+        self.optimizer = optimizer
+        self.criterion_kwargs = criterion_kwargs
+        self.optimizer_kwargs = optimizer_kwargs
+        self.lr = lr
+        self.num_epochs = num_epochs
+        self.custom_dataset_train = custom_dataset_train
+        self.custom_dataset_pred = custom_dataset_pred
+        self.batch_size = batch_size
+        self.hid_size = hid_size
+        self.num_stacks = num_stacks
+        self.num_levels = num_levels
+        self.num_decoder_layer = num_decoder_layer
+        self.concat_len = concat_len
+        self.groups = groups
+        self.kernel = kernel
+        self.dropout = dropout
+        self.single_step_output_One = single_step_output_One
+        self.positionalE = positionalE
+        self.modified = modified
+        self.RIN = RIN
+
+        super().__init__(
+            num_epochs=num_epochs,
+            batch_size=batch_size,
+            criterion_kwargs=criterion_kwargs,
+            optimizer=optimizer,
+            optimizer_kwargs=optimizer_kwargs,
+            lr=lr,
+        )
+
+        from sktime.utils.dependencies import _check_soft_dependencies
+
+        if _check_soft_dependencies("torch"):
+            import torch
+
+            self.criterions = {
+                "MSE": torch.nn.MSELoss,
+                "L1": torch.nn.L1Loss,
+                "SmoothL1": torch.nn.SmoothL1Loss,
+                "Huber": torch.nn.HuberLoss,
+            }
+
+            self.optimizers = {
+                "Adadelta": torch.optim.Adadelta,
+                "Adagrad": torch.optim.Adagrad,
+                "Adam": torch.optim.Adam,
+                "AdamW": torch.optim.AdamW,
+                "SGD": torch.optim.SGD,
+            }
+
+    def _build_network(self, fh):
+        # Define the SCINet-based network
+        from sktime.networks.scinet import SCINet
+
+        return SCINet(
+            seq_len=self.seq_len,
+            input_dim=self._y.shape[-1],
+            pred_len=fh,
+            hid_size=self.hid_size,
+            num_stacks=self.hid_size,
+            num_levels=self.num_levels,
+            num_decoder_layer=self.num_decoder_layer,
+            concat_len=self.concat_len,
+            groups=self.groups,
+            kernel=self.kernel,
+            dropout=self.dropout,
+            single_step_output_One=self.single_step_output_One,
+            positionalE=self.positionalE,
+            modified=self.modified,
+            RIN=self.RIN,
+        )._build()
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return ``"default"`` set.
+
+
+        Returns
+        -------
+        params : dict or list of dict
+        """
+        params = [
+            {
+                "seq_len": 8,
+                "lr": 0.005,
+                "optimizer": "Adam",
+                "batch_size": 1,
+                "num_epochs": 1,
+            },
+            {
+                "seq_len": 16,
+                "lr": 0.001,
+                "optimizer": "Adam",
+                "batch_size": 4,
+                "num_epochs": 2,
+            },
+        ]
+
+        return params
diff --git a/sktime/networks/scinet.py b/sktime/networks/scinet.py
new file mode 100644
index 000000000..31279096f
--- /dev/null
+++ b/sktime/networks/scinet.py
@@ -0,0 +1,1024 @@
+"""Deep Learning Forecasters using SCINet Forecaster."""
+
+import math
+
+import numpy as np
+
+from sktime.utils.dependencies import _check_soft_dependencies
+
+if _check_soft_dependencies("torch", severity="none"):
+    import torch
+    import torch.nn as nn
+    import torch.nn.functional as F
+    from torch.autograd import Variable
+
+    nn_module = nn.Module
+else:
+
+    class nn_module:
+        """Dummy class if torch is unavailable."""
+
+
+class Splitting:
+    """
+    A neural network module for splitting input into even and odd parts.
+
+    The `_Splitting` class defines a PyTorch module that splits an input tensor into
+    two parts: the even-indexed and odd-indexed elements. This is useful in tasks
+    requiring input splitting or masking.
+
+    This class wraps the `Splitting` neural network module to provide an additional
+    `_build` method for instantiating the wrapped `Splitting` class. The `Splitting`
+    module is used for splitting an input tensor into even-indexed and odd-indexed
+    parts.
+
+    Methods
+    -------
+    _build :
+        Creates an instance of the wrapped `Splitting` class.
+    """
+
+    class _Splitting(nn_module):
+        def __init__(self):
+            super().__init__()
+
+        def even(self, x):
+            """
+            Extract even-indexed elements from the input tensor.
+
+            Parameters
+            ----------
+            x : torch.Tensor
+                Input tensor of shape [Batch, Sequence Length, Channels].
+
+            Returns
+            -------
+            torch.Tensor
+                Tensor containing even-indexed elements of `x`.
+            """
+            return x[:, ::2, :]
+
+        def odd(self, x):
+            """
+            Extract odd-indexed elements from the input tensor.
+
+            Parameters
+            ----------
+            x : torch.Tensor
+                Input tensor of shape [Batch, Sequence Length, Channels].
+
+            Returns
+            -------
+            torch.Tensor
+                Tensor containing odd-indexed elements of `x`.
+            """
+            return x[:, 1::2, :]
+
+        def forward(self, x):
+            """
+            Split the input tensor into even and odd parts.
+
+            Parameters
+            ----------
+            x : torch.Tensor
+                Input tensor of shape [Batch, Sequence Length, Channels].
+
+            Returns
+            -------
+            tuple
+                A tuple containing:
+                - Even-indexed elements as a tensor.
+                - Odd-indexed elements as a tensor.
+            """
+            return (self.even(x), self.odd(x))
+
+    def __init__(self):
+        """Initialize the SplittingModule wrapper."""
+        pass
+
+    def _build(self):
+        """Instantiate the wrapped `_Splitting` class."""
+        return self._Splitting()
+
+
+class Interactor:
+    """
+    Neural network module for tensor operations.
+
+    This class wraps the Interactor module, providing a convenient
+    interface for its initialization with predefined parameters.
+
+    Parameters
+    ----------
+    in_planes (int): Number of input planes (channels) in the input tensor.
+    splitting (bool, optional): Whether to split the input tensor. Defaults to True.
+    kernel (int, optional): The kernel size for convolution layers. Defaults to 5.
+    dropout (float, optional): The dropout rate for regularization. Defaults to 0.5.
+    groups (int, optional): Number of groups for convolutions. Defaults to 1.
+    hidden_size (int, optional): Size of hidden layer. Defaults to 1.
+    INN (bool, optional): Whether to apply modifications to the network.
+    Defaults to True.
+    """
+
+    class _Interactor(nn_module):
+        def __init__(
+            self,
+            in_planes,
+            splitting=True,
+            kernel=5,
+            dropout=0.5,
+            groups=1,
+            hidden_size=1,
+            INN=True,
+        ):
+            super().__init__()
+            self.modified = INN
+            self.kernel_size = kernel
+            self.dilation = 1
+            self.dropout = dropout
+            self.hidden_size = hidden_size
+            self.groups = groups
+
+            if self.kernel_size % 2 == 0:
+                pad_l = (
+                    self.dilation * (self.kernel_size - 2) // 2 + 1
+                )  # by default: stride==1
+                pad_r = (
+                    self.dilation * (self.kernel_size) // 2 + 1
+                )  # by default: stride==1
+            else:
+                pad_l = (
+                    self.dilation * (self.kernel_size - 1) // 2 + 1
+                )  # we fix the kernel size of the second layer as 3.
+                pad_r = self.dilation * (self.kernel_size - 1) // 2 + 1
+            self.splitting = splitting
+            self.split = Splitting()._build()
+
+            modules_P = []
+            modules_U = []
+            modules_psi = []
+            modules_phi = []
+            prev_size = 1
+
+            size_hidden = self.hidden_size
+            modules_P += [
+                nn.ReplicationPad1d((pad_l, pad_r)),
+                nn.Conv1d(
+                    in_planes * prev_size,
+                    int(in_planes * size_hidden),
+                    kernel_size=self.kernel_size,
+                    dilation=self.dilation,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.LeakyReLU(negative_slope=0.01, inplace=True),
+                nn.Dropout(self.dropout),
+                nn.Conv1d(
+                    int(in_planes * size_hidden),
+                    in_planes,
+                    kernel_size=3,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.Tanh(),
+            ]
+            modules_U += [
+                nn.ReplicationPad1d((pad_l, pad_r)),
+                nn.Conv1d(
+                    in_planes * prev_size,
+                    int(in_planes * size_hidden),
+                    kernel_size=self.kernel_size,
+                    dilation=self.dilation,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.LeakyReLU(negative_slope=0.01, inplace=True),
+                nn.Dropout(self.dropout),
+                nn.Conv1d(
+                    int(in_planes * size_hidden),
+                    in_planes,
+                    kernel_size=3,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.Tanh(),
+            ]
+
+            modules_phi += [
+                nn.ReplicationPad1d((pad_l, pad_r)),
+                nn.Conv1d(
+                    in_planes * prev_size,
+                    int(in_planes * size_hidden),
+                    kernel_size=self.kernel_size,
+                    dilation=self.dilation,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.LeakyReLU(negative_slope=0.01, inplace=True),
+                nn.Dropout(self.dropout),
+                nn.Conv1d(
+                    int(in_planes * size_hidden),
+                    in_planes,
+                    kernel_size=3,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.Tanh(),
+            ]
+            modules_psi += [
+                nn.ReplicationPad1d((pad_l, pad_r)),
+                nn.Conv1d(
+                    in_planes * prev_size,
+                    int(in_planes * size_hidden),
+                    kernel_size=self.kernel_size,
+                    dilation=self.dilation,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.LeakyReLU(negative_slope=0.01, inplace=True),
+                nn.Dropout(self.dropout),
+                nn.Conv1d(
+                    int(in_planes * size_hidden),
+                    in_planes,
+                    kernel_size=3,
+                    stride=1,
+                    groups=self.groups,
+                ),
+                nn.Tanh(),
+            ]
+            self.phi = nn.Sequential(*modules_phi)
+            self.psi = nn.Sequential(*modules_psi)
+            self.P = nn.Sequential(*modules_P)
+            self.U = nn.Sequential(*modules_U)
+
+        def forward(self, x):
+            """
+            Forward pass of the Interactor module.
+
+            Splits the input if 'splitting' is True, and applies the
+            respective operations. If 'modified' is True, applies
+            modified equations, otherwise applies the default operations.
+
+            x (Tensor): The input tensor to be processed by the module.
+
+            Returns
+            -------
+            tuple: Two tensors (x_even_update, x_odd_update) or (c, d)
+            """
+            if self.splitting:
+                (x_even, x_odd) = self.split(x)
+            else:
+                (x_even, x_odd) = x
+
+            if self.modified:
+                x_even = x_even.permute(0, 2, 1)
+                x_odd = x_odd.permute(0, 2, 1)
+
+                d = x_odd.mul(torch.exp(self.phi(x_even)))
+                c = x_even.mul(torch.exp(self.psi(x_odd)))
+
+                x_even_update = c + self.U(d)
+                x_odd_update = d - self.P(c)
+
+                return (x_even_update, x_odd_update)
+
+            else:
+                x_even = x_even.permute(0, 2, 1)
+                x_odd = x_odd.permute(0, 2, 1)
+
+                d = x_odd - self.P(x_even)
+                c = x_even + self.U(d)
+
+                return (c, d)
+
+    def __init__(
+        self,
+        in_planes,
+        splitting=True,
+        kernel=5,
+        dropout=0.5,
+        groups=1,
+        hidden_size=1,
+        INN=True,
+    ):
+        """Initialize the Interactor module wrapper."""
+        # Initialize all class parameters with provided arguments or default values
+        self.in_planes = in_planes
+        self.splitting = splitting
+        self.kernel = kernel
+        self.dropout = dropout
+        self.groups = groups
+        self.hidden_size = hidden_size
+        self.INN = INN
+
+    def _build(self):
+        """Instantiate the wrapped Interactor module with predefined parameters.
+
+        Returns
+        -------
+        Interactor : Interactor
+            The initialized Interactor module with default parameters.
+        """
+        return self._Interactor(
+            in_planes=self.in_planes,
+            splitting=self.splitting,
+            kernel=self.kernel,
+            dropout=self.dropout,
+            groups=self.groups,
+            hidden_size=self.hidden_size,
+            INN=self.INN,
+        )
+
+
+class InteractorLevel:
+    """InteractorLevel class for applying Interactor at a specific level.
+
+    Parameters
+    ----------
+    in_planes (int): Number of input channels.
+    kernel (int): Kernel size for the convolution layer.
+    dropout (float): Dropout rate for regularization.
+    groups (int): Number of groups for group convolutions.
+    hidden_size (int): Size of the hidden layers in the network.
+    INN (bool): A flag to enable/disable the INN architecture.
+    """
+
+    class _InteractorLevel(nn_module):
+        def __init__(self, in_planes, kernel, dropout, groups, hidden_size, INN):
+            """Initialize the InteractorLevel module."""
+            super().__init__()
+            self.level = Interactor(
+                in_planes=in_planes,
+                splitting=True,
+                kernel=kernel,
+                dropout=dropout,
+                groups=groups,
+                hidden_size=hidden_size,
+                INN=INN,
+            )._build()
+
+        def forward(self, x):
+            """
+            Forward pass for the InteractorLevel.
+
+            The forward method takes an input tensor `x`, passes it through
+            the Interactor, and returns the updated even and odd parts of
+            the tensor. These parts are the result of the interaction
+            operation at the specified level.
+            """
+            (x_even_update, x_odd_update) = self.level(x)
+            return (x_even_update, x_odd_update)
+
+    def __init__(self, in_planes, kernel, dropout, groups, hidden_size, INN):
+        """Initialize the wrapper of the InteractorLevel module."""
+        self.in_planes = in_planes
+        self.kernel = kernel
+        self.dropout = dropout
+        self.groups = groups
+        self.hidden_size = hidden_size
+        self.INN = INN
+
+    def _build(self):
+        """Instantiate the InteractorLevel module with the specified parameters."""
+        return self._InteractorLevel(
+            in_planes=self.in_planes,
+            kernel=self.kernel,
+            dropout=self.dropout,
+            groups=self.groups,
+            hidden_size=self.hidden_size,
+            INN=self.INN,
+        )
+
+
+class LevelSCINet:
+    """
+    A neural network class for LevelSCINet with interaction layers.
+
+    Parameters
+    ----------
+        in_planes (int): Number of input channels.
+        kernel_size (int): Size of the convolutional kernel.
+        dropout (float): Dropout rate to avoid overfitting.
+        groups (int): Number of groups for grouped convolutions.
+        hidden_size (int): Hidden layer size for the interaction network.
+        INN (bool): Whether to use an invertible neural network.
+    """
+
+    class _LevelSCINet(nn_module):
+        def __init__(self, in_planes, kernel_size, dropout, groups, hidden_size, INN):
+            """Initialize the LevelSCINet with an InteractorLevel module."""
+            super().__init__()
+            self.interact = InteractorLevel(
+                in_planes=in_planes,
+                kernel=kernel_size,
+                dropout=dropout,
+                groups=groups,
+                hidden_size=hidden_size,
+                INN=INN,
+            )._build()
+
+        def forward(self, x):
+            """
+            Forward pass through the LevelSCINet.
+
+            Parameters
+            ----------
+                x (tensor): The input tensor to the network.
+
+            Returns
+            -------
+                tuple: A tuple containing the even and odd updates after
+                interaction, with dimensions (B, T, D) for both even and odd.
+            """
+            (x_even_update, x_odd_update) = self.interact(x)
+            return x_even_update.permute(0, 2, 1), x_odd_update.permute(
+                0, 2, 1
+            )  # even: B, T, D odd: B, T, D
+
+    def __init__(self, in_planes, kernel_size, dropout, groups, hidden_size, INN):
+        """Initialize the LevelSCINet wrapper module."""
+        self.in_planes = in_planes
+        self.kernel_size = kernel_size
+        self.dropout = dropout
+        self.groups = groups
+        self.hidden_size = hidden_size
+        self.INN = INN
+
+    def _build(self):
+        """Build LevelSCINet actual module."""
+        return self._LevelSCINet(
+            in_planes=self.in_planes,
+            kernel_size=self.kernel_size,
+            dropout=self.dropout,
+            groups=self.groups,
+            hidden_size=self.hidden_size,
+            INN=self.INN,
+        )
+
+
+class SCINet_Tree:
+    """SCINet_Tree class implements a recursive SCINet model.
+
+    Parameters
+    ----------
+    in_planes: The number of input planes (features) for the model.
+    current_level: The current level in the recursive SCINet tree.
+    kernel_size: The kernel size used in convolution operations.
+    dropout: Dropout rate for regularization.
+    groups: Number of groups for group convolutions.
+    hidden_size: Size of the hidden layer in SCINet.
+    INN: A boolean flag for using the INN module.
+    """
+
+    class _SCINet_Tree(nn_module):
+        def __init__(
+            self,
+            in_planes,
+            current_level,
+            kernel_size,
+            dropout,
+            groups,
+            hidden_size,
+            INN,
+        ):
+            """
+            Initialize the SCINet_Tree module and its sub-modules.
+
+            Sets the current_level and initializes the working block as
+            a LevelSCINet. If not at the base level, it recursively creates
+            sub-modules for even and odd levels of SCINet_Tree.
+            """
+            super().__init__()
+            self.current_level = current_level
+
+            self.workingblock = LevelSCINet(
+                in_planes=in_planes,
+                kernel_size=kernel_size,
+                dropout=dropout,
+                groups=groups,
+                hidden_size=hidden_size,
+                INN=INN,
+            )._build()
+
+            if current_level != 0:
+                self.SCINet_Tree_odd = SCINet_Tree(
+                    in_planes,
+                    current_level - 1,
+                    kernel_size,
+                    dropout,
+                    groups,
+                    hidden_size,
+                    INN,
+                )._build()
+                self.SCINet_Tree_even = SCINet_Tree(
+                    in_planes,
+                    current_level - 1,
+                    kernel_size,
+                    dropout,
+                    groups,
+                    hidden_size,
+                    INN,
+                )._build()
+
+        def zip_up_the_pants(self, even, odd):
+            """
+            Zips up the even and odd indexed sub-sequences.
+
+            The method permutes and interleaves the even and odd subsequences
+            from input tensors and ensures that they have the same length by
+            padding the shorter one, then returns the interleaved result.
+            """
+            even = even.permute(1, 0, 2)
+            odd = odd.permute(1, 0, 2)  # L, B, D
+            even_len = even.shape[0]
+            odd_len = odd.shape[0]
+            mlen = min((odd_len, even_len))
+            _ = []
+            for i in range(mlen):
+                _.append(even[i].unsqueeze(0))
+                _.append(odd[i].unsqueeze(0))
+            if odd_len < even_len:
+                _.append(even[-1].unsqueeze(0))
+            return torch.cat(_, 0).permute(1, 0, 2)  # B, L, D
+
+        def forward(self, x):
+            """
+            Forward pass of the SCINet_Tree model.
+
+            The input is processed through the working block, and depending
+            on the current_level, the output is recursively passed through
+            even and odd sub-trees. If at the base level, the zipped output
+            is returned after permutation.
+            """
+            x_even_update, x_odd_update = self.workingblock(x)
+            # We recursively reordered these sub-series. You can run the
+            # ./utils/recursive_demo.py to emulate this procedure.
+            if self.current_level == 0:
+                return self.zip_up_the_pants(x_even_update, x_odd_update)
+            else:
+                return self.zip_up_the_pants(
+                    self.SCINet_Tree_even(x_even_update),
+                    self.SCINet_Tree_odd(x_odd_update),
+                )
+
+    def __init__(
+        self, in_planes, current_level, kernel_size, dropout, groups, hidden_size, INN
+    ):
+        """Initialize the wrapper of SCINet tree module."""
+        # Adjusted values based on the input parameters
+        self.in_planes = in_planes
+        self.current_level = current_level
+        self.kernel_size = kernel_size
+        self.dropout = dropout
+        self.groups = groups
+        self.hidden_size = hidden_size
+        self.INN = INN
+
+    def _build(self):
+        """Build actual SCINeT_Tree module."""
+        return self._SCINet_Tree(
+            in_planes=self.in_planes,
+            current_level=self.current_level,
+            kernel_size=self.kernel_size,
+            dropout=self.dropout,
+            groups=self.groups,
+            hidden_size=self.hidden_size,
+            INN=self.INN,
+        )
+
+
+class EncoderTree:
+    """EncoderTree encodes data through SCINet levels.
+
+    Parameters
+    ----------
+    in_planes (int): The number of input channels in the input data.
+    num_levels (int): The number of hierarchical levels in the network.
+    kernel_size (int): The size of the convolutional kernel.
+    dropout (float): The dropout rate to prevent overfitting.
+    groups (int): The number of groups for group convolutions.
+    hidden_size (int): The size of the hidden layer.
+    INN (bool): A flag indicating whether to use an INN network.
+    """
+
+    class _EncoderTree(nn_module):
+        def __init__(
+            self, in_planes, num_levels, kernel_size, dropout, groups, hidden_size, INN
+        ):
+            """Initialize the EncoderTree class and the SCINet_Tree instance."""
+            super().__init__()
+            self.levels = num_levels
+            self.SCINet_Tree = SCINet_Tree(
+                in_planes=in_planes,
+                current_level=num_levels - 1,
+                kernel_size=kernel_size,
+                dropout=dropout,
+                groups=groups,
+                hidden_size=hidden_size,
+                INN=INN,
+            )._build()
+
+        def forward(self, x):
+            """
+            Forward pass for the EncoderTree model.
+
+            x (Tensor): Input tensor passed through the SCINet_Tree.
+
+            Returns
+            -------
+            Tensor: Output tensor from the SCINet_Tree after processing.
+            """
+            x = self.SCINet_Tree(x)
+
+            return x
+
+    def __init__(
+        self, in_planes, num_levels, kernel_size, dropout, groups, hidden_size, INN
+    ):
+        """Initialize Encoder Tree wrapper class."""
+        self.in_planes = in_planes
+        self.num_levels = num_levels
+        self.kernel_size = kernel_size
+        self.dropout = dropout
+        self.groups = groups
+        self.hidden_size = hidden_size
+        self.INN = INN
+
+    def _build(self):
+        """Build encoder tree actual module."""
+        return self._EncoderTree(
+            in_planes=self.in_planes,
+            num_levels=self.num_levels,
+            kernel_size=self.kernel_size,
+            dropout=self.dropout,
+            groups=self.groups,
+            hidden_size=self.hidden_size,
+            INN=self.INN,
+        )
+
+
+class SCINet:
+    """SCINet: Time-Series Forecasting Model.
+
+    Implementation of the SCINet model for time series forecasting, leveraging
+    a stack-based encoder-decoder architecture to capture temporal dependencies
+    effectively.
+
+    SCINet supports features such as positional encoding, reverse instance
+    normalization (RIN), and flexible decoder layers to enhance forecasting accuracy.
+
+    Parameters
+    ----------
+    seq_len : int
+        Length of the input sequence.
+    pred_len : int
+        Length of the prediction (forecast horizon).
+    input_dim : int, default=9
+        Number of input features (dimensions) per time step.
+    hid_size : int, default=1
+        Size of the hidden layer in the encoder.
+    num_stacks : int, default=1
+        Number of stack-based encoder-decoder layers. Maximum of two stacks
+        supported.
+    num_levels : int, default=3
+        Number of hierarchical levels in the encoder tree.
+    num_decoder_layer : int, default=1
+        Number of layers in the decoder for producing predictions.
+    concat_len : int, default=0
+        Length of concatenation for intermediate outputs in multi-stack models.
+    groups : int, default=1
+        Number of groups for grouped convolutions in encoder levels.
+    kernel : int, default=5
+        Size of the convolutional kernel.
+    dropout : float, default=0.5
+        Dropout rate to prevent overfitting.
+    single_step_output_One : int, default=0
+        Flag to enable single-step output.
+    positionalE : bool, default=False
+        Whether to include positional encoding in the input sequence.
+    modified : bool, default=True
+        Flag to enable modifications in the SCINet encoder.
+    RIN : bool, default=False
+        Flag to enable Reverse Instance Normalization (RIN) for input
+        normalization.
+    """
+
+    class _SCINet(nn_module):
+        def __init__(
+            self,
+            pred_len,
+            seq_len,
+            input_dim=9,
+            hid_size=1,
+            num_stacks=1,
+            num_levels=3,
+            num_decoder_layer=1,
+            concat_len=0,
+            groups=1,
+            kernel=5,
+            dropout=0.5,
+            single_step_output_One=0,
+            positionalE=False,
+            modified=True,
+            RIN=False,
+        ):
+            super().__init__()
+
+            self.input_dim = input_dim
+            self.seq_len = seq_len
+            self.pred_len = pred_len
+            self.hidden_size = hid_size
+            self.num_levels = num_levels
+            self.groups = groups
+            self.modified = modified
+            self.kernel_size = kernel
+            self.dropout = dropout
+            self.single_step_output_One = single_step_output_One
+            self.concat_len = concat_len
+            self.pe = positionalE
+            self.RIN = RIN
+            self.num_decoder_layer = num_decoder_layer
+
+            self.blocks1 = EncoderTree(
+                in_planes=self.input_dim,
+                num_levels=self.num_levels,
+                kernel_size=self.kernel_size,
+                dropout=self.dropout,
+                groups=self.groups,
+                hidden_size=self.hidden_size,
+                INN=modified,
+            )._build()
+
+            if num_stacks == 2:  # we only implement two stacks at most.
+                self.blocks2 = EncoderTree(
+                    in_planes=self.input_dim,
+                    num_levels=self.num_levels,
+                    kernel_size=self.kernel_size,
+                    dropout=self.dropout,
+                    groups=self.groups,
+                    hidden_size=self.hidden_size,
+                    INN=modified,
+                )._build()
+
+            self.stacks = num_stacks
+
+            for m in self.modules():
+                if isinstance(m, nn.Conv2d):
+                    n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
+                    m.weight.data.normal_(0, math.sqrt(2.0 / n))
+                elif isinstance(m, nn.BatchNorm2d):
+                    m.weight.data.fill_(1)
+                    m.bias.data.zero_()
+                elif isinstance(m, nn.Linear):
+                    m.bias.data.zero_()
+            self.projection1 = nn.Conv1d(
+                self.seq_len, self.pred_len, kernel_size=1, stride=1, bias=False
+            )
+            self.div_projection = nn.ModuleList()
+            self.overlap_len = self.seq_len // 4
+            self.div_len = self.seq_len // 6
+
+            if self.num_decoder_layer > 1:
+                self.projection1 = nn.Linear(self.seq_len, self.pred_len)
+                for layer_idx in range(self.num_decoder_layer - 1):
+                    div_projection = nn.ModuleList()
+                    for i in range(6):
+                        lens = (
+                            min(i * self.div_len + self.overlap_len, self.seq_len)
+                            - i * self.div_len
+                        )
+                        div_projection.append(nn.Linear(lens, self.div_len))
+                    self.div_projection.append(div_projection)
+
+            if self.single_step_output_One:  # only output the N_th timestep.
+                if self.stacks == 2:
+                    if self.concat_len:
+                        self.projection2 = nn.Conv1d(
+                            self.concat_len + self.pred_len,
+                            1,
+                            kernel_size=1,
+                            bias=False,
+                        )
+                    else:
+                        self.projection2 = nn.Conv1d(
+                            self.seq_len + self.pred_len, 1, kernel_size=1, bias=False
+                        )
+            else:  # output the N timesteps.
+                if self.stacks == 2:
+                    if self.concat_len:
+                        self.projection2 = nn.Conv1d(
+                            self.concat_len + self.pred_len,
+                            self.pred_len,
+                            kernel_size=1,
+                            bias=False,
+                        )
+                    else:
+                        self.projection2 = nn.Conv1d(
+                            self.seq_len + self.pred_len,
+                            self.pred_len,
+                            kernel_size=1,
+                            bias=False,
+                        )
+
+            # For positional encoding
+            self.pe_hidden_size = input_dim
+            if self.pe_hidden_size % 2 == 1:
+                self.pe_hidden_size += 1
+
+            num_timescales = self.pe_hidden_size // 2
+            max_timescale = 10000.0
+            min_timescale = 1.0
+
+            log_timescale_increment = math.log(
+                float(max_timescale) / float(min_timescale)
+            ) / max(num_timescales - 1, 1)
+            # temp = torch.arange(num_timescales, dtype=torch.float32)
+            inv_timescales = min_timescale * torch.exp(
+                torch.arange(num_timescales, dtype=torch.float32)
+                * -log_timescale_increment
+            )
+            self.register_buffer("inv_timescales", inv_timescales)
+
+            ### RIN Parameters ###
+            if self.RIN:
+                self.affine_weight = nn.Parameter(torch.ones(1, 1, input_dim))
+                self.affine_bias = nn.Parameter(torch.zeros(1, 1, input_dim))
+
+        def get_position_encoding(self, x):
+            """Generate position encoding for the input tensor `x`."""
+            max_length = x.size()[1]
+            position = torch.arange(
+                max_length, dtype=torch.float32, device=x.device
+            )  # tensor([0., 1., 2., 3., 4.], device='cuda:0')
+            # temp1 = position.unsqueeze(1)  # 5 1
+            # temp2 = self.inv_timescales.unsqueeze(0)  # 1 256
+            scaled_time = position.unsqueeze(1) * self.inv_timescales.unsqueeze(
+                0
+            )  # 5 256
+            signal = torch.cat(
+                [torch.sin(scaled_time), torch.cos(scaled_time)], dim=1
+            )  # [T, C]
+            signal = F.pad(signal, (0, 0, 0, self.pe_hidden_size % 2))
+            signal = signal.view(1, max_length, self.pe_hidden_size)
+
+            return signal
+
+        def forward(self, x):
+            """Perform the forward pass through the network.
+
+            Ensure that the sequence length (`self.seq_len`) is divisible by 2 raised
+            to the power of the number of levels (`self.num_levels`).
+
+            Raises
+            ------
+            AssertionError
+                If `seq_len` is not divisible by 2^num_levels`.
+            """
+            assert self.seq_len % (np.power(2, self.num_levels)) == 0
+            # evenly divided the input length into two parts.
+            # (e.g., 32 -> 16 -> 8 -> 4 for 3 levels)
+            if self.pe:
+                pe = self.get_position_encoding(x)
+                if pe.shape[2] > x.shape[2]:
+                    x += pe[:, :, :-1]
+                else:
+                    x += self.get_position_encoding(x)
+
+            ### activated when RIN flag is set ###
+            if self.RIN:
+                print("/// RIN ACTIVATED ///\r", end="")
+                means = x.mean(1, keepdim=True).detach()
+                # mean
+                x = x - means
+                # var
+                stdev = torch.sqrt(
+                    torch.var(x, dim=1, keepdim=True, unbiased=False) + 1e-5
+                )
+                x /= stdev
+                # affine
+                # print(x.shape,self.affine_weight.shape,self.affine_bias.shape)
+                x = x * self.affine_weight + self.affine_bias
+
+            # the first stack
+            res1 = x
+            x = self.blocks1(x)
+            x += res1
+            if self.num_decoder_layer == 1:
+                x = self.projection1(x)
+            else:
+                x = x.permute(0, 2, 1)
+                for div_projection in self.div_projection:
+                    output = torch.zeros(x.shape, dtype=x.dtype).cuda()
+                    for i, div_layer in enumerate(div_projection):
+                        div_x = x[
+                            :,
+                            :,
+                            i * self.div_len : min(
+                                i * self.div_len + self.overlap_len, self.seq_len
+                            ),
+                        ]
+                        output[:, :, i * self.div_len : (i + 1) * self.div_len] = (
+                            div_layer(div_x)
+                        )
+                    x = output
+                x = self.projection1(x)
+                x = x.permute(0, 2, 1)
+
+            if self.stacks == 1:
+                ### reverse RIN ###
+                if self.RIN:
+                    x = x - self.affine_bias
+                    x = x / (self.affine_weight + 1e-10)
+                    x = x * stdev
+                    x = x + means
+
+                return x
+
+            elif self.stacks == 2:
+                MidOutPut = x
+                if self.concat_len:
+                    x = torch.cat((res1[:, -self.concat_len :, :], x), dim=1)
+                else:
+                    x = torch.cat((res1, x), dim=1)
+
+                # the second stack
+                res2 = x
+                x = self.blocks2(x)
+                x += res2
+                x = self.projection2(x)
+
+                ### Reverse RIN ###
+                if self.RIN:
+                    MidOutPut = MidOutPut - self.affine_bias
+                    MidOutPut = MidOutPut / (self.affine_weight + 1e-10)
+                    MidOutPut = MidOutPut * stdev
+                    MidOutPut = MidOutPut + means
+
+                if self.RIN:
+                    x = x - self.affine_bias
+                    x = x / (self.affine_weight + 1e-10)
+                    x = x * stdev
+                    x = x + means
+
+                return x, MidOutPut
+
+    def __init__(
+        self,
+        pred_len,
+        seq_len,
+        input_dim=9,
+        hid_size=1,
+        num_stacks=1,
+        num_levels=3,
+        num_decoder_layer=1,
+        concat_len=0,
+        groups=1,
+        kernel=5,
+        dropout=0.5,
+        single_step_output_One=0,
+        positionalE=False,
+        modified=True,
+        RIN=False,
+    ):
+        """Initialize SCINet wrapper."""
+        self.pred_len = pred_len
+        self.seq_len = seq_len
+        self.input_dim = input_dim
+        self.hid_size = hid_size
+        self.num_stacks = num_stacks
+        self.num_levels = num_levels
+        self.num_decoder_layer = num_decoder_layer
+        self.concat_len = concat_len
+        self.groups = groups
+        self.kernel = kernel
+        self.dropout = dropout
+        self.single_step_output_One = single_step_output_One
+        self.positionalE = positionalE
+        self.modified = modified
+        self.RIN = RIN
+
+    def _build(self):
+        """Initialize actual SCINet model from self._SCINet."""
+        return self._SCINet(
+            pred_len=self.pred_len,
+            seq_len=self.seq_len,
+            input_dim=self.input_dim,
+            hid_size=self.hid_size,
+            num_stacks=self.num_stacks,
+            num_levels=self.num_levels,
+            num_decoder_layer=self.num_decoder_layer,
+            concat_len=self.concat_len,
+            groups=self.groups,
+            kernel=self.kernel,
+            dropout=self.dropout,
+            single_step_output_One=self.single_step_output_One,
+            positionalE=self.positionalE,
+            modified=self.modified,
+            RIN=self.RIN,
+        )
+
+
+def get_variable(x):
+    """Convert the input to a Variable and move it to CUDA if available."""
+    x = Variable(x)
+    return x.cuda() if torch.cuda.is_available() else x


Test patch:
diff --git a/sktime/annotation/tests/__init__.py b/sktime/annotation/tests/__init__.py
deleted file mode 100644
index 33c0ca507..000000000
--- a/sktime/annotation/tests/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-"""Time series annotation tests."""
diff --git a/sktime/clustering/tests/spatio_temporal/__init__.py b/sktime/clustering/tests/spatio_temporal/__init__.py
new file mode 100644
index 000000000..1f865c08a
--- /dev/null
+++ b/sktime/clustering/tests/spatio_temporal/__init__.py
@@ -0,0 +1,1 @@
+"""Tests for spatio-temporal clustering."""
diff --git a/sktime/clustering/tests/spatio_temporal/test_st_dbscan.py b/sktime/clustering/tests/spatio_temporal/test_st_dbscan.py
new file mode 100644
index 000000000..d984898c4
--- /dev/null
+++ b/sktime/clustering/tests/spatio_temporal/test_st_dbscan.py
@@ -0,0 +1,135 @@
+"""Tests for spatio-temporal DBSCAN."""
+
+import numpy as np
+import pytest
+
+from sktime.clustering.spatio_temporal import STDBSCAN
+from sktime.clustering.utils.toy_data_generation._make_moving_blobs import (
+    make_moving_blobs,
+)
+
+
+def _rename_labels(X, centers_origin, y_pred, n_labels):
+    """Rename cluster labels to match the true labels."""
+    # rename y_pred labels to match y_true
+    y_pred_renamed = y_pred.copy()
+
+    # find the closest cluster center at time 0
+    for l in range(n_labels):
+        # data at index 0
+        t0_mask = X.index.get_level_values(1).to_numpy() == 0
+        X_t0 = X[t0_mask].to_numpy()
+        y_pred_t0 = y_pred[t0_mask]
+        c = np.mean(X_t0[y_pred_t0 == l], axis=0)
+
+        # find the closest cluster center at time 0
+        dist = np.linalg.norm(centers_origin - c[1:], axis=1)
+
+        # rename cluster l to the closest cluster center at time 0
+        y_pred_renamed[y_pred == l] = np.argmin(dist)
+
+    return y_pred_renamed
+
+
+@pytest.mark.parametrize(
+    "n_times,sparse_matrix_threshold,n_jobs",
+    [(3, 2000, -1), (20, 2000, None), (3, 10, 1), (3, 10, -1), (20, 10, None)],
+)
+def test_st_dbscan(n_times, sparse_matrix_threshold, n_jobs):
+    """Test implementation of spatio-temporal DBSCAN."""
+    centers_origin = np.array([[-1, -1], [0, 0], [1, 1]])
+    X, y_true = make_moving_blobs(n_times=n_times, centers_origin=centers_origin)
+
+    st_dbscan = STDBSCAN(
+        eps1=0.5,
+        eps2=3,
+        min_samples=5,
+        metric="euclidean",
+        frame_size=None,
+        frame_overlap=None,
+        sparse_matrix_threshold=sparse_matrix_threshold,
+        n_jobs=n_jobs,
+    )
+    st_dbscan.fit(X)
+    y_pred = st_dbscan.labels_
+
+    n_labels = len(np.unique(y_pred[y_pred != -1]))
+    assert n_labels == 3
+    y_pred_renamed = _rename_labels(X, centers_origin, y_pred, n_labels)
+    assert np.all(y_pred_renamed == y_true)
+
+
+def test_st_dbscan_data_not_sorted_by_time():
+    centers_origin = np.array([[-1, -1], [0, 0], [1, 1]])
+    X, y_true = make_moving_blobs(n_times=10, centers_origin=centers_origin)
+
+    X_wrong_sorting = X.sort_index(inplace=False, ascending=False, level=1)
+
+    st_dbscan = STDBSCAN(eps1=0.5, eps2=3, min_samples=5)
+    st_dbscan.fit(X_wrong_sorting)
+    y_pred = st_dbscan.labels_
+    n_labels = len(np.unique(y_pred[y_pred != -1]))
+    assert n_labels == 3
+    y_pred_renamed = _rename_labels(X, centers_origin, y_pred, n_labels)
+    assert np.all(y_pred_renamed == y_true)
+
+
+@pytest.mark.parametrize(
+    "n_times,frame_size,frame_overlap",
+    [(40, 40, 5), (40, 10, 5), (40, 20, 10), (20, 10, None)],
+)
+def test_st_dbscan_frame_split(n_times, frame_size, frame_overlap):
+    centers_origin = np.array([[-1, -1], [0, 0], [1, 1]])
+    X, y_true = make_moving_blobs(
+        n_times=n_times, cluster_std=0.05, centers_origin=centers_origin
+    )
+
+    st_dbscan = STDBSCAN(
+        eps1=0.5,
+        eps2=3,
+        min_samples=5,
+        frame_size=20,
+        frame_overlap=5,
+        n_jobs=None,
+    )
+
+    st_dbscan.fit(X)
+
+    y_pred = st_dbscan.labels_
+
+    n_labels = len(np.unique(y_pred[y_pred != -1]))
+    assert n_labels == 3
+    y_pred_renamed = _rename_labels(X, centers_origin, y_pred, n_labels)
+    assert np.all(y_pred_renamed == y_true)
+
+
+@pytest.mark.parametrize(
+    "frame_size,sparse_matrix_threshold",
+    [(None, 2000), (None, 10), (20, 2000), (20, 10)],
+)
+def test_st_dbscan_data_with_noise(frame_size, sparse_matrix_threshold):
+    centers_origin = np.array([[-10, -10], [0, 0], [10, 10]])
+    X, y_true = make_moving_blobs(
+        n_times=20, cluster_std=1, centers_origin=centers_origin
+    )
+
+    st_dbscan = STDBSCAN(
+        eps1=1,
+        eps2=3,
+        min_samples=5,
+        metric="euclidean",
+        frame_size=frame_size,
+        frame_overlap=None,
+        sparse_matrix_threshold=sparse_matrix_threshold,
+        n_jobs=None,
+    )
+
+    st_dbscan.fit(X)
+    y_pred = st_dbscan.labels_
+
+    n_labels = len(np.unique(y_pred[y_pred != -1]))
+    assert n_labels == 3
+
+    y_pred_renamed = _rename_labels(X, centers_origin, y_pred, n_labels)
+
+    assert np.all(y_pred_renamed[y_pred != -1] == y_true[y_pred != -1])
diff --git a/sktime/detection/tests/test_all_annotators.py b/sktime/detection/tests/test_all_annotators.py
deleted file mode 100644
index 9c5aa4638..000000000
--- a/sktime/detection/tests/test_all_annotators.py
+++ /dev/null
@@ -1,108 +0,0 @@
-"""Tests for sktime annotators."""
-
-__author__ = ["miraep8", "fkiraly", "klam-data", "pyyim", "mgorlin"]
-__all__ = []
-
-import numpy as np
-import pandas as pd
-
-from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester
-from sktime.utils._testing.annotation import make_detection_problem
-from sktime.utils.validation.annotation import check_learning_type, check_task
-
-
-class AnnotatorsFixtureGenerator(BaseFixtureGenerator):
-    """Fixture generator for time series annotator (outlier, change point, etc) tests.
-
-    Fixtures parameterized
-    ----------------------
-    estimator_class: estimator inheriting from BaseObject
-        ranges over estimator classes not excluded by EXCLUDE_ESTIMATORS, EXCLUDED_TESTS
-    estimator_instance: instance of estimator inheriting from BaseObject
-        ranges over estimator classes not excluded by EXCLUDE_ESTIMATORS, EXCLUDED_TESTS
-        instances are generated by create_test_instance class method
-    scenario: instance of TestScenario
-        ranges over all scenarios returned by retrieve_scenarios
-    """
-
-    # note: this should be separate from TestAllAnnotators
-    #   additional fixtures, parameters, etc should be added here
-    #   TestAllAnnotators should contain the tests only
-
-    estimator_type_filter = "detector"
-
-    fixture_sequence = [
-        "estimator_class",
-        "estimator_instance",
-        "fitted_estimator",
-        "scenario",
-        "method_nsc",
-        "method_nsc_arraylike",
-    ]
-
-
-class TestAllAnnotators(AnnotatorsFixtureGenerator, QuickTester):
-    """Module level tests for all sktime annotators."""
-
-    def test_output_type(self, estimator_instance):
-        """Test annotator output type."""
-        estimator = estimator_instance
-
-        X_train = make_detection_problem(
-            n_timepoints=50, estimator_type=estimator.get_tag("distribution_type")
-        )
-        estimator.fit(X_train)
-        X_test = make_detection_problem(
-            n_timepoints=10, estimator_type=estimator.get_tag("distribution_type")
-        )
-        y_test = estimator.predict(X_test)
-        assert isinstance(y_test, pd.Series)
-
-    def test_transform_output_type(self, estimator_instance):
-        """Test output type for the transform method."""
-        X_train = make_detection_problem(
-            n_timepoints=50,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        estimator_instance.fit(X_train)
-        X_test = make_detection_problem(
-            n_timepoints=10,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        y_test = estimator_instance.transform(X_test)
-        assert isinstance(y_test, pd.DataFrame)
-        assert len(y_test) == len(X_test)
-
-    def test_predict_points(self, estimator_instance):
-        X_train = make_detection_problem(
-            n_timepoints=50,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        estimator_instance.fit(X_train)
-        X_test = make_detection_problem(
-            n_timepoints=10,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        y_pred = estimator_instance.predict_points(X_test)
-        assert isinstance(y_pred, (pd.Series, np.ndarray))
-
-    def test_predict_segments(self, estimator_instance):
-        X_train = make_detection_problem(
-            n_timepoints=50,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        estimator_instance.fit(X_train)
-
-        X_test = make_detection_problem(
-            n_timepoints=10,
-            estimator_type=estimator_instance.get_tag("distribution_type"),
-        )
-        y_test = estimator_instance.predict_segments(X_test)
-        assert isinstance(y_test, pd.Series)
-        assert isinstance(y_test.index.dtype, pd.IntervalDtype)
-        assert pd.api.types.is_integer_dtype(y_test)
-
-    def test_annotator_tags(self, estimator_class):
-        """Check the learning_type and task tags are valid."""
-        check_task(estimator_class.get_class_tag("task"))
-        check_learning_type(estimator_class.get_class_tag("learning_type"))
diff --git a/sktime/annotation/tests/test_all_annotators.py b/sktime/detection/tests/test_all_detectors.py
similarity index 84%
rename from sktime/annotation/tests/test_all_annotators.py
rename to sktime/detection/tests/test_all_detectors.py
index 9c5aa4638..ae6a9c1fb 100644
--- a/sktime/annotation/tests/test_all_annotators.py
+++ b/sktime/detection/tests/test_all_detectors.py
@@ -1,4 +1,4 @@
-"""Tests for sktime annotators."""
+"""Tests for sktime detectors."""
 
 __author__ = ["miraep8", "fkiraly", "klam-data", "pyyim", "mgorlin"]
 __all__ = []
@@ -7,12 +7,12 @@ import numpy as np
 import pandas as pd
 
 from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester
-from sktime.utils._testing.annotation import make_detection_problem
-from sktime.utils.validation.annotation import check_learning_type, check_task
+from sktime.utils._testing.detection import make_detection_problem
+from sktime.utils.validation.detection import check_learning_type, check_task
 
 
-class AnnotatorsFixtureGenerator(BaseFixtureGenerator):
-    """Fixture generator for time series annotator (outlier, change point, etc) tests.
+class DetectorFixtureGenerator(BaseFixtureGenerator):
+    """Fixture generator for time series detector (outlier, change point, etc) tests.
 
     Fixtures parameterized
     ----------------------
@@ -25,9 +25,9 @@ class AnnotatorsFixtureGenerator(BaseFixtureGenerator):
         ranges over all scenarios returned by retrieve_scenarios
     """
 
-    # note: this should be separate from TestAllAnnotators
+    # note: this should be separate from TestAllDetectors
     #   additional fixtures, parameters, etc should be added here
-    #   TestAllAnnotators should contain the tests only
+    #   TestAllDetectors should contain the tests only
 
     estimator_type_filter = "detector"
 
@@ -41,11 +41,11 @@ class AnnotatorsFixtureGenerator(BaseFixtureGenerator):
     ]
 
 
-class TestAllAnnotators(AnnotatorsFixtureGenerator, QuickTester):
-    """Module level tests for all sktime annotators."""
+class TestAllDetectors(DetectorFixtureGenerator, QuickTester):
+    """Module level tests for all sktime detectors."""
 
     def test_output_type(self, estimator_instance):
-        """Test annotator output type."""
+        """Test detector output type."""
         estimator = estimator_instance
 
         X_train = make_detection_problem(
@@ -102,7 +102,7 @@ class TestAllAnnotators(AnnotatorsFixtureGenerator, QuickTester):
         assert isinstance(y_test.index.dtype, pd.IntervalDtype)
         assert pd.api.types.is_integer_dtype(y_test)
 
-    def test_annotator_tags(self, estimator_class):
+    def test_detector_tags(self, estimator_class):
         """Check the learning_type and task tags are valid."""
         check_task(estimator_class.get_class_tag("task"))
         check_learning_type(estimator_class.get_class_tag("learning_type"))
diff --git a/sktime/forecasting/tests/test_neuralforecast.py b/sktime/forecasting/tests/test_neuralforecast.py
index 89b9bfddf..c8a3038ba 100644
--- a/sktime/forecasting/tests/test_neuralforecast.py
+++ b/sktime/forecasting/tests/test_neuralforecast.py
@@ -5,7 +5,13 @@ import pandas
 import pytest
 
 from sktime.datasets import load_longley
-from sktime.forecasting.neuralforecast import NeuralForecastLSTM, NeuralForecastRNN
+from sktime.forecasting.neuralforecast import (
+    NeuralForecastDilatedRNN,
+    NeuralForecastGRU,
+    NeuralForecastLSTM,
+    NeuralForecastRNN,
+    NeuralForecastTCN,
+)
 from sktime.split import temporal_train_test_split
 from sktime.tests.test_switch import run_test_for_class
 
@@ -15,9 +21,26 @@ y, X = load_longley()
 y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=4)
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_univariate_y_without_X(model_class) -> None:
@@ -39,9 +62,26 @@ def test_neural_forecast_univariate_y_without_X(model_class) -> None:
     pandas.testing.assert_index_equal(y_pred.index, y_test.index, check_names=False)
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_univariate_y_with_X(model_class) -> None:
@@ -80,9 +120,26 @@ def test_neural_forecast_univariate_y_with_X(model_class) -> None:
     pandas.testing.assert_index_equal(y_pred.index, y_test.index, check_names=False)
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_multivariate_y_without_X(model_class) -> None:
@@ -100,9 +157,26 @@ def test_neural_forecast_multivariate_y_without_X(model_class) -> None:
     pandas.testing.assert_index_equal(X_pred.index, X_test.index, check_names=False)
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_non_default_loss(model_class) -> None:
@@ -129,9 +203,26 @@ def test_neural_forecast_with_non_default_loss(model_class) -> None:
     pandas.testing.assert_index_equal(X_pred.index, X_test.index, check_names=False)
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_fail_with_multiple_predictions(model_class) -> None:
@@ -157,9 +248,26 @@ def test_neural_forecast_fail_with_multiple_predictions(model_class) -> None:
         model.predict()
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_auto_freq(model_class) -> None:
@@ -180,7 +288,16 @@ def test_neural_forecast_with_auto_freq(model_class) -> None:
     assert offset_freq == offset_auto_freq
 
 
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.parametrize(
     "freq",
     [
@@ -203,7 +320,15 @@ def test_neural_forecast_with_auto_freq(model_class) -> None:
     ],
 )
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_auto_against_given_freq(model_class, freq) -> None:
@@ -245,9 +370,26 @@ def test_neural_forecast_with_auto_against_given_freq(model_class, freq) -> None
         (pandas.period_range(start="2024-01-01", periods=10).drop(["2024-01-02"]), "D"),
     ],
 )
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_auto_freq_on_valid_index(
@@ -277,9 +419,26 @@ def test_neural_forecast_with_auto_freq_on_valid_index(
         pandas.Index([1, 2, 3, 4, 5, 7])
     ],
 )
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_auto_freq_on_missing_int_like(index, model_class) -> None:
@@ -304,9 +463,26 @@ def test_neural_forecast_with_auto_freq_on_missing_int_like(index, model_class)
         pandas.to_datetime(["2000-01-01", "2000-01-02", "2000-01-04", "2000-01-05"]),
     ],
 )
-@pytest.mark.parametrize("model_class", [NeuralForecastLSTM, NeuralForecastRNN])
+@pytest.mark.parametrize(
+    "model_class",
+    [
+        NeuralForecastDilatedRNN,
+        NeuralForecastGRU,
+        NeuralForecastLSTM,
+        NeuralForecastRNN,
+        NeuralForecastTCN,
+    ],
+)
 @pytest.mark.skipif(
-    not run_test_for_class([NeuralForecastLSTM, NeuralForecastRNN]),
+    not run_test_for_class(
+        [
+            NeuralForecastLSTM,
+            NeuralForecastRNN,
+            NeuralForecastDilatedRNN,
+            NeuralForecastGRU,
+            NeuralForecastTCN,
+        ]
+    ),
     reason="run test only if softdeps are present and incrementally (if requested)",
 )
 def test_neural_forecast_with_auto_freq_on_missing_date_like(
diff --git a/sktime/tests/_config.py b/sktime/tests/_config.py
index 38d5ea2dd..c469604e9 100644
--- a/sktime/tests/_config.py
+++ b/sktime/tests/_config.py
@@ -269,11 +269,6 @@ EXCLUDED_TESTS = {
         "test_predict_segments",
         "test_transform_output_type",
     ],
-    "DetectorPipeline": [
-        "test_predict_points",
-        "test_predict_segments",
-        "test_transform_output_type",
-    ],
     "BinarySegmentation": [
         "test_predict_segments",
         "test_transform_output_type",
@@ -301,11 +296,6 @@ EXCLUDED_TESTS = {
         "test_predict_segments",
         "test_transform_output_type",
     ],
-    "SubLOF": [
-        "test_predict_points",
-        "test_predict_segments",
-        "test_transform_output_type",
-    ],
 }
 
 # exclude tests but keyed by test name
@@ -416,7 +406,6 @@ EXCLUDED_TESTS_BY_TEST = {
         "SlidingWindowSegmenter",
         "SlopeTransformer",
         "StackingForecaster",
-        "SubLOF",
         "SummaryClassifier",
         "SupervisedIntervals",
         "SupervisedTimeSeriesForest",
diff --git a/sktime/tests/test_class_register.py b/sktime/tests/test_class_register.py
index 8f1f57a73..2435b6137 100644
--- a/sktime/tests/test_class_register.py
+++ b/sktime/tests/test_class_register.py
@@ -21,11 +21,11 @@ def get_test_class_registry():
         keys are scitypes, values are test classes TestAll[Scitype]
     """
     from sktime.alignment.tests.test_all_aligners import TestAllAligners
-    from sktime.annotation.tests.test_all_annotators import TestAllAnnotators
     from sktime.classification.early_classification.tests.test_all_early_classifiers import (  # noqa E501
         TestAllEarlyClassifiers,
     )
     from sktime.classification.tests.test_all_classifiers import TestAllClassifiers
+    from sktime.detection.tests.test_all_detectors import TestAllDetectors
     from sktime.dists_kernels.tests.test_all_dist_kernels import (
         TestAllPairwiseTransformers,
         TestAllPanelTransformers,
@@ -54,7 +54,7 @@ def get_test_class_registry():
     # so also imply estimator and object tests, or only object tests
     testclass_dict["aligner"] = TestAllAligners
     testclass_dict["classifier"] = TestAllClassifiers
-    testclass_dict["detector"] = TestAllAnnotators
+    testclass_dict["detector"] = TestAllDetectors
     testclass_dict["distribution"] = TestAllDistributions
     testclass_dict["early_classifier"] = TestAllEarlyClassifiers
     testclass_dict["forecaster"] = TestAllForecasters
@@ -62,7 +62,7 @@ def get_test_class_registry():
     testclass_dict["param_est"] = TestAllParamFitters
     testclass_dict["regressor"] = TestAllRegressors
     # todo 1.0.0 - remove series-annotator
-    testclass_dict["series-annotator"] = TestAllAnnotators
+    testclass_dict["series-annotator"] = TestAllDetectors
     testclass_dict["splitter"] = TestAllSplitters
     testclass_dict["transformer"] = TestAllTransformers
     testclass_dict["transformer-pairwise"] = TestAllPairwiseTransformers