def test_FISTA_catch_Lipschitz(self): if debug_print: print("Test FISTA catch Lipschitz") ig = ImageGeometry(127, 139, 149) initial = ImageData(geometry=ig) initial = ig.allocate() b = initial.copy() # fill with random numbers b.fill(numpy.random.random(initial.shape)) initial = ig.allocate(ImageGeometry.RANDOM) identity = IdentityOperator(ig) #### it seems FISTA does not work with Nowm2Sq norm2sq = LeastSquares(identity, b) if debug_print: print('Lipschitz', norm2sq.L) # norm2sq.L = None #norm2sq.L = 2 * norm2sq.c * identity.norm()**2 #norm2sq = OperatorCompositionFunction(L2NormSquared(b=b), identity) opt = {'tol': 1e-4, 'memopt': False} if debug_print: print("initial objective", norm2sq(initial)) try: alg = FISTA(initial=initial, f=L1Norm(), g=ZeroFunction()) self.assertTrue(False) except ValueError as ve: print(ve) self.assertTrue(True)
def test_GD(self): print("Test GD") ig = ImageGeometry(12, 13, 14) initial = ig.allocate() # b = initial.copy() # fill with random numbers # b.fill(numpy.random.random(initial.shape)) b = ig.allocate('random') identity = IdentityOperator(ig) norm2sq = LeastSquares(identity, b) rate = norm2sq.L / 3. alg = GD(initial=initial, objective_function=norm2sq, rate=rate, atol=1e-9, rtol=1e-6) alg.max_iteration = 1000 alg.run(verbose=0) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array()) alg = GD(initial=initial, objective_function=norm2sq, rate=rate, max_iteration=20, update_objective_interval=2, atol=1e-9, rtol=1e-6) alg.max_iteration = 20 self.assertTrue(alg.max_iteration == 20) self.assertTrue(alg.update_objective_interval == 2) alg.run(20, verbose=0) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array())
def test_Lipschitz(self): print('Test for OperatorCompositionFunction') M, N = 50, 50 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) b = ig.allocate('random', seed=1) print('Check call with IdentityOperator operator... OK\n') operator = 3 * IdentityOperator(ig) u = ig.allocate('random_int', seed=50) func2 = LeastSquares(operator, b, 0.5) assert func2.L != 2 print(func2.L) func2.L = 2 assert func2.L == 2
def test_FISTA_Norm2Sq(self): print("Test FISTA Norm2Sq") ig = ImageGeometry(127, 139, 149) b = ig.allocate(ImageGeometry.RANDOM) # fill with random numbers initial = ig.allocate(ImageGeometry.RANDOM) identity = IdentityOperator(ig) #### it seems FISTA does not work with Nowm2Sq norm2sq = LeastSquares(identity, b) #norm2sq.L = 2 * norm2sq.c * identity.norm()**2 #norm2sq = OperatorCompositionFunction(L2NormSquared(b=b), identity) opt = {'tol': 1e-4, 'memopt': False} if debug_print: print("initial objective", norm2sq(initial)) alg = FISTA(initial=initial, f=norm2sq, g=ZeroFunction()) alg.max_iteration = 2 alg.run(20, verbose=0) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array()) alg = FISTA(initial=initial, f=norm2sq, g=ZeroFunction(), max_iteration=2, update_objective_interval=3) self.assertTrue(alg.max_iteration == 2) self.assertTrue(alg.update_objective_interval == 3) alg.run(20, verbose=0) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array())
def setUp(self, *args, **kwargs): M, N, K = 3, 4, 5 self.ig = ImageGeometry(M, N, K) self.x = self.ig.allocate('random', seed=1) self.b = self.ig.allocate('random', seed=2) self.eta = self.ig.allocate(0.1) self.operator = IdentityOperator(self.ig) scalar = 0.25 self.f1 = L2NormSquared() self.f2 = L1Norm() self.f3 = scalar * L2NormSquared() self.f4 = scalar * L1Norm() self.f5 = scalar * L2NormSquared(b=self.b) self.f6 = scalar * L1Norm(b=self.b) self.f7 = ZeroFunction() self.f8 = 5 * ConstantFunction(10) self.f9 = LeastSquares(self.operator, self.b, c=scalar) self.f10 = 0.5 * KullbackLeibler(b=self.b, eta=self.eta) self.f11 = KullbackLeibler(b=self.b, eta=self.eta) self.f12 = 10 self.list1 = [self.f1, self.f2, self.f3, self.f4, self.f5, \ self.f6, self.f7, self.f8, self.f9, self.f10, self.f11, self.f12]
def test_Norm2sq_as_OperatorCompositionFunction(self): print('Test for OperatorCompositionFunction') M, N = 50, 50 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) #numpy.random.seed(1) b = ig.allocate('random', seed=1) print('Check call with IdentityOperator operator... OK\n') operator = 3 * IdentityOperator(ig) u = ig.allocate('random', seed=50) f = 0.5 * L2NormSquared(b=b) func1 = OperatorCompositionFunction(f, operator) func2 = LeastSquares(operator, b, 0.5) print("f.L {}".format(f.L)) print("0.5*f.L {}".format((0.5 * f).L)) print("type func1 {}".format(type(func1))) print("func1.L {}".format(func1.L)) print("func2.L {}".format(func2.L)) print("operator.norm() {}".format(operator.norm())) numpy.testing.assert_almost_equal(func1(u), func2(u)) print('Check gradient with IdentityOperator operator... OK\n') tmp1 = ig.allocate() tmp2 = ig.allocate() res_gradient1 = func1.gradient(u) res_gradient2 = func2.gradient(u) func1.gradient(u, out=tmp1) func2.gradient(u, out=tmp2) self.assertNumpyArrayAlmostEqual(res_gradient1.as_array(), res_gradient2.as_array()) self.assertNumpyArrayAlmostEqual(tmp1.as_array(), tmp2.as_array()) print('Check call with MatrixOperator... OK\n') mat = np.random.randn(M, N) operator = MatrixOperator(mat) vg = VectorGeometry(N) b = vg.allocate('random') u = vg.allocate('random') func1 = OperatorCompositionFunction(0.5 * L2NormSquared(b=b), operator) func2 = LeastSquares(operator, b, 0.5) self.assertNumpyArrayAlmostEqual(func1(u), func2(u)) numpy.testing.assert_almost_equal(func1.L, func2.L)
def test_Lipschitz4(self): print('Test for test_Lipschitz4') M, N = 50, 50 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) b = ig.allocate('random', seed=1) print('Check call with IdentityOperator operator... OK\n') operator = 3 * IdentityOperator(ig) u = ig.allocate('random_int', seed=50) # func2 = LeastSquares(operator, b, 0.5) func1 = ConstantFunction(0.3) f3 = func1 + 3 assert f3.L == 0 print("OK") print(f3.L) f3.L = 2 assert f3.L == 2 print("OK") assert func1.L == 0 print("OK") try: func1.L = 2 assert False except AttributeError as ve: assert True print("OK") f2 = LeastSquares(operator, b, 0.5) f4 = 2 * f2 assert f4.L == 2 * f2.L print("OK") f4.L = 10 assert f4.L != 2 * f2.L print("OK") f4 = -2 * f2 assert f4.L == 2 * f2.L
def test_SumFunction(self): M, N, K = 3,4,5 ig = ImageGeometry(M, N, K) tmp = ig.allocate('random', seed=1) b = ig.allocate('random', seed=2) eta = ig.allocate(0.1) operator = IdentityOperator(ig) scalar = 0.25 f1 = L2NormSquared() f2 = L1Norm() f3 = scalar * L2NormSquared() f4 = scalar * L1Norm() f5 = scalar * L2NormSquared(b=b) f6 = scalar * L1Norm(b=b) f7 = ZeroFunction() f8 = 5 * ConstantFunction(10) f9 = LeastSquares(operator, b, c=scalar) f10 = 0.5*KullbackLeibler(b=b,eta = eta) f11 = KullbackLeibler(b=b, eta =eta) f12 = 10 # f10 = 0.5 * MixedL21Norm() # f11 = IndicatorBox(lower=0) list1 = [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12] print('################### Check sum of two functions ################## \n') for func in list1: # check sum of two functions if isinstance(func, ScaledFunction): type_fun = ' scalar * ' + type(func.function).__name__ else: type_fun = type(func).__name__ if isinstance(func, Number): tmp_fun_eval = func else: tmp_fun_eval = func(tmp) sumf = f1 + func self.assertNumpyArrayAlmostEqual(sumf(tmp), f1(tmp) + tmp_fun_eval ) print('{} = ( {} + {} ) is OK'.format(type(sumf).__name__, type(f1).__name__, type_fun)) sumf1 = func + f1 self.assertNumpyArrayAlmostEqual(sumf1(tmp), tmp_fun_eval + f1(tmp)) print('Checking commutative') print('{} + ( {} + {} ) is OK\n'.format(type(sumf1).__name__, type_fun, type(f1).__name__)) print('################### Check Lispchitz constant ################## \n') for i,func in enumerate(list1): if isinstance(func, ScaledFunction): type_fun = ' scalar * ' + type(func.function).__name__ else: type_fun = type(func).__name__ try: # check Lispchitz sum of two functions print ("i", i,func.__class__.__name__) if isinstance(func, Number): tmp_fun_L = 0 else: tmp_fun_L = func.L sumf = f1 + func try: sumf.L==f1.L + tmp_fun_L except TypeError: print('Function {} has L = None'.format(type_fun)) except ValueError as nie: print (func.__class__.__name__, nie) print('\n################### Check Gradient ################## \n') for func in list1: if isinstance(func, ScaledFunction): type_fun = ' scalar * ' + type(func.function).__name__ else: type_fun = type(func).__name__ sumf = f1 + func # check gradient try: if isinstance(func, Number): tmp_fun_gradient = 0 else: tmp_fun_gradient = func.gradient(tmp) self.assertNumpyArrayAlmostEqual(sumf.gradient(tmp).as_array(), (f1.gradient(tmp) + tmp_fun_gradient).as_array()) except NotImplementedError: print("{} is not differentiable".format(type_fun)) print('\n################### Check Gradient Out ################## \n') out_left = ig.allocate() out_right1 = ig.allocate() out_right2 = ig.allocate() for i, func in enumerate(list1): if isinstance(func, ScaledFunction): type_fun = ' scalar * ' + type(func.function).__name__ else: type_fun = type(func).__name__ sumf = f1 + func # check gradient out try: if isinstance(func, Number): tmp_fun_gradient_out = 0 else: func.gradient(tmp, out = out_right2) tmp_fun_gradient_out = out_right2.as_array() #print('Check {} + {}\n'.format(type(f1).__name__, type_fun)) sumf.gradient(tmp, out = out_left) f1.gradient(tmp, out = out_right1) self.assertNumpyArrayAlmostEqual(out_left.as_array(), out_right1.as_array() + tmp_fun_gradient_out) except NotImplementedError: print("{} is not differentiable".format(type_fun))
def tests_for_LS_weightedLS(self): ig = ImageGeometry(40, 30) numpy.random.seed(1) A = IdentityOperator(ig) b = ig.allocate('random') x = ig.allocate('random') c = numpy.float64(0.3) weight = ig.allocate('random') D = DiagonalOperator(weight) norm_weight = numpy.float64(D.norm()) print("norm_weight", norm_weight) f1 = LeastSquares(A, b, c, weight) f2 = LeastSquares(A, b, c) print("Check LS vs wLS") # check Lipshitz numpy.testing.assert_almost_equal(f2.L, 2 * c * (A.norm()**2)) print("unwrapped", 2. * c * norm_weight * (A.norm()**2)) print("f1.L", f1.L) numpy.testing.assert_almost_equal( f1.L, numpy.float64(2.) * c * norm_weight * (A.norm()**2)) print("Lipschitz is ... OK") # check call with weight res1 = c * (A.direct(x) - b).dot(weight * (A.direct(x) - b)) res2 = f1(x) numpy.testing.assert_almost_equal(res1, res2) print("Call is ... OK") # check call without weight #res1 = c * (A.direct(x)-b).dot((A.direct(x) - b)) res1 = c * (A.direct(x) - b).squared_norm() res2 = f2(x) numpy.testing.assert_almost_equal(res1, res2) print("Call without weight is ... OK") # check gradient with weight out = ig.allocate(None) res1 = f1.gradient(x) #out = f1.gradient(x) f1.gradient(x, out=out) res2 = 2 * c * A.adjoint(weight * (A.direct(x) - b)) numpy.testing.assert_array_almost_equal(res1.as_array(), res2.as_array()) numpy.testing.assert_array_almost_equal(out.as_array(), res2.as_array()) print("GradientOperator is ... OK") # check gradient without weight out = ig.allocate() res1 = f2.gradient(x) f2.gradient(x, out=out) res2 = 2 * c * A.adjoint(A.direct(x) - b) numpy.testing.assert_array_almost_equal(res1.as_array(), res2.as_array()) numpy.testing.assert_array_almost_equal(out.as_array(), res2.as_array()) print("GradientOperator without weight is ... OK") print( "Compare Least Squares with DiagonalOperator + CompositionOperator" ) ig2 = ImageGeometry(100, 100, 100) A = IdentityOperator(ig2) b = ig2.allocate('random') x = ig2.allocate('random') c = 0.3 weight = ig2.allocate('random') weight_operator = DiagonalOperator(weight.sqrt()) tmp_A = CompositionOperator(weight_operator, A) tmp_b = weight_operator.direct(b) f1 = LeastSquares(tmp_A, tmp_b, c) f2 = LeastSquares(A, b, c, weight) t0 = timer() res1 = f1(x) t1 = timer() print("Time with Composition+Diagonal is {}".format(t1 - t0)) t2 = timer() res2 = f2(x) t3 = timer() print("Time with LS + weight is {}".format(t3 - t2)) numpy.testing.assert_almost_equal(res1, res2, decimal=2)
def test_SumFunction_more_inputs(self): # Test Lipshchitz value with more than 2 functions list2 = [ LeastSquares(self.operator, self.b, c=0.25), LeastSquares(self.operator, self.b, c=4), LeastSquares(self.operator, self.b, c=5) ] F = SumFunction(*list2) L = 0. for f in list2: L += f.L self.assertAlmostEqual(L, F.L) # assert Lmax property self.assertAlmostEqual(max(f.L for f in list2), F.Lmax) ## test value of the gradient out = list2[0].gradient(self.x) out += list2[1].gradient(self.x) out += list2[2].gradient(self.x) # gradient without out out2 = F.gradient(self.x) np.testing.assert_allclose(out.as_array(), out2.as_array()) # gradient with out out3 = self.x * 0. F.gradient(self.x, out=out3) np.testing.assert_allclose(out.as_array(), out3.as_array()) # check call method val = F(self.x) val2 = 0. for f in F.functions: val2 += f(self.x) np.testing.assert_almost_equal(val, val2) # adding one more function (3 in total) scalar = 2.5 F2 = F + ConstantFunction(scalar) # test __add__ method assert len(F2.functions) == len(F.functions) + 1 # test if the sum remains a SumFunction self.assertIsInstance(F2, SumFunction) # check call np.testing.assert_almost_equal(F2(self.x), F(self.x) + scalar) # adding one more function (4 in total) F3 = F + F2 np.testing.assert_almost_equal(F2(self.x) + F(self.x), F3(self.x)) self.assertEqual(len(F3.functions), len(F2.functions) + len(F.functions)) # test if the sum remains a SumFunction self.assertIsInstance(F3, SumFunction)
ig.voxel_num_y = int(num_pixels_x - 600 / bins) ig.voxel_num_z = int(400 // bins) print(ig) #%% Reconstruct with FDK fbp = FBP(ig, ag) fbp.set_input(aq_data) FBP_3D_gpu = fbp.get_output() show2D(FBP_3D_gpu, slice_list=[('vertical', 204 // bins), ('horizontal_y', 570 // bins)], title="FBP reconstruction", fix_range=(-0.02, 0.07)) #%% Setup least sqaures and force pre-calculation of Lipschitz constant Projector = ProjectionOperator(ig, ag) LS = LeastSquares(A=Projector, b=aq_data) print("Lipschitz constant =", LS.L) #%% Setup FISTA to solve for least squares fista = FISTA(x_init=ig.allocate(0), f=LS, g=ZeroFunction(), max_iteration=1000) fista.update_objective_interval = 10 #%% Run FISTA fista.run(300) LS_reco = fista.get_output() show2D(LS_reco, slice_list=[('vertical', 204 // bins), ('horizontal_y', 570 // bins)], title="LS reconstruction",
titles=['no centre', 'COR'], cmap='gist_earth', ) #%% from cil.optimisation.functions import TotalVariation from cil.optimisation.algorithms import FISTA from cil.optimisation.functions import LeastSquares from cil.plugins.astra.operators import ProjectionOperator as A # from cil.plugins.ccpi_regularisation.functions import FGP_TV K = A(ig_cs, ag_shift) # the c parameter is used to remove scaling of L2NormSquared in PDHG # c = 2 f = LeastSquares(K, ldata, c=0.5 * c) if sparse_beads: f.L = 1071.1967 * c else: f.L = 24.4184 * c alpha_rgl = 0.003 alpha = alpha_rgl * ig_cs.voxel_size_x g = c * alpha * TotalVariation(lower=0.) g = FGP_TV(alpha, 100, 1e-5, 1, 1, 0, 'gpu') algo = FISTA(initial=K.domain.allocate(0), f=f, g=g, max_iteration=10000, update_objective_interval=2) #%%
#%% plotter2D( [FBP_cs, FBP_output], titles=['no centre', 'COR'], cmap='gist_earth', ) #%% from cil.optimisation.functions import TotalVariation from cil.optimisation.algorithms import FISTA from cil.optimisation.functions import LeastSquares from cil.plugins.astra.operators import ProjectionOperator as A # from cil.plugins.ccpi_regularisation.functions import FGP_TV K = A(ig_cs, ag_shift) f = LeastSquares(K, ldata, c=0.5) if sparse_beads: f.L = 1071.1967 else: f.L = 24.4184 alpha_rgl = 0.003 alpha = alpha_rgl * ig_cs.voxel_size_x g = alpha * TotalVariation(lower=0.) g = FGP_TV(alpha, 100, 1e-5, 1, 1, 0, 'gpu') algo = FISTA(initial=K.domain.allocate(0), f=f, g=g, max_iteration=10000, update_objective_interval=2) #%%