def test_proximal_composition(pos_scalar, sigma): """Test for proximal of composition with semi-orthogonal linear operator. This test is for ``prox[f * L](x)``, where ``L`` is a linear operator such that ``L * L.adjoint = mu * IdentityOperator``. Specifically, ``L`` is taken to be ``scal * IdentityOperator``, since this is equivalent to scaling of the argument. """ sigma = float(sigma) space = odl.uniform_discr(0, 1, 10) prox_factory = proximal_l2_squared(space) # The semi-orthogonal linear operator scal = pos_scalar L = odl.ScalingOperator(space, scal) mu = scal ** 2 # L = scal * I => L * L.adjoint = scal ** 2 * I prox_factory_composition = proximal_composition(prox_factory, L, mu) prox = prox_factory_composition(sigma) assert isinstance(prox, odl.Operator) x = space.element(np.arange(-5, 5)) prox_x = prox(x) equiv_prox = proximal_arg_scaling(prox_factory, scal)(sigma) expected_result = equiv_prox(x) assert all_almost_equal(prox_x, expected_result, places=PLACES)
def test_module_forward(shape, use_cuda): """Test forward evaluation with operators as modules.""" ndim = len(shape) space = odl.uniform_discr([0] * ndim, shape, shape) odl_op = odl.ScalingOperator(space, 2) op_mod = odl_torch.OperatorAsModule(odl_op) x = torch.from_numpy(np.ones(shape)) if use_cuda: x = x.cuda() # Test with 1 extra dim (minimum) x_var = autograd.Variable(x, requires_grad=True)[None, ...] y_var = op_mod(x_var) assert y_var.data.shape == (1, ) + odl_op.range.shape assert all_almost_equal(y_var.data.cpu().numpy(), 2 * np.ones((1, ) + shape)) # Test with 2 extra dims x_var = autograd.Variable(x, requires_grad=True)[None, None, ...] y_var = op_mod(x_var) assert y_var.data.shape == (1, 1) + odl_op.range.shape assert all_almost_equal(y_var.data.cpu().numpy(), 2 * np.ones((1, 1) + shape)) # Make sure data stays on the GPU if use_cuda: assert y_var.is_cuda
def test_module_forward(shape, device): """Test forward evaluation with operators as modules.""" # Define ODL operator and wrap as module ndim = len(shape) space = odl.uniform_discr([0] * ndim, shape, shape, dtype='float32') odl_op = odl.ScalingOperator(space, 2) op_mod = odl_torch.OperatorModule(odl_op) # Input data x_arr = np.ones(shape, dtype='float32') # Test with 1 extra dim (minimum) x = torch.from_numpy(x_arr).to(device)[None, ...] x.requires_grad_(True) res = op_mod(x) res_arr = res.detach().cpu().numpy() assert res_arr.shape == (1, ) + odl_op.range.shape assert all_almost_equal(res_arr, np.asarray(odl_op(x_arr))[None, ...]) assert x.device.type == res.device.type == device # Test with 2 extra dims x = torch.from_numpy(x_arr).to(device)[None, None, ...] x.requires_grad_(True) res = op_mod(x) res_arr = res.detach().cpu().numpy() assert res_arr.shape == (1, 1) + odl_op.range.shape assert all_almost_equal(res_arr, np.asarray(odl_op(x_arr))[None, None, ...]) assert x.device.type == res.device.type == device
def reconstruction(proj_data, parameters): # Extract the separate parameters lam, sigma = parameters print('lam = {}, sigma = {}'.format(lam, sigma)) # We do not allow negative parameters, so return a bogus result if lam <= 0 or sigma <= 0: return np.inf * space.one() # Create data term ||Ax - b||_2^2 l2_norm = odl.solvers.L2NormSquared(ray_trafo.range) data_discrepancy = l2_norm * (ray_trafo - proj_data) # Create regularizing functional huber(|grad(x)|) gradient = odl.Gradient(space) l1_norm = odl.solvers.GroupL1Norm(gradient.range) smoothed_l1 = odl.solvers.MoreauEnvelope(l1_norm, sigma=sigma) regularizer = smoothed_l1 * gradient # Create full objective functional obj_fun = data_discrepancy + lam * regularizer # Pick parameters maxiter = 30 num_store = 5 # Run the algorithm x = ray_trafo.domain.zero() odl.solvers.bfgs_method(obj_fun, x, maxiter=maxiter, num_store=num_store, hessinv_estimate=odl.ScalingOperator( space, 1 / odl.power_method_opnorm(ray_trafo)**2)) return x
gradient = odl.Gradient(reco_space, method='forward') gradient_back = odl.Gradient(reco_space, method='backward') eps = odl.DiagonalOperator(gradient_back, reco_space.ndim) # Create the domain of the problem, given by the reconstruction space and the # range of the gradient on the reconstruction space. domain = odl.ProductSpace(reco_space, gradient.range) # Column vector of three operators defined as: # 1. Computes ``A(x)`` # 2. Computes ``grad(x) - y`` # 3. Computes ``eps(y)`` op = odl.BroadcastOperator( ray_trafo * odl.ComponentProjection(domain, 0), odl.ReductionOperator(gradient, odl.ScalingOperator(gradient.range, -1)), eps * odl.ComponentProjection(domain, 1)) # Do not use the g functional, set it to zero. g = odl.solvers.ZeroFunctional(op.domain) # Create functionals for the dual variable # l2-squared data matching l2_norm = odl.solvers.L2NormSquared(ray_trafo.range).translated(data) # The l1-norms scaled by regularization paramters l1_norm_1 = 0.001 * odl.solvers.L1Norm(gradient.range) l1_norm_2 = 1e-4 * odl.solvers.L1Norm(eps.range) # Combine functionals, order must correspond to the operator K
# [[Dx, 0], [0, Dy], [0.5*Dy, 0.5*Dx]], range=W) E = odl.operator.ProductSpaceOperator( [[Dx, 0], [0, Dy], [0.5*Dy, 0.5*Dx], [0.5*Dy, 0.5*Dx]]) W = E.range # Create the domain of the problem, given by the reconstruction space and the # range of the gradient on the reconstruction space. domain = odl.ProductSpace(U, V) # Column vector of three operators defined as: # 1. Computes ``Ax`` # 2. Computes ``Gx - y`` # 3. Computes ``Ey`` op = odl.BroadcastOperator( A * odl.ComponentProjection(domain, 0), odl.ReductionOperator(G, odl.ScalingOperator(V, -1)), E * odl.ComponentProjection(domain, 1)) # Do not use the g functional, set it to zero. g = odl.solvers.ZeroFunctional(domain) # l2-squared data matching l2_norm = odl.solvers.L2NormSquared(A.range).translated(data) # parameters alpha = 1e-1 beta = 1 # The l1-norms scaled by regularization paramters l1_norm_1 = alpha * odl.solvers.L1Norm(V) l1_norm_2 = alpha * beta * odl.solvers.L1Norm(W)
data = ray_trafo(discr_phantom) data += odl.phantom.white_noise(ray_trafo.range) * np.mean(data) * 0.1 # --- Set up optimization problem and solve --- # # Create objective functional ||Ax - b||_2^2 as composition of l2 norm squared # and the residual operator. obj_fun = odl.solvers.L2NormSquared(ray_trafo.range) * (ray_trafo - data) # Create line search line_search = 1.0 # line_search = odl.solvers.BacktrackingLineSearch(obj_fun) # Create initial estimate of the inverse Hessian by a diagonal estimate opnorm = odl.power_method_opnorm(ray_trafo) hessinv_estimate = odl.ScalingOperator(reco_space, 1 / opnorm**2) # Optionally pass callback to the solver to display intermediate results callback = (odl.solvers.CallbackPrintIteration() & odl.solvers.CallbackShow()) # Pick parameters maxiter = 20 num_store = 5 # only save some vectors (Limited memory) # Choose a starting point x = ray_trafo.domain.zero() # Run the algorithm odl.solvers.bfgs_method(obj_fun, x, line_search=line_search,
data_discrepancy = odl.solvers.L2NormSquared(A.range).translated(rhs) l1_norm = odl.solvers.L1Norm(space) huber = 2.5 * odl.solvers.MoreauEnvelope(l1_norm, sigma=0.01) my_op = MyOperatorTrace(domain=grad_vec.range, range=space, linear=False) spc_cov_matrix = [[1, -c], [-c, 1]] spc_cov_matrix_inv_sqrt = inverse_sqrt_matrix(spc_cov_matrix) Lam = LamOp(grad_vec.range, arr=spc_cov_matrix_inv_sqrt) func = data_discrepancy * op + huber * my_op * Lam * grad_vec fbp_op = odl.tomo.fbp_op(ray_trafo, filter_type='Hann', frequency_scaling=0.7) x = A.domain.element([fbp_op(data[0]), fbp_op(data[1])]) x.show(clim=[0.9, 1.1]) callback = (odl.solvers.CallbackShow(step=5) & odl.solvers.CallbackShow(step=5, clim=[-0.1, 0.1]) & odl.solvers.CallbackShow(step=5, clim=[0.9, 1.1]) & odl.solvers.CallbackPrintIteration()) opnorm = odl.power_method_opnorm(op) hessinv_estimate = odl.ScalingOperator(func.domain, 1 / opnorm ** 2) odl.solvers.bfgs_method(func, x, line_search=1.0, maxiter=1000, num_store=10, callback=callback, hessinv_estimate=hessinv_estimate)
phantom = odl.phantom.shepp_logan(space, modified=True) # Create sinogram of forward projected phantom with noise data = operator(phantom) data += odl.phantom.white_noise(operator.range) * np.mean(np.abs(data)) * 0.05 # --- Set up optimization problem and solve --- # # Create data term ||Ax - b||_2^2 as composition of the squared L2 norm and the # ray trafo translated by the data. l2_norm = odl.solvers.L2NormSquared(operator.range) data_discrepancy = l2_norm * (operator - data) # Create initial estimate of the inverse Hessian by a diagonal estimate opnorm = odl.power_method_opnorm(operator) hessinv_estimate = odl.ScalingOperator(space, 0.5 / opnorm**2) sigma = 0.03 lam = 0.3 # Create regularizing functional || |grad(x)| ||_1 and smooth the functional # using the Moreau envelope. # The parameter sigma controls the strength of the regularization. gradient = odl.Gradient(space) l1_norm = odl.solvers.GroupL1Norm(gradient.range) smoothed_l1 = odl.solvers.MoreauEnvelope(l1_norm, sigma=sigma) regularizer = smoothed_l1 * gradient # Create full objective functional obj_fun = data_discrepancy + lam * regularizer
mu = [ np.less(y, (c[0] + c[1]) / 2), np.logical_and(np.greater_equal(y, (c[0] + c[1]) / 2), np.less(y, (c[1] + c[2]) / 2)), np.greater_equal(y, (c[1] + c[2]) / 2) ] x = y.copy() callback = (odl.solvers.CallbackShow('bias', display_step=1) & odl.solvers.CallbackPrintIteration()) # Store some values I = len(c) spatial_domain = y.space ones = spatial_domain.one() # ones.inner(x) gives integral of x scaling = odl.ScalingOperator(spatial_domain, lam1) conv_adj_mu_pow_m = [None] * I cd # Iteratively solve the coordinate descent equations for _ in range(niter): # Update mu for i in range(I): summand = spatial_domain.zero() convi = conv((x - c[i])**2) for j in range(I): convj = conv((x - c[j])**2) summand += np.power(convi / convj, 1.0 / (m - 1.0)) mu[i] = 1.0 / summand conv_adj_mu_pow_m[i] = conv.adjoint(np.power(mu[i], m)) # Update c
# Create huber norm grad = odl.Gradient(space) l1_norm = odl.solvers.GroupL1Norm(grad.range) huber = odl.solvers.MoreauEnvelope(l1_norm, sigma=sigma) func = l2 + lam * huber * grad callback = odl.solvers.CallbackPrintIteration( 'huber material {} lam {}'.format(material, lam)) opnorm = odl.power_method_opnorm(ray_trafo) if lam > 0: reg_norm = odl.power_method_opnorm((lam * huber * grad).gradient) else: reg_norm = 0 hessinv_estimate = odl.ScalingOperator(func.domain, 1 / (opnorm + reg_norm)**2) x = func.domain.zero() odl.solvers.bfgs_method(func, x, line_search=1.0, maxiter=1000, num_store=10, callback=callback, hessinv_estimate=hessinv_estimate) import scipy.io as sio mdict = {'result': x.asarray(), 'lam': lam} sio.savemat( 'data/results/parameters/result_huber_{}_lam_{}'.format(material, lam), mdict)
def inf_action(self, lie_alg_element): assert lie_alg_element in self.lie_group.associated_algebra return odl.ScalingOperator(self.domain, np.trace(lie_alg_element.arr))
def action(self, lie_grp_element): assert lie_grp_element in self.lie_group return odl.ScalingOperator(self.domain, np.linalg.det(lie_grp_element.arr))