text: '''
      Evaluate classification performance with optional voting.
      Will use H5 dataset in default. If using normal, will shift to the normal dataset.
  '''
  import tensorflow as tf
  import numpy as np
  import argparse
  import socket
  import importlib
  import time
  import os
  import scipy.misc
  import sys
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  ROOT_DIR = BASE_DIR
  sys.path.append(BASE_DIR)
  sys.path.append(os.path.join(ROOT_DIR, 'models'))
  sys.path.append(os.path.join(ROOT_DIR, 'utils'))
  import provider
  import modelnet_dataset
  import modelnet_h5_dataset
  sys.path.append(os.path.join(BASE_DIR, '..'))
  import data_utils
  import pc_util
  import json
  
  parser = argparse.ArgumentParser()
  parser.add_argument('--gpu', type=int, default=0, help='GPU to use [default: GPU 0]')
  parser.add_argument('--model', default='pointnet2_cls_partseg', help='Model name: pointnet_cls or pointnet_cls_basic [default: pointnet_cls]')
  parser.add_argument('--batch_size', type=int, default=1, help='Batch Size during training [default: 1]')
  parser.add_argument('--num_point', type=int, default=2048, help='Point Number [256/512/1024/2048] [default: 1024]')
  
  parser.add_argument('--model_path', default='../../../../pointnet2/log_partseg_chairs_augmented25rot/model.ckpt', help='model checkpoint file path [default: log/model.ckpt]')
  parser.add_argument('--dump_dir', default='dump_partseg_augmented25rot/', help='dump folder path [dump]')
  parser.add_argument('--with_bg', default = True, help='Whether to have background or not [default: True]')
  parser.add_argument('--norm', default = True, help='Whether to normalize data or not [default: False]')
  parser.add_argument('--center_data', default = True, help='Whether to explicitly center the data [default: False]')
  parser.add_argument('--seg_weight', type=int, default=1.0, help='Segmentation weight in loss')
  
  # parser.add_argument('--test_file', default = '../training_data/test_objectdataset_v1.pickle', help='Location of test file')
  parser.add_argument('--test_file', default = '/home/vgd/object_dataset/parts/test_objectdataset_augmented25rot.h5', help='Location of test file')
  
  parser.add_argument('--visu_mask', default = False, help='Whether to dump mask [default: False]')
  parser.add_argument('--visu', default = False, help='Whether to dump image for error case [default: False]')
  FLAGS = parser.parse_args()
  
  DATA_DIR = os.path.join(ROOT_DIR, '../../../../')
  BATCH_SIZE = FLAGS.batch_size
  NUM_POINT = FLAGS.num_point
  MODEL_PATH = FLAGS.model_path
  GPU_INDEX = FLAGS.gpu
  MODEL = importlib.import_module(FLAGS.model) # import network module
  DUMP_DIR = FLAGS.dump_dir
  if not os.path.exists(DUMP_DIR): os.mkdir(DUMP_DIR)
  LOG_FOUT = open(os.path.join(DUMP_DIR, 'log_evaluate.txt'), 'w')
  LOG_FOUT.write(str(FLAGS)+'\n')
  
  WITH_BG = FLAGS.with_bg
  NORMALIZED = FLAGS.norm
  TEST_FILE = FLAGS.test_file
  CENTER_DATA = FLAGS.center_data
  SEG_WEIGHT = FLAGS.seg_weight
  
  NUM_CLASSES = 6
  SHAPE_NAMES = [line.rstrip() for line in \
      open( '../training_data/chair_parts.txt')] 
  
  HOSTNAME = socket.gethostname()
  
  np.random.seed(0)
  
  print("Normalized: "+str(NORMALIZED))
  print("Center Data: "+str(CENTER_DATA))   
  
  TEST_DATA, TEST_LABELS, TEST_PARTS = data_utils.load_parts_h5(TEST_FILE) 
  
  if (CENTER_DATA):
      TEST_DATA = data_utils.center_data(TEST_DATA)
  
  if (NORMALIZED):
      TEST_DATA = data_utils.normalize_data(TEST_DATA)
  
  color_map_file = '../part_color_mapping.json'
  color_map = json.load(open(color_map_file, 'r'))
  def output_color_point_cloud(data, seg, out_file):
      with open(out_file, 'w') as f:
          l = len(seg)
          for i in range(l):
              color = color_map[seg[i]]
              f.write('v %f %f %f %f %f %f\n' % (data[i][0], data[i][1], data[i][2], color[0], color[1], color[2]))
  
  def save_binfiles(pc, parts, fname):
      print(pc.shape)
      num_vertices = pc.shape[0]
      print(num_vertices)
      pc = pc.flatten()
      
      object_bin = []
      object_bin.append(num_vertices)
  
      for i in range(pc.shape[0]):
          object_bin.append(pc[i])
          if i%3==2:
              ##insert dummy colors, normal nyu and label
              for j in range(8):
                  object_bin.append(1.0)
      
      # object_bin.append(parts[int((i-2)/3)])
  
      object_bin = np.array(object_bin)
      print(object_bin.shape)
  
      object_bin.astype('float32').tofile(fname+'.bin')
      # exit()
  
      ##output parts_bin
      parts_bin = []
      parts_bin.append(num_vertices)
      for i in range(parts.shape[0]):
          parts_bin.append(parts[i])
          parts_bin.append(parts[i])
  
      parts_bin = np.array(parts_bin)
      print(parts_bin.shape)
      parts_bin.astype('float32').tofile(fname+'_part.bin')
  
      # print(parts_bin)
      # print(np.unique(parts_bin))
      # exit()
  
  # for i in range(len(TEST_DATA)):
  #     fname = str(i)+'_gt_debug.obj'
  #     output_color_point_cloud(TEST_DATA[i], TEST_PARTS[i],fname)
  #     # save_binfiles(TEST_DATA[i], TEST_PARTS[i],fname)
  # exit()
  
  
  def log_string(out_str):
      LOG_FOUT.write(out_str+'\n')
      LOG_FOUT.flush()
      print(out_str)
  
  def evaluate(num_votes):
      is_training = False
       
      with tf.device('/gpu:'+str(GPU_INDEX)):
          pointclouds_pl, labels_pl, parts_pl = MODEL.placeholder_inputs(BATCH_SIZE, NUM_POINT)
          is_training_pl = tf.placeholder(tf.bool, shape=())
  
          # simple model
          seg_pred = MODEL.get_model(pointclouds_pl, is_training_pl)
          total_loss = MODEL.get_loss(seg_pred, parts_pl)
  
          # Add ops to save and restore all the variables.
          saver = tf.train.Saver()
          
      # Create a session
      config = tf.ConfigProto()
      config.gpu_options.allow_growth = True
      config.allow_soft_placement = True
      config.log_device_placement = True
      sess = tf.Session(config=config)
  
      # Restore variables from disk.
      saver.restore(sess, MODEL_PATH)
      log_string("Model restored.")
  
      ops = {'pointclouds_pl': pointclouds_pl,
             'labels_pl': labels_pl,
             'parts_pl': parts_pl,
             'is_training_pl': is_training_pl,
             'seg_pred': seg_pred,
             'loss': total_loss}
  
      eval_one_epoch(sess, ops, num_votes)
  
     
  def eval_one_epoch(sess, ops, num_votes=1, topk=1):
      error_cnt = 0
      is_training = False
  
      total_seen = 0
      loss_sum = 0
      total_seen_class = [0 for _ in range(NUM_CLASSES)]
      total_correct_class = [0 for _ in range(NUM_CLASSES)]
  
      total_correct_seg = 0
  
      current_data, current_label, current_parts = data_utils.get_current_data_parts_h5(TEST_DATA, TEST_LABELS, TEST_PARTS, NUM_POINT)
  
      current_label = np.squeeze(current_label)
      current_parts = np.squeeze(current_parts)
  
      num_batches = current_data.shape[0]//BATCH_SIZE
      
      for batch_idx in range(num_batches):
          start_idx = batch_idx * BATCH_SIZE
          end_idx = (batch_idx+1) * BATCH_SIZE
          cur_batch_size = end_idx - start_idx
          
          # Aggregating BEG
          batch_loss_sum = 0 # sum of losses for the batch
          batch_seg_sum = np.zeros((cur_batch_size, NUM_POINT, NUM_CLASSES)) # score for classes
          for vote_idx in range(num_votes):
              # rotated_data = provider.rotate_point_cloud_by_angle(current_data[start_idx:end_idx, :, :],
              #                                   vote_idx/float(num_votes) * np.pi * 2)
              rotated_data = current_data[start_idx:end_idx, :, :]           
              feed_dict = {ops['pointclouds_pl']: rotated_data,
                          ops['parts_pl']: current_parts[start_idx:end_idx],
                          ops['labels_pl']: current_label[start_idx:end_idx],
                          ops['is_training_pl']: is_training}
              loss_val, seg_val = sess.run([ops['loss'], ops['seg_pred']],
                                        feed_dict=feed_dict)
  
              batch_seg_sum += seg_val
              batch_loss_sum += (loss_val * cur_batch_size / float(num_votes))
          # pred_val_topk = np.argsort(batch_pred_sum, axis=-1)[:,-1*np.array(range(topk))-1]
          # pred_val = np.argmax(batch_pred_classes, 1)
          # Aggregating END
          seg_val = np.argmax(batch_seg_sum, 2)
          seg_correct = np.sum(seg_val == current_parts[start_idx:end_idx])
          total_correct_seg += seg_correct
          
          total_seen += cur_batch_size
          loss_sum += batch_loss_sum
  
          for i in range(start_idx, end_idx):
              parts = current_parts[i]
              for j in range(len(parts)):
                  part = parts[j]
  
                  total_seen_class[part] += 1
                  total_correct_class[part] += (seg_val[i-start_idx][j] == part)
  
          total_parts_seen = 0
          cum_sum = 0
          part_accs = []
  
          # fname = str(start_idx)+'_gt'
          # fname = os.path.join(DUMP_DIR, fname)
          # save_binfiles(current_data[start_idx,:,:], current_parts[start_idx],fname)
  
          # fname = str(start_idx)+'_pred'
          # fname = os.path.join(DUMP_DIR, fname)
          # save_binfiles(current_data[start_idx,:,:], seg_val[0],fname)
  
          # fname = str(start_idx)+'_pred.obj'
          # fname = os.path.join(DUMP_DIR, fname)
          # output_color_point_cloud(current_data[start_idx,:,:], seg_val[0],fname)
  
          # fname = str(start_idx)+'_gt.obj'
          # fname = os.path.join(DUMP_DIR, fname)
          # output_color_point_cloud(current_data[start_idx,:,:], current_parts[start_idx],fname)        
  
          for i in range(NUM_CLASSES):
              if (total_seen_class[i]==0):
                  part_accs.append(-1.0)
                  continue
              part_acc = float(total_correct_class[i])/float(total_seen_class[i])
              cum_sum += part_acc
              part_accs.append(part_acc)
              total_parts_seen +=1
  
      log_string('total seen: %d' % (total_seen)) 
      log_string('eval mean loss: %f' % (loss_sum / float(total_seen)))
      log_string('eval seg accuracy: %f' % (total_correct_seg / (float(total_seen)*NUM_POINT)))
      log_string('eval avg class acc: %f' % (cum_sum/float(total_parts_seen)))  
  
      for i, name in enumerate(SHAPE_NAMES):
          log_string('%10s:\t%0.3f' % (name, part_accs[i]))
      
  
  
  if __name__=='__main__':
      with tf.Graph().as_default():
          evaluate(num_votes=1)
      LOG_FOUT.close()
  
  