Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7f61ce9
Refactor SSSD-ECG: Separate data loading from model implementation
claude Nov 19, 2025
2c5a81a
Merge pull request #1 from nnknk0802/claude/refactor-diffusion-datalo…
nnknk0802 Nov 19, 2025
43340b6
Add standalone SSSD-ECG implementation
claude Nov 19, 2025
57c8259
Merge pull request #2 from nnknk0802/claude/standalone-implementation…
nnknk0802 Nov 19, 2025
f6f1afe
Fix: Remove pytorch_lightning dependency from standalone implementation
claude Nov 19, 2025
a01868b
Merge pull request #3 from nnknk0802/claude/standalone-implementation…
nnknk0802 Nov 19, 2025
173af4c
Add PTB-XL dataloader module and examples
claude Nov 19, 2025
805bf20
Add .gitignore to exclude Python cache files and IDE settings
claude Nov 19, 2025
0fd9aed
Merge pull request #4 from nnknk0802/claude/ptbxl-dataloader-creation…
nnknk0802 Nov 19, 2025
9cb2265
Fix: Properly handle reformat_as_memmap return value and add debug sc…
claude Nov 19, 2025
a94596e
Merge pull request #5 from nnknk0802/claude/ptbxl-dataloader-creation…
nnknk0802 Nov 19, 2025
69343cd
Add DataFrame checker and v2 dataloader with workaround
claude Nov 19, 2025
026da97
Merge pull request #6 from nnknk0802/claude/ptbxl-dataloader-creation…
nnknk0802 Nov 19, 2025
7eb443c
Fix: Support min_cnt=0 by using unfiltered label columns
claude Nov 19, 2025
071aebc
Merge pull request #7 from nnknk0802/claude/ptbxl-dataloader-creation…
nnknk0802 Nov 20, 2025
9eb8929
Add JIT-compiled generate_jit method for faster inference
claude Nov 24, 2025
c94c0f7
Merge pull request #9 from nnknk0802/claude/add-generate-jit-01RjCW6F…
nnknk0802 Nov 24, 2025
8822428
Fix CUDA device selection to support cuda:1 and other devices
claude Nov 24, 2025
8174725
Add device validation and helpful error messages for CUDA device sele…
claude Nov 24, 2025
d322cda
Add check_devices.py utility script to verify available CUDA devices
claude Nov 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# IDE settings
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Data files (optional - uncomment if you don't want to track large data files)
# *.npy
# *.npz
# *.pkl
# *.h5
# *.hdf5
# data/
# processed_*/
264 changes: 264 additions & 0 deletions CUDA_DEVICE_SELECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
# CUDA Device Selection

This document explains how to use specific CUDA devices (cuda:0, cuda:1, etc.) with the SSSD-ECG model.

## Problem Fixed

Previously, the model was hardcoded to use `cuda:0` only. Attempting to use other CUDA devices (like `cuda:1`) would result in errors because `.cuda()` calls were hardcoded throughout the codebase.

## Solution

All hardcoded `.cuda()` calls have been replaced with device-aware `.to(device)` calls. The device parameter now properly propagates through all functions.

## Usage

### Specifying CUDA Device During Initialization

You can now specify any CUDA device when initializing the model:

```python
from model_wrapper import SSSDECG

# Use the first CUDA device (cuda:0)
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:0")

# Use the second CUDA device (cuda:1)
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:1")

# Use a specific CUDA device by index
device_id = 2
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device=f"cuda:{device_id}")

# Use CPU
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cpu")

# Auto-select (default: cuda if available, else cpu)
model = SSSDECG(config_path="config/config_SSSD_ECG.json")
```

### Using torch.device Objects

You can also pass `torch.device` objects:

```python
import torch

# Create a torch.device object
device = torch.device("cuda:1")
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device=device)
```

### Training Example

```python
import torch
from model_wrapper import SSSDECG

# Initialize model on cuda:1
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:1")

# Your training data should also be on the same device
x = torch.randn(8, 8, 1000).to("cuda:1") # batch_size=8, channels=8, length=1000
y = torch.randint(0, 71, (8,)).to("cuda:1") # class labels

# Forward pass - automatically uses cuda:1
loss = model(x, y)

# Backward pass
optimizer = torch.optim.Adam(model.parameters(), lr=2e-4)
optimizer.zero_grad()
loss.backward()
optimizer.step()
```

### Generation Example

```python
import torch
from model_wrapper import SSSDECG

# Initialize model on cuda:1
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:1")

# Load checkpoint
model.load_checkpoint("checkpoint.pkl")

# Generate samples - automatically uses cuda:1
labels = torch.tensor([0, 5, 10, 15, 20]).to("cuda:1")
samples = model.generate(labels=labels)

print(f"Generated samples shape: {samples.shape}")
print(f"Samples device: {samples.device}") # Should be cuda:1
```

### Multi-GPU Training

For distributed training across multiple GPUs, you can initialize separate model instances:

```python
import torch
from model_wrapper import SSSDECG

# Model on GPU 0
model_0 = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:0")

# Model on GPU 1
model_1 = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:1")
```

Or use PyTorch's `DataParallel` or `DistributedDataParallel`:

```python
import torch
import torch.nn as nn
from model_wrapper import SSSDECG

# Initialize model on cuda:0
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:0")

# Wrap with DataParallel to use all available GPUs
if torch.cuda.device_count() > 1:
print(f"Using {torch.cuda.device_count()} GPUs")
model = nn.DataParallel(model)
```

## Changes Made

The following files were modified to support arbitrary CUDA device selection:

### sssd_standalone directory:
- `utils/util.py`: Added `device` parameter to `std_normal`, `calc_diffusion_step_embedding`, `sampling_label`, and `training_loss_label` functions
- `model_wrapper.py`: Updated to pass `device` parameter to utility functions
- `models/SSSD_ECG.py`: Updated `Residual_group.forward()` to pass device to `calc_diffusion_step_embedding`

### src/sssd directory:
- `utils/util.py`: Same changes as sssd_standalone
- `model_wrapper.py`: Same changes as sssd_standalone
- `models/SSSD_ECG.py`: Same changes as sssd_standalone

## Testing

To verify that different CUDA devices work correctly, use the provided test script:

```bash
python test_cuda_devices.py
```

This script will:
1. Detect all available CUDA devices
2. Test model initialization on each device
3. Test training forward pass
4. Test generation
5. Verify all tensors are on the correct device

## Backward Compatibility

All changes are backward compatible. If you don't specify a device, the model will default to using CUDA if available (same as before), but now you have the flexibility to choose specific devices.

```python
# Old code still works
model = SSSDECG(config_path="config/config_SSSD_ECG.json")

# New code with explicit device selection
model = SSSDECG(config_path="config/config_SSSD_ECG.json", device="cuda:1")
```

## Checking Available Devices

Before initializing the model, you can check which devices are available:

```python
from model_wrapper import SSSDECG

# Print available devices
SSSDECG.print_available_devices()
# Output:
# Available devices:
# CUDA devices: 2
# - cuda:0: NVIDIA GeForce RTX 3090
# - cuda:1: NVIDIA GeForce RTX 3080
# - cpu: CPU

# Get list of available devices
devices = SSSDECG.list_available_devices()
print(devices) # ['cuda:0', 'cuda:1', 'cpu']
```

## Troubleshooting

### Error: "CUDA error: invalid device ordinal"

This error occurs when you try to use a CUDA device that doesn't exist. For example:

```python
# If you only have 1 GPU (cuda:0), this will fail:
model = SSSDECG(config_path="config.json", device="cuda:1")
```

**Solution:**

1. Check available devices first:
```python
from model_wrapper import SSSDECG
SSSDECG.print_available_devices()
```

2. The improved error message will now tell you which devices are available:
```
RuntimeError: CUDA device 'cuda:1' requested but only 1 device(s) available.
Available devices: cuda:0, cpu
```

3. Use an available device:
```python
model = SSSDECG(config_path="config.json", device="cuda:0")
```

### Error: "CUDA is not available"

This error occurs when PyTorch cannot detect any CUDA devices.

**Possible causes and solutions:**

1. **No GPU on the system:**
- Use CPU instead: `device="cpu"`

2. **CUDA drivers not installed:**
- Install appropriate NVIDIA drivers for your GPU
- Install CUDA toolkit

3. **PyTorch installed without CUDA support:**
- Check: `python -c "import torch; print(torch.cuda.is_available())"`
- If False, reinstall PyTorch with CUDA support:
```bash
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118
```

### Working with CUDA_VISIBLE_DEVICES

If you're using `CUDA_VISIBLE_DEVICES` to restrict visible GPUs, remember that PyTorch will renumber them:

```bash
# System has cuda:0, cuda:1, cuda:2, cuda:3
# Only expose cuda:1 and cuda:3
export CUDA_VISIBLE_DEVICES=1,3

# In Python, these will be cuda:0 and cuda:1
python your_script.py
```

```python
# In your script with CUDA_VISIBLE_DEVICES=1,3:
model = SSSDECG(config_path="config.json", device="cuda:0") # This is physical cuda:1
model = SSSDECG(config_path="config.json", device="cuda:1") # This is physical cuda:3
```

### Checking Device Assignment

To verify your model is on the correct device:

```python
model = SSSDECG(config_path="config.json", device="cuda:1")
print(f"Model device: {model.device}")
print(f"Model weights device: {next(model.parameters()).device}")
```
Loading