wavedl 1.5.4__tar.gz → 1.5.5__tar.gz
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.
- {wavedl-1.5.4/src/wavedl.egg-info → wavedl-1.5.5}/PKG-INFO +2 -2
- {wavedl-1.5.4 → wavedl-1.5.5}/README.md +1 -1
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/__init__.py +1 -1
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/hpo.py +2 -1
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/data.py +77 -13
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/metrics.py +22 -1
- {wavedl-1.5.4 → wavedl-1.5.5/src/wavedl.egg-info}/PKG-INFO +2 -2
- {wavedl-1.5.4 → wavedl-1.5.5}/LICENSE +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/pyproject.toml +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/setup.cfg +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/hpc.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/__init__.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/_template.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/base.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/cnn.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/convnext.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/densenet.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/efficientnet.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/efficientnetv2.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/mobilenetv3.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/registry.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/regnet.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/resnet.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/resnet3d.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/swin.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/tcn.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/unet.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/models/vit.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/test.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/train.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/__init__.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/config.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/constraints.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/cross_validation.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/distributed.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/losses.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/optimizers.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl/utils/schedulers.py +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl.egg-info/SOURCES.txt +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl.egg-info/dependency_links.txt +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl.egg-info/entry_points.txt +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl.egg-info/requires.txt +0 -0
- {wavedl-1.5.4 → wavedl-1.5.5}/src/wavedl.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: wavedl
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.5
|
|
4
4
|
Summary: A Scalable Deep Learning Framework for Wave-Based Inverse Problems
|
|
5
5
|
Author: Ductho Le
|
|
6
6
|
License: MIT
|
|
@@ -388,7 +388,7 @@ WaveDL/
|
|
|
388
388
|
├── configs/ # YAML config templates
|
|
389
389
|
├── examples/ # Ready-to-run examples
|
|
390
390
|
├── notebooks/ # Jupyter notebooks
|
|
391
|
-
├── unit_tests/ # Pytest test suite (
|
|
391
|
+
├── unit_tests/ # Pytest test suite (731 tests)
|
|
392
392
|
│
|
|
393
393
|
├── pyproject.toml # Package config, dependencies
|
|
394
394
|
├── CHANGELOG.md # Version history
|
|
@@ -342,7 +342,7 @@ WaveDL/
|
|
|
342
342
|
├── configs/ # YAML config templates
|
|
343
343
|
├── examples/ # Ready-to-run examples
|
|
344
344
|
├── notebooks/ # Jupyter notebooks
|
|
345
|
-
├── unit_tests/ # Pytest test suite (
|
|
345
|
+
├── unit_tests/ # Pytest test suite (731 tests)
|
|
346
346
|
│
|
|
347
347
|
├── pyproject.toml # Package config, dependencies
|
|
348
348
|
├── CHANGELOG.md # Version history
|
|
@@ -175,13 +175,14 @@ def create_objective(args):
|
|
|
175
175
|
env["CUDA_VISIBLE_DEVICES"] = str(gpu_id)
|
|
176
176
|
|
|
177
177
|
# Run training
|
|
178
|
+
# Note: We inherit the user's cwd instead of setting cwd=Path(__file__).parent
|
|
179
|
+
# because site-packages may be read-only and train.py creates cache directories
|
|
178
180
|
try:
|
|
179
181
|
result = subprocess.run(
|
|
180
182
|
cmd,
|
|
181
183
|
capture_output=True,
|
|
182
184
|
text=True,
|
|
183
185
|
timeout=args.timeout,
|
|
184
|
-
cwd=Path(__file__).parent,
|
|
185
186
|
env=env,
|
|
186
187
|
)
|
|
187
188
|
|
|
@@ -207,6 +207,10 @@ class NPZSource(DataSource):
|
|
|
207
207
|
|
|
208
208
|
The error for object arrays happens at ACCESS time, not load time.
|
|
209
209
|
So we need to probe the keys to detect if pickle is required.
|
|
210
|
+
|
|
211
|
+
WARNING: When mmap_mode is not None, the returned NpzFile must be kept
|
|
212
|
+
open for arrays to remain valid. Caller is responsible for closing.
|
|
213
|
+
For non-mmap loading, use _load_and_copy() instead to avoid leaks.
|
|
210
214
|
"""
|
|
211
215
|
data = np.load(path, allow_pickle=False, mmap_mode=mmap_mode)
|
|
212
216
|
try:
|
|
@@ -222,6 +226,26 @@ class NPZSource(DataSource):
|
|
|
222
226
|
return np.load(path, allow_pickle=True, mmap_mode=mmap_mode)
|
|
223
227
|
raise
|
|
224
228
|
|
|
229
|
+
@staticmethod
|
|
230
|
+
def _load_and_copy(path: str, keys: list[str]) -> dict[str, np.ndarray]:
|
|
231
|
+
"""Load NPZ and copy arrays, ensuring file is properly closed.
|
|
232
|
+
|
|
233
|
+
This prevents file descriptor leaks by copying arrays before closing.
|
|
234
|
+
Use this for eager loading; use _safe_load for memory-mapped access.
|
|
235
|
+
"""
|
|
236
|
+
data = NPZSource._safe_load(path, keys, mmap_mode=None)
|
|
237
|
+
try:
|
|
238
|
+
result = {}
|
|
239
|
+
for key in keys:
|
|
240
|
+
if key in data:
|
|
241
|
+
arr = data[key]
|
|
242
|
+
# Copy ensures we don't hold reference to mmap
|
|
243
|
+
result[key] = arr.copy() if hasattr(arr, "copy") else arr
|
|
244
|
+
return result
|
|
245
|
+
finally:
|
|
246
|
+
if hasattr(data, "close"):
|
|
247
|
+
data.close()
|
|
248
|
+
|
|
225
249
|
def load(self, path: str) -> tuple[np.ndarray, np.ndarray]:
|
|
226
250
|
"""Load NPZ file (pickle enabled only for sparse matrices)."""
|
|
227
251
|
# First pass to find keys without loading data
|
|
@@ -238,7 +262,7 @@ class NPZSource(DataSource):
|
|
|
238
262
|
f"Found: {keys}"
|
|
239
263
|
)
|
|
240
264
|
|
|
241
|
-
data = self.
|
|
265
|
+
data = self._load_and_copy(path, [input_key, output_key])
|
|
242
266
|
inp = data[input_key]
|
|
243
267
|
outp = data[output_key]
|
|
244
268
|
|
|
@@ -290,7 +314,7 @@ class NPZSource(DataSource):
|
|
|
290
314
|
f"Supported keys: {OUTPUT_KEYS}. Found: {keys}"
|
|
291
315
|
)
|
|
292
316
|
|
|
293
|
-
data = self.
|
|
317
|
+
data = self._load_and_copy(path, [output_key])
|
|
294
318
|
return data[output_key]
|
|
295
319
|
|
|
296
320
|
|
|
@@ -527,9 +551,17 @@ class MATSource(DataSource):
|
|
|
527
551
|
inp = self._load_dataset(f, input_key)
|
|
528
552
|
outp = self._load_dataset(f, output_key)
|
|
529
553
|
|
|
530
|
-
# Handle
|
|
531
|
-
|
|
532
|
-
|
|
554
|
+
# Handle transposed outputs from MATLAB.
|
|
555
|
+
# Case 1: (1, N) - N samples with 1 target → transpose to (N, 1)
|
|
556
|
+
# Case 2: (T, 1) - 1 sample with T targets → transpose to (1, T)
|
|
557
|
+
num_samples = inp.shape[0] # inp is already transposed
|
|
558
|
+
if outp.ndim == 2:
|
|
559
|
+
if outp.shape[0] == 1 and outp.shape[1] == num_samples:
|
|
560
|
+
# 1D vector: (1, N) → (N, 1)
|
|
561
|
+
outp = outp.T
|
|
562
|
+
elif outp.shape[1] == 1 and outp.shape[0] != num_samples:
|
|
563
|
+
# Single sample with multiple targets: (T, 1) → (1, T)
|
|
564
|
+
outp = outp.T
|
|
533
565
|
|
|
534
566
|
except OSError as e:
|
|
535
567
|
raise ValueError(
|
|
@@ -614,7 +646,10 @@ class MATSource(DataSource):
|
|
|
614
646
|
# Load with sparse matrix support
|
|
615
647
|
outp = self._load_dataset(f, output_key)
|
|
616
648
|
|
|
617
|
-
# Handle 1D outputs
|
|
649
|
+
# Handle 1D outputs that become (1, N) after transpose.
|
|
650
|
+
# Note: This method has no input to compare against, so we can't
|
|
651
|
+
# distinguish single-sample outputs. This is acceptable for training
|
|
652
|
+
# data where single-sample is unlikely. For inference, use load_test_data.
|
|
618
653
|
if outp.ndim == 2 and outp.shape[0] == 1:
|
|
619
654
|
outp = outp.T
|
|
620
655
|
|
|
@@ -775,7 +810,7 @@ def load_test_data(
|
|
|
775
810
|
raise KeyError(
|
|
776
811
|
f"Input key not found. Tried: {custom_input_keys}. Found: {keys}"
|
|
777
812
|
)
|
|
778
|
-
data = NPZSource.
|
|
813
|
+
data = NPZSource._load_and_copy(
|
|
779
814
|
path, [inp_key] + ([out_key] if out_key else [])
|
|
780
815
|
)
|
|
781
816
|
inp = data[inp_key]
|
|
@@ -824,8 +859,17 @@ def load_test_data(
|
|
|
824
859
|
inp = mat_source._load_dataset(f, inp_key)
|
|
825
860
|
if out_key:
|
|
826
861
|
outp = mat_source._load_dataset(f, out_key)
|
|
827
|
-
|
|
828
|
-
|
|
862
|
+
# Handle transposed outputs from MATLAB
|
|
863
|
+
# Case 1: (1, N) - N samples with 1 target → transpose to (N, 1)
|
|
864
|
+
# Case 2: (T, 1) - 1 sample with T targets → transpose to (1, T)
|
|
865
|
+
num_samples = inp.shape[0]
|
|
866
|
+
if outp.ndim == 2:
|
|
867
|
+
if outp.shape[0] == 1 and outp.shape[1] == num_samples:
|
|
868
|
+
# 1D vector: (1, N) → (N, 1)
|
|
869
|
+
outp = outp.T
|
|
870
|
+
elif outp.shape[1] == 1 and outp.shape[0] != num_samples:
|
|
871
|
+
# Single sample with multiple targets: (T, 1) → (1, T)
|
|
872
|
+
outp = outp.T
|
|
829
873
|
else:
|
|
830
874
|
outp = None
|
|
831
875
|
else:
|
|
@@ -844,7 +888,7 @@ def load_test_data(
|
|
|
844
888
|
)
|
|
845
889
|
out_key = DataSource._find_key(keys, custom_output_keys)
|
|
846
890
|
keys_to_probe = [inp_key] + ([out_key] if out_key else [])
|
|
847
|
-
data = NPZSource.
|
|
891
|
+
data = NPZSource._load_and_copy(path, keys_to_probe)
|
|
848
892
|
inp = data[inp_key]
|
|
849
893
|
if inp.dtype == object:
|
|
850
894
|
inp = np.array(
|
|
@@ -894,9 +938,17 @@ def load_test_data(
|
|
|
894
938
|
out_key = DataSource._find_key(keys, custom_output_keys)
|
|
895
939
|
if out_key:
|
|
896
940
|
outp = mat_source._load_dataset(f, out_key)
|
|
897
|
-
# Handle
|
|
898
|
-
|
|
899
|
-
|
|
941
|
+
# Handle transposed outputs from MATLAB
|
|
942
|
+
# Case 1: (1, N) - N samples with 1 target → transpose to (N, 1)
|
|
943
|
+
# Case 2: (T, 1) - 1 sample with T targets → transpose to (1, T)
|
|
944
|
+
num_samples = inp.shape[0]
|
|
945
|
+
if outp.ndim == 2:
|
|
946
|
+
if outp.shape[0] == 1 and outp.shape[1] == num_samples:
|
|
947
|
+
# 1D vector: (1, N) → (N, 1)
|
|
948
|
+
outp = outp.T
|
|
949
|
+
elif outp.shape[1] == 1 and outp.shape[0] != num_samples:
|
|
950
|
+
# Single sample with multiple targets: (T, 1) → (1, T)
|
|
951
|
+
outp = outp.T
|
|
900
952
|
else:
|
|
901
953
|
outp = None
|
|
902
954
|
else:
|
|
@@ -1153,6 +1205,18 @@ def prepare_data(
|
|
|
1153
1205
|
logger.warning(
|
|
1154
1206
|
f" Failed to remove stale cache {stale_file}: {e}"
|
|
1155
1207
|
)
|
|
1208
|
+
|
|
1209
|
+
# Fail explicitly if stale cache files couldn't be removed
|
|
1210
|
+
# This prevents silent reuse of outdated data
|
|
1211
|
+
remaining_stale = [
|
|
1212
|
+
f for f in [CACHE_FILE, SCALER_FILE] if os.path.exists(f)
|
|
1213
|
+
]
|
|
1214
|
+
if remaining_stale:
|
|
1215
|
+
raise RuntimeError(
|
|
1216
|
+
f"Cannot regenerate cache: stale files could not be removed. "
|
|
1217
|
+
f"Please manually delete: {remaining_stale}"
|
|
1218
|
+
)
|
|
1219
|
+
|
|
1156
1220
|
# RANK 0: Create cache (can take a long time for large datasets)
|
|
1157
1221
|
# Other ranks will wait at the barrier below
|
|
1158
1222
|
|
|
@@ -815,7 +815,28 @@ def plot_qq(
|
|
|
815
815
|
|
|
816
816
|
# Standardize errors for QQ plot
|
|
817
817
|
err = errors[:, i]
|
|
818
|
-
|
|
818
|
+
std_err = np.std(err)
|
|
819
|
+
|
|
820
|
+
# Guard against zero variance (constant errors)
|
|
821
|
+
if std_err < 1e-10:
|
|
822
|
+
title = (
|
|
823
|
+
param_names[i] if param_names and i < len(param_names) else f"Param {i}"
|
|
824
|
+
)
|
|
825
|
+
ax.text(
|
|
826
|
+
0.5,
|
|
827
|
+
0.5,
|
|
828
|
+
"Zero variance\n(constant errors)",
|
|
829
|
+
ha="center",
|
|
830
|
+
va="center",
|
|
831
|
+
fontsize=10,
|
|
832
|
+
transform=ax.transAxes,
|
|
833
|
+
)
|
|
834
|
+
ax.set_title(f"{title}\n(zero variance)")
|
|
835
|
+
ax.set_xlabel("Theoretical Quantiles")
|
|
836
|
+
ax.set_ylabel("Sample Quantiles")
|
|
837
|
+
continue
|
|
838
|
+
|
|
839
|
+
standardized = (err - np.mean(err)) / std_err
|
|
819
840
|
|
|
820
841
|
# Calculate theoretical quantiles and sample quantiles
|
|
821
842
|
(osm, osr), (slope, intercept, r) = stats.probplot(standardized, dist="norm")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: wavedl
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.5
|
|
4
4
|
Summary: A Scalable Deep Learning Framework for Wave-Based Inverse Problems
|
|
5
5
|
Author: Ductho Le
|
|
6
6
|
License: MIT
|
|
@@ -388,7 +388,7 @@ WaveDL/
|
|
|
388
388
|
├── configs/ # YAML config templates
|
|
389
389
|
├── examples/ # Ready-to-run examples
|
|
390
390
|
├── notebooks/ # Jupyter notebooks
|
|
391
|
-
├── unit_tests/ # Pytest test suite (
|
|
391
|
+
├── unit_tests/ # Pytest test suite (731 tests)
|
|
392
392
|
│
|
|
393
393
|
├── pyproject.toml # Package config, dependencies
|
|
394
394
|
├── CHANGELOG.md # Version history
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|