Skip to content
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

move objective outside of acquistion folder #395

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aepsych/acquisition/lse.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing import Optional, Union

import torch
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from botorch.acquisition.input_constructors import acqf_input_constructor
from botorch.acquisition.monte_carlo import (
MCAcquisitionFunction,
Expand Down
2 changes: 1 addition & 1 deletion aepsych/acquisition/mc_posterior_variance.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import torch
from aepsych.acquisition.monotonic_rejection import MonotonicMCAcquisition
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from botorch.acquisition.input_constructors import acqf_input_constructor
from botorch.acquisition.monte_carlo import MCAcquisitionFunction
from botorch.acquisition.objective import MCAcquisitionObjective
Expand Down
2 changes: 1 addition & 1 deletion aepsych/acquisition/mutual_information.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import torch
from aepsych.acquisition.monotonic_rejection import MonotonicMCAcquisition
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from botorch.acquisition.input_constructors import acqf_input_constructor
from botorch.acquisition.monte_carlo import MCAcquisitionFunction
from botorch.acquisition.objective import MCAcquisitionObjective
Expand Down
2 changes: 1 addition & 1 deletion aepsych/generators/monotonic_thompson_sampler_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import numpy as np
import torch
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from aepsych.config import Config
from aepsych.generators.base import AEPsychGenerator
from aepsych.models.monotonic_rejection_gp import MonotonicRejectionGP
Expand Down
2 changes: 1 addition & 1 deletion aepsych/generators/semi_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing import Type

import torch
from aepsych.acquisition.objective.semi_p import SemiPThresholdObjective
from aepsych.objective.semi_p import SemiPThresholdObjective
from aepsych.generators import OptimizeAcqfGenerator
from aepsych.models.semi_p import SemiParametricGPModel

Expand Down
2 changes: 1 addition & 1 deletion aepsych/likelihoods/semi_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from typing import Optional

import torch
from aepsych.acquisition.objective import AEPsychObjective, FloorProbitObjective
from aepsych.config import Config
from aepsych.objective import AEPsychObjective, FloorProbitObjective
from gpytorch.likelihoods import _OneDimensionalLikelihood


Expand Down
4 changes: 2 additions & 2 deletions aepsych/models/semi_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
import gpytorch
import numpy as np
import torch
from aepsych.acquisition.objective import FloorLogitObjective
from aepsych.objective import FloorLogitObjective

from aepsych.acquisition.objective.semi_p import SemiPThresholdObjective
from aepsych.objective.semi_p import SemiPThresholdObjective
from aepsych.config import Config
from aepsych.likelihoods import BernoulliObjectiveLikelihood, LinearBernoulliLikelihood
from aepsych.models import GPClassificationModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import sys

from ...config import Config
from .objective import (
AEPsychObjective,
from .aepsych_objective import AEPsychObjective
from .probit import ProbitObjective
from .floor_objective import (
FloorGumbelObjective,
FloorLogitObjective,
FloorProbitObjective,
Expand Down
13 changes: 13 additions & 0 deletions aepsych/objective/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.

# pyre-strict

from typing import Optional

from botorch.acquisition.objective import MCAcquisitionObjective
from torch import Tensor


class AEPsychObjective(MCAcquisitionObjective):
def inverse(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
raise NotImplementedError
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,14 @@
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.

from __future__ import annotations

from typing import Optional

import torch
from botorch.acquisition.objective import MCAcquisitionObjective
from torch import Tensor
from torch.distributions.normal import Normal


class AEPsychObjective(MCAcquisitionObjective):
def inverse(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
raise NotImplementedError


class ProbitObjective(AEPsychObjective):
"""Probit objective

Transforms the input through the normal CDF (probit).
"""

def forward(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
"""Evaluates the objective (normal CDF).

Args:
samples (Tensor): GP samples.
X (Optional[Tensor], optional): ignored, here for compatibility
with MCAcquisitionObjective.

Returns:
Tensor: [description]
"""
return Normal(loc=0, scale=1).cdf(samples.squeeze(-1))

def inverse(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
"""Evaluates the inverse of the objective (normal PPF).

Args:
samples (Tensor): GP samples.
X (Optional[Tensor], optional): ignored, here for compatibility
with MCAcquisitionObjective.
from torch.distributions.normal import Normal

Returns:
Tensor: [description]
"""
return Normal(loc=0, scale=1).icdf(samples.squeeze(-1))
from .base import AEPsychObjective


class FloorLinkObjective(AEPsychObjective):
Expand Down
42 changes: 42 additions & 0 deletions aepsych/objective/probit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.

# pyre-strict

from typing import Optional

from torch import Tensor

from .base import AEPsychObjective


class ProbitObjective(AEPsychObjective):
"""Probit objective

Transforms the input through the normal CDF (probit).
"""

def forward(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
"""Evaluates the objective (normal CDF).

Args:
samples (Tensor): GP samples.
X (Optional[Tensor], optional): ignored, here for compatibility
with MCAcquisitionObjective.

Returns:
Tensor: [description]
"""
return Normal(loc=0, scale=1).cdf(samples.squeeze(-1))

def inverse(self, samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
"""Evaluates the inverse of the objective (normal PPF).

Args:
samples (Tensor): GP samples.
X (Optional[Tensor], optional): ignored, here for compatibility
with MCAcquisitionObjective.

Returns:
Tensor: [description]
"""
return Normal(loc=0, scale=1).icdf(samples.squeeze(-1))
File renamed without changes.
2 changes: 1 addition & 1 deletion docs/gp_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ By way of example, if our goal is to estimate the psychometric function at every

From a technical perspective, there are two categories of acquisition functions in AEPsych:

1. Monte Carlo (MC) acquisition functions. These acquisition functions can be evaluated by sampling from the model posterior. In the simplest case we sample from the latent perceptual field posterior, but we can also sample from other posteriors such as the response probability posterior, or response threshold posterior. The most common acquisition functions of this kind is BALD, or information maximization w.r.t. the response probability posterior (aka [`BernoulliMCMutualInformation`](https://aepsych.org/api/acquisition.html#aepsych.acquisition.mutual_information.BernoulliMCMutualInformation) in AEPsych), or BALV, or variance maximization (aka [`MCPosteriorVariance`](https://aepsych.org/api/acquisition.html#aepsych.acquisition.mc_posterior_variance.MCPosteriorVariance) in AEPsych). [Keeley et al. 2023](https://arxiv.org/abs/2302.01187) additionally introduced `ThresholdBALV`, which is BALV defined over the threshold rather than probability posterior for the semi-parametric GP models in AEPsych. To use `ThresholdBALV`, use `MCPosteriorVariance` with the `objective=[SemiPThresholdObjective](https://aepsych.org/api/acquisition.html#aepsych.acquisition.objective.SemiPThresholdObjective)` option. Because they only require sampling from the posterior, they can be used with any model which admits sampling from the posterior.
1. Monte Carlo (MC) acquisition functions. These acquisition functions can be evaluated by sampling from the model posterior. In the simplest case we sample from the latent perceptual field posterior, but we can also sample from other posteriors such as the response probability posterior, or response threshold posterior. The most common acquisition functions of this kind is BALD, or information maximization w.r.t. the response probability posterior (aka [`BernoulliMCMutualInformation`](https://aepsych.org/api/acquisition.html#aepsych.acquisition.mutual_information.BernoulliMCMutualInformation) in AEPsych), or BALV, or variance maximization (aka [`MCPosteriorVariance`](https://aepsych.org/api/acquisition.html#aepsych.acquisition.mc_posterior_variance.MCPosteriorVariance) in AEPsych). [Keeley et al. 2023](https://arxiv.org/abs/2302.01187) additionally introduced `ThresholdBALV`, which is BALV defined over the threshold rather than probability posterior for the semi-parametric GP models in AEPsych. To use `ThresholdBALV`, use `MCPosteriorVariance` with the `objective=[SemiPThresholdObjective](https://aepsych.org/api/acquisition.html#aepsych.objective.SemiPThresholdObjective)` option. Because they only require sampling from the posterior, they can be used with any model which admits sampling from the posterior.
2. Analytic acquisition functions. These acquisition functions require an explicit multivariate normal (MVN) posterior to be evaluated. They can often be faster to evaluate, and enable efficient computation of _lookahead_ approaches, which compute the acquisition in expectation of the posterior as it will be given the next observation. As with MC acquisition functions, they can be evaluated w.r.t. the current or lookahead function posterior (as in [Zhao et al. 2021](https://proceedings.neurips.cc/paper_files/paper/2021/hash/50d2e70cdf7dd05be85e1b8df3f8ced4-Abstract.html), the lookahead level set (threshold) posterior, as described in [Letham et al. 2022](https://arxiv.org/abs/2203.09751), or any other posterior that can be approximated as MVN (e.g. the full semi-parametric posterior, with the MVN approximation taken after posterior inference.

For more on analytic and MC acquisition functions, you can check the [BoTorch docs](https://botorch.org/docs/acquisition), and AEPsych supports all BoTorch acquisition functions, as well as a growing number of acquisition functions developed specifically for human psychophysics. From an application perspective, acquisition functions in AEPsych could be sorted based on their goals:
Expand Down
6 changes: 3 additions & 3 deletions sphinx/source/acquisition.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
aepsych.acquisition
aepsych.acquisition
===========================

Submodules
Expand Down Expand Up @@ -60,10 +60,10 @@ aepsych.acquisition.mutual\_information module
:undoc-members:
:show-inheritance:

aepsych.acquisition.objective module
aepsych.objective module
------------------------------------

.. automodule:: aepsych.acquisition.objective
.. automodule:: aepsych.objective
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion tests/acquisition/test_lse.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import numpy as np
import torch
from aepsych.acquisition.lse import MCLevelSetEstimation
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from botorch.utils.testing import MockModel, MockPosterior
from scipy.stats import norm

Expand Down
2 changes: 1 addition & 1 deletion tests/acquisition/test_mi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
BernoulliMCMutualInformation,
MonotonicBernoulliMCMutualInformation,
)
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from aepsych.benchmark.test_functions import f_1d
from aepsych.generators import (
MonotonicRejectionGenerator,
Expand Down
2 changes: 1 addition & 1 deletion tests/acquisition/test_monotonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import torch
from aepsych.acquisition.monotonic_rejection import MonotonicMCLSE
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from aepsych.models.derivative_gp import MixedDerivativeVariationalGP
from botorch.acquisition.objective import IdentityMCObjective
from botorch.utils.testing import BotorchTestCase
Expand Down
2 changes: 1 addition & 1 deletion tests/acquisition/test_objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import numpy as np
import torch
from aepsych.acquisition.objective import (
from aepsych.objective import (
FloorGumbelObjective,
FloorLogitObjective,
FloorProbitObjective,
Expand Down
2 changes: 1 addition & 1 deletion tests/models/test_monotonic_rejection_gp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


from aepsych.acquisition.monotonic_rejection import MonotonicMCLSE
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from aepsych.generators import MonotonicRejectionGenerator
from aepsych.models import MonotonicRejectionGP
from aepsych.strategy import Strategy
Expand Down
2 changes: 1 addition & 1 deletion tests/models/test_pairwise_probit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import numpy.testing as npt
import torch
from aepsych import server, utils_logging
from aepsych.acquisition.objective import ProbitObjective
from aepsych.objective import ProbitObjective
from aepsych.benchmark.test_functions import f_1d, f_2d, f_pairwise, new_novel_det
from aepsych.config import Config
from aepsych.generators import OptimizeAcqfGenerator, SobolGenerator
Expand Down
4 changes: 2 additions & 2 deletions tests/models/test_semi_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import torch
from aepsych.acquisition import MCPosteriorVariance
from aepsych.acquisition.lookahead import GlobalMI
from aepsych.acquisition.objective import (
from aepsych.objective import (
FloorGumbelObjective,
FloorLogitObjective,
FloorProbitObjective,
Expand All @@ -22,7 +22,7 @@
from aepsych.generators import OptimizeAcqfGenerator, SobolGenerator
from aepsych.likelihoods import BernoulliObjectiveLikelihood
from aepsych.strategy import SequentialStrategy, Strategy
from aepsych.acquisition.objective.semi_p import (
from aepsych.objective.semi_p import (
SemiPProbabilityObjective,
SemiPThresholdObjective,
)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import torch
from aepsych.acquisition import EAVC, MCLevelSetEstimation
from aepsych.acquisition.monotonic_rejection import MonotonicMCLSE
from aepsych.acquisition.objective import FloorGumbelObjective, ProbitObjective
from aepsych.objective import FloorGumbelObjective, ProbitObjective
from aepsych.config import Config
from aepsych.generators import (
MonotonicRejectionGenerator,
Expand Down
8 changes: 4 additions & 4 deletions website/_tutorials/Semi_P_tutorial.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h3 id="Semi-parametric-psychophysical-model-tutorial">Semi-parametric psychophy
<div class="highlight hl-ipython3"><pre><span></span><span class="c1">### SemiP imports</span>

<span class="kn">from</span> <span class="nn">aepsych.likelihoods</span> <span class="kn">import</span> <span class="n">BernoulliObjectiveLikelihood</span>
<span class="kn">from</span> <span class="nn">aepsych.acquisition.objective</span> <span class="kn">import</span> <span class="p">(</span>
<span class="kn">from</span> <span class="nn">aepsych.objective</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">FloorGumbelObjective</span><span class="p">,</span>
<span class="n">FloorLogitObjective</span><span class="p">,</span>
<span class="n">FloorProbitObjective</span><span class="p">,</span>
Expand All @@ -85,7 +85,7 @@ <h4 id="Test-function">Test function<a class="anchor-link" href="#Test-function"
<div class="inner_cell">
<div class="input_area">
<div class="highlight hl-ipython3"><pre><span></span><span class="c1"># Detection test function</span>
<span class="n">lb</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">lb</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">ub</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>

<span class="n">xgrid</span> <span class="o">=</span> <span class="n">dim_grid</span><span class="p">(</span><span class="n">lower</span><span class="o">=</span><span class="n">lb</span><span class="p">,</span> <span class="n">upper</span><span class="o">=</span><span class="n">ub</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
Expand Down Expand Up @@ -149,7 +149,7 @@ <h4 id="Fitting-the-model">Fitting the model<a class="anchor-link" href="#Fittin
<div class="inner_cell">
<div class="input_area">
<div class="highlight hl-ipython3"><pre><span></span><span class="c1">### fit SemiP models</span>
<span class="n">semip_model</span> <span class="o">=</span> <span class="n">SemiParametricGPModel</span><span class="p">(</span><span class="n">lb</span><span class="o">=</span><span class="n">lb</span><span class="p">,</span> <span class="n">ub</span><span class="o">=</span><span class="n">ub</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">stim_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
<span class="n">semip_model</span> <span class="o">=</span> <span class="n">SemiParametricGPModel</span><span class="p">(</span><span class="n">lb</span><span class="o">=</span><span class="n">lb</span><span class="p">,</span> <span class="n">ub</span><span class="o">=</span><span class="n">ub</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">stim_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
<span class="n">likelihood</span><span class="o">=</span><span class="n">LinearBernoulliLikelihood</span><span class="p">(</span><span class="n">objective</span><span class="o">=</span><span class="n">FloorProbitObjective</span><span class="p">(</span><span class="n">floor</span><span class="o">=</span><span class="mi">0</span><span class="p">)))</span>
<span class="n">approx_model</span> <span class="o">=</span> <span class="n">HadamardSemiPModel</span><span class="p">(</span><span class="n">lb</span><span class="o">=</span><span class="n">lb</span><span class="p">,</span> <span class="n">ub</span><span class="o">=</span><span class="n">ub</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">stim_dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
<span class="n">likelihood</span><span class="o">=</span><span class="n">BernoulliObjectiveLikelihood</span><span class="p">(</span><span class="n">objective</span><span class="o">=</span><span class="n">FloorProbitObjective</span><span class="p">(</span><span class="n">floor</span><span class="o">=</span><span class="mi">0</span><span class="p">)))</span>
Expand Down Expand Up @@ -332,4 +332,4 @@ <h1 id="Active-learning">Active learning<a class="anchor-link" href="#Active-lea
</div>
</div>
</div>
</div>
</div>
4 changes: 2 additions & 2 deletions website/pages/api/_modules/aepsych/acquisition/lse.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h1>Source code for aepsych.acquisition.lse</h1><div class="highlight"><pre>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Union</span>

<span class="kn">import</span> <span class="nn">torch</span>
<span class="kn">from</span> <span class="nn">aepsych.acquisition.objective</span> <span class="kn">import</span> <span class="n">ProbitObjective</span>
<span class="kn">from</span> <span class="nn">aepsych.objective</span> <span class="kn">import</span> <span class="n">ProbitObjective</span>
<span class="kn">from</span> <span class="nn">botorch.acquisition.input_constructors</span> <span class="kn">import</span> <span class="n">acqf_input_constructor</span>
<span class="kn">from</span> <span class="nn">botorch.acquisition.monte_carlo</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">MCAcquisitionFunction</span><span class="p">,</span>
Expand Down Expand Up @@ -165,4 +165,4 @@ <h3 id="searchlabel">Quick search</h3>
</div>
</div>
<div class="clearer"></div>
</div></div>
</div></div>
Loading
Loading