1
|
|
|
""" |
2
|
|
|
QMCSampler Example - Quasi-Monte Carlo Sampling |
3
|
|
|
|
4
|
|
|
The QMCSampler uses Quasi-Monte Carlo sequences (like Sobol or Halton) |
5
|
|
|
to generate low-discrepancy samples. These sequences provide better |
6
|
|
|
coverage of the parameter space compared to purely random sampling. |
7
|
|
|
|
8
|
|
|
Characteristics: |
9
|
|
|
- Low-discrepancy sequences for uniform space filling |
10
|
|
|
- Better convergence than random sampling |
11
|
|
|
- Deterministic sequence generation |
12
|
|
|
- Excellent space coverage properties |
13
|
|
|
- No learning from previous evaluations |
14
|
|
|
- Good baseline for comparison with adaptive methods |
15
|
|
|
|
16
|
|
|
QMC sequences are particularly effective for: |
17
|
|
|
- Integration and sampling problems |
18
|
|
|
- Initial design of experiments |
19
|
|
|
- Baseline optimization comparisons |
20
|
|
|
""" |
21
|
|
|
|
22
|
|
|
import numpy as np |
23
|
|
|
from sklearn.datasets import load_wine |
24
|
|
|
from sklearn.linear_model import LogisticRegression |
25
|
|
|
from sklearn.model_selection import cross_val_score |
26
|
|
|
|
27
|
|
|
from hyperactive.experiment.integrations import SklearnCvExperiment |
28
|
|
|
from hyperactive.opt.optuna import QMCSampler |
29
|
|
|
|
30
|
|
|
|
31
|
|
|
def qmc_theory(): |
32
|
|
|
"""Explain Quasi-Monte Carlo theory.""" |
33
|
|
|
# Quasi-Monte Carlo (QMC) Theory: |
34
|
|
|
# |
35
|
|
|
# 1. Low-Discrepancy Sequences: |
36
|
|
|
# - Deterministic sequences that fill space uniformly |
37
|
|
|
# - Better distribution than random sampling |
38
|
|
|
# - Minimize gaps and clusters in parameter space |
39
|
|
|
# - Convergence rate O(log^d(N)/N) vs O(1/√N) for random |
40
|
|
|
# |
41
|
|
|
# 2. Common QMC Sequences: |
42
|
|
|
# - Sobol: Based on binary representations |
43
|
|
|
# - Halton: Based on prime number bases |
44
|
|
|
# - Faure: Generalization of Halton sequences |
45
|
|
|
# - Each has different strengths for different dimensions |
46
|
|
|
# |
47
|
|
|
# 3. Space-Filling Properties: |
48
|
|
|
# - Stratification: Even coverage of parameter regions |
49
|
|
|
# - Low discrepancy: Uniform distribution approximation |
50
|
|
|
# - Correlation breaking: Reduces clustering |
51
|
|
|
# |
52
|
|
|
# 4. Advantages over Random Sampling: |
53
|
|
|
# - Better convergence for integration |
54
|
|
|
# - More uniform exploration |
55
|
|
|
# - Reproducible sequences |
56
|
|
|
# - No unlucky clustering |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
def demonstrate_space_filling(): |
60
|
|
|
"""Demonstrate space-filling properties conceptually.""" |
61
|
|
|
# Space-Filling Comparison: |
62
|
|
|
# |
63
|
|
|
# Random Sampling: |
64
|
|
|
# Can have clusters and gaps |
65
|
|
|
# Uneven coverage especially with few samples |
66
|
|
|
# Variance in coverage quality |
67
|
|
|
# Some regions may be under-explored |
68
|
|
|
# |
69
|
|
|
# Quasi-Monte Carlo (QMC): |
70
|
|
|
# Systematic space filling |
71
|
|
|
# Even coverage with fewer samples |
72
|
|
|
# Consistent coverage quality |
73
|
|
|
# All regions explored proportionally |
74
|
|
|
# |
75
|
|
|
# Grid Sampling: |
76
|
|
|
# Perfect regular coverage |
77
|
|
|
# Exponential scaling with dimensions |
78
|
|
|
# May miss optimal points between grid lines |
79
|
|
|
# |
80
|
|
|
# → QMC provides balanced approach between random and grid |
81
|
|
|
|
82
|
|
|
|
83
|
|
|
def main(): |
84
|
|
|
# === QMCSampler Example === |
85
|
|
|
# Quasi-Monte Carlo Low-Discrepancy Sampling |
86
|
|
|
|
87
|
|
|
qmc_theory() |
88
|
|
|
demonstrate_space_filling() |
89
|
|
|
|
90
|
|
|
# Load dataset |
91
|
|
|
X, y = load_wine(return_X_y=True) |
92
|
|
|
print(f"Dataset: Wine classification ({X.shape[0]} samples, {X.shape[1]} features)") |
93
|
|
|
|
94
|
|
|
# Create experiment |
95
|
|
|
estimator = LogisticRegression(random_state=42, max_iter=1000) |
96
|
|
|
experiment = SklearnCvExperiment(estimator=estimator, X=X, y=y, cv=5) |
97
|
|
|
|
98
|
|
|
# Define search space |
99
|
|
|
param_space = { |
100
|
|
|
"C": (0.001, 100), # Regularization strength |
101
|
|
|
"l1_ratio": (0.0, 1.0), # Elastic net mixing parameter |
102
|
|
|
"solver": ["liblinear", "saga"], # Solver algorithm |
103
|
|
|
"penalty": ["l1", "l2", "elasticnet"], # Regularization type |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
# Search Space: |
107
|
|
|
# C: (0.001, 100) - Regularization strength |
108
|
|
|
# l1_ratio: (0.0, 1.0) - Elastic net mixing parameter |
109
|
|
|
# solver: ['liblinear', 'saga'] - Solver algorithm |
110
|
|
|
# penalty: ['l1', 'l2', 'elasticnet'] - Regularization type |
111
|
|
|
|
112
|
|
|
# Configure QMCSampler |
113
|
|
|
optimizer = QMCSampler( |
114
|
|
|
param_space=param_space, |
115
|
|
|
n_trials=32, # Power of 2 often works well for QMC |
116
|
|
|
random_state=42, |
117
|
|
|
experiment=experiment, |
118
|
|
|
qmc_type="sobol", # Sobol or Halton sequences |
119
|
|
|
scramble=True, # Randomized QMC (Owen scrambling) |
120
|
|
|
) |
121
|
|
|
|
122
|
|
|
# QMCSampler Configuration: |
123
|
|
|
# n_trials: 32 (power of 2 for better QMC properties) |
124
|
|
|
# qmc_type: 'sobol' sequence |
125
|
|
|
# scramble: True (randomized QMC) |
126
|
|
|
# Deterministic low-discrepancy sampling |
127
|
|
|
|
128
|
|
|
# QMC Sequence Types: |
129
|
|
|
# Sobol: Excellent for moderate dimensions, binary-based |
130
|
|
|
# Halton: Good for low dimensions, prime-based |
131
|
|
|
# Scrambling: Adds randomization while preserving uniformity |
132
|
|
|
|
133
|
|
|
# Run optimization |
134
|
|
|
# Running QMC sampling optimization... |
135
|
|
|
best_params = optimizer.run() |
136
|
|
|
|
137
|
|
|
# Results |
138
|
|
|
print("\n=== Results ===") |
139
|
|
|
print(f"Best parameters: {best_params}") |
140
|
|
|
print(f"Best score: {optimizer.best_score_:.4f}") |
141
|
|
|
print() |
142
|
|
|
|
143
|
|
|
# QMC behavior analysis: |
144
|
|
|
# |
145
|
|
|
# QMC Sampling Analysis: |
146
|
|
|
# |
147
|
|
|
# Sequence Properties: |
148
|
|
|
# Deterministic generation (reproducible with same seed) |
149
|
|
|
# Low-discrepancy (uniform distribution approximation) |
150
|
|
|
# Space-filling (systematic coverage of parameter space) |
151
|
|
|
# Stratification (even coverage of all regions) |
152
|
|
|
# No clustering or large gaps |
153
|
|
|
# |
154
|
|
|
# Sobol Sequence Characteristics: |
155
|
|
|
# Binary-based construction |
156
|
|
|
# Good equidistribution properties |
157
|
|
|
# Effective for dimensions up to ~40 |
158
|
|
|
# Popular choice for QMC sampling |
159
|
|
|
# |
160
|
|
|
# Scrambling Benefits (when enabled): |
161
|
|
|
# Breaks regularity patterns |
162
|
|
|
# Provides Monte Carlo error estimates |
163
|
|
|
# Maintains low-discrepancy properties |
164
|
|
|
# Reduces correlation artifacts |
165
|
|
|
# |
166
|
|
|
# QMC vs Other Sampling Methods: |
167
|
|
|
# |
168
|
|
|
# vs Pure Random Sampling: |
169
|
|
|
# + Better space coverage with fewer samples |
170
|
|
|
# + More consistent performance |
171
|
|
|
# + Faster convergence for integration-like problems |
172
|
|
|
# - No true randomness (if needed for some applications) |
173
|
|
|
# |
174
|
|
|
# vs Grid Search: |
175
|
|
|
# + Works well in higher dimensions |
176
|
|
|
# + No exponential scaling |
177
|
|
|
# + Covers continuous spaces naturally |
178
|
|
|
# - No systematic guarantee of finding grid optimum |
179
|
|
|
# |
180
|
|
|
# vs Adaptive Methods (TPE, GP): |
181
|
|
|
# + No assumptions about objective function |
182
|
|
|
# + Embarrassingly parallel |
183
|
|
|
# + Consistent performance regardless of function type |
184
|
|
|
# - No learning from previous evaluations |
185
|
|
|
# - May waste evaluations in clearly suboptimal regions |
186
|
|
|
# |
187
|
|
|
# Best Use Cases: |
188
|
|
|
# Design of experiments (DoE) |
189
|
|
|
# Initial exploration phase |
190
|
|
|
# Baseline for comparing adaptive methods |
191
|
|
|
# Integration and sampling problems |
192
|
|
|
# When function evaluations are parallelizable |
193
|
|
|
# Robustness testing across parameter space |
194
|
|
|
# |
195
|
|
|
# Implementation Considerations: |
196
|
|
|
# Use powers of 2 for n_trials with Sobol sequences |
197
|
|
|
# Consider scrambling for better statistical properties |
198
|
|
|
# Choose sequence type based on dimensionality: |
199
|
|
|
# - Sobol: Good general choice |
200
|
|
|
# - Halton: Better for low dimensions (< 6) |
201
|
|
|
# QMC works best with transformed uniform parameters |
202
|
|
|
# |
203
|
|
|
# Practical Recommendations: |
204
|
|
|
# 1. Use QMC for initial exploration (first 20-50 evaluations) |
205
|
|
|
# 2. Switch to adaptive methods (TPE/GP) for focused search |
206
|
|
|
# 3. Use for sensitivity analysis across full parameter space |
207
|
|
|
# 4. Good choice when unsure about objective function properties |
208
|
|
|
# 5. Ideal for parallel evaluation scenarios |
209
|
|
|
|
210
|
|
|
return best_params, optimizer.best_score_ |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
if __name__ == "__main__": |
214
|
|
|
best_params, best_score = main() |
215
|
|
|
|