When playing with zfit tutorial, I just tried to remove the floating option of the alpha_sig parameter. In other words, I changed

alpha_sig = zfit.Parameter('alpha_sig', 200, 100, 400, floating=False)

to

alpha_sig = zfit.Parameter('alpha_sig', 200, 100, 400)

In this case, the result.hesse function fails. (The result is empty.)

[a path]/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py:153: UserWarning: minuit failed to calculate the covariance matrix or similar when calling `hesse`.Try to use `hesse_np` as the method instead and try again.This is unexpected and may has to do with iminuitV2. Either way, please fill an issue if this is not expected to fail for you.
  warnings.warn('minuit failed to calculate the covariance matrix or similar when calling `hesse`.'

Then I changed the hesse function from

result.hesse(method='minuit_hesse', name='hesse')

to

result.hesse(method='hesse_np', name='hesse')

and it also fails with error

[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py:943: RuntimeWarning: Exception occurred, parameter values are not reset and in an arbitrary, last used state. If this happens during normal operation, make sure you reset the values.
  warnings.warn("Exception occurred, parameter values are not reset and in an arbitrary, last"
Traceback (most recent call last):
  File "[a path]/zfit/Introduction2_DSCB.py", line 102, in <module>
    print(result.hesse(method='hesse_np', name='hesse'))
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/tensorflow/python/util/deprecation.py", line 549, in new_func
    return func(*args, **kwargs)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py", line 1010, in hesse
    error_dict = self._hesse(params=uncached_params, method=method, cl=cl)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py", line 1030, in _hesse
    covariance_dict = self.covariance(params, method, as_dict=True)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py", line 1189, in covariance
    self._covariance_dict[method] = self._covariance(method=method)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py", line 1211, in _covariance
    return method(result=self, params=params)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/zfit/minimizers/fitresult.py", line 177, in _covariance_np
    covariance = np.linalg.inv(hessian)
  File "<__array_function__ internals>", line 5, in inv
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/numpy/linalg/linalg.py", line 546, in inv
    ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
  File "[a path]/zfit/.venv/lib/python3.9/site-packages/numpy/linalg/linalg.py", line 88, in _raise_linalgerror_singular
    raise LinAlgError("Singular matrix")
numpy.linalg.LinAlgError: Singular matrix

I frequently see this error in other usages (parameters and functions (like DoubleCB)) of zfit as well. Please tell me what the errors (especially the latter) mean and what I can do. Thanks!

The following is the exact script.

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import zfit
from zfit import z
import sys

size_normal = 10000
mass_obs = zfit.Space('mass', (0, 1000))

mu_sig = zfit.Parameter('mu_sig', 400, 100, 600)
sigma_sig = zfit.Parameter('sigma_sig', 50, 1, 100)
alpha_sig = zfit.Parameter('alpha_sig', 200, 100, 400)#, floating=False)
n_sig = zfit.Parameter('n sig', 4, 0.1, 30, floating=False)
signal = zfit.pdf.CrystalBall(obs=mass_obs, mu=mu_sig, sigma=sigma_sig, alpha=alpha_sig, n=n_sig)

lam = zfit.Parameter('lambda', -0.01, -0.05, -0.001)
comb_bkg = zfit.pdf.Exponential(lam, obs=mass_obs)

part_reco_data = np.random.normal(loc=200, scale=150, size=700)
part_reco_data = zfit.Data.from_numpy(obs=mass_obs, array=part_reco_data)  # we don't need to do this but now we're sure it's inside the limits
part_reco = zfit.pdf.KDE1DimExact(obs=mass_obs, data=part_reco_data, bandwidth='adaptive_zfit')

sig_frac = zfit.Parameter('sig_frac', 0.3, 0, 1)
comb_bkg_frac = zfit.Parameter('comb_bkg_frac', 0.25, 0, 1)
model = zfit.pdf.SumPDF([signal, comb_bkg, part_reco], [sig_frac, comb_bkg_frac])

with zfit.param.set_values([mu_sig, sigma_sig, sig_frac, comb_bkg_frac, lam], [370, 34, 0.18, 0.15, -0.006]):
    data = model.sample(n=10000)

sig_yield = zfit.Parameter('sig_yield', 2000, 0, 10000, step_size=1)
sig_ext = signal.create_extended(sig_yield)

comb_bkg_yield = zfit.Parameter('comb_bkg_yield', 6000, 0, 10000, step_size=1)
comb_bkg_ext = comb_bkg.create_extended(comb_bkg_yield)

part_reco_yield = zfit.Parameter('part_reco_yield', 2000, 0, 10000, step_size=1)
part_reco.set_yield(part_reco_yield)
part_reco_ext = part_reco

model_ext_sum = zfit.pdf.SumPDF([sig_ext, comb_bkg_ext, part_reco_ext])

nll = zfit.loss.ExtendedUnbinnedNLL(model_ext_sum, data)

minimizer = zfit.minimize.Minuit(gradient=True)

values = z.unstack_x(data)
obs_right_tail = zfit.Space('mass', (700, 1000))
data_tail = zfit.Data.from_tensor(obs=obs_right_tail, tensor=values)
with comb_bkg.set_norm_range(obs_right_tail):
    nll_tail = zfit.loss.UnbinnedNLL(comb_bkg, data_tail)
    minimizer.minimize(nll_tail)
lam.floating = False

result = minimizer.minimize(nll)
#print(result.hesse(method='minuit_hesse', name='hesse'))
print(result.hesse(method='hesse_np', name='hesse'))
1

There are 1 best solutions below

0
On

The error arises as the Hessian matrix, or better its inverse cannot be calculated.

As the value of 200 seems quite high to me, the reason can be that it is simply not sensitive to this parameter. I would try to set it in a different range for example.

What I noticed is that the minimum is quite unstable for alpha, it's a parameter that has such a small influence.

Furthermore, there seems to be a numerical problem with hesse_np compared to the default version as the numbers diverge.

Here is the script, I've just let the param float (maybe try several times). If that doesn't work or you see the numbers diverging as well, it's maybe worth to open an issue.

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import zfit
from zfit import z
import sys

size_normal = 10000
mass_obs = zfit.Space('mass', (0, 1000))

mu_sig = zfit.Parameter('mu_sig', 400, 100, 600)
sigma_sig = zfit.Parameter('sigma_sig', 50, 1, 100)
alpha_sig = zfit.Parameter('alpha_sig', 2, 1, 400)#, floating=False)
n_sig = zfit.Parameter('n sig', 4, 0.1, 30, floating=False)
signal = zfit.pdf.CrystalBall(obs=mass_obs, mu=mu_sig, sigma=sigma_sig, alpha=alpha_sig, n=n_sig)

lam = zfit.Parameter('lambda', -0.01, -0.05, -0.001)
comb_bkg = zfit.pdf.Exponential(lam, obs=mass_obs)

part_reco_data = np.random.normal(loc=200, scale=150, size=700)
part_reco_data = zfit.Data.from_numpy(obs=mass_obs, array=part_reco_data)  # we don't need to do this but now we're sure it's inside the limits
part_reco = zfit.pdf.KDE1DimExact(obs=mass_obs, data=part_reco_data, bandwidth='adaptive_zfit')

sig_frac = zfit.Parameter('sig_frac', 0.3, 0, 1)
comb_bkg_frac = zfit.Parameter('comb_bkg_frac', 0.25, 0, 1)
model = zfit.pdf.SumPDF([signal, comb_bkg, part_reco], [sig_frac, comb_bkg_frac])

with zfit.param.set_values([mu_sig, sigma_sig, sig_frac, comb_bkg_frac, lam], [370, 34, 0.18, 0.15, -0.006]):
    data = model.sample(n=10000)

sig_yield = zfit.Parameter('sig_yield', 2000, 0, 10000, step_size=1)
sig_ext = signal.create_extended(sig_yield)

comb_bkg_yield = zfit.Parameter('comb_bkg_yield', 6000, 0, 10000, step_size=1)
comb_bkg_ext = comb_bkg.create_extended(comb_bkg_yield)

part_reco_yield = zfit.Parameter('part_reco_yield', 2000, 0, 10000, step_size=1)
part_reco.set_yield(part_reco_yield)
part_reco_ext = part_reco

model_ext_sum = zfit.pdf.SumPDF([sig_ext, comb_bkg_ext, part_reco_ext])

nll = zfit.loss.ExtendedUnbinnedNLL(model_ext_sum, data)

minimizer = zfit.minimize.Minuit(gradient=True, verbosity=7)

values = z.unstack_x(data)
obs_right_tail = zfit.Space('mass', (700, 1000))
data_tail = zfit.Data.from_tensor(obs=obs_right_tail, tensor=values)
with comb_bkg.set_norm_range(obs_right_tail):
    nll_tail = zfit.loss.UnbinnedNLL(comb_bkg, data_tail)
    minimizer.minimize(nll_tail)
lam.floating = False

result = minimizer.minimize(nll)
#print(result.hesse(method='minuit_hesse', name='hesse'))
print(result)
result.hesse(name='hesse')
print(result)
result.hesse(method='hesse_np', name='hesse_np')
print(result)