I want to add some noise to the variable \alpha like this:
\alpha=\alpha*exp(\varepsilon)
where \varepsilon~Normal(0,\sigma) is a separate, independent noise term (non-trainable)
and \sigma~HalfNormal(sigma=1) (trainable).
The distribution of random variables in pymc is trainable as default,
but I want \varepsilon to always be a normal distribution with mu=0 and sigma=\sigma when sampling.
How can i do this?
Any help is really appreciated, thanks!
You need to implement a custom step sampler that always updates the value of the variable with a new draw from the prior, regardless of the model logp.
import pymc3 as pm
import arviz as az
import numpy as np
import matplotlib.pyplot as plt
from pymc3.step_methods.arraystep import BlockedStep
class UpdateIndependentNoiseTermStep(BlockedStep):
def __init__(self, epsilon, sigma, model=None):
pm.modelcontext(model)
self.vars = [epsilon]
self.epsilon = epsilon
self.sigma = sigma
pass
def step(self, point: dict):
sigma = self.sigma
if not isinstance(1.0*self.sigma, float):
sigma = np.exp(point[self.sigma.transformed.name])
pass
point[self.epsilon.name] = pm.Normal.dist(mu=0, sigma=sigma).random()
return point
pass
import pymc3 as pm
import arviz as az
import numpy as np
import matplotlib.pyplot as plt
from pymc3.step_methods.arraystep import BlockedStep
from custom import UpdateIndependentNoiseTermStep
data = 100 * np.exp(1) ** pm.Normal.dist(mu=0, sigma=0.2).random(size=2000)
plt.plot(data)