Spaces:
Runtime error
Runtime error
| # Copyright 2016 The TensorFlow Authors All Rights Reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # ============================================================================== | |
| """Various losses for training navigation agents. | |
| Defines various loss functions for navigation agents, | |
| compute_losses_multi_or. | |
| """ | |
| import os, numpy as np | |
| import matplotlib.pyplot as plt | |
| import tensorflow as tf | |
| from tensorflow.contrib import slim | |
| from tensorflow.contrib.slim import arg_scope | |
| from tensorflow.contrib.slim.nets import resnet_v2 | |
| from tensorflow.python.training import moving_averages | |
| import logging | |
| from src import utils | |
| import src.file_utils as fu | |
| from tfcode import tf_utils | |
| def compute_losses_multi_or(logits, actions_one_hot, weights=None, | |
| num_actions=-1, data_loss_wt=1., reg_loss_wt=1., | |
| ewma_decay=0.99, reg_loss_op=None): | |
| assert(num_actions > 0), 'num_actions must be specified and must be > 0.' | |
| with tf.name_scope('loss'): | |
| if weights is None: | |
| weight = tf.ones_like(actions_one_hot, dtype=tf.float32, name='weight') | |
| actions_one_hot = tf.cast(tf.reshape(actions_one_hot, [-1, num_actions], | |
| 're_actions_one_hot'), tf.float32) | |
| weights = tf.reduce_sum(tf.reshape(weights, [-1, num_actions], 're_weight'), | |
| reduction_indices=1) | |
| total = tf.reduce_sum(weights) | |
| action_prob = tf.nn.softmax(logits) | |
| action_prob = tf.reduce_sum(tf.multiply(action_prob, actions_one_hot), | |
| reduction_indices=1) | |
| example_loss = -tf.log(tf.maximum(tf.constant(1e-4), action_prob)) | |
| data_loss_op = tf.reduce_sum(example_loss * weights) / total | |
| if reg_loss_op is None: | |
| if reg_loss_wt > 0: | |
| reg_loss_op = tf.add_n(tf.losses.get_regularization_losses()) | |
| else: | |
| reg_loss_op = tf.constant(0.) | |
| if reg_loss_wt > 0: | |
| total_loss_op = data_loss_wt*data_loss_op + reg_loss_wt*reg_loss_op | |
| else: | |
| total_loss_op = data_loss_wt*data_loss_op | |
| is_correct = tf.cast(tf.greater(action_prob, 0.5, name='pred_class'), tf.float32) | |
| acc_op = tf.reduce_sum(is_correct*weights) / total | |
| ewma_acc_op = moving_averages.weighted_moving_average( | |
| acc_op, ewma_decay, weight=total, name='ewma_acc') | |
| acc_ops = [ewma_acc_op] | |
| return reg_loss_op, data_loss_op, total_loss_op, acc_ops | |
| def get_repr_from_image(images_reshaped, modalities, data_augment, encoder, | |
| freeze_conv, wt_decay, is_training): | |
| # Pass image through lots of convolutional layers, to obtain pool5 | |
| if modalities == ['rgb']: | |
| with tf.name_scope('pre_rgb'): | |
| x = (images_reshaped + 128.) / 255. # Convert to brightness between 0 and 1. | |
| if data_augment.relight and is_training: | |
| x = tf_utils.distort_image(x, fast_mode=data_augment.relight_fast) | |
| x = (x-0.5)*2.0 | |
| scope_name = encoder | |
| elif modalities == ['depth']: | |
| with tf.name_scope('pre_d'): | |
| d_image = images_reshaped | |
| x = 2*(d_image[...,0] - 80.0)/100.0 | |
| y = d_image[...,1] | |
| d_image = tf.concat([tf.expand_dims(x, -1), tf.expand_dims(y, -1)], 3) | |
| x = d_image | |
| scope_name = 'd_'+encoder | |
| resnet_is_training = is_training and (not freeze_conv) | |
| with slim.arg_scope(resnet_v2.resnet_utils.resnet_arg_scope(resnet_is_training)): | |
| fn = getattr(tf_utils, encoder) | |
| x, end_points = fn(x, num_classes=None, global_pool=False, | |
| output_stride=None, reuse=None, | |
| scope=scope_name) | |
| vars_ = slim.get_variables_to_restore() | |
| conv_feat = x | |
| return conv_feat, vars_ | |
| def default_train_step_kwargs(m, obj, logdir, rng_seed, is_chief, num_steps, | |
| iters, train_display_interval, | |
| dagger_sample_bn_false): | |
| train_step_kwargs = {} | |
| train_step_kwargs['obj'] = obj | |
| train_step_kwargs['m'] = m | |
| # rng_data has 2 independent rngs, one for sampling episodes and one for | |
| # sampling perturbs (so that we can make results reproducible. | |
| train_step_kwargs['rng_data'] = [np.random.RandomState(rng_seed), | |
| np.random.RandomState(rng_seed)] | |
| train_step_kwargs['rng_action'] = np.random.RandomState(rng_seed) | |
| if is_chief: | |
| train_step_kwargs['writer'] = tf.summary.FileWriter(logdir) #, m.tf_graph) | |
| else: | |
| train_step_kwargs['writer'] = None | |
| train_step_kwargs['iters'] = iters | |
| train_step_kwargs['train_display_interval'] = train_display_interval | |
| train_step_kwargs['num_steps'] = num_steps | |
| train_step_kwargs['logdir'] = logdir | |
| train_step_kwargs['dagger_sample_bn_false'] = dagger_sample_bn_false | |
| return train_step_kwargs | |
| # Utilities for visualizing and analysing validation output. | |
| def save_d_at_t(outputs, global_step, output_dir, metric_summary, N): | |
| """Save distance to goal at all time steps. | |
| Args: | |
| outputs : [gt_dist_to_goal]. | |
| global_step : number of iterations. | |
| output_dir : output directory. | |
| metric_summary : to append scalars to summary. | |
| N : number of outputs to process. | |
| """ | |
| d_at_t = np.concatenate(map(lambda x: x[0][:,:,0]*1, outputs), axis=0) | |
| fig, axes = utils.subplot(plt, (1,1), (5,5)) | |
| axes.plot(np.arange(d_at_t.shape[1]), np.mean(d_at_t, axis=0), 'r.') | |
| axes.set_xlabel('time step') | |
| axes.set_ylabel('dist to next goal') | |
| axes.grid('on') | |
| file_name = os.path.join(output_dir, 'dist_at_t_{:d}.png'.format(global_step)) | |
| with fu.fopen(file_name, 'w') as f: | |
| fig.savefig(f, bbox_inches='tight', transparent=True, pad_inches=0) | |
| file_name = os.path.join(output_dir, 'dist_at_t_{:d}.pkl'.format(global_step)) | |
| utils.save_variables(file_name, [d_at_t], ['d_at_t'], overwrite=True) | |
| plt.close(fig) | |
| return None | |
| def save_all(outputs, global_step, output_dir, metric_summary, N): | |
| """Save numerous statistics. | |
| Args: | |
| outputs : [locs, goal_loc, gt_dist_to_goal, node_ids, perturbs] | |
| global_step : number of iterations. | |
| output_dir : output directory. | |
| metric_summary : to append scalars to summary. | |
| N : number of outputs to process. | |
| """ | |
| all_locs = np.concatenate(map(lambda x: x[0], outputs), axis=0) | |
| all_goal_locs = np.concatenate(map(lambda x: x[1], outputs), axis=0) | |
| all_d_at_t = np.concatenate(map(lambda x: x[2][:,:,0]*1, outputs), axis=0) | |
| all_node_ids = np.concatenate(map(lambda x: x[3], outputs), axis=0) | |
| all_perturbs = np.concatenate(map(lambda x: x[4], outputs), axis=0) | |
| file_name = os.path.join(output_dir, 'all_locs_at_t_{:d}.pkl'.format(global_step)) | |
| vars = [all_locs, all_goal_locs, all_d_at_t, all_node_ids, all_perturbs] | |
| var_names = ['all_locs', 'all_goal_locs', 'all_d_at_t', 'all_node_ids', 'all_perturbs'] | |
| utils.save_variables(file_name, vars, var_names, overwrite=True) | |
| return None | |
| def eval_ap(outputs, global_step, output_dir, metric_summary, N, num_classes=4): | |
| """Processes the collected outputs to compute AP for action prediction. | |
| Args: | |
| outputs : [logits, labels] | |
| global_step : global_step. | |
| output_dir : where to store results. | |
| metric_summary : summary object to add summaries to. | |
| N : number of outputs to process. | |
| num_classes : number of classes to compute AP over, and to reshape tensors. | |
| """ | |
| if N >= 0: | |
| outputs = outputs[:N] | |
| logits = np.concatenate(map(lambda x: x[0], outputs), axis=0).reshape((-1, num_classes)) | |
| labels = np.concatenate(map(lambda x: x[1], outputs), axis=0).reshape((-1, num_classes)) | |
| aps = [] | |
| for i in range(logits.shape[1]): | |
| ap, rec, prec = utils.calc_pr(labels[:,i], logits[:,i]) | |
| ap = ap[0] | |
| tf_utils.add_value_to_summary(metric_summary, 'aps/ap_{:d}: '.format(i), ap) | |
| aps.append(ap) | |
| return aps | |
| def eval_dist(outputs, global_step, output_dir, metric_summary, N): | |
| """Processes the collected outputs during validation to | |
| 1. Plot the distance over time curve. | |
| 2. Compute mean and median distances. | |
| 3. Plots histogram of end distances. | |
| Args: | |
| outputs : [locs, goal_loc, gt_dist_to_goal]. | |
| global_step : global_step. | |
| output_dir : where to store results. | |
| metric_summary : summary object to add summaries to. | |
| N : number of outputs to process. | |
| """ | |
| SUCCESS_THRESH = 3 | |
| if N >= 0: | |
| outputs = outputs[:N] | |
| # Plot distance at time t. | |
| d_at_t = [] | |
| for i in range(len(outputs)): | |
| locs, goal_loc, gt_dist_to_goal = outputs[i] | |
| d_at_t.append(gt_dist_to_goal[:,:,0]*1) | |
| # Plot the distance. | |
| fig, axes = utils.subplot(plt, (1,1), (5,5)) | |
| d_at_t = np.concatenate(d_at_t, axis=0) | |
| axes.plot(np.arange(d_at_t.shape[1]), np.mean(d_at_t, axis=0), 'r.') | |
| axes.set_xlabel('time step') | |
| axes.set_ylabel('dist to next goal') | |
| axes.grid('on') | |
| file_name = os.path.join(output_dir, 'dist_at_t_{:d}.png'.format(global_step)) | |
| with fu.fopen(file_name, 'w') as f: | |
| fig.savefig(f, bbox_inches='tight', transparent=True, pad_inches=0) | |
| file_name = os.path.join(output_dir, 'dist_at_t_{:d}.pkl'.format(global_step)) | |
| utils.save_variables(file_name, [d_at_t], ['d_at_t'], overwrite=True) | |
| plt.close(fig) | |
| # Plot the trajectories and the init_distance and final distance. | |
| d_inits = [] | |
| d_ends = [] | |
| for i in range(len(outputs)): | |
| locs, goal_loc, gt_dist_to_goal = outputs[i] | |
| d_inits.append(gt_dist_to_goal[:,0,0]*1) | |
| d_ends.append(gt_dist_to_goal[:,-1,0]*1) | |
| # Plot the distance. | |
| fig, axes = utils.subplot(plt, (1,1), (5,5)) | |
| d_inits = np.concatenate(d_inits, axis=0) | |
| d_ends = np.concatenate(d_ends, axis=0) | |
| axes.plot(d_inits+np.random.rand(*(d_inits.shape))-0.5, | |
| d_ends+np.random.rand(*(d_ends.shape))-0.5, '.', mec='red', mew=1.0) | |
| axes.set_xlabel('init dist'); axes.set_ylabel('final dist'); | |
| axes.grid('on'); axes.axis('equal'); | |
| title_str = 'mean: {:0.1f}, 50: {:0.1f}, 75: {:0.2f}, s: {:0.1f}' | |
| title_str = title_str.format( | |
| np.mean(d_ends), np.median(d_ends), np.percentile(d_ends, q=75), | |
| 100*(np.mean(d_ends <= SUCCESS_THRESH))) | |
| axes.set_title(title_str) | |
| file_name = os.path.join(output_dir, 'dist_{:d}.png'.format(global_step)) | |
| with fu.fopen(file_name, 'w') as f: | |
| fig.savefig(f, bbox_inches='tight', transparent=True, pad_inches=0) | |
| file_name = os.path.join(output_dir, 'dist_{:d}.pkl'.format(global_step)) | |
| utils.save_variables(file_name, [d_inits, d_ends], ['d_inits', 'd_ends'], | |
| overwrite=True) | |
| plt.close(fig) | |
| # Plot the histogram of the end_distance. | |
| with plt.style.context('seaborn-white'): | |
| d_ends_ = np.sort(d_ends) | |
| d_inits_ = np.sort(d_inits) | |
| leg = []; | |
| fig, ax = utils.subplot(plt, (1,1), (5,5)) | |
| ax.grid('on') | |
| ax.set_xlabel('Distance from goal'); ax.xaxis.label.set_fontsize(16); | |
| ax.set_ylabel('Fraction of data'); ax.yaxis.label.set_fontsize(16); | |
| ax.plot(d_ends_, np.arange(d_ends_.size)*1./d_ends_.size, 'r') | |
| ax.plot(d_inits_, np.arange(d_inits_.size)*1./d_inits_.size, 'k') | |
| leg.append('Final'); leg.append('Init'); | |
| ax.legend(leg, fontsize='x-large'); | |
| ax.set_axis_on() | |
| title_str = 'mean: {:0.1f}, 50: {:0.1f}, 75: {:0.2f}, s: {:0.1f}' | |
| title_str = title_str.format( | |
| np.mean(d_ends), np.median(d_ends), np.percentile(d_ends, q=75), | |
| 100*(np.mean(d_ends <= SUCCESS_THRESH))) | |
| ax.set_title(title_str) | |
| file_name = os.path.join(output_dir, 'dist_hist_{:d}.png'.format(global_step)) | |
| with fu.fopen(file_name, 'w') as f: | |
| fig.savefig(f, bbox_inches='tight', transparent=True, pad_inches=0) | |
| # Log distance metrics. | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/success_init: ', | |
| 100*(np.mean(d_inits <= SUCCESS_THRESH))) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/success_end: ', | |
| 100*(np.mean(d_ends <= SUCCESS_THRESH))) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_init (75): ', | |
| np.percentile(d_inits, q=75)) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_end (75): ', | |
| np.percentile(d_ends, q=75)) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_init (median): ', | |
| np.median(d_inits)) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_end (median): ', | |
| np.median(d_ends)) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_init (mean): ', | |
| np.mean(d_inits)) | |
| tf_utils.add_value_to_summary(metric_summary, 'dists/dist_end (mean): ', | |
| np.mean(d_ends)) | |
| return np.median(d_inits), np.median(d_ends), np.mean(d_inits), np.mean(d_ends), \ | |
| np.percentile(d_inits, q=75), np.percentile(d_ends, q=75), \ | |
| 100*(np.mean(d_inits) <= SUCCESS_THRESH), 100*(np.mean(d_ends) <= SUCCESS_THRESH) | |
| def plot_trajectories(outputs, global_step, output_dir, metric_summary, N): | |
| """Processes the collected outputs during validation to plot the trajectories | |
| in the top view. | |
| Args: | |
| outputs : [locs, orig_maps, goal_loc]. | |
| global_step : global_step. | |
| output_dir : where to store results. | |
| metric_summary : summary object to add summaries to. | |
| N : number of outputs to process. | |
| """ | |
| if N >= 0: | |
| outputs = outputs[:N] | |
| N = len(outputs) | |
| plt.set_cmap('gray') | |
| fig, axes = utils.subplot(plt, (N, outputs[0][1].shape[0]), (5,5)) | |
| axes = axes.ravel()[::-1].tolist() | |
| for i in range(N): | |
| locs, orig_maps, goal_loc = outputs[i] | |
| is_semantic = np.isnan(goal_loc[0,0,1]) | |
| for j in range(orig_maps.shape[0]): | |
| ax = axes.pop(); | |
| ax.plot(locs[j,0,0], locs[j,0,1], 'ys') | |
| # Plot one by one, so that they come in different colors. | |
| for k in range(goal_loc.shape[1]): | |
| if not is_semantic: | |
| ax.plot(goal_loc[j,k,0], goal_loc[j,k,1], 's') | |
| if False: | |
| ax.plot(locs[j,:,0], locs[j,:,1], 'r.', ms=3) | |
| ax.imshow(orig_maps[j,0,:,:,0], origin='lower') | |
| ax.set_axis_off(); | |
| else: | |
| ax.scatter(locs[j,:,0], locs[j,:,1], c=np.arange(locs.shape[1]), | |
| cmap='jet', s=10, lw=0) | |
| ax.imshow(orig_maps[j,0,:,:,0], origin='lower', vmin=-1.0, vmax=2.0) | |
| if not is_semantic: | |
| xymin = np.minimum(np.min(goal_loc[j,:,:], axis=0), np.min(locs[j,:,:], axis=0)) | |
| xymax = np.maximum(np.max(goal_loc[j,:,:], axis=0), np.max(locs[j,:,:], axis=0)) | |
| else: | |
| xymin = np.min(locs[j,:,:], axis=0) | |
| xymax = np.max(locs[j,:,:], axis=0) | |
| xy1 = (xymax+xymin)/2. - np.maximum(np.max(xymax-xymin), 12) | |
| xy2 = (xymax+xymin)/2. + np.maximum(np.max(xymax-xymin), 12) | |
| ax.set_xlim([xy1[0], xy2[0]]) | |
| ax.set_ylim([xy1[1], xy2[1]]) | |
| ax.set_axis_off() | |
| file_name = os.path.join(output_dir, 'trajectory_{:d}.png'.format(global_step)) | |
| with fu.fopen(file_name, 'w') as f: | |
| fig.savefig(f, bbox_inches='tight', transparent=True, pad_inches=0) | |
| plt.close(fig) | |
| return None | |
| def add_default_summaries(mode, arop_full_summary_iters, summarize_ops, | |
| summarize_names, to_aggregate, action_prob_op, | |
| input_tensors, scope_name): | |
| assert(mode == 'train' or mode == 'val' or mode == 'test'), \ | |
| 'add_default_summaries mode is neither train or val or test.' | |
| s_ops = tf_utils.get_default_summary_ops() | |
| if mode == 'train': | |
| s_ops.summary_ops, s_ops.print_summary_ops, additional_return_ops, \ | |
| arop_summary_iters, arop_eval_fns = tf_utils.simple_summaries( | |
| summarize_ops, summarize_names, mode, to_aggregate=False, | |
| scope_name=scope_name) | |
| s_ops.additional_return_ops += additional_return_ops | |
| s_ops.arop_summary_iters += arop_summary_iters | |
| s_ops.arop_eval_fns += arop_eval_fns | |
| elif mode == 'val': | |
| s_ops.summary_ops, s_ops.print_summary_ops, additional_return_ops, \ | |
| arop_summary_iters, arop_eval_fns = tf_utils.simple_summaries( | |
| summarize_ops, summarize_names, mode, to_aggregate=to_aggregate, | |
| scope_name=scope_name) | |
| s_ops.additional_return_ops += additional_return_ops | |
| s_ops.arop_summary_iters += arop_summary_iters | |
| s_ops.arop_eval_fns += arop_eval_fns | |
| elif mode == 'test': | |
| s_ops.summary_ops, s_ops.print_summary_ops, additional_return_ops, \ | |
| arop_summary_iters, arop_eval_fns = tf_utils.simple_summaries( | |
| [], [], mode, to_aggregate=[], scope_name=scope_name) | |
| s_ops.additional_return_ops += additional_return_ops | |
| s_ops.arop_summary_iters += arop_summary_iters | |
| s_ops.arop_eval_fns += arop_eval_fns | |
| if mode == 'val': | |
| arop = s_ops.additional_return_ops | |
| arop += [[action_prob_op, input_tensors['train']['action']]] | |
| arop += [[input_tensors['step']['loc_on_map'], | |
| input_tensors['common']['goal_loc'], | |
| input_tensors['step']['gt_dist_to_goal']]] | |
| arop += [[input_tensors['step']['loc_on_map'], | |
| input_tensors['common']['orig_maps'], | |
| input_tensors['common']['goal_loc']]] | |
| s_ops.arop_summary_iters += [-1, arop_full_summary_iters, | |
| arop_full_summary_iters] | |
| s_ops.arop_eval_fns += [eval_ap, eval_dist, plot_trajectories] | |
| elif mode == 'test': | |
| arop = s_ops.additional_return_ops | |
| arop += [[input_tensors['step']['loc_on_map'], | |
| input_tensors['common']['goal_loc'], | |
| input_tensors['step']['gt_dist_to_goal']]] | |
| arop += [[input_tensors['step']['gt_dist_to_goal']]] | |
| arop += [[input_tensors['step']['loc_on_map'], | |
| input_tensors['common']['goal_loc'], | |
| input_tensors['step']['gt_dist_to_goal'], | |
| input_tensors['step']['node_ids'], | |
| input_tensors['step']['perturbs']]] | |
| arop += [[input_tensors['step']['loc_on_map'], | |
| input_tensors['common']['orig_maps'], | |
| input_tensors['common']['goal_loc']]] | |
| s_ops.arop_summary_iters += [-1, -1, -1, arop_full_summary_iters] | |
| s_ops.arop_eval_fns += [eval_dist, save_d_at_t, save_all, | |
| plot_trajectories] | |
| return s_ops | |