def test_methanical_condition_number(self): ''' Mechanical test of condition number calculation ''' # Unitary Matrix F = ops.FourierTransform(image_size, dtype=global_dtype, backend=global_backend) assert F.condition_number == 1 assert not F.condition_number_is_upper_bound # Matrix with a condition number hh = yp.changeBackend((np.random.rand(image_size[0], image_size[1]) + 0.1).astype(np.complex64), global_backend) D = ops.Diagonalize(hh, dtype=global_dtype, backend=global_backend) assert not D.condition_number_is_upper_bound # Product of two unitary matricies assert (F * F).condition_number == 1 assert not (F * F).condition_number_is_upper_bound # Product of one unitary and one non-singular matrix assert (F * D).condition_number == D.condition_number assert not (F * D).condition_number_is_upper_bound # because one matrix is unitary, this condition number is NOT an upper bound. This can be checked numerically. # Product of two non-singular matricies. hh_2 = yp.changeBackend((np.random.rand(image_size[0], image_size[1]) + 0.1).astype(np.complex64), global_backend) D2 = ops.Diagonalize(hh_2, dtype=global_dtype, backend=global_backend) assert (D * D2).condition_number >= D.condition_number assert (D * D2).condition_number_is_upper_bound
def test_operator_fourier_transform(self): # Define "true" FFTs Ft = lambda x: np.fft.fftshift(np.fft.fft2(np.fft.fftshift(x, axes=(0, 1)), axes=(0, 1), norm='ortho'), axes=(0, 1)) iFt = lambda x: np.fft.fftshift(np.fft.ifft2(np.fft.fftshift(x, axes=(0, 1)), axes=(0, 1), norm='ortho'), axes=(0, 1)) eps_fft = yp.precision(self.x, for_sum=True) if global_backend == 'numpy': fft_backends = ['scipy', 'numpy'] else: fft_backends = ['af'] for fft_backend in fft_backends: # Create Operator F = ops.FourierTransform(image_size, dtype=global_dtype, axes=(0, 1), fft_backend=fft_backend, center=True, backend=global_backend) # Check forward model assert yp.sumb(yp.abs(Ft(self.x).reshape(image_size) - yp.changeBackend(F * self.x, 'numpy').reshape(image_size))) < eps_fft, '%f' % yp.sumb(yp.abs(Ft(x).reshape(image_size) - yp.changeBackend(F * vec(self.x), 'numpy').reshape(image_size))) assert yp.sumb(yp.abs(iFt(self.x).reshape(image_size) - yp.changeBackend((F.H * self.x), 'numpy').reshape(image_size))) < eps_fft # Check reciprocity assert yp.sumb(yp.abs(F * F.H * self.x - self.x)) < eps_fft, "%.4e" % yp.sumb(yp.abs(F * F.H * vec(self.x) - vec(self.x))) # Check Gradient F.gradient_check()
def test_shape(self): # Check that shape function is correct assert bops.shape(bops.changeBackend(self.x_ocl_rect, 'numpy')) == self.sz assert bops.shape(bops.changeBackend(self.x_np_rect, 'arrayfire')) == self.sz
def test_intensity(self): I = ops.Intensity(image_size) # Check forward operator assert yp.sumb(yp.abs((yp.abs(yp.changeBackend(self.x, 'numpy')) ** 2) - yp.changeBackend(I * self.x, 'numpy'))) < eps # Check gradient I.gradient_check()
def test_operator_matrix_multiply(self): matrix_size = (10,10) m = yp.rand(matrix_size, global_dtype, global_backend) xm = yp.rand(matrix_size[1], global_dtype, global_backend) M = ops.MatrixMultiply(m) # Check Forward operator assert yp.sumb(yp.abs(yp.vec(yp.changeBackend(M * xm, 'numpy')) - yp.vec(yp.changeBackend(m, 'numpy').dot(yp.changeBackend(xm, 'numpy'))))) < eps, "%f" % yp.sumb(yp.abs(yp.changeBackend(M * xm, 'numpy') - yp.changeBackend(m, 'numpy').dot(yp.changeBackend(xm, 'numpy'))[:, np.newaxis])) # Check Adjoint assert yp.sumb(yp.abs(yp.vec(yp.changeBackend(M.H * xm, 'numpy')) - yp.vec(np.conj(yp.changeBackend(m, 'numpy').T).dot(yp.changeBackend(xm, 'numpy'))))) < eps, "%f" % yp.sumb(yp.abs(yp.changeBackend(M.H * xm, 'numpy') - np.conj(yp.changeBackend(m, 'numpy').T).dot(yp.changeBackend(xm, 'numpy'))[:, np.newaxis])) # Check gradient M.gradient_check()
def normalize(self, force=False): if 'normalization' not in self.metadata.calibration or force: # Calculation normalization vectors from htdeblur.recon import normalize_measurements (frame_normalization_list_y, frame_normalization_list_x) = normalize_measurements(self, debug=False) # Convert to numpy for saving _frame_normalization_list_y = [yp.changeBackend(norm, 'numpy').tolist() for norm in frame_normalization_list_y] _frame_normalization_list_x = [yp.changeBackend(norm, 'numpy').tolist() for norm in frame_normalization_list_x] # Save in metadata self.metadata.calibration['normalization'] = {'frame_normalization_x': _frame_normalization_list_x, 'frame_normalization_y': _frame_normalization_list_y} # Save calibration file self.saveCalibration()
def setup_method(self, test_method): # Initialize arrays self.eps = bops.precision(dtype) * np.prod(shape) self.x_np_ones = bops.ones(shape, dtype, 'numpy') self.x_ocl_ones = bops.ones(shape, dtype, 'arrayfire') self.x_ocl_randn = bops.randn(shape, dtype, 'arrayfire') self.x_np_randn = np.asarray(self.x_ocl_randn) self.x_ocl_randu = bops.randu(shape, dtype, 'arrayfire') self.x_np_randu = np.asarray(self.x_ocl_randu) # Create random matricies self.A_ocl = bops.randn((10, 10), backend='arrayfire') self.A_np = np.asarray(self.A_ocl) self.sz = (10, 20) self.x_np_rect = bops.randn(self.sz, backend='numpy') assert bops.shape(self.x_np_rect) == self.sz self.x_ocl_rect = bops.randn(self.sz, backend='arrayfire') assert bops.shape(self.x_ocl_rect) == self.sz # Load object and crop to size brain = imageio.imread(object_file_name) x_0 = sp.misc.imresize( brain, size=image_size)[:, :, object_color_channel].astype( bops.getNativeDatatype(dtype, 'numpy')) / 255. # Convert object to desired backend self.x = bops.changeBackend(x_0, 'arrayfire')
def test_operator_convolution_circular(self): ''' Circular Convolution Operator ''' # Generate circular convolution operator C = ops.Convolution(self.h) # Test forward operator conv2 = lambda x, h: yp.changeBackend(np.fft.ifftshift((np.fft.ifft2(np.fft.fft2(x, axes=(0,1), norm='ortho') * np.fft.fft2(h, axes=(0,1), norm='ortho'), axes=(0,1), norm='ortho')), axes=(0,1)).astype(yp.getNativeDatatype(global_dtype, 'numpy')), global_backend) x_np = yp.changeBackend(self.x, 'numpy') h_np = yp.changeBackend(self.h, 'numpy') assert np.sum(np.abs(yp.reshape(C * yp.vec(self.x), image_size) - conv2(x_np, h_np)) ** 2) < 1e-3, \ 'SSE (%.4e) is greater than tolerance (%.4e)' % ((np.sum(np.abs((C * yp.vec(self.x)).reshape(image_size)-conv2(x,h)))), eps) # Check gradient C.gradient_check()
def test_indexing(self): q = bops.randn((10, 10), backend='numpy', dtype='complex32') q_ocl = bops.changeBackend(q, 'arrayfire') q_ocl_np = bops.changeBackend(q_ocl, 'numpy') assert np.sum(np.abs(q - q_ocl_np)) < eps m = bops.rand((10, 20), dtype, "numpy") m_ocl = bops.changeBackend(m, 'arrayfire') assert abs(m[0, 1] - bops.scalar(m_ocl[0, 1])) < eps assert abs(m[1, 1] - bops.scalar(m_ocl[1, 1])) < eps assert abs(bops.scalar(m_ocl[4, 1]) - m[4, 1]) < eps assert bops.scalar(self.x_np_rect[5, 15]) == bops.scalar( bops.changeBackend(self.x_np_rect, 'arrayfire')[5, 15]) assert bops.scalar(self.x_ocl_rect[5, 15]) == bops.scalar( bops.changeBackend(self.x_ocl_rect, 'numpy')[5, 15])
def test_crop(self): crop_size = [self.x_np_randn.shape[i] - 2 for i in range(len(shape))] assert np.sum( np.abs( bops.crop(self.x_np_randn, crop_size, crop_start=(0, 0)) - np.asarray( bops.crop(self.x_ocl_randn, crop_size, crop_start=( 0, 0))))) < 1e-4 x_full_np = bops.rand((20, 20), dtype=dtype, backend='numpy') x_full_ocl = bops.changeBackend(x_full_np, 'arrayfire') crop_size = tuple(np.asarray(bops.shape(x_full_np)) // 2) crop_start = (2, 2) x_crop_np = bops.crop(x_full_np, crop_size, crop_start=crop_start) x_crop_ocl = bops.crop(x_full_ocl, crop_size, crop_start=crop_start) assert np.sum( np.abs(bops.changeBackend(x_crop_ocl, 'numpy') - x_crop_np)) < 1e-4
def test_operator_crop_non_centered(self): ''' Non-centered Crop Operator ''' # Generate Crop Operator crop_size = (image_size[0] // 2, image_size[1] // 2) crop_start = (6, 6) CR = ops.Crop(image_size, crop_size, pad_value=0, dtype=global_dtype, backend=global_backend, crop_start=crop_start) # Check forward operator y_1 = yp.changeBackend(CR * self.x, 'numpy') y_2 = yp.changeBackend(yp.crop(self.x, crop_size, crop_start), 'numpy') assert yp.sumb(yp.abs(y_1 - y_2)) < eps # Check Adjoint Operator pad_size = [int((image_size[i] - crop_size[i]) / 2) for i in range(len(image_size))] y_3 = yp.pad(yp.crop(self.x, crop_size, crop_start), image_size, crop_start, pad_value=0) y_4 = yp.reshape(CR.H * CR * self.x, image_size) assert yp.sumb(yp.abs(y_3 - y_4)) < eps # Check gradient CR.gradient_check()
def test_operator_crop(self): ''' Crop Operator ''' # Generate Crop Operator crop_size = (image_size[0] // 2, image_size[1] // 2) CR = ops.Crop(image_size, crop_size, pad_value=0, dtype=global_dtype, backend=global_backend) # Check forward operator crop_start = tuple(np.asarray(image_size) // 2 - np.asarray(crop_size) // 2) y_1 = yp.changeBackend(CR * self.x, 'numpy') y_2 = yp.changeBackend(yp.crop(self.x, crop_size, crop_start), 'numpy') assert yp.sumb(yp.abs(y_1 - y_2)) < eps # Check Adjoint Operator pad_size = [int((image_size[i] - crop_size[i]) / 2) for i in range(len(image_size))] y_3 = yp.pad(yp.crop(self.x, crop_size, crop_start), image_size, crop_start, pad_value=0) y_4 = CR.H * CR * self.x assert yp.sumb(yp.abs(y_3 - y_4)) < eps # Check gradient CR.gradient_check()
def test_operator_exponential(self): L2 = ops.L2Norm(image_size) F = ops.FourierTransform(image_size) EXP = ops.Exponential(image_size) # Forward model assert yp.sumb(yp.abs(yp.changeBackend(EXP * self.x, 'numpy') - np.exp(yp.changeBackend(self.x, 'numpy')))) < eps # Check gradient EXP.gradient_check() # Generate composite operator D = ops.Diagonalize(self.h) L2 = ops.L2Norm(image_size) EXP_COMP = L2 * F * EXP EXP_COMP.gradient_check() EXP_COMP_2 = L2 * F * EXP * D EXP_COMP_2.gradient_check()
def test_operator_stacking_linear(self): # Create list of operators op_list_linear = [ ops.FourierTransform(image_size, dtype=global_dtype, backend=global_backend), ops.Identity(image_size, dtype=global_dtype, backend=global_backend), ops.Exponential(image_size, dtype=global_dtype, backend=global_backend) ] # Horizontally stacked operators H_l = ops.Hstack(op_list_linear) # Vertically stack x for forward operator x_np = yp.changeBackend(self.x, 'numpy') x3 = yp.changeBackend(np.vstack((x_np, x_np, x_np)), global_backend) # Check forward operation y2 = yp.zeros(op_list_linear[0].N, op_list_linear[0].dtype, op_list_linear[0].backend) for op in op_list_linear: y2 = y2 + op * self.x assert yp.sumb(yp.abs(yp.changeBackend(H_l(x3) - y2, 'numpy'))) < eps, "%.4e" % yp.sumb(yp.abs(H_l(x3) - y2)) # Check gradient H_l.gradient_check() # Create vertically stacked operator V_l = ops.Vstack(op_list_linear) # Check forward operator y3 = np.empty((0,image_size[1]), dtype=yp.getNativeDatatype(global_dtype, 'numpy')) for index, op in enumerate(op_list_linear): y3 = np.append(y3, (op * self.x), axis=0) y3 = yp.changeBackend(y3, global_backend) assert yp.sumb(yp.abs(V_l * self.x - y3)) < eps, "%.4e" % yp.sumb(yp.abs(V_l * vec(x) - y3)) # Check gradient V_l.gradient_check()
def test_operator_shift(self): ''' Shift Operator ''' # Normal shift shift = (0, 10) # should be y, x T = ops.Shift(image_size, shift) def shift_func(x, shift): x = yp.changeBackend(self.x, 'numpy') for ax, sh in enumerate(shift): x = np.roll(self.x, int(sh), axis=ax) return(x) # Check Forward Operator y_1 = yp.changeBackend(T * self.x, 'numpy') y_2 = shift_func(yp.changeBackend(self.x, 'numpy'), shift) assert yp.sumb(yp.abs(y_1 - y_2)) < eps # Check Adjoint Operator assert yp.sumb(yp.abs(T.H * T * self.x - self.x)) < eps # Check gradient T.gradient_check()
def test_operator_phase_ramp(self): eps_phase_ramp = 1e-4 shift = yp.changeBackend(np.asarray((-5,3)).astype(yp.getNativeDatatype(global_dtype, 'numpy')), global_backend) # Generate phase ramp R = ops.PhaseRamp(image_size) r = R * shift F = ops.FourierTransform(image_size, dtype=global_dtype, normalize=False, backend=global_backend) D_R = ops.Diagonalize(r, dtype=global_dtype) S_R = F.H * D_R * F # Pixel-wise shift operator S = ops.Shift(image_size, shift) # Check that phase ramp is shifting by correct amount assert yp.sumb(yp.abs(yp.changeBackend(S_R * self.x, 'numpy') - yp.changeBackend(S * self.x, 'numpy'))) < 1e-3 # Check gradient of phase ramp convolution S_R.gradient_check() # Check gradient of phase ramp R.gradient_check(eps=1e-1)
def test_operator_sum(self): ''' Element-wise Sum Operator ''' axis_to_sum = (0,1) Σ = ops.Sum(image_size, axes=axis_to_sum) # Check forward operator y_1 = yp.changeBackend(Σ * self.x, 'numpy') y_2 = yp.sumb(yp.changeBackend(self.x, 'numpy'), axes=axis_to_sum) assert yp.abs(yp.sumb(y_1 - y_2)) < eps # Check adjoint operator y_3 = yp.changeBackend(Σ.H * Σ * self.x, 'numpy') reps = [1, ] * len(image_size) axes = list(range(len(image_size))) if axis_to_sum is 'all' else axis_to_sum scale = 1 for axis in axes: reps[axis] = image_size[axis] scale *= 1 / image_size[axis] y_4 = yp.tile(y_2, reps) * scale assert yp.sumb(yp.abs(y_3 - y_4)) < eps # Check gradient Σ.gradient_check(eps=1)
def Derivative(N, axis=0, dtype=None, backend=None, label=None): # Configure backend and datatype backend = backend if backend is not None else config.default_backend dtype = dtype if dtype is not None else config.default_dtype # Generate shift grid using numpy r_x = np.arange(-N[1] / 2, N[1] / 2, 1.0) / N[1] r_y = np.arange(-N[0] / 2, N[0] / 2, 1.0) / N[0] grid_np = np.meshgrid(r_x, r_y) # Convert to correct backend and datatype grid = [] for g in grid_np: grid.append( changeBackend(g.astype(getNativeDatatype(dtype, 'numpy')), backend)) # Generate operator G = Diagonalize(2 * np.pi * 1j * grid[axis], dtype=dtype, backend=backend) F = FourierTransform(N, dtype=dtype, backend=backend) op = F.H * G * F # Set label and latex representation if label is None: if (axis == 0): op.label = "∂y" latex_str = "\\frac{\partial}{\partial y}" elif (axis == 1): op.label = "∂x" latex_str = "\\frac{\partial}{\partial x}" else: op.label = label latex_str = label # Set latex to be just label def repr_latex(latex_input=None): if latex_input is None: return latex_str else: return latex_str + ' \\times ' + latex_input op.repr_latex = repr_latex # Set condition number to 1 TODO: The operators above should have condition 1 op.condition_number = 1.0 return (op)
def setup_method(self, test_method): # Load object and crop to size x_0 = yp.rand(image_size) # Convert object to desired backend self.x = yp.changeBackend(x_0, global_backend) # Generate convolution kernel h h_size = np.array([4, 4]) self.h = yp.zeros(image_size, global_dtype, global_backend) self.h[image_size[0] // 2 - h_size[0] // 2:image_size[0] // 2 + h_size[0] // 2, image_size[1] // 2 - h_size[1] // 2:image_size[1] // 2 + h_size[1] // 2] = yp.randn((h_size[0], h_size[1]), global_dtype, global_backend) # A = ops.Convolution(image_size, h, dtype=global_dtype, fft_backend='numpy', backend=global_backend) self.A = ops.FourierTransform(image_size, dtype=global_dtype, backend=global_backend, center=True) self.y = self.A(yp.vectorize(self.x))
def test_operator_wavelet(self): ''' Wavelet Transform Operator ''' import pywt wavelet_list = ['db1', 'haar', 'rbio1.1', 'bior1.1', 'bior4.4', 'sym12'] for wavelet_test in wavelet_list: # Wavelet Transform W = ops.WaveletTransform(image_size, wavelet_type=wavelet_test, use_cycle_spinning=False) # Check forward operation coeffs = pywt.wavedecn(self.x, wavelet=wavelet_test) x_wavelet, coeff_slices = pywt.coeffs_to_array(coeffs) assert yp.sumb(yp.abs(yp.changeBackend(W * self.x, 'numpy') - x_wavelet)) < eps, "Difference %.6e" # Check inverse operation coeffs_from_arr = pywt.array_to_coeffs(x_wavelet, coeff_slices) cam_recon = pywt.waverecn(coeffs_from_arr, wavelet=wavelet_test) assert yp.sumb(yp.abs(W.H * W * self.x - self.x)) < 1e-2 # Ensure that the wavelet transform isn't just identity (weird bug) if W.shape[1] is yp.size(self.x): assert yp.sumb(yp.abs(W * yp.vec(self.x) - yp.vec(self.x))) > 1e-2, "%s" % wavelet_test
def add(signal, type='gaussian', **kwargs): """ Add noise to a measurement""" if type == 'gaussian': snr = kwargs.get('snr', 1.0) signal_mean = yp.abs(yp.mean(signal)) noise_gaussian = np.random.normal(0, signal_mean / snr, yp.shape(signal)) return signal + noise_gaussian elif type == 'poisson': noise_poisson = np.random.poisson(np.real(signal)) return signal + noise_poisson elif type == 'saltpepper' or type == 'saltandpepper': salt_pepper_ratio = kwargs.get('ratio', 0.5) salt_pepper_saturation = kwargs.get('saturation', 0.004) output = yp.changeBackend(signal, 'numpy') # Salt mode num_salt = np.ceil(salt_pepper_saturation * signal.size * salt_pepper_ratio) coords = [ np.random.randint(0, i - 1, int(num_salt)) for i in signal.shape ] output[tuple(coords)] = 1 # Pepper mode num_pepper = np.ceil(salt_pepper_saturation * signal.size * (1. - salt_pepper_ratio)) coords = [ np.random.randint(0, i - 1, int(num_pepper)) for i in signal.shape ] output[tuple(coords)] = 0 return yp.cast_like(output, signal) elif type == 'speckle': noise_speckle = yp.randn(signal.shape) return signal + signal * noise_speckle
def test_matmul(self): matrix_size = (10, 20) m = bops.rand(matrix_size, dtype, 'arrayfire') xm = bops.rand(matrix_size[1], dtype, 'arrayfire') assert np.sum( np.abs( bops.changeBackend(bops.matmul(m, xm), 'numpy') - bops.changeBackend(m, 'numpy').dot( bops.changeBackend(xm, 'numpy')))) < eps # Check matrix multiply (numpy to arrayfire) m_np = bops.rand(matrix_size, dtype, 'numpy') xm_np = bops.rand(matrix_size[1], dtype, 'numpy') m_ocl = bops.changeBackend(m_np, 'arrayfire') xm_ocl = bops.changeBackend(xm_np, 'arrayfire') assert np.sum( np.abs( bops.changeBackend(bops.matmul(m_ocl, xm_ocl), 'numpy') - m_np.dot(xm_np))) < eps
def shift_func(x, shift): x = yp.changeBackend(self.x, 'numpy') for ax, sh in enumerate(shift): x = np.roll(self.x, int(sh), axis=ax) return(x)