Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
O
OptiOrch
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Zizhe Wang
OptiOrch
Commits
2e0c3302
"README.md" did not exist on "5d210a9d63b1c6bda254ac207725806043123b6a"
Commit
2e0c3302
authored
1 year ago
by
Zizhe Wang
Browse files
Options
Downloads
Patches
Plain Diff
fix adaptive instance selection
parent
9e36b3c8
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/adaptive_instance_selection.py
+71
-31
71 additions, 31 deletions
src/adaptive_instance_selection.py
src/optimize_main.py
+15
-5
15 additions, 5 deletions
src/optimize_main.py
src/parallel_computing.py
+5
-5
5 additions, 5 deletions
src/parallel_computing.py
with
91 additions
and
41 deletions
src/adaptive_instance_selection.py
+
71
−
31
View file @
2e0c3302
...
@@ -7,19 +7,26 @@
...
@@ -7,19 +7,26 @@
# #
# #
####################################
####################################
from
sklearn.mixture
import
GaussianMixture
from
scipy.stats.qmc
import
LatinHypercube
as
lhs
import
numpy
as
np
import
numpy
as
np
from
pyDOE
import
lhs
from
config
import
PARAM_TYPES
,
PARAM_BOUNDS
from
sklearn.cluster
import
KMeans
# Initial Sampling
# Initial Sampling
def
initial_sampling
(
param_bounds
,
n_samples
):
def
initial_sampling
(
param_bounds
,
n_samples
):
dimensions
=
len
(
param_bounds
)
dimensions
=
len
(
param_bounds
)
samples
=
lhs
(
dimensions
,
samples
=
n_samples
)
# Latin hypercube sampling (LHS)
samples
=
lhs
(
d
=
dimensions
).
random
(
n
=
n_samples
)
# Latin hypercube sampling (LHS)
if
samples
.
size
==
0
:
raise
ValueError
(
"
Initial sampling produced an empty set of samples.
"
)
# Scale samples to parameter bounds
# Scale samples to parameter bounds and respect parameter types
for
i
,
(
param
,
bounds
)
in
enumerate
(
param_bounds
.
items
()):
for
i
,
(
param
,
bounds_info
)
in
enumerate
(
param_bounds
.
items
()):
bounds
=
bounds_info
[
"
bounds
"
]
samples
[:,
i
]
=
bounds
[
0
]
+
samples
[:,
i
]
*
(
bounds
[
1
]
-
bounds
[
0
])
samples
[:,
i
]
=
bounds
[
0
]
+
samples
[:,
i
]
*
(
bounds
[
1
]
-
bounds
[
0
])
if
bounds_info
[
"
type
"
]
==
'
int
'
:
samples
[:,
i
]
=
np
.
round
(
samples
[:,
i
]).
astype
(
int
)
print
(
f
"
Initial samples shape:
{
samples
.
shape
}
"
)
return
samples
return
samples
# Evaluate Samples
# Evaluate Samples
...
@@ -28,49 +35,82 @@ def evaluate_samples(samples, objective_function):
...
@@ -28,49 +35,82 @@ def evaluate_samples(samples, objective_function):
for
sample
in
samples
:
for
sample
in
samples
:
result
=
objective_function
(
sample
)
result
=
objective_function
(
sample
)
results
.
append
(
result
)
results
.
append
(
result
)
return
np
.
array
(
results
)
return
np
.
array
(
results
)
# Clustering Samples
# Advanced Clustering
def
cluster_samples
(
samples
,
n_clusters
):
def
advanced_clustering_samples
(
samples
,
n_clusters
):
kmeans
=
KMeans
(
n_clusters
=
n_clusters
)
if
len
(
samples
)
==
0
:
kmeans
.
fit
(
samples
)
raise
ValueError
(
"
Cannot cluster an empty set of samples.
"
)
labels
=
kmeans
.
labels_
gmm
=
GaussianMixture
(
n_components
=
n_clusters
,
covariance_type
=
'
full
'
)
centers
=
kmeans
.
cluster_centers_
gmm
.
fit
(
samples
)
labels
=
gmm
.
predict
(
samples
)
centers
=
gmm
.
means_
return
labels
,
centers
return
labels
,
centers
# Adaptive Selection
# Adaptive Selection with Adaptive Threshold
def
select_informative_instances
(
samples
,
results
,
threshold
=
0.1
):
def
adaptive_select_informative_instances
(
samples
,
results
,
initial_threshold
=
0.15
,
adapt_rate
=
0.05
):
if
len
(
samples
)
==
0
or
len
(
results
)
==
0
:
raise
ValueError
(
"
Received empty samples or results for selection.
"
)
performance
=
np
.
mean
(
results
,
axis
=
1
)
performance
=
np
.
mean
(
results
,
axis
=
1
)
cutoff
=
np
.
percentile
(
performance
,
threshold
*
100
)
threshold
=
initial_threshold
while
True
:
# Ensure the threshold does not exceed 1
effective_threshold
=
min
(
threshold
,
1.0
)
cutoff
=
np
.
percentile
(
performance
,
effective_threshold
*
100
)
selected_samples
=
samples
[
performance
<=
cutoff
]
selected_samples
=
samples
[
performance
<=
cutoff
]
if
len
(
selected_samples
)
>=
3
:
break
threshold
+=
adapt_rate
if
selected_samples
.
size
==
0
:
raise
ValueError
(
"
Selection of informative instances resulted in an empty set.
"
)
print
(
f
"
Selected samples shape:
{
selected_samples
.
shape
}
"
)
return
selected_samples
return
selected_samples
# Iterative Refinement
# Iterative Refinement
def
iterative_refinement
(
samples
,
results
,
objective_function
,
n_iterations
=
5
,
threshold
=
0.1
):
def
iterative_refinement
(
samples
,
results
,
objective_function
,
maximize_indices
,
n_iterations
=
5
,
initial_threshold
=
0.15
,
adapt_rate
=
0.05
):
for
_
in
range
(
n_iterations
):
for
iteration
in
range
(
n_iterations
):
print
(
f
"
Iteration
{
iteration
}
: Starting with samples shape:
{
samples
.
shape
}
"
)
# Evaluate current samples
# Evaluate current samples
current_results
=
evaluate_samples
(
samples
,
objective_function
)
current_results
=
evaluate_samples
(
samples
,
objective_function
)
# Select informative instances
# Print performance metrics for current samples
samples
=
select_informative_instances
(
samples
,
current_results
,
threshold
)
print
(
f
"
Iteration
{
iteration
}
: Current results:
{
current_results
}
"
)
# Select informative instances with adaptive threshold
selected_samples
=
adaptive_select_informative_instances
(
samples
,
current_results
,
initial_threshold
,
adapt_rate
)
# Ensure objective negation is correctly handled
for
i
in
range
(
len
(
current_results
)):
for
idx
in
maximize_indices
:
current_results
[
i
][
idx
]
=
-
current_results
[
i
][
idx
]
# Ensure at least a minimum number of samples are selected to maintain diversity
if
len
(
selected_samples
)
<
3
:
selected_samples
=
samples
[
np
.
argsort
(
np
.
mean
(
current_results
,
axis
=
1
))[:
3
]]
# Re-cluster the selected samples
# Re-cluster the selected samples
n_clusters
=
max
(
1
,
int
(
len
(
samples
)
*
0.
1
))
# Ensure at least 1 cluster
n_clusters
=
max
(
1
,
min
(
3
,
int
(
len
(
selected_
samples
)
*
0.
3
)
))
# Ensure at least 1 cluster
, maximum 3 clusters
labels
,
centers
=
cluster_samples
(
samples
,
n_clusters
)
labels
,
centers
=
advanced_
cluster
ing
_samples
(
selected_
samples
,
n_clusters
)
# Generate new samples around cluster centers
# Generate new samples around cluster centers
new_samples
=
[]
new_samples
=
[]
for
center
in
centers
:
for
center
in
centers
:
perturbations
=
np
.
random
.
uniform
(
-
0.05
,
0.05
,
center
.
shape
)
for
_
in
range
(
1
):
# Generate 1 new sample per center to control the growth of sample size
perturbations
=
np
.
random
.
uniform
(
-
0.05
,
0.05
,
center
.
shape
)
# Use smaller perturbations for finer adjustments
new_samples
.
append
(
center
+
perturbations
)
new_samples
.
append
(
center
+
perturbations
)
samples
=
np
.
vstack
((
samples
,
new_samples
))
# Combine selected samples with new samples, ensuring we don't grow the sample size too much
samples
=
np
.
vstack
((
selected_samples
,
new_samples
))
if
len
(
samples
)
>
len
(
selected_samples
)
+
2
:
# Limit the growth of samples
samples
=
samples
[:
len
(
selected_samples
)
+
2
]
return
samples
# Debugging output
print
(
f
"
Iteration
{
iteration
}
: Samples shape after selection and new sample generation:
{
samples
.
shape
}
"
)
# Define the objective function wrapper
return
samples
def
objective_function
(
param_values
):
\ No newline at end of file
return
optimization_function
(
param_values
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
src/optimize_main.py
+
15
−
5
View file @
2e0c3302
...
@@ -17,25 +17,29 @@ from pymoo.optimize import minimize
...
@@ -17,25 +17,29 @@ from pymoo.optimize import minimize
from
scipy.stats
import
ttest_ind
from
scipy.stats
import
ttest_ind
from
optimization_libraries
import
initialize_algorithm
from
optimization_libraries
import
initialize_algorithm
from
parallel_computing
import
execute_parallel_tasks
,
cleanup_temp_dirs
from
parallel_computing
import
execute_parallel_tasks
,
cleanup_temp_dirs
from
config
import
PARAMETERS
,
OBJECTIVES
,
MAXIMIZE
,
PARAM_BOUNDS
,
PRECISION
,
PLOT_CONFIG
,
OPTIMIZATION_CONFIG
,
N_JOBS
from
config
import
PARAMETERS
,
OBJECTIVES
,
MAXIMIZE
,
PARAM_BOUND
_VALUES
,
PARAM_TYPE
S
,
PRECISION
,
PLOT_CONFIG
,
OPTIMIZATION_CONFIG
,
N_JOBS
class
OptimizationProblem
(
Problem
):
class
OptimizationProblem
(
Problem
):
def
__init__
(
self
):
def
__init__
(
self
):
self
.
param_names
=
list
(
PARAM_BOUNDS
.
keys
())
self
.
param_names
=
list
(
PARAM_BOUND_VALUES
.
keys
())
self
.
param_types
=
[
PARAM_TYPES
[
param
]
for
param
in
self
.
param_names
]
self
.
objective_names
=
OBJECTIVES
self
.
objective_names
=
OBJECTIVES
self
.
maximize_indices
=
[
self
.
objective_names
.
index
(
res
)
for
res
in
MAXIMIZE
]
self
.
maximize_indices
=
[
self
.
objective_names
.
index
(
res
)
for
res
in
MAXIMIZE
]
n_var
=
len
(
self
.
param_names
)
n_var
=
len
(
self
.
param_names
)
n_obj
=
len
(
self
.
objective_names
)
n_obj
=
len
(
self
.
objective_names
)
xl
=
np
.
array
([
PARAM_BOUNDS
[
param
][
0
]
for
param
in
self
.
param_names
])
xl
=
np
.
array
([
PARAM_BOUND
_VALUE
S
[
param
][
0
]
for
param
in
self
.
param_names
])
xu
=
np
.
array
([
PARAM_BOUNDS
[
param
][
1
]
for
param
in
self
.
param_names
])
xu
=
np
.
array
([
PARAM_BOUND
_VALUE
S
[
param
][
1
]
for
param
in
self
.
param_names
])
print
(
f
"
Number of variables:
{
n_var
}
"
)
print
(
f
"
Number of variables:
{
n_var
}
"
)
print
(
f
"
Lower bounds:
{
xl
}
"
)
print
(
f
"
Lower bounds:
{
xl
}
"
)
print
(
f
"
Upper bounds:
{
xu
}
"
)
print
(
f
"
Upper bounds:
{
xu
}
"
)
super
().
__init__
(
n_var
=
n_var
,
n_obj
=
n_obj
,
n_constr
=
0
,
xl
=
xl
,
xu
=
xu
)
super
().
__init__
(
n_var
=
n_var
,
n_obj
=
n_obj
,
n_constr
=
0
,
xl
=
xl
,
xu
=
xu
)
def
_evaluate
(
self
,
X
,
out
,
*
args
,
**
kwargs
):
def
_evaluate
(
self
,
X
,
out
,
*
args
,
**
kwargs
):
for
i
,
param_type
in
enumerate
(
self
.
param_types
):
if
param_type
==
"
int
"
:
X
[:,
i
]
=
np
.
round
(
X
[:,
i
]).
astype
(
int
)
param_values_list
=
[
dict
(
zip
(
self
.
param_names
,
x
))
for
x
in
X
]
param_values_list
=
[
dict
(
zip
(
self
.
param_names
,
x
))
for
x
in
X
]
results
=
execute_parallel_tasks
(
param_values_list
,
OPTIMIZATION_CONFIG
[
"
USE_ADAPTIVE_INSTANCE_SELECTION
"
])
results
=
execute_parallel_tasks
(
param_values_list
,
OPTIMIZATION_CONFIG
[
"
USE_ADAPTIVE_INSTANCE_SELECTION
"
]
,
self
.
maximize_indices
)
# Debugging output before any processing
# Debugging output before any processing
print
(
f
"
Initial results:
{
results
}
"
)
print
(
f
"
Initial results:
{
results
}
"
)
...
@@ -99,6 +103,12 @@ def run_optimization(use_adaptive_instance_selection):
...
@@ -99,6 +103,12 @@ def run_optimization(use_adaptive_instance_selection):
print_and_plot_results
(
res
,
problem
)
print_and_plot_results
(
res
,
problem
)
# Save results to a file
# Save results to a file
# Negate back the maximized objectives before saving
results_to_save
=
res
.
F
.
copy
()
for
i
in
range
(
len
(
results_to_save
)):
for
idx
in
problem
.
maximize_indices
:
results_to_save
[
i
][
idx
]
=
-
results_to_save
[
i
][
idx
]
results_data
=
{
results_data
=
{
"
results
"
:
res
.
F
.
tolist
(),
"
results
"
:
res
.
F
.
tolist
(),
"
elapsed_time
"
:
elapsed_time
,
"
elapsed_time
"
:
elapsed_time
,
...
...
This diff is collapsed.
Click to expand it.
src/parallel_computing.py
+
5
−
5
View file @
2e0c3302
...
@@ -14,8 +14,8 @@ import numpy as np
...
@@ -14,8 +14,8 @@ import numpy as np
from
time
import
sleep
from
time
import
sleep
from
joblib
import
Parallel
,
delayed
from
joblib
import
Parallel
,
delayed
from
OMPython
import
OMCSessionZMQ
from
OMPython
import
OMCSessionZMQ
from
config
import
MODEL_FILE
,
MODEL_NAME
,
SIMULATION_STOP_TIME
,
PARAMETERS
,
OBJECTIVES
,
PARAM_BOUNDS
,
MODEL_PATH
,
PRECISION
,
OPTIMIZATION_CONFIG
,
N_JOBS
from
config
import
MODEL_FILE
,
MODEL_NAME
,
SIMULATION_STOP_TIME
,
PARAMETERS
,
OBJECTIVES
,
PARAM_BOUNDS
,
PARAM_TYPES
,
MODEL_PATH
,
PRECISION
,
OPTIMIZATION_CONFIG
,
N_JOBS
from
adaptive_instance_selection
import
initial_sampling
,
evaluate_samples
,
cluster_samples
,
select_informative_instances
,
iterative_refinement
from
adaptive_instance_selection
import
initial_sampling
,
evaluate_samples
,
advanced_
cluster
ing
_samples
,
adaptive_
select_informative_instances
,
iterative_refinement
temp_dirs
=
[]
# List to store paths of temporary directories
temp_dirs
=
[]
# List to store paths of temporary directories
...
@@ -66,7 +66,7 @@ def optimization_function(param_values, retries=3, delay=2):
...
@@ -66,7 +66,7 @@ def optimization_function(param_values, retries=3, delay=2):
param_values
=
{
param
:
value
for
param
,
value
in
zip
(
PARAMETERS
,
param_values
)}
param_values
=
{
param
:
value
for
param
,
value
in
zip
(
PARAMETERS
,
param_values
)}
# Set model parameters
# Set model parameters
rounded_param_values
=
{
param
:
round
(
value
,
PRECISION
)
for
param
,
value
in
param_values
.
items
()}
rounded_param_values
=
{
param
:
round
(
value
,
PRECISION
)
if
PARAM_TYPES
[
param
]
==
'
float
'
else
int
(
value
)
for
param
,
value
in
param_values
.
items
()}
for
param
,
value
in
rounded_param_values
.
items
():
for
param
,
value
in
rounded_param_values
.
items
():
set_param_result
=
omc
.
sendExpression
(
f
"
setParameterValue(
{
MODEL_NAME
}
,
{
param
}
,
{
value
}
)
"
)
set_param_result
=
omc
.
sendExpression
(
f
"
setParameterValue(
{
MODEL_NAME
}
,
{
param
}
,
{
value
}
)
"
)
if
not
set_param_result
:
if
not
set_param_result
:
...
@@ -125,7 +125,7 @@ def cleanup_temp_dirs():
...
@@ -125,7 +125,7 @@ def cleanup_temp_dirs():
print
(
f
"
Error:
{
e
}
"
)
print
(
f
"
Error:
{
e
}
"
)
break
# Exit the loop for non-permission errors
break
# Exit the loop for non-permission errors
def
execute_parallel_tasks
(
tasks
,
use_adaptive_instance_selection
):
def
execute_parallel_tasks
(
tasks
,
use_adaptive_instance_selection
,
maximize_indices
):
results
=
[]
results
=
[]
if
use_adaptive_instance_selection
:
if
use_adaptive_instance_selection
:
...
@@ -136,7 +136,7 @@ def execute_parallel_tasks(tasks, use_adaptive_instance_selection):
...
@@ -136,7 +136,7 @@ def execute_parallel_tasks(tasks, use_adaptive_instance_selection):
initial_results
=
Parallel
(
n_jobs
=
N_JOBS
)(
delayed
(
optimization_function
)(
sample
)
for
sample
in
initial_samples
)
initial_results
=
Parallel
(
n_jobs
=
N_JOBS
)(
delayed
(
optimization_function
)(
sample
)
for
sample
in
initial_samples
)
# Iterative refinement
# Iterative refinement
refined_samples
=
iterative_refinement
(
initial_samples
,
initial_results
,
optimization_function
)
refined_samples
=
iterative_refinement
(
initial_samples
,
initial_results
,
optimization_function
,
maximize_indices
)
# Parallel evaluation of refined samples
# Parallel evaluation of refined samples
refined_results
=
Parallel
(
n_jobs
=
N_JOBS
)(
delayed
(
optimization_function
)(
task
)
for
task
in
refined_samples
)
refined_results
=
Parallel
(
n_jobs
=
N_JOBS
)(
delayed
(
optimization_function
)(
task
)
for
task
in
refined_samples
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment