Skip to content

Commit

Permalink
Several cleanups, move old code to legacy, change n_draws to n
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-eschle committed Nov 21, 2018
1 parent e1a2868 commit 799c7e5
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 79 deletions.
15 changes: 8 additions & 7 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ Development Lead
Contributors
------------

Michele Atzeni <michele.atzeni@cern.ch>
Andrea Mauri <a.mauri@cern.ch>
Anton Poluektov <anton.poluektov@cern.ch>
Albert Puig <albert.puig@cern.ch>
Nicola Serra <nicola.serra@cern.ch>
Rafael Silva Coutinho <rsilvaco@cern.ch>
Zhenzi Wang <zhenzi@physik.uzh.ch>
| Jonas Eschle <jonas.eschle@cern.ch>
| Michele Atzeni <michele.atzeni@cern.ch>
| Andrea Mauri <a.mauri@cern.ch>
| Anton Poluektov <anton.poluektov@cern.ch>
| Albert Puig <albert.puig@cern.ch>
| Nicola Serra <nicola.serra@cern.ch>
| Rafael Silva Coutinho <rsilvaco@cern.ch>
| Zhenzi Wang <zhenzi@physik.uzh.ch>
File renamed without changes.
5 changes: 0 additions & 5 deletions zfit/core/optimization.py → legacy/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@
from zfit.settings import types as ztypes

# start legacy
import zfit
import zfit.ztf

if zfit.settings.LEGACY_MODE:
import zfit.legacy
from zfit.core.math import gradient_par as gradient

cacheable_tensors = []

Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions tests/test_basePDF.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

class TestGaussian(zfit.core.basepdf.BasePDF):

def _unnormalized_pdf(self, x):
def _unnormalized_pdf(self, x, norm_range=False):
return tf.exp((-(x - mu_true) ** 2) / (2 * sigma_true ** 2)) # non-normalized gaussian


Expand Down Expand Up @@ -108,13 +108,13 @@ def test_sampling():
sess = zfit.sess
sess.run(init)
n_draws = 1000
sample_tensor = gauss_params1.sample(n_draws=n_draws, limits=(low, high))
sample_tensor = gauss_params1.sample(n=n_draws, limits=(low, high))
sampled_from_gauss1 = sess.run(sample_tensor)
assert max(sampled_from_gauss1[0]) <= high
assert min(sampled_from_gauss1[0]) >= low
assert n_draws == len(sampled_from_gauss1[0])

sampled_gauss1_full = sess.run(gauss_params1.sample(n_draws=10000,
sampled_gauss1_full = sess.run(gauss_params1.sample(n=10000,
limits=(mu_true - abs(sigma_true) * 5,
mu_true + abs(sigma_true) * 5)))
mu_sampled = np.mean(sampled_gauss1_full)
Expand All @@ -132,7 +132,7 @@ class SampleGauss(TestGaussian):
SampleGauss.register_inverse_analytic_integral(func=lambda x, params: x + 1000.)

gauss1 = SampleGauss()
sample = gauss1.sample(n_draws=10000, limits=(2., 5.))
sample = gauss1.sample(n=10000, limits=(2., 5.))

sample = zfit.sess.run(sample)

Expand Down
45 changes: 22 additions & 23 deletions zfit/core/basemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,47 +706,47 @@ def _inverse_analytic_integrate(self, x):
return self._inverse_analytic_integral[0](x=x, params=self.parameters)

@_BaseModel_register_check_support(True)
def _sample(self, n_draws, limits):
def _sample(self, n, limits):
raise NotImplementedError

def sample(self, n_draws: int, limits: ztyping.LimitsType, name: str = "sample") -> ztyping.XType:
"""Sample `n_draws` within `limits` from the pdf.
def sample(self, n: int, limits: ztyping.LimitsType, name: str = "sample") -> ztyping.XType:
"""Sample `n` points within `limits` from the pdf.
Args:
n_draws (int): The number of samples to be generated
n (int): The number of samples to be generated
limits (tuple, Range): In which region to sample in
name (str):
Returns:
Tensor(n_dims, n_samples)
"""
limits = convert_to_range(limits, dims=Range.FULL)
return self._hook_sample(n_draws=n_draws, limits=limits, name=name)
return self._hook_sample(n=n, limits=limits, name=name)

def _hook_sample(self, limits, n_draws, name='_hook_sample'):
return self._norm_sample(n_draws=n_draws, limits=limits, name=name)
def _hook_sample(self, limits, n, name='_hook_sample'):
return self._norm_sample(n=n, limits=limits, name=name)

def _norm_sample(self, n_draws, limits, name):
def _norm_sample(self, n, limits, name):
"""Dummy function"""
return self._limits_sample(n_draws=n_draws, limits=limits, name=name)
return self._limits_sample(n=n, limits=limits, name=name)

def _limits_sample(self, n_draws, limits, name):
def _limits_sample(self, n, limits, name):
try:
return self._call_sample(n_draws=n_draws, limits=limits, name=name)
return self._call_sample(n=n, limits=limits, name=name)
except MultipleLimitsNotImplementedError:
raise NotImplementedError("MultipleLimits auto handling in sample currently not supported.")

def _call_sample(self, n_draws, limits, name):
with self._name_scope(name, values=[n_draws, limits]):
n_draws = ztf.convert_to_tensor(n_draws, dtype=ztypes.int, name="n_draws")
def _call_sample(self, n, limits, name):
with self._name_scope(name, values=[n, limits]):
n = ztf.convert_to_tensor(n, dtype=ztypes.int, name="n")

with suppress(NotImplementedError):
return self._sample(n_draws=n_draws, limits=limits)
return self._sample(n=n, limits=limits)
with suppress(NotImplementedError):
return self._analytic_sample(n_draws=n_draws, limits=limits)
return self._fallback_sample(n_draws=n_draws, limits=limits)
return self._analytic_sample(n=n, limits=limits)
return self._fallback_sample(n=n, limits=limits)

def _analytic_sample(self, n_draws, limits: Range):
def _analytic_sample(self, n, limits: Range):
if len(limits) > 1:
raise MultipleLimitsNotImplementedError()

Expand All @@ -767,15 +767,14 @@ def _analytic_sample(self, n_draws, limits: Range):
except NotImplementedError:
raise NotImplementedError("analytic sampling not possible because the analytic integral is not"
"implemented for the boundaries:".format(limits.get_boundaries()))
prob_sample = ztf.random_uniform(shape=(n_draws, limits.n_dims), minval=lower_prob_lim,
prob_sample = ztf.random_uniform(shape=(n, limits.n_dims), minval=lower_prob_lim,
maxval=upper_prob_lim)
sample = self._inverse_analytic_integrate(x=prob_sample)
return sample

def _fallback_sample(self, n_draws, limits):
sample = zsample.accept_reject_sample(prob=self._func_to_sample_from, # no need to normalize
n_draws=n_draws,
limits=limits, prob_max=None) # None -> auto
def _fallback_sample(self, n, limits):
sample = zsample.accept_reject_sample(prob=self._func_to_sample_from, n=n, limits=limits,
prob_max=None) # None -> auto
return sample

@abc.abstractmethod
Expand Down
13 changes: 0 additions & 13 deletions zfit/core/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,3 @@ def interpolate(t, c):
interp = tf.reduce_sum(tf.stack(wts), 0)
return interp


def gradient_par(func):
"""Return TF graph for analytic gradient_par of the input func wrt all floating variables.
Arguments:
func (Tensor): A function of which the derivatives with respect to the free floating
parameters will be taken.
Return:
list(graph): the derivative
"""
tfpars = tf.trainable_variables() # Create TF variables
float_tfpars = [p for p in tfpars if p.floating()] # List of floating parameters
return tf.gradients(func, float_tfpars) # Get analytic gradient_par
33 changes: 15 additions & 18 deletions zfit/core/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@


@no_multiple_limits
def accept_reject_sample(prob: typing.Callable, n_draws: int, limits: Range,
sampler: typing.Callable = tf.random_uniform,
dtype=ztypes.float,
prob_max: typing.Union[None, int] = None) -> tf.Tensor:
def accept_reject_sample(prob: typing.Callable, n: int, limits: Range, sampler: typing.Callable = tf.random_uniform,
dtype=ztypes.float, prob_max: typing.Union[None, int] = None) -> tf.Tensor:
"""Accept reject sample from a probability distribution.
Args:
prob (function): A function taking x a Tensor as an argument and returning the probability
(or anything that is proportional to the probability).
n_draws (int): Number of samples to produce
n (int): Number of samples to produce
limits (Range): The limits to sample from
sampler (function): A function taking n_draws as an argument and returning values between
sampler (function): A function taking n as an argument and returning values between
0 and 1
dtype ():
prob_max (Union[None, int]): The maximum of the pdf function for the given limits. If None
Expand All @@ -36,16 +34,16 @@ def accept_reject_sample(prob: typing.Callable, n_draws: int, limits: Range,
lower, upper = limits.get_boundaries()
lower = ztf.convert_to_tensor(lower, dtype=dtype)
upper = ztf.convert_to_tensor(upper, dtype=dtype)
n_draws = tf.to_int64(n_draws)
n = tf.to_int64(n)

def enough_produced(n_draws, sample, n_total_drawn, eff):
return tf.less(tf.shape(sample, out_type=tf.int64)[1], n_draws)
def enough_produced(n, sample, n_total_drawn, eff):
return tf.less(tf.shape(sample, out_type=tf.int64)[1], n)

def sample_body(n_draws, sample, n_total_drawn=0, eff=1.):
def sample_body(n, sample, n_total_drawn=0, eff=1.):
if sample is None:
n_to_produce = n_draws
n_to_produce = n
else:
n_to_produce = n_draws - tf.shape(sample, out_type=tf.int64)[1]
n_to_produce = n - tf.shape(sample, out_type=tf.int64)[1]
# TODO: add efficiency cap for memory efficiency (prevent too many samples at once produced)
n_to_produce = tf.to_int64(ztf.to_real(n_to_produce) / eff * 0.99) + 100 # just to make sure
n_total_drawn += n_to_produce
Expand All @@ -71,14 +69,14 @@ def sample_body(n_draws, sample, n_total_drawn=0, eff=1.):

# efficiency (estimate) of how many samples we get
eff = ztf.to_real(tf.shape(sample, out_type=tf.int64)[1]) / ztf.to_real(n_total_drawn)
return n_draws, sample, n_total_drawn, eff
return n, sample, n_total_drawn, eff

sample = tf.while_loop(cond=enough_produced, body=sample_body, # paraopt
loop_vars=sample_body(n_draws=n_draws, sample=None, # run first once for initialization
loop_vars=sample_body(n=n, sample=None, # run first once for initialization
n_total_drawn=0, eff=1.),
swap_memory=True, parallel_iterations=4,
back_prop=False)[1] # backprop not needed here
return sample[:, :n_draws] # cutting away to many produced
return sample[:, :n] # cutting away to many produced


if __name__ == '__main__':
Expand Down Expand Up @@ -106,9 +104,8 @@ def sample_body(n_draws, sample, n_total_drawn=0, eff=1.):
# maximum = None
list1 = []

sampled_dist_ar = accept_reject_sample(prob=dist.prob, n_draws=100000000,
limits=(-13.5, 16.5),
prob_max=maximum, sampler=None)
sampled_dist_ar = accept_reject_sample(prob=dist.prob, n=100000000, limits=(-13.5, 16.5), sampler=None,
prob_max=maximum)

# HACK

Expand Down
4 changes: 2 additions & 2 deletions zfit/models/dist_tfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def _unnormalized_pdf(self, x, norm_range=False):
def _analytic_integrate(self, limits, norm_range):
lower, upper = limits.get_boundaries()
if all(-np.array(lower) == np.array(upper) == np.infty):
return ztf.to_real(1.)
return ztf.to_real(1.) # tfp distributions are normalized to 1
lower = ztf.to_real(lower[0])
upper = ztf.to_real(upper[0])
integral = self.tf_distribution.cdf(upper) - self.tf_distribution.cdf(lower)
Expand All @@ -59,5 +59,5 @@ def __init__(self, tau, name="Exponential"):

class Uniform(WrapDistribution):
def __init__(self, low, high, name="Uniform"):
distribution = tfp.distributions.Exponential(low=low, high=high, name=name + "_tf")
distribution = tfp.distributions.Uniform(low=low, high=high, name=name + "_tfp")
super().__init__(distribution=distribution, name=name)
7 changes: 0 additions & 7 deletions zfit/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@

from zfit.util.container import DotDict

# legacy settings
LEGACY_MODE = True


# Use double precision throughout


def set_seed(seed):
"""
Expand All @@ -34,4 +28,3 @@ def set_seed(seed):
options = DotDict({'epsilon': 1e-8})

sess = tf.Session()

0 comments on commit 799c7e5

Please sign in to comment.