diff --git a/examples/active_learners/pref_gp_ucb_learner.py b/examples/active_learners/pref_gp_ucb_learner.py new file mode 100644 index 0000000..aa8aa53 --- /dev/null +++ b/examples/active_learners/pref_gp_ucb_learner.py @@ -0,0 +1,76 @@ +# Copyright 2024 Ian Rankin +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation files (the "Software"), to deal in the Software +# without restriction, including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +# to whom the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +# GP_UCB_learner.py +# Written Ian Rankin - January 2024 +# +# An example usage of preference GP with a UCB active learning algorithm +# This is done using a 1D function. + + +import numpy as np +import matplotlib.pyplot as plt + +import lop + + +# the function to approximate +def f_sin(x, data=None): + return 2 * np.cos(np.pi * (x-2)) * np.exp(-(0.9*x)) + +def main(): + al = lop.GV_UCBLearner() + model = lop.PreferenceGP(lop.RBF_kern(0.5,0.7), active_learner=al, normalize_gp=True) + + + # Generate active learning point and add it to the model + for i in range(10): + # generate random test set to select test point from + x_canidiates = np.random.random(20)*10 + + test_pt_idxs = model.select(x_canidiates, 2) + + + x_train = x_canidiates[test_pt_idxs] + y_train = f_sin(x_train) + y_pairs = lop.gen_pairs_from_idx(np.argmax(y_train), list(range(len(y_train)))) + + model.add(x_train, y_pairs) + + # Create test output of model + x_test = np.arange(0,10,0.005) + y_test = f_sin(x_test) + y_pred,y_sigma = model.predict(x_test) + std = np.sqrt(y_sigma) + + print(std) + + # Plot output of model with uncertianty + sigma_to_plot = 1.96 + plt.plot(x_test, y_test, zorder=5) + plt.plot(x_test, y_pred, zorder=5) + plt.scatter(model.X_train, model.F, zorder=10) + plt.gca().fill_between(x_test, y_pred-(sigma_to_plot*std), y_pred+(sigma_to_plot*std), color='#dddddd', zorder=1) + plt.xlabel('input values') + plt.ylabel('GP output') + plt.legend(['Real function', 'Predicted function', 'Active learning points', '95% condidence region']) + plt.show() + +if __name__ == '__main__': + main() + diff --git a/tests/active_learning/test_GV_UCB_learner.py b/tests/active_learning/test_GV_UCB_learner.py index 62c384a..66d53e9 100644 --- a/tests/active_learning/test_GV_UCB_learner.py +++ b/tests/active_learning/test_GV_UCB_learner.py @@ -46,3 +46,32 @@ def test_GV_UCB_learner_trains_basic_GP(): assert (np.abs(y_pred - y_test) < 0.2).all() + +def test_GV_UCB_learner_trains_preference_GP(): + al = lop.GV_UCBLearner() + model = lop.PreferenceGP(lop.RBF_kern(0.5,1.0), active_learner=al, normalize_positive=True) + + + np.random.seed(5) # just to ensure it doesn't break the test on a bad dice roll + for i in range(10): + # generate random test set to select test point from + x_canidiates = np.random.random(20)*10 + + test_pt_idxs = model.select(x_canidiates, 3) + + + x_train = x_canidiates[test_pt_idxs] + y_train = f_sin(x_train) + + y_pairs = lop.gen_pairs_from_idx(np.argmax(y_train), list(range(len(y_train)))) + + model.add(x_train, y_pairs) + + x_test = np.array([1.6,1.8,2.1,2.3,2.5,2.7]) + y_test = f_sin(x_test) + y_pred = model(x_test) + + assert not np.isnan(y_pred).any() + + assert (np.abs(y_pred - y_test) < 0.5).all() + diff --git a/tests/utilities/test_utility.py b/tests/utilities/test_utility.py index 0286e3d..a7bed1e 100644 --- a/tests/utilities/test_utility.py +++ b/tests/utilities/test_utility.py @@ -55,3 +55,22 @@ def test_fake_pairs(): assert p[1] == 0 assert p[2] == i+1 + + +def test_gen_pairs_from_idx(): + y_train = np.array([0,1,2,3]) + + y_pairs = lop.gen_pairs_from_idx(np.argmax(y_train), list(range(len(y_train)))) + + assert len(y_pairs) == 3 + assert y_pairs[0][0] == -1 + assert y_pairs[0][1] == 3 + assert y_pairs[0][2] == 0 + assert y_pairs[1][0] == -1 + assert y_pairs[1][1] == 3 + assert y_pairs[1][2] == 1 + assert y_pairs[2][0] == -1 + assert y_pairs[2][1] == 3 + assert y_pairs[2][2] == 2 + +