Example #1
0
  def __init__(self, name, inputs, targets, tower_setup, merge_type):
    super(CompleteSiameseMerge, self).__init__()
    curr, n_features_inp = prepare_input(inputs)

    batch_size = smart_shape(curr)[0]
    curr1 = curr[:,tf.newaxis,:]
    curr2 = curr[tf.newaxis,:,:]

    if merge_type == "concat":
      # curr1_big = tf.reshape(tf.tile(curr1, [batch_size]), [batch_size, -1])
      # curr2_big = tf.reshape(tf.tile(curr2, [batch_size]), [batch_size, -1])

      curr1 = tf.transpose(curr1, perm=[1, 0, 2])
      curr1_big = tf.tile(curr1, [batch_size,1,1])
      curr1_big = tf.transpose(curr1_big, perm=[1, 0, 2])
      curr2_big = tf.tile(curr2, [batch_size,1,1])

      whole_mat = tf.concat((curr1_big,curr2_big),2)
    elif merge_type == "add":
      whole_mat = curr1 + curr2
    elif merge_type == "subtract":
      whole_mat = curr1 - curr2
    elif merge_type == "abs_subtract":
      whole_mat = tf.abs(curr1 - curr2)
    else:
      raise ValueError("No correct merge type")

    targets1 = targets[:,tf.newaxis]
    targets2 = targets[tf.newaxis,:]
    whole_targets = tf.cast(tf.equal(targets1,targets2),tf.int32)

    boolean_target = tf.cast(tf.ones([batch_size,batch_size]),tf.bool)
    #### Following extracts one sided + diagonal, but for now we are using both sided as concat is non-symmetric
    #### In future may want to remove the diagonal
    # boolean_target = tf.matrix_band_part(boolean_target, -1, 0),tf.bool
    targets_list = tf.boolean_mask(whole_targets,boolean_target)
    vectors_list = tf.boolean_mask(whole_mat,boolean_target)

    debug = 0
    if debug:
      # Print - debug example code
      def test(a):
        print(a)
        return numpy.array([5], dtype="int32")

      t, = tf.py_func(test, [smart_shape(targets_list)], [tf.int32])
      with tf.control_dependencies([t]):
        targets_list = tf.identity(targets_list)

      t, = tf.py_func(test, [smart_shape(vectors_list)], [tf.int32])
      with tf.control_dependencies([t]):
        targets_list = tf.identity(targets_list)

    self.outputs = [vectors_list]
    self.out_labels = targets_list
Example #2
0
    def Expand(idx):
      anchor = curr[idx, :]
      anchor_class = targets[idx]
      classes,classes_ids = tf.unique(targets)
      anchor_class_id = classes_ids[idx]
      class_division = tf.cast(tf.equal(targets, anchor_class), tf.int32) - tf.cast(tf.equal(list(range(0,size)),idx),tf.int32)
      partitioned_output = tf.dynamic_partition(curr, class_division, 2)
      #partitioned_targets = tf.dynamic_partition(targets, class_division, 2)

      # Positives
      positives = partitioned_output[1]

      size_positives = smart_shape(positives)[0]
      anchor_positive_repmat = tf.reshape(tf.tile(anchor,[size_positives]),[size_positives,-1])
      positives_combined = tf.concat((anchor_positive_repmat,positives),1)
      new_targets_positive = tf.ones([smart_shape(positives_combined)[0]],dtype=tf.int32)

      # Negatives
      negative_size = smart_shape(classes)[0]

      def Get_negatives(neg_idx):
        curr_neg_class = classes[neg_idx]
        neg_class_division = tf.cast(tf.equal(targets, curr_neg_class), tf.int32)
        neg_partitioned_output = tf.dynamic_partition(curr, neg_class_division, 2)
        negative_set = neg_partitioned_output[1]
        size_negative_set = smart_shape(negative_set)[0]
        random_negative_idx = tf.random_shuffle(tf.range(1, size_negative_set))[0]
        random_negative = negative_set[random_negative_idx,:]
        return random_negative

      looper = tf.range(0, anchor_class_id)
      iter_val = tf.minimum(anchor_class_id+1,negative_size)
      # looper = tf.range(0, idx)
      # iter_val = tf.minimum(idx + 1, negative_size)
      looper = tf.concat([looper,tf.range(iter_val,negative_size)],0)

      negatives = tf.map_fn(Get_negatives, looper, dtype=tf.float32)
      size_negatives = smart_shape(negatives)[0]
      anchor_negative_repmat = tf.reshape(tf.tile(anchor, [size_negatives]), [size_negatives, -1])
      negatives_combined = tf.concat((anchor_negative_repmat,negatives),1)
      new_targets_negative = tf.zeros([smart_shape(negatives_combined)[0]],dtype=tf.int32)

      all_combined = tf.concat((positives_combined,negatives_combined),0)
      new_targets_combined = tf.concat((new_targets_positive,new_targets_negative),0)

      return all_combined, new_targets_combined
Example #3
0
 def Get_negatives(neg_idx):
   curr_neg_class = classes[neg_idx]
   neg_class_division = tf.cast(tf.equal(targets, curr_neg_class), tf.int32)
   neg_partitioned_output = tf.dynamic_partition(curr, neg_class_division, 2)
   negative_set = neg_partitioned_output[1]
   size_negative_set = smart_shape(negative_set)[0]
   random_negative_idx = tf.random_shuffle(tf.range(1, size_negative_set))[0]
   random_negative = negative_set[random_negative_idx,:]
   return random_negative
Example #4
0
def create_tensor_dict(unnormalized_img,
                       label,
                       tag,
                       raw_label=None,
                       old_label=None,
                       flow_past=None,
                       flow_future=None,
                       use_index_img=False,
                       u0=None,
                       u1=None,
                       bboxes=None,
                       ids=None,
                       classes=None,
                       img_id=None,
                       ignore_regions=None,
                       scene_infos=None,
                       old_label_as_dt=None):
    tensors = {"unnormalized_img": unnormalized_img, "tag": tag}
    #note that "label" is a bit a misnomer, since it's actually a mask. better rename it at some point
    if label is not None:
        tensors["label"] = label
    if raw_label is None:
        if label is not None:
            tensors["raw_label"] = label
    else:
        tensors["raw_label"] = raw_label
    if old_label is not None:
        tensors["old_label"] = old_label
    if flow_past is not None:
        tensors["flow_past"] = flow_past
    if flow_future is not None:
        tensors["flow_future"] = flow_future
    if bboxes is not None:
        tensors[Constants.BBOXES] = bboxes
    if ids is not None:
        tensors[Constants.IDS] = ids
    if classes is not None:
        tensors[Constants.CLASSES] = classes
    if u0 is not None:
        tensors[Constants.DT_NEG] = u0
    if u1 is not None:
        tensors[Constants.DT_POS] = u1
    if img_id is not None:
        tensors[Constants.IMG_IDS] = img_id
    if ignore_regions is not None:
        tensors[Constants.IGNORE_REGIONS] = ignore_regions
    if scene_infos is not None:
        tensors[Constants.SCENE_INFOS] = scene_infos
    if old_label_as_dt is not None:
        tensors[Constants.OLD_LABEL_AS_DT] = old_label_as_dt
    if use_index_img:
        shape = smart_shape(unnormalized_img)
        index_img = create_index_image(shape[0], shape[1])
        tensors["index_img"] = index_img
    return tensors
Example #5
0
    def embed(image, offset, pad_mode):
        """
    Embeds the image and performs reflection padding.

    :param image: The tensor to translate.
    :param offset: The offset by which we translate.
    :param pad_mode: The padding mode, or a constant
    :return: The augmented image.
    """
        # Compute offsets and sizes
        #shape = image.get_shape().as_list()
        shape = smart_shape(image)
        start = [tf.maximum(-offset[0], 0), tf.maximum(-offset[1], 0)]
        size = [shape[0] - tf.abs(offset[0]), shape[1] - tf.abs(offset[1])]

        # Pad the image on the opposite side
        padding = [[tf.maximum(0, offset[0]),
                    tf.maximum(0, -offset[0])],
                   [tf.maximum(0, offset[1]),
                    tf.maximum(0, -offset[1])]]

        # no padding on channel dimension for images
        if len(image.get_shape().as_list()) == 3:
            start.append(0)
            size.append(shape[2])
            padding.append([0, 0])

        # Extract the image region that is defined by the offset
        region = tf.slice(image, start, size)
        # region = image[max(-offset[0], 0):shape[0]-max(0, offset[0]),
        #               max(-offset[1], 0):shape[1]-max(0, offset[1])]

        if isinstance(pad_mode, str):
            region = tf.pad(region, padding, mode=pad_mode)
            return region
        else:
            const = pad_mode
            dtype = region.dtype
            region = tf.cast(region, tf.int32) - const
            region = tf.pad(region, padding, mode='CONSTANT')
            region = region + const
            return tf.cast(region, dtype)
Example #6
0
    def apply(self, tensors, scale=None):
        if scale is None:
            # atm minval 1.0 to only zoom in, later also allow smaller values
            scale = tf.random_uniform([1],
                                      minval=1.0,
                                      maxval=1.25,
                                      dtype=tf.float32,
                                      seed=None)

        img = tensors["unnormalized_img"]
        h, w = smart_shape(img)[:2]
        crop_size = (h, w)
        h_scaled = tf.to_int32(tf.ceil(tf.cast(h, scale.dtype) * scale))
        w_scaled = tf.to_int32(tf.ceil(tf.cast(w, scale.dtype) * scale))
        scaled_size = tf.concat([h_scaled, w_scaled], axis=0)
        offset = None
        aug_tensors = tensors.copy()

        def _scale(key, bilinear, offset_, force_key=False):
            if force_key:
                assert key in tensors
            if key in tensors:
                im = tensors[key]
                aug_im = resize_image(im, scaled_size, bilinear)
                aug_im, offset_ = random_crop_image(aug_im, crop_size, offset_)
                aug_tensors[key] = aug_im
            return offset_

        offset = _scale("unnormalized_img", True, offset, True)
        _scale("label", False, offset, False)
        _scale("old_label", False, offset)
        _scale("index_img", False, offset)
        _scale("flow_past", True, offset)
        _scale("flow_future", True, offset)
        #attention: when we zoom in, the shift in number of pixels (i.e. optical flow) gets larger
        if "flow_past" in aug_tensors:
            aug_tensors["flow_past"] *= scale
        if "flow_future" in aug_tensors:
            aug_tensors["flow_future"] *= scale

        return aug_tensors
Example #7
0
def clustering_features_extractor(engine, output_layer):
    outputs = output_layer.outputs[0]
    features = output_layer.y_class_features
    det_boxes, det_scores, reid, det_classes, num_detections = outputs
    det_boxes = tf.squeeze(det_boxes, axis=2)
    #conceptual problem: the features before the softmax are shared across anchors
    #let's just ignore that for now and replicate the features for each anchor
    n_anchors = 9
    shape = smart_shape(features)
    features = tf.tile(tf.expand_dims(features, axis=2),
                       multiples=[1, 1, n_anchors, 1])
    features = tf.reshape(features, tf.stack([shape[0], -1, shape[-1]],
                                             axis=0))

    def extract(filename, extract_boxes):
        data = engine.valid_data
        feed_dict = {
            data.img_filename_placeholder: filename,
            data.bboxes_placeholder: extract_boxes
        }
        det_boxes_val, det_features_val, det_scores_val = engine.session.run(
            [det_boxes, features, det_scores], feed_dict=feed_dict)
        #remove batch dimension
        batch_size = det_boxes_val.shape[0]
        assert batch_size == 1
        det_boxes_val = det_boxes_val[0]
        det_features_val = det_features_val[0]
        det_scores_val = det_scores_val[0]
        #compute IOUs and select most overlapping, for convenience let's do this with numpy instead of tensorflow
        ious = compute_ious(det_boxes_val, extract_boxes)
        indices = ious.argmax(axis=1)
        det_features_out = det_features_val[indices]
        det_scores_out = det_scores_val[indices]
        return det_features_out, det_scores_out

    return extract
Example #8
0
 def reshape_group(self, x, batch_size):
   shape = smart_shape(x)
   shape2 = shape[1:]
   shape2[0] = self.group_size * batch_size
   x = tf.reshape(x, shape2)
   return x
Example #9
0
  def __init__(self, name, inputs, targets, tower_setup, merge_type):
    super(ExpandedSiameseMerge, self).__init__()
    curr, n_features_inp = prepare_input(inputs)
    size = smart_shape(curr)[0]

    def Expand(idx):
      anchor = curr[idx, :]
      anchor_class = targets[idx]
      classes,classes_ids = tf.unique(targets)
      anchor_class_id = classes_ids[idx]
      class_division = tf.cast(tf.equal(targets, anchor_class), tf.int32) - tf.cast(tf.equal(list(range(0,size)),idx),tf.int32)
      partitioned_output = tf.dynamic_partition(curr, class_division, 2)
      #partitioned_targets = tf.dynamic_partition(targets, class_division, 2)

      # Positives
      positives = partitioned_output[1]

      size_positives = smart_shape(positives)[0]
      anchor_positive_repmat = tf.reshape(tf.tile(anchor,[size_positives]),[size_positives,-1])
      positives_combined = tf.concat((anchor_positive_repmat,positives),1)
      new_targets_positive = tf.ones([smart_shape(positives_combined)[0]],dtype=tf.int32)

      # Negatives
      negative_size = smart_shape(classes)[0]

      def Get_negatives(neg_idx):
        curr_neg_class = classes[neg_idx]
        neg_class_division = tf.cast(tf.equal(targets, curr_neg_class), tf.int32)
        neg_partitioned_output = tf.dynamic_partition(curr, neg_class_division, 2)
        negative_set = neg_partitioned_output[1]
        size_negative_set = smart_shape(negative_set)[0]
        random_negative_idx = tf.random_shuffle(tf.range(1, size_negative_set))[0]
        random_negative = negative_set[random_negative_idx,:]
        return random_negative

      looper = tf.range(0, anchor_class_id)
      iter_val = tf.minimum(anchor_class_id+1,negative_size)
      # looper = tf.range(0, idx)
      # iter_val = tf.minimum(idx + 1, negative_size)
      looper = tf.concat([looper,tf.range(iter_val,negative_size)],0)

      negatives = tf.map_fn(Get_negatives, looper, dtype=tf.float32)
      size_negatives = smart_shape(negatives)[0]
      anchor_negative_repmat = tf.reshape(tf.tile(anchor, [size_negatives]), [size_negatives, -1])
      negatives_combined = tf.concat((anchor_negative_repmat,negatives),1)
      new_targets_negative = tf.zeros([smart_shape(negatives_combined)[0]],dtype=tf.int32)

      all_combined = tf.concat((positives_combined,negatives_combined),0)
      new_targets_combined = tf.concat((new_targets_positive,new_targets_negative),0)

      return all_combined, new_targets_combined

    expanded, new_targets = tf.map_fn(Expand, tf.range(0, size), dtype=(tf.float32, tf.int32))

    if merge_type == "concat":
      expanded = tf.reshape(expanded, [-1, n_features_inp * 2])
    elif merge_type == "add":
      part1 = expanded[::2, :]
      part2 = expanded[1::2, :]
      expanded = part1 + part2
    elif merge_type == "subtract":
      part1 = expanded[::2, :]
      part2 = expanded[1::2, :]
      expanded = part1 - part2
    elif merge_type == "abs_subtract":
      part1 = expanded[::2, :]
      part2 = expanded[1::2, :]
      expanded = tf.abs(part1 - part2)
    else:
      expanded = expanded

    new_targets = tf.reshape(new_targets, [-1])

    debug = 0
    if debug:
      # Print - debug example code
      def test(a):
        print(a)
        return numpy.array([5], dtype="int32")

      t, = tf.py_func(test, [smart_shape(new_targets)], [tf.int32])
      with tf.control_dependencies([t]):
        expanded = tf.identity(expanded)

    self.outputs = [expanded]
    self.out_labels = new_targets
Example #10
0
def resize_detection_fixed_size(tensors, input_size, for_testing=False):
    tensors_out = tensors.copy()
    #ignore_regions are currently not supported in this resize mode
    if Constants.IGNORE_REGIONS in tensors_out:
        del tensors_out[Constants.IGNORE_REGIONS]
    img = tensors[Constants.UNNORMALIZED_IMG]
    original_img = img
    bboxes = tensors[Constants.BBOXES]

    # remove the padding
    n_real_detections = tf.reduce_sum(
        tf.cast(tensors[Constants.IDS] > 0, tf.int32))
    bboxes = bboxes[:n_real_detections]
    classes = tensors[Constants.CLASSES][:n_real_detections]

    # permute y1, y2, x1, x2 -> y1, x1, y2, x1
    bboxes = tf.stack(
        [bboxes[..., 0], bboxes[..., 2], bboxes[..., 1], bboxes[..., 3]],
        axis=-1)

    # normalize bboxes to [0..1]
    height = tf.shape(img)[0]
    width = tf.shape(img)[1]
    bboxes = tf.cast(bboxes, tf.float32) / tf.cast(
        tf.stack([height, width, height, width], axis=0), tf.float32)

    import object_detection.core.preprocessor as preproc
    if not for_testing:
        #crop (ssd style)
        img, bboxes, classes = preproc.ssd_random_crop(img, bboxes, classes)
        #alternative
        #img, bboxes, classes = preproc.random_crop_image(img, real_boxes, real_boxes)

        # include random horizontal flip augmentation here
        img, bboxes = preproc.random_horizontal_flip(img, bboxes)

    #resize image, note: boxes don't need resizing as they are in relative coordinates
    img = preproc.resize_image(img,
                               new_height=input_size[0],
                               new_width=input_size[1])

    if for_testing:
        _, bboxes = preproc.scale_boxes_to_pixel_coordinates(
            original_img, bboxes)
    else:
        _, bboxes = preproc.scale_boxes_to_pixel_coordinates(img, bboxes)

    #permute back y1, x1, y2, x1 -> y1, y2, x1, x2
    bboxes = tf.stack(
        [bboxes[..., 0], bboxes[..., 2], bboxes[..., 1], bboxes[..., 3]],
        axis=-1)

    #pad the stuff needs to be padded back to the maximum size
    padded_size = smart_shape(tensors[Constants.CLASSES])[0]
    n_real_detections_after_crop = smart_shape(bboxes)[0]
    pad_size = padded_size - n_real_detections_after_crop
    paddings_bboxes = [[0, pad_size], [0, 0]]
    bboxes = tf.pad(bboxes, paddings=paddings_bboxes)
    paddings_classes_ids = [[0, pad_size]]
    classes = tf.pad(classes, paddings=paddings_classes_ids)
    ids = tf.pad(tf.range(n_real_detections_after_crop) + 1,
                 paddings=paddings_classes_ids)
    if isinstance(padded_size, int):
        bboxes.set_shape((padded_size, 4))
        classes.set_shape((padded_size, ))
        ids.set_shape((padded_size, ))
    else:
        bboxes.set_shape((None, 4))
    #note that we do not retain the original ids, but it does not matter since this resize_mode is only meant for
    #isolated frames
    tensors_out[Constants.UNNORMALIZED_IMG] = img
    tensors_out[Constants.BBOXES] = bboxes
    tensors_out[Constants.CLASSES] = classes
    tensors_out[Constants.IDS] = ids
    tensors_out[Constants.RESIZED_SIZES] = tf.shape(img)[:2]
    if for_testing:
        tensors_out[Constants.ORIGINAL_SIZES] = tf.shape(original_img)[:2]
    return tensors_out
Example #11
0
 def add_mask_summary(self, mask, name):
   from ReID_net.datasets.Util.Util import smart_shape
   assert len(smart_shape(mask)) == 2
   im = tf.tile(tf.cast(mask, tf.float32)[tf.newaxis, :, :, tf.newaxis], multiples=[1, 1, 1, 3])
   summary = tf.summary.image(name, im)
   self.summaries.append(summary)
Example #12
0
    def __init__(self,
                 name,
                 inputs,
                 targets,
                 n_classes,
                 n_clusters,
                 tower_setup,
                 use_complete_batch,
                 use_SPN,
                 exclude_zeros_from_loss,
                 original_labels=None,
                 margin=2.0,
                 dropout=0.0,
                 l2=L2_DEFAULT):
        super(Clustering, self).__init__()
        self.measures = {}
        inp, n_features_inp = prepare_collapsed_input_and_dropout(
            inputs, dropout)

        with tf.variable_scope(name):
            W = self.create_weight_variable("W", [n_features_inp, n_clusters],
                                            l2, tower_setup)
            b = self.create_bias_variable("b", [n_clusters], tower_setup)
            y_pred = tf.matmul(inp, W) + b
            y_pred = tf.nn.softmax(y_pred, -1, 'softmax')
            self.outputs = [y_pred]

            summ = tf.summary.histogram("softmax", y_pred)
            self.summaries.append(summ)

            if use_complete_batch:
                #original_labels = targets
                curr = y_pred
                batch_size = smart_shape(curr)[0]
                curr1 = curr[:, tf.newaxis, :]
                curr2 = curr[tf.newaxis, :, :]

                curr1 = tf.transpose(curr1, perm=[1, 0, 2])
                curr1_big = tf.tile(curr1, [batch_size, 1, 1])
                curr1_big = tf.transpose(curr1_big, perm=[1, 0, 2])
                curr2_big = tf.tile(curr2, [batch_size, 1, 1])

                boolean_target = tf.cast(tf.ones([batch_size, batch_size]),
                                         tf.bool)
                #### Following extracts one sided + diagonal, but for now we are using both sided as concat is non-symmetric
                #### In future may want to remove the diagonal
                # boolean_target = tf.matrix_band_part(boolean_target, -1, 0),tf.bool

                y_pred0 = tf.boolean_mask(curr1_big, boolean_target)
                y_pred1 = tf.boolean_mask(curr2_big, boolean_target)

                if not use_SPN:
                    targets1 = targets[:, tf.newaxis]
                    targets2 = targets[tf.newaxis, :]
                    whole_targets = tf.cast(tf.equal(targets1, targets2),
                                            tf.int32)
                    targets = tf.boolean_mask(whole_targets, boolean_target)
            else:
                y_pred0 = y_pred[0::2]
                y_pred1 = y_pred[1::2]
                targets = targets[::2]

            if original_labels is not None:
                cluster_ids = tf.argmax(y_pred, axis=-1)
                self.measures[Constants.CLUSTER_IDS] = [cluster_ids]
                self.measures[Constants.ORIGINAL_LABELS] = [original_labels]

            #y_pred0_stopped = tf.stop_gradient(y_pred0)
            #y_pred1_stopped = tf.stop_gradient(y_pred1)

            def kl(x, y):
                epsilon = tf.constant(1e-8, tf.float32)
                x += epsilon
                y += epsilon
                return tf.reduce_sum(x * tf.log(x / y), axis=-1)

            kl1 = kl(y_pred0, y_pred1)
            kl2 = kl(y_pred1, y_pred0)

            #kl1 = kl(y_pred0_stopped, y_pred1)
            #kl2 = kl(y_pred1_stopped, y_pred0)

            def Lh(x):
                return tf.nn.relu(margin - x)
                # return tf.nn.softplus(-x)

            pos_loss = kl1 + kl2
            neg_loss = Lh(kl1) + Lh(kl2)
            loss = tf.where(tf.cast(targets, tf.bool), pos_loss, neg_loss)
            if exclude_zeros_from_loss:
                norm_factor = tf.maximum(
                    tf.count_nonzero(loss, dtype=tf.float32), 1.0)
                loss /= norm_factor
                loss *= tf.cast(smart_shape(inp)[0], tf.float32)
            elif use_complete_batch:
                loss /= tf.cast(smart_shape(inp)[0], tf.float32)
            self.loss = tf.reduce_sum(loss)
            self.add_scalar_summary(self.loss, "loss")
Example #13
0
    def __init__(self,
                 name,
                 inputs,
                 targets,
                 n_classes,
                 n_features,
                 tower_setup,
                 imgs_raw=None,
                 original_labels=None,
                 activation="linear",
                 dropout=0.0,
                 batch_norm=False,
                 batch_norm_decay=BATCH_NORM_DECAY_DEFAULT,
                 l2=L2_DEFAULT,
                 negative_weighting_factor=1):
        super(FullyConnectedWithTripletLoss, self).__init__()
        self.measures = {}
        inp, n_features_inp = prepare_collapsed_input_and_dropout(
            inputs, dropout)
        with tf.variable_scope(name):
            if batch_norm:
                inp = tf.expand_dims(inp, axis=0)
                inp = tf.expand_dims(inp, axis=0)
                inp = self.create_and_apply_batch_norm(inp, n_features_inp,
                                                       batch_norm_decay,
                                                       tower_setup)
                inp = tf.squeeze(inp, axis=[0, 1])
            W = self.create_weight_variable("W", [n_features_inp, n_features],
                                            l2, tower_setup)
            b = self.create_bias_variable("b", [n_features], tower_setup)
            z = tf.matmul(inp, W) + b
            h = get_activation(activation)(z)
            self.outputs = [h]

            if original_labels is not None:
                self.measures[Constants.EMBEDDING] = [h]
                self.measures[Constants.ORIGINAL_LABELS] = [original_labels]

            self.add_scalar_summary(tf.norm(h[0]), "embedding_norm")
            self.summaries.append(tf.summary.histogram("embedding", h))

            size = smart_shape(h)[0]
            eps = 1e-10

            # New print debug example
            def my_print(x, name):
                with tf.control_dependencies([
                        tf.assert_equal(
                            tf.reduce_all(tf.greater(tf.shape(x), 0)), True)
                ]):
                    if x.dtype in (tf.float32, tf.float64):
                        with tf.control_dependencies([
                                tf.assert_equal(tf.reduce_all(tf.is_finite(x)),
                                                True)
                        ]):
                            return tf.Print(x, [
                                tf.shape(x),
                                tf.reduce_all(tf.is_finite(x)), x
                            ],
                                            name,
                                            summarize=200)
                    else:
                        return tf.Print(x, [tf.shape(x), x], name)

            def get_loss(idx):
                anchor = h[idx, :]
                anchor_class = targets[idx]

                ###### New code ######
                class_division = tf.equal(targets, anchor_class)
                not_self_mask = tf.logical_not(
                    tf.cast(tf.one_hot(idx, depth=size), tf.bool))
                positive_output = tf.boolean_mask(
                    h, tf.logical_and(class_division, not_self_mask))
                negative_output = tf.boolean_mask(
                    h, tf.logical_not(class_division))
                # negative_output = tf.boolean_mask(h, tf.logical_and(tf.logical_not(class_division),not_self_mask))
                # positive_output = my_print(positive_output,"positive_output")
                # negative_output = my_print(negative_output, "negative_output")

                positive_distances = tf.abs(anchor - positive_output)
                pos_dis_val = tf.norm(positive_distances + eps, axis=1)
                hardest_positive, hardest_positive_idx = tf.nn.top_k(
                    pos_dis_val, 1)

                negative_distances = tf.abs(anchor - negative_output)
                neg_dis_val = tf.norm(negative_distances + eps, axis=1)
                minus_neg_dis_val = tf.negative(neg_dis_val)
                # minus_neg_dis_val = tf.Print(minus_neg_dis_val,[minus_neg_dis_val])
                # minus_neg_dis_val = tf.Print(minus_neg_dis_val, [minus_neg_dis_val.shape])
                minus_hardest_negative, hardest_negative_idx = tf.nn.top_k(
                    minus_neg_dis_val, 1)
                hardest_negative = tf.negative(minus_hardest_negative)

                # minus_hardest_negative, hardest_negative_idx = tf.nn.top_k(minus_neg_dis_val, negative_weighting_factor)
                # hardest_negative = tf.negative(minus_hardest_negative)
                # hardest_negative = tf.reduce_sum(hardest_negative,-1)

                ###### Old code with dynamic partition ######
                # class_division = tf.cast(tf.equal(targets, anchor_class), tf.int32)
                # not_self_mask = tf.logical_not(tf.cast(tf.one_hot(idx, depth=size), tf.bool))
                # partitioned_output = tf.dynamic_partition(h, class_division, 2)
                # positive_output = partitioned_output[1]
                # negative_output = partitioned_output[0]

                # class_division = tf.equal(targets, anchor_class)
                # not_self_mask = tf.logical_not(tf.cast(tf.one_hot(idx, depth=size),tf.bool))
                # positive_output = tf.boolean_mask(h, tf.logical_and(class_division, not_self_mask))
                # negative_output = tf.boolean_mask(h, tf.logical_not(class_division))
                #
                #
                # positive_distances = tf.abs(anchor - positive_output)
                # pos_dis_val = tf.norm(positive_distances+eps, axis=1)
                # hardest_positive_idx = tf.argmax(pos_dis_val,0)
                # pos_div_size = smart_shape(positive_output)[0]
                # pos_divider = tf.one_hot(hardest_positive_idx,pos_div_size,dtype=tf.int32)
                # hardest_positive = tf.dynamic_partition(positive_distances,pos_divider,2)[1]
                # hardest_positive_class = tf.gather(targets, hardest_positive_idx)
                # hardest_positive = tf.norm(hardest_positive+eps, axis=1)
                #
                # negative_distances = tf.abs(anchor - negative_output)
                # neg_dis_val = tf.norm(negative_distances+eps, axis=1)
                # hardest_negative_idx = tf.argmin(neg_dis_val,0)
                # neg_div_size = smart_shape(negative_output)[0]
                # neg_divider = tf.one_hot(hardest_negative_idx,neg_div_size,dtype=tf.int32)
                # hardest_negative = tf.dynamic_partition(negative_distances,neg_divider,2)[1]
                # hardest_negative_class = tf.gather(targets,hardest_negative_idx)
                # hardest_negative = tf.norm(hardest_negative+eps, axis=1)

                # hardest_positive = my_print(hardest_positive,"hardest_positive")
                # hardest_negative = my_print(hardest_negative,"hardest_negative")

                #### Next two lines should be the same
                loss = tf.nn.softplus(hardest_positive - hardest_negative)
                # loss = tf.nn.softplus(hardest_positive - negative_weighting_factor*hardest_negative)
                # loss = tf.log1p(tf.exp(hardest_positive - hardest_negative))

                #### Code for using a hard margin rather than a softmargin
                # margin = 1
                # loss = tf.maximum(0., margin + hardest_positive - hardest_negative)

                anchor_img = tf.zeros([], tf.float32)
                hard_pos_img = tf.zeros([], tf.float32)
                hard_neg_img = tf.zeros([], tf.float32)
                if imgs_raw is not None:
                    positive_images = tf.boolean_mask(
                        imgs_raw, tf.logical_and(class_division,
                                                 not_self_mask))
                    negative_images = tf.boolean_mask(
                        imgs_raw, tf.logical_not(class_division))
                    anchor_img = imgs_raw[idx]
                    hard_pos_img = positive_images[tf.squeeze(
                        hardest_positive_idx)]
                    hard_neg_img = negative_images[tf.squeeze(
                        hardest_negative_idx)]

                    # self.summaries.append(tf.summary.image("anchor_image", imgs_raw[idx]))
                    # positive_images = tf.squeeze(tf.boolean_mask(imgs_raw, tf.logical_and(class_division, not_self_mask)))
                    # negative_images = tf.squeeze(tf.boolean_mask(imgs_raw, tf.logical_not(class_division)))
                    # self.summaries.append(tf.summary.image("hardest_postive_image",positive_images[hardest_positive_idx]))
                    # self.summaries.append(tf.summary.image("hardest_negative_image", negative_images[hardest_negative_idx]))

                return loss, hardest_positive, hardest_negative, anchor_img, hard_pos_img, hard_neg_img

            #### Next two lines should be the same
            loss, hardest_positive, hardest_negative, anchor_imgs, hard_pos_imgs, hard_neg_imgs = \
              tf.map_fn(get_loss, tf.range(0, size), dtype=(tf.float32,tf.float32,tf.float32, tf.float32, tf.float32, tf.float32))
            # loss, hardest_positive, hardest_negative = [get_loss(idx) for idx in xrange(size)]

            self.loss = tf.reduce_sum(loss)
            hardest_positive = tf.reduce_sum(hardest_positive)
            hardest_negative = tf.reduce_sum(hardest_negative)
            self.add_scalar_summary(self.loss, "loss")
            self.add_scalar_summary(hardest_positive, "hardest_positive")
            self.add_scalar_summary(hardest_negative, "hardest_negative")
            # tf.summary.image()
            self.n_features = n_features

            if imgs_raw is not None:
                self.summaries.append(
                    tf.summary.image("anchor_image", anchor_imgs))
                self.summaries.append(
                    tf.summary.image("hardest_postive_image", hard_pos_imgs))
                self.summaries.append(
                    tf.summary.image("hardest_negative_image", hard_neg_imgs))