# Custom step method insists not free random variable

**URL:** <https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093>\
**Category:** v5\
**Created:** [March 26, 2024, 2:44pm UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093 "2024-03-26T14:44:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![brandonhorsley](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/brandonhorsley/32/6693_2.png) [@brandonhorsley](https://discourse.pymc.io/u/brandonhorsley)\
**Post date:** [March 26, 2024, 2:44pm UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/1 "2024-03-26T14:44:07Z")

</div>

Hi all,

I’ve got some code running where I am hoping to improve the sampling by doing a custom sampling method but have run into a bit of a wall with it.

The relevant block of code is:

```auto
with pm.Model() as model_multinomial1:
        #M=2

        # Define priors
        #sd=0.05
        eta_sep=pm.TruncatedNormal("eta_sep",mu=0,sigma=1,lower=0.0,upper=1.0,shape=2) #array of
        eta=pm.Deterministic("eta",[0.5,0.5]+eta_sep*0.05)
        theta=pm.Deterministic("theta",2*pt.arccos(pt.sqrt(eta)))
        #priors for conciseness

        #sd=a_dev
        a_sep=pm.TruncatedNormal("a_sep", mu=0, sigma=1,lower=-np.pi,upper=np.pi, shape=2) #array of priors for conciseness
        a=pm.Deterministic("a",[0,0]+a_sep*a_dev)

        sd=0.7
        b_sep=pm.Normal("b_sep", mu=0, sigma=1,shape=2) #array of priors for conciseness
        b=pm.Deterministic("b",[0.7,0.7]+b_sep*sd)

        #Have decided to open the Volt variable to allow additional freedom
        Volt=pm.Normal("Volt",mu=V_2_dist,sigma=0.1)
        #Volt=pm.Deterministic("Volt",pt.as_tensor(V_2_dist))
        
        phi=pm.Deterministic("phi",a[:,None]+b[:,None]*pm.math.sqr(Volt))
        
        #phi1 vanishes from p expression under simplification
        p1=pm.Deterministic("p1",-pm.math.sin(theta[0])*pm.math.sin(theta[1])*pm.math.cos(phi[0])/2 + pm.math.cos(theta[0])*pm.math.cos(theta[1])/2 + 1/2)
        p2=pm.Deterministic("p2",-pm.math.cos(theta[0] - theta[1])/4 - pm.math.cos(theta[0] + theta[1])/4 - pm.math.cos(-phi[0] + theta[0] + theta[1])/8 + pm.math.cos(phi[0] - theta[0] + theta[1])/8 + pm.math.cos(phi[0] + theta[0] - theta[1])/8 - pm.math.cos(phi[0] + theta[0] + theta[1])/8 + 1/2)

        P=pm.Deterministic("P",pm.math.stack([p1,p2],axis=-1))
        likelihood=pm.Multinomial("likelihood",n=1000,p=P[0],shape=(N,2),observed=data_2)

    print(model_multinomial1.free_RVs)
    
    with model_multinomial1:

        #stepmethod=[pm.NUTS([a_sep]),pm.NUTS([a_sep,b_sep]),pm.NUTS([a_sep,b_sep,eta_sep])]

        trace_multinomial_2_HMC = pm.sample(draws=int(1e3), chains=4, cores=cpucount,step=pm.Metropolis(vars=["a_sep"]), return_inferencedata=True)

```

But when I try to run this in my clean anaconda environment, the printing free random variables line gives me what I expect but then throws the following error:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/pymc3/original/2X/e/ef74cd19bebd5658c2c0f35e361cb96c349ed6c4.png)

If I don’t give any arguments (so no vars=…) in the custom step method then it runs fine but then that defeats the purpose of me trying to do some custom sampling! Could this be a genuine bug or am I misusing the step method argument of pm.sample()?

---

<div class="post-metadata">

**Author:** ![jessegrabowski](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/jessegrabowski/32/5010_2.png) [@jessegrabowski](https://discourse.pymc.io/u/jessegrabowski)\
**Post date:** [March 26, 2024, 2:51pm UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/2 "2024-03-26T14:51:22Z")

</div>

I believe you’re supposed to pass the variable itself (`a_sep`), rather than the string name (`"a_sep"`)

---

<div class="post-metadata">

**Author:** ![brandonhorsley](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/brandonhorsley/32/6693_2.png) [@brandonhorsley](https://discourse.pymc.io/u/brandonhorsley)\
**Post date:** [March 26, 2024, 3:13pm UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/3 "2024-03-26T15:13:26Z")

</div>

That works! It’s strange because I did that originally and got the error so I tried putting it as a string but in retrying it just now it works as intended 🤦‍♂️ I’m not gonna look a gift horse in the mouth, thanks anyway 😂

---

<div class="post-metadata">

**Author:** ![brandonhorsley](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/brandonhorsley/32/6693_2.png) [@brandonhorsley](https://discourse.pymc.io/u/brandonhorsley)\
**Post date:** [March 28, 2024, 10:43am UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/4 "2024-03-28T10:43:06Z")

</div>

@jessegrabowski Turns out that I think I have isolated the underlying problem that explains the experienced fluke. So in making a minimal working example i changed my code from 2 models with custom stepmethod to just one and when there is just one then custom sampling steps work as expected, but when i tried again with my code that had two models in it then the error was still there (maybe considered a bug but is perhaps moreso just a case of poor pymc practice)

So if I have two models like so based off the GLM example in the docs:

```auto
with Model() as model1:
        # Define priors
        sigma = HalfCauchy("sigma", beta=10)
        intercept = Normal("Intercept", 0, sigma=20)
        slope = Normal("slope", 0, sigma=20)

        # Define likelihood
        likelihood = Normal("y", mu=intercept + slope * x, sigma=sigma, observed=y)

with Model() as model2:
        # Define priors
        sigma = Normal("sigma", 0,sigma=1)
        intercept = Normal("Intercept", 0, sigma=20)
        slope = Normal("slope", 0, sigma=20)

        # Define likelihood
        likelihood = Normal("y", mu=intercept + slope * x, sigma=sigma, observed=y)

with model1:
        stepmethod=[pm.NUTS([sigma]),pm.NUTS([sigma,slope, intercept])]

        samples1=sample(1000,step=stepmethod)

with model2:
        stepmethod=[pm.NUTS([sigma]),pm.NUTS([sigma,slope]), pm.NUTS([sigma,slope, intercept])]

        samples2=sample(1000,step=stepmethod)

```

causes the error, but in changing say model 1 variable names so all cases of {mu,slope,intercept}-\>{mu1,slope1,intercept1} then resolves the error meaning that sharing variable names between models screws up custom sampling methods.

---

<div class="post-metadata">

**Author:** ![jessegrabowski](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/jessegrabowski/32/5010_2.png) [@jessegrabowski](https://discourse.pymc.io/u/jessegrabowski)\
**Post date:** [March 28, 2024, 10:47am UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/5 "2024-03-28T10:47:47Z")

</div>

It’s not really anything to do with the custom step perse; you’re overwriting the python variables when you re-declare the models, so the name “sigma” is pointing to the wrong thing. You could instead access the variables by using the model itself like a dictionary, for example `mode1['sigma']` will return the correct RV named “sigma” associated with `model1`

---

<div class="post-metadata">

**Author:** ![brandonhorsley](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/brandonhorsley/32/6693_2.png) [@brandonhorsley](https://discourse.pymc.io/u/brandonhorsley)\
**Post date:** [March 28, 2024, 10:55am UTC](https://discourse.pymc.io/t/custom-step-method-insists-not-free-random-variable/14093/6 "2024-03-28T10:55:48Z")

</div>

Ahh that way of accessing will be a massive help then, save me having to recomb over some of the larger models and rewrite 😅
