dfm-python 0.5.54__py3-none-any.whl → 0.5.56__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 (60) hide show
  1. dfm_python/__init__.py +19 -49
  2. dfm_python/config/__init__.py +7 -5
  3. dfm_python/config/constants.py +145 -7
  4. dfm_python/config/schema/__init__.py +12 -6
  5. dfm_python/config/schema/model.py +75 -15
  6. dfm_python/config/schema/params.py +94 -0
  7. dfm_python/config/schema/results.py +126 -31
  8. dfm_python/config/types.py +54 -17
  9. dfm_python/dataset/__init__.py +8 -47
  10. dfm_python/dataset/ddfm_dataset.py +371 -0
  11. dfm_python/{datamodule/dfm_dm.py → dataset/dfm_dataset.py} +254 -91
  12. dfm_python/dataset/time.py +97 -0
  13. dfm_python/decoder/__init__.py +3 -1
  14. dfm_python/decoder/base.py +78 -0
  15. dfm_python/decoder/linear.py +63 -59
  16. dfm_python/decoder/mlp.py +117 -126
  17. dfm_python/encoder/__init__.py +9 -9
  18. dfm_python/encoder/pca.py +6 -5
  19. dfm_python/encoder/simple_autoencoder.py +292 -0
  20. dfm_python/functional/em.py +25 -6
  21. dfm_python/functional/irf.py +4 -4
  22. dfm_python/logger/__init__.py +24 -8
  23. dfm_python/logger/inference_logger.py +56 -30
  24. dfm_python/logger/train_logger.py +86 -65
  25. dfm_python/models/__init__.py +2 -10
  26. dfm_python/models/base.py +103 -384
  27. dfm_python/models/ddfm.py +738 -1695
  28. dfm_python/models/dfm.py +311 -265
  29. dfm_python/numeric/estimator.py +234 -25
  30. dfm_python/numeric/stability.py +78 -16
  31. dfm_python/numeric/statistic.py +353 -0
  32. dfm_python/numeric/validator.py +333 -6
  33. dfm_python/ssm/companion.py +4 -4
  34. dfm_python/ssm/kalman.py +2 -1
  35. dfm_python/utils/__init__.py +50 -148
  36. dfm_python/utils/checkpoint.py +295 -0
  37. dfm_python/utils/helper.py +62 -152
  38. dfm_python/utils/loss.py +100 -0
  39. dfm_python/utils/misc.py +164 -171
  40. {dfm_python-0.5.54.dist-info → dfm_python-0.5.56.dist-info}/METADATA +1 -1
  41. dfm_python-0.5.56.dist-info/RECORD +58 -0
  42. dfm_python/datamodule/__init__.py +0 -31
  43. dfm_python/datamodule/base.py +0 -618
  44. dfm_python/datamodule/ddfm_dm.py +0 -276
  45. dfm_python/datamodule/kdfm_dm.py +0 -180
  46. dfm_python/dataset/dataloader.py +0 -142
  47. dfm_python/dataset/dataset.py +0 -158
  48. dfm_python/dataset/process.py +0 -435
  49. dfm_python/encoder/simple_encoder.py +0 -474
  50. dfm_python/encoder/variational_encoder.py +0 -0
  51. dfm_python/models/kdfm.py +0 -1855
  52. dfm_python/trainer/__init__.py +0 -679
  53. dfm_python/trainer/ddfm.py +0 -656
  54. dfm_python/trainer/dfm.py +0 -156
  55. dfm_python/trainer/kdfm.py +0 -138
  56. dfm_python/utils/common.py +0 -298
  57. dfm_python/utils/tensor_utils.py +0 -199
  58. dfm_python-0.5.54.dist-info/RECORD +0 -66
  59. {dfm_python-0.5.54.dist-info → dfm_python-0.5.56.dist-info}/WHEEL +0 -0
  60. {dfm_python-0.5.54.dist-info → dfm_python-0.5.56.dist-info}/licenses/LICENSE +0 -0
dfm_python/__init__.py CHANGED
@@ -23,40 +23,36 @@ Key Features:
23
23
  - Robust handling of missing data (internal spline interpolation)
24
24
  - Automatic standardization and data clipping
25
25
 
26
- Example (Standard Lightning Pattern):
27
- >>> from dfm_python import DFM, DFMDataModule, DFMTrainer
26
+ Example:
27
+ >>> from dfm_python import DFM, DFMDataset
28
28
  >>> import pandas as pd
29
29
  >>>
30
30
  >>> # Step 1: Load and preprocess data
31
31
  >>> df = pd.read_csv('data/your_data.csv')
32
32
  >>> df_processed = df[[col for col in df.columns if col != 'date']]
33
33
  >>>
34
- >>> # Step 2: Create DataModule
35
- >>> dm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
36
- >>> dm.setup()
34
+ >>> # Step 2: Create Dataset
35
+ >>> dataset = DFMDataset(config_path='config/default.yaml', data=df_processed)
37
36
  >>>
38
37
  >>> # Step 3: Create model and load config
39
38
  >>> model = DFM()
40
39
  >>> model.load_config('config/default.yaml')
41
40
  >>>
42
- >>> # Step 4: Create trainer and fit (standard Lightning pattern)
43
- >>> trainer = DFMTrainer(max_epochs=100) # DEFAULT_MAX_EPOCHS
44
- >>> trainer.fit(model, dm)
41
+ >>> # Step 4: Fit model
42
+ >>> model.fit(X=dataset.get_processed_data(), dataset=dataset)
45
43
  >>>
46
44
  >>> # Step 5: Predict
47
45
  >>> Xf, Zf = model.predict(horizon=6)
48
46
  >>>
49
- >>> # Or use DDFM (same pattern)
50
- >>> from dfm_python import DDFM, DDFMTrainer
47
+ >>> # Or use DDFM
48
+ >>> from dfm_python import DDFM, DDFMDataset
51
49
  >>>
52
- >>> dm_ddfm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
53
- >>> dm_ddfm.setup()
50
+ >>> dataset_ddfm = DDFMDataset(config_path='config/default.yaml', data=df_processed)
54
51
  >>>
55
52
  >>> ddfm_model = DDFM(encoder_layers=[64, 32], num_factors=2)
56
53
  >>> ddfm_model.load_config('config/default.yaml')
57
54
  >>>
58
- >>> trainer_ddfm = DDFMTrainer(max_epochs=100) # DEFAULT_MAX_EPOCHS
59
- >>> trainer_ddfm.fit(ddfm_model, dm_ddfm)
55
+ >>> ddfm_model.train(dataset=dataset_ddfm)
60
56
  >>> Xf, Zf = ddfm_model.predict(horizon=6)
61
57
 
62
58
  Note: DFMConfig uses frequency dict to specify series (column names -> frequencies).
@@ -65,7 +61,7 @@ Note: DFMConfig uses frequency dict to specify series (column names -> frequenci
65
61
  For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
66
62
  """
67
63
 
68
- __version__ = "0.5.54"
64
+ __version__ = "0.5.56"
69
65
 
70
66
  # ============================================================================
71
67
  # PUBLIC API DEFINITION
@@ -92,20 +88,15 @@ from .config import (
92
88
  from .config import DFMConfig
93
89
 
94
90
  # Results
95
- from .config import DFMResult, DDFMResult, KDFMResult, BaseResult
91
+ from .config import DFMResult, DDFMResult, BaseResult
96
92
 
97
93
  # Utilities (from utils/ subpackage)
98
94
  from .utils.metric import calculate_rmse
99
95
 
100
- # DataModule classes (includes both Lightning and custom implementations)
96
+ # Dataset classes
101
97
  # Users can import these directly from dfm_python
102
- from .datamodule import (
103
- DFMDataModule,
104
- DDFMDataModule, # DDFM-specific DataModule
105
- KDFMDataModule, # KDFM-specific DataModule
106
- DDFMDataset, # DDFM Dataset class (usually not needed directly)
107
- KDFMDataset, # KDFM Dataset class (usually not needed directly)
108
- )
98
+ from .dataset.dfm_dataset import DFMDataset
99
+ from .dataset.ddfm_dataset import DDFMDataset
109
100
 
110
101
  # Model implementations
111
102
  from .models.base import BaseFactorModel
@@ -114,9 +105,6 @@ from .models.dfm import DFM
114
105
  # DDFM high-level API (PyTorch is mandatory)
115
106
  from .models.ddfm import DDFM
116
107
 
117
- # KDFM high-level API
118
- from .models.kdfm import KDFM
119
-
120
108
  __all__ = [
121
109
  # Core classes
122
110
  'DFM',
@@ -126,7 +114,7 @@ __all__ = [
126
114
  'ConfigSource', 'YamlSource',
127
115
  'make_config_source',
128
116
  # Low-level API (functional interface - advanced usage)
129
- 'BaseResult', 'DFMResult', 'DDFMResult', 'KDFMResult', 'calculate_rmse',
117
+ 'BaseResult', 'DFMResult', 'DDFMResult', 'calculate_rmse',
130
118
  ]
131
119
 
132
120
  # DDFM high-level API (PyTorch is mandatory)
@@ -134,27 +122,9 @@ __all__.extend([
134
122
  'DDFM', # High-level API class
135
123
  ])
136
124
 
137
- # KDFM high-level API
138
- __all__.extend([
139
- 'KDFM', # High-level API class
140
- ])
141
-
142
- # Lightning modules (mandatory dependency)
125
+ # Dataset classes
143
126
  __all__.extend([
144
- 'DFMDataModule',
145
- 'DDFMDataModule', # DDFM-specific DataModule
146
- 'KDFMDataModule', # KDFM-specific DataModule
147
- 'DDFMDataset', # DDFM Dataset class (usually not needed directly)
148
- 'KDFMDataset', # KDFM Dataset class (usually not needed directly)
127
+ 'DFMDataset', # DFM Dataset class
128
+ 'DDFMDataset', # DDFM Dataset class
149
129
  ])
150
130
 
151
- # Trainer classes (mandatory dependency)
152
- from .trainer import DFMTrainer, DDFMTrainer, KDFMTrainer
153
-
154
- __all__.extend([
155
- 'DFMTrainer',
156
- 'DDFMTrainer',
157
- 'KDFMTrainer',
158
- ])
159
-
160
-
@@ -8,8 +8,9 @@ Note: Series are specified via frequency dict mapping column names to frequencie
8
8
  """
9
9
 
10
10
  from .schema import (
11
- BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig,
12
- BaseResult, DFMResult, DDFMResult, KDFMResult, FitParams,
11
+ BaseModelConfig, DFMConfig, DDFMConfig,
12
+ BaseResult, DFMResult, DDFMResult,
13
+ DFMFitParams, DDFMFitParams, FitParams, # FitParams is backward compatibility alias
13
14
  )
14
15
  # DEFAULT_BLOCK_NAME is imported lazily where needed to avoid circular imports
15
16
  from .constants import (
@@ -105,11 +106,12 @@ __all__ = [
105
106
  'BaseModelConfig', 'BaseResult',
106
107
  # 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import - import directly from functional.dfm_block
107
108
  # Model-specific configs (from schema.py)
108
- 'DFMConfig', 'DDFMConfig', 'KDFMConfig',
109
+ 'DFMConfig', 'DDFMConfig',
109
110
  # Parameter overrides
110
- 'FitParams',
111
+ 'DFMFitParams', 'DDFMFitParams',
112
+ 'FitParams', # Backward compatibility alias
111
113
  # Model-specific results (from results.py)
112
- 'DFMResult', 'DDFMResult', 'KDFMResult',
114
+ 'DFMResult', 'DDFMResult',
113
115
  # Utilities
114
116
  'validate_frequency',
115
117
  # IO
@@ -26,8 +26,10 @@ DEFAULT_MIN_DELTA = 1e-6 # Minimum change for improvement
26
26
  MIN_EIGENVALUE = 1e-8 # Minimum eigenvalue for positive definite matrices
27
27
  MIN_DIAGONAL_VARIANCE = 1e-8 # Minimum variance for diagonal elements
28
28
  MIN_OBSERVATION_NOISE = 1e-4 # Minimum observation noise for measurement error (used in EM updates)
29
+ DEFAULT_DDFM_OBSERVATION_NOISE = 1e-15 # Default observation noise for DDFM state-space (matches original TensorFlow)
29
30
  MIN_FACTOR_VARIANCE = 1e-10 # Minimum variance for factors
30
31
  MIN_STD = 1e-8 # Minimum standard deviation
32
+ MIN_STD_FOR_SCALE_CHECK = 1e-10 # Minimum standard deviation for scale ratio computation (more lenient than MIN_STD)
31
33
  DEFAULT_VARIANCE_FALLBACK = 1.0 # Default variance fallback value for numerical stability
32
34
 
33
35
  # Maximum eigenvalues
@@ -44,8 +46,11 @@ DEFAULT_CLEAN_INF = MAX_EIGENVALUE # Default value for Inf replacement in clean
44
46
  # Identity matrix defaults
45
47
  DEFAULT_IDENTITY_SCALE = 1.0 # Default scale for create_scaled_identity(n, 1.0)
46
48
  DEFAULT_ZERO_VALUE = 0.0 # Default zero value for explicit zero assignments
47
- DEFAULT_XAVIER_GAIN = 1.0 # Default gain for Xavier initialization
48
- DEFAULT_OUTPUT_LAYER_GAIN = 0.1 # Default gain for output layer Xavier initialization (smaller for stability)
49
+ DEFAULT_INF_VALUE = float('inf') # Default infinity value for loss/scale comparisons
50
+ DEFAULT_XAVIER_GAIN = 1.0 # Default gain for Xavier initialization (matches TensorFlow GlorotNormal)
51
+ DEFAULT_OUTPUT_LAYER_GAIN = 1.0 # Default gain for output layer Xavier initialization (matches original TensorFlow DDFM GlorotNormal for all layers)
52
+ # NOTE: Original TensorFlow DDFM uses GlorotNormal (gain=1.0) for all layers including output layer.
53
+ # Updated to match original TensorFlow behavior to address training divergence (encoder weights too small, near-zero factors).
49
54
 
50
55
  # Companion matrix initialization defaults
51
56
  DEFAULT_INIT_SCALE = 0.01 # Default initialization scale for companion matrix B and C matrices
@@ -59,6 +64,41 @@ DEFAULT_REGULARIZATION = 1e-6 # Default regularization value
59
64
  DEFAULT_CLIP_THRESHOLD = 10.0 # Default clipping threshold (in standard deviations)
60
65
  DEFAULT_DATA_CLIP_THRESHOLD = 100.0 # Default data clipping threshold
61
66
 
67
+ # Scale validation thresholds (for DDFM scale alignment checks)
68
+ DEFAULT_SCALE_RATIO_MAX = 10.0 # Maximum acceptable scale ratio (prediction std / data std)
69
+ DEFAULT_SCALE_RATIO_MIN = 0.1 # Minimum acceptable scale ratio (prediction std / data std)
70
+ DEFAULT_STANDARDIZATION_MEAN_THRESHOLD = 0.1 # Maximum acceptable absolute mean for standardized data (mean should be ≈0)
71
+ DEFAULT_STANDARDIZATION_STD_MIN = 0.1 # Minimum acceptable std for standardized data (std should be ≈1)
72
+ DEFAULT_STANDARDIZATION_STD_MAX = 10.0 # Maximum acceptable std for standardized data (std should be ≈1)
73
+ DEFAULT_STANDARDIZED_TARGET_STD = 1.0 # Target std for standardized data (std should be ≈1.0 for StandardScaler)
74
+
75
+ # Variance collapse diagnostics thresholds (for DDFM variance collapse detection)
76
+ DEFAULT_VARIANCE_COLLAPSE_THRESHOLD = 0.1 # Prediction std threshold for variance collapse detection (std < 0.1 indicates collapse)
77
+ DEFAULT_FACTOR_COLLAPSE_THRESHOLD = 0.01 # Factor magnitude threshold for factor collapse detection (|mean| < 0.01 indicates collapse)
78
+ DEFAULT_BATCHNORM_SUPPRESSION_THRESHOLD = 0.01 # BatchNorm running_var threshold for signal suppression detection (var < 0.01 indicates suppression)
79
+ DEFAULT_TIMESTEP_COLLAPSE_THRESHOLD = 0.1 # Per-time-step std threshold for localized collapse detection (std < 0.1 indicates collapse)
80
+ DEFAULT_TIMESTEP_COLLAPSE_RATIO_THRESHOLD = 0.5 # Ratio threshold for localized collapse (ratio > 0.5 indicates widespread collapse)
81
+ DEFAULT_EXPECTED_FACTOR_MAGNITUDE_MIN = 0.1 # Expected minimum factor magnitude (for warning messages)
82
+ DEFAULT_EXPECTED_FACTOR_MAGNITUDE_MAX = 1.0 # Expected maximum factor magnitude (for warning messages)
83
+
84
+ # DDFM reproduction target values (for debugging and diagnostics)
85
+ DEFAULT_TARGET_PREDICTION_STD = 1.0 # Target prediction std for standardized data (should be ~1.0 for StandardScaler)
86
+ DEFAULT_VARIANCE_COLLAPSE_STD = 0.03 # Observed variance collapse std (std ~0.03 vs target ~1.0)
87
+ DEFAULT_TARGET_CONVERGENCE_ITERATIONS = 10 # Target convergence iterations for exchange_rate dataset (TensorFlow reference)
88
+ DEFAULT_TARGET_DDFM_LOSS = 0.56 # Target DDFM training loss for exchange_rate dataset (TensorFlow reference)
89
+ DEFAULT_DDFM_LOSS_MULTIPLIER = 1.8 # Current loss multiplier vs target (1.00 vs 0.56 = 1.8x)
90
+
91
+ # Logging precision constants
92
+ DEFAULT_SCALE_LOG_PRECISION = 6 # Default precision for scale logging format strings (e.g., .6f)
93
+ DEFAULT_TIME_LOG_PRECISION = 2 # Default precision for time logging format strings (e.g., .2f)
94
+ DEFAULT_LOSS_LOG_PRECISION = 6 # Default precision for loss/delta logging format strings (e.g., .6f)
95
+
96
+ # Time conversion constants
97
+ SECONDS_PER_MINUTE = 60 # Seconds per minute (for time conversion)
98
+
99
+ # Logging level constants
100
+ LOGGING_DEBUG_LEVEL = 10 # logging.DEBUG level for conditional checks
101
+
62
102
  # ============================================================================
63
103
  # Training Defaults
64
104
  # ============================================================================
@@ -68,15 +108,41 @@ DEFAULT_MAX_ITER = 100 # Default maximum EM iterations (general)
68
108
  DEFAULT_EM_MAX_ITER = 5000 # Default maximum EM iterations (DFM-specific)
69
109
  DEFAULT_MAX_EPOCHS = 100 # Default maximum training epochs
70
110
  DEFAULT_MAX_MCMC_ITER = 200 # Default maximum MCMC iterations
111
+ DEFAULT_N_MC_SAMPLES = 10 # Default number of MC samples per MCMC iteration for DDFM denoising training (matches original TensorFlow epochs=10 default, per experiment/config/model/ddfm.yaml)
112
+ DEFAULT_FACTOR_ORDER = 1 # Default factor order for DDFM (AR(1) dynamics)
113
+ DEFAULT_AR_ORDER_2 = 2 # Default AR order 2 for DDFM forecast (AR(2) dynamics)
71
114
 
72
115
  # Batch size defaults
73
116
  DEFAULT_BATCH_SIZE = 32 # Default batch size for neural networks
74
- DEFAULT_DDFM_BATCH_SIZE = 100 # Default batch size for DDFM
117
+ DEFAULT_DDFM_WINDOW_SIZE = 100 # Default window size (time-step batch size) for DDFM
118
+ DEFAULT_DDFM_BATCH_SIZE = 100 # Default batch size for DDFM (matches original TensorFlow batch_size=100)
119
+
120
+ # DDFM target interpolation defaults
121
+ DEFAULT_MIN_TARGET_INTERPOLATE_RATIO = 0.3 # Default minimum target interpolate ratio threshold for DDFM (ratio of missing target values above which interpolation is skipped)
122
+
123
+ # MCMC training defaults (for DDFM sequential MC processing)
124
+ DEFAULT_MCMC_EPOCHS = 1 # Default epochs per MC sample (MCMC training pattern: one epoch per MC sample)
125
+ DEFAULT_MCMC_VERBOSE = 0 # Default verbosity for MCMC training (silent training)
126
+
127
+ # Placeholder defaults (for DDFM placeholder MC dataset)
128
+ DEFAULT_PLACEHOLDER_MC_SAMPLES = 1 # Minimal MC samples for placeholder dataset (replaced after on_train_start)
129
+ DEFAULT_PLACEHOLDER_DATA_SHAPE_T = 100 # Default time steps for placeholder data shape
130
+ DEFAULT_PLACEHOLDER_DATA_SHAPE_N = 10 # Default number of series for placeholder data shape
131
+ DEFAULT_PLACEHOLDER_SEED = 42 # Seed for placeholder random state (common test value, placeholder gets replaced)
132
+ DEFAULT_NUM_WORKERS = 0 # Default number of workers for DataLoader (0 = single-threaded)
133
+ DEFAULT_CUDA_DEVICE_INDEX = 0 # Default CUDA device index for GPU operations (0 = first GPU)
134
+
135
+ # Initialization sample size defaults
136
+ DEFAULT_KDFM_INIT_SAMPLE_SIZE = 100 # Default sample size for KDFM initialization (first N rows used for initialize_from_data)
75
137
 
76
138
  # Learning rate defaults
77
139
  DEFAULT_LEARNING_RATE = 0.001 # Default learning rate
78
140
  DEFAULT_DDFM_LEARNING_RATE = 0.005 # Default learning rate for DDFM
79
141
 
142
+ # Autoencoder training defaults (matches original TensorFlow pattern)
143
+ DEFAULT_AUTOENCODER_FIT_EPOCHS = 1 # Number of epochs per MC sample (matches original TensorFlow: epochs=1 per autoencoder.fit() call)
144
+ DEFAULT_AUTOENCODER_FIT_VERBOSE = 0 # Verbosity level for autoencoder.fit() (0 = silent, matches original TensorFlow verbose=0)
145
+
80
146
  # Gradient clipping
81
147
  DEFAULT_GRAD_CLIP_VAL = 1.0 # Default gradient clipping value
82
148
 
@@ -86,6 +152,22 @@ DEFAULT_WEIGHT_DECAY = 0.0 # Default weight decay (L2 regularization)
86
152
  # Learning rate decay
87
153
  DEFAULT_LR_DECAY_RATE = 0.96 # Default exponential decay rate for learning rate
88
154
 
155
+ # Optimizer defaults
156
+ VALID_OPTIMIZERS = {'Adam', 'AdamW', 'SGD'} # Valid optimizer types for DDFM
157
+
158
+ # Adam optimizer defaults
159
+ DEFAULT_ADAM_BETA1 = 0.9 # Default beta1 (momentum decay) for Adam optimizer
160
+ DEFAULT_ADAM_BETA2 = 0.999 # Default beta2 (squared gradient decay) for Adam optimizer
161
+ DEFAULT_ADAM_EPS = 1e-7 # Default epsilon for Adam optimizer (matches TensorFlow default for DDFM compatibility)
162
+ DEFAULT_PYTORCH_ADAM_EPS = 1e-8 # PyTorch default epsilon for Adam optimizer (for reference)
163
+
164
+ # Batch normalization defaults (matching TensorFlow/Keras defaults)
165
+ DEFAULT_BATCH_NORM_MOMENTUM = 0.99 # TensorFlow/Keras BatchNormalization default momentum
166
+ DEFAULT_BATCH_NORM_EPS = 1e-3 # TensorFlow/Keras BatchNormalization default epsilon
167
+
168
+ # Random seed defaults
169
+ DEFAULT_RANDOM_SEED_MAX = 2**31 # Maximum value for random seed generation (2147483647, 32-bit signed integer max)
170
+
89
171
  # Loss function defaults
90
172
  DEFAULT_HUBER_DELTA = 1.0 # Default delta parameter for Huber loss
91
173
  HUBER_QUADRATIC_COEFF = 0.5 # Quadratic coefficient for Huber loss (0.5 * a^2 term)
@@ -115,7 +197,11 @@ CHOLESKY_LOG_DET_FACTOR = 2.0 # Factor for log determinant computation from Cho
115
197
  # ============================================================================
116
198
 
117
199
  # Encoder layer defaults
118
- DEFAULT_ENCODER_LAYERS = [64, 32] # Default encoder layer sizes
200
+ DEFAULT_ENCODER_LAYERS = [16, 4] # Default encoder layer sizes (matches experiment config and ddfm.py default parameter)
201
+ DEFAULT_NUM_FACTORS = 3 # Default number of factors for DDFM
202
+ DEFAULT_ACTIVATION = 'relu' # Default activation function for DDFM
203
+ DEFAULT_DECODER = 'linear' # Default decoder type for DDFM
204
+ DEFAULT_USE_BATCH_NORM = True # Default batch normalization setting for DDFM
119
205
 
120
206
  # ============================================================================
121
207
  # Data Processing Defaults
@@ -131,8 +217,8 @@ DEFAULT_START_DATE = datetime(2000, 1, 1)
131
217
  # Default window size for DDFM
132
218
  DEFAULT_WINDOW_SIZE = 100
133
219
  DEFAULT_TENT_KERNEL_SIZE = 5 # Default tent kernel size for slower-frequency series aggregation
134
- # Note: DEFAULT_BATCH_SIZE is defined above (line 52) as 32 for general neural networks
135
- # Use DEFAULT_DDFM_BATCH_SIZE (100) for DDFM-specific batch size
220
+ # Note: DEFAULT_BATCH_SIZE is defined above (line 88) as 32 for general neural networks
221
+ # Use DEFAULT_DDFM_WINDOW_SIZE (100) for DDFM-specific window size (time-step batch size)
136
222
 
137
223
  # Warning/display limits
138
224
  MAX_WARNING_ITEMS = 5 # Maximum number of items to show in warning messages
@@ -142,6 +228,9 @@ MAX_ERROR_ITEMS = 20 # Maximum number of items to show in error message details
142
228
  DEFAULT_MIN_OBS = 5 # Default minimum observations for estimation
143
229
  DEFAULT_MIN_OBS_IDIO = 5 # Default minimum observations for idio estimation
144
230
  DEFAULT_MIN_OBS_VAR = 7 # Minimum observations for VAR estimation (order + 5)
231
+ DEFAULT_MIN_OBS_PRETRAIN = 50 # Minimum observations for DDFM pre-training without interpolation
232
+ DEFAULT_MULT_EPOCH_PRETRAIN = 1 # Multiplier for DDFM pre-training epochs
233
+ DEFAULT_PRETRAIN_EPOCHS = 200 # Default number of epochs for DDFM pre-training (matching original paper)
145
234
 
146
235
  # Dimension validation bounds
147
236
  MIN_TIME_STEPS = 1 # Minimum number of time steps (T) required for data
@@ -149,7 +238,9 @@ MIN_VARIABLES = 1 # Minimum number of variables (N) required for data
149
238
  MIN_DDFM_TIME_STEPS = 2 # Minimum number of time steps (T) required for DDFM training (DDFM-specific, different from general MIN_TIME_STEPS=1)
150
239
  MIN_DDFM_DATASET_SIZE_WARNING = 10 # Minimum dataset size (T) below which DDFM denoising training warns about potential instability
151
240
  MIN_ITER_FOR_DELTA_COMPUTATION = 1 # Minimum iteration count required before computing delta (MSE change) in DDFM denoising training
241
+ DEFAULT_MIN_ITER_FOR_CONVERGENCE_CHECK = 2 # Minimum iteration count required before checking convergence in DDFM (check from iteration 3 onwards)
152
242
  MIN_EPS_SHAPE_FOR_IDIO = 1 # Minimum eps shape dimension required for idiosyncratic component processing in DDFM
243
+ MIN_SHAPE_FOR_AR2 = 2 # Minimum shape dimension for AR(2) forecast (need at least 2 previous time steps)
153
244
 
154
245
  # Idiosyncratic component defaults
155
246
  DEFAULT_IDIO_STD = 0.1 # Default idiosyncratic standard deviation (when estimation fails)
@@ -328,6 +419,7 @@ __all__ = [
328
419
  'MIN_OBSERVATION_NOISE',
329
420
  'MIN_FACTOR_VARIANCE',
330
421
  'MIN_STD',
422
+ 'MIN_STD_FOR_SCALE_CHECK',
331
423
  'MAX_EIGENVALUE',
332
424
  'DEFAULT_EIGENVALUE_MAX_MAGNITUDE',
333
425
  'DEFAULT_EIGENVALUE_WARN_THRESHOLD',
@@ -343,19 +435,53 @@ __all__ = [
343
435
  'DEFAULT_REGULARIZATION',
344
436
  'DEFAULT_CLIP_THRESHOLD',
345
437
  'DEFAULT_DATA_CLIP_THRESHOLD',
438
+ 'DEFAULT_SCALE_RATIO_MAX',
439
+ 'DEFAULT_SCALE_RATIO_MIN',
440
+ 'DEFAULT_STANDARDIZATION_MEAN_THRESHOLD',
441
+ 'DEFAULT_STANDARDIZATION_STD_MIN',
442
+ 'DEFAULT_STANDARDIZATION_STD_MAX',
443
+ 'DEFAULT_STANDARDIZED_TARGET_STD',
444
+ 'DEFAULT_TARGET_PREDICTION_STD',
445
+ 'DEFAULT_VARIANCE_COLLAPSE_STD',
446
+ 'DEFAULT_TARGET_CONVERGENCE_ITERATIONS',
447
+ 'DEFAULT_TARGET_DDFM_LOSS',
448
+ 'DEFAULT_DDFM_LOSS_MULTIPLIER',
449
+ 'DEFAULT_SCALE_LOG_PRECISION',
450
+ 'DEFAULT_TIME_LOG_PRECISION',
451
+ 'DEFAULT_LOSS_LOG_PRECISION',
452
+ 'SECONDS_PER_MINUTE',
346
453
  'MIN_CONDITION_NUMBER',
347
454
  'MAX_CONDITION_NUMBER',
348
455
  # Training
349
456
  'DEFAULT_MAX_ITER',
350
457
  'DEFAULT_MAX_EPOCHS',
351
458
  'DEFAULT_MAX_MCMC_ITER',
459
+ 'DEFAULT_N_MC_SAMPLES',
352
460
  'DEFAULT_BATCH_SIZE', # General neural network default (32)
353
- 'DEFAULT_DDFM_BATCH_SIZE', # DDFM-specific default (100)
461
+ 'DEFAULT_DDFM_WINDOW_SIZE', # DDFM-specific window size default (100)
462
+ 'DEFAULT_DDFM_BATCH_SIZE', # DDFM batch size default (100)
463
+ 'DEFAULT_PLACEHOLDER_MC_SAMPLES', # Placeholder MC samples default (1)
464
+ 'DEFAULT_PLACEHOLDER_DATA_SHAPE_T', # Placeholder data shape T default (100)
465
+ 'DEFAULT_PLACEHOLDER_DATA_SHAPE_N', # Placeholder data shape N default (10)
466
+ 'DEFAULT_PLACEHOLDER_SEED', # Placeholder random seed default (42)
467
+ 'DEFAULT_NUM_WORKERS', # DataLoader num_workers default (0)
468
+ 'DEFAULT_CUDA_DEVICE_INDEX', # CUDA device index default (0 = first GPU)
469
+ 'DEFAULT_KDFM_INIT_SAMPLE_SIZE', # KDFM initialization sample size default (100)
354
470
  'DEFAULT_LEARNING_RATE',
355
471
  'DEFAULT_DDFM_LEARNING_RATE',
472
+ 'DEFAULT_AUTOENCODER_FIT_EPOCHS',
473
+ 'DEFAULT_AUTOENCODER_FIT_VERBOSE',
356
474
  'DEFAULT_GRAD_CLIP_VAL',
357
475
  'DEFAULT_WEIGHT_DECAY',
358
476
  'DEFAULT_LR_DECAY_RATE',
477
+ 'VALID_OPTIMIZERS',
478
+ 'DEFAULT_ADAM_BETA1',
479
+ 'DEFAULT_ADAM_BETA2',
480
+ 'DEFAULT_ADAM_EPS',
481
+ 'DEFAULT_TENSORFLOW_ADAM_EPS',
482
+ 'DEFAULT_BATCH_NORM_MOMENTUM',
483
+ 'DEFAULT_BATCH_NORM_EPS',
484
+ 'DEFAULT_RANDOM_SEED_MAX',
359
485
  'DEFAULT_HUBER_DELTA',
360
486
  'HUBER_QUADRATIC_COEFF',
361
487
  'DEFAULT_DDFM_CLIP_RANGE_DEEP',
@@ -368,7 +494,13 @@ __all__ = [
368
494
  'DEFAULT_STRUCTURAL_DIAG_SCALE',
369
495
  'DEFAULT_CHOLESKY_EPS',
370
496
  # Architecture
497
+ 'DEFAULT_FACTOR_ORDER',
498
+ 'DEFAULT_AR_ORDER_2',
371
499
  'DEFAULT_ENCODER_LAYERS',
500
+ 'DEFAULT_NUM_FACTORS',
501
+ 'DEFAULT_ACTIVATION',
502
+ 'DEFAULT_DECODER',
503
+ 'DEFAULT_USE_BATCH_NORM',
372
504
  # Data processing
373
505
  'DEFAULT_NAN_METHOD',
374
506
  'DEFAULT_NAN_K',
@@ -378,12 +510,18 @@ __all__ = [
378
510
  'DEFAULT_MIN_OBS',
379
511
  'DEFAULT_MIN_OBS_IDIO',
380
512
  'DEFAULT_MIN_OBS_VAR',
513
+ 'DEFAULT_MIN_OBS_PRETRAIN',
514
+ 'DEFAULT_MULT_EPOCH_PRETRAIN',
515
+ 'DEFAULT_PRETRAIN_EPOCHS',
381
516
  # Dimension validation
382
517
  'MIN_TIME_STEPS',
383
518
  'MIN_VARIABLES',
519
+ 'MIN_SHAPE_FOR_AR2',
384
520
  'MIN_DDFM_TIME_STEPS',
521
+ 'MIN_SHAPE_FOR_AR2',
385
522
  'MIN_DDFM_DATASET_SIZE_WARNING',
386
523
  'MIN_ITER_FOR_DELTA_COMPUTATION',
524
+ 'DEFAULT_MIN_ITER_FOR_CONVERGENCE_CHECK',
387
525
  'MIN_EPS_SHAPE_FOR_IDIO',
388
526
  'DEFAULT_IDIO_STD',
389
527
  'DEFAULT_IDIO_RHO0',
@@ -1,17 +1,23 @@
1
1
  """Configuration schema package for DFM models.
2
2
 
3
3
  This package contains:
4
- - model.py: BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig - model configurations
5
- - results.py: BaseResult, DFMResult, DDFMResult, KDFMResult - result structures
4
+ - model.py: BaseModelConfig, DFMConfig, DDFMConfig - model configurations
5
+ - results.py: BaseResult, DFMResult, DDFMResult - result structures
6
6
 
7
7
  Note: Series are specified via frequency dict mapping column names to frequencies.
8
8
  """
9
9
 
10
- from .model import BaseModelConfig, DFMConfig, DDFMConfig, KDFMConfig
11
- from .results import BaseResult, DFMResult, DDFMResult, KDFMResult, FitParams
10
+ from .model import BaseModelConfig, DFMConfig, DDFMConfig
11
+ from .results import BaseResult, DFMResult, DDFMResult
12
+ from .params import DFMFitParams, DDFMFitParams
13
+
14
+ # Backward compatibility alias
15
+ FitParams = DFMFitParams
12
16
 
13
17
  __all__ = [
14
- 'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'KDFMConfig',
15
- 'BaseResult', 'DFMResult', 'DDFMResult', 'KDFMResult', 'FitParams',
18
+ 'BaseModelConfig', 'DFMConfig', 'DDFMConfig',
19
+ 'BaseResult', 'DFMResult', 'DDFMResult',
20
+ 'DFMFitParams', 'DDFMFitParams',
21
+ 'FitParams', # Backward compatibility alias
16
22
  ]
17
23
 
@@ -46,7 +46,7 @@ from ..constants import (
46
46
  DEFAULT_LEARNING_RATE,
47
47
  DEFAULT_MAX_EPOCHS,
48
48
  DEFAULT_BATCH_SIZE,
49
- DEFAULT_DDFM_BATCH_SIZE,
49
+ DEFAULT_DDFM_WINDOW_SIZE,
50
50
  DEFAULT_GRAD_CLIP_VAL,
51
51
  DEFAULT_REGULARIZATION_SCALE,
52
52
  DEFAULT_STRUCTURAL_REG_WEIGHT,
@@ -444,14 +444,14 @@ class DFMConfig(BaseModelConfig):
444
444
  return result
445
445
 
446
446
  @classmethod
447
- def from_dict(cls, data: Dict[str, Any]) -> Union['DFMConfig', 'DDFMConfig']:
448
- """Create DFMConfig or DDFMConfig from dictionary.
447
+ def from_dict(cls, data: Dict[str, Any]) -> Union['DFMConfig', 'DDFMConfig', 'KDFMConfig']:
448
+ """Create DFMConfig, DDFMConfig, or KDFMConfig from dictionary.
449
449
 
450
450
  Expected format: {'frequency': {'column_name': 'frequency'}, 'blocks': {...}, ...}
451
451
 
452
452
  Also accepts estimation parameters: threshold, max_iter, etc.
453
453
  """
454
- from ...config.adapter import detect_config_type, MODEL_TYPE_DDFM, _normalize_blocks_dict
454
+ from ...config.adapter import detect_config_type, MODEL_TYPE_DDFM, MODEL_TYPE_KDFM, _normalize_blocks_dict
455
455
  from ...utils.errors import ConfigurationError
456
456
 
457
457
  # Extract base params (handles frequency conversion from series if needed)
@@ -463,6 +463,9 @@ class DFMConfig(BaseModelConfig):
463
463
  if config_type == MODEL_TYPE_DDFM:
464
464
  return DDFMConfig(**base_params, **DDFMConfig._extract_ddfm(data))
465
465
 
466
+ if config_type == MODEL_TYPE_KDFM:
467
+ return KDFMConfig(**base_params, **KDFMConfig._extract_kdfm(data))
468
+
466
469
  # Handle blocks for DFM
467
470
  from ...config.adapter import _raise_config_error, _is_dict_like
468
471
  blocks_dict = data.get('blocks', {})
@@ -492,24 +495,25 @@ class DDFMConfig(BaseModelConfig):
492
495
  - Series definitions via frequency dict (column names -> frequencies)
493
496
  """
494
497
  # ========================================================================
495
- # Neural Network Training Parameters
498
+ # Neural Network Training Hyper Parameters
496
499
  # ========================================================================
497
500
  encoder_layers: Optional[List[int]] = None # Hidden layer dimensions for encoder (default: [64, 32])
498
501
  num_factors: Optional[int] = None # Number of factors (inferred from config if None)
499
502
  activation: str = 'relu' # Activation function ('tanh', 'relu', 'sigmoid', default: 'relu' to match original DDFM)
500
503
  use_batch_norm: bool = True # Use batch normalization in encoder (default: True)
501
504
  learning_rate: float = 0.001 # Learning rate for Adam optimizer (default: 0.001)
502
- epochs: int = 100 # Number of training epochs (default: 100)
503
- batch_size: int = 100 # Batch size for training (default: 100 to match original DDFM)
505
+ n_mc_samples: int = 10 # Number of MC samples per MCMC iteration (default: 10, matching original TensorFlow epochs=10 default, per experiment/config/model/ddfm.yaml)
506
+ window_size: int = 100 # Window size (time-step batch size) for training (default: 100 to match original DDFM)
504
507
  # Note: factor_order removed - factors always use AR(1) dynamics (simplified)
505
508
  use_idiosyncratic: bool = True # Model idio components with AR(1) dynamics (default: True)
506
509
  min_obs_idio: int = 5 # Minimum observations for idio AR(1) estimation (default: 5)
507
510
 
508
511
  # Additional training parameters
509
- max_iter: int = DEFAULT_MAX_MCMC_ITER # Maximum MCMC iterations for iterative factor extraction
512
+ max_epoch: int = DEFAULT_MAX_MCMC_ITER # Maximum number of epochs (MCMC iterations). One epoch = one MCMC iteration (MC sampling → training → convergence check)
510
513
  tolerance: float = DEFAULT_TOLERANCE # Convergence tolerance for MCMC iterations
511
514
  disp: int = 10 # Display frequency for training progress
512
515
  seed: Optional[int] = None # Random seed for reproducibility
516
+ lags_input: int = 0 # Number of lags of inputs on encoder (default 0, matching original TensorFlow DDFM)
513
517
 
514
518
 
515
519
  # ========================================================================
@@ -519,24 +523,42 @@ class DDFMConfig(BaseModelConfig):
519
523
  @classmethod
520
524
  def _extract_ddfm(cls, data: Dict[str, Any]) -> Dict[str, Any]:
521
525
  """Extract DDFM-specific parameters from config dict."""
522
- base_params = cls._extract_base(data)
526
+ # Don't extract base params here - they're already in base_params from from_dict
527
+ from ..constants import DEFAULT_N_MC_SAMPLES
523
528
  ddfm_params = cls._extract_params(data, {
524
529
  'encoder_layers': None,
525
530
  'num_factors': None,
526
531
  'activation': 'relu',
527
532
  'use_batch_norm': True,
528
533
  'learning_rate': DEFAULT_LEARNING_RATE,
529
- 'epochs': DEFAULT_MAX_EPOCHS,
530
- 'batch_size': DEFAULT_DDFM_BATCH_SIZE,
534
+ 'epochs': DEFAULT_N_MC_SAMPLES, # Backward compatibility: map 'epochs' to n_mc_samples
535
+ 'n_mc_samples': DEFAULT_N_MC_SAMPLES, # Preferred name: number of MC samples per MCMC iteration
536
+ 'window_size': DEFAULT_DDFM_WINDOW_SIZE, # Window size (time-step batch size) for training
531
537
  'use_idiosyncratic': True,
532
538
  'min_obs_idio': DEFAULT_MIN_OBS_IDIO,
533
- 'max_iter': DEFAULT_MAX_MCMC_ITER,
539
+ 'max_epoch': DEFAULT_MAX_MCMC_ITER, # Maximum epochs (MCMC iterations)
534
540
  'tolerance': DEFAULT_TOLERANCE,
535
541
  'disp': DEFAULT_DISP,
536
542
  'seed': None,
543
+ 'lags_input': 0, # Number of lags (default 0, matching original TensorFlow)
537
544
  })
538
- base_params.update(ddfm_params)
539
- return base_params
545
+ # Map 'epochs' from config to 'n_mc_samples' for clarity (backward compatibility)
546
+ # Always remove 'epochs' if present (even if n_mc_samples is also present)
547
+ if 'epochs' in ddfm_params:
548
+ if 'n_mc_samples' not in ddfm_params:
549
+ ddfm_params['n_mc_samples'] = ddfm_params['epochs']
550
+ ddfm_params.pop('epochs') # Always remove 'epochs' to avoid passing it to constructor
551
+ # Map 'batch_size' from config to 'window_size' for backward compatibility
552
+ if 'batch_size' in ddfm_params:
553
+ if 'window_size' not in ddfm_params:
554
+ ddfm_params['window_size'] = ddfm_params['batch_size']
555
+ ddfm_params.pop('batch_size') # Always remove 'batch_size' to avoid passing it to constructor
556
+ # Only accept 'max_epoch' parameter (no backward compatibility)
557
+ # Remove any old parameter names if present
558
+ ddfm_params.pop('max_iter', None)
559
+ ddfm_params.pop('max_iterations', None)
560
+ ddfm_params.pop('max_mc_iter', None)
561
+ return ddfm_params
540
562
 
541
563
  @classmethod
542
564
  def from_dict(cls, data: Dict[str, Any]) -> 'DDFMConfig':
@@ -544,7 +566,7 @@ class DDFMConfig(BaseModelConfig):
544
566
  result = DFMConfig.from_dict(data)
545
567
  if isinstance(result, DDFMConfig):
546
568
  return result
547
- from ..utils.errors import ConfigurationError
569
+ from ...utils.errors import ConfigurationError
548
570
  raise ConfigurationError(
549
571
  "Expected DDFMConfig but got DFMConfig",
550
572
  details=f"Result type: {type(result).__name__}, expected: DDFMConfig"
@@ -557,6 +579,8 @@ class KDFMConfig(BaseModelConfig):
557
579
 
558
580
  This dataclass contains all configuration parameters for the KDFM model.
559
581
  It inherits from BaseModelConfig and adds KDFM-specific parameters.
582
+
583
+ Note: KDFM does not use blocks structure (unlike DFM). Only frequency dict is needed.
560
584
  """
561
585
  # VARMA parameters
562
586
  ar_order: int = DEFAULT_KDFM_AR_ORDER # VAR order p
@@ -577,6 +601,42 @@ class KDFMConfig(BaseModelConfig):
577
601
  structural_reg_weight: float = DEFAULT_STRUCTURAL_REG_WEIGHT # Weight for structural loss
578
602
  use_regularization: bool = True
579
603
  regularization_scale: float = DEFAULT_REGULARIZATION_SCALE
604
+
605
+ # ========================================================================
606
+ # Factory Methods
607
+ # ========================================================================
608
+
609
+ @classmethod
610
+ def _extract_kdfm(cls, data: Dict[str, Any]) -> Dict[str, Any]:
611
+ """Extract KDFM-specific parameters from config dict."""
612
+ # Don't extract base params here - they're already in base_params from from_dict
613
+ kdfm_params = cls._extract_params(data, {
614
+ 'ar_order': DEFAULT_KDFM_AR_ORDER,
615
+ 'ma_order': DEFAULT_KDFM_MA_ORDER,
616
+ 'structural_method': 'cholesky',
617
+ 'structural_rank': None,
618
+ 'learning_rate': DEFAULT_LEARNING_RATE,
619
+ 'max_epochs': DEFAULT_MAX_EPOCHS,
620
+ 'batch_size': DEFAULT_BATCH_SIZE,
621
+ 'weight_decay': DEFAULT_REGULARIZATION_SCALE,
622
+ 'grad_clip_val': DEFAULT_GRAD_CLIP_VAL,
623
+ 'structural_reg_weight': DEFAULT_STRUCTURAL_REG_WEIGHT,
624
+ 'use_regularization': True,
625
+ 'regularization_scale': DEFAULT_REGULARIZATION_SCALE,
626
+ })
627
+ return kdfm_params
628
+
629
+ @classmethod
630
+ def from_dict(cls, data: Dict[str, Any]) -> 'KDFMConfig':
631
+ """Create KDFMConfig from dictionary (delegates to DFMConfig.from_dict for type detection)."""
632
+ result = DFMConfig.from_dict(data)
633
+ if isinstance(result, KDFMConfig):
634
+ return result
635
+ from ..utils.errors import ConfigurationError
636
+ raise ConfigurationError(
637
+ f"Expected KDFMConfig but got {type(result).__name__}",
638
+ details=f"Result type: {type(result).__name__}, expected: KDFMConfig"
639
+ )
580
640
 
581
641
 
582
642
  # ============================================================================