Drawing and adding samples of random size

Hi,

Apologizes for coming here with a basic question like this, but all the attempts has failed.

I am trying to draw a number of events using Poisson distribution:
N = pyro.sample(“N”, dist.Poisson(torch.as_tensor([10.]))
and then draw N times from a normal distribution and add the numbers.
At the end I want to sample from a model using Predictive with parallel=True.

Can this be achieved in a simple way?

Thanks!

I’m trying this as well and got this far:

def model():
    N = pyro.sample('N', dist.Poisson(10))
    locs = torch.zeros((N.int().item()))
    scales = torch.ones((N.int().item()))
    normals = pyro.sample('normals', dist.Normal(locs, scales))
    return(normals)
results = model()
print(results)
print(torch.sum(results))

Just so I understand correctly, are you trying to predict the sum given a fixed “N” as an input?

Hi,

Yes, this is just to get the distribution for sum of normals based on fixed N.
So I want to include torch.sum(results) inside a model() and make it all in a vectorised way, so that could draw k samples from resulting sum.

Here is a complete example:

def model():
    p = pyro.sample("p", dist.Poisson(torch.as_tensor([10.])))
    x = pyro.sample("x", dist.Normal(40*torch.ones(p.int().item()),10.))
    y = pyro.sample("y", dist.Normal(35*torch.ones(p.int().item()),20.))
    ev = torch.sum(x>y)
    if ev>0:
        reward = pyro.sample("reward", dist.Normal(torch.as_tensor([100.]),torch.as_tensor([5.])).expand([ev]))
        s = torch.sum(reward)
    else:
        s = 0
    return s

Executing model() works but Predictive(model, {}, num_samples=1000)() fails.

I’ve been working with variables of changing dimension in Pyro as well, so far I haven’t had much luck changing the dimension on-the-fly. Here’s a work-around that might fit in your use case:

def model():
    N = pyro.sample('N', dist.Poisson(10))
    M = torch.zeros(30 - N.int().item())
    locs = torch.zeros(30)
    scales = torch.ones(30)
    normals = pyro.sample('normals', dist.Normal(locs, scales))
    normals[N.int().item():] = M
    sum_normals = pyro.deterministic('sum', torch.sum(normals))

pyro.infer.Predictive(model, {}, num_samples=1000)()['sum']

The idea is to set your maximum theoretical N (30 seems to work fine for Poisson(10)) and send the whole loc and scale vectors (size = 30) through the Normal sampling operation. You then zero out M = 30 - N of your values, and use the Deterministic function to produce the sum of the normals.

The code worked for me - not the cleanest solution, but it might work for you.

1 Like

Yes, that is a good workaround!
Can anyone advice if the same can be obtained with a more elegant approach? Problem seems to be pretty simple in theory…

This is likely an issue with Predictive – see this post and this associated issue. In particular, when I attempt to use Predictive, I get an error like

/opt/anaconda3/lib/python3.7/site-packages/pyro/infer/predictive.py in _predictive_sequential(model, posterior_samples, model_args, model_kwargs, num_samples, return_site_shapes, return_trace)
     46     else:
     47         return {site: torch.stack([s[site] for s in collected]).reshape(shape)
---> 48                 for site, shape in return_site_shapes.items()}

which makes sense because the shape is itself an rv.

If your only goal is simulation, a model like

def model(): 
    N = pyro.sample("N", dist.Poisson(10.)) 
    noise = pyro.sample("noise", dist.Normal(0, 1).expand((int(N),))) 
    randsum = pyro.deterministic("rand_sum", noise.sum()) 
    return randsum

should be fine. As far as sampling from the prior predictive, since this is just calling model() and we can do this with

samples = torch.stack(list(map(lambda x: model(), range(100))))

then replacing map with something like

import multiprocessing
pool = multiprocessing.Pool(None)
...
samples = torch.stack(list(pool.map(lambda x: model(), range(100))))

would be okay.