Esempio n. 1
0
def get_max_diff_adjacent_crops(
    start_id,
    end_id,
    crop_metric,
    model_name,
    image_scale,
    compare_corr=True,
    use_top5=True
):  # eventually add step size, right now defaults to 1 in code

    # compare_correctness: bool indicating whether the final crops should necessarily have different classification correctness
    # use_top5: bool indicating whether using top5 correctness or top1 correctness
    # returns the two crops. If compare_correctness==True and there are no correctly classified crops, returns None.

    crop_type = 'proportional' if crop_metric <= 1. else 'constant'
    folders = [
        PATH_TO_DATA + settings.maxdiff_folder_name(
            'size', crop_metric, model_name, image_scale,
            'diff' if compare_corr else 'any', conf)
        for conf in ['high', 'low']
    ]
    for folder in folders:
        if not os.path.exists(folder):
            os.makedirs(folder)

    sess = tf.Session()
    model = settings.MODELS[model_name]
    imgs = tf.placeholder(tf.float32, [None, model.im_size, model.im_size, 3])
    network = model(imgs, sess)

    image_ids = range(start_id, end_id + 1)
    hc_correct = []
    hc_incorrect = []
    lc_correct = []
    lc_incorrect = []
    h_activations = {}
    l_activations = {}
    for image_id in image_ids:

        f = open('small-dataset-to-imagenet.txt')
        lines = f.readlines()
        image_tag = lines[image_id].split(" ", 1)[0]
        print(image_tag)

        #image_tag = settings.get_ind_name(image_id)
        image_filename = PATH_TO_DATA + settings.folder_name(
            'img') + image_tag  #+ ('.png' if image_id == 50001 else '.JPEG')
        image = Image.open(image_filename)
        if image.mode != 'RGB':
            image = image.convert('RGB')
        image = np.asarray(image)

        image_label = image_tag[:-5] + '_' + str(
            crop_metric) + '_' + model_name + '_'
        correctness_type = 'top5' if use_top5 else 'top1'
        correctness_filename = PATH_TO_DATA + (settings.map_folder_name(
            settings.TOP5_MAPTYPE,
            crop_metric) if use_top5 else settings.map_folder_name(
                settings.TOP1_MAPTYPE, crop_metric)) + image_label + (
                    settings.TOP5_MAPTYPE
                    if use_top5 else settings.TOP1_MAPTYPE) + '.npy'
        cor_map = np.load(correctness_filename)
        corr_extension = '_diffcorrectness' if compare_corr else '_anycorrectness'

        if compare_corr:
            if not cor_map.any():
                print('%s has no correctly classified crops.' % image_tag)
                continue
            elif cor_map.all():
                print('%s has only correctly classified crops.' % image_tag)
                continue

        con_map_filename = PATH_TO_DATA + settings.map_folder_name(
            settings.CONFIDENCE_MAPTYPE,
            crop_metric) + image_label + settings.CONFIDENCE_MAPTYPE + '.npy'
        con_map = np.load(con_map_filename)

        down_diff = np.diff(
            con_map, axis=0)  # apparently assumes step_size=1 (adjacency)
        up_diff = -1. * down_diff
        right_diff = np.diff(con_map)
        left_diff = -1. * right_diff
        diffs = {
            'up': up_diff,
            'down': down_diff,
            'left': left_diff,
            'right': right_diff
        }

        # TESTER: CLASSIFYING CROPS TO SEE IF THERE'S A DIFFERENCE BETWEEN WHAT THE TESTER REPORTS AND WHAT THIS REPORTS
        true_labels = json.load(
            open('caffe_ilsvrc12/' + settings.DATASET + '-labels.json'))

        while True:
            maxes = {
                direction: np.unravel_index(np.argmax(diffs[direction]),
                                            diffs[direction].shape)
                for direction in diffs
            }  # map each directional diff to its argmax (index of its maximum confidence diff)
            max_dir = max(
                [direction for direction in maxes],
                key=lambda direction: diffs[direction][tuple(maxes[direction])]
            )  # get the direction of the diff whose max confidence is the highest out of the four max confidences
            # depending on the max-confidence direction, get the argmax of that direction. The more confident crop will be offset by 1 in a way that depends on the direction.
            if max_dir == 'up':
                up_max = maxes['up']
                gcell, cell = (
                    tuple(up_max), (up_max[0] + 1, up_max[1])
                )  # up (and left) are like this because when up and left diffs are made, the negation also changes the direction in which your step goes. it goes down -> up; right -> left.
            elif max_dir == 'down':
                down_max = maxes['down']
                cell, gcell = (tuple(down_max), (down_max[0] + 1, down_max[1]))
            elif max_dir == 'left':
                left_max = maxes['left']
                gcell, cell = (tuple(left_max), (left_max[0], left_max[1] + 1))
            else:
                right_max = maxes['right']
                cell, gcell = (tuple(right_max), (right_max[0],
                                                  right_max[1] + 1))

            diff_correctness = cor_map[cell] != cor_map[gcell]
            if diff_correctness or not compare_correctness:
                y, x = cell
                gy, gx = gcell
                height, width, channels = image.shape
                crop_size = get_crop_size(
                    height, proportion) if height <= width else get_crop_size(
                        width, proportion)
                dim_used = 'height' if height <= width else 'width'

                cropped = image[cell[0]:cell[0] + crop_size,
                                cell[1]:cell[1] + crop_size]
                gcropped = image[gcell[0]:gcell[0] + crop_size,
                                 gcell[1]:gcell[1] + crop_size]
                true_value = true_labels[image_tag[:-5]]
                hc = imresize(gcropped, (network.im_size, network.im_size))
                lc = imresize(cropped, (network.im_size, network.im_size))

                hresult = sess.run(network.pull_layers,
                                   feed_dict={network.imgs: [hc]})
                hcprob = hresult[0][0]
                h_activations[image_id] = hresult[1:]

                result = sess.run(network.pull_layers,
                                  feed_dict={network.imgs: [lc]})
                lcprob = lresult[0][0]
                l_activations[image_id] = lresult[1:]

                hcpreds = (np.argsort(hcprob)[::-1])[0:5]
                lcpreds = (np.argsort(lcprob)[::-1])[0:5]

                if true_value in hcpreds:
                    hc_correct.append(image_id)
                else:
                    hc_incorrect.append(image_id)
                if true_value in lcpreds:
                    lc_correct.append(image_id)
                else:
                    lc_incorrect.append(image_id)

                maxdiff_folder = settings.maxdiff_folder_name(crop_metric)
                np.save(
                    PATH_TO_DATA + maxdiff_folder + image_label +
                    'maxdiff_lowconf' + corr_extension, cropped)
                np.save(
                    PATH_TO_DATA + maxdiff_folder + image_label +
                    'maxdiff_highconf' + corr_extension, gcropped)
                break

            else:
                if max_dir in ['up', 'left']:
                    diffs[max_dir][
                        gcell] = -2.  # for the diff where that was the argmax, mark the cell containing it to something lower than any real entry (-1. <= real entry <= 1.) This is gcell for up, left and cell for down, right because the lower-indexed cell is always the one that contained the confidence originally
                else:
                    diffs[max_dir][cell] = -2.

    print('INTERNAL TEST')
    print("High confidence crop correctly classified:", hc_correct)
    print('High confidence crop incorrectly classified:', hc_incorrect)
    print('Low confidence crop correctly classified:', lc_correct)
    print('Low confidence crop incorrectly classified:', lc_incorrect)
    sess.close()
    return h_activations, l_activations
Esempio n. 2
0
def backprop_crops(image_id, crop_metric, model_name, image_scale):
    '''
    note: even with the graph inefficiency, it makes more sense for this function to be one image at a time because the indices are different for each one. This would only change if I figured out a programmatic way to find the right indices. 
    '''

    # Get indices for this map
    with open(PATH_TO_DATA + settings.BACKPROP_INDICES_FILENAME,
              'r') as indfile:
        all_inds = json.load(indfile)
        indices = all_inds[str(
            (crop_metric, model_name, image_scale, image_id))]

    with tf.Session() as sess:

        # Set up CNN
        model = settings.MODELS[model_name]
        batch_size = len(indices)
        imgs = tf.placeholder(tf.float32,
                              [batch_size, model.im_size, model.im_size, 3])
        network = model(imgs, sess)

        # Create backprop objects
        true_labels = json.load(
            open('caffe_ilsvrc12/' + settings.DATASET + '-labels.json'))
        true_label = true_labels[settings.get_ind_name(image_id)]
        y = tf.constant([true_label for __ in range(batch_size)])
        err = tf.nn.sparse_softmax_cross_entropy_with_logits(
            labels=y, logits=network.logits)
        dy_dx = tf.gradients(err, network.imgs)

        # Scale image, get all crops and run backprop
        image = Image.open(PATH_TO_DATA + settings.folder_name('img') +
                           settings.get_ind_name(image_id) + '.JPEG')
        width, height = image.size
        image = imresize(image,
                         (int(width * image_scale), int(height * image_scale)))
        crop_type = 'proportional' if crop_metric <= 1. else 'constant'
        crop_size = get_crop_size(
            height, crop_metric,
            crop_type) if height <= width else get_crop_size(
                width, crop_metric, crop_type)
        all_crops = []
        for x1, y1 in indices:
            crop = image[y1:y1 + crop_size, x1:x1 + crop_size, :]
            # crop = image.crop((x1, y1, x1 + crop_size, y1 + crop_size))
            all_crops.append(imresize(crop, (model.im_size, model.im_size)))
            # all_crops.append(imresize(image, (model.im_size, model.im_size)))	# TODO remove after making sure this code is working

        backprops = sess.run(
            dy_dx,
            feed_dict={network.imgs: model.preprocess(np.array(all_crops))})[0]

    # Make backprop results visualizable
    backprops = backprops - np.min(backprops, axis=(1, 2), keepdims=True)
    backprops = backprops / np.max(backprops, axis=(1, 2), keepdims=True)
    backprops = backprops * 255.
    backprops = backprops.astype(np.uint8)

    # savez results
    folder = PATH_TO_DATA + settings.map_folder_name(
        settings.BACKPROP_MAPTYPE, crop_metric, model_name, image_scale)
    filename = PATH_TO_DATA + settings.map_filename(
        settings.BACKPROP_MAPTYPE, crop_metric, model_name, image_scale,
        image_id)
    if not os.path.exists(folder):
        os.makedirs(folder)
    np.savez(filename,
             **{str(indices[i]): backprops[i]
                for i in range(len(indices))})
def create_confidence_map(start_id,
                          end_id,
                          crop_metric,
                          model_name,
                          image_scale,
                          make_cmap=True,
                          make_top5=True,
                          make_top1=True,
                          make_distance=True):

    # Get the crop type - if the crop_metric is a fraction, it's a proportion. If it's larger than 1, it's a constant crop size.
    crop_type = 'proportional' if crop_metric <= 1. else 'constant'

    # Prepare folders
    maptypes = [
        settings.CONFIDENCE_MAPTYPE, settings.TOP5_MAPTYPE,
        settings.TOP1_MAPTYPE, settings.DISTANCE_MAPTYPE
    ]
    folders = [
        PATH_TO_DATA +
        settings.map_folder_name(maptype, crop_metric, model_name, image_scale)
        for maptype in maptypes
    ]
    for folder in folders:
        if not os.path.exists(folder):
            os.makedirs(folder)

    # Get the right model
    model = settings.MODELS[model_name]

    # Before anything else happens, so we only set up once despite multiple images, make a network for each GPU
    config = tf.ConfigProto(log_device_placement=True,
                            allow_soft_placement=True)
    config.gpu_options.allow_growth = True
    sess = tf.Session(config=config)
    networks = []
    for i in range(NUM_GPUS):
        gpu = 'device:GPU:%d' % i
        with tf.device(gpu):
            imgs = tf.placeholder(
                tf.float32, [BATCH_SIZE, model.im_size, model.im_size, 3])
            if not model_name == 'alexnet':
                network = model(imgs, sess, reuse=None if i == 0 else True)
            else:
                network = model(imgs, sess)
            networks.append(network)

    # Get each map called for!
    labels_file = open('caffe_ilsvrc12/' + settings.DATASET + '-labels.json')
    true_labels = json.load(labels_file)
    image_ids = range(start_id, end_id + 1)

    for image_id in image_ids:

        f = open('small-dataset-to-imagenet.txt')
        lines = f.readlines()
        image_tag = lines[image_id].split(" ", 1)[0]
        print(image_tag)

        #image_tag = settings.get_ind_name(image_id)

        image_filename = PATH_TO_DATA + settings.folder_name(
            'img') + image_tag  #+ ('.png' if image_id == 50001 else'.JPEG')
        true_class = true_labels[image_tag[:-5]] if image_id != 50001 else 266
        im = Image.open(image_filename)
        if im.mode != 'RGB':
            im = im.convert(
                'RGB'
            )  # make sure bw images are 3-channel, because they get opened in L mode
        width, height = im.size

        # Resize image based on image_scale
        im = im.resize((int(width * image_scale), int(height * image_scale)))

        width, height = im.size

        # TODO do resizing experiment    im = imresize(im, (width*image_scale, height*image_scale))	# resize image as needed

        crop_size = get_crop_size(
            height, crop_metric,
            crop_type) if height <= width else get_crop_size(
                width, crop_metric, crop_type)
        crop_size -= 2  # reduce size by two pixels for small crops
        crop_x1s = range(width - crop_size + 1)
        crop_y1s = range(height - crop_size + 1)
        crop_dims = itertools.product(crop_x1s, crop_y1s)

        C, O, F, D = (np.zeros((height - crop_size + 1, width - crop_size + 1))
                      for __ in range(4))
        crop_dims = list(crop_dims)
        total_crops = len(crop_dims)
        crop_index = 0

        overall_start_time = time.clock()
        print('TOTAL CROPS:', total_crops)
        sys.stdout.flush()
        while crop_index < total_crops:  # While we haven't exhausted crops TODO see if the logic needs to be changed
            all_cropped_imgs = []
            stub_crops = 0  # Initializing to 0 in case there's an image with no stub crops (i.e. number of crops is a multiple of 64)
            map_indices = [
            ]  # The indices that these confidences will be mapped to

            for i in range(
                    BATCH_SIZE * NUM_GPUS
            ):  # Get BATCH_SIZE crops for each GPU (total of NUM_GPUS)

                if crop_index == total_crops:  # If we're on the last round and it's not all 64, repeat the last crop for the rest
                    stub_crops = (
                        BATCH_SIZE * NUM_GPUS
                    ) - i  # the number of crops still needed, because i in this round is the number of crops that have already been filled in
                    cropped = imresize(
                        cropped, (model.im_size, model.im_size)
                    )  # resize the last one (from previous round) permanently. There will be a previous one due to the while logic
                    for i in range(stub_crops):
                        all_cropped_imgs.append(
                            cropped
                        )  # fill in the rest of the slots with the resized last crop
                    break

                # If not on the last one, continue on to fill in the next crop
                x1, y1 = crop_dims[crop_index]
                map_indices.append((x1, y1))
                cropped = im.crop((x1, y1, x1 + crop_size, y1 + crop_size))
                all_cropped_imgs.append(
                    imresize(cropped, (model.im_size, model.im_size)))
                crop_index += 1  # Increment to get the next crop dimensions

            start_time = time.clock()
            network_probs = list(map(lambda x: x.probs, networks))
            num_crops = len(all_cropped_imgs)
            partition_cropped_imgs = [
                all_cropped_imgs[int(i * num_crops / NUM_GPUS):min(
                    num_crops, int((i + 1) * num_crops / NUM_GPUS))]
                for i in range(NUM_GPUS)
            ]  # TODO yikes is this correct
            prob = np.array(
                sess.run(network_probs,
                         feed_dict={
                             networks[i].imgs: model.preprocess(
                                 np.array(partition_cropped_imgs[i]))
                             for i in range(NUM_GPUS)
                         }))

            #  prob = sess.run(vgg.probs, feed_dict={vgg.imgs: all_cropped_imgs})
            end_time = time.clock()
            print('Time for running one size-' + str(BATCH_SIZE), 'batch:',
                  end_time - start_time, 'seconds')
            print('CROPS COMPLETED SO FAR:', crop_index)
            sys.stdout.flush()

            # plot the confidences in the map. For final iteration, which likely has <BATCH_SIZE meaningful crops, the index list being of shorter length will cause them to be thrown.
            confidence = prob[:, :, true_class].reshape(BATCH_SIZE * NUM_GPUS)
            for i in range(len(map_indices)):
                c, r = map_indices[i]
                C[r, c] = confidence[i]

            # plot the top-5 and top-1 binary correctness maps
            flat_probs = prob.reshape(
                (NUM_GPUS * BATCH_SIZE, settings.NUM_CLASSES))
            sorted_classes = flat_probs.argsort(axis=1)
            top_5 = sorted_classes[:, -5:]
            top_1 = sorted_classes[:, -1].squeeze()
            for i in range(len(map_indices)):
                c, r = map_indices[i]
                O[r, c] = 255. if top_1[i] == true_class else 0.
                F[r, c] = 255. if true_class in top_5[i] else 0.

            # plot the distance map
            sixth = sorted_classes[:, 6]
            for i in range(len(map_indices)):
                c, r = map_indices[i]
                if true_class in top_5[i]:
                    D[r, c] = 255. * flat_probs[i][true_class] - flat_probs[i][
                        sixth[i]]
                else:
                    D[r, c] = 0.

        overall_end_time = time.clock()
        print(
            'Time for overall cropping and map-building process with size-' +
            str(BATCH_SIZE), 'batch:', overall_end_time - overall_start_time,
            'seconds')
        sys.stdout.flush()

        # Make confidence map, save to confidence map folder
        if make_cmap:
            np.save(
                PATH_TO_DATA +
                settings.map_filename(settings.CONFIDENCE_MAPTYPE, crop_metric,
                                      model_name, image_scale, image_id) +
                '_small', C)

        # Save binary correctness maps
        if make_top5:
            np.save(
                PATH_TO_DATA +
                settings.map_filename(settings.TOP5_MAPTYPE, crop_metric,
                                      model_name, image_scale, image_id) +
                '_small', F)
        if make_top1:
            np.save(
                PATH_TO_DATA +
                settings.map_filename(settings.TOP1_MAPTYPE, crop_metric,
                                      model_name, image_scale, image_id) +
                '_small', O)

        # Save distance maps
        if make_distance:
            np.save(
                PATH_TO_DATA +
                settings.map_filename(settings.DISTANCE_MAPTYPE, crop_metric,
                                      model_name, image_scale, image_id) +
                '_small', D)

        print(image_tag)