def calcInvFisher(sigma, invSigma=None, factorSigma=None): """ Efficiently compute the exact inverse of the FIM of a Gaussian. Returns a list of the diagonal blocks. """ if invSigma == None: invSigma = inv(sigma) if factorSigma == None: factorSigma = cholesky(sigma) dim = sigma.shape[0] invF = [mat(1 / (invSigma[-1, -1] + factorSigma[-1, -1] ** -2))] invD = 1 / invSigma[-1, -1] for k in reversed(list(range(dim - 1))): v = invSigma[k + 1:, k] w = invSigma[k, k] wr = w + factorSigma[k, k] ** -2 u = dot(invD, v) s = dot(v, u) q = 1 / (w - s) qr = 1 / (wr - s) t = -(1 + q * s) / w tr = -(1 + qr * s) / wr invF.append(blockCombine([[qr, tr * u], [mat(tr * u).T, invD + qr * outer(u, u)]])) invD = blockCombine([[q , t * u], [mat(t * u).T, invD + q * outer(u, u)]]) invF.append(sigma) invF.reverse() return invF
def calcInvFisher(sigma, invSigma=None, factorSigma=None): """ Efficiently compute the exact inverse of the FIM of a Gaussian. Returns a list of the diagonal blocks. """ if invSigma == None: invSigma = inv(sigma) if factorSigma == None: factorSigma = cholesky(sigma) dim = sigma.shape[0] invF = [mat(1 / (invSigma[-1, -1] + factorSigma[-1, -1]**-2))] invD = 1 / invSigma[-1, -1] for k in reversed(list(range(dim - 1))): v = invSigma[k + 1:, k] w = invSigma[k, k] wr = w + factorSigma[k, k]**-2 u = dot(invD, v) s = dot(v, u) q = 1 / (w - s) qr = 1 / (wr - s) t = -(1 + q * s) / w tr = -(1 + qr * s) / wr invF.append( blockCombine([[qr, tr * u], [mat(tr * u).T, invD + qr * outer(u, u)]])) invD = blockCombine([[q, t * u], [mat(t * u).T, invD + q * outer(u, u)]]) invF.append(sigma) invF.reverse() return invF
def _calcBatchUpdate(self, fitnesses): samples = self.allSamples[-self.batchSize:] d = self.numParameters invA = inv(self.factorSigma) invSigma = inv(self.sigma) diagInvA = diag(diag(invA)) # efficient computation of V, which corresponds to inv(Fisher)*logDerivs V = zeros((self.numDistrParams, self.batchSize)) # u is used to compute the uniform baseline u = zeros(self.numDistrParams) for i in range(self.batchSize): s = dot(invA.T, (samples[i] - self.x)) R = outer(s, dot(invA, s)) - diagInvA flatR = triu2flat(R) u[:d] += fitnesses[i] * (samples[i] - self.x) u[d:] += fitnesses[i] * flatR V[:d, i] += samples[i] - self.x V[d:, i] += flatR j = self.numDistrParams - 1 D = 1 / invSigma[-1, -1] # G corresponds to the blocks of the inv(Fisher) G = 1 / (invSigma[-1, -1] + invA[-1, -1]**2) u[j] = dot(G, u[j]) V[j, :] = dot(G, V[j, :]) j -= 1 for k in reversed(range(d - 1)): p = invSigma[k + 1:, k] w = invSigma[k, k] wg = w + invA[k, k]**2 q = dot(D, p) c = dot(p, q) r = 1 / (w - c) rg = 1 / (wg - c) t = -(1 + r * c) / w tg = -(1 + rg * c) / wg G = blockCombine([[rg, tg * q], [mat(tg * q).T, D + rg * outer(q, q)]]) D = blockCombine([[r, t * q], [mat(t * q).T, D + r * outer(q, q)]]) u[j - (d - k - 1):j + 1] = dot(G, u[j - (d - k - 1):j + 1]) V[j - (d - k - 1):j + 1, :] = dot(G, V[j - (d - k - 1):j + 1, :]) j -= d - k # determine the update vector, according to different baselines. if self.baselineType == self.BLOCKBASELINE: update = zeros(self.numDistrParams) vsquare = multiply(V, V) j = self.numDistrParams - 1 for k in reversed(range(self.numParameters)): b0 = sum(vsquare[j - (d - k - 1):j + 1, :], 0) b = dot(b0, fitnesses) / sum(b0) update[j - (d - k - 1):j + 1] = dot( V[j - (d - k - 1):j + 1, :], (fitnesses - b)) j -= d - k b0 = sum(vsquare[:j + 1, :], 0) b = dot(b0, fitnesses) / sum(b0) update[:j + 1] = dot(V[:j + 1, :], (fitnesses - b)) elif self.baselineType == self.SPECIFICBASELINE: update = zeros(self.numDistrParams) vsquare = multiply(V, V) for j in range(self.numDistrParams): b = dot(vsquare[j, :], fitnesses) / sum(vsquare[j, :]) update[j] = dot(V[j, :], (fitnesses - b)) elif self.baselineType == self.UNIFORMBASELINE: v = sum(V, 1) update = u - dot(v, u) / dot(v, v) * v elif self.baselineType == self.NOBASELINE: update = dot(V, fitnesses) else: raise NotImplementedError('No such baseline implemented') return update / self.batchSize
def _calcBatchUpdate(self, fitnesses): samples = self.allSamples[-self.batchSize:] d = self.numParameters invA = inv(self.factorSigma) invSigma = inv(self.sigma) diagInvA = diag(diag(invA)) # efficient computation of V, which corresponds to inv(Fisher)*logDerivs V = zeros((self.numDistrParams, self.batchSize)) # u is used to compute the uniform baseline u = zeros(self.numDistrParams) for i in range(self.batchSize): s = dot(invA.T, (samples[i] - self.x)) R = outer(s, dot(invA, s)) - diagInvA flatR = triu2flat(R) u[:d] += fitnesses[i] * (samples[i] - self.x) u[d:] += fitnesses[i] * flatR V[:d, i] += samples[i] - self.x V[d:, i] += flatR j = self.numDistrParams - 1 D = 1 / invSigma[-1, -1] # G corresponds to the blocks of the inv(Fisher) G = 1 / (invSigma[-1, -1] + invA[-1, -1] ** 2) u[j] = dot(G, u[j]) V[j, :] = dot(G, V[j, :]) j -= 1 for k in reversed(range(d - 1)): p = invSigma[k + 1:, k] w = invSigma[k, k] wg = w + invA[k, k] ** 2 q = dot(D, p) c = dot(p, q) r = 1 / (w - c) rg = 1 / (wg - c) t = -(1 + r * c) / w tg = -(1 + rg * c) / wg G = blockCombine([[rg, tg * q], [mat(tg * q).T, D + rg * outer(q, q)]]) D = blockCombine([[r , t * q], [mat(t * q).T, D + r * outer(q, q)]]) u[j - (d - k - 1):j + 1] = dot(G, u[j - (d - k - 1):j + 1]) V[j - (d - k - 1):j + 1, :] = dot(G, V[j - (d - k - 1):j + 1, :]) j -= d - k # determine the update vector, according to different baselines. if self.baselineType == self.BLOCKBASELINE: update = zeros(self.numDistrParams) vsquare = multiply(V, V) j = self.numDistrParams - 1 for k in reversed(range(self.numParameters)): b0 = sum(vsquare[j - (d - k - 1):j + 1, :], 0) b = dot(b0, fitnesses) / sum(b0) update[j - (d - k - 1):j + 1] = dot(V[j - (d - k - 1):j + 1, :], (fitnesses - b)) j -= d - k b0 = sum(vsquare[:j + 1, :], 0) b = dot(b0, fitnesses) / sum(b0) update[:j + 1] = dot(V[:j + 1, :], (fitnesses - b)) elif self.baselineType == self.SPECIFICBASELINE: update = zeros(self.numDistrParams) vsquare = multiply(V, V) for j in range(self.numDistrParams): b = dot(vsquare[j, :], fitnesses) / sum(vsquare[j, :]) update[j] = dot(V[j, :], (fitnesses - b)) elif self.baselineType == self.UNIFORMBASELINE: v = sum(V, 1) update = u - dot(v, u) / dot(v, v) * v elif self.baselineType == self.NOBASELINE: update = dot(V, fitnesses) else: raise NotImplementedError('No such baseline implemented') return update / self.batchSize