I am just beginning to learn probabilistic programming and I am trying to implement a Cognitive Diagnostic Model named DINA. My implementation is inspired by the dina package in R language: dina R. link to paper
I am able to successfully implement the code in PyMC3 (code below). But my almost identical code in Pyro keeps failing. Please advice what may I be missing.
My data contains ‘i’ students responding to ‘j’ questions in an exam. Each jth question is annotated with ‘k’ possible skills required to answer the question. Given each correct answer, we need to estimate which of the ‘k’ skills does the student’s posses. Also, we need to estimate item’s guess and slip parameter based on how difficult it is to answer a question.
- X: (i,j) contains 0 or 1 given student got the answer right or wrong
#Dummy X matrix
X = np.random.randint(0,2,size = (i,j))
- Q: (j,k) contains 0 or 1 given whether jth item requires kth skill to get the answer right.
#Dummy Q matrix
Q = np.random.randint(0,2,size = (j,k))
- Alpha: (i,k) should contain 0 or 1 given whether the ith student possess kth skill based on X and Q matrix.
- Guess: (j,) question’s guess parameter
- Slip: (j,) question’s slip parameter
MCMC - NUTS
PyMC3 code (working):
alpha_prior = np.ones((i,k))/k alpha = pm.Bernoulli("alpha", p=alpha_prior, shape = (i,k)) guess = pm.Beta("guess",alpha = 1.0, beta = 1, shape = j) slip = pm.Beta("slip",alpha = 1.0, beta = 1, shape = j) # eta respresents whether student possess the skills required to answer the question t1 = T.dot(alpha, Q.T) skills_and = T.sum(Q, axis = 1) eta = T.cast(T.eq(t1, skills_and), dtype = 'int32') # prob_of_X is calculated based on guess and slip parameter. The idea is that even though student possess all the skills, they can get the answer wrong (slip) and vice-verse for guess parameter. a = T.pow(guess, (1-eta)) b = T.pow((1-slip), eta) prob_of_X = T.mul(a,b) generated_x = pm.Bernoulli("generated_x", prob_of_X, shape = (i,j), observed = X) dina_trace = pm.sample(100, tune=10)
Only 100 samples in chain.
Sequential sampling (2 chains in 1 job)
NUTS: [slip, guess]
100%|██████████| 110/110 [00:26<00:00, 4.17it/s]
100%|██████████| 110/110 [00:25<00:00, 4.27it/s]
Pyro code (giving error):
alpha_prior = torch.ones(k)/k alpha = pyro.sample("alpha", dist.Bernoulli(probs = alpha_prior).expand([i,k])) guess = pyro.sample("guess", dist.Beta(1,1).expand([j])) slip = pyro.sample("slip", dist.Beta(1,1).expand([j])) t1 = torch.matmul(alpha, torch.transpose(self.Q, 0, 1)) skills_and = torch.sum(Q, dim = 1) eta = torch.eq(t1, skills_and).long() a = torch.pow(guess, (1-eta)) b = torch.pow((1-slip), eta) prob_of_X = torch.mul(a, b) generated_X = pyro.sample("generated_X", dist.Bernoulli(prob_of_X).expand([i,j]), obs = self.X)
#dina.model is the function under which above code is written
16 slip = pyro.sample(“slip”, dist.Beta(1,1).expand([j]))
—> 18 t1 = torch.matmul(alpha, torch.transpose(self.Q, 0, 1))
19 skills_and = torch.sum(Q, dim = 1)
RuntimeError: mat1 and mat2 shapes cannot be multiplied (1x2 and 4x7)
alpha dist 10 4 |
value 2 |
guess dist 7 |
value 7 |
slip dist 7 |
value 7 |