          self.name = "VGG_Face2"
          self.input_size = 224
          # Average image provided in https://github.com/ox-vgg/vgg_face2
          self._average_img = np.array([91.4953, 103.8827, 131.0912])
          self._iterator = self._get_bin()
  
          logger.debug("Initialized %s", self.__class__.__name__)
 
</s> remove         kwargs = dict(method=method)
        if self._use_vector_linkage(num_predictions, dims):
            func = linkage_vector
        else:
            kwargs["preserve_input"] = False
            func = linkage
 </s> add         self._result_linkage = self._do_linkage(predictions, method)
        logger.debug("Initialized %s", self.__class__.__name__) </s> remove         self._args = arguments
        self.changes = None
        self.serializer = None
        self._vgg_face = None
        self._loader = FacesLoader(self._args.input_dir)

    def process(self):
        """ Main processing function of the sort tool """

        # Setting default argument values that cannot be set by argparse

        # Set output folder to the same value as input folder
        # if the user didn't specify it.
        if self._args.output_dir is None:
            logger.verbose("No output directory provided. Using input folder as output folder.")
            self._args.output_dir = self._args.input_dir

        # Assigning default threshold values based on grouping method
        if (self._args.final_process == "folders"
                and self._args.min_threshold < 0.0):
            method = self._args.group_method.lower()
            if method == 'face-cnn':
                self._args.min_threshold = 7.2
            elif method == 'hist':
                self._args.min_threshold = 0.3

        # Load VGG Face if sorting by face
        if self._args.sort_method.lower() == "face":
            self._vgg_face = VGGFace(exclude_gpus=self._args.exclude_gpus)
            self._vgg_face.init_model()

        # If logging is enabled, prepare container
        if self._args.log_changes:
            self.changes = {}

            # Assign default sort_log.json value if user didn't specify one
            if self._args.log_file_path == 'sort_log.json':
                self._args.log_file_path = os.path.join(self._args.input_dir,
                                                        'sort_log.json')

            # Set serializer based on log file extension
            self.serializer = get_serializer_from_filename(self._args.log_file_path)

        # Prepare sort, group and final process method names
        _sort = "sort_" + self._args.sort_method.lower()
        _group = "group_" + self._args.group_method.lower()
        _final = "final_process_" + self._args.final_process.lower()
        if _sort.startswith('sort_color-'):
            self._args.color_method = _sort.replace('sort_color-', '')
            _sort = _sort[:10]
        self._args.sort_method = _sort.replace('-', '_')
        self._args.group_method = _group.replace('-', '_')
        self._args.final_process = _final.replace('-', '_')

        self.sort_process()

    def launch_aligner(self):
        """ Load the aligner plugin to retrieve landmarks """
        extractor = Extractor(None, "fan", None,
                              normalize_method="hist", exclude_gpus=self._args.exclude_gpus)
        extractor.set_batchsize("align", 1)
        extractor.launch()
        return extractor

    @staticmethod
    def alignment_dict(filename, image):
        """ Set the image to an ExtractMedia object for alignment """
        height, width = image.shape[:2]
        face = DetectedFace(left=0, width=width, top=0, height=height)
        return ExtractMedia(filename, image, detected_faces=[face])

    def _get_landmarks(self):
        """ Multi-threaded, parallel and sequentially ordered landmark loader """
        extractor = self.launch_aligner()
        filename_list, image_list = self._get_images()
        feed_list = list(map(Sort.alignment_dict, filename_list, image_list))
        landmarks = np.zeros((len(feed_list), 68, 2), dtype='float32')

        logger.info("Finding landmarks in images...")
        # TODO thread the put to queue so we don't have to put and get at the same time
        # Or even better, set up a proper background loader from disk (i.e. use lib.image.ImageIO)
        for idx, feed in enumerate(tqdm(feed_list, desc="Aligning", file=sys.stdout)):
            extractor.input_queue.put(feed)
            landmarks[idx] = next(extractor.detected_faces()).detected_faces[0].landmarks_xy

        return filename_list, image_list, landmarks

    def _get_images(self):
        """ Multi-threaded, parallel and sequentially ordered image loader """
        logger.info("Loading images...")
        filename_list = self.find_images(self._args.input_dir)
        with futures.ThreadPoolExecutor() as executor:
            image_list = list(tqdm(executor.map(read_image, filename_list),
                                   desc="Loading Images",
                                   file=sys.stdout,
                                   total=len(filename_list)))

        return filename_list, image_list
 </s> add         logger.debug("Initializing %s: arguments: %s", self.__class__.__name__, arguments)
        self._processes = dict(blur=SortBlur,
                               blur_fft=SortBlur,
                               distance=SortDistance,
                               yaw=SortYaw,
                               pitch=SortPitch,
                               size=SortSize,
                               face=SortFace,
                               face_cnn=SortFaceCNN,
                               face_cnn_dissim=SortFaceCNN,
                               hist=SortHistogram,
                               hist_dissim=SortHistogram,
                               color_black=SortColor,
                               color_gray=SortColor,
                               color_luma=SortColor,
                               color_green=SortColor,
                               color_orange=SortColor)

        self._args = self._parse_arguments(arguments)
        self._changes = {}
        self.serializer: Optional[Serializer] = None

        if arguments.log_changes:
            self.serializer = get_serializer_from_filename(arguments.log_file_path)

        self._sorter = self._get_sorter()
        logger.debug("Initialized %s", self.__class__.__name__)

    def _set_output_folder(self, arguments):
        """ Set the output folder correctly if it has not been provided
        Parameters:
        ----------
        arguments: :class:`argparse.Namespace`
            The command line arguments passed to the sort process </s> remove         Returns
        -------
        float
            The estimated fft blur score for the face
 </s> add         Obtains the bins and original filenames from :attr:`_sorter` and outputs into appropriate
        bins in the output location
        self._bins = {}
          self.name = "VGG_Face2"
          self.input_size = 224
        self._bins = {}
          # Average image provided in https://github.com/ox-vgg/vgg_face2
          self._average_img = np.array([91.4953, 103.8827, 131.0912])
          self._iterator = self._get_bin()
  
          logger.debug("Initialized %s", self.__class__.__name__)
keep add keep keep keep keep keep
 Overhaul sort:
  - Standardize image data reading and writing
  - Optimize loading (just one pass required)
  - Make all sort groups binnable (to greater or lesser results)
  - Add sort by pitch
  - Deprecate multiple options
  - linting, docs + locales 
plugins/extract/recognition/vgg_face2_keras.py