def computeGradientLogZ(self): if 'grad_logZ' in self.__dict__: return self.computeLogZ() N = len(self.theta) L = self.traj.L assert not np.isnan(self.theta).any() log_grad_Zs0_dirs = self.traj.features_np[0] log_grad_Zs0_norms = dot(self.traj.features_np[0], self.theta) self.log_grad_Zs_norms = [log_grad_Zs0_norms] self.log_grad_Zs_dirs = [log_grad_Zs0_dirs] # Recursion: for l in range(1, L): N_l = self.traj.num_choices[l] l_vec_dirs = np.zeros((N_l, N)) l_vec_norms = MINUS_INF * np.ones(N_l) conns_back = self.traj.connections_backward[l] w = dot(self.traj.features_np[l], self.theta) assert not np.isnan(w).any() for i in range(N_l): vs0_dir = np.array([self.traj.features_np[l][i]]) vs0_norm = np.array([self.logZs[l][i]]) if i not in conns_back: (n, d) = lse_vec_npy(vs0_dir, vs0_norm) l_vec_dirs[i] = d l_vec_norms[i] = n else: vs_dirs = np.vstack((vs0_dir, \ self.log_grad_Zs_dirs[l-1][conns_back[i]])) vs_norms = np.hstack((vs0_norm, \ w[i] + \ self.log_grad_Zs_norms[l-1][conns_back[i]])) (n, d) = lse_vec_npy(vs_dirs, vs_norms) l_vec_dirs[i] = d l_vec_norms[i] = n self.log_grad_Zs_norms.append(l_vec_norms) self.log_grad_Zs_dirs.append(l_vec_dirs) assert(len(self.log_grad_Zs_norms) == L) self.log_grad_Z = lse_vec_npy(self.log_grad_Zs_dirs[L-1], self.log_grad_Zs_norms[L-1]) (l_norm, v) = self.log_grad_Z if l_norm < 100 and l_norm > -100: self.grad_Z = exp(l_norm) * v self.grad_logZ = exp(l_norm - self.logZ) * v
def computeHessianLogZ(self): """ Hessian of log(Z). """ if 'hess_logZ' in self.__dict__: return inf = float('inf') self.computeLogZ() self.computeGradientLogZ() N = len(self.theta) L = self.traj.L # The initial values: N_0 = self.traj.num_choices[0] log_hess_Zs0_norms = np.dot(self.traj.features_np[0], self.theta) log_hess_Zs0_dirs = np.zeros((N_0, N, N)) for i in range(N_0): log_hess_Zs0_dirs[i] = np.outer(self.traj.features_np[0][i], \ self.traj.features_np[0][i]) self.log_hess_Zs_norms = [log_hess_Zs0_norms] self.log_hess_Zs_dirs = [log_hess_Zs0_dirs] # Recursion: for l in range(1, L): N_l = self.traj.num_choices[l] l_vec_norm = -inf * np.ones(N_l) l_vec_dir = np.zeros((N_l, N, N)) conns_back = self.traj.connections_backward[l] w = dot(self.traj.features_np[l], self.theta) for i in range(N_l): T_i_l = self.traj.features_np[l][i] vs0_norm = np.array([self.logZs[l][i]]) vs0_dir = np.array([outer(T_i_l, T_i_l)]) if i in conns_back: us_norm = self.log_grad_Zs_norms[l-1][conns_back[i]] us_dir = self.log_grad_Zs_dirs[l-1][conns_back[i]] (l_norm, u_g_vec) = lse_vec_npy(us_dir, us_norm) vs_norm = np.hstack((vs0_norm, \ w[i] + \ self.log_hess_Zs_norms[l-1][conns_back[i]], \ w[i] + l_norm, \ w[i] + l_norm)) M = np.array([outer(u_g_vec, T_i_l)]) Mt = np.array([outer(T_i_l, u_g_vec)]) vs_dir = np.vstack((vs0_dir, \ self.log_hess_Zs_dirs[l-1][conns_back[i]], \ M, Mt)) (li_vec_norm, li_vec_dir) = lse_vec_npy(vs_dir, vs_norm) l_vec_norm[i] = li_vec_norm l_vec_dir[i] = li_vec_dir else: l_vec_norm[i] = vs0_norm l_vec_dir[i] = vs0_dir self.log_hess_Zs_dirs.append(l_vec_dir) self.log_hess_Zs_norms.append(l_vec_norm) assert(len(self.log_hess_Zs_dirs) == L) self.log_hess_Z = lse_vec_npy(self.log_hess_Zs_dirs[-1], \ self.log_hess_Zs_norms[-1]) (l_norm, h) = self.log_hess_Z if l_norm < 100 and l_norm > -100: self.hess_Z = exp(l_norm) * h (l_norm_g, g) = self.log_grad_Z self.hess_logZ = np.zeros_like(h) if l_norm - self.logZ > -60: self.hess_logZ += exp(l_norm - self.logZ) * h if l_norm_g - self.logZ > -30: self.hess_logZ -= exp(2 * l_norm_g - 2 * self.logZ) * outer(g, g)