How to access attributes in step method class from outside?

Dear all,

I have written my own custom step method and want to access some attributes from my Step method class outside of the class. How do I do that?
To be specific in an example below, I want to access the variables accrate and count in the class MyStepMethod in order to calculate the acceptance rate outside of the class.

import pymc3 as pm
import numpy as np
import matplotlib.pyplot as plt
from pymc3.step_methods.arraystep import ArrayStep
from pymc3 import Continuous

class NormalDist(Continuous):

def __init__(self, mean, *args, **kwargs):
    super(NormalDist, self).__init__(*args, **kwargs)
    self.mean = mean

def logp(self, I):
    a=np.log(np.exp(-(I - self.mean) ** 2 / 2) / np.sqrt(2 * np.pi))
    return a

class MyStepMethod(ArrayStep):

def __init__(self, vars, model=None):
    self.vars = vars
    model = pm.modelcontext(model)
    super(MyStepMethod, self).__init__(vars, [model.fastlogp])
    self.accrate = 0
    self.count = 0

def astep(self, q0, logp):

    self.count += 1

    q = q0.copy()
    q[0] = np.random.normal(q0[0], 1) # symmetric proposal

    logalt = logp(q0)
    logneu = logp(q)
    accept = logneu - logalt

    if (accept > 0) or (np.random.uniform(low=0, high=1) < np.exp(accept)):
        self.accrate += 1

        return q

    else:
        return q0

with pm.Model() as model:

mean = 0

I = NormalDist("I", mean=mean)
updI = MyStepMethod(vars=[I])
trace = pm.sample(10000, [updI], start={'I':0.5})

print(MyStepMethod.accrate/MyStepMethod.count) # Problem!
pm.traceplot(trace)
plt.show()

I could print the acceptance rate every time the function astep is called, though it really slows down the computation when having a large numbers of samples. Thanks in advance for any help!

You should probability save the properties you would like to access in stats of the step_method, eg see:

or a more complex example:

1 Like

Very helpful! Thank you!

I noticed that when you want to save your trace in the form of

db = pm.backends.Text(‘MyTrace’)
trace = pm.sample(10000, [updI], start={‘I’:0.5}, trace=db)

the trace.stat_names command returns an empty set.
Is there an easy way around it to save the trace values but still keep the stats values?

EDIT: It works out if you save your trace as pandas dataframe and then save it as csv file, then you can still access the stats attributes. i.e.
df = pm.backends.tracetab.trace_to_dataframe(trace)
df.to_csv(“MyTest.csv”)

1 Like