Repository: sktime/sktime
Pull request #7542 (2024-12-17 21:55:18)

[ENH] refactor checks for detector outputs into separate module
This PR refactors the checks for detector outputs from `TestAllDetectors` to a separate module, `detection._datatypes`.

This is in order to introduce a data checker layer similra to `datatypes`, without fully integrating with the `datatypes` machinery yet - as we will probably reuse the utilities inside `BaseDetector` before that.


Patch:
diff --git a/sktime/classification/deep_learning/cnn.py b/sktime/classification/deep_learning/cnn.py
index d8c37ce76..05b5128bf 100644
--- a/sktime/classification/deep_learning/cnn.py
+++ b/sktime/classification/deep_learning/cnn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class CNNClassifier(BaseDeepClassifier):
     """Time Convolutional Neural Network (CNN), as described in [1]_.
 
+    Adapted from the implementation from Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/cnn.py
+
     Parameters
     ----------
     n_epochs       : int, default = 2000
@@ -51,11 +54,6 @@ class CNNClassifier(BaseDeepClassifier):
           ``input_shape[0] < 60`` in the input layer, and ``"valid"`` otherwise.
         - "valid", "same", and other values are passed directly to ``Conv1D``
 
-    Notes
-    -----
-    Adapted from the implementation from Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/cnn.py
-
     References
     ----------
     .. [1] Zhao et. al, Convolutional neural networks for time series classification,
@@ -75,7 +73,8 @@ class CNNClassifier(BaseDeepClassifier):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "TonyBagnall"],
+        "authors": ["hfawaz", "James-Large"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["James-Large"],
         "python_dependencies": "tensorflow",
         # estimator type handled by parent class
diff --git a/sktime/classification/deep_learning/cntc.py b/sktime/classification/deep_learning/cntc.py
index 6238ac9c7..e4404761a 100644
--- a/sktime/classification/deep_learning/cntc.py
+++ b/sktime/classification/deep_learning/cntc.py
@@ -12,6 +12,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class CNTCClassifier(BaseDeepClassifier):
     """Contextual Time-series Neural Classifier (CNTC), as described in [1].
 
+    Adapted from the implementation from Fullah et. al
+    https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb
+
     Parameters
     ----------
     n_epochs       : int, default = 2000
@@ -38,11 +41,6 @@ class CNTCClassifier(BaseDeepClassifier):
     optimizer       : keras.optimizer, default=keras.optimizers.Adam(),
     metrics         : list of strings, default=["accuracy"],
 
-    Notes
-    -----
-    Adapted from the implementation from Fullah et. al
-    https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb
-
     References
     ----------
     .. [1] Network originally defined in:
@@ -73,7 +71,13 @@ class CNTCClassifier(BaseDeepClassifier):
     """
 
     _tags = {
-        "authors": ["James-Large", "Withington", "TonyBagnall", "AurumnPegasus"],
+        "authors": [
+            "AmaduFullah",
+            "James-Large",
+            "Withington",
+            "TonyBagnall",
+            "AurumnPegasus",
+        ],
         "maintainers": ["James-Large", "Withington", "AurumnPegasus"],
         "python_dependencies": ["tensorflow", "keras-self-attention"],
     }
diff --git a/sktime/classification/deep_learning/fcn.py b/sktime/classification/deep_learning/fcn.py
index 6a1470c33..2d0b9b5fd 100644
--- a/sktime/classification/deep_learning/fcn.py
+++ b/sktime/classification/deep_learning/fcn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class FCNClassifier(BaseDeepClassifier):
     """Fully Connected Neural Network (FCN), as described in [1]_.
 
+    Adapted from the implementation from Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
+
     Parameters
     ----------
     should inherited fields be listed here?
@@ -39,11 +42,6 @@ class FCNClassifier(BaseDeepClassifier):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-    Notes
-    -----
-    Adapted from the implementation from Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
-
     References
     ----------
     .. [1] Zhao et. al, Convolutional neural networks for time series classification,
@@ -63,7 +61,8 @@ class FCNClassifier(BaseDeepClassifier):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "AurumnPegasus"],
+        "authors": ["hfawaz", "James-Large", "AurumnPegasus"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["James-Large", "AurumnPegasus"],
         # estimator type handled by parent class
     }
diff --git a/sktime/classification/deep_learning/lstmfcn.py b/sktime/classification/deep_learning/lstmfcn.py
index 983d6c82f..e4e9aa46d 100644
--- a/sktime/classification/deep_learning/lstmfcn.py
+++ b/sktime/classification/deep_learning/lstmfcn.py
@@ -15,10 +15,8 @@ from sktime.networks.lstmfcn import LSTMFCNNetwork
 class LSTMFCNClassifier(BaseDeepClassifier):
     """Implementation of LSTMFCNClassifier from Karim et al (2019) [1].
 
-    Overview
-    --------
-     Combines an LSTM arm with a CNN arm. Optionally uses an attention mechanism in the
-     LSTM which the author indicates provides improved performance.
+    Combines an LSTM arm with a CNN arm. Optionally uses an attention mechanism in the
+    LSTM which the author indicates provides improved performance.
 
     Parameters
     ----------
diff --git a/sktime/classification/deep_learning/mcdcnn.py b/sktime/classification/deep_learning/mcdcnn.py
index a84c21e9b..d11832a66 100644
--- a/sktime/classification/deep_learning/mcdcnn.py
+++ b/sktime/classification/deep_learning/mcdcnn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class MCDCNNClassifier(BaseDeepClassifier):
     """Multi Channel Deep Convolutional Neural Classifier, as described in [1]_.
 
+    Adapted from the implementation of Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mcdcnn.py
+
     Parameters
     ----------
     n_epochs : int, optional (default=120)
@@ -57,11 +60,6 @@ class MCDCNNClassifier(BaseDeepClassifier):
     random_state : int, optional (default=0)
         The seed to any random action.
 
-    Notes
-    -----
-    Adapted from the implementation of Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mcdcnn.py
-
     References
     ----------
     .. [1] Zheng et. al, Time series classification using multi-channels deep
@@ -81,7 +79,7 @@ class MCDCNNClassifier(BaseDeepClassifier):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["james-large"],
+        "authors": ["hfawaz", "james-large"],
         "maintainers": ["james-large"],
         "python_dependencies": "tensorflow",
         # estimator type handled by parent class
diff --git a/sktime/classification/deep_learning/mlp.py b/sktime/classification/deep_learning/mlp.py
index e8c770116..7e6c9f7d0 100644
--- a/sktime/classification/deep_learning/mlp.py
+++ b/sktime/classification/deep_learning/mlp.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class MLPClassifier(BaseDeepClassifier):
     """Multi Layer Perceptron Network (MLP), as described in [1]_.
 
+    Adapted from the implementation from source code
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
+
     Parameters
     ----------
     should inherited fields be listed here?
@@ -39,11 +42,6 @@ class MLPClassifier(BaseDeepClassifier):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-    Notes
-    -----
-    Adapted from the implementation from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
-
     References
     ----------
     .. [1] Wang et. al, Time series classification from
@@ -63,7 +61,8 @@ class MLPClassifier(BaseDeepClassifier):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "AurumnPegasus"],
+        "authors": ["hfawaz", "James-Large", "AurumnPegasus"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["James-Large", "AurumnPegasus"],
         # estimator type handled by parent class
     }
diff --git a/sktime/classification/deep_learning/resnet.py b/sktime/classification/deep_learning/resnet.py
index 82e46c667..6a2a84b28 100644
--- a/sktime/classification/deep_learning/resnet.py
+++ b/sktime/classification/deep_learning/resnet.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class ResNetClassifier(BaseDeepClassifier):
     """Residual Neural Network as described in [1].
 
+    Adapted from the implementation from source code
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
+
     Parameters
     ----------
     n_epochs       : int, default = 1500
@@ -38,12 +41,6 @@ class ResNetClassifier(BaseDeepClassifier):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-
-    Notes
-    -----
-    Adapted from the implementation from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
-
     References
     ----------
         .. [1] Wang et. al, Time series classification from
@@ -63,7 +60,8 @@ class ResNetClassifier(BaseDeepClassifier):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "AurumnPegasus", "nilesh05apr"],
+        "authors": ["hfawaz", "James-Large", "AurumnPegasus", "nilesh05apr"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["James-Large", "AurumnPegasus", "nilesh05apr"],
         "python_dependencies": ["tensorflow"],
         # estimator type handled by parent class
diff --git a/sktime/detection/_datatypes/__init__.py b/sktime/detection/_datatypes/__init__.py
new file mode 100644
index 000000000..95f3aca30
--- /dev/null
+++ b/sktime/detection/_datatypes/__init__.py
@@ -0,0 +1,1 @@
+"""Utilities to handle checks and conversions between output formats of detectors."""
diff --git a/sktime/detection/_datatypes/_check.py b/sktime/detection/_datatypes/_check.py
new file mode 100644
index 000000000..b3b1c3746
--- /dev/null
+++ b/sktime/detection/_datatypes/_check.py
@@ -0,0 +1,59 @@
+"""Utilities to handle checks and conversions between output formats of detectors."""
+
+import pandas as pd
+
+
+def _is_valid_detection(obj, type="points"):
+    """Check if the input is valid common output format.
+
+    Parameters
+    ----------
+    obj : pd.DataFrame
+        Output of a detector to check for validity
+    type : str {"points", "segments"}
+        Type of output to check for validity
+    """
+    if not isinstance(obj, pd.DataFrame):
+        return False
+    if not isinstance(obj.index, pd.RangeIndex):
+        return False
+    if "ilocs" not in obj.columns:
+        return False
+
+    if type == "points":
+        return _is_points_dtype(obj)
+    elif type == "segments":
+        return _is_segments_dtype(obj)
+
+    return False
+
+
+def _is_points_dtype(obj):
+    """Check if the input is points-like.
+
+    Assumes validity of input is checked elsewhere.
+
+    Parameters
+    ----------
+    obj : pd.DataFrame
+        Output of a detector to check
+    """
+    return pd.api.types.is_integer_dtype(obj.ilocs.dtype)
+
+
+def _is_segments_dtype(obj):
+    """Check if the input is valid segments-like.
+
+    Assumes validity of input is checked elsewhere.
+
+    Parameters
+    ----------
+    obj : pd.DataFrame
+        Output of a detector to check
+    """
+    ilocs_dtype = obj.ilocs.dtype
+    if not (isinstance(ilocs_dtype, pd.IntervalDtype) or len(obj) == 0):
+        return False
+    if not len(obj) == 0:
+        return pd.api.types.is_integer_dtype(ilocs_dtype.subtype)
+    return True
diff --git a/sktime/forecasting/base/_meta.py b/sktime/forecasting/base/_meta.py
index 740541659..72c6d8dad 100644
--- a/sktime/forecasting/base/_meta.py
+++ b/sktime/forecasting/base/_meta.py
@@ -18,6 +18,12 @@ class _HeterogenousEnsembleForecaster(_HeterogenousMetaEstimator, BaseForecaster
     # this must be an iterable of (name: str, estimator, ...) tuples for the default
     _steps_attr = "forecasters"
 
+    # if the estimator is fittable, _HeterogenousMetaEstimator also
+    # provides an override for get_fitted_params for params from the fitted estimators
+    # the fitted estimators should be in a different attribute, _steps_fitted_attr
+    # this must be an iterable of (name: str, estimator, ...) tuples for the default
+    _steps_fitted_attr = "forecasters_"
+
     def __init__(self, forecasters, n_jobs=None):
         self.forecasters = forecasters
         self.forecasters_ = None
diff --git a/sktime/forecasting/compose/_hierarchy_ensemble.py b/sktime/forecasting/compose/_hierarchy_ensemble.py
index 9a7d1f7da..131912399 100644
--- a/sktime/forecasting/compose/_hierarchy_ensemble.py
+++ b/sktime/forecasting/compose/_hierarchy_ensemble.py
@@ -61,19 +61,20 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster):
     >>> from sktime.forecasting.trend import PolynomialTrendForecaster, TrendForecaster
     >>> from sktime.utils._testing.hierarchical import _bottom_hier_datagen
     >>> y = _bottom_hier_datagen(
-    ...         no_bottom_nodes=7,
-    ...         no_levels=2,
-    ...         random_seed=123
+    ...     no_bottom_nodes=7,
+    ...     no_levels=2,
+    ...     random_seed=123,
     ... )
 
     >>> # Example of by = 'level'
     >>> forecasters = [
     ...     ('naive', NaiveForecaster(), 0),
-    ...     ('trend', TrendForecaster(), 1)
+    ...     ('trend', TrendForecaster(), 1),
     ... ]
     >>> forecaster = HierarchyEnsembleForecaster(
-    ...                 forecasters=forecasters,
-    ...                 by='level', default = PolynomialTrendForecaster(degree=2)
+    ...     forecasters=forecasters,
+    ...     by='level',
+    ...     default=PolynomialTrendForecaster(degree=2),
     ... )
     >>> forecaster.fit(y, fh=[1, 2, 3])
     HierarchyEnsembleForecaster(...)
@@ -188,11 +189,12 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster):
         x = X
 
         # check forecasters
-        self.forecasters_ = self._check_forecasters(y, z)
+        forecasters_ = self._check_forecasters(y, z)
+        self.forecasters_ = self._ensure_clone(forecasters_)
         self.fitted_list = []
 
         if y.index.nlevels == 1:
-            frcstr = self.forecasters_[0][1].clone()
+            frcstr = self.forecasters_[0][1]
             frcstr.fit(y, fh=fh, X=X)
             self.fitted_list.append([frcstr, y.index])
             return self
@@ -201,7 +203,7 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster):
             hier_dict = self._get_hier_dict(z)
             for _, forecaster, level in self.forecasters_:
                 if level in hier_dict.keys():
-                    frcstr = forecaster.clone()
+                    frcstr = forecaster
                     df = z[z.index.droplevel(-1).isin(hier_dict[level])]
                     if X is not None:
                         x = X.loc[df.index]
@@ -211,7 +213,7 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster):
         else:
             node_dict, frcstr_dict = self._get_node_dict(z)
             for key, nodes in node_dict.items():
-                frcstr = frcstr_dict[key].clone()
+                frcstr = frcstr_dict[key]
                 df = z[z.index.droplevel(-1).isin(nodes)]
                 if X is not None:
                     x = X.loc[df.index]
@@ -594,6 +596,21 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster):
 
         return forecasters
 
+    def _ensure_clone(self, forecasters):
+        """Ensure that forecasters are cloned.
+
+        This should be done by _check_forecasters, but the function is hard to
+        understand and debug. This function is a safety net to ensure that
+        all forecasters are cloned.
+
+        This function, and _check_forecasters, should be refactored to be more
+        readable and maintainable.
+        """
+        forecasters_ = []
+        for name, forecaster, level_nd in forecasters:
+            forecasters_.append((name, forecaster.clone(), level_nd))
+        return forecasters_
+
     @classmethod
     def get_test_params(cls):
         """Return testing parameter settings for the estimator.
diff --git a/sktime/networks/cnn.py b/sktime/networks/cnn.py
index 663b16c30..b4dce3e99 100644
--- a/sktime/networks/cnn.py
+++ b/sktime/networks/cnn.py
@@ -9,7 +9,7 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class CNNNetwork(BaseDeepNetwork):
     """Establish the network structure for a CNN.
 
-    Adapted from the implementation used in [1]
+    Adapted from the implementation used in [1]_.
 
     Parameters
     ----------
@@ -31,18 +31,18 @@ class CNNNetwork(BaseDeepNetwork):
     random_state    : int, default = 0
         seed to any needed random actions
 
-    Notes
-    -----
-    Adapted from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/cnn.py
-
     References
     ----------
     .. [1] Zhao et al. Convolutional neural networks for time series classification,
     Journal of Systems Engineering and Electronics 28(1), 162--169, 2017
     """
 
-    _tags = {"python_dependencies": "tensorflow"}
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": ["hfawaz"],
+        "python_dependencies": "tensorflow",
+    }
 
     def __init__(
         self,
diff --git a/sktime/networks/fcn.py b/sktime/networks/fcn.py
index 9626ed965..185fe27a4 100644
--- a/sktime/networks/fcn.py
+++ b/sktime/networks/fcn.py
@@ -9,18 +9,16 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class FCNNetwork(BaseDeepNetwork):
     """Establish the network structure for a FCN.
 
-    Adapted from the implementation used in [1]
+    Adapted from the implementation of Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
+
+    Implements network in [1]_.
 
     Parameters
     ----------
-    random_state    : int, default = 0
+    random_states : int, default = 0
         seed to any needed random actions
 
-    Notes
-    -----
-    Adapted from the implementation from Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
-
     References
     ----------
     .. [1] Network originally defined in:
diff --git a/sktime/networks/inceptiontime.py b/sktime/networks/inceptiontime.py
index 379111e3a..0c2ab1a32 100644
--- a/sktime/networks/inceptiontime.py
+++ b/sktime/networks/inceptiontime.py
@@ -24,7 +24,10 @@ class InceptionTimeNetwork(BaseDeepNetwork):
                     ArXiv}, Year                     = {2019} }
     """
 
-    _tags = {"python_dependencies": "tensorflow"}
+    _tags = {
+        "authors": ["hfawaz", "JamesLarge", "Withington"],
+        "python_dependencies": "tensorflow",
+    }
 
     def __init__(
         self,
diff --git a/sktime/networks/mcdcnn.py b/sktime/networks/mcdcnn.py
index 6d82745b7..cd1e8f351 100644
--- a/sktime/networks/mcdcnn.py
+++ b/sktime/networks/mcdcnn.py
@@ -1,6 +1,6 @@
 """Multi Channel Deep Convolution Neural Network (MCDCNN)."""
 
-__author__ = ["James Large", "Withington"]
+__author__ = ["James-Large", "Withington"]
 
 from sktime.networks.base import BaseDeepNetwork
 from sktime.utils.dependencies import _check_dl_dependencies
@@ -10,7 +10,7 @@ class MCDCNNNetwork(BaseDeepNetwork):
     """
     Multi Channel Deep Convolutional Neural Network (MCDCNN).
 
-    Adapted from the implementation from Fawaz et. al:
+    Adapted from the implementation of Fawaz et. al:
     https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mcdcnn.py
 
     Parameters
@@ -35,7 +35,10 @@ class MCDCNNNetwork(BaseDeepNetwork):
         The seed to any random action.
     """
 
-    _tags = {"python_dependencies": "tensorflow"}
+    _tags = {
+        "authors": ["hfawaz", "James-Large", "Withington"],
+        "python_dependencies": "tensorflow",
+    }
 
     def __init__(
         self,
diff --git a/sktime/networks/mlp.py b/sktime/networks/mlp.py
index 6c5912650..dfbccbda0 100644
--- a/sktime/networks/mlp.py
+++ b/sktime/networks/mlp.py
@@ -9,18 +9,16 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class MLPNetwork(BaseDeepNetwork):
     """Establish the network structure for a MLP.
 
-    Adapted from the implementation used in [1]
+    Adapted from the implementation from source code
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
+
+    Implements a simple MLP network, as in [1]_.
 
     Parameters
     ----------
     random_state    : int, default = 0
         seed to any needed random actions
 
-    Notes
-    -----
-    Adapted from the implementation from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
-
     References
     ----------
     .. [1]  Network originally defined in:
@@ -31,7 +29,10 @@ class MLPNetwork(BaseDeepNetwork):
     1578--1585}, year={2017}, organization={IEEE} }
     """
 
-    _tags = {"python_dependencies": "tensorflow"}
+    _tags = {
+        "authors": ["hfawaz", "James-Large", "Withington", "AurumnPegasus"],
+        "python_dependencies": "tensorflow",
+    }
 
     def __init__(
         self,
diff --git a/sktime/networks/resnet.py b/sktime/networks/resnet.py
index 0c5630b1a..53c3f7844 100644
--- a/sktime/networks/resnet.py
+++ b/sktime/networks/resnet.py
@@ -1,6 +1,6 @@
 """Residual Network (ResNet) (minus the final output layer)."""
 
-__author__ = ["James Large", "Withington", "nilesh05apr"]
+__author__ = ["James-Large", "Withington", "nilesh05apr"]
 
 from sktime.networks.base import BaseDeepNetwork
 from sktime.utils.dependencies import _check_dl_dependencies
@@ -9,18 +9,14 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class ResNetNetwork(BaseDeepNetwork):
     """Establish the network structure for a ResNet.
 
-    Adapted from the implementations used in [1]
+    Adapted from the implementation in
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
 
     Parameters
     ----------
     random_state : int, optional (default = 0)
         The random seed to use random activities.
 
-    Notes
-    -----
-    Adapted from the implementation source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
-
     References
     ----------
     .. [1] H. Fawaz, G. B. Lanckriet, F. Petitjean, and L. Idoumghar,
@@ -34,7 +30,10 @@ class ResNetNetwork(BaseDeepNetwork):
     1578--1585}, year={2017}, organization={IEEE} }
     """
 
-    _tags = {"python_dependencies": ["tensorflow", "keras-self-attention"]}
+    _tags = {
+        "authors": ["hfawaz", "James-Large", "Withington", "nilesh05apr"],
+        "python_dependencies": ["tensorflow", "keras-self-attention"],
+    }
 
     def __init__(self, random_state=0):
         _check_dl_dependencies(severity="error")
diff --git a/sktime/regression/deep_learning/cnn.py b/sktime/regression/deep_learning/cnn.py
index de9a0a8f6..a0037ad02 100644
--- a/sktime/regression/deep_learning/cnn.py
+++ b/sktime/regression/deep_learning/cnn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class CNNRegressor(BaseDeepRegressor):
     """Time Series Convolutional Neural Network (CNN), as described in [1].
 
+    Adapted from the implementation from Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/cnn.py
+
     Parameters
     ----------
     n_epochs       : int, default = 2000
@@ -77,7 +80,8 @@ class CNNRegressor(BaseDeepRegressor):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["AurumnPegasus", "achieveordie"],
+        "authors": ["hfawaz", "AurumnPegasus", "achieveordie"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["AurumnPegasus", "achieveordie"],
         "python_dependencies": "tensorflow",
         # estimator type handled by parent class
diff --git a/sktime/regression/deep_learning/cntc.py b/sktime/regression/deep_learning/cntc.py
index 830c9dfa6..03d51830f 100644
--- a/sktime/regression/deep_learning/cntc.py
+++ b/sktime/regression/deep_learning/cntc.py
@@ -12,6 +12,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class CNTCRegressor(BaseDeepRegressor):
     """Contextual Time-series Neural Regressor (CNTC), as described in [1].
 
+    Adapted from the implementation from Fullah et. al
+    https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb
+
     Parameters
     ----------
     n_epochs       : int, default = 2000
@@ -38,11 +41,6 @@ class CNTCRegressor(BaseDeepRegressor):
     optimizer       : keras.optimizer, default=keras.optimizers.Adam(),
     metrics         : list of strings, default=["accuracy"],
 
-    Notes
-    -----
-    Adapted from the implementation from Fullah et. al
-    https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb
-
     References
     ----------
     .. [1] Network originally defined in:
@@ -63,7 +61,12 @@ class CNTCRegressor(BaseDeepRegressor):
     """
 
     _tags = {
-        "authors": ["James-Large", "Withington", "TonyBagnall", "AurumnPegasus"],
+        "authors": [
+            "AmaduFullah",
+            "James-Large",
+            "Withington",
+            "AurumnPegasus",
+        ],
         "maintainers": ["James-Large", "Withington", "AurumnPegasus", "nilesh05apr"],
         "python_dependencies": ["tensorflow", "keras-self-attention"],
     }
diff --git a/sktime/regression/deep_learning/fcn.py b/sktime/regression/deep_learning/fcn.py
index 244de161b..ed3d81dcb 100644
--- a/sktime/regression/deep_learning/fcn.py
+++ b/sktime/regression/deep_learning/fcn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class FCNRegressor(BaseDeepRegressor):
     """Fully Connected Neural Network (FCN), as described in [1]_.
 
+    Adapted from the implementation from Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
+
     Parameters
     ----------
     should inherited fields be listed here?
@@ -38,11 +41,6 @@ class FCNRegressor(BaseDeepRegressor):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-    Notes
-    -----
-    Adapted from the implementation from Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/fcn.py
-
     References
     ----------
     .. [1] Zhao et. al, Convolutional neural networks for time series classification,
@@ -52,7 +50,7 @@ class FCNRegressor(BaseDeepRegressor):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "AurumnPegasus"],
+        "authors": ["hfawaz", "James-Large", "AurumnPegasus"],
         "maintainers": ["James-Large", "AurumnPegasus", "nilesh05apr"],
         # estimator type handled by parent class
     }
diff --git a/sktime/regression/deep_learning/inceptiontime.py b/sktime/regression/deep_learning/inceptiontime.py
index f2b704125..6cd95fce7 100644
--- a/sktime/regression/deep_learning/inceptiontime.py
+++ b/sktime/regression/deep_learning/inceptiontime.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class InceptionTimeRegressor(BaseDeepRegressor):
     """InceptionTime Deep Learning Regressor.
 
+    Adapted from the implementation of Fawaz et. al
+    https://github.com/hfawaz/InceptionTime/blob/master/classifiers/inception.py
+
     Parameters
     ----------
     n_epochs : int, default=1500
@@ -39,15 +42,12 @@ class InceptionTimeRegressor(BaseDeepRegressor):
     -----
     ..[1] Fawaz et. al, InceptionTime: Finding AlexNet for Time Series
     Classification, Data Mining and Knowledge Discovery, 34, 2020
-
-    Adapted from the implementation from Fawaz et. al
-    https://github.com/hfawaz/InceptionTime/blob/master/classifiers/inception.py
     """
 
     _tags = {
         # packaging info
         # --------------
-        "authors": ["james-large"],
+        "authors": ["hfawaz", "james-large"],
         "maintainers": ["james-large", "niles05apr"],
         # estimator type handled by parent class
     }
diff --git a/sktime/regression/deep_learning/mcdcnn.py b/sktime/regression/deep_learning/mcdcnn.py
index 01ea12725..3b235d718 100644
--- a/sktime/regression/deep_learning/mcdcnn.py
+++ b/sktime/regression/deep_learning/mcdcnn.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class MCDCNNRegressor(BaseDeepRegressor):
     """Multi Channel Deep Convolutional Neural Regressor, adopted from [1]_.
 
+    Adapted from the implementation of Fawaz et. al
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mcdcnn.py
+
     Parameters
     ----------
     n_epochs : int, optional (default=120)
@@ -56,11 +59,6 @@ class MCDCNNRegressor(BaseDeepRegressor):
     random_state : int, optional (default=0)
         The seed to any random action.
 
-    Notes
-    -----
-    Adapted from the implementation of Fawaz et. al
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mcdcnn.py
-
     References
     ----------
     .. [1] Zheng et. al, Time series classification using multi-channels deep
@@ -80,7 +78,7 @@ class MCDCNNRegressor(BaseDeepRegressor):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large"],
+        "authors": ["hfawaz", "James-Large"],
         "python_dependencies": "tensorflow",
         # estimator type handled by parent class
     }
diff --git a/sktime/regression/deep_learning/mlp.py b/sktime/regression/deep_learning/mlp.py
index ead20dbd3..ea752b81c 100644
--- a/sktime/regression/deep_learning/mlp.py
+++ b/sktime/regression/deep_learning/mlp.py
@@ -15,6 +15,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class MLPRegressor(BaseDeepRegressor):
     """Multi Layer Perceptron Network (MLP), as described in [1]_.
 
+    Adapted from the implementation by hfawaz in
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
+
     Parameters
     ----------
     should inherited fields be listed here?
@@ -38,11 +41,6 @@ class MLPRegressor(BaseDeepRegressor):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-    Notes
-    -----
-    Adapted from the implementation from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py
-
     References
     ----------
     .. [1] Wang et. al, Time series classification from
@@ -64,7 +62,7 @@ class MLPRegressor(BaseDeepRegressor):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "AurumnPegasus"],
+        "authors": ["hfawaz", "James-Large", "AurumnPegasus"],
         "maintainers": ["James-Large", "AurumnPegasus", "nilesh05apr"],
         # estimator type handled by parent class
     }
diff --git a/sktime/regression/deep_learning/resnet.py b/sktime/regression/deep_learning/resnet.py
index 2a8ce52aa..557b2dc49 100644
--- a/sktime/regression/deep_learning/resnet.py
+++ b/sktime/regression/deep_learning/resnet.py
@@ -14,6 +14,9 @@ from sktime.utils.dependencies import _check_dl_dependencies
 class ResNetRegressor(BaseDeepRegressor):
     """Residual Neural Network Regressor adopted from [1].
 
+    Adapted from the implementation by hfawaz in
+    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
+
     Parameters
     ----------
     n_epochs       : int, default = 1500
@@ -37,12 +40,6 @@ class ResNetRegressor(BaseDeepRegressor):
     optimizer       : keras.optimizers object, default = Adam(lr=0.01)
         specify the optimizer and the learning rate to be used.
 
-
-    Notes
-    -----
-    Adapted from the implementation from source code
-    https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/resnet.py
-
     References
     ----------
         .. [1] Wang et. al, Time series classification from
@@ -62,7 +59,8 @@ class ResNetRegressor(BaseDeepRegressor):
     _tags = {
         # packaging info
         # --------------
-        "authors": ["James-Large", "Withington"],
+        "authors": ["hfawaz", "James-Large", "Withington"],
+        # hfawaz for dl-4-tsc
         "maintainers": ["Withington"],
         "python_dependencies": "tensorflow",
         # estimator type handled by parent class


Test patch:
diff --git a/sktime/detection/tests/test_all_detectors.py b/sktime/detection/tests/test_all_detectors.py
index 335b7b6b1..13ae66282 100644
--- a/sktime/detection/tests/test_all_detectors.py
+++ b/sktime/detection/tests/test_all_detectors.py
@@ -5,6 +5,7 @@ __all__ = []
 
 import pandas as pd
 
+from sktime.detection._datatypes._check import _is_valid_detection
 from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester
 from sktime.utils._testing.detection import make_detection_problem
 from sktime.utils.validation.detection import check_learning_type, check_task
@@ -54,9 +55,21 @@ class TestAllDetectors(DetectorFixtureGenerator, QuickTester):
         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.DataFrame)
-        assert isinstance(y_test.index, pd.RangeIndex)
+        y_pred = estimator.predict(X_test)
+
+        detector_type = estimator.get_tag("task")
+        if detector_type in ["anomaly_detection", "change_point_detection"]:
+            expected_y_pred_type = "points"
+        elif detector_type == "segmentation":
+            expected_y_pred_type = "segments"
+        else:
+            raise ValueError(
+                f"Unknown task tag of {estimator_instance}: {detector_type}, "
+                "expected one of ['anomaly_detection', 'change_point_detection', "
+                f"'segmentation'], but found {detector_type}"
+            )
+
+        assert _is_valid_detection(y_pred, type=expected_y_pred_type), y_pred
 
     def test_transform_output_type(self, estimator_instance):
         """Test output type for the transform method."""
@@ -84,10 +97,7 @@ class TestAllDetectors(DetectorFixtureGenerator, QuickTester):
             estimator_type=estimator_instance.get_tag("distribution_type"),
         )
         y_pred = estimator_instance.predict_points(X_test)
-        assert isinstance(y_pred, pd.DataFrame)
-        assert isinstance(y_pred.index, pd.RangeIndex)
-        assert "ilocs" in y_pred.columns
-        assert pd.api.types.is_integer_dtype(y_pred["ilocs"].dtype), y_pred
+        assert _is_valid_detection(y_pred, type="points"), y_pred
 
     def test_predict_segments(self, estimator_instance):
         X_train = make_detection_problem(
@@ -101,13 +111,7 @@ class TestAllDetectors(DetectorFixtureGenerator, QuickTester):
             estimator_type=estimator_instance.get_tag("distribution_type"),
         )
         y_pred = estimator_instance.predict_segments(X_test)
-        assert isinstance(y_pred, pd.DataFrame)
-        assert isinstance(y_pred.index, pd.RangeIndex)
-        assert "ilocs" in y_pred.columns
-        ilocs_dtype = y_pred["ilocs"].dtype
-        assert isinstance(y_pred["ilocs"].dtype, pd.IntervalDtype) or len(y_pred) == 0
-        if not len(y_pred) == 0:
-            assert pd.api.types.is_integer_dtype(ilocs_dtype.subtype)
+        assert _is_valid_detection(y_pred, type="segments"), y_pred
 
     def test_detector_tags(self, estimator_class):
         """Check the learning_type and task tags are valid."""
diff --git a/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py b/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py
index 1f6d5c928..760818b69 100644
--- a/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py
+++ b/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py
@@ -212,3 +212,34 @@ def test_level_one_data(forecasters, default):
         def_pred = def_frcstr.predict()
         msg = "Node default predictions do not match"
         assert np.all(actual_pred.loc[def_pred.index] == def_pred), msg
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(HierarchyEnsembleForecaster),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_get_fitted_params():
+    """Tests that get_fitted_params works as expected.
+
+    Checks absence of bug #7418.
+    """
+    from sktime.forecasting.compose import HierarchyEnsembleForecaster
+    from sktime.forecasting.naive import NaiveForecaster
+    from sktime.forecasting.trend import PolynomialTrendForecaster, TrendForecaster
+    from sktime.utils._testing.hierarchical import _bottom_hier_datagen
+
+    y = _bottom_hier_datagen(no_bottom_nodes=7, no_levels=2, random_seed=123)
+
+    forecasters = [
+        ("naive", NaiveForecaster(), 0),
+        ("trend", TrendForecaster(), 1),
+    ]
+    forecaster = HierarchyEnsembleForecaster(
+        forecasters=forecasters,
+        by="level",
+        default=PolynomialTrendForecaster(degree=2),
+    )
+    forecaster.fit(y, fh=[1, 2, 3])
+
+    assert forecaster.get_fitted_params()["naive"].is_fitted
+    assert forecaster.get_fitted_params()["trend"].is_fitted