def inference_minibatch(self, kern, X, Z, likelihood, Y, Zp):
num_data, output_dim = Y.shape<EOL>beta = <NUM_LIT:1.>/np.fmax(likelihood.variance, <NUM_LIT>)<EOL>het_noise = beta.size > <NUM_LIT:1><EOL>if self.Y_speedup and not het_noise:<EOL><INDENT>YYT_factor = self.get_YYTfactor(Y)<EOL><DEDENT>else:<EOL><INDENT>YYT_factor = Y<EOL><DEDENT>n_start = self.batch_pos<EOL>batchsize = num_data if self.batchsize is None else self.batchsize<EOL>n_end = min(batchsize+n_start, num_data)<EOL>if n_end == num_data:<EOL><INDENT>isEnd = True<EOL>self.batch_pos = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>isEnd = False<EOL>self.batch_pos = n_end<EOL><DEDENT>if batchsize == num_data:<EOL><INDENT>Y_slice = YYT_factor<EOL>X_slice = X<EOL><DEDENT>else:<EOL><INDENT>Y_slice = YYT_factor[n_start:n_end]<EOL>X_slice = X[n_start:n_end]<EOL><DEDENT>psi0 = kern._Kdiag(X_slice) <EOL>psi1 = kern.K(X_slice, Z) <EOL>betapsi1 = np.einsum('<STR_LIT>', beta, psi1)<EOL>X_slice = X_slice.values<EOL>Z = Z.values<EOL>Zp = Zp.gamma.values<EOL>indX = np.int_(X_slice[:, -<NUM_LIT:1>])<EOL>indZ = np.int_(Z[:, -<NUM_LIT:1>]) - Zp.shape[<NUM_LIT:0>]<EOL>betaY = beta*Y_slice<EOL>dL_dpsi2R = self.midRes['<STR_LIT>']<EOL>v = self.midRes['<STR_LIT:v>']<EOL>dL_dpsi0 = -<NUM_LIT>*output_dim*(beta * Zp[indX, :]) <EOL>dL_dpsi1 = np.dot(betaY, v.T)<EOL>dL_dEZp  = psi1*dL_dpsi1<EOL>dL_dpsi1 = Zp[np.ix_(indX, indZ)]*dL_dpsi1<EOL>dL_dgamma = np.zeros(Zp.shape)<EOL>for d in np.unique(indX):<EOL><INDENT>indd = indX == d<EOL>betapsi1d = betapsi1[indd, :]<EOL>psi1d = psi1[indd, :]<EOL>Zpd = Zp[d, :]<EOL>Zp2 = Zpd[:, None]*Zpd[None, :] - np.diag(np.power(Zpd, <NUM_LIT:2>)) + np.diag(Zpd)<EOL>dL_dpsi1[indd, :] += np.dot(betapsi1d, Zp2[np.ix_(indZ, indZ)] * dL_dpsi2R)*<NUM_LIT><EOL>dL_EZp2 = dL_dpsi2R * (np.dot(psi1d.T, psi1d) * beta)*<NUM_LIT>  <EOL>EZ = Zp[d, indZ]<EOL>for q in range(Zp.shape[<NUM_LIT:1>]):<EOL><INDENT>EZt = EZ.copy()<EOL>indq = indZ == q<EOL>EZt[indq] = <NUM_LIT><EOL>dL_dgamma[d, q] = np.sum(dL_dEZp[np.ix_(indd, indq)]) + np.sum(dL_EZp2[:, indq]*EZt[:, None]) -<NUM_LIT>*beta*(np.sum(psi0[indd, q]))<EOL><DEDENT><DEDENT>if isEnd:<EOL><INDENT>dL_dthetaL = self.midRes['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>dL_dthetaL = <NUM_LIT:0.><EOL><DEDENT>grad_dict = {'<STR_LIT>': dL_dpsi0,<EOL>'<STR_LIT>': dL_dpsi1,<EOL>'<STR_LIT>': dL_dthetaL,<EOL>'<STR_LIT>': dL_dgamma}<EOL>return isEnd, (n_start, n_end), grad_dict<EOL>
The second phase of inference: Computing the derivatives over a minibatch of Y
Compute: dL_dpsi0, dL_dpsi1, dL_dpsi2, dL_dthetaL
return a flag showing whether it reached the end of Y (isEnd)