def make_inverse_update_ops(self): """Create and return update ops corresponding to registered computations.""" ops = super(InverseProvidingFactor, self).make_inverse_update_ops() num_inverses = len(self._inverses_by_damping) matrix_power_registered = bool(self._matpower_by_exp_and_damping) use_eig = (self._eigendecomp or matrix_power_registered or num_inverses >= EIGENVALUE_DECOMPOSITION_THRESHOLD) if use_eig: self.register_eigendecomp() # ensures self._eigendecomp is set eigenvalues, eigenvectors = self._eigendecomp # pylint: disable=unpacking-non-sequence # The matrix self._cov is positive semidefinite by construction, but the # numerical eigenvalues could be negative due to numerical errors, so here # we clip them to be at least EIGENVALUE_CLIPPING_THRESHOLD. clipped_eigenvalues = math_ops.maximum(eigenvalues, EIGENVALUE_CLIPPING_THRESHOLD) for damping, inv in self._inverses_by_damping.items(): ops.append( inv.assign( math_ops.matmul(eigenvectors / (clipped_eigenvalues + damping), array_ops.transpose(eigenvectors)))) for (exp, damping), matpower in self._matpower_by_exp_and_damping.items(): ops.append( matpower.assign( math_ops.matmul(eigenvectors * (clipped_eigenvalues + damping)** exp, array_ops.transpose(eigenvectors)))) else: for damping, inv in self._inverses_by_damping.items(): ops.append(inv.assign(utils.posdef_inv(self._cov, damping))) return ops
def make_inverse_update_ops(self): """Create and return update ops corresponding to registered computations.""" ops = [] num_inverses = len(self._inverses_by_damping) matrix_power_registered = bool(self._matpower_by_exp_and_damping) use_eig = (self._eigendecomp or matrix_power_registered or num_inverses >= EIGENVALUE_DECOMPOSITION_THRESHOLD) if use_eig: self.register_eigendecomp() # ensures self._eigendecomp is set eigenvalues, eigenvectors = self._eigendecomp # pylint: disable=unpacking-non-sequence for damping, inv in self._inverses_by_damping.items(): ops.append( inv.assign( math_ops.matmul(eigenvectors / (eigenvalues + damping), array_ops.transpose(eigenvectors)))) for (exp, damping ), matpower in self._matpower_by_exp_and_damping.items(): ops.append( matpower.assign( math_ops.matmul( eigenvectors * (eigenvalues + damping)**exp, array_ops.transpose(eigenvectors)))) # These ops share computation and should be run on a single device. ops = [control_flow_ops.group(*ops)] else: for damping, inv in self._inverses_by_damping.items(): ops.append(inv.assign(utils.posdef_inv(self._cov, damping))) return ops
def make_inverse_update_ops(self): """Create and return update ops corresponding to registered computations.""" ops = [] num_inverses = len(self._inverses_by_damping) matrix_power_registered = bool(self._matpower_by_exp_and_damping) use_eig = ( self._eigendecomp or matrix_power_registered or num_inverses >= EIGENVALUE_DECOMPOSITION_THRESHOLD) if use_eig: self.register_eigendecomp() # ensures self._eigendecomp is set eigenvalues, eigenvectors = self._eigendecomp # pylint: disable=unpacking-non-sequence for damping, inv in self._inverses_by_damping.items(): ops.append( inv.assign( math_ops.matmul(eigenvectors / (eigenvalues + damping), array_ops.transpose(eigenvectors)))) for (exp, damping), matpower in self._matpower_by_exp_and_damping.items(): ops.append( matpower.assign( math_ops.matmul(eigenvectors * (eigenvalues + damping)**exp, array_ops.transpose(eigenvectors)))) # These ops share computation and should be run on a single device. ops = [control_flow_ops.group(*ops)] else: for damping, inv in self._inverses_by_damping.items(): ops.append(inv.assign(utils.posdef_inv(self._cov, damping))) return ops
def make_inverse_update_ops(self): """Create and return update ops corresponding to registered computations.""" ops = [] # We do this to ensure that we don't reuse the eigendecomp from old calls # to make_inverse_update_ops that may be placed on different devices. This # can happen is the user has both a permanent and lazily constructed # version of the inverse ops (and only uses one of them). self.reset_eigendecomp() num_inverses = len(self._inverses_by_damping) matrix_power_registered = bool(self._matpower_by_exp_and_damping) use_eig = (self._eigendecomp or matrix_power_registered or num_inverses >= EIGENVALUE_DECOMPOSITION_THRESHOLD) if use_eig: eigenvalues, eigenvectors = self.get_eigendecomp() # pylint: disable=unpacking-non-sequence for damping, inv in self._inverses_by_damping.items(): ops.append( inv.assign( math_ops.matmul(eigenvectors / (eigenvalues + damping), array_ops.transpose(eigenvectors)))) for (exp, damping ), matpower in self._matpower_by_exp_and_damping.items(): ops.append( matpower.assign( math_ops.matmul( eigenvectors * (eigenvalues + damping)**exp, array_ops.transpose(eigenvectors)))) # These ops share computation and should be run on a single device. ops = [control_flow_ops.group(*ops)] else: for damping, inv in self._inverses_by_damping.items(): ops.append(inv.assign(utils.posdef_inv(self._cov, damping))) return ops
def make_inverse_update_ops(self): """Create and return update ops corresponding to registered computations.""" ops = [] # We do this to ensure that we don't reuse the eigendecomp from old calls # to make_inverse_update_ops that may be placed on different devices. This # can happen is the user has both a permanent and lazily constructed # version of the inverse ops (and only uses one of them). self.reset_eigendecomp() num_inverses = len(self._inverses_by_damping) matrix_power_registered = bool(self._matpower_by_exp_and_damping) use_eig = ( self._eigendecomp or matrix_power_registered or num_inverses >= EIGENVALUE_DECOMPOSITION_THRESHOLD) if use_eig: eigenvalues, eigenvectors = self.get_eigendecomp() # pylint: disable=unpacking-non-sequence for damping, inv in self._inverses_by_damping.items(): ops.append( inv.assign( math_ops.matmul(eigenvectors / (eigenvalues + damping), array_ops.transpose(eigenvectors)))) for (exp, damping), matpower in self._matpower_by_exp_and_damping.items(): ops.append( matpower.assign( math_ops.matmul(eigenvectors * (eigenvalues + damping)**exp, array_ops.transpose(eigenvectors)))) # These ops share computation and should be run on a single device. ops = [control_flow_ops.group(*ops)] else: for damping, inv in self._inverses_by_damping.items(): ops.append(inv.assign(utils.posdef_inv(self._cov, damping))) return ops