deepecgkit 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. deepecgkit/__init__.py +42 -0
  2. deepecgkit/__main__.py +6 -0
  3. deepecgkit/cli/__init__.py +61 -0
  4. deepecgkit/cli/commands/__init__.py +16 -0
  5. deepecgkit/cli/commands/evaluate.py +83 -0
  6. deepecgkit/cli/commands/info.py +73 -0
  7. deepecgkit/cli/commands/predict.py +94 -0
  8. deepecgkit/cli/commands/train.py +331 -0
  9. deepecgkit/cli/config.py +23 -0
  10. deepecgkit/cli/evaluation.py +251 -0
  11. deepecgkit/cli/logger.py +26 -0
  12. deepecgkit/cli/main.py +429 -0
  13. deepecgkit/cli/registry.py +32 -0
  14. deepecgkit/datasets/__init__.py +33 -0
  15. deepecgkit/datasets/af_classification.py +301 -0
  16. deepecgkit/datasets/base.py +146 -0
  17. deepecgkit/datasets/ltafdb.py +363 -0
  18. deepecgkit/datasets/mitbih_afdb.py +287 -0
  19. deepecgkit/datasets/modules.py +222 -0
  20. deepecgkit/datasets/preprocessing.py +208 -0
  21. deepecgkit/datasets/ptbxl.py +567 -0
  22. deepecgkit/datasets/splitting.py +225 -0
  23. deepecgkit/datasets/unified_af.py +316 -0
  24. deepecgkit/evaluation/__init__.py +40 -0
  25. deepecgkit/evaluation/evaluator.py +398 -0
  26. deepecgkit/evaluation/metrics.py +164 -0
  27. deepecgkit/evaluation/visualization.py +285 -0
  28. deepecgkit/models/__init__.py +51 -0
  29. deepecgkit/models/af_classifier.py +177 -0
  30. deepecgkit/models/convnext_v2_1d.py +183 -0
  31. deepecgkit/models/crnn.py +117 -0
  32. deepecgkit/models/deep_res_cnn.py +215 -0
  33. deepecgkit/models/ecg_dualnet.py +230 -0
  34. deepecgkit/models/fcn_wang.py +88 -0
  35. deepecgkit/models/gru_model.py +99 -0
  36. deepecgkit/models/inception_time.py +197 -0
  37. deepecgkit/models/kanres_wide_x.py +150 -0
  38. deepecgkit/models/kanres_x.py +126 -0
  39. deepecgkit/models/lstm_model.py +96 -0
  40. deepecgkit/models/mamba1d.py +232 -0
  41. deepecgkit/models/medformer.py +229 -0
  42. deepecgkit/models/resnet1d.py +189 -0
  43. deepecgkit/models/resnet1d_wang.py +182 -0
  44. deepecgkit/models/se_resnet1d.py +232 -0
  45. deepecgkit/models/simple_cnn.py +82 -0
  46. deepecgkit/models/tcn.py +178 -0
  47. deepecgkit/models/transformer_ecg.py +127 -0
  48. deepecgkit/models/xresnet1d.py +265 -0
  49. deepecgkit/models/xresnet1d_benchmark.py +227 -0
  50. deepecgkit/registry.py +97 -0
  51. deepecgkit/training/__init__.py +9 -0
  52. deepecgkit/training/train.py +171 -0
  53. deepecgkit/utils/__init__.py +72 -0
  54. deepecgkit/utils/download.py +123 -0
  55. deepecgkit/utils/weights.py +107 -0
  56. deepecgkit-0.1.0.dist-info/METADATA +99 -0
  57. deepecgkit-0.1.0.dist-info/RECORD +61 -0
  58. deepecgkit-0.1.0.dist-info/WHEEL +5 -0
  59. deepecgkit-0.1.0.dist-info/entry_points.txt +2 -0
  60. deepecgkit-0.1.0.dist-info/licenses/LICENSE +201 -0
  61. deepecgkit-0.1.0.dist-info/top_level.txt +1 -0
deepecgkit/__init__.py ADDED
@@ -0,0 +1,42 @@
1
+ """
2
+ DeepECG-Kit: A comprehensive Python package for ECG analysis using deep learning.
3
+
4
+ This package provides tools for:
5
+ - Loading and preprocessing ECG data
6
+ - Training deep learning models on ECG signals
7
+ - Evaluating model performance
8
+ - Traditional ECG analysis methods
9
+ - Visualization and reporting
10
+
11
+ Basic usage:
12
+ import deepecgkit as ecg
13
+
14
+
15
+ data = ecg.load_ecg_data("path/to/data")
16
+
17
+
18
+ preprocessed = ecg.preprocess(data)
19
+
20
+
21
+ model = ecg.models.KanResWideX(input_channels=12, output_size=1)
22
+ trainer = ecg.train_model(model, preprocessed)
23
+
24
+
25
+ results = ecg.evaluate_model(model, test_data)
26
+ """
27
+
28
+ from deepecgkit.datasets import ECGDataModule
29
+ from deepecgkit.models import KanResWideX
30
+ from deepecgkit.training import ECGLitModel
31
+ from deepecgkit.utils import read_csv
32
+
33
+ __version__ = "0.1.0"
34
+ __author__ = "DeepECG Kit Contributors"
35
+ __license__ = "MIT"
36
+
37
+ __all__ = [
38
+ "ECGDataModule",
39
+ "ECGLitModel",
40
+ "KanResWideX",
41
+ "read_csv",
42
+ ]
deepecgkit/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Entry point for python -m deepecgkit."""
2
+
3
+ from deepecgkit.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,61 @@
1
+ """
2
+ Command-line interface for deepecg-kit.
3
+
4
+ Usage:
5
+ deepecg train --model <model> --dataset <dataset> [options]
6
+ deepecg evaluate --checkpoint <path> --dataset <dataset> [options]
7
+ deepecg predict --checkpoint <path> --input <file> [options]
8
+ deepecg resume --checkpoint <path> [options]
9
+ deepecg list-models
10
+ deepecg list-datasets
11
+ deepecg info --model <model>
12
+
13
+ Datasets are automatically downloaded when first used if not already present.
14
+ Use --force-download to re-download an existing dataset.
15
+ """
16
+
17
+ from deepecgkit.cli.commands import (
18
+ evaluate,
19
+ list_datasets,
20
+ list_models,
21
+ predict,
22
+ resume,
23
+ show_info,
24
+ train,
25
+ )
26
+ from deepecgkit.cli.config import load_config
27
+ from deepecgkit.cli.logger import CLILogger
28
+ from deepecgkit.cli.main import main
29
+ from deepecgkit.cli.registry import (
30
+ DATASET_INPUT_CHANNELS,
31
+ DATASET_NAMES,
32
+ DATASET_NUM_CLASSES,
33
+ MODEL_DESCRIPTIONS,
34
+ MODEL_NAMES,
35
+ MODEL_WEIGHTS,
36
+ _get_dataset_registry,
37
+ _get_model_registry,
38
+ )
39
+ from deepecgkit.training import ECGLitModel
40
+
41
+ __all__ = [
42
+ "DATASET_INPUT_CHANNELS",
43
+ "DATASET_NAMES",
44
+ "DATASET_NUM_CLASSES",
45
+ "MODEL_DESCRIPTIONS",
46
+ "MODEL_NAMES",
47
+ "MODEL_WEIGHTS",
48
+ "CLILogger",
49
+ "ECGLitModel",
50
+ "_get_dataset_registry",
51
+ "_get_model_registry",
52
+ "evaluate",
53
+ "list_datasets",
54
+ "list_models",
55
+ "load_config",
56
+ "main",
57
+ "predict",
58
+ "resume",
59
+ "show_info",
60
+ "train",
61
+ ]
@@ -0,0 +1,16 @@
1
+ """CLI command functions."""
2
+
3
+ from deepecgkit.cli.commands.evaluate import evaluate
4
+ from deepecgkit.cli.commands.info import list_datasets, list_models, show_info
5
+ from deepecgkit.cli.commands.predict import predict
6
+ from deepecgkit.cli.commands.train import resume, train
7
+
8
+ __all__ = [
9
+ "evaluate",
10
+ "list_datasets",
11
+ "list_models",
12
+ "predict",
13
+ "resume",
14
+ "show_info",
15
+ "train",
16
+ ]
@@ -0,0 +1,83 @@
1
+ """Evaluate command."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Dict, Optional
5
+
6
+ import pytorch_lightning as pl
7
+
8
+ from deepecgkit.cli.logger import CLILogger
9
+ from deepecgkit.cli.registry import DATASET_NAMES, _get_dataset_registry
10
+ from deepecgkit.datasets import ECGDataModule
11
+ from deepecgkit.training import ECGLitModel
12
+
13
+
14
+ def evaluate(
15
+ checkpoint: str,
16
+ dataset_name: str,
17
+ data_dir: Optional[str] = None,
18
+ batch_size: int = 32,
19
+ num_workers: int = 4,
20
+ accelerator: str = "auto",
21
+ devices: int = 1,
22
+ force_download: bool = False,
23
+ split: str = "test",
24
+ logger: Optional[CLILogger] = None,
25
+ ) -> int:
26
+ """Evaluate a trained model on a dataset."""
27
+ logger = logger or CLILogger()
28
+
29
+ checkpoint_path = Path(checkpoint)
30
+ if not checkpoint_path.exists():
31
+ logger.error(f"Checkpoint not found: {checkpoint}")
32
+ return 1
33
+
34
+ dataset_registry = _get_dataset_registry()
35
+
36
+ if dataset_name not in dataset_registry:
37
+ logger.error(f"Unknown dataset: {dataset_name}")
38
+ logger.info(f"Available datasets: {', '.join(DATASET_NAMES)}")
39
+ return 1
40
+
41
+ try:
42
+ logger.info(f"Loading model from {checkpoint}...")
43
+ lit_model = ECGLitModel.load_from_checkpoint(checkpoint)
44
+
45
+ dataset_class = dataset_registry[dataset_name]
46
+ dataset_kwargs: Dict[str, Any] = {"force_download": force_download}
47
+ if data_dir:
48
+ dataset_kwargs["data_dir"] = data_dir
49
+
50
+ logger.info(f"Creating data module with {dataset_name} dataset...")
51
+ data_module = ECGDataModule(
52
+ dataset_class=dataset_class,
53
+ batch_size=batch_size,
54
+ num_workers=num_workers,
55
+ download=True,
56
+ dataset_kwargs=dataset_kwargs,
57
+ )
58
+
59
+ trainer = pl.Trainer(
60
+ accelerator=accelerator,
61
+ devices=devices,
62
+ enable_progress_bar=not logger.quiet,
63
+ )
64
+
65
+ logger.info(f"Running evaluation on {split} split...")
66
+ if split == "test":
67
+ results = trainer.test(lit_model, data_module)
68
+ elif split == "val":
69
+ results = trainer.validate(lit_model, data_module)
70
+ else:
71
+ logger.error(f"Invalid split: {split}. Use 'test' or 'val'.")
72
+ return 1
73
+
74
+ if results:
75
+ logger.info("\nEvaluation Results:")
76
+ logger.info("-" * 40)
77
+ for key, value in results[0].items():
78
+ logger.info(f" {key}: {value:.4f}")
79
+
80
+ return 0
81
+ except Exception as e:
82
+ logger.error(f"Evaluation failed: {e}")
83
+ return 1
@@ -0,0 +1,73 @@
1
+ """Info and listing commands."""
2
+
3
+ from typing import Optional
4
+
5
+ from deepecgkit.cli.logger import CLILogger
6
+ from deepecgkit.cli.registry import (
7
+ DATASET_NAMES,
8
+ DATASET_NUM_CLASSES,
9
+ MODEL_DESCRIPTIONS,
10
+ MODEL_NAMES,
11
+ MODEL_WEIGHTS,
12
+ _get_model_registry,
13
+ )
14
+
15
+
16
+ def list_models() -> None:
17
+ """List all available models."""
18
+ print("Available models:")
19
+ print("-" * 60)
20
+ for name in sorted(MODEL_NAMES):
21
+ desc = MODEL_DESCRIPTIONS.get(name, "")
22
+ weights = MODEL_WEIGHTS.get(name, [])
23
+ print(f" {name}")
24
+ if desc:
25
+ print(f" Description: {desc}")
26
+ if weights:
27
+ print(f" Pretrained weights: {', '.join(weights)}")
28
+ print()
29
+
30
+
31
+ def list_datasets() -> None:
32
+ """List all available datasets."""
33
+ print("Available datasets:")
34
+ print("-" * 60)
35
+ for name in sorted(DATASET_NAMES):
36
+ num_classes = DATASET_NUM_CLASSES[name]
37
+ print(f" {name}")
38
+ print(f" Classes: {num_classes}")
39
+ print()
40
+
41
+
42
+ def show_info(model_name: str, logger: Optional[CLILogger] = None) -> int:
43
+ """Show detailed information about a model."""
44
+ logger = logger or CLILogger()
45
+
46
+ if model_name not in MODEL_NAMES:
47
+ logger.error(f"Unknown model: {model_name}")
48
+ logger.info(f"Available models: {', '.join(MODEL_NAMES)}")
49
+ return 1
50
+
51
+ try:
52
+ model_registry = _get_model_registry()
53
+ model_class = model_registry[model_name]
54
+ model = model_class(input_channels=1, output_size=4)
55
+
56
+ total_params = sum(p.numel() for p in model.parameters())
57
+ trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
58
+
59
+ print(f"Model: {model_name}")
60
+ print("=" * 60)
61
+ print(f"Description: {MODEL_DESCRIPTIONS.get(model_name, 'N/A')}")
62
+ print(f"Total parameters: {total_params:,}")
63
+ print(f"Trainable parameters: {trainable_params:,}")
64
+ print(f"Pretrained weights: {', '.join(MODEL_WEIGHTS.get(model_name, ['None']))}")
65
+ print()
66
+ print("Architecture:")
67
+ print("-" * 60)
68
+ print(model)
69
+
70
+ return 0
71
+ except Exception as e:
72
+ logger.error(f"Failed to load model info: {e}")
73
+ return 1
@@ -0,0 +1,94 @@
1
+ """Predict command."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+ import torch
10
+ import wfdb
11
+
12
+ import deepecgkit.cli as _cli
13
+ from deepecgkit.cli.logger import CLILogger
14
+
15
+
16
+ def predict(
17
+ checkpoint: str,
18
+ input_path: str,
19
+ output_path: Optional[str] = None,
20
+ batch_size: int = 1,
21
+ accelerator: str = "auto",
22
+ logger: Optional[CLILogger] = None,
23
+ ) -> int:
24
+ """Run inference on ECG data."""
25
+ logger = logger or CLILogger()
26
+
27
+ checkpoint_file = Path(checkpoint)
28
+ if not checkpoint_file.exists():
29
+ logger.error(f"Checkpoint not found: {checkpoint}")
30
+ return 1
31
+
32
+ input_file = Path(input_path)
33
+ if not input_file.exists():
34
+ logger.error(f"Input file not found: {input_path}")
35
+ return 1
36
+
37
+ try:
38
+ logger.info(f"Loading model from {checkpoint}...")
39
+ lit_model = _cli.ECGLitModel.load_from_checkpoint(checkpoint)
40
+ lit_model.eval()
41
+
42
+ logger.info(f"Loading input data from {input_path}...")
43
+ if input_file.suffix == ".npy":
44
+ data = np.load(input_path)
45
+ elif input_file.suffix == ".csv":
46
+ data = pd.read_csv(input_path).values
47
+ elif input_file.suffix in (".dat", ".hea"):
48
+ record = wfdb.rdrecord(str(input_file.with_suffix("")))
49
+ data = record.p_signal
50
+ else:
51
+ logger.error(f"Unsupported input format: {input_file.suffix}")
52
+ logger.info("Supported formats: .npy, .csv, .dat/.hea (WFDB)")
53
+ return 1
54
+
55
+ if data.ndim == 1:
56
+ data = data.reshape(1, 1, -1)
57
+ elif data.ndim == 2:
58
+ data = data.reshape(data.shape[0], 1, -1)
59
+
60
+ tensor = torch.tensor(data, dtype=torch.float32)
61
+
62
+ logger.info("Running inference...")
63
+ device = "cuda" if accelerator == "gpu" and torch.cuda.is_available() else "cpu"
64
+ lit_model = lit_model.to(device)
65
+ tensor = tensor.to(device)
66
+
67
+ with torch.no_grad():
68
+ outputs = lit_model(tensor)
69
+ if hasattr(outputs, "logits"):
70
+ outputs = outputs.logits
71
+ probabilities = torch.softmax(outputs, dim=-1)
72
+ predictions = torch.argmax(probabilities, dim=-1)
73
+
74
+ results = {
75
+ "predictions": predictions.cpu().numpy().tolist(),
76
+ "probabilities": probabilities.cpu().numpy().tolist(),
77
+ }
78
+
79
+ if output_path:
80
+ output_file = Path(output_path)
81
+ output_file.parent.mkdir(parents=True, exist_ok=True)
82
+ with open(output_file, "w") as f:
83
+ json.dump(results, f, indent=2)
84
+ logger.info(f"Results saved to {output_path}")
85
+ else:
86
+ logger.info("\nPrediction Results:")
87
+ logger.info("-" * 40)
88
+ for i, (pred, prob) in enumerate(zip(results["predictions"], results["probabilities"])):
89
+ logger.info(f" Sample {i}: class={pred}, confidence={max(prob):.4f}")
90
+
91
+ return 0
92
+ except Exception as e:
93
+ logger.error(f"Prediction failed: {e}")
94
+ return 1