                       self.__class__.__name__, detector, aligner, masker, configfile,
                       multiprocess, rotate_images, min_size, normalize_method, image_is_aligned)
          self._flow = self._set_flow(detector, aligner, masker)
          self.phase = self._flow[0]
          self._queue_size = 32
          self._vram_buffer = 256  # Leave a buffer for VRAM allocation
          self._detect = self._load_detect(detector, rotate_images, min_size, configfile)
          self._align = self._load_align(aligner, configfile, normalize_method)
          self._mask = self._load_mask(masker, image_is_aligned, configfile)
          self._is_parallel = self._set_parallel_processing(multiprocess)
 
</s> remove             self._queue_size = 32
            if task == "extract_{}_in".format(self._flow[0]) or (not self._is_parallel
                                                                 and not task.endswith("_out")):
                self._queue_size = 64
 </s> add  </s> remove         self.queue_size = 32
 </s> add         self.queue_size = 1 </s> remove         for phase in range(self.extractor.passes):
 </s> add         for phase in range(self._extractor.passes): </s> remove         io_args = (self._queue) if io_args is None else (self._queue, *io_args)
        retval = MultiThread(getattr(self, "_{}".format(self._task)), *io_args, thread_count=1)
        logger.trace(retval)
        return retval
 </s> add         if self._is_video:
            self._count = int(count_frames(self.location, fast=fast_count))
            self._file_list = [self._dummy_video_framename(i + 1) for i in range(self.count)]
        else:
            if isinstance(self.location, (list, tuple)):
                self._file_list = self.location
            else:
                self._file_list = get_image_paths(self.location)
            self._count = len(self.file_list) </s> remove         self._task = task.lower()
        self._is_video = self._check_input()
        self._input = self.location if self._is_video else get_image_paths(self.location)
        self._count = count_frames(self._input) if self._is_video else len(self._input)
        self._queue = queue_manager.get_queue(name="{}_{}".format(self.__class__.__name__,
                                                                  self._task),
                                              maxsize=queue_size)
        self._thread = self._set_thread(io_args=(load_with_hash, ))
        self._thread.start()
 </s> add         self._count = None
        self._file_list = None
        self._get_count_and_filelist(fast_count)
        # We only ever need 1 item in each queue. This is 2 items cached (1 in queue 1 waiting
        # for queue) at each point. Adding more just stacks RAM with no speed benefit.
        self._queue_size = 1
                       self.__class__.__name__, detector, aligner, masker, configfile,
                       multiprocess, rotate_images, min_size, normalize_method, image_is_aligned)
          self._flow = self._set_flow(detector, aligner, masker)
          self.phase = self._flow[0]
        # We only ever need 1 item in each queue. This is 2 items cached (1 in queue 1 waiting
        # for queue) at each point. Adding more just stacks RAM with no speed benefit.
        self._queue_size = 1
          self._vram_buffer = 256  # Leave a buffer for VRAM allocation
          self._detect = self._load_detect(detector, rotate_images, min_size, configfile)
          self._align = self._load_align(aligner, configfile, normalize_method)
          self._mask = self._load_mask(masker, image_is_aligned, configfile)
          self._is_parallel = self._set_parallel_processing(multiprocess)
keep keep keep keep replace keep keep keep keep keep
 scripts.extract - code optimizations

Limit queue sizes to reduce RAM usage
Rename lib.image.BackgroundIO to ImageIO
Create separate ImagesLoader and ImagesSaver classes
Load/Save images from centralized lib.image.ImageIO
scripts.extract documentation 
plugins/extract/pipeline.py