-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hardness benchmark #440
base: main
Are you sure you want to change the base?
Hardness benchmark #440
Changes from all commits
54bd0f5
1c46668
b2dd010
1208c29
9b95e32
34a2738
e4bfeb8
5c2d8c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
""" | ||
@Time : 2024/09/30 11:17:24 | ||
@Author : Daniel Persaud | ||
@Version : 1.0 | ||
@Contact : [email protected] | ||
@Desc : Hardness benchmarking, a maximization task on experimental hardness dataset. | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING | ||
|
||
from pandas import DataFrame | ||
import os | ||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
import scipy as sp | ||
import pandas as pd | ||
import seaborn as sns | ||
|
||
from baybe.campaign import Campaign | ||
from baybe.objectives import SingleTargetObjective | ||
from baybe.parameters import NumericalDiscreteParameter, TaskParameter | ||
from baybe.searchspace import SearchSpace | ||
from baybe.simulation import simulate_scenarios | ||
from baybe.targets import NumericalTarget | ||
from baybe.utils.random import set_random_seed | ||
from baybe.recommenders.pure.nonpredictive.sampling import RandomRecommender | ||
from baybe.targets import NumericalTarget, TargetMode | ||
from benchmarks.definition import ( | ||
Benchmark, | ||
ConvergenceExperimentSettings, | ||
) | ||
|
||
|
||
# IMPORT AND PREPROCESS DATA------------------------------------------------------------------------------ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need for these kind of headers, ideally remove them or replace them by more descriptive comments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally, you could briefly describe what happens here in the pre-processing: That is, what does this benchmark describe, what is the pre-processing doing and why is it necessary. Also, general question (also to @AdrianSosic and @Scienfitz ): Wouldn't it be sufficient to just have the pre-processed data as a |
||
strHomeDir = os.getcwd() | ||
dfMP = pd.read_csv( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These variable names are not really expressive, could you give some more detailed names? Abbreviating stuff like "df" for "dataframe" is fine, but it is not clear what "MP" is supposed to mean. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, a lot of your variables have redundant or incorrect names: You call a lot of things "temp", but they do not seem to be temporaray but instead are used later on. In my opinion, such variables should then not be called "_temp". Moreover, you tend to include the type of an object in its name, e.g. in |
||
os.path.join(strHomeDir, "benchmarks", "domains", "mp_bulkModulus_goodOverlap.csv"), index_col=0 | ||
) | ||
dfExp = pd.read_csv( | ||
os.path.join(strHomeDir, "benchmarks", "domains", "exp_hardness_goodOverlap.csv"), index_col=0 | ||
) | ||
lstElementCols = dfExp.columns.to_list()[4:] | ||
|
||
# ----- FUTHER CLEAN THE DATA BASED ON THE EDA ----- | ||
# initialize an empty dataframe to store the integrated hardness values | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please capitalize the first word of all comments to be consistent with how we write comments. |
||
dfExp_integratedHardness = pd.DataFrame() | ||
|
||
# for each unique composition in dfExp, make a cubic spline interpolation of the hardness vs load curve | ||
for strComposition_temp in dfExp["composition"].unique(): | ||
dfComposition_temp = dfExp[dfExp["composition"] == strComposition_temp] | ||
# sort the data by load | ||
dfComposition_temp = dfComposition_temp.sort_values(by="load") | ||
dfComposition_temp = dfComposition_temp.drop_duplicates(subset="load") | ||
if len(dfComposition_temp) < 5: # continue to the next composition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you continue in this case? |
||
continue | ||
|
||
# make a cubic spline interpolation of the hardness vs load curve | ||
spSpline_temp = sp.interpolate.CubicSpline(dfComposition_temp["load"], dfComposition_temp["hardness"]) | ||
# integrate the spline from the minimum load to the maximum load | ||
fltIntegral_temp = spSpline_temp.integrate(0.5, 5, extrapolate = True) | ||
|
||
# make a new dataframe with the lstElementCols from dfComposition_temp | ||
dfComposition_temp = dfComposition_temp[['strComposition', 'composition'] + lstElementCols] | ||
dfComposition_temp = dfComposition_temp.drop_duplicates(subset='composition') | ||
dfComposition_temp["integratedHardness"] = fltIntegral_temp | ||
|
||
dfExp_integratedHardness = pd.concat([dfExp_integratedHardness, dfComposition_temp]) | ||
|
||
# ----- TARGET FUNCTION (INTEGRATED HARDNESS) ----- | ||
# make a dataframe for the task function (integrated hardness) | ||
dfSearchSpace_target = dfExp_integratedHardness[lstElementCols] | ||
dfSearchSpace_target["Function"] = "targetFunction" | ||
|
||
# make a lookup table for the task function (integrate hardness) - add the 'integratedHardness' column from dfExp to dfSearchSpace_task | ||
dfLookupTable_target = pd.concat([dfSearchSpace_target, dfExp_integratedHardness["integratedHardness"]], axis=1) | ||
dfLookupTable_target = dfLookupTable_target.rename(columns={"integratedHardness":"Target"}) | ||
|
||
# ----- SOURCE FUNCTION (VOIGT BULK MODULUS) ----- | ||
# make a dataframe for the source function (voigt bulk modulus) | ||
dfSearchSpace_source = dfMP[lstElementCols] | ||
dfSearchSpace_source["Function"] = "sourceFunction" | ||
|
||
# make a lookup table for the source function (voigt bulk modulus) - add the 'vrh' column from dfMP to dfSearchSpace_source | ||
dfLookupTable_source = pd.concat([dfSearchSpace_source, dfMP["vrh"]], axis=1) | ||
dfLookupTable_source = dfLookupTable_source.rename(columns={"vrh": "Target"}) | ||
|
||
# concatenate the two dataframes | ||
dfSearchSpace = pd.concat([dfSearchSpace_target, dfSearchSpace_source]) | ||
|
||
def hardness(settings: ConvergenceExperimentSettings) -> DataFrame: | ||
"""Integrated hardness benchmark, compares across random, default, and no task parameter set up | ||
|
||
Inputs: | ||
B discrete {0.8, 0.66666667, 0.92307692 ...} |B| = 13 | ||
Sc discrete {0., 0.00384615, 0.01923077 ...} |Sc| = 26 | ||
Cr discrete {0.01, 0.06, 0.1 ...} |Cr| = 20 | ||
Y discrete {0., 0.07307692, 0.05769231 ...} |Y| = 31 | ||
Zr discrete {0., 0.07307692, 0.05769231 ...} |Zr| = 19 | ||
Gd discrete {0., 0.03968254, 0.01587302 ...} |Gd| = 12 | ||
Hf discrete {0., 0.008, 0.02 ...} |Hf| = 13 | ||
Ta discrete {0., 0.006, 0.008 ...} |Ta| = 17 | ||
W discrete {0.19, 0.14, 0.1 ...} |W| = 30 | ||
Re discrete {0., 0.2, 0.33333 ...} |Re| = 15 | ||
Output: discrete | ||
Objective: Maximization | ||
""" | ||
|
||
lstParameters_bb = [] | ||
lstParameters_bb_noTask = [] | ||
|
||
# for each column in dfSearchSpace except the last one, create a NumericalDiscreteParameter | ||
for strCol_temp in dfSearchSpace.columns[:-1]: | ||
bbParameter_temp = NumericalDiscreteParameter( | ||
name=strCol_temp, | ||
values=np.unique(dfSearchSpace[strCol_temp]), | ||
tolerance=0.0, | ||
) | ||
# append the parameter to the list of parameters | ||
lstParameters_bb.append(bbParameter_temp) | ||
lstParameters_bb_noTask.append(bbParameter_temp) | ||
|
||
# create a TaskParameter | ||
bbTaskParameter = TaskParameter( | ||
name="Function", | ||
values=["targetFunction", "sourceFunction"], | ||
active_values=["targetFunction"], | ||
) | ||
|
||
# append the taskParameter to the list of parameters | ||
lstParameters_bb.append(bbTaskParameter) | ||
|
||
search_space = SearchSpace.from_dataframe(dfSearchSpace, parameters=lstParameters_bb) | ||
SearchSpace_noTask = SearchSpace.from_dataframe(dfSearchSpace_target[lstElementCols], parameters=lstParameters_bb_noTask) | ||
|
||
objective = NumericalTarget(name="Target", mode=TargetMode.MAX).to_objective() | ||
|
||
scenarios: dict[str, Campaign] = { | ||
"Random Recommender": Campaign( | ||
searchspace=SearchSpace.from_dataframe( | ||
dfSearchSpace_target[lstElementCols], | ||
parameters=lstParameters_bb_noTask | ||
), | ||
recommender=RandomRecommender(), | ||
objective=objective, | ||
), | ||
"Default Recommender": Campaign( | ||
searchspace=SearchSpace.from_dataframe( | ||
dfSearchSpace, | ||
parameters=lstParameters_bb, | ||
), | ||
objective=objective, | ||
), | ||
"noTask_bb": Campaign( | ||
searchspace=SearchSpace_noTask, | ||
objective=objective, | ||
), | ||
} | ||
|
||
return simulate_scenarios( | ||
scenarios, | ||
dfLookupTable_target, | ||
batch_size=settings.batch_size, | ||
n_doe_iterations=settings.n_doe_iterations, | ||
n_mc_iterations=settings.n_mc_iterations, | ||
impute_mode="error", | ||
) | ||
|
||
|
||
def hardness_transfer_learning(settings: ConvergenceExperimentSettings) -> DataFrame: | ||
"""Integrated hardness benchmark, transfer learning with different initialized data sizes | ||
|
||
Inputs: | ||
B discrete {0.8, 0.66666667, 0.92307692 ...} |B| = 13 | ||
Sc discrete {0., 0.00384615, 0.01923077 ...} |Sc| = 26 | ||
Cr discrete {0.01, 0.06, 0.1 ...} |Cr| = 20 | ||
Y discrete {0., 0.07307692, 0.05769231 ...} |Y| = 31 | ||
Zr discrete {0., 0.07307692, 0.05769231 ...} |Zr| = 19 | ||
Gd discrete {0., 0.03968254, 0.01587302 ...} |Gd| = 12 | ||
Hf discrete {0., 0.008, 0.02 ...} |Hf| = 13 | ||
Ta discrete {0., 0.006, 0.008 ...} |Ta| = 17 | ||
W discrete {0.19, 0.14, 0.1 ...} |W| = 30 | ||
Re discrete {0., 0.2, 0.33333 ...} |Re| = 15 | ||
Output: discrete | ||
Objective: Maximization | ||
""" | ||
|
||
lstParameters_bb = [] | ||
lstParameters_bb_noTask = [] | ||
|
||
# for each column in dfSearchSpace except the last one, create a NumericalDiscreteParameter | ||
for strCol_temp in dfSearchSpace.columns[:-1]: | ||
bbParameter_temp = NumericalDiscreteParameter( | ||
name=strCol_temp, | ||
values=np.unique(dfSearchSpace[strCol_temp]), | ||
tolerance=0.0, | ||
) | ||
# append the parameter to the list of parameters | ||
lstParameters_bb.append(bbParameter_temp) | ||
lstParameters_bb_noTask.append(bbParameter_temp) | ||
|
||
# create a TaskParameter | ||
bbTaskParameter = TaskParameter( | ||
name="Function", | ||
values=["targetFunction", "sourceFunction"], | ||
active_values=["targetFunction"], | ||
) | ||
|
||
# append the taskParameter to the list of parameters | ||
lstParameters_bb.append(bbTaskParameter) | ||
|
||
objective = NumericalTarget(name="Target", mode=TargetMode.MAX).to_objective() | ||
|
||
for n in (2, 4, 6, 30): | ||
bbSearchSpace = SearchSpace.from_dataframe(dfSearchSpace, parameters=lstParameters_bb) | ||
bbCampaign_temp = Campaign( | ||
searchspace=bbSearchSpace, | ||
objective=objective) | ||
# create a list of dataframes with n samples from dfLookupTable_source to use as initial data | ||
lstInitialData_temp = [dfLookupTable_source.sample(n) for _ in range(settings.n_mc_iterations)] | ||
|
||
return simulate_scenarios( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something is weird here: You only ever call this with the latest value of |
||
{f"{n} Initial Data": bbCampaign_temp}, | ||
dfLookupTable_target, | ||
initial_data=lstInitialData_temp, | ||
batch_size=settings.batch_size, | ||
n_doe_iterations=settings.n_doe_iterations, | ||
impute_mode="error", | ||
) | ||
|
||
benchmark_config = ConvergenceExperimentSettings( | ||
batch_size=1, | ||
n_doe_iterations=20, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate on why you chose these values? |
||
n_mc_iterations=5, | ||
) | ||
|
||
hardness_benchmark = Benchmark( | ||
function=hardness, | ||
best_possible_result=None, | ||
settings=benchmark_config, | ||
optimal_function_inputs=None, | ||
) | ||
|
||
hardness_transfer_learning_benchmark = Benchmark( | ||
function=hardness_transfer_learning, | ||
best_possible_result=None, | ||
settings=benchmark_config, | ||
optimal_function_inputs=None, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
|
||
# describe the benchmark task | ||
print("Hardness benchmark is a maximization task on experimental hardness dataset. ") | ||
print("The dataset is downselect to 94 composition with more than 5 hardness values. ") | ||
print("The hardness values are integrated using cubic spline interpolation, and the task is to maximize the integrated hardness. ") | ||
print("") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather add a "\n" at the end of a previous print if you want to have a new line. |
||
print("Hardness benchmark compares across random, default, and no task parameter set up. ") | ||
print("") | ||
print("Hardness transfer learning benchmark compares across different initialized data sizes. ") | ||
|
||
|
||
# Visualize the Hardness value histogram | ||
# initialize a subplot with 1 row and 1 column | ||
fig, ax = plt.subplots( | ||
1, 1, | ||
figsize=(8, 5), | ||
facecolor='w', | ||
edgecolor='k', | ||
constrained_layout = True | ||
) | ||
|
||
# plot a histogram of the hardness values | ||
ax.hist(dfExp["hardness"], bins=20) | ||
|
||
# add a title, x-aixs label, and y-axis label | ||
ax.set_xlabel("Hardness") | ||
ax.set_ylabel("Frequency") | ||
ax.set_title("Integrated Hardness Distribution") | ||
|
||
# add a grid | ||
ax.grid() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,17 @@ | ||
"""Benchmark domains.""" | ||
|
||
from benchmarks.definition.config import Benchmark | ||
from benchmarks.domains.synthetic_2C1D_1C import synthetic_2C1D_1C_benchmark | ||
|
||
BENCHMARKS: list[Benchmark] = [ | ||
synthetic_2C1D_1C_benchmark, | ||
] | ||
|
||
__all__ = ["BENCHMARKS"] | ||
"""Benchmark domains.""" | ||
|
||
from benchmarks.definition.config import Benchmark | ||
from benchmarks.domains.synthetic_2C1D_1C import synthetic_2C1D_1C_benchmark | ||
from benchmarks.domains.CrabNet_AdvOpt import crabnet_advopt_benchmark | ||
from benchmarks.domains.Hardness import hardness_benchmark, hardness_transfer_learning_benchmark | ||
|
||
BENCHMARKS: list[Benchmark] = [ | ||
#synthetic_2C1D_1C_benchmark, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add the original benchmark and remove the comment on the other benchmark as these things are technically independent. |
||
# crabnet_advopt_benchmark, | ||
hardness_benchmark, | ||
hardness_transfer_learning_benchmark, | ||
] | ||
|
||
__all__ = ["BENCHMARKS"] | ||
|
||
# python -m benchmarks | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line should be removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This autogenerated header should be deleted and should instead have a short one-line description of what this benchmark is about.