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

PIG 16 - Model Priors API #4381

Merged
merged 18 commits into from Nov 3, 2023

Conversation

nbiederbeck
Copy link
Contributor

This pull request adds a rough PIG for Prior (and FitStatistic). I anticipate I will add details with your assistance.

@codecov
Copy link

codecov bot commented Mar 15, 2023

Codecov Report

Merging #4381 (f6d08d2) into main (e6e5dd8) will decrease coverage by 0.28%.
Report is 165 commits behind head on main.
The diff coverage is n/a.

@@            Coverage Diff             @@
##             main    #4381      +/-   ##
==========================================
- Coverage   75.90%   75.62%   -0.28%     
==========================================
  Files         223      226       +3     
  Lines       32312    33026     +714     
==========================================
+ Hits        24527    24977     +450     
- Misses       7785     8049     +264     

see 61 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

Motivation
==========

Using priors on models and on parameters is the next step in full-fledged statistical analyses.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Using priors on models and on parameters is the next step in full-fledged statistical analyses.
Using priors on models or on parameters is the next step in full-fledged statistical analyses.

==========

Using priors on models and on parameters is the next step in full-fledged statistical analyses.
A prior can incorporate the analysers' knowledge of the topic at hand, and yield more realistically and trustworthy results.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not only the analyser... Indeed, one idea to deal with the IRFs systematics was to use the priors mechanics. So, if it is implemented like that, the knowledge comes from the people making the IRFs...

By the use, do we add as use case the inclusion of IRFs systematics into priors?

@adonath adonath added the pig label Mar 15, 2023
@adonath
Copy link
Member

adonath commented Mar 15, 2023

Thanks a lot @nbiederbeck for this minimal draft. The overall structure is good and the content should be extended for details now:

  • We need the definition of an abstract Prior base class. Define the evaluation and parameter API.
  • Clarify whether priors can have fittable parameters (yes!)
  • Some priors do not have fitable parameters...
  • Do we need a special PriorParameter class?
  • Clarify serialisation of priors with the model e.g. via an example YAML file
  • Mention prior registry system
  • Add a list of proposed standard priors: GaussianPrior, UniformPrior, MultivariateGaussianPrior
  • Strictly speaking one would not need the L2Regularization as it presents a multivariate Gaussian prior.
  • Clarify which Gammapy classes will support a .prior attribute: Models, SpectralModel, SkyModel etc.
  • Clarify how (hierarchical) priors are combined in the fit-statistic function
  • Do we need e.g. a class like PriorFitStatistic(beta=1.)?

These are just some thoughts for now, I'm sure I'll have some more...

@adonath adonath changed the title Add Prior PIG PIG-16: Model Priors API Mar 31, 2023

.. code:: python

class L2Regularization():
Copy link
Member

@adonath adonath Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this case actually corresponds to the GaussianPrior on each of the individual parameters, where mu=0 and sigma=1. The most general case I could imagine would be MultiVariateGaussianPrior on a list of parameters. The case of L2 regularization would be included there...but probably we just keep it for convenience.

@adonath adonath changed the title PIG-16: Model Priors API PIG 16 - Model Priors API May 12, 2023
@adonath
Copy link
Member

adonath commented May 26, 2023

@katrinstreil kindly agreed to take over the writing and further development of the PIG. Please let us of know if you have any questions.

This was referenced Jun 28, 2023
registerrier
registerrier previously approved these changes Jun 28, 2023
Copy link
Contributor

@registerrier registerrier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @katrinstreil @nbiederbeck . This already quite nice.

I would like to clarify a number of potential issues:

  1. it seems a bit complicated to me that priors can live and be defined and evaluated at different levels in the modeling package structure. I don't think that the SkyModel is the correct place anyway. We could have something to set priors on the Models instance with e.g. models.set_prior(parameters, prior).
  2. Parameters have units. How do we make sure that units are correctly handled?
  3. Is the PriorFitStatistic really needed? As far as I can see, it is mostly a single function.
  4. Connected to this, I wonder if the mixing of two use cases in a single prior framework is not a bit confusing. We have:
  • priors on individual parameters as usually done in e.g. sherpa, bxa, 3ML.
  • penalization terms for the ML which are used for e.g. regularization in unfolding
    Maybe this should be distinct features?


Future additional properties of the ``Prior`` classes:

- Fittable parameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that Prior has to contain Parameter objects? Doesn't this cause problems?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think in general a prior should be treated much like a model. In general prior parameter can be fitted in a likelihood fit (maximum a posteriori) as well...so I think they should handle Parameter objects.

self.mu = mu
self.sigma = sigma

def evaluate(self, value):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this follow the general scheme applied in models where evaluate is a static method that takes all parameters on input?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that the .evaluate() method should be static if possible. This will allows us to easier move to other tensor libraries later...The stateful call can happen in Prior.__call__

docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved

The prior classes are supposed to be set as ``.prior`` on:

* Model-like classes, for instance the ``SkyModel`` class:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really make sense to define the prior on the SkyModel? I would assume the more logical place is Parameters.
I suppose there are use cases where the prior applies to parameters of distinct SkyModel.
You could still do model.parameters.prior = some_prior

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason why it should be attached to the Model is bookkeeping. Priors should be serialized with the model. Parameters do not know, to which model they belong. The alternative is to handle it completely independent as we do for the covariance matrix and we would rely on the order of parameters. But in this case it would still be attached to the Model.

def __call__(self, base):

if isinstance(base, Parameter):
return self.evaluate(base.value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does it deal with the Parameter unit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess priors should be defined in such a way, that they are unit less (i.e. a likelihood after evaluation). But maybe we should add a check for this...

return np.sum(stat, dtype=np.float64) + PriorFitStatistic(weight=1).stat_sum(models = self.models)


Where the ``PriorFitStatistic`` iterates the models and parameters, evaluates and combines the priors with the possibility to assign a weight.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The need of an additional class seems unclear at the moment. It does only stat_sum, you could equivalently do something like this in Datasets.stat_sum():

    def stat_sum(self):
        """Compute joint statistic function value."""
        stat_sum = 0
  
        for dataset in self:
            stat_sum += dataset.stat_sum()
        prior_stat_sum = self.models.parameters.prior_stat_sum()
        return stat_sum + prior_stat_sum

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of the additional class is just to make it explicit, that one changes to a MAP estimate. It's like a global switch to account for the prior or not. The alternative is indeed to always evaluate priors, if present...

docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
@adonath
Copy link
Member

adonath commented Sep 15, 2023

Connected to this, I wonder if the mixing of two use cases in a single prior framework is not a bit confusing. We have:
priors on individual parameters as usually done in e.g. sherpa, bxa, 3ML.
penalization terms for the ML which are used for e.g. regularization in unfolding
Maybe this should be distinct features?

I don't think they are not distinct features. If you do the math you will find the L2 regularization corresponds to a multivariate Gaussian prior in a Maximum A-Posteriori estimation. The information is all in the covariance matrix. I think the right approach here is to just introduce a MultivariateGaussianPrior and some convenience methods for the creation of covariance matrices. See my sample above.

@registerrier registerrier marked this pull request as ready for review September 19, 2023 10:26
registerrier
registerrier previously approved these changes Oct 17, 2023
Copy link
Contributor

@registerrier registerrier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @katrinstreil .

Let's now send it to the CC.

docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
docs/development/pigs/pig-026.rst Outdated Show resolved Hide resolved
@registerrier
Copy link
Contributor

@katrinstreil , you will also need to update the index.rst file to add the PIG to the list.

bkhelifi
bkhelifi previously approved these changes Oct 18, 2023
Copy link
Member

@bkhelifi bkhelifi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @katrinstreil and @nbiederbeck

@katrinstreil katrinstreil mentioned this pull request Oct 18, 2023
Co-authored-by: Régis Terrier <regis.terrier@m4x.org>
@registerrier registerrier added this to the 1.2 milestone Nov 3, 2023
@registerrier
Copy link
Contributor

Review period is over. The PIG is accepted. Merging now.

@registerrier registerrier merged commit 586a1ff into gammapy:main Nov 3, 2023
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants