pairs = torch.cartesian_prod(torch.arange(K), torch.arange(K)) # all 1024 pairs
patterns = torch.tensor([[True, False], [False, True], [True, True]])
@torch.no_grad()
def exact_bound(model): # the bound averaged over the true table, all steps and patterns
total = 0.0
for t in range(1, T + 1):
weight = (alpha_bar[t - 1] - alpha_bar[t]) / (1 - alpha_bar[t])
for masked in patterns:
masked = masked.expand(len(pairs), 2)
z = torch.where(masked, MASK, pairs)
logp = torch.log_softmax(model(z, torch.full((len(pairs),), t)), -1)
logp = logp.gather(-1, pairs[..., None])[..., 0]
n_masked = masked[0].sum()
prob = (1 - alpha_bar[t]) ** n_masked * alpha_bar[t] ** (2 - n_masked)
total += prob * weight * (table.flatten() * (-logp * masked).sum(1)).sum()
return total
torch.manual_seed(1)
model = MaskedMLP()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for step in range(6000):
if step == 4000:
optimizer.param_groups[0]['lr'] = 2e-4
x0 = data[torch.randint(0, len(data), (512,))]
t = torch.randint(1, T + 1, (512,))
loss = masked_loss(model, x0, t).mean()
optimizer.zero_grad(), loss.backward(), optimizer.step()
if step % 2000 == 0:
print(f'step {step:>4}: exact bound {exact_bound(model):.3f} nats')
print(f'final exact bound {exact_bound(model):.3f} nats; entropy {entropy:.3f} nats')