Hi all, I’ve written a model that runs beautifully with NUTS in numpyro, but I’m trying to write a guide to get it running using SVI in pyro and I’ve been struggling. The model estimates scores based on football match results by estimating the attacking and defensive abilities of each team:
def model(home_id, away_id, score1_obs=None, score2_obs=None):
# priors
mu_att = pyro.sample("mu_att", dist.Normal(0.0, 1.0))
sd_att = pyro.sample("sd_att", dist.StudentT(3.0, 0.0, 2.5))
mu_def = pyro.sample("mu_def", dist.Normal(0.0, 1.0))
sd_def = pyro.sample("sd_def", dist.StudentT(3.0, 0.0, 2.5))
home = pyro.sample("home", dist.Normal(0.0, 1.0)) # home advantage
nt = len(np.unique(home_id))
# team-specific model parameters
with pyro.plate("plate_teams", nt):
attack = pyro.sample("attack", dist.Normal(mu_att, sd_att))
defend = pyro.sample("defend", dist.Normal(mu_def, sd_def))
# likelihood
theta1 = torch.exp(home + attack[home_id] - defend[away_id])
theta2 = torch.exp(attack[away_id] - defend[home_id])
with pyro.plate("data", len(home_id)):
pyro.sample("s1", dist.Poisson(theta1), obs=score1_obs)
pyro.sample("s2", dist.Poisson(theta2), obs=score2_obs)
I’ve attempted to write the guide as:
def guide(home_id, away_id, score1_obs=None, score2_obs=None):
# priors
mu_locs = pyro.param("mu_loc", torch.tensor(0.0).expand(3))
mu_scales = pyro.param(
"mu_scale", torch.tensor(0.1).expand(3), constraint=constraints.positive
)
sd_dfs = pyro.param(
"sd_df", torch.tensor(2.0).expand(3), constraint=constraints.positive
)
sd_scales = pyro.param(
"sd_scale", torch.tensor(0.1).expand(3), constraint=constraints.positive
)
pyro.sample("mu_att", dist.Normal(mu_locs[0], mu_scales[0]))
pyro.sample("mu_def", dist.Normal(mu_locs[1], mu_scales[1]))
pyro.sample("sd_att", dist.StudentT(sd_dfs[0], torch.tensor(0.0), sd_scales[0]))
pyro.sample("sd_def", dist.StudentT(sd_dfs[1], torch.tensor(0.0), sd_scales[1]))
pyro.sample("home", dist.Normal(mu_locs[2], mu_scales[2])) # home advantage
nt = len(np.unique(home_id))
mu_team_locs = pyro.param("mu_team_loc", torch.tensor(0.0).expand(2))
mu_team_scales = pyro.param(
"mu_team_scale", torch.tensor(0.1).expand(2), constraint=constraints.positive
)
# team-specific model parameters
with pyro.plate("plate_teams", nt):
pyro.sample("attack", dist.Normal(mu_team_locs[0], mu_team_scales[0]))
pyro.sample("defend", dist.Normal(mu_team_locs[1], mu_team_scales[1]))
following the rule to write a pyro.param
for everything that isn’t obs
. But I get the error
ValueError: The parameter scale has invalid values
Trace Shapes:
Param Sites:
Sample Sites:
mu_att dist |
value |
sd_att dist |
value |
mu_def dist |
value |
sd_def dist |
value |
home dist |
value |
plate_teams dist |
value 20 |
I’ve actually tried many different structures sizes for the (based on nt
= 20) attack and defend parameters in the plate, but with no luck. Any help with this guide is greatly appreciated, especially with the HalfStudentT
distribution (do I need a pyro.param()
on the scale as well?). If there is an appropriate AutoGuide, that is also great. Cheers
Full reproducible code here.