Commit 92c9d1a6 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

Merge branch 'likelihood_renamings' into 'NIFTy_7'

Likelihood renamings

See merge request !645
parents ada00fdb 1fb9abd8
......@@ -82,14 +82,15 @@ comparison to MGVI can be found in `demos/variational_inference_visualized.py`.
For further details see (<https://arxiv.org/abs/2105.10470>).
LikelihoodOperator
------------------
A new subclass of `EnergyOperator` was introduced and all `EnergyOperator`s
that are likelihoods are now `LikelihoodOperator`s. A `LikelihoodOperator`
has to implement the function `get_transformation`, which returns a
coordinate transformation in which the Fisher metric of the likelihood becomes
the identity matrix. This is needed for the `GeoMetricKL` algorithm.
LikelihoodEnergyOperator
------------------------
A new subclass of `EnergyOperator` was introduced and all `EnergyOperator`s that
are likelihoods are now `LikelihoodEnergyOperator`s. A
`LikelihoodEnergyOperator` has to implement the function `get_transformation`,
which returns a coordinate transformation in which the Fisher metric of the
likelihood becomes the identity matrix. This is needed for the `GeoMetricKL`
algorithm.
Changes since NIFTy 5
......
......@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2020 Max-Planck-Society
# Copyright(C) 2013-2021 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
......@@ -64,16 +64,16 @@ def main():
data = ift.random.current_rng().binomial(1, tmp)
data = ift.Field.from_raw(R.target, data)
# Compute likelihood and Hamiltonian
# Compute likelihood energy and Hamiltonian
position = ift.from_random(harmonic_space, 'normal')
likelihood = ift.BernoulliEnergy(data) @ p
likelihood_energy = ift.BernoulliEnergy(data) @ p
ic_newton = ift.DeltaEnergyController(
name='Newton', iteration_limit=100, tol_rel_deltaE=1e-8)
minimizer = ift.NewtonCG(ic_newton)
ic_sampling = ift.GradientNormController(iteration_limit=100)
# Minimize the Hamiltonian
H = ift.StandardHamiltonian(likelihood, ic_sampling)
H = ift.StandardHamiltonian(likelihood_energy, ic_sampling)
H = ift.EnergyAdapter(position, H, want_metric=True)
# minimizer = ift.L_BFGS(ic_newton)
H, convergence = minimizer(H)
......
......@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2020 Max-Planck-Society
# Copyright(C) 2013-2021 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
......@@ -85,14 +85,14 @@ def main():
# Define instrumental response
R = GR(M)
# Generate mock data and define likelihood operator
# Generate mock data and define likelihood energy operator
d_space = R.target[0]
lamb = R(sky)
mock_position = ift.from_random(domain, 'normal')
data = lamb(mock_position)
data = ift.random.current_rng().poisson(data.val.astype(np.float64))
data = ift.Field.from_raw(d_space, data)
likelihood = ift.PoissonianEnergy(data) @ lamb
likelihood_energy = ift.PoissonianEnergy(data) @ lamb
# Settings for minimization
ic_newton = ift.DeltaEnergyController(
......@@ -100,7 +100,7 @@ def main():
minimizer = ift.NewtonCG(ic_newton)
# Compute MAP solution by minimizing the information Hamiltonian
H = ift.StandardHamiltonian(likelihood)
H = ift.StandardHamiltonian(likelihood_energy)
initial_position = ift.from_random(domain, 'normal')
H = ift.EnergyAdapter(initial_position, H, want_metric=True)
H, convergence = minimizer(H)
......
......@@ -106,10 +106,10 @@ def main():
deltaE=0.5, iteration_limit=15, convergence_level=2)
minimizer_sampling = ift.NewtonCG(ic_sampling_nl)
# Set up likelihood and information Hamiltonian
likelihood = (ift.GaussianEnergy(mean=data, inverse_covariance=N.inverse) @
signal_response)
H = ift.StandardHamiltonian(likelihood, ic_sampling)
# Set up likelihood energy and information Hamiltonian
likelihood_energy = (ift.GaussianEnergy(mean=data, inverse_covariance=N.inverse) @
signal_response)
H = ift.StandardHamiltonian(likelihood_energy, ic_sampling)
initial_mean = ift.MultiField.full(H.domain, 0.)
mean = initial_mean
......
......@@ -124,9 +124,9 @@ def main():
# number of samples used to estimate the KL
N_samples = 20
# Set up likelihood and information Hamiltonian
likelihood = ift.GaussianEnergy(mean=data, inverse_covariance=N.inverse) @ signal_response
H = ift.StandardHamiltonian(likelihood, ic_sampling)
# Set up likelihood energy and information Hamiltonian
likelihood_energy = ift.GaussianEnergy(mean=data, inverse_covariance=N.inverse) @ signal_response
H = ift.StandardHamiltonian(likelihood_energy, ic_sampling)
# Begin minimization
initial_mean = ift.MultiField.full(H.domain, 0.)
......
......@@ -84,9 +84,9 @@ if __name__ == "__main__":
# Number of samples used to estimate the KL
n_samples = 5
# Set up likelihood and information Hamiltonian
likelihood = ift.PoissonianEnergy(data) @ signal
ham = ift.StandardHamiltonian(likelihood, ic_sampling)
# Set up likelihood energy and information Hamiltonian
likelihood_energy = ift.PoissonianEnergy(data) @ signal
ham = ift.StandardHamiltonian(likelihood_energy, ic_sampling)
# Start minimization
initial_mean = ift.MultiField.full(ham.domain, 0.)
......
......@@ -57,12 +57,12 @@ if __name__ == "__main__":
d_space = R.target[0]
lamb = R(sky)
# Generate simulated signal and data and build log-likelihood
# Generate simulated signal and data and build likelihood energy
mock_position = ift.from_random(sky.domain, "normal")
data = ift.random.current_rng().poisson(lamb(mock_position).val)
data = ift.makeField(d_space, data)
loglikelihood = ift.PoissonianEnergy(data) @ lamb
H = ift.StandardHamiltonian(loglikelihood)
likelihood_energy = ift.PoissonianEnergy(data) @ lamb
H = ift.StandardHamiltonian(likelihood_energy)
# Settings for minimization
IC = ift.StochasticAbsDeltaEnergyController(5, iteration_limit=200,
......
......@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2020 Max-Planck-Society
# Copyright(C) 2013-2021 Max-Planck-Society
# Author: Philipp Arras
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
......@@ -104,8 +104,8 @@ def main():
N = ift.DiagonalOperator(ift.makeField(d_space, var))
IC = ift.DeltaEnergyController(tol_rel_deltaE=1e-12, iteration_limit=200)
likelihood = ift.GaussianEnergy(d, N) @ R
Ham = ift.StandardHamiltonian(likelihood, IC)
likelihood_energy = ift.GaussianEnergy(d, N) @ R
Ham = ift.StandardHamiltonian(likelihood_energy, IC)
H = ift.EnergyAdapter(params, Ham, want_metric=True)
# Minimize
......
......@@ -378,11 +378,11 @@ compute the negative log-likelihood of the problem in standardized coordinates
at a given position in parameter space.
Finally, the :class:`~operators.energy_operators.StandardHamiltonian`
can be constructed from the likelihood, represented by a
:class:`~operators.energy_operators.LikelihoodOperator` instance.
:class:`~operators.energy_operators.LikelihoodEnergyOperator` instance.
Several commonly used forms of the likelihoods are already provided in
NIFTy, such as :class:`~operators.energy_operators.GaussianEnergy`,
:class:`~operators.energy_operators.PoissonianEnergy`,
:class:`~operators.energy_operators.InverseGammaLikelihood` or
:class:`~operators.energy_operators.InverseGammaEnergy` or
:class:`~operators.energy_operators.BernoulliEnergy`, but the user
is free to implement any likelihood customized to the problem at hand.
The demo code `demos/getting_started_3.py` illustrates how to set up an energy
......
......@@ -48,7 +48,7 @@ from .operators.simple_linear_operators import (
from .operators.matrix_product_operator import MatrixProductOperator
from .operators.value_inserter import ValueInserter
from .operators.energy_operators import (
EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaLikelihood,
EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaEnergy,
BernoulliEnergy, StandardHamiltonian, AveragedEnergy, QuadraticFormOperator,
Squared2NormOperator, StudentTEnergy, VariableCovarianceGaussianEnergy)
from .operators.convolution_operators import FuncConvolutionOperator
......
......@@ -11,13 +11,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2019 Max-Planck-Society
# Copyright(C) 2013-2021 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
from ..minimization.energy_adapter import EnergyAdapter
from ..multi_field import MultiField
from ..operators.energy_operators import (InverseGammaLikelihood,
from ..operators.energy_operators import (InverseGammaEnergy,
StandardHamiltonian)
from ..operators.scaling_operator import ScalingOperator
from ..operators.simple_linear_operators import ducktape
......@@ -74,7 +74,7 @@ def make_adjust_variances_hamiltonian(a,
if scaling is not None:
x = ScalingOperator(x.target, scaling)(x)
return StandardHamiltonian(InverseGammaLikelihood(d_eval/2.)(x),
return StandardHamiltonian(InverseGammaEnergy(d_eval/2.)(x),
ic_samp=ic_samp)
......
......@@ -83,19 +83,19 @@ class EnergyOperator(Operator):
_target = DomainTuple.scalar_domain()
class LikelihoodOperator(EnergyOperator):
"""Represent a log-likelihood.
class LikelihoodEnergyOperator(EnergyOperator):
"""Represent a negative log-likelihood.
The input to the Operator are the parameters of the likelihood. Unlike a
general `EnergyOperator`, the metric of a `LikelihoodOperator` is the
Fisher information metric of the likelihood.
The input to the Operator are the parameters of the negative log-likelihood.
Unlike a general `EnergyOperator`, the metric of a
`LikelihoodEnergyOperator` is the Fisher information metric of the
likelihood.
"""
def get_metric_at(self, x):
"""Computes the Fisher information metric for a `LikelihoodOperator`
"""Compute the Fisher information metric for a `LikelihoodEnergyOperator`
at `x` using the Jacobian of the coordinate transformation given by
:func:`~nifty7.operators.operator.Operator.get_transformation`.
"""
:func:`~nifty7.operators.operator.Operator.get_transformation`. """
dtp, f = self.get_transformation()
ch = None
if dtp is not None:
......@@ -152,7 +152,7 @@ class QuadraticFormOperator(EnergyOperator):
return x.new(res, VdotOperator(self._op(x.val)))
class VariableCovarianceGaussianEnergy(LikelihoodOperator):
class VariableCovarianceGaussianEnergy(LikelihoodEnergyOperator):
"""Computes the negative log pdf of a Gaussian with unknown covariance.
The covariance is assumed to be diagonal.
......@@ -249,7 +249,7 @@ class VariableCovarianceGaussianEnergy(LikelihoodOperator):
return self._dt, f
class _SpecialGammaEnergy(LikelihoodOperator):
class _SpecialGammaEnergy(LikelihoodEnergyOperator):
def __init__(self, residual):
self._domain = DomainTuple.make(residual.domain)
self._resi = residual
......@@ -272,7 +272,7 @@ class _SpecialGammaEnergy(LikelihoodOperator):
return self._dt, sc*ScalingOperator(self._domain, 1.).log()
class GaussianEnergy(LikelihoodOperator):
class GaussianEnergy(LikelihoodEnergyOperator):
"""Computes a negative-log Gaussian.
Represents up to constants in :math:`m`:
......@@ -370,7 +370,7 @@ class GaussianEnergy(LikelihoodOperator):
return f'GaussianEnergy {dom}'
class PoissonianEnergy(LikelihoodOperator):
class PoissonianEnergy(LikelihoodEnergyOperator):
"""Computes likelihood Hamiltonians of expected count field constrained by
Poissonian count data.
......@@ -408,7 +408,7 @@ class PoissonianEnergy(LikelihoodOperator):
return np.float64, 2.*ScalingOperator(self._domain, 1.).sqrt()
class InverseGammaLikelihood(LikelihoodOperator):
class InverseGammaEnergy(LikelihoodEnergyOperator):
"""Computes the negative log-likelihood of the inverse gamma distribution.
It negative log-pdf(x) is given by
......@@ -457,7 +457,7 @@ class InverseGammaLikelihood(LikelihoodOperator):
return self._sampling_dtype, res
class StudentTEnergy(LikelihoodOperator):
class StudentTEnergy(LikelihoodEnergyOperator):
"""Computes likelihood energy corresponding to Student's t-distribution.
.. math ::
......@@ -495,7 +495,7 @@ class StudentTEnergy(LikelihoodOperator):
return np.float64, makeOp(((th+1)/(th+3)).sqrt())
class BernoulliEnergy(LikelihoodOperator):
class BernoulliEnergy(LikelihoodEnergyOperator):
"""Computes likelihood energy of expected event frequency constrained by
event data.
......@@ -585,8 +585,8 @@ class StandardHamiltonian(EnergyOperator):
return (lhx+prx).add_metric(met)
def __repr__(self):
subs = 'Likelihood:\n{}'.format(utilities.indent(self._lh.__repr__()))
subs += '\nPrior:\n{}'.format(self._prior)
subs = 'Likelihood energy:\n{}'.format(utilities.indent(self._lh.__repr__()))
subs += '\nPrior energy:\n{}'.format(self._prior)
return 'StandardHamiltonian:\n' + utilities.indent(subs)
def _simplify_for_constant_input_nontrivial(self, c_inp):
......
......@@ -111,7 +111,7 @@ class Operator(metaclass=NiftyMeta):
"""The coordinate transformation that maps into a coordinate system in
which the metric of a likelihood is the Euclidean metric. It is `None`,
except for instances of
:class:`~nifty7.operators.energy_operators.LikelihoodOperator` or
:class:`~nifty7.operators.energy_operators.LikelihoodEnergyOperator` or
(nested) sums thereof.
Returns
......
......@@ -39,7 +39,7 @@ from .plot import Plot
__all__ = ['PS_field', 'power_analyze', 'create_power_operator',
'density_estimator', 'create_harmonic_smoothing_operator',
'from_random', 'full', 'makeField', 'is_fieldlike',
'is_linearization', 'is_operator', 'makeDomain', 'is_likelihood',
'is_linearization', 'is_operator', 'makeDomain', 'is_likelihood_energy',
'get_signal_variance', 'makeOp', 'domain_union',
'get_default_codomain', 'single_plot', 'exec_time',
'calculate_position'] + list(pointwise.ptw_dict.keys())
......@@ -591,8 +591,8 @@ def calculate_position(operator, output):
return pos
def is_likelihood(obj):
"""Checks if object is likelihood-like.
def is_likelihood_energy(obj):
"""Checks if object behaves like a likelihood energy.
"""
return isinstance(obj, Operator) and obj.get_transformation() is not None
......
......@@ -103,7 +103,7 @@ def test_inverse_gamma(field):
space = field.domain
d = ift.random.current_rng().normal(10, size=space.shape)**2
d = ift.Field(space, d)
energy = ift.InverseGammaLikelihood(d)
energy = ift.InverseGammaEnergy(d)
ift.extra.check_operator(energy, field, tol=1e-10)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment