From a2d5688e601688d5aed1e68870da2575aa3592f2 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 15:52:33 +0000 Subject: [PATCH 01/17] add 'similar libraries' section --- .gitignore | 4 ++ README.md | 26 ++++++++++ benchmarks/__init__.py | 8 +++ benchmarks/requirements.txt | 6 +++ benchmarks/run.sh | 19 +++++++ benchmarks/test_aeon.py | 82 ++++++++++++++++++++++++++++++ benchmarks/test_pyts.py | 79 +++++++++++++++++++++++++++++ benchmarks/test_sequentia.py | 61 ++++++++++++++++++++++ benchmarks/test_sktime.py | 98 ++++++++++++++++++++++++++++++++++++ benchmarks/test_tslearn.py | 83 ++++++++++++++++++++++++++++++ benchmarks/utils.py | 60 ++++++++++++++++++++++ 11 files changed, 526 insertions(+) create mode 100644 benchmarks/__init__.py create mode 100644 benchmarks/requirements.txt create mode 100755 benchmarks/run.sh create mode 100644 benchmarks/test_aeon.py create mode 100644 benchmarks/test_pyts.py create mode 100644 benchmarks/test_sequentia.py create mode 100644 benchmarks/test_sktime.py create mode 100644 benchmarks/test_tslearn.py create mode 100644 benchmarks/utils.py diff --git a/.gitignore b/.gitignore index 5025358..4f89515 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,7 @@ venv.bak/ # Changelog entry ENTRY.md + +# Jupyter Notebook +*.ipynb_checkpoints/ +*.ipynb diff --git a/README.md b/README.md index df0fd0c..c4d94de 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,32 @@ Parameter estimation with the Baum-Welch algorithm and prediction with the forwa In most cases, the only necessary change is to add a `lengths` key-word argument to provide sequence length information, e.g. `fit(X, y, lengths=lengths)` instead of `fit(X, y)`. +### Similar libraries + +As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is a comparison of the DTW k-nearest neighbors algorithm features supported Sequentia and similar libraries. + +||**sequentia**|[aeon](https://github.com/aeon-toolkit/aeon)|[tslearn](https://github.com/tslearn-team/tslearn)|[sktime](https://github.com/sktime/sktime)|[pyts](https://github.com/johannfaouzi/pyts)| +|-|:-:|:-:|:-:|:-:|:-:| +|Scikit-Learn compatible|✅|✅|✅|✅|✅| +|Multivariate sequences|✅|✅|✅|✅|❌| +|Variable length sequences|✅|✅|❌1|❌2|❌3| +|No padding required|✅|❌|❌|❌2|❌3| +|Classification|✅|✅|✅|✅|✅| +|Regression|✅|✅|✅|✅|❌| +|Preprocessing|✅|✅|✅|✅|✅| +|Multiprocessing|✅|✅|✅|✅|✅| +|Custom weighting|✅|✅|✅|✅|✅| +|Sakoe-Chiba band constraint|✅|✅|✅|✅|✅| +|Itakura paralellogram constraint|❌|✅|✅|✅|✅| +|Dependent DTW (DTWD)|✅|✅|✅|✅|❌| +|Independent DTW (DTWI)|✅|❌|❌|❌|✅| +|Custom DTW measures|❌4|✅|❌|✅|✅| + +- 1tslearn requires NaN/zero padding for variable length sequences, but doesn't seem to mask the padding. +- 2sktime does not support variable length sequences for kNN, so they must be padded (and padding is not masked). +- 3pyts does not support variable length sequences for kNN, so they must be padded (and padding is not masked). +- 4sequentia only supports [dtaidistance](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries in Python, as it is written in C. + ## Installation The latest stable version of Sequentia can be installed with the following command: diff --git a/benchmarks/__init__.py b/benchmarks/__init__.py new file mode 100644 index 0000000..f8f49c1 --- /dev/null +++ b/benchmarks/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Collection of runtime benchmarks for Python packages +providing dynamic time warping k-nearest neighbors algorithms. +""" diff --git a/benchmarks/requirements.txt b/benchmarks/requirements.txt new file mode 100644 index 0000000..1353452 --- /dev/null +++ b/benchmarks/requirements.txt @@ -0,0 +1,6 @@ +# python==3.12.8 +sequentia==2.1.0 +aeon==1.0.0 +tslearn==0.6.3 +sktime==0.35.0 +pyts==0.13.0 diff --git a/benchmarks/run.sh b/benchmarks/run.sh new file mode 100755 index 0000000..ed732a8 --- /dev/null +++ b/benchmarks/run.sh @@ -0,0 +1,19 @@ +echo "sequentia" +python test_sequentia.py --n-jobs 16 --number 10 +echo + +echo "aeon" +python test_aeon.py --n-jobs 16 --number 10 +echo + +echo "tslearn" +python test_tslearn.py --n-jobs 16 --number 10 +echo + +echo "sktime" +python test_sktime.py --n-jobs 16 --number 10 +echo + +echo "pyts" +python test_pyts.py --n-jobs 16 --number 10 +echo diff --git a/benchmarks/test_aeon.py b/benchmarks/test_aeon.py new file mode 100644 index 0000000..a03f13e --- /dev/null +++ b/benchmarks/test_aeon.py @@ -0,0 +1,82 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Runtime benchmarks for aeon's dynamic time warping +k-nearest neighbors algorithm. +""" + +from __future__ import annotations + +import timeit +import typing as t + +import numpy as np +from aeon.classification.distance_based import KNeighborsTimeSeriesClassifier +from aeon.transformations.collection import Padder +from dtaidistance import dtw_ndim +from utils import load_dataset + +from sequentia.datasets.base import SequentialDataset + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + +DataSplit: t.TypeAlias = tuple[np.ndarray, np.ndarray] + + +def distance(s1: np.ndarray, s2: np.ndarray) -> float: + """DTAIDistance DTW measure - not used.""" + # need to transpose sequences again + return dtw_ndim.distance(s1.T, s2.T, use_c=True) + + +def prepare(data: SequentialDataset) -> DataSplit: + """Prepare the dataset - padding.""" + # transpose sequences and pad + X = [x.T for x, _ in data] + padder = Padder() + X_pad = padder.fit_transform(X) + # X_pad = X_pad.astype("float64") + return X_pad, data.y + + +def run(*, train_data: DataSplit, test_data: DataSplit, n_jobs: int) -> None: + """Fit and predict the classifier.""" + # initialize model + clf = KNeighborsTimeSeriesClassifier( + n_neighbors=1, + n_jobs=n_jobs, + distance="dtw", + # distance=distance, + ) + + # fit model + X_train, y_train = train_data + clf.fit(X_train, y_train) + + # predict model + X_test, _ = test_data + clf.predict(X_test) + + +if __name__ == "__main__": + import argparse + + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument("--n-jobs", type=int, default=1) + parser.add_argument("--number", type=int, default=10) + args: argparse.Namespace = parser.parse_args() + + train_data, test_data = load_dataset(multivariate=False) + train_data, test_data = prepare(train_data), prepare(test_data) + + benchmark = timeit.timeit( + "run(train_data=train_data, test_data=test_data, n_jobs=args.n_jobs)", + globals=locals(), + number=args.number, + ) + + print(args) # noqa: T201 + print(f"{benchmark:.3f}s") # noqa: T201 diff --git a/benchmarks/test_pyts.py b/benchmarks/test_pyts.py new file mode 100644 index 0000000..2da3c57 --- /dev/null +++ b/benchmarks/test_pyts.py @@ -0,0 +1,79 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Runtime benchmarks for pyts's dynamic time warping +k-nearest neighbors algorithm. +""" + +from __future__ import annotations + +import timeit +import typing as t + +import numpy as np +from aeon.transformations.collection import Padder +from pyts.classification import KNeighborsClassifier +from utils import load_dataset + +from sequentia.datasets.base import SequentialDataset + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + +DataSplit: t.TypeAlias = tuple[np.ndarray, np.ndarray] + + +def prepare(data: SequentialDataset, length: int) -> DataSplit: + """Prepare the dataset - pad and flatten.""" + # transpose sequences and pad + X = [x.T for x, _ in data] + padder = Padder(pad_length=length) + X_pad = padder.fit_transform(X) + return X_pad[:, 0], data.y + + +def multivariate( + *, train_data: DataSplit, test_data: DataSplit, n_jobs: int +) -> None: + """Fit and predict the classifier.""" + # initialize model + clf = KNeighborsClassifier( + n_neighbors=1, + n_jobs=n_jobs, + metric="dtw", + ) + + # fit model + X_train, y_train = train_data + clf.fit(X_train, y_train) + + # predict model + X_test, _ = test_data + clf.predict(X_test) + + +if __name__ == "__main__": + import argparse + + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument("--n-jobs", type=int, default=1) + parser.add_argument("--number", type=int, default=10) + args: argparse.Namespace = parser.parse_args() + + train_data, test_data = load_dataset(multivariate=False) + length = max(train_data.lengths.max(), test_data.lengths.max()) + train_data, test_data = ( + prepare(train_data, length=length), + prepare(test_data, length=length), + ) + + benchmark = timeit.timeit( + "func(train_data=train_data, test_data=test_data, n_jobs=args.n_jobs)", + globals=locals(), + number=args.number, + ) + + print(args) # noqa: T201 + print(f"{benchmark:.3f}s") # noqa: T201 diff --git a/benchmarks/test_sequentia.py b/benchmarks/test_sequentia.py new file mode 100644 index 0000000..8ba7e45 --- /dev/null +++ b/benchmarks/test_sequentia.py @@ -0,0 +1,61 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Runtime benchmarks for sequentia's dynamic time warping +k-nearest neighbors algorithm. +""" + +from __future__ import annotations + +import timeit + +import numpy as np +from utils import load_dataset + +import sequentia +from sequentia.datasets.base import SequentialDataset + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + + +def multivariate( + *, train_data: SequentialDataset, test_data: SequentialDataset, n_jobs: int +) -> None: + """Fit and predict the classifier.""" + # initialize model + clf = sequentia.models.KNNClassifier( + k=1, + use_c=True, + n_jobs=n_jobs, + random_state=random_state, + classes=train_data.classes, + ) + + # fit model + clf.fit(X=train_data.X, y=train_data.y, lengths=train_data.lengths) + + # predict model + clf.predict(X=test_data.X, lengths=test_data.lengths) + + +if __name__ == "__main__": + import argparse + + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument("--n-jobs", type=int, default=1) + parser.add_argument("--number", type=int, default=10) + args: argparse.Namespace = parser.parse_args() + + train_data, test_data = load_dataset(multivariate=False) + + benchmark = timeit.timeit( + "func(train_data=train_data, test_data=test_data, n_jobs=args.n_jobs)", + globals=locals(), + number=args.number, + ) + + print(args) # noqa: T201 + print(f"{benchmark:.3f}s") # noqa: T201 diff --git a/benchmarks/test_sktime.py b/benchmarks/test_sktime.py new file mode 100644 index 0000000..e335a13 --- /dev/null +++ b/benchmarks/test_sktime.py @@ -0,0 +1,98 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Runtime benchmarks for sktime's dynamic time warping +k-nearest neighbors algorithm. +""" + +from __future__ import annotations + +import timeit +import typing as t + +import numpy as np +import pandas as pd +from dtaidistance import dtw_ndim +from sktime.classification.distance_based import KNeighborsTimeSeriesClassifier +from utils import load_dataset + +from sequentia.datasets.base import SequentialDataset + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + +DataSplit: t.TypeAlias = tuple[pd.Series, np.ndarray] + + +def distance(s1: pd.Series, s2: pd.Series) -> np.ndarray: + """DTAIDistance DTW measure - not used.""" + s1, s2 = s1.droplevel(1), s2.droplevel(1) + m = s1.index.max() + 1 + n = s2.index.max() + 1 + matrix = np.zeros((m, n)) + for i in range(m): + a = np.trim_zeros(s1.loc[i].to_numpy(dtype=np.float64)) + for j in range(n): + b = np.trim_zeros(s2.loc[j].to_numpy(dtype=np.float64)) + matrix[i][j] = dtw_ndim.distance(a, b, use_c=True) + return matrix + + +def pad(x: np.ndarray, length: int) -> np.ndarray: + """Pad a sequence with zeros.""" + return np.concat((x, np.zeros((length - len(x), x.shape[-1])))) + + +def prepare(data: SequentialDataset) -> DataSplit: + """Prepare the dataset - pad and convert to multi-indexed + Pandas DataFrame. + """ + # convert to padded pandas multi-index + length = data.lengths.max() + X = [pd.DataFrame(pad(x, length=length)) for x, _ in data] + X_pd = pd.concat(X, keys=range(len(X)), axis=0) + return X_pd, data.y + + +def multivariate( + *, train_data: DataSplit, test_data: DataSplit, n_jobs: int +) -> None: + """Fit and predict the classifier.""" + # initialize model + clf = KNeighborsTimeSeriesClassifier( + n_neighbors=1, + n_jobs=n_jobs, + distance="dtw", + # distance=distance, + ) + + # fit model + X_train, y_train = train_data + clf.fit(X_train, y_train) + + # predict model + X_test, _ = test_data + clf.predict(X_test) + + +if __name__ == "__main__": + import argparse + + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument("--n-jobs", type=int, default=1) + parser.add_argument("--number", type=int, default=10) + args: argparse.Namespace = parser.parse_args() + + train_data, test_data = load_dataset(multivariate=False) + train_data, test_data = prepare(train_data), prepare(test_data) + + benchmark = timeit.timeit( + "func(train_data=train_data, test_data=test_data, n_jobs=args.n_jobs)", + globals=locals(), + number=args.number, + ) + + print(args) # noqa: T201 + print(f"{benchmark:.3f}s") # noqa: T201 diff --git a/benchmarks/test_tslearn.py b/benchmarks/test_tslearn.py new file mode 100644 index 0000000..b8e0306 --- /dev/null +++ b/benchmarks/test_tslearn.py @@ -0,0 +1,83 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Runtime benchmarks for tslearn's dynamic time warping +k-nearest neighbors algorithm. +""" + +from __future__ import annotations + +import timeit +import typing as t + +import numpy as np +from aeon.transformations.collection import Padder +from dtaidistance import dtw_ndim +from tslearn.neighbors import KNeighborsTimeSeriesClassifier +from utils import load_dataset + +from sequentia.datasets.base import SequentialDataset + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + +DataSplit: t.TypeAlias = tuple[np.ndarray, np.ndarray] + + +def distance(s1: np.ndarray, s2: np.ndarray) -> float: + """DTAIDistance DTW measure - not used.""" + return dtw_ndim.distance(s1, s2, use_c=True) + + +def prepare(data: SequentialDataset, length: int) -> DataSplit: + """Prepare the dataset - padding.""" + # pad sequences - zeros/nans are not ignored (!!!) + X = [x.T for x, _ in data] + padder = Padder(pad_length=length) + X_pad = padder.fit_transform(X) + # X_pad[(X_pad == 0).all(axis=1, keepdims=True)] = np.nan + return X_pad, data.y + + +def run(*, train_data: DataSplit, test_data: DataSplit, n_jobs: int) -> None: + """Fit and predict the classifier.""" + # initialize model + clf = KNeighborsTimeSeriesClassifier( + n_neighbors=1, + n_jobs=n_jobs, + ) + + # fit model + X_train, y_train = train_data + clf.fit(X_train, y_train) + + # predict model + X_test, _ = test_data + clf.predict(X_test) + + +if __name__ == "__main__": + import argparse + + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument("--n-jobs", type=int, default=1) + parser.add_argument("--number", type=int, default=10) + args: argparse.Namespace = parser.parse_args() + + train_data, test_data = load_dataset(multivariate=False) + length = max(train_data.lengths.max(), test_data.lengths.max()) + train_data, test_data = ( + prepare(train_data, length=length), + prepare(test_data, length=length), + ) + + benchmark = timeit.timeit( + "run(train_data=train_data, test_data=test_data, n_jobs=args.n_jobs)", + globals=locals(), + number=args.number, + ) + + print(args) # noqa: T201 + print(f"{benchmark:.3f}s") # noqa: T201 diff --git a/benchmarks/utils.py b/benchmarks/utils.py new file mode 100644 index 0000000..7a52713 --- /dev/null +++ b/benchmarks/utils.py @@ -0,0 +1,60 @@ +# Copyright (c) 2019 Sequentia Developers. +# Distributed under the terms of the MIT License (see the LICENSE file). +# SPDX-License-Identifier: MIT +# This source code is part of the Sequentia project (https://github.com/eonu/sequentia). + +"""Utilities for benchmarking.""" + +from __future__ import annotations + +import numpy as np + +from sequentia.datasets.base import SequentialDataset +from sequentia.datasets.digits import load_digits + +__all__ = ["load_dataset"] + +np.random.seed(0) +random_state: np.random.RandomState = np.random.RandomState(0) + + +def load_dataset( + *, multivariate: bool +) -> tuple[SequentialDataset, SequentialDataset]: + """Loads the Free Spoken Digit Dataset.""" + # load data + data: SequentialDataset = load_digits() + + # split dataset + train_data, test_data = data.split( + test_size=0.5, + random_state=random_state, + shuffle=True, + stratify=True, + ) + + if multivariate: + # return untransformed data + return train_data, test_data + + # retrieve features + X_train, X_test = train_data.X, test_data.X + + # reduce to one dimension + X_train = X_train.mean(axis=-1, keepdims=True) + X_test = X_test.mean(axis=-1, keepdims=True) + + # return splits + train_split: SequentialDataset = SequentialDataset( + X=X_train, + y=train_data.y, + lengths=train_data.lengths, + classes=train_data.classes, + ) + test_split: SequentialDataset = SequentialDataset( + X=X_test, + y=test_data.y, + lengths=test_data.lengths, + classes=test_data.classes, + ) + return train_split, test_split From 7691b574e195d341b26d0a9acbdd3158bb9304c9 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:05:05 +0000 Subject: [PATCH 02/17] add plot --- .gitignore | 3 +- README.md | 42 +- benchmarks/benchmark.svg | 1625 ++++++++++++++++++++++++++++++++++++++ benchmarks/plot.ipynb | 104 +++ 4 files changed, 1765 insertions(+), 9 deletions(-) create mode 100644 benchmarks/benchmark.svg create mode 100644 benchmarks/plot.ipynb diff --git a/.gitignore b/.gitignore index 4f89515..b953c5e 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,5 @@ venv.bak/ # Changelog entry ENTRY.md -# Jupyter Notebook +# Jupyter Notebook checkpoints *.ipynb_checkpoints/ -*.ipynb diff --git a/README.md b/README.md index c4d94de..d0d1359 100644 --- a/README.md +++ b/README.md @@ -98,14 +98,14 @@ In most cases, the only necessary change is to add a `lengths` key-word argument ### Similar libraries -As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is a comparison of the DTW k-nearest neighbors algorithm features supported Sequentia and similar libraries. +As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is a comparison of the DTW k-nearest neighbors algorithm features supported by Sequentia and similar libraries. ||**sequentia**|[aeon](https://github.com/aeon-toolkit/aeon)|[tslearn](https://github.com/tslearn-team/tslearn)|[sktime](https://github.com/sktime/sktime)|[pyts](https://github.com/johannfaouzi/pyts)| |-|:-:|:-:|:-:|:-:|:-:| |Scikit-Learn compatible|✅|✅|✅|✅|✅| |Multivariate sequences|✅|✅|✅|✅|❌| -|Variable length sequences|✅|✅|❌1|❌2|❌3| -|No padding required|✅|❌|❌|❌2|❌3| +|Variable length sequences|✅|✅|➖1|❌2|❌3| +|No padding required|✅|❌|➖1|❌2|❌3| |Classification|✅|✅|✅|✅|✅| |Regression|✅|✅|✅|✅|❌| |Preprocessing|✅|✅|✅|✅|✅| @@ -117,10 +117,38 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is |Independent DTW (DTWI)|✅|❌|❌|❌|✅| |Custom DTW measures|❌4|✅|❌|✅|✅| -- 1tslearn requires NaN/zero padding for variable length sequences, but doesn't seem to mask the padding. -- 2sktime does not support variable length sequences for kNN, so they must be padded (and padding is not masked). -- 3pyts does not support variable length sequences for kNN, so they must be padded (and padding is not masked). -- 4sequentia only supports [dtaidistance](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries in Python, as it is written in C. +- 1tslearn supports variable length sequences with padding, but doesn't seem to mask the padding. +- 2sktime does not support variable length sequences so they must be padded (and padding is not masked). +- 3pyts does not support variable length sequences so they must be padded (and padding is not masked). +- 4sequentia only supports [dtaidistance](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. + +#### Benchmarks + + + +To compare the above libraries in runtime performance on dynamic time warping k-nearest neighbors classification tasks, a simple benchmark was performed on a univariate sequence dataset. + +The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/sections/datasets/digits.html) was used for benchmarking and consists of: + +- 3000 recordings of 10 spoken digits (0-9) + - 50 recordings of each digit for each of 6 speakers + - 1500 used for training, 1500 used for testing (split via label stratification) +- 13 features ([MFCCs](https://en.wikipedia.org/wiki/Mel-frequency_cepstrum)) + - Only the first feature was used as not all of the libraries support multivariate sequences +- Sequence length statistics: + - Minimum: 6 + - Median: 17 + - Maximum: 92 + +Each result measures the total time taken to complete training and prediction repeated 10 times on the above train/test split. + +All of the above libraries support multiprocessing, and prediction was performed using 16 workers. + +> **Device information**: +> - Processor: AMD Ryzen™ AI 7 PRO 360 +> - Memory: 64 GB LPDDR5X-7500MHz (8 cores, 16 threads, 2-5GHz) +> - Solid State Drive: 1 TB SSD M.2 2280 PCIe Gen4 Performance TLC Opal +> - Operating system: Fedora Linux 41 (Workstation Edition) ## Installation diff --git a/benchmarks/benchmark.svg b/benchmarks/benchmark.svg new file mode 100644 index 0000000..18bf63f --- /dev/null +++ b/benchmarks/benchmark.svg @@ -0,0 +1,1625 @@ + + + + + + + + 2024-12-24T17:02:41.891473 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/benchmarks/plot.ipynb b/benchmarks/plot.ipynb new file mode 100644 index 0000000..3ccb463 --- /dev/null +++ b/benchmarks/plot.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "ed902379-677e-4c90-aa1c-95ef9dbb1d11", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "plt.style.use(\"ggplot\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c92bf960-ddb5-409f-bd3c-5bce0a03ccd0", + "metadata": {}, + "outputs": [], + "source": [ + "from sequentia import" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "6649bf2d-7430-401d-8113-f3c1e1cf4779", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(5, 4))\n", + "\n", + "runtimes = [31.871, 828.855, 887.367, 1210.012, 2778.706]\n", + "labels = [\"sequentia\", \"sktime*\", \"aeon\", \"tslearn*\", \"pyts*\"]\n", + "\n", + "bars = ax.bar(labels, runtimes, width=0.5, color=\"C1\")\n", + "ax.set(xlabel=\"Package\", ylabel=\"Runtime (s)\")\n", + "ax.set_title(\"Univariate DTW-kNN performance\\n(1,500 FSDD train/test sequences, 16 workers)\", fontsize=11)\n", + "\n", + "def fmt(s: float) -> str:\n", + " if s < 60:\n", + " return f\"{round(s)}s\"\n", + " m, s = divmod(s, 60)\n", + " return f\"{round(m)}m {round(s)}s\"\n", + "\n", + "for bar in bars:\n", + " plt.text(\n", + " bar.get_x() + bar.get_width() / 2, bar.get_height(),\n", + " fmt(bar.get_height()), ha='center', va='bottom', fontsize=9,\n", + " )\n", + "\n", + "for lab in ax.get_xticklabels():\n", + " if lab.get_text() == \"sequentia\":\n", + " lab.set_fontweight('bold')\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(\"benchmark.svg\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07aeb22f-d8be-4759-9012-1a3e9479343a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 528f3d0a553497730deebb2f7ea7a7a40deb22e6 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:06:56 +0000 Subject: [PATCH 03/17] adjust plot --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d0d1359..e313374 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,6 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is #### Benchmarks - - To compare the above libraries in runtime performance on dynamic time warping k-nearest neighbors classification tasks, a simple benchmark was performed on a univariate sequence dataset. The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/sections/datasets/digits.html) was used for benchmarking and consists of: @@ -134,12 +132,14 @@ The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/secti - 50 recordings of each digit for each of 6 speakers - 1500 used for training, 1500 used for testing (split via label stratification) - 13 features ([MFCCs](https://en.wikipedia.org/wiki/Mel-frequency_cepstrum)) - - Only the first feature was used as not all of the libraries support multivariate sequences + - Only the first feature was used as not all of the above libraries support multivariate sequences - Sequence length statistics: - Minimum: 6 - Median: 17 - Maximum: 92 + + Each result measures the total time taken to complete training and prediction repeated 10 times on the above train/test split. All of the above libraries support multiprocessing, and prediction was performed using 16 workers. From d0911a3caab6c6762063f928e1bf51bebede6788 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:06:56 +0000 Subject: [PATCH 04/17] adjust plot --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d0d1359..6f2ae85 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,6 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is #### Benchmarks - - To compare the above libraries in runtime performance on dynamic time warping k-nearest neighbors classification tasks, a simple benchmark was performed on a univariate sequence dataset. The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/sections/datasets/digits.html) was used for benchmarking and consists of: @@ -134,7 +132,7 @@ The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/secti - 50 recordings of each digit for each of 6 speakers - 1500 used for training, 1500 used for testing (split via label stratification) - 13 features ([MFCCs](https://en.wikipedia.org/wiki/Mel-frequency_cepstrum)) - - Only the first feature was used as not all of the libraries support multivariate sequences + - Only the first feature was used as not all of the above libraries support multivariate sequences - Sequence length statistics: - Minimum: 6 - Median: 17 @@ -144,6 +142,8 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. + + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 > - Memory: 64 GB LPDDR5X-7500MHz (8 cores, 16 threads, 2-5GHz) From 71cb150ed4be7d59874197d10070d597f6ca544d Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:10:42 +0000 Subject: [PATCH 05/17] split processor details --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f2ae85..06ebb74 100644 --- a/README.md +++ b/README.md @@ -142,11 +142,13 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. - + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 -> - Memory: 64 GB LPDDR5X-7500MHz (8 cores, 16 threads, 2-5GHz) +> - 8 cores, 16 threads +> - 2-5GHz +> - Memory: 64 GB LPDDR5X-7500MHz > - Solid State Drive: 1 TB SSD M.2 2280 PCIe Gen4 Performance TLC Opal > - Operating system: Fedora Linux 41 (Workstation Edition) From 4e54c636b2f6c6ba9d00e200235e505f42a9310b Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:14:23 +0000 Subject: [PATCH 06/17] no align --- README.md | 2 +- benchmarks/benchmark.svg | 364 +++++++++++++++++++-------------------- benchmarks/plot.ipynb | 10 +- 3 files changed, 186 insertions(+), 190 deletions(-) diff --git a/README.md b/README.md index 06ebb74..006ac4b 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. - + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 diff --git a/benchmarks/benchmark.svg b/benchmarks/benchmark.svg index 18bf63f..3f9a775 100644 --- a/benchmarks/benchmark.svg +++ b/benchmarks/benchmark.svg @@ -1,12 +1,12 @@ - + - 2024-12-24T17:02:41.891473 + 2024-12-24T17:13:37.655962 image/svg+xml @@ -22,8 +22,8 @@ @@ -31,32 +31,32 @@ z - + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + +L 565.2 243.16 +" clip-path="url(#pfaca7e0435)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -800,18 +800,18 @@ z - + - + - + - + - + - + - + - + - + @@ -905,18 +905,18 @@ L 349.2 137.667937 - + - + - + - + - + - + @@ -973,7 +973,7 @@ L 349.2 67.339895 - + - +" clip-path="url(#pfaca7e0435)" style="fill: #348abd"/> - +" clip-path="url(#pfaca7e0435)" style="fill: #348abd"/> - +" clip-path="url(#pfaca7e0435)" style="fill: #348abd"/> - +" clip-path="url(#pfaca7e0435)" style="fill: #348abd"/> - +" clip-path="url(#pfaca7e0435)" style="fill: #348abd"/> - - - + - + - + - + @@ -1270,7 +1270,7 @@ z - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/benchmarks/plot.ipynb b/benchmarks/plot.ipynb index 3ccb463..9cf0eb1 100644 --- a/benchmarks/plot.ipynb +++ b/benchmarks/plot.ipynb @@ -25,15 +25,15 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 79, "id": "6649bf2d-7430-401d-8113-f3c1e1cf4779", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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RERUWVWoKxbHjx8H3j8EL6/Ro0fDy8sLKioquHv3LoKDg5GRkQFjY2M0atQIPXv2FMsqKSlh+vTp2LhxI2bNmgV1dXV4enrKPPfCzMwM06dPR2BgIIKDg2FsbIxRo0bxGRZERERERHKSCJXl2koFFBcXJzNa1OdKIpHAwsIC0dHRleZSHZUvthmSB9sNyYPtpvLotv1heYdQYe0f4FRudauqqpb4HosK1RWKiIiIiIgqJyYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMCYWRERERESkMJXyDiCvvXv34sqVK4iKioKamhocHR0xcOBAWFpaimUyMzOxdetWXLp0CVlZWXB3d8eIESNgYGAglomPj8eGDRsQEhICDQ0NeHp6on///lBWVhbLhISEYOvWrXjx4gWMjY3Rq1cveHl5/ef7TERERET0KahQVyzu378PHx8fBAQEYNasWcjOzsaCBQuQnp4ulgkMDMT169cxefJkzJs3D4mJiVi+fLm4PCcnB4sWLYJUKsWCBQswZswYnD17Fjt37hTLxMbGYvHixXBxccHSpUvRqVMnrFu3Drdu3frP95mIiIiI6FNQoRILf39/eHl5oVq1arCxscGYMWMQHx+PsLAwAEBaWhpOnz6NwYMHw9XVFXZ2dhg9ejQePXqE0NBQAMDt27cRGRmJcePGwcbGBh4eHvDz88OxY8cglUoBAMePH4eZmRkGDRoEKysrtG/fHo0bN8bhw4fLdf+JiIiIiCqrCtUV6kNpaWkAAB0dHQBAWFgYsrOz4ebmJpapWrUqTExMEBoaCkdHR4SGhsLa2lqma1SdOnWwceNGvHjxAra2tnj8+LHMNgDA3d0dW7ZsKTCOrKwsZGVlidMSiQSampri35+73GPAY0ElxTZD8mC7IXmw3dCnoLK03wqbWOTk5GDLli2oWbMmrK2tAQBJSUlQUVGBtra2TFl9fX0kJSWJZfImFbnLc5fl/s6dl7fMu3fvkJmZCTU1NZlle/fuxe7du8VpW1tbLFmyBKampmW6z5Wdubl5eYdAlQzbDMmD7YbkwXZTGTwo7wAqLAsLi/IOoUQqbGKxadMmvHjxAvPnzy/vUNCjRw907txZnM7NGuPi4sTuVZ8ziUQCc3NzxMTEQBCE8g6HKgG2GZIH2w3Jg+2GPgXR0dHlVreKikqJv0yvkInFpk2bcOPGDcybNw/GxsbifAMDA0ilUqSmpspctXjz5o14lcLAwABPnjyR2d6bN2/EZbm/c+flLaOpqZnvagUAqKqqQlVVtcBYeZL6H0EQeDyoVNhmSB5sNyQPthuqzCpL261QN28LgoBNmzbhypUrmD17NszMzGSW29nZQVlZGXfv3hXnvXz5EvHx8XB0dAQAODo6IiIiQiZxuHPnDjQ1NWFlZQUAcHBwkNlGbpncbRARERERUelUqMRi06ZNOH/+PCZMmABNTU0kJSUhKSkJmZmZAAAtLS20bt0aW7duxb179xAWFoa1a9fC0dFRTArc3d1hZWWF1atXIzw8HLdu3cKOHTvg4+MjXnVo164dYmNjsW3bNkRFReHYsWO4fPkyOnXqVK77T0RERERUWUmECnRtxdfXt8D5o0ePFh9el/uAvIsXL0IqlRb4gLy4uDhs3LgRISEhUFdXh6enJwYMGJDvAXmBgYGIjIyU+wF5cXFxMqNFfa4kEgksLCwQHR1daS7VUflimyF5sN2QPNhuKo9u2x+WdwgV1v4BTuVWt6qqaonvsahQiUVlw8Ti//GkTaXFNkPyYLshebDdVB5MLApXWRKLCtUVioiIiIiIKicmFkREREREpDAmFkREREREpDAmFkREREREpLBSPyAvNjYW165dw8OHDxEVFYXk5GRIJBLo6uqiatWqcHJyQv369fM9g4KIiIiIiD5dJU4srl+/joMHD+Lhw4cQBAHm5uYwMzNDtWrVAACpqal4/vw5/v33XwQGBsLJyQldu3ZFvXr1Pmb8RERERERUAZQosfD390d4eDgaNGiASZMmwc3NDVpaWgWWTUtLw507d/DPP//gxx9/RPXq1REQEFDWcRMRERERUQVSosTCxcUFU6dOlXkIXWG0tLTQuHFjNG7cGElJSQgODi6LOImIiIiIqAIrUWLRv39/uTZuYGAg97pERERERFR5cFQoIiIiIiJSWKlHhQKAu3fv4tmzZ+jatas47/Tp0wgKCoJUKkWzZs0waNAgKCkxbyEiIiIi+hzI9ck/KCgI4eHh4nRERAQ2bNgAPT091KpVC0eOHMGBAwfKMk4iIiIiIqrA5EosoqKiYG9vL06fO3cOmpqamD9/PiZNmoQ2bdrg3LlzZRknERERERFVYHIlFunp6dDU1BSnb926hTp16kBdXR0AUKNGDcTFxZVdlEREREREVKHJlViYmJjg6dOnAICYmBi8ePECtWvXFpenpKRAVVW17KIkIiIiIqIKTa6bt5s3b47du3cjISEBkZGR0NbWRoMGDcTlYWFhsLCwKMs4iYiIiIioApMrsejZsyekUilu3rwJExMTjB49Gtra2sD7qxUhISHo2LFjWcdKREREREQVlFyJhbKyMvr164d+/frlW6ajo4MNGzaURWxERERERFRJ8EETRERERESksBIlFr/++itiY2NLvfGYmBj8+uuv8sRFRERERESVSIm6Qr1+/RoTJkyAm5sbmjZtCldXV5iYmBRYNjY2Fnfv3sXly5cREhIiM1oUERERERF9mkqUWMyYMQMPHz7EwYMHsX79euTk5EBXVxempqbQ0dGBIAhITU1FbGwsUlJSoKSkBA8PD8yZMwdOTk4ffy+IiIiIiKhclfjmbScnJzg5OSE5ORnXr19HaGgoXr58idevXwMAdHV10bBhQzg6OqJu3brQ19f/mHETEREREVEFUupRofT09NCqVSu0atXq40RERERERESVDkeFIiIiIiIihTGxICIiIiIihTGxICIiIiIihTGxICIiIiIihTGxICIiIiIihTGxICIiIiIihZV6uNm8QkNDERISgjdv3sDHxwcWFhbIyMhAVFQULC0toaGhUXaREhERERFRhSVXYiGVSvHTTz/h6tWr4rz69evDwsICEokEAQEB6NSpE3r27FmWsRIRERERUQUlV1eoHTt24Pr16xg5ciR++uknmWVqampo3LixTNJB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bRrq168PDQ0NDB06tEyHel25ciVWrFghTtvb26NJkybi8PpF1f/27VvMnz8fz58/h6qqKurWrYvFixeXWWxElZFEEAShtCuNGzcO3t7e6Nq168eJqpKIi4tDVlZWeYdR7iQSCSwsLBAdHQ05mhN9hthmSB5sNyQPtpvKo9v2h+UdQoW1f8B/0wWwIKqqqjA1NS1RWbmevN2tWzecOnUKaWlp8qxORERERESfGLm6QqWnp0NDQwPjx49H06ZNYWJiIo7ikFfnzp3LIkYiIiIiIqrg5Eosfv/9d/HvY8eOFVqOiQUREdHnqWJ1a3lQ3gGIyrNLC9HHJldisXr16rKPhIiIiIiIKi25EouS3sBBRERERESfB7lu3iYiIiIiIspLrisWY8aMgUQiKbKMRCLBzz//LG9cRERERERUiciVWNSqVStfYpGTk4O4uDg8evQI1apVg62tbVnFSEREREREFZzcVywKEx4ejoCAADRv3lyRuIiIiIiIqBIp83ssbGxs4O3tje3bt5f1pomIiIiIqIL6KDdv6+vrIzIy8mNsmoiIiIiIKqAyTyzevn2L06dPw9jYuKw3TUREREREFZRc91jMmzevwPlpaWmIioqCVCrF2LFjFY2NiIiIiIgqCbkSC0EQChxu1tTUFG5ubmjVqhWqVq1aFvEREREREVElIFdiMXfu3GLLFJZ8EBERERHRp6fM77GQSqU4efIkJk6cWNabJiIiIiKiCqpUVyykUimuXbuGmJgY6OjooG7dujAyMgIAZGRk4OjRowgODkZSUhKqVKnysWImIiIiIqIKpsSJRUJCAubNm4eYmBhxnpqaGr799luoqKhg1apVSEhIQI0aNTB06FA0atToY8VMREREREQVTIkTix07diA2NhbdunWDk5MTYmNj8ddff+HXX39FcnIyqlWrhnHjxqFWrVofN2IiIiIiIqpwSpxY3LlzB15eXujfv784z8DAAD/++CM8PDzw7bffQknpozxvj4iIiIiIKrgSJxZv3ryBg4ODzDxHR0cAQOvWrcskqbh//z4OHDiAZ8+eITExEVOmTEHDhg3F5YIgYNeuXTh16hRSU1Ph5OSEESNGwMLCQiyTkpKCzZs34/r165BIJGjUqBGGDh0KDQ0Nsczz58+xadMmPH36FHp6emjfvj26deumcPxERERERJ+rEmcDOTk5UFNTk5mnqqoKANDS0iqTYDIyMmBjY4Phw4cXuHz//v04cuQIRo4ciYULF0JdXR0BAQHIzMwUy6xatQovXrzArFmzMH36dDx48ADr168Xl6elpWHBggUwMTHB4sWLMXDgQAQFBeHkyZNlsg9ERERERJ+jUo0KFRsbi7CwMHE6LS0NABAdHV1gcmFnZ1eqYDw8PODh4VHgMkEQEBwcjJ49e6JBgwYAgLFjx2LkyJG4evUqmjVrhsjISNy6dQuLFi2Cvb09AGDYsGFYtGgRvvjiCxgZGeHChQuQSqUYPXo0VFRUUK1aNYSHh+PQoUNo27ZtqeIlIiIiIqL/V6rEYufOndi5c2e++Rs3biy0fFmJjY1FUlISateuLc7T0tJCjRo1EBoaimbNmiE0NBTa2tpiUgEAbm5ukEgkePLkCRo2bIjQ0FA4OztDReV/u+7u7o79+/cjJSUFOjo6+erOyspCVlaWOC2RSKCpqSn+/bnLPQY8FlRSbDMkD7Yb+hSw/ZI8Kku7KXFi8fXXX3/cSIqRlJQEANDX15eZr6+vLy5LSkqCnp6ezHJlZWXo6OjIlDEzM5MpY2BgIC4rKLHYu3cvdu/eLU7b2tpiyZIlMDU1LbP9+xSYm5uXdwhUybDNfDpWr16NLVu24O7du+jQoQP27dtXYLlXr17B2dkZ1tbWuHXrllx1FdVuCtr++fPn0aFDB5lyaWlpGDt2LFatWiVXDFQSD8o7gAop732h9CG2mcJUlnZT4sTCy8vr40ZSgfXo0QOdO3cWp3Ozxri4OEil0nKMrGKQSCQwNzdHTEwMBEEo73CoEmCb+fRoampi9OjROH/+PKKjoxEdHV1guS+//BIuLi5ISEgotExhStJuCtp+jRo18PjxY7FMXFwc6tWrh7Zt25Y6BiJFsc2RPMqz3aioqJT4y/RSdYUqT7lXFd68eQNDQ0Nx/ps3b2BjYyOWSU5OllkvOzsbKSkp4voGBgbi1YtcudO5ZT6kqqoq3qj+IX4o+h9BEHg8qFTYZj4duVcEQkJCEB0dXeD/9dixY0hMTESvXr2wceNGscyLFy/QuHFjLF++HCtXrkR8fDwGDx6MkSNHYsKECbh58yZcXV2xbt06mJubF9puCtv+h3bt2gVbW1vUr18fgiAgIyMDM2bMwPHjxyGVSmFpaYkVK1agTp06ZX6ciHjOI3lUlnZTaR48YWZmBgMDA9y9e1ecl5aWhidPnojD3jo6OiI1NVXmBvN79+5BEATUqFFDLPPgwQOZKw137tyBpaVlgd2giIhIccnJyZg3bx4WL15caJmLFy/i1KlTOHz4MDZt2oRRo0Zh3rx5uHPnDlRVVYvstlSS7efasWMH+vbtK04HBQXh/v37uHjxIh48eIANGzawqysRkRwqVGKRnp6O8PBwhIeHA+9v2A4PD0d8fDwkEgk6duyIPXv24Nq1a4iIiMDq1athaGgojhJlZWWFOnXqYP369Xjy5AkePnyIzZs3o2nTpjAyMgIANG/eHCoqKli3bh1evHiBS5cu4ciRIzJdnYiIqGwtWLAAffr0KXK0wAkTJkBLSwuOjo6oVasWGjZsiJo1a0JdXR3t27eX+WJJnu0DwL///ouIiAj06dNHnKeqqoqUlBQ8fvwYgiDA3t4eVatWlXNPiYg+XxWqK9TTp08xb948cXrr1q0AAE9PT4wZMwbdunVDRkYG1q9fj7S0NDg5OWHmzJkyz9cYP348Nm3ahPnz54sPyBs2bJi4XEtLC7NmzcKmTZswffp06OrqolevXhxqlojoI/n3339x7do1HD16tMhyea8SaGpqwsTERGY6NTVVoe0DwJ9//glvb28YGxuL83r16oVXr15h+vTpiI6Ohre3N2bPni1+IUVERCVToRILFxcX7Nq1q9DlEokEfn5+8PPzK7SMjo4OJkyYUGQ91atXx/z58xWKlehT9dtvv2HXrl14+PAhWrVqhc2bN8ssHzlyJK5du4a0tDQYGhqib9++mDhxYpnHERcXBy8vL1haWuLEiRPi/HPnziEgIADPnj2DpaUl5syZg1atWpV5/VR2Lly4gOfPn6Nu3boAgMzMTKSnp8PV1RWnTp366NuvUqUKAODt27c4dOgQNmzYILO+iooKxo8fj/HjxyMuLg6jR4/GihUrsGDBAoVjIyL6nFSoxIKIyl+VKlUwYcIEcXSfD02ePBl2dnZQV1dHVFQUBgwYgGrVqqFXr15lGoe/vz9cXFyQmJgoznv+/DmGDx+OtWvXok2bNjh16hRGjhyJU6dOoXr16mVaP5WOVCoVf3JycpCeng4lJSWoqanhyy+/RL9+/cSyhw4dwp9//ont27fDxMQEL1++VKju4rafa9++fTA0NISnp6fM+hcuXICBgQGcnJygpaUFDQ0NKCsrKxQTEdHnqELdY0FE5a9jx45o3759od1AnJ2doa6uLk4rKSnh2bNnwPvRfapWrYodO3agSZMmcHBwwIIFC/Dq1Sv07dsXNWvWRK9evRAbG1tkDMeOHUNSUlK+ZOXMmTNwc3ODt7c3lJSU4O3tjTp16ojPmUlMTMTw4cNRq1YtODs7o3379oiMjCyDo0LFWblyJezt7bFq1SqcOHEC9vb26N+/PwBAV1cXlpaW4o++vj5UVFRgaWlZJh/gS7r9HTt2wM/PD0pKsm998fHxGDNmDJydndG4cWPo6upi8uTJCsdFRPS54RULIiq1GTNmYNeuXUhPT4eVlRV8fX1llueO7hMZGQkfHx9cv34dixcvho2NDQYPHoxVq1Zh06ZNBW47d3Sfbdu24erVqzLLChpmVBAEPHjw/w9VWrduHaRSKa5fvw41NTU8ePAA2traZb7/lN8333yDb775pkRlP+zSWq1aNURFRcmUyftQ0tx18o7kVJrt5zp8+HCB5bt3747u3buXaNtERFQ4XrEgolJbtGgRHj9+jODgYPTu3Rv6+voyyz/W6D4tWrTA7du3cfToUUilUhw9ehRXr17F27dvgfej+yQmJiIsLAzKyspwdXWVee4NERERfTxMLIhILkpKSnB3d4eOjg6+//57mWWKju4zZsyYApfXqFEDv/zyC1asWAF3d3f8+eef6Natm5g8fP3112jUqBFGjRqFOnXqYPbs2Xj37l0Z7TEREREVhV2hiEghWVlZ4j0WiirJ6D4+Pj7w8fER1+ncuTN69+4NANDW1oa/vz/8/f0RERGBIUOGIDAwEKNGjSqT+D5X3bY/LO8Q8nhQ3gHI2D/AqbxDICKqMHjFgohkSKVSpKeny4zuk5mZCQCIjIzE4cOHkZqaipycHFy9ehWbN2/ON8qOvL788kucP38ex48fx/HjxzFlyhTY29vj+PHj4lWP27dvQyqVIiUlBT/++CMSExPFezxOnDiBp0+fIicnBzo6OlBRUYGKCr8/ISIi+i/wHZeIZKxcuRIrVqwQp+3t7dGkSRPxZtqNGzdiypQpyMnJQZUqVTB06FCMHTu2TOrW1dWFrq6uOJ13dJ9cixYtws2bNyGRSNCiRQsEBQVBS0sLABAeHo7Zs2cjLi4O2tra6NixIwYNGlQmsREREVHRJMKHQ6xQicXFxSErK6u8wyh3EokEFhYWiI6OzjdiD1FB2GYql4rVFapiYVeowrHdFIxtpnBsM4Urz3ajqqoqc+9kUdgVioiIiIiIFMbEgoiIiIiIFMZ7LIg+IxXrMjNH9yEiIvqU8IoFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpjIkFEREREREpTKW8AyiNXbt2Yffu3TLzLC0t8dNPPwEAMjMzsXXrVly6dAlZWVlwd3fHiBEjYGBgIJaPj4/Hhg0bEBISAg0NDXh6eqJ///5QVlb+z/eHiIiIiOhTUakSCwCoVq0avvvuO3FaSel/F10CAwNx48YNTJ48GVpaWti0aROWL1+O77//HgCQk5ODRYsWwcDAAAsWLEBiYiJWr14NZWVl9O/fv1z2h4iIiIjoU1DpukIpKSnBwMBA/NHT0wMApKWl4fTp0xg8eDBcXV1hZ2eH0aNH49GjRwgNDQUA3L59G5GRkRg3bhxsbGzg4eEBPz8/HDt2DFKptJz3jIiIiIio8qp0iUVMTAy++uorjB07FqtWrUJ8fDwAICwsDNnZ2XBzcxPLVq1aFSYmJmJiERoaCmtra5muUXXq1MG7d+/w4sWLctgbIiIiIqJPQ6XqCuXg4IDRo0fD0tISiYmJ2L17N2bPno3ly5cjKSkJKioq0NbWlllHX18fSUlJAICkpCSZpCJ3ee6ywmRlZSErK0uclkgk0NTUFP/+3OUeAx4LqszYfkkebDdUWmwzJI/K0m4qVWLh4eEh/l29enUx0bh8+TLU1NQ+Wr179+6VuWnc1tYWS5Ysgamp6UerszIyNzcv7xCoWA/KO4AKy8LCorxDqMDYbgrDdlMUtpuCsM0UhW2mMJWl3VSqxOJD2trasLS0RExMDGrXrg2pVIrU1FSZqxZv3rwRr1IYGBjgyZMnMtt48+aNuKwwPXr0QOfOncXp3KwxLi6O92a8Px7m5uaIiYmBIAjlHQ6RXKKjo8s7BKqE2G6otNhmSB7l2W5UVFRK/GV6pU4s0tPTERMTgxYtWsDOzg7Kysq4e/cuGjduDAB4+fIl4uPj4ejoCABwdHTEnj178ObNG7EL1J07d6CpqQkrK6tC61FVVYWqqmqBy/hB+n8EQeDxoEqLbZfkwXZDpcU2Q/KoLO2mUiUWW7duRf369WFiYoLExETs2rULSkpKaN68ObS0tNC6dWts3boVOjo60NLSwubNm+Ho6CgmFu7u7rCyssLq1asxYMAAJCUlYceOHfDx8Sk0cSAiIiIiouJVqsQiISEBK1euxNu3b6GnpwcnJycEBASIQ84OHjwYEokEy5cvh1QqFR+Ql0tJSQnTp0/Hxo0bMWvWLKirq8PT0xN+fn7luFdERERERJVfpUosJk6cWORyNTU1jBgxQiaZ+JCpqSlmzJjxEaIjIiIiIvp8VbrnWBARERERUcXDxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKIiIiIiBTGxIKKNWvWLNSvXx81a9ZEvXr1MHv2bGRmZiI+Ph5jx45FvXr1oKenB29vbxw/fry8wyUiIiKicsDEgoo1ePBgnDt3Do8ePcKJEydw//59rF27FqmpqXB1dcXBgweRlJSEqVOnYvTo0QgNDS3vkImIiIjoP8bEgorl4OAALS0tAIAgCFBSUsKzZ89QvXp1jBo1CpaWllBSUkK7du1gb2+PGzduAAAyMjIwefJkuLq6wsnJCa1bt8atW7fKeW+IiIiI6GNQKe8AqHJYvXo1Vq5cibS0NBgaGsLf3z9fmfj4eDx58gTOzs4AgKCgINy/fx8XL16Enp4ewsLCoKGhUQ7RExEREdHHxisWVCJjx47F48ePcfbsWXzxxRcwNTWVWZ6ZmYmvv/4anTt3hru7OwBAVVUVKSkpePz4MQRBgL29PapWrVpOe0BEREREHxMTCyoVBwcH1KpVC5MmTRLnZWZmonfv3tDU1MQPP/wgzu/Vqxd8fX0xffp0uLm5YeLEiUhISCinyImIiIjoY2JiQaUmlUrx7Nkz4H1S8eWXXyIzMxMbNmyAmpqaWE5FRQXjx4/HyZMncfbsWURFRWHFihXlGDkRERERfSxMLKhIqamp2LlzJ968eQNBEPDgwQOsXLkSXl5eyMrKwqhRo5CWloZ9+/ZBXV1dZt0LFy7g3r17kEql0NLSgoaGBpSVlcttX4iIiIjo4+HN21QkiUSCvXv3Yv78+cjMzISJiQk6duyIKVOm4Nq1azh27Bg0NDRgYmICQRAAAOPGjcP48eMRHx8Pf39/vHz5EhoaGmjRogUmT55c3rtERERERB8BEwsqkpaWFnbs2FHgsiZNmiAqKgoSiQQWFhaIjo4WkwsA6N69O7p37/4fRktERERE5YVdoYiIiIiISGGf9RWLo0ePik+Nrl69OoYNG4YaNWqUd1hERERERJXOZ5tYXLp0CVu3bsXIkSPh4OCAw4cPIyAgAD/99BP09fXLO7xiddv+sLxD+MCD8g5AtH+AU3mHQERERPTZ+Wy7Qh06dAht2rRBq1atYGVlhZEjR0JNTQ1nzpwp79CIiIiIiCqdzzKxkEqlCAsLg5ubmzhPSUkJbm5uCA0NLdfYiIiIiIgqo8+yK1RycjJycnJgYGAgM9/AwAAvX77MVz4rKwtZWVnitEQigaamJlRUyu/w1TTTKbe6KzpVVdXyDqHCYrspHNtN4dhuCsd2Uzi2m4KxzRSObaZw5dluSvN597NMLEpr79692L17tzjdrFkzTJgwAYaGhuUW07bBpuVWN1VebDckD7YbkgfbDZUW20zl91l2hdLT04OSkhKSkpJk5iclJeW7igEAPXr0wJYtW8SfkSNHylzB+Ny9e/cO06ZNw7t378o7FKok2GZIHmw3JA+2G5IH2418PsvEQkVFBXZ2drh37544LycnB/fu3YOjo2O+8qqqqtDS0pL54aXM/xEEAc+ePZN5OB5RUdhmSB5sNyQPthuSB9uNfD7brlCdO3fGmjVrYGdnhxo1aiA4OBgZGRnw8vIq79CIiIiIiCqdzzaxaNq0KZKTk7Fr1y4kJSXBxsYGM2fOLLArFBERERERFe2zTSwAoH379mjfvn15h1Hpqaqqonfv3uweRiXGNkPyYLshebDdkDzYbuQjEdh5jIiIiIiIFPRZ3rxNRERERERli4kFEREREREpjIkFVRpnz56Fr68vfH19yzuUz9aaNWuwdOnSUq/n6+uLK1eufJSYiOjzEBsbC19fX4SHh5d3KERUCCYWVOHMnTsXvr6+WLNmjcx8PT09ODg4wMHBodxio6Lt2rULU6dOzTf/119/hYeHx38SQ0hICHbt2vWf1EVEipk7dy62bNlS3mEoZO7cueUdAn0E8n6RFhsbm+/zy+eEiQVVGnXr1kVAQAACAgLKOxQqJQMDg48+ssbx48fx5s0bcVoqleLgwYOQSqUftV4i+rSU5Jxx/fp1hIWFycy7ePEiXr58+REjo4rs/PnziImJEacFQcDRo0eRkpJSrnH91z7r4WYrqxs3buCvv/5CVFQUpFIpDA0NYWdnh5EjR0JHRwc3b97Evn378OzZM2RnZ8Pe3h6+vr5wdXUVt/H8+XP8+uuvCA8Ph6WlJYYNG4Y5c+YAAHr37g1fX1+EhIRg3rx5AIDVq1fDzMwMeN+tBQBGjx4tPlAwKioKO3fuREhICNLS0mBubo4OHTqgXbt2Yp1jxoxBXFwcunbtioyMDFy8eBFKSkpo1qwZBg0aBGVlZZluTn///Tf+/vtvsf779+9j7dq1wPtvxvH+hRwcHIzY2FikpaVBQ0MDNWrUgJ+fH2rUqPHR/xefqn/++QdBQUGIiYmBuro6bG1tC7wS8eTJEyxatAhdunSBgYEBdu/eDRTQRnx9fTFlyhQ0bNgQsbGxGDt2LCZOnIijR4/i6dOnsLa2xrhx45CWloaNGzciKioKzs7OGDt2LPT09MT6Tp06hUOHDiE2Nhampqbo0KEDfHx8AAAmJiZYunQpatSogcTERMybNw8NGzaERCL5z44blcytW7fw119/4cWLF1BSUoKjoyOGDBkCc3NzAEB8fDy2bt2KO3fuQCKRwNnZGUOGDBHPQTk5OdizZw9OnjyJ5ORkVK1aFQMGDECdOnWA998Yjh07Ft988w2OHj2Kx48fw8LCAiNHjoSjo2O57jv9z5o1a3D//n3cv38fwcHBAIAlS5bg4MGDuH37NtLT02FsbIwePXqgVatWBW4jIiIC27Ztw4MHD6ChoYHatWtj8ODB4nmjuLaW93x07NgxPHnyBCNHjkRISAhSU1Ph5OSEQ4cOQSqVomnTphgyZAhUVFRQpUoVBAYGwsHBAampqVixYgV0dHTg7u7+Hx5BKsrcuXNRrVo1AMC5c+egoqICb29v+Pn54a+//sLly5exfPlymXWmTp2KevXqQUlJSfz8kft+NmfOHNSsWROBgYH4999/kZqaCn19fXh7e6NHjx4wMzPDmjVr4OTkhISEBCxcuBC2traf3XC1TCwqmeTkZCxbtgxSqRQmJibQ1tZGfHw8Ll++jAEDBuDOnTtYuXIlBEGAqakpJBIJHj58iAULFmDWrFlwdXVFZmYmFi1ahISEBCgrK0MqlWLx4sVyxxQdHQ1/f3+kpaVBR0cHlpaWiIyMxMaNG5GcnIzevXvLlD98+DA0NTWhpqaGhIQEHDlyBNWqVUPbtm3h4OCAyMhIvHv3Drq6uuLJv7AX5tOnTxEREQETExMYGRnh5cuXuH37NkJDQ7Fy5Uo+8FAOiYmJWLlyJQYMGICGDRsiPT0dDx48yFfu3r17WLZsGQYOHIi2bdsiMzMTERERuH37Nr777jsAgJaWVqH1BAUFYfDgwTAxMcEvv/yCVatWQVNTE0OGDIG6ujp+/PFH7Ny5EyNHjgTeJ5G7du3CsGHDYGtri2fPnmH9+vVQV1eHl5cX6tatCycnJ/j7+yM+Ph7z58+Hra3tRzxSJK/09HR07twZ1atXR3p6Onbu3Illy5Zh6dKlyMnJQUBAABwdHTF//nwoKSlhz549WLhwIZYtWwYVFRUEBwfj4MGD+PLLL2Fra4vTp09jyZIlWLFiBSwsLMR6duzYgS+++ALm5ubYsWMHVq5ciVWrVkFZWblc95/+39ChQxEdHY1q1arBz88PeH9eiIyMxMyZM6Grq4uYmBhkZmYWuH5qairmz5+P1q1bY/DgwcjMzMT27dvx448/il+UFdXWlJT+12lj+/btGDRokPhBMCQkBCEhITA0NMScOXMQExODn376CTY2Nmjbti2srKzg7++PlStX4vnz5/Dx8UHbtm3/oyNHJfX333+jdevWWLRoEZ4+fYpff/0VJiYmaNWqFYKCgvDkyRPxS8hnz54hIiICU6ZMgb6+PqKiovDu3TuMHj0aAKCjo4Pg4GBcu3YNkyZNgomJCV6/fo34+HgAQM2aNTFnzhx8//33ePToEaZNm/afdQGuSJhYVDLx8fGQSqXQ1NTETz/9BDU1NQiCgKdPn0JPTw/bt2+HIAho1aoVRo0aBQBYvnw5rly5gl27dsHV1RUXLlxAQkICAGDatGmoU6cOTp8+jXXr1skV0969e5GWloZq1aph4cKFUFdXR3BwMLZs2YJ9+/ahU6dO0NTUFMsbGxtj6dKlUFFRwbhx45CYmIh79+6hbdu2CAgIwNy5c3H//n3UrVsXY8aMKbJuHx8f9OvXD+rq6gCAmJgYjB8/Hu/evcONGzfQunVrufbpc5aYmIjs7Gw0atQIpqamAABra2uZMleuXMHq1asxatQoNG3aFACgpqYGDQ0NKCkplSih69Kli/gNc8eOHbFy5UrMnj0bTk5OAIDWrVvj7NmzYvldu3bhiy++QKNGjQAAZmZmiIyMxMmTJ+Hl5YVbt24hKCgItWvXRmJiIn777Tc0btwY7du3l/kAQeWvcePGMtNff/01RowYgcjISISHh0MQBIwaNUq82jR69GgMGTIEISEhcHd3x8GDB9GtWzc0a9YMADBw4ECEhITg8OHDGDFihLjdLl26oG7dusD7bx0nT56MmJgYVK1a9T/dXyqYlpYWVFRUoK6uLp4zEhISYGNjA3t7e+D967wwR48eha2tLfr37y/O+/rrr/H111/j5cuXsLS0LLKt5T2vderUSTy35NLR0cHw4cOhpKSEqlWrwsPDQ3yvevnyJbZs2QJ7e3tUr14dd+7cQXh4OPr27QsdHZ0yO0akGGNjYwwePBgSiQSWlpaIiIjA4cOH0bZtW9SpUwdnz54VE4szZ86gVq1aqFKlCvD+PS0rK0vm/Sw+Ph4WFhZwcnKCRCIR3yMB4PHjx9i2bRscHR3FL0BCQ0PRo0cPqKmplcPelw8mFpWMlZUVqlSpglevXmHEiBGwsLBAtWrV0LhxY5iZmSEuLg54/wI5c+aMzLqPHz8GALx48QIAoK6uLn6wa9KkidyJxZMnT8TtfvHFFzLLMjMz8fz5c/HDIgDUr19f/CbbzMwMiYmJMn3jSyM1NRUbN25EWFgY0tLSkPd5j7nJE5WOjY0N3NzcMGXKFLi7u6N27dpo3Lix+Gb55MkT3LhxA5MnT0bDhg3lrifvm7q+vn6B83LbRXp6Ol69eoV169Zh/fr1YpmcnByxLcXGxuLbb79FZGQkQkJCMH78eAQHByMnJ4eJRQUTHR2NnTt34smTJ3j79i1ycnKA92/az58/R0xMDAYNGiSzTlZWFl69eoW0tDQkJibKnFPw/tvC58+fy8zL255yPxy8efOGiUUF1q5dOyxfvhzPnj2Du7s7GjRogJo1axZY9vnz57h3716+9x0AePXqFSwtLYtsa3nbh52dXb5tWFlZyZw7DA0NERERAQB4+fIl+vbtCzs7Ozx48ACTJ0/GhQsXkJyczMSiAnFwcJDpDuvo6IhDhw4hJycHbdq0wS+//IJBgwZBSUkJFy9exODBg4vcnpeXFxYsWICJEyfC3d0d9erVE7u/RUdH4+uvv4aSkhKCgoIwevRoHDt2DJmZmUwsqOJSU1PD4sWLce7cOTx+/BhRUVE4f/48zp07h0mTJonlqlSpItM3PVdpbmTN+2LMPRmnpaUVWj5v16W8PvxQl7d7TG6XBHkeAJ+eno6AgACkpqZCVVUVNjY2UFFREROo3JipdJSUlDBr1iw8evQId+7cwdGjR7Fjxw4sXLgQeN+2dHV1cebMGdStWxcqKvKdRvKul9vW8nZRkUgkYrtIT08HAHz11Vf5RgXLbV+59/NERkaK2+/atatcsdHHtWTJEpiamuKrr76CoaEhBEHAN998A6lUivT0dNjZ2WH8+PH51ivonFaUgtqYPOca+u94eHhg7dq1uHHjBu7cuYP58+fDx8cnX6KJ9+eFevXqYeDAgfmW5SaSRbW1vDQ0NPJt48Muc3nPSfXr189Xvnnz5nLsMZWXevXqQUVFBVeuXIGKigqkUmm+K1wfsrOzw+rVq3Hr1i3cuXMHP/74I9zc3PDNN9+gZcuWwPsvufC+vbRv3/4/2ZeKhIlFJZOWloaoqCi0b98eHTp0AAAEBATg9u3bePDgAUxNTREXFwdbW1tMmDBBPDG+fPkS8fHxUFFREW9mysjIwO3bt+Hu7o5//vknX11538Sjo6Nhbm6Oy5cv5ytnb2+PyMhIaGlpYcaMGeK3NcnJybh3716pb5bM7daUkZFRZLmXL18iNTUVeH95u3nz5ggNDcWsWbNKVR/lJ5FI4OTkBCcnJ/Tu3RujR48Wn0Ohq6uLKVOmYO7cufjxxx8xadIk8QOciorKR0noDAwMYGhoiFevXqFFixZFlnVxcYGLi0uZx0Bl4+3bt3j58iW++uorODs7AwAePnwoLre1tcWlS5egp6dX6D06hoaGePjwIWrVqiXOe/ToEQdsqIQKOmfo6enBy8sLXl5eOHHiBLZt21ZgYmFra4t///0XpqamBd43U1xbKyscbrbiyu1Rkevx48cwNzcXv5Dy9PTE2bNnoaKigmbNmslcWSjs/UxLSwtNmzZF06ZN0bhxYyxcuBApKSniZx8zM7Niu3F/yphYVDLJycmYNWsWtLW1YWxsDKlUKg5vZ21tDUdHR6xatQr//PMP7t+/DyMjI7GrkaenJ2rXro3mzZtj165dSEhIwJIlS2Bubo7Xr1/nq8vCwgImJiaIj4/HqlWrYGNjg0ePHuUr16NHD1y5cgWvXr3C119/DQsLC6SkpCAhIQHGxsZiH/ySsrS0xM2bN/Hvv/9i2rRp0NPTg7+/f75yZmZmUFdXR0ZGBtatW4d9+/bJ3aWK/ufx48e4e/cu3N3doa+vj8ePH4sj7+R2NdHX18ecOXMwb948rFy5EhMnToSysjLMzMwQGxuL8PBwGBkZQVNTs8xGxPD19cVvv/0GLS0t1KlTB1KpFE+fPkVqaio6d+5cJnXQx6etrQ1dXV2cPHkShoaGiI+Px/bt28XlLVq0wMGDB/HDDz/A19cXxsbGiIuLw7///otu3brB2NgYXbt2xa5du2Bubg4bGxucOXMG4eHhBV7loIrN1NQUjx8/RmxsLDQ0NHDkyBHY2dmhWrVqyMrKwvXr1wvtuubj44NTp05h5cqV6Nq1K3R0dBATE4NLly5h1KhRxbY1+vTFx8cjMDAQ3t7eCAsLw5EjR2SS1DZt2oi9Pb7//nuZdU1NTXH79m28fPkSOjo60NLSwtGjR2FgYABbW1tIJBL8888/MDAwKHKgks8NE4tKRkdHB15eXuKJWBAEVK1aFS1btkSbNm0gkUigpaWFAwcOICwsDC9fvoSRkRHc3d3Rpk0b4H13qunTp2PDhg149uwZJBIJpk2blu9bF2VlZUycOBGbNm1CZGQkUlJSMGXKlHwjSFlaWiIgIAC7du1CSEgIXrx4AQMDA9SpU6fUSQXe33AZERGBx48f49mzZ9DV1S30WEyePBm///47Xr16BRUVFUybNg0zZ84sdZ30P5qamnjw4AGCg4Px7t07mJiYYNCgQfDw8MClS5fEcgYGBpg9ezbmzp2LVatWYcKECWjUqBH+/fdfzJs3D6mpqTJDEiuqTZs2UFdXx4EDB7Bt2zaoq6vD2toanTp1KpPt039DSUkJEyZMwG+//YZvvvkGlpaWGDp0qHj+UVdXx7x587Bt2zYsW7YM6enpMDIygqurqzgIRIcOHZCWloatW7fizZs3sLKywrRp02RGhKLKoUuXLlizZg0mT56MzMxM+Pn54Y8//kBcXBzU1NTg5OSEiRMnFriukZERvv/+e2zfvh0BAQHIysqCqakp3N3dIZFIIJFIimxr9Olr2bIlMjMzMWPGDCgpKaFjx44yo3dZWFigZs2aSElJydfNtm3btrh//z6mT5+O9PR0zJkzBxoaGjhw4ACio6OhpKSEGjVqiNum/ycR2OGU3ssdqzn3ORZEREREldHcuXNhY2ODIUOGFFpGEASMHz8ePj4+vPJdRnjFgoiIiIg+K8nJybh48SKSkpLK7Mo6MbEgIiIios/MiBEjoKuri6+++opDBJchdoUiIiIiIiKF8W4TIiIiIiJSGBMLIiIiIiJSGBMLIiIiIiJSGBMLIiIiIiJSGBMLIiIiIiJSGBMLIiKqkMaMGYPFixeXdxhERFRCfI4FERGVyNmzZ7F27VpxWlVVFSYmJqhduzZ69eoFAwODco2PiIjKFxMLIiIqFV9fX5iZmSErKwsPHz7E8ePHcfPmTSxfvhzq6urlHR4REZUTJhZERFQqHh4esLe3BwC0adMGurq6OHToEK5evYrmzZuXd3hERFROmFgQEZFCXF1dcejQIcTGxuLAgQO4cuUKXr58iYyMDFhZWaFHjx5o3LhxvvXOnTuHI0eO4MWLF1BVVYW1tTV69uwJd3f3Qus6e/Ys1q1bh06dOuGLL75ASkoK9uzZg9u3byM2NhZKSkqoWbMm+vfvDxsbG5l14+LisHnzZty7dw/q6upo3rw56tSpg4ULF2LOnDlwcXERyz5+/Bi7du1CaGgosrOzYW9vj379+sHJyamMjx4R0aeDN28TEZFCYmJiAAC6uro4cuQIbGxs4Ovri379+kFZWRkrVqzAjRs3ZNYJCgrC6tWroaKiAl9fX/Tp0wfGxsa4d+9eofWcPHkSv/zyC7p3744vvvgCAPDq1StcvXoV9erVw+DBg9GlSxdERERg7ty5SEhIENdNT0/H/PnzcffuXXTo0AE9e/ZEaGgotm/fnq+ee/fuYc6cOXj37h369OmDfv36IS0tDfPnz8eTJ0/K8MgREX1aeMWCiIhKJS0tDcnJycjKysKjR4/w119/QU1NDfXq1YOnpyfU1NTEsu3bt8e0adNw6NAh1K1bF3ifiOzevRsNGzbE5MmToaT0v++4BEEosM7g4GAEBgbC19cXvXr1EudbW1tj5cqVMtto2bIlJk2ahNOnT6N3797A+6Tk1atXmDp1Kho0aAAAaNu2LaZNmyZTjyAI2LBhA1xcXDBz5kxIJBIAgLe3NyZPnowdO3Zg1qxZZXQkiYg+LUwsiIioVL7//nuZaVNTU4wbNw5GRkYy81NSUpCTkwNnZ2dcvHhRnH/lyhUIgoDevXvLJAQAxA/yee3fvx/bt2/HwIED0bVrV5llqqqq4t85OTlITU2FhoYGLC0t8ezZM3HZrVu3YGRkhPr164vz1NTU0KZNG2zdulWcFx4ejujoaPTs2RNv376VqcvV1RXnz59HTk5OvriJiIiJBRERldLw4cNhYWEBZWVl6Ovrw9LSUvygff36dezZswfh4eHIysoS18mbMLx69QoSiQRWVlbF1nX//n3cuHED3bp1y5dU4H0yERwcjOPHjyM2NhY5OTniMh0dHfHvuLg4VKlSJV/iYm5uLjMdHR0NAFizZk2hMaWlpclsm4iI/h8TCyIiKpUaNWqIo0Ll9eDBAyxduhTOzs4YPnw4DA0NoaysjLNnz+LChQty1VWtWjWkpqbi3Llz8Pb2hpmZmczyvXv3YufOnWjVqhX8/Pygo6MDiUSCwMDAQrtVFSV3nYEDB+a7+TuXhoaGXPtCRPSpY2JBRERl4t9//4Wqqir8/f1luiidPXtWplyVKlUgCAIiIyML/fCeS1dXF5MnT8bs2bMxf/58zJ8/X6bL1T///AMXFxd8/fXXMuulpqZCV1dXnDY1NUVkZCQEQZC5apF743ne2ABAS0sLtWvXLvUxICL6nLGTKBERlQklJSVIJBKZ7kixsbG4evWqTLmGDRtCIpFg9+7dMmVRyM3bxsbG+O6775CZmYkFCxbI3PtQ0L0Oly9flhkRCgDc3d2RkJCAa9euifMyMzNx6tQpmXJ2dnaoUqUKDh48iPT09HzbTk5OLuYoEBF9vnjFgoiIykTdunVx6NAhLFy4EM2aNUNycjKOHTsGc3NzPH/+XCxnbm6Onj174q+//sKcOXPQsGFDqKqq4smTJzAyMkL//v3zbdvc3ByzZs3C3LlzERAQgNmzZ0NLSwv16tXD7t27sXbtWjg6OiIiIgIXLlwQrzzk8vb2xtGjR7Fy5Up07NgRBgYGuHDhgnhlJfcqhpKSEkaNGoWFCxdi8uTJ8PLygpGRERISEhASEgJNTU1Mnz79ox9LIqLKiFcsiIioTLi6umLUqFFISkpCYGAgLl68iAEDBojDu+bl5+eHr7/+GpmZmdixYwd27tyJ+Ph4uLq6Frp9a2trzJw5E9HR0ViyZAkyMzPRo0cPdO7cGbdv38aWLVvw7NkzTJ8+HcbGxjLramhoYM6cOXB1dUVwcDD27NkDJycncejavF23XFxcEBAQADs7Oxw7dgy//fYb/v77bxgYGKBz585lesyIiD4lEkGeu9uIiIg+AYcPH0ZgYCDWrVuXb7hcIiIqHV6xICKiz0JmZma+6ZMnT8LCwoJJBRFRGeA9FkRE9FlYtmwZTExMYGNjg7S0NJw/fx5RUVEYP358eYdGRPRJYFcoIiL6LBw+fBinT58WH6RnZWWFbt26oWnTpuUdGhHRJ4GJBRERERERKYz3WBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcKYWBARERERkcL+D1Ku0R/qYZLOAAAAAElFTkSuQmCC", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -41,14 +41,14 @@ } ], "source": [ - "fig, ax = plt.subplots(figsize=(5, 4))\n", + "fig, ax = plt.subplots(figsize=(8, 4))\n", "\n", "runtimes = [31.871, 828.855, 887.367, 1210.012, 2778.706]\n", "labels = [\"sequentia\", \"sktime*\", \"aeon\", \"tslearn*\", \"pyts*\"]\n", "\n", "bars = ax.bar(labels, runtimes, width=0.5, color=\"C1\")\n", "ax.set(xlabel=\"Package\", ylabel=\"Runtime (s)\")\n", - "ax.set_title(\"Univariate DTW-kNN performance\\n(1,500 FSDD train/test sequences, 16 workers)\", fontsize=11)\n", + "ax.set_title(\"Univariate DTW-kNN performance (1,500 FSDD train/test sequences, 16 workers)\", fontsize=11)\n", "\n", "def fmt(s: float) -> str:\n", " if s < 60:\n", From b2f2c380a2ce92a9795d63e28bc35a0d1e7e4080 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:20:54 +0000 Subject: [PATCH 07/17] shorten --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 006ac4b..88cb1c9 100644 --- a/README.md +++ b/README.md @@ -138,16 +138,14 @@ The [Free Spoken Digit Dataset](https://sequentia.readthedocs.io/en/latest/secti - Median: 17 - Maximum: 92 -Each result measures the total time taken to complete training and prediction repeated 10 times on the above train/test split. +Each result measures the total time taken to complete training and prediction repeated 10 times. All of the above libraries support multiprocessing, and prediction was performed using 16 workers.
> **Device information**: -> - Processor: AMD Ryzen™ AI 7 PRO 360 -> - 8 cores, 16 threads -> - 2-5GHz +> - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) > - Memory: 64 GB LPDDR5X-7500MHz > - Solid State Drive: 1 TB SSD M.2 2280 PCIe Gen4 Performance TLC Opal > - Operating system: Fedora Linux 41 (Workstation Edition) From 2247db2283ccdb77fa34d28fba9257abc0f29905 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:21:20 +0000 Subject: [PATCH 08/17] remove width --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88cb1c9..6a81187 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. - + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) From f5eb4a375b0a8f29e6eed86ff6447b323ce827a0 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:22:38 +0000 Subject: [PATCH 09/17] specify 100% width --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a81187..6ae7350 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. - + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) From 267c367c521e5b7248564b3d29a9f05d3f862800 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:23:39 +0000 Subject: [PATCH 10/17] flatten --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ae7350..192f2af 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is - 3pyts does not support variable length sequences so they must be padded (and padding is not masked). - 4sequentia only supports [dtaidistance](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. -#### Benchmarks +### Benchmarks To compare the above libraries in runtime performance on dynamic time warping k-nearest neighbors classification tasks, a simple benchmark was performed on a univariate sequence dataset. From eb8f1804d22cebf00253a0518d73977e12399aa8 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:28:23 +0000 Subject: [PATCH 11/17] teletype --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 192f2af..7d1436c 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ In most cases, the only necessary change is to add a `lengths` key-word argument As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is a comparison of the DTW k-nearest neighbors algorithm features supported by Sequentia and similar libraries. -||**sequentia**|[aeon](https://github.com/aeon-toolkit/aeon)|[tslearn](https://github.com/tslearn-team/tslearn)|[sktime](https://github.com/sktime/sktime)|[pyts](https://github.com/johannfaouzi/pyts)| +||**`sequentia`**|[`aeon`](https://github.com/aeon-toolkit/aeon)|[`tslearn`](https://github.com/tslearn-team/tslearn)|[`sktime`](https://github.com/sktime/sktime)|[`pyts`](https://github.com/johannfaouzi/pyts)| |-|:-:|:-:|:-:|:-:|:-:| |Scikit-Learn compatible|✅|✅|✅|✅|✅| |Multivariate sequences|✅|✅|✅|✅|❌| @@ -117,10 +117,10 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is |Independent DTW (DTWI)|✅|❌|❌|❌|✅| |Custom DTW measures|❌4|✅|❌|✅|✅| -- 1tslearn supports variable length sequences with padding, but doesn't seem to mask the padding. -- 2sktime does not support variable length sequences so they must be padded (and padding is not masked). -- 3pyts does not support variable length sequences so they must be padded (and padding is not masked). -- 4sequentia only supports [dtaidistance](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. +- 1`tslearn` supports variable length sequences with padding, but doesn't seem to mask the padding. +- 2sktime` does not support variable length sequences so they are padded (and padding is not masked). +- 3`pyts` does not support variable length sequences so they are padded (and padding is not masked). +- 4`sequentia` only supports [`dtaidistance`](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. ### Benchmarks @@ -144,6 +144,8 @@ All of the above libraries support multiprocessing, and prediction was performed +*: `sktime`, `tslearn` and `pyts` seem to not mask padding, which may result in incorrect predictions. + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) > - Memory: 64 GB LPDDR5X-7500MHz From 8fefe380b30b5741da4b68fe7680403631934826 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:29:33 +0000 Subject: [PATCH 12/17] reorder --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7d1436c..565e75f 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is |Custom DTW measures|❌4|✅|❌|✅|✅| - 1`tslearn` supports variable length sequences with padding, but doesn't seem to mask the padding. -- 2sktime` does not support variable length sequences so they are padded (and padding is not masked). +- 2`sktime` does not support variable length sequences so they are padded (and padding is not masked). - 3`pyts` does not support variable length sequences so they are padded (and padding is not masked). - 4`sequentia` only supports [`dtaidistance`](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. @@ -142,10 +142,10 @@ Each result measures the total time taken to complete training and prediction re All of the above libraries support multiprocessing, and prediction was performed using 16 workers. - - *: `sktime`, `tslearn` and `pyts` seem to not mask padding, which may result in incorrect predictions. + + > **Device information**: > - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) > - Memory: 64 GB LPDDR5X-7500MHz From 190cb764db452f0597ccc370f90a2eb06d7759e8 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:32:34 +0000 Subject: [PATCH 13/17] comma --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 565e75f..fac8de0 100644 --- a/README.md +++ b/README.md @@ -118,9 +118,9 @@ As DTW k-nearest neighbors is the core algorithm offered by Sequentia, below is |Custom DTW measures|❌4|✅|❌|✅|✅| - 1`tslearn` supports variable length sequences with padding, but doesn't seem to mask the padding. -- 2`sktime` does not support variable length sequences so they are padded (and padding is not masked). -- 3`pyts` does not support variable length sequences so they are padded (and padding is not masked). -- 4`sequentia` only supports [`dtaidistance`](https://github.com/wannesm/dtaidistance) which is one of the fastest DTW libraries as it is written in C. +- 2`sktime` does not support variable length sequences, so they are padded (and padding is not masked). +- 3`pyts` does not support variable length sequences, so they are padded (and padding is not masked). +- 4`sequentia` only supports [`dtaidistance`](https://github.com/wannesm/dtaidistance), which is one of the fastest DTW libraries as it is written in C. ### Benchmarks From e32412dfa89339dee91ade4b03f0f0a23c7c63e2 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:37:27 +0000 Subject: [PATCH 14/17] add product --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fac8de0..2a4dd8b 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ All of the above libraries support multiprocessing, and prediction was performed > **Device information**: +> - Product: ThinkPad T14s (Gen 6) > - Processor: AMD Ryzen™ AI 7 PRO 360 (8 cores, 16 threads, 2-5GHz) > - Memory: 64 GB LPDDR5X-7500MHz > - Solid State Drive: 1 TB SSD M.2 2280 PCIe Gen4 Performance TLC Opal From 87436dd29e5f83eb515d7cf552587605b31143ac Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:38:55 +0000 Subject: [PATCH 15/17] add installation link --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2a4dd8b..8a562f6 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ About · Build Status · Features · + Installation · Documentation · Examples · Acknowledgments · From ca291e03bdd08e76e151dd3317d3e5a5dcbb55d6 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:43:35 +0000 Subject: [PATCH 16/17] add example without preprocessing --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a562f6..f5d4338 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,13 @@ lengths = np.array([3, 5, 2]) # Sequence classes y = np.array([0, 1, 1]) -# Create a transformation pipeline that feeds into a KNNClassifier +# Train and predict (without preprocessing) +clf = KNNClassifier(k=1) +clf.fit(X, y, lengths=lengths) +y_pred = clf.predict(X, lengths=lengths) +acc = pipeline.score(X, y, lengths=lengths) + +# Create a preprocessing pipeline that feeds into a KNNClassifier # 1. Individually denoise each sequence by applying a median filter for each feature # 2. Individually standardize each sequence by subtracting the mean and dividing the s.d. for each feature # 3. Reduce the dimensionality of the data to a single feature by using PCA From 996b4ff63c7c7cdeee27723c92a6641f07db5aa2 Mon Sep 17 00:00:00 2001 From: Edwin Onuonga Date: Tue, 24 Dec 2024 17:47:16 +0000 Subject: [PATCH 17/17] add .gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..60404dc --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.ipynb linguist-documentation \ No newline at end of file