diff --git a/.github/workflows/bayesopt_interfaces.yaml b/.github/workflows/bayesopt_interfaces.yaml new file mode 100644 index 0000000..1aee45d --- /dev/null +++ b/.github/workflows/bayesopt_interfaces.yaml @@ -0,0 +1,57 @@ +on: + push: + pull_request: + +jobs: + tests_physbo_interface: + name: Run tests for physbo_interface + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: [3.8] + os: [ubuntu-20.04] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools + pip install pytest + - name: Install bayesopt_interfaces + run: | + pip install ml_interfaces/bayesopt_interfaces + - name: Run pytest + run: pytest -v ml_interfaces/bayesopt_interfaces/tests/test_physbo_interface.py + + tests_combo_interface: + name: Run tests for combo_interface + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04] + container: + image: python:2.7.18-buster + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools + pip install pytest cython numpy + - name: Install combo + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git clone https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/tsudalab/combo.git + cd combo + python setup.py install + - name: Install bayesopt_interfaces + run: | + pip install ml_interfaces/bayesopt_interfaces + - name: Run pytest + run: | + pytest -v ml_interfaces/bayesopt_interfaces/tests/test_combo_interface.py diff --git a/ml_interfaces/bayesopt_interfaces/.gitignore b/ml_interfaces/bayesopt_interfaces/.gitignore index ff043ed..6dfb7ca 100644 --- a/ml_interfaces/bayesopt_interfaces/.gitignore +++ b/ml_interfaces/bayesopt_interfaces/.gitignore @@ -1,2 +1,6 @@ *.~ -*.pyc \ No newline at end of file +*.pyc +examples/data/chosen_actions.csv +examples/data/result +tests/data/chosed_actions.csv +tests/data/result diff --git a/ml_interfaces/bayesopt_interfaces/bayesopt_if/combo_interface.py b/ml_interfaces/bayesopt_interfaces/bayesopt_if/combo_interface.py index 592ae83..a7cb755 100755 --- a/ml_interfaces/bayesopt_interfaces/bayesopt_if/combo_interface.py +++ b/ml_interfaces/bayesopt_interfaces/bayesopt_if/combo_interface.py @@ -20,7 +20,7 @@ class ComboInterface(): - def __init__(self, bayesopt, candidates_path='candidates.csv', policy_load_dir='.', policy_save_dir='.', use_saved_policy=False, search_score='PI'): + def __init__(self, bayesopt, candidates_path='candidates.csv', policy_load_dir='.', policy_save_dir='.', use_saved_policy=False, visualize=True, search_score='PI'): self.data = None self.X = None self.actions = None @@ -32,6 +32,7 @@ def __init__(self, bayesopt, candidates_path='candidates.csv', policy_load_dir=' self.policy_load_dir = policy_load_dir self.policy_save_dir = policy_save_dir self.use_saved_policy = use_saved_policy + self.visualize = visualize self.search_mode = 0 # 0: random search, 1: bayes self.search_score = search_score # score: PI, EI, TS self.is_write_completed = False @@ -54,10 +55,11 @@ def start_bayesopt(self): self.generate_policy() # for visualization - self.fig, self.ax = plt.subplots(2, 1, tight_layout=True) # avoid overlap of labels + if self.visualize: + self.fig, self.ax = plt.subplots(2, 1, tight_layout=True) # avoid overlap of labels - # visualize - self.visualize() + # visualize + self.visualize() def load_dataset(self): @@ -169,7 +171,8 @@ def save_data(self, policy_save_dir='.'): self.save_policy(self.policy_save_dir) self.save_candidates_and_actions(self.policy_save_dir) # csv self.save_candidates_with_scores(self.policy_save_dir) # csv - self.save_plt(self.policy_save_dir) + if self.visualize: + self.save_plt(self.policy_save_dir) def save_policy(self, policy_save_dir='.'): diff --git a/ml_interfaces/bayesopt_interfaces/bayesopt_if/physbo_interface.py b/ml_interfaces/bayesopt_interfaces/bayesopt_if/physbo_interface.py index d3d347e..c295a54 100755 --- a/ml_interfaces/bayesopt_interfaces/bayesopt_if/physbo_interface.py +++ b/ml_interfaces/bayesopt_interfaces/bayesopt_if/physbo_interface.py @@ -10,7 +10,7 @@ class PhysboInterface(ComboInterface): - def __init__(self, candidates_path='candidates.csv', policy_load_dir='.', policy_save_dir='.', use_saved_policy=False, search_score='PI'): + def __init__(self, candidates_path='candidates.csv', policy_load_dir='.', policy_save_dir='.', use_saved_policy=False, visualize=True, search_score='PI'): self.candidates_path = candidates_path self.policy_load_dir = policy_load_dir self.policy_save_dir = policy_save_dir @@ -24,6 +24,7 @@ def __init__(self, candidates_path='candidates.csv', policy_load_dir='.', policy self.policy_load_dir, self.policy_save_dir, self.use_saved_policy, + self.visualize, self.search_score) # python3 description diff --git a/ml_interfaces/bayesopt_interfaces/examples/data/candidates.csv b/ml_interfaces/bayesopt_interfaces/examples/data/candidates.csv new file mode 100644 index 0000000..2a1b71f --- /dev/null +++ b/ml_interfaces/bayesopt_interfaces/examples/data/candidates.csv @@ -0,0 +1,21 @@ +p1,p2,p3,p4,y +180,0,100,200, +180,0,200,200, +180,0,300,200, +180,0,400,200, +180,100,100,200, +180,100,200,200, +180,100,300,200, +180,100,400,200, +180,200,100,200, +180,200,200,200, +180,200,300,200, +180,200,400,200, +180,300,100,200, +180,300,200,200, +180,300,300,200, +180,300,400,200, +180,400,100,200, +180,400,200,200, +180,400,300,200, +180,400,400,200, diff --git a/ml_interfaces/bayesopt_interfaces/examples/data/results.csv b/ml_interfaces/bayesopt_interfaces/examples/data/results.csv new file mode 100644 index 0000000..be0f592 --- /dev/null +++ b/ml_interfaces/bayesopt_interfaces/examples/data/results.csv @@ -0,0 +1,21 @@ +y +0.001 +0.401 +0.398 +0.305 +0.001 +0.352 +0.350 +0.237 +0.350 +0.374 +0.288 +0.262 +0.290 +0.250 +0.245 +0.204 +0.216 +0.129 +0.151 +0.091 diff --git a/ml_interfaces/bayesopt_interfaces/examples/run_combo.py b/ml_interfaces/bayesopt_interfaces/examples/run_combo.py new file mode 100755 index 0000000..bca9c10 --- /dev/null +++ b/ml_interfaces/bayesopt_interfaces/examples/run_combo.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import random +import sys + +import combo +from bayesopt_if.combo_interface import ComboInterface + + +def main(): + # dir setting + candidates_path = './data/candidates.csv' + policy_load_dir = './data/load' + policy_save_dir = './data/result' + + # Generate combo + ci = ComboInterface(combo, candidates_path, policy_load_dir, policy_save_dir, use_saved_policy=False) + ci.start_bayesopt() + + # Write combo operation below + ## Following procedure is important for correct generation of result data. + ## search -> write(and update -> visualize) + for i in range(1): + ci.search_next_param_random() + ci.write_result(random.random()) # write result + for i in range(1): + ci.search_next_param_bayes() + ci.write_result(random.random()) # write result + + raw_input('Press enter to save and finish\n') + + ci.save_data(policy_save_dir) + + +if __name__ == '__main__': + main() diff --git a/ml_interfaces/bayesopt_interfaces/examples/run_physbo.py b/ml_interfaces/bayesopt_interfaces/examples/run_physbo.py new file mode 100755 index 0000000..1b97ff5 --- /dev/null +++ b/ml_interfaces/bayesopt_interfaces/examples/run_physbo.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import csv +import os +import sys + +from bayesopt_if.physbo_interface import PhysboInterface + + +def get_data_from_result_list(index): + with open('./data/results.csv') as f: + reader = csv.reader(f) + l = [row for row in reader] + + return float(l[index+1][0]) + + +def main(): + # dir setting + candidates_path = './data/candidates.csv' + policy_load_dir = './data/load' + policy_save_dir = './data/result' + + # Generate physbo + pi = PhysboInterface(candidates_path, policy_load_dir, policy_save_dir, use_saved_policy=False, search_score='EI') + pi.start_bayesopt() + + # Procedure of search and register data to PHYSBO + # - Following procedure is important for correct generation of result data. + # - search -> write (and update -> visualize) + + # Search with Random search for initial step + for i in range(3): + pi.search_next_param_random() + result = get_data_from_result_list(pi.get_next_index()) # get result/evaluation data from experiment. (Result list is used for this test program). + pi.write_result(result) # write result to PHYSBO + # Search with Bayesian optimization + for i in range(3): + pi.search_next_param_bayes() + result = get_data_from_result_list(pi.get_next_index()) + pi.write_result(result) + + input('Press enter to save and finish\n') + + pi.save_data(policy_save_dir) + + +if __name__ == '__main__': + main() diff --git a/ml_interfaces/bayesopt_interfaces/requirements.txt b/ml_interfaces/bayesopt_interfaces/requirements.txt index 5a7eca9..a3b25d0 100644 --- a/ml_interfaces/bayesopt_interfaces/requirements.txt +++ b/ml_interfaces/bayesopt_interfaces/requirements.txt @@ -1,2 +1,4 @@ matplotlib +pandas physbo +pyyaml diff --git a/ml_interfaces/bayesopt_interfaces/setup.py b/ml_interfaces/bayesopt_interfaces/setup.py index 290dbe0..d13c984 100644 --- a/ml_interfaces/bayesopt_interfaces/setup.py +++ b/ml_interfaces/bayesopt_interfaces/setup.py @@ -9,7 +9,7 @@ def _requires_from_file(filename): version='0.1.0', author='Yuki Asano', author_email='yasano@g.ecc.u-tokyo.ac.jp', - description='', + description='Interface for Bayesian Optimization', packages=find_packages(), install_requires = _requires_from_file('requirements.txt') ) diff --git a/ml_interfaces/bayesopt_interfaces/tests/data/candidates-correct.csv b/ml_interfaces/bayesopt_interfaces/tests/data/candidates-correct.csv new file mode 100644 index 0000000..67d7216 --- /dev/null +++ b/ml_interfaces/bayesopt_interfaces/tests/data/candidates-correct.csv @@ -0,0 +1,21 @@ +p1,p2,p3,p4,y +180,0,100,200,0.001 +180,0,200,200,0.401 +180,0,300,200,0.398 +180,0,400,200,0.305 +180,100,100,200,0.001 +180,100,200,200,0.352 +180,100,300,200,0.35 +180,100,400,200,0.237 +180,200,100,200,0.35 +180,200,200,200,0.374 +180,200,300,200,0.288 +180,200,400,200,0.262 +180,300,100,200,0.29 +180,300,200,200,0.25 +180,300,300,200,0.245 +180,300,400,200,0.204 +180,400,100,200,0.216 +180,400,200,200,0.129 +180,400,300,200,0.151 +180,400,400,200,0.091 diff --git a/ml_interfaces/bayesopt_interfaces/tests/test_combo_interface.py b/ml_interfaces/bayesopt_interfaces/tests/test_combo_interface.py index bca9c10..78221b2 100755 --- a/ml_interfaces/bayesopt_interfaces/tests/test_combo_interface.py +++ b/ml_interfaces/bayesopt_interfaces/tests/test_combo_interface.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import csv +import filecmp import os import random import sys @@ -8,31 +10,43 @@ import combo from bayesopt_if.combo_interface import ComboInterface +file_dir = os.path.dirname(__file__) +data_dir = os.path.join(file_dir, 'data') -def main(): + +def get_data_from_result_list(index): + results_path = os.path.join(data_dir, 'results.csv') + with open(results_path) as f: + reader = csv.reader(f) + l = [row for row in reader] + + return float(l[index+1][0]) + + +def test_combo_interface(): # dir setting - candidates_path = './data/candidates.csv' - policy_load_dir = './data/load' - policy_save_dir = './data/result' + candidates_path = os.path.join(data_dir, 'candidates.csv') + correct_candidates_path = os.path.join(data_dir, 'candidates-correct.csv') + policy_load_dir = os.path.join(data_dir, 'load') + policy_save_dir = os.path.join(data_dir, 'result') # Generate combo - ci = ComboInterface(combo, candidates_path, policy_load_dir, policy_save_dir, use_saved_policy=False) + ci = ComboInterface(combo, candidates_path, policy_load_dir, policy_save_dir, use_saved_policy=False, visualize=False) ci.start_bayesopt() # Write combo operation below ## Following procedure is important for correct generation of result data. ## search -> write(and update -> visualize) - for i in range(1): + for i in range(3): ci.search_next_param_random() - ci.write_result(random.random()) # write result - for i in range(1): + result = get_data_from_result_list(ci.get_next_index()) # get result/evaluation data from experiment. (Result list is used for this test program). + ci.write_result(result) # write result + for i in range(17): ci.search_next_param_bayes() - ci.write_result(random.random()) # write result - - raw_input('Press enter to save and finish\n') + result = get_data_from_result_list(ci.get_next_index()) + ci.write_result(result) + #raw_input('Press enter to save and finish\n') ci.save_data(policy_save_dir) - -if __name__ == '__main__': - main() + assert filecmp.cmp(candidates_path, correct_candidates_path) diff --git a/ml_interfaces/bayesopt_interfaces/tests/test_physbo_interface.py b/ml_interfaces/bayesopt_interfaces/tests/test_physbo_interface.py index 1b97ff5..e2dabb5 100755 --- a/ml_interfaces/bayesopt_interfaces/tests/test_physbo_interface.py +++ b/ml_interfaces/bayesopt_interfaces/tests/test_physbo_interface.py @@ -2,25 +2,31 @@ # -*- coding: utf-8 -*- import csv +import filecmp import os import sys from bayesopt_if.physbo_interface import PhysboInterface +file_dir = os.path.dirname(__file__) +data_dir = os.path.join(file_dir, 'data') + def get_data_from_result_list(index): - with open('./data/results.csv') as f: + results_path = os.path.join(data_dir, 'results.csv') + with open(results_path) as f: reader = csv.reader(f) l = [row for row in reader] return float(l[index+1][0]) -def main(): +def test_physbo_interface(): # dir setting - candidates_path = './data/candidates.csv' - policy_load_dir = './data/load' - policy_save_dir = './data/result' + candidates_path = os.path.join(data_dir, 'candidates.csv') + correct_candidates_path = os.path.join(data_dir, 'candidates-correct.csv') + policy_load_dir = os.path.join(data_dir, 'load') + policy_save_dir = os.path.join(data_dir, 'result') # Generate physbo pi = PhysboInterface(candidates_path, policy_load_dir, policy_save_dir, use_saved_policy=False, search_score='EI') @@ -36,15 +42,12 @@ def main(): result = get_data_from_result_list(pi.get_next_index()) # get result/evaluation data from experiment. (Result list is used for this test program). pi.write_result(result) # write result to PHYSBO # Search with Bayesian optimization - for i in range(3): + for i in range(17): pi.search_next_param_bayes() result = get_data_from_result_list(pi.get_next_index()) pi.write_result(result) - input('Press enter to save and finish\n') - + #input('Press enter to save and finish\n') pi.save_data(policy_save_dir) - -if __name__ == '__main__': - main() + assert filecmp.cmp(candidates_path, correct_candidates_path)