def runNetPasses(sess, target_placeholder, target_func, net_output, cnp, residual): """Runs the net for num_passes. Step 3 in the paper. Args: target_placeholder: (tf.placeholder shape [1, num_samples]) For feeding the target function to the net. target_func: (np.array of float shape [1, num_samples]) The initial target function. net_output: (tf.Tensor of float shape [1, num_samples]) The net output, V. cnp: The output commands and parameters from each generator, see below. residual: target_func - net_output. cnp stands for "commands and parameters". cnp[i] is a list [commands, multiplier, offset] for generator i. commands is a Tensor shape [1, 2] for Phi_i and lambda_i. multiplier and offset are each a Tensor shape [1, 1] for A_i and k_i. Returns: A list of the computed cnps for each pass. """ predictions = [] # Sum of the net_output from the first i+1 passes. # List of cnps for each pass. pass_cnps = [] pass_target = target_func for pass_num in range(0, num_passes): with sess.as_default(): net_output_np, cnp_np, residual_np = sess.run( [net_output, cnp, residual], feed_dict={target_placeholder: pass_target}) pass_target = residual_np if not predictions: predictions.append(net_output_np) else: predictions.append(net_output_np + predictions[-1]) pass_cnps.append(cnp_np) error = math.sqrt(np.sum(np.square(target_func - predictions[-1]))) print('Pass %d: error sqrt (sum(error*error)): %f' % (pass_num, error)) utils.graphBatch([target_func[0]], FLAGS.out_dir + '/target.png', title = 'Target', ylim=[-1.5, 1.5]) utils.graphBatch( [target_func[0]] + [p[0] for p in predictions], FLAGS.out_dir + '/networkPredictions.png', title='Target + Network Predictions with Residuals', labels=['Target', 'Network Prediction'] + [ '+Residual Correction %d' % i for i in range(1, len(predictions))], ylim=[-1.5, 1.5]) return pass_cnps
def reweightSampledBases(bases_before_params, target_func): """Compute optimal parameters to fit the bases to the target_func. Step 5 in the paper. Writes graphs comparing the optimized parameters to the target_func into --out_dir/refit*.png. Args: bases_before_params: The sampled bases produced by the commands. List of length len(generator_specs) * num_passes since every generator in every pass produces one command. Each entry is an np.array shape [1, num_samples]. """ # Av is shape [num_samples, len(bases_before_params) + 1]. # As described in Step 5, we compute just one Delta parameter that # is the sum of k_i. The added row of Av computes Delta. Av = np.transpose(bases_before_params) Av = np.concatenate([Av, np.ones([num_samples, 1])], axis=1) # bv is shape [num_samples, 1] bv = np.transpose(target_func) A = tf.placeholder(tf.float32, Av.shape, name='A') b = tf.placeholder(tf.float32, bv.shape, name='b') linsol = tf.linalg.lstsq(A, b) sess = tf.Session() done = False while not done: try: with sess.as_default(): x = sess.run(linsol, feed_dict={A: Av, b: bv}) done = True except tf.errors.InvalidArgumentError as e: print('Cholesky likely failed. Adding miniscule noise.') for c in range(Av.shape[1] - 1): Av[random.randint(0, Av.shape[0] - 1)][c] *= random.uniform( 0.999, 1.001) ans = np.matmul(Av, x) err = ans - bv print('linSolve final error:', math.sqrt(np.sum(err * err))) utils.graphBatch([target_func[0], ans], FLAGS.out_dir + '/refit.png', title='After Reweighting', labels=['Target', 'After Reweighting'], ylim=[-1.5, 1.5])
def reconstructUsingBases(generator_specs, pass_cnps, target_func): """Apply the commands to the basis (rather than generators). Step 4 in the paper. Writes graphs to --out_dir/extractedCommands*.png comparing the target_func to the basis after applying the multiplier and offset. pass_cnps contains the commands and parameters for each pass and for each generator. Returns: (list of np.array shape [1, num_samples]) Each entry is a sampled basis for each generator before the parameters are applied. """ # The sampled basis for each function before applying the multiplier # and offset. There are num_passes * len(generator_specs) bases in # this list. bases_before_params = [] # The sampled function after each pass, including multiplier and # offset. Written to the graphs. command_fits = [] for pass_num in range(num_passes): current = np.zeros([num_samples]) for gen_num in range(len(generator_specs)): start = pass_cnps[pass_num][gen_num][0][0][0] # Phi period = pass_cnps[pass_num][gen_num][0][0][1] # lambda multiplier = pass_cnps[pass_num][gen_num][1][0][0] # A offset = pass_cnps[pass_num][gen_num][2][0][0] # k print('Pass %d function %d: command (unscaled) (%f, %f),' ' multiplier %f, offset %f' % (pass_num, gen_num, start, period, multiplier, offset)) sampled_basis = functions.applyFunc( start, period, num_samples, generator_specs[gen_num].function_name) bases_before_params.append(sampled_basis.copy()) sampled_basis *= multiplier sampled_basis += offset current += sampled_basis if pass_num == 0: command_fits.append(current) else: command_fits.append(current + command_fits[-1]) err = target_func[0] - command_fits[-1] print('recon based on commands iteration: %d : %f' % (pass_num, math.sqrt(np.sum(err * err)))) utils.graphBatch( [target_func[0]] + command_fits, FLAGS.out_dir + '/extractedCommands.png', title='Target + Extracted Commands', labels=['Target'] + ['Extracted Commands (pass %d)' % i for i in range(len(command_fits))], ylim=[-1.5, 1.5]) return bases_before_params