def draw_das(D, ax): idx_img = info['show_reconstruction'] sampler = D.sampler() S, _, _ = sampler.decode(D[idx_img]) sky_model = D.ground_truth[idx_img] A = phased_array.steering_operator(D.XYZ, D.R, D.wl) alpha = 1 / (2 * pylinalg.eighMax(A)) beta = 2 * D.lambda_[idx_img] * alpha * (1 - D.gamma) + 1 exec_time = time.time() das = spectral.DAS(D.XYZ, S, D.wl, D.R) * 2 * alpha / beta exec_time = time.time() - exec_time if info['interpolation_order'] is not None: N = info['interpolation_order'] approximate_kernel = True if (N > 15) else False interp = interpolate.Interpolator(N, approximate_kernel) N_s = N_px = D.R.shape[1] das = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=das.reshape((1, N_px)), r=D.R) das = np.clip(das, a_min=0, a_max=None) das_plot = s2image.Image(data=das, grid=D.R) das_plot.draw(catalog=sky_model.xyz, projection=info['projection'], use_contours=False, catalog_kwargs=dict(edgecolor='g', ), ax=ax) ax.set_title(f'DAS, {exec_time:.02f} [s]')
def draw_apgd_filter(D, ax): R_focus = np.mean(D.R, axis=1) R_focus /= linalg.norm(R_focus) idx_focus = np.argmax(R_focus @ D.R) A = phased_array.steering_operator(D.XYZ, D.R, D.wl) N_px = D.R.shape[1] alpha = 1 / (2 * pylinalg.eighMax(A)) beta = 2 * np.median(D.lambda_) * alpha * (1 - D.gamma) + 1 psf = pylinalg.psf_exp(D.XYZ, D.R, D.wl, center=R_focus) filter = (e(idx_focus, N_px) - 2 * alpha * psf) / beta if info['interpolation_order'] is not None: N = info['interpolation_order'] approximate_kernel = True if (N > 15) else False interp = interpolate.Interpolator(N, approximate_kernel) N_s = N_px = D.R.shape[1] filter = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=filter.reshape((1, N_px)), r=D.R) filter = np.clip(filter, a_min=0, a_max=None) filter_plot = s2image.Image(data=filter, grid=D.R) filter_plot.draw(projection=info['projection'], use_contours=False, catalog_kwargs=dict(edgecolor='g', ), ax=ax) ax.set_title(r'$p_{\theta}^{APGD}\left(\widetilde{L}\right)$')
def draw_apgd_psf(D, ax): R_focus = np.mean(D.R, axis=1) R_focus /= linalg.norm(R_focus) A = phased_array.steering_operator(D.XYZ, D.R, D.wl) alpha = 1 / (2 * pylinalg.eighMax(A)) beta = 2 * np.median(D.lambda_) * alpha * (1 - D.gamma) + 1 psf = (pylinalg.psf_exp(D.XYZ, D.R, D.wl, center=R_focus) * (2 * alpha / beta)) if info['interpolation_order'] is not None: N = info['interpolation_order'] approximate_kernel = True if (N > 15) else False interp = interpolate.Interpolator(N, approximate_kernel) N_s = N_px = D.R.shape[1] psf = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=psf.reshape((1, N_px)), r=D.R) psf = np.clip(psf, a_min=0, a_max=None) psf_plot = s2image.Image(data=psf, grid=D.R) psf_plot.draw(projection=info['projection'], use_contours=False, catalog_kwargs=dict(edgecolor='g', ), ax=ax) ax.set_title(r'$\Psi_{APGD}(r, r_{0})$')
def get_field(D, P, idx_img, img_type): """ Parameters ---------- D : list(:py:class:`~deepwave.nn.DataSet`) (9,) multi-frequency datasets. P : list(:py:class:`~deepwave.nn.crnn.Parameter`) (9,) multi-frequency trained parameters. idx_img : int Image index img_type : str One of ['APGD', 'RNN', 'DAS'] Returns ------- I : :py:class:`~numpy.ndarray` (9, N_px) frequency intensities of specified image. """ I = [] for idx_freq in range(9): Df, Pf = D[idx_freq], P[idx_freq] N_antenna = Df.XYZ.shape[1] N_px = Df.R.shape[1] K = int(Pf['K']) parameter = crnn.Parameter(N_antenna, N_px, K) sampler = Df.sampler() A = phased_array.steering_operator(Df.XYZ, Df.R, Df.wl) if img_type == 'APGD': _, I_apgd, _ = sampler.decode(Df[idx_img]) I.append(I_apgd) elif img_type == 'RNN': Ln, _ = graph.laplacian_exp(Df.R, normalized=True) afunc = lambda _: func.retanh(Pf['tanh_lin_limit'], _) p_opt = Pf['p_opt'][np.argmin(Pf['v_loss'])] S, _, I_prev = sampler.decode(Df[idx_img]) N_layer = Pf['N_layer'] rnn_eval = crnn.Evaluator(N_layer, parameter, p_opt, Ln, afunc) I_rnn = rnn_eval(S, I_prev) I.append(I_rnn) elif img_type == 'DAS': S, _, _ = sampler.decode(Df[idx_img]) alpha = 1 / (2 * pylinalg.eighMax(A)) beta = 2 * Df.lambda_[idx_img] * alpha * (1 - Df.gamma) + 1 I_das = spectral.DAS(Df.XYZ, S, Df.wl, Df.R) * 2 * alpha / beta I.append(I_das) else: raise ValueError(f'Parameter[img_type] invalid.') I = np.stack(I, axis=0) return I
def train_network(args): """ Parameters ---------- args : :py:class:`~argparse.Namespace` Returns ------- opt : dict p_opt : :py:class:`~numpy.ndarray` (N_epoch + 1, N_cell) optimized parameter per epoch. `p_opt[0] = p_apgd` iter_loss : :py:class:`~numpy.ndarray` (N_epoch, N_batch) loss function value per (epoch, batch) on training set. t_loss : :py:class:`~numpy.ndarray` (N_epoch + 1,) loss function value per epoch on training set. v_loss : :py:class:`~numpy.ndarray` (N_epoch + 1,) loss function value per epoch on validation set. t : :py:class:`~numpy.ndarray` (N_epoch,) execution time [s] per epoch. Includes time to compute training/validation loss. idx_t : :py:class:`~numpy.ndarray` (N_k1,) sample indices used for training set. idx_v : :py:class:`~numpy.ndarray` (N_k2,) sample indices used for validation set. K : int Order of polynomial filter. D_lambda : float tau_lambda : float N_layer : int psf_threshold : float tanh_lin_limit : float lr : float mu : float batch_size : int """ if args.seed is not None: np.random.seed(args.seed) D = nn.DataSet.from_file(str(args.dataset)) A = phased_array.steering_operator(D.XYZ, D.R, D.wl) N_antenna, N_px = A.shape sampler = nn.Sampler(N_antenna, N_px) # Set optimization initial point. p_apgd, K = crnn.APGD_Parameter(D.XYZ, D.R, D.wl, lambda_=np.median(D.lambda_), gamma=D.gamma, L=2 * pylinalg.eighMax(A), eps=args.psf_threshold) parameter = crnn.Parameter(N_antenna, N_px, K) p0 = p_apgd.copy() if args.random_initializer: p_mu, p_D, p_tau = parameter.decode(p0) if not args.fix_mu: mu_step = np.abs(p_mu[~np.isclose(p_mu, 0)]).min() p_mu[:] = mu_step * np.random.randn(K + 1) if not args.fix_tau: tau_step = np.abs(p_tau[~np.isclose(p_tau, 0)]).min() p_tau[:] = tau_step * np.random.randn(N_px) if not args.fix_D: D_step = np.abs(p_D[~np.isclose(p_D, 0)]).min() / 2 # because complex-valued. p_D[:] = D_step * ( np.random.randn(N_antenna, N_px) + 1j * np.random.randn(N_antenna, N_px)) R_laplacian, _ = graph.laplacian_exp(D.R, normalized=True) afunc = (lambda x: func.retanh(args.tanh_lin_limit, x), lambda x: func.d_retanh(args.tanh_lin_limit, x)) trainable_parameter = (('mu', not args.fix_mu), ('D', not args.fix_D), ('tau', not args.fix_tau)) sample_loss = crnn.SampleLossFunction(args.N_layer, parameter, sampler, R_laplacian, args.loss, afunc, trainable_parameter) ridge_loss = crnn.D_RidgeLossFunction(args.D_lambda, parameter) laplacian_loss = crnn.LaplacianLossFunction(R_laplacian, args.tau_lambda, parameter) sgd_solver = optim.StochasticGradientDescent(func=[sample_loss, ridge_loss, laplacian_loss], batch_size=args.batch_size, N_epoch=args.N_epoch, alpha=args.lr, mu=args.mu, verbosity='HIGH') log_fname = (pathlib.Path(args.parameter.parent) / (args.parameter.stem + ".log")) logging.basicConfig(level=logging.DEBUG, format='%(asctime)s | %(message)s', filename=log_fname, filemode='w') # Setup logging to stdout. console = logging.StreamHandler(sys.stdout) console.setLevel(logging.DEBUG) console_formatter = logging.Formatter('%(asctime)s | %(message)s') console.setFormatter(console_formatter) logging.getLogger(__name__).addHandler(console) logging.info(str(args)) ### Dataset Preprocessing: drop all-0 samples + permutation _, I, _ = sampler.decode(D[:]) sample_mask = ~np.isclose(I.sum(axis=1), 0) if args.tv_index is None: # Random split idx_valid = np.flatnonzero(sample_mask) idx_sample = np.random.permutation(idx_valid) N_sample = len(idx_valid) idx_ts = idx_sample[int(N_sample * args.tv_ratio):] idx_vs = idx_sample[:int(N_sample * args.tv_ratio)] else: # Deterministic split idx_tv = np.load(args.tv_index) if not (('idx_train' in idx_tv) and ('idx_test' in idx_tv)): raise ValueError('Parameter[tv_index] does not have keys "idx_train" and "idx_test".') idx_ts = idx_tv['idx_train'] if not (argcheck.has_integers(idx_ts) and np.all((0 <= idx_ts) & (idx_ts < len(D)))): raise ValueError('Specified "idx_ts" values must be integer and in {0, ..., len(D) - 1}.') idx_vs = idx_tv['idx_test'] if not (argcheck.has_integers(idx_vs) and np.all((0 <= idx_vs) & (idx_vs < len(D)))): raise ValueError('Specified "idx_vs" values must be integer and in {0, ..., len(D) - 1}.') idx_invalid = np.flatnonzero(~sample_mask) idx_ts = np.setdiff1d(idx_ts, idx_invalid) idx_vs = np.setdiff1d(idx_vs, idx_invalid) D_ts = nn.DataSet(D[idx_ts], D.XYZ, D.R, D.wl, ground_truth=[D.ground_truth[idx] for idx in idx_ts], lambda_=np.array([np.median(D.lambda_[idx_ts])] * len(idx_ts)), gamma=D.gamma, N_iter=D.N_iter[idx_ts], tts=D.tts[idx_ts]) D_vs = nn.DataSet(D[idx_vs], D.XYZ, D.R, D.wl, ground_truth=[D.ground_truth[idx] for idx in idx_vs], lambda_=np.array([np.median(D.lambda_[idx_vs])] * len(idx_vs)), gamma=D.gamma, N_iter=D.N_iter[idx_vs], tts=D.tts[idx_vs]) out = sgd_solver.fit(D_ts, D_vs, p0, file_name=args.parameter) # Augment output with extra information. out = dict(**out, D_lambda=args.D_lambda, tau_lambda=args.tau_lambda, N_layer=args.N_layer, psf_threshold=args.psf_threshold, tanh_lin_limit=args.tanh_lin_limit, lr=args.lr, mu=args.mu, batch_size=args.batch_size, K=K, idx_t=idx_ts, idx_v=idx_vs, loss=args.loss) return out
def process(args): file = pathlib.Path(args.dataset).expanduser().absolute() if not (file.exists() and (file.suffix == '.npz')): raise ValueError('Dataset is non-conformant.') D = nn.DataSet.from_file(str(file)) N_sample = len(D) if not (0 <= args.img_idx < N_sample): raise ValueError('Parameter[img_idx] is out-of-bounds.') S, I_apgd, I_prev = D.sampler().decode(D[args.img_idx]) I_das = spectral.DAS(D.XYZ, S, D.wl, D.R) # Rescale DAS to lie on same range as APGD A = phased_array.steering_operator(D.XYZ, D.R, D.wl) alpha = 1 / (2 * pylinalg.eighMax(A)) beta = 2 * D.lambda_[args.img_idx] * alpha * (1 - D.gamma) + 1 I_das *= (2 * alpha) / beta if args.interpolation_order is not None: N = args.interpolation_order approximate_kernel = True if (N > 15) else False interp = interpolate.Interpolator(N, approximate_kernel) N_s = N_px = D.R.shape[1] I_prev = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=I_prev.reshape((1, N_px)), r=D.R) I_prev = np.clip(I_prev, a_min=0, a_max=None) I_apgd = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=I_apgd.reshape((1, N_px)), r=D.R) I_apgd = np.clip(I_apgd, a_min=0, a_max=None) I_das = interp.__call__(weight=np.ones((N_s, )), support=D.R, f=I_das.reshape((1, N_px)), r=D.R) I_das = np.clip(I_das, a_min=0, a_max=None) fig = plt.figure() ax_prev = fig.add_subplot(131) ax_apgd = fig.add_subplot(132) ax_das = fig.add_subplot(133) s2image.Image(I_prev, D.R).draw(catalog=D.ground_truth[args.img_idx].xyz, projection=args.projection, catalog_kwargs=dict(edgecolor='g', ), ax=ax_prev) ax_prev.set_title(r'$APGD_{init}$') s2image.Image(I_apgd, D.R).draw(catalog=D.ground_truth[args.img_idx].xyz, projection=args.projection, catalog_kwargs=dict(edgecolor='g', ), ax=ax_apgd) ax_apgd.set_title('APGD') s2image.Image(I_das, D.R).draw(catalog=D.ground_truth[args.img_idx].xyz, projection=args.projection, catalog_kwargs=dict(edgecolor='g', ), ax=ax_das) ax_das.set_title('DAS') fig.show()
def solve(S, A, lambda_=None, gamma=0.5, L=None, d=50, x0=None, eps=1e-3, N_iter_max=200, verbosity='LOW', momentum=True): """ APGD solution to the Acoustic Camera problem. (Algorithm 3.1) Parameters ---------- S : :py:class:`~numpy.ndarray` (M, M) visibility matrix A : :py:class:`~numpy.ndarray` (M, N) system steering matrix. lambda_ : float Regularization parameter. If `None`, then it is chosen according to Remark 3.4. gamma : float Linear trade-off between lasso and ridge regularizers. L : float Lipschitz constant of the gradient of the smooth function being optimized. If `None`, then it is estimated using :py:func:`~deepwave.tools.math.linalg.eighMax`. d : float Weight parameter as defined in [1]. x0 : :py:class:`~numpy.ndarray` (N,) initial intensity field estimate. Defaults to 0 if not explicitly initialized. eps : float Relative tolerance stopping threshold. N_iter_max : int Maximum number of iterations. verbosity : str One of 'NONE', 'LOW', 'HIGH', 'ALL'. momentum : bool If :py:class:`False`, disable Nesterov acceleration. Returns ------- I_opt : dict sol : :py:class:`~numpy.ndarray` (N,) optimal intensity field. solver : str The used solver. crit : {‘ATOL’, ‘DTOL’, ‘RTOL’, ‘XTOL’, ‘MAXIT’} The used stopping criterion. niter : int The number of iterations. time : float The execution time in seconds. objective : :py:class:`~numpy.ndarray` The successive evaluations of the objective function at each iteration. backtrace : :py:class:`~numpy.ndarray` (N_iter + 1, N) successive values of the objective parameter at each iteration. backtrace[0] holds the initial solution. L : float Lipschitz constant of the gradient of the smooth function being optimized. lambda_ : float Regularization parameter gamma : float Linear trade-off between lasso and ridge regularizers. Notes ----- [1] On the Convergence of the Iterates of the "Fast Iterative [Shrinkage/Thresholding Algorithm" [Chambolle, Dossal] """ M, N = A.shape if not ((S.shape[0] == S.shape[1]) and (S.shape[0] == M)): raise ValueError('Parameters[S, A] are inconsistent.') if not np.allclose(S, S.conj().T): raise ValueError('Parameter[S] must be Hermitian.') if not (0 <= gamma <= 1): raise ValueError('Parameter[gamma] is must lie in [0, 1].') if L is None: L = 2 * pylinalg.eighMax(A) elif L <= 0: raise ValueError('Parameter[L] must be positive.') if d < 2: raise ValueError(r'Parameter[d] must be \ge 2.') if x0 is None: x0 = np.zeros((N, ), dtype=np.float64) elif np.any(x0 < 0): raise ValueError('Parameter[x0] must be non-negative.') if not (0 < eps < 1): raise ValueError('Parameter[eps] must lie in (0, 1).') if N_iter_max < 1: raise ValueError('Parameter[N_iter_max] must be positive.') if verbosity not in ('NONE', 'LOW', 'HIGH', 'ALL'): raise ValueError('Unknown verbosity specification.') if lambda_ is None: if gamma > 0: # Procedure of Remark 3.4 # When gamma == 0, we fall into the ridge-regularizer case, so no # need to do the following. func = [l2_loss(S, A), elastic_net_loss(lambda_=0, gamma=gamma)] solver = opt.solvers.forward_backward( accel=ground_truth_accel(d, L, momentum=False)) I_opt = _solve(functions=func, x0=np.zeros((N, )), solver=solver, rtol=eps, maxit=1, verbosity=verbosity) alpha = 1 / L lambda_ = np.max(I_opt['sol']) / (10 * alpha * gamma) else: lambda_ = 1 # Anything will do. elif lambda_ < 0: raise ValueError('Parameter[lambda_] must be non-negative.') func = [l2_loss(S, A), elastic_net_loss(lambda_, gamma)] solver = opt.solvers.forward_backward( accel=ground_truth_accel(d, L, momentum)) I_opt = _solve(functions=func, x0=x0.copy(), solver=solver, rtol=eps, maxit=N_iter_max, verbosity=verbosity) I_opt['gamma'] = gamma I_opt['lambda_'] = lambda_ I_opt['L'] = L return I_opt