Skip to content

Processor

TransformersQAProcessor

Question Answering Data Processor. Use this class to generate tensor inputs from human legible text/string data. This class can be used with a majority of the Bert architecture transformer models with the span-based extractive, Question Answering predictive head from Hugging Face.

Usage:

>>> processor = TRansformersQAProcessor(model_name_or_path="distilbert-base-cased-distilled-squad")
>>> processor.process(query=["string"], context["string"])

**Parameters:**

* **model_name_or_path** - String defining HF question answering model/tokenizer's name
Source code in fastnn/processors/nlp/question_answering.py
class TransformersQAProcessor(Processor):
    """Question Answering Data Processor. Use this class to generate tensor inputs from human legible text/string data.
    This class can be used with a majority of the Bert architecture transformer models with the span-based extractive,
    Question Answering predictive head from Hugging Face.

    Usage:
    ```python
    >>> processor = TRansformersQAProcessor(model_name_or_path="distilbert-base-cased-distilled-squad")
    >>> processor.process(query=["string"], context["string"])

    **Parameters:**

    * **model_name_or_path** - String defining HF question answering model/tokenizer's name
    ```
    """

    def __init__(
        self, model_name_or_path: str = "distilbert-base-cased-distilled-squad"
    ):
        self.tokenizer = AutoTokenizer.from_pretrained(
            model_name_or_path, use_fast=False
        )  # Can't use fast tokenizer yet for QA `use_fast=True`

    def process(
        self,
        query: List[str],
        context: List[str],
        max_seq_length: int = 512,
        doc_stride: int = 128,
        max_query_length: int = 64,
    ) -> Tuple[List[SquadExample], List[SquadFeatures], Dataset]:
        """Generate torch `Dataset` object from query/context string pairs using specified tokenizer from HF.
        This provides clear tensor input representations for compatible models.

        Returns a tuple `Dataset` and matching `SquadFeatures`

        * **query** - List of query strings, must be same length as `context`
        * **context** - List of context strings, must be same length as `query`
        * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
        * **doc_stride** - Number of token strides to take when splitting up context into chunks of size `max_seq_length`
        * **max_query_length** - Maximum token length for queries
        """
        examples = self._generate_squad_examples(query=query, context=context)
        features, dataset = squad_convert_examples_to_features(
            examples,
            self.tokenizer,
            max_seq_length=max_seq_length,
            doc_stride=doc_stride,
            max_query_length=max_query_length,
            is_training=False,
            return_dataset="pt",
            threads=1,
        )

        return examples, features, dataset

    def process_batch(
        self,
        query: List,
        context: List,
        mini_batch_size: int = 8,
        max_seq_length: int = 512,
        doc_stride: int = 128,
        max_query_length: int = 64,
        use_gpu: bool = False,
    ) -> Tuple[List[SquadExample], List[SquadFeatures], DataLoader]:
        """Generate torch `DataLoader` object from query/context string pairs using specified tokenizer from HF.
        This provides clear tensor input representations for compatible models in an easy to use batch

        Returns a tuple of (List[`SquadExample`], List[`SquadFeatures`], `DataLoader`)

        * **query** - List of query strings, must be same length as `context`
        * **context** - List of context strings, must be same length as `query`
        * **mini_batch_size** - Batch size for inference
        * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
        * **doc_stride** - Number of token strides to take when splitting up context into chunks of size `max_seq_length`
        * **max_query_length** - Maximum token length for queries
        * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
        """

        if use_gpu:
            if torch.cuda.is_available():
                device = torch.device("cuda")
            else:
                logger.info("GPU not available")
                device = torch.device("cpu")
        else:
            device = torch.device("cpu")

        examples, features, dataset = self.process(
            query=query,
            context=context,
            max_seq_length=max_seq_length,
            doc_stride=doc_stride,
            max_query_length=max_query_length,
        )

        dataloader = DataLoader(
            dataset,
            batch_size=mini_batch_size,
            collate_fn=lambda x: [t.to(device) for t in self._qa_collate_fn(x)],
        )

        return examples, features, dataloader

    def process_output(
        self,
        outputs: List[Tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
        examples: List[SquadExample],
        features: List[SquadFeatures],
        n_best_size: int = 5,
        max_answer_length: int = 10,
        do_lower_case: bool = False,
        verbose_logging: bool = False,
        version_2_with_negative: bool = False,
        null_score_diff_threshold: float = 0.0,
    ):
        pass

    def process_output_batch(
        self,
        outputs: List[Tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
        examples: List[SquadExample],
        features: List[SquadFeatures],
        n_best_size: int = 5,
        max_answer_length: int = 64,
        do_lower_case: bool = False,
        verbose_logging: bool = False,
        version_2_with_negative: bool = False,
        null_score_diff_threshold: float = 0.0,
    ) -> Tuple[OrderedDict, OrderedDict]:
        """Process output of Transformers QA model into human legible results.

        * **outputs** - List of batch output tensors from a model's forward pass
        * **examples** - List of `SquadExample` objects for each original context/query pair used as input. This is returned from the built-in `process()` or `process_batch()` methods
        * **features** - List of `SquadFeature` objects for each context/query pair over the original doc_stride lengths. This is also returned from the built-in `process()` or `process_batch()` methods
        * **n_best_size** - Number of top n results you want
        * **max_answer_length** - Maximum token length for answers that are returned
        * **do_lower_case** - Set as `True` if using uncased QA models
        * **verbose_logging** - Set True if you want prediction verbose loggings
        * **version_2_with_negative** - Set as True if using QA model with SQUAD2.0
        * **null_score_diff_threshold** - Threshold for predicting null(no answer) in Squad 2.0 Model.  Default is 0.0.  Raise this if you want fewer null answers
        """

        # Generate results per example query
        all_results: List[SquadResult] = []
        for output in outputs:
            example_indices = output[2]
            for i, example_index in enumerate(example_indices):
                start_logits = self._to_list(output[0][i])
                end_logits = self._to_list(output[1][i])
                eval_feature = features[example_index[0].item()]
                unique_id = int(eval_feature.unique_id)
                result = SquadResult(unique_id, start_logits, end_logits)
                all_results.append(result)

        # Compute predictions based off logits on a per example basis
        answers, n_best = compute_predictions_logits(
            all_examples=examples,
            all_features=features,
            all_results=all_results,
            n_best_size=n_best_size,
            max_answer_length=max_answer_length,
            do_lower_case=do_lower_case,
            verbose_logging=verbose_logging,
            version_2_with_negative=version_2_with_negative,
            null_score_diff_threshold=null_score_diff_threshold,
            tokenizer=self.tokenizer,
        )

        return answers, n_best

    def _qa_collate_fn(self, data):
        batch = default_collate(data)
        # Generate same batch dims for scalars to address future batch inferencing
        batch[3].unsqueeze_(1)
        batch[4].unsqueeze_(1)
        return batch

    def _to_list(self, tensor: torch.Tensor):
        return tensor.detach().cpu().tolist()

    def _generate_squad_examples(
        self, query: List[str], context: List[str]
    ) -> List[SquadExample]:
        """Generate HF Squad Example objects with query/context pairs"""
        assert len(query) == len(context)
        examples = []
        title = "qa"
        is_impossible = False
        answer_text = None
        start_position_character = None
        answers = ["answer"]
        for idx, (q, c) in enumerate(zip(query, context)):
            example = SquadExample(
                qas_id=str(idx),
                question_text=q,
                context_text=c,
                answer_text=answer_text,
                start_position_character=start_position_character,
                title=title,
                is_impossible=is_impossible,
                answers=answers,
            )
            examples.append(example)
        return examples

process(self, query, context, max_seq_length=512, doc_stride=128, max_query_length=64)

Generate torch Dataset object from query/context string pairs using specified tokenizer from HF. This provides clear tensor input representations for compatible models.

Returns a tuple Dataset and matching SquadFeatures

  • query - List of query strings, must be same length as context
  • context - List of context strings, must be same length as query
  • max_seq_length - Maximum context token length. Check model configs to see max sequence length the model was trained with
  • doc_stride - Number of token strides to take when splitting up context into chunks of size max_seq_length
  • max_query_length - Maximum token length for queries
Source code in fastnn/processors/nlp/question_answering.py
def process(
    self,
    query: List[str],
    context: List[str],
    max_seq_length: int = 512,
    doc_stride: int = 128,
    max_query_length: int = 64,
) -> Tuple[List[SquadExample], List[SquadFeatures], Dataset]:
    """Generate torch `Dataset` object from query/context string pairs using specified tokenizer from HF.
    This provides clear tensor input representations for compatible models.

    Returns a tuple `Dataset` and matching `SquadFeatures`

    * **query** - List of query strings, must be same length as `context`
    * **context** - List of context strings, must be same length as `query`
    * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
    * **doc_stride** - Number of token strides to take when splitting up context into chunks of size `max_seq_length`
    * **max_query_length** - Maximum token length for queries
    """
    examples = self._generate_squad_examples(query=query, context=context)
    features, dataset = squad_convert_examples_to_features(
        examples,
        self.tokenizer,
        max_seq_length=max_seq_length,
        doc_stride=doc_stride,
        max_query_length=max_query_length,
        is_training=False,
        return_dataset="pt",
        threads=1,
    )

    return examples, features, dataset

process_batch(self, query, context, mini_batch_size=8, max_seq_length=512, doc_stride=128, max_query_length=64, use_gpu=False)

Generate torch DataLoader object from query/context string pairs using specified tokenizer from HF. This provides clear tensor input representations for compatible models in an easy to use batch

Returns a tuple of (List[SquadExample], List[SquadFeatures], DataLoader)

  • query - List of query strings, must be same length as context
  • context - List of context strings, must be same length as query
  • mini_batch_size - Batch size for inference
  • max_seq_length - Maximum context token length. Check model configs to see max sequence length the model was trained with
  • doc_stride - Number of token strides to take when splitting up context into chunks of size max_seq_length
  • max_query_length - Maximum token length for queries
  • use_gpu - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
Source code in fastnn/processors/nlp/question_answering.py
def process_batch(
    self,
    query: List,
    context: List,
    mini_batch_size: int = 8,
    max_seq_length: int = 512,
    doc_stride: int = 128,
    max_query_length: int = 64,
    use_gpu: bool = False,
) -> Tuple[List[SquadExample], List[SquadFeatures], DataLoader]:
    """Generate torch `DataLoader` object from query/context string pairs using specified tokenizer from HF.
    This provides clear tensor input representations for compatible models in an easy to use batch

    Returns a tuple of (List[`SquadExample`], List[`SquadFeatures`], `DataLoader`)

    * **query** - List of query strings, must be same length as `context`
    * **context** - List of context strings, must be same length as `query`
    * **mini_batch_size** - Batch size for inference
    * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
    * **doc_stride** - Number of token strides to take when splitting up context into chunks of size `max_seq_length`
    * **max_query_length** - Maximum token length for queries
    * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
    """

    if use_gpu:
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            logger.info("GPU not available")
            device = torch.device("cpu")
    else:
        device = torch.device("cpu")

    examples, features, dataset = self.process(
        query=query,
        context=context,
        max_seq_length=max_seq_length,
        doc_stride=doc_stride,
        max_query_length=max_query_length,
    )

    dataloader = DataLoader(
        dataset,
        batch_size=mini_batch_size,
        collate_fn=lambda x: [t.to(device) for t in self._qa_collate_fn(x)],
    )

    return examples, features, dataloader

process_output_batch(self, outputs, examples, features, n_best_size=5, max_answer_length=64, do_lower_case=False, verbose_logging=False, version_2_with_negative=False, null_score_diff_threshold=0.0)

Process output of Transformers QA model into human legible results.

  • outputs - List of batch output tensors from a model's forward pass
  • examples - List of SquadExample objects for each original context/query pair used as input. This is returned from the built-in process() or process_batch() methods
  • features - List of SquadFeature objects for each context/query pair over the original doc_stride lengths. This is also returned from the built-in process() or process_batch() methods
  • n_best_size - Number of top n results you want
  • max_answer_length - Maximum token length for answers that are returned
  • do_lower_case - Set as True if using uncased QA models
  • verbose_logging - Set True if you want prediction verbose loggings
  • version_2_with_negative - Set as True if using QA model with SQUAD2.0
  • null_score_diff_threshold - Threshold for predicting null(no answer) in Squad 2.0 Model. Default is 0.0. Raise this if you want fewer null answers
Source code in fastnn/processors/nlp/question_answering.py
def process_output_batch(
    self,
    outputs: List[Tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
    examples: List[SquadExample],
    features: List[SquadFeatures],
    n_best_size: int = 5,
    max_answer_length: int = 64,
    do_lower_case: bool = False,
    verbose_logging: bool = False,
    version_2_with_negative: bool = False,
    null_score_diff_threshold: float = 0.0,
) -> Tuple[OrderedDict, OrderedDict]:
    """Process output of Transformers QA model into human legible results.

    * **outputs** - List of batch output tensors from a model's forward pass
    * **examples** - List of `SquadExample` objects for each original context/query pair used as input. This is returned from the built-in `process()` or `process_batch()` methods
    * **features** - List of `SquadFeature` objects for each context/query pair over the original doc_stride lengths. This is also returned from the built-in `process()` or `process_batch()` methods
    * **n_best_size** - Number of top n results you want
    * **max_answer_length** - Maximum token length for answers that are returned
    * **do_lower_case** - Set as `True` if using uncased QA models
    * **verbose_logging** - Set True if you want prediction verbose loggings
    * **version_2_with_negative** - Set as True if using QA model with SQUAD2.0
    * **null_score_diff_threshold** - Threshold for predicting null(no answer) in Squad 2.0 Model.  Default is 0.0.  Raise this if you want fewer null answers
    """

    # Generate results per example query
    all_results: List[SquadResult] = []
    for output in outputs:
        example_indices = output[2]
        for i, example_index in enumerate(example_indices):
            start_logits = self._to_list(output[0][i])
            end_logits = self._to_list(output[1][i])
            eval_feature = features[example_index[0].item()]
            unique_id = int(eval_feature.unique_id)
            result = SquadResult(unique_id, start_logits, end_logits)
            all_results.append(result)

    # Compute predictions based off logits on a per example basis
    answers, n_best = compute_predictions_logits(
        all_examples=examples,
        all_features=features,
        all_results=all_results,
        n_best_size=n_best_size,
        max_answer_length=max_answer_length,
        do_lower_case=do_lower_case,
        verbose_logging=verbose_logging,
        version_2_with_negative=version_2_with_negative,
        null_score_diff_threshold=null_score_diff_threshold,
        tokenizer=self.tokenizer,
    )

    return answers, n_best

TransformersTokenTaggingProcessor

Token Tagging Data Processor. Use this class to generate tensor inputs from human legible text/string data. This class can be used with a majority of the Bert architecture transformer models with a token-level predictive head for token classification from Hugging Face.

Usage:

>>> processor = TransformersTokenTaggingProcessor(model_name_or_path="dbmdz/bert-large-cased-finetuned-conll03-english")
>>> processor.process(text=["string"])

**Parameters:**

* **model_name_or_path** - String defining HF token tagging model/tokenizer's name
* **label_strings** - List of strings that specify label strings with index as key for this specific processor
Source code in fastnn/processors/nlp/token_tagging.py
class TransformersTokenTaggingProcessor(Processor):
    """Token Tagging Data Processor. Use this class to generate tensor inputs from human legible text/string data.
    This class can be used with a majority of the Bert architecture transformer models with a token-level predictive head
    for token classification from Hugging Face.

    Usage:
    ```python
    >>> processor = TransformersTokenTaggingProcessor(model_name_or_path="dbmdz/bert-large-cased-finetuned-conll03-english")
    >>> processor.process(text=["string"])

    **Parameters:**

    * **model_name_or_path** - String defining HF token tagging model/tokenizer's name
    * **label_strings** - List of strings that specify label strings with index as key for this specific processor
    ```
    """

    def __init__(
        self,
        model_name_or_path: str = "dbmdz/bert-large-cased-finetuned-conll03-english",
        label_strings: List[str] = [
            "O",  # Outside of a named entity
            "B-MISC",  # Beginning of a miscellaneous entity right after another miscellaneous entity
            "I-MISC",  # Miscellaneous entity
            "B-PER",  # Beginning of a person's name right after another person's name
            "I-PER",  # Person's name
            "B-ORG",  # Beginning of an organisation right after another organisation
            "I-ORG",  # Organisation
            "B-LOC",  # Beginning of a location right after another location
            "I-LOC",  # Location
        ],
    ):
        self.tokenizer = AutoTokenizer.from_pretrained(
            model_name_or_path, use_fast=True
        )
        self.label_strings = label_strings

    def process(
        self,
        text: List[str],
        max_seq_length: int = 512,
    ) -> Tuple:
        """Generate torch `Dataset` object from query/context string pairs using specified tokenizer from HF.
        This provides clear tensor input representations for compatible models.

        Returns a `Dataset`

        * **text** - List of text strings
        * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
        """

        tokens = self.tokenizer(
            text=text, return_tensors="pt", padding="max_length", truncation=True
        )
        dataset = TensorDataset(
            tokens["input_ids"],
            tokens["attention_mask"],
        )

        return dataset

    def process_batch(
        self,
        text: List,
        mini_batch_size: int = 8,
        max_seq_length: int = 512,
        use_gpu: bool = False,
    ) -> DataLoader:
        """Generate torch `DataLoader` object from text strings using specified tokenizer from HF.
        This provides clear tensor input representations for compatible models in an easy to use batch

        Returns a `DataLoader`

        * **text** - List of text strings
        * **mini_batch_size** - Batch size for inference
        * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
        * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
        """

        if use_gpu:
            if torch.cuda.is_available():
                device = torch.device("cuda")
            else:
                logger.info("GPU not available")
                device = torch.device("cpu")
        else:
            device = torch.device("cpu")

        dataset = self.process(text=text)

        dataloader = DataLoader(
            dataset,
            batch_size=mini_batch_size,
            collate_fn=lambda x: [t.to(device) for t in self._collate_fn(x)],
        )

        return dataloader

    def process_output(
        self,
        outputs: List[Tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
    ):
        pass

    def process_output_batch(self, outputs: List) -> List[List[Tuple[str, str]]]:
        """Process output of Transformers NER model

        * **outputs** - List of batch output tensors from a model's forward pass
        """
        results = []
        for logits, input_ids in outputs:
            tokens_batch = [self.tokenizer.convert_ids_to_tokens(i) for i in input_ids]
            argmax_batch = [torch.argmax(o, dim=1) for o in logits]
            for i in range(len(tokens_batch)):
                # Filter out padding
                results.append(
                    [
                        (token, self.label_strings[prediction])
                        for token, prediction in zip(
                            tokens_batch[i], argmax_batch[i].cpu().numpy()
                        )
                        if token != "[PAD]"
                    ]
                )
        return results

    def _collate_fn(self, data):
        batch = default_collate(data)
        return batch

process(self, text, max_seq_length=512)

Generate torch Dataset object from query/context string pairs using specified tokenizer from HF. This provides clear tensor input representations for compatible models.

Returns a Dataset

  • text - List of text strings
  • max_seq_length - Maximum context token length. Check model configs to see max sequence length the model was trained with
Source code in fastnn/processors/nlp/token_tagging.py
def process(
    self,
    text: List[str],
    max_seq_length: int = 512,
) -> Tuple:
    """Generate torch `Dataset` object from query/context string pairs using specified tokenizer from HF.
    This provides clear tensor input representations for compatible models.

    Returns a `Dataset`

    * **text** - List of text strings
    * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
    """

    tokens = self.tokenizer(
        text=text, return_tensors="pt", padding="max_length", truncation=True
    )
    dataset = TensorDataset(
        tokens["input_ids"],
        tokens["attention_mask"],
    )

    return dataset

process_batch(self, text, mini_batch_size=8, max_seq_length=512, use_gpu=False)

Generate torch DataLoader object from text strings using specified tokenizer from HF. This provides clear tensor input representations for compatible models in an easy to use batch

Returns a DataLoader

  • text - List of text strings
  • mini_batch_size - Batch size for inference
  • max_seq_length - Maximum context token length. Check model configs to see max sequence length the model was trained with
  • use_gpu - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
Source code in fastnn/processors/nlp/token_tagging.py
def process_batch(
    self,
    text: List,
    mini_batch_size: int = 8,
    max_seq_length: int = 512,
    use_gpu: bool = False,
) -> DataLoader:
    """Generate torch `DataLoader` object from text strings using specified tokenizer from HF.
    This provides clear tensor input representations for compatible models in an easy to use batch

    Returns a `DataLoader`

    * **text** - List of text strings
    * **mini_batch_size** - Batch size for inference
    * **max_seq_length** - Maximum context token length. Check model configs to see max sequence length the model was trained with
    * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
    """

    if use_gpu:
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            logger.info("GPU not available")
            device = torch.device("cpu")
    else:
        device = torch.device("cpu")

    dataset = self.process(text=text)

    dataloader = DataLoader(
        dataset,
        batch_size=mini_batch_size,
        collate_fn=lambda x: [t.to(device) for t in self._collate_fn(x)],
    )

    return dataloader

process_output_batch(self, outputs)

Process output of Transformers NER model

  • outputs - List of batch output tensors from a model's forward pass
Source code in fastnn/processors/nlp/token_tagging.py
def process_output_batch(self, outputs: List) -> List[List[Tuple[str, str]]]:
    """Process output of Transformers NER model

    * **outputs** - List of batch output tensors from a model's forward pass
    """
    results = []
    for logits, input_ids in outputs:
        tokens_batch = [self.tokenizer.convert_ids_to_tokens(i) for i in input_ids]
        argmax_batch = [torch.argmax(o, dim=1) for o in logits]
        for i in range(len(tokens_batch)):
            # Filter out padding
            results.append(
                [
                    (token, self.label_strings[prediction])
                    for token, prediction in zip(
                        tokens_batch[i], argmax_batch[i].cpu().numpy()
                    )
                    if token != "[PAD]"
                ]
            )
    return results

ObjectDetectionProcessor

Object Detection processor dealing with image files or 3xHxW formatted images and boxes, scores, labels out processing. Since most resizing and padding transforms are done by the object detection models in PyTorch, datasets and dataloaders willl generate batches of images as lists.

Usage:

>>> processor = ObjectDetectionProcessor()
>>> processor.process(file_paths=["file_path.png"])

**Parameters:**
* **label_strings** - List of strings that specify label strings with index as key for this specific processor
Source code in fastnn/processors/cv/object_detection.py
class ObjectDetectionProcessor(Processor):
    """Object Detection processor dealing with image files or 3xHxW formatted images and boxes, scores, labels out processing.
    Since most resizing and padding transforms are done by the object detection models in PyTorch, datasets and dataloaders willl
    generate batches of images as lists.

    Usage:
    ```python
    >>> processor = ObjectDetectionProcessor()
    >>> processor.process(file_paths=["file_path.png"])

    **Parameters:**
    * **label_strings** - List of strings that specify label strings with index as key for this specific processor

    ```
    """

    def __init__(self, label_strings: List[str]):
        self.label_strings = label_strings

    def process(
        self,
        dir_path: str,
        transforms: Optional[Callable] = ConvertImageDtype(torch.float),
    ) -> Dataset:
        """Generate torch `Dataset` object from list of file paths or image Tensors.
        This provides clear tensor input representations for compatible models.

        Returns a Dataset

        * **dir_path** - String path to directory of images you'd like to process
        """

        dataset = ImageDataset(root=dir_path, transforms=transforms)

        return dataset

    def process_batch(
        self,
        dir_path: str,
        transforms: Optional[Callable] = ConvertImageDtype(torch.float),
        mini_batch_size: int = 8,
        use_gpu: bool = False,
    ) -> DataLoader:
        """Generate torch `Dataloader` object from data directory path.
        This provides clear tensor input representations for compatible models.

        Returns a `Dataloader`

        * **dir_path** - String path to directory of images you'd like to process
        * **mini_batch_size** - Batch size for inference
        * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
        """

        if use_gpu:
            if torch.cuda.is_available():
                device = torch.device("cuda")
            else:
                logger.info("GPU not available")
                device = torch.device("cpu")
        else:
            device = torch.device("cpu")

        dataset = self.process(dir_path=dir_path, transforms=transforms)

        # Instead of a tensor batch, the lambda collate_fn will provide a list batch
        dataloader = DataLoader(
            dataset,
            batch_size=mini_batch_size,
            collate_fn=lambda x: [[t.to(device) for t in self._od_collate_fn(x)]],
        )

        return dataloader

    def process_output(
        self,
    ):
        pass

    def process_output_batch(
        self, outputs: List[List[torch.Tensor]], dataset: Dataset
    ) -> List[List[Tuple[torch.Tensor, np.array]]]:
        """Process output of object detection model into human legible results.
        Outputs from `FasterRCNNModule`


        Returns batched results of list of list of tuples containing boxed images in tensor and numpy format

        * **outputs** - List of batch output tensors from a model's forward pass
        * **dataset** - Corresponding dataset with originial images matched with model outputs

        """
        # Labeled Images
        results = []

        for idx, out in enumerate(outputs):
            labeled_images = []
            for label_idx in range(1, len(out), 3):
                labels = [self.label_strings[o] for o in out[label_idx]]

                unique_labels = set(labels)
                label_colors_map = {}
                for label in unique_labels:
                    label_colors_map[label] = tuple(
                        np.random.choice(range(256), size=3)
                    )

                label_colors = [label_colors_map[label] for label in labels]

                output_tensor, output_numpy = self.draw_bounding_boxes(
                    ConvertImageDtype(torch.uint8)(
                        dataset[idx * (len(out) // 3) + label_idx // 3]
                    ),
                    out[label_idx - 1],
                    labels=labels,
                    colors=label_colors,
                )
                labeled_images.append((output_tensor, output_numpy))
            results.append(labeled_images)

        return results

    def _od_collate_fn(self, data):
        """Custom collate fn to output dynamic image batches without same-dim requirements via. `stack`.
        This is not technically a "correct" collate_fn for most of torch's vision models. Should be wrapped as a list
        in the lambda collate fn.
        """
        data = [img for img in data]
        return data

    @torch.no_grad()
    def draw_bounding_boxes(
        self,
        image: torch.Tensor,
        boxes: torch.Tensor,
        labels: Optional[List[str]] = None,
        colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
        width: int = 1,
        font: Optional[str] = "arial.ttf",
        font_size: int = 10,
    ) -> Tuple[torch.Tensor, np.array]:

        """
        Added and modified from TorchVision utils.
        Draws bounding boxes on given image.
        The values of the input image should be uint8 between 0 and 255.
        Args:
            image (Tensor): Tensor of shape (C x H x W)
            bboxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
                the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
                `0 <= ymin < ymax < H`.
            labels (List[str]): List containing the labels of bounding boxes.
            colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can
                be represented as `str` or `Tuple[int, int, int]`.
            width (int): Width of bounding box.
            font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
                also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
                `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
            font_size (int): The requested font size in points.
        """

        if not isinstance(image, torch.Tensor):
            raise TypeError(f"Tensor expected, got {type(image)}")
        elif image.dtype != torch.uint8:
            raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
        elif image.dim() != 3:
            raise ValueError("Pass individual images, not batches")

        ndarr = image.permute(1, 2, 0).numpy()
        img_to_draw = Image.fromarray(ndarr)

        img_boxes = boxes.to(torch.int64).tolist()

        draw = ImageDraw.Draw(img_to_draw)

        pixel_ratio = max(1, (max(ndarr.shape[0], ndarr.shape[1]) // 1000))

        for i, bbox in enumerate(img_boxes):
            color = None if colors is None else colors[i]
            draw.rectangle(bbox, width=width * pixel_ratio, outline=color)

            if labels is not None:
                txt_font = (
                    ImageFont.load_default()
                    if font is None
                    else ImageFont.truetype(font=font, size=font_size * pixel_ratio)
                )
                draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)

        return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1), np.array(
            img_to_draw
        )

draw_bounding_boxes(self, image, boxes, labels=None, colors=None, width=1, font='arial.ttf', font_size=10)

Added and modified from TorchVision utils. Draws bounding boxes on given image. The values of the input image should be uint8 between 0 and 255.

Parameters:

Name Type Description Default
image Tensor

Tensor of shape (C x H x W)

required
bboxes Tensor

Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that the boxes are absolute coordinates with respect to the image. In other words: 0 <= xmin < xmax < W and 0 <= ymin < ymax < H.

required
labels List[str]

List containing the labels of bounding boxes.

None
colors List[Union[str, Tuple[int, int, int]]]

List containing the colors of bounding boxes. The colors can be represented as str or Tuple[int, int, int].

None
width int

Width of bounding box.

1
font str

A filename containing a TrueType font. If the file is not found in this filename, the loader may also search in other directories, such as the fonts/ directory on Windows or /Library/Fonts/, /System/Library/Fonts/ and ~/Library/Fonts/ on macOS.

'arial.ttf'
font_size int

The requested font size in points.

10
Source code in fastnn/processors/cv/object_detection.py
@torch.no_grad()
def draw_bounding_boxes(
    self,
    image: torch.Tensor,
    boxes: torch.Tensor,
    labels: Optional[List[str]] = None,
    colors: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
    width: int = 1,
    font: Optional[str] = "arial.ttf",
    font_size: int = 10,
) -> Tuple[torch.Tensor, np.array]:

    """
    Added and modified from TorchVision utils.
    Draws bounding boxes on given image.
    The values of the input image should be uint8 between 0 and 255.
    Args:
        image (Tensor): Tensor of shape (C x H x W)
        bboxes (Tensor): Tensor of size (N, 4) containing bounding boxes in (xmin, ymin, xmax, ymax) format. Note that
            the boxes are absolute coordinates with respect to the image. In other words: `0 <= xmin < xmax < W` and
            `0 <= ymin < ymax < H`.
        labels (List[str]): List containing the labels of bounding boxes.
        colors (List[Union[str, Tuple[int, int, int]]]): List containing the colors of bounding boxes. The colors can
            be represented as `str` or `Tuple[int, int, int]`.
        width (int): Width of bounding box.
        font (str): A filename containing a TrueType font. If the file is not found in this filename, the loader may
            also search in other directories, such as the `fonts/` directory on Windows or `/Library/Fonts/`,
            `/System/Library/Fonts/` and `~/Library/Fonts/` on macOS.
        font_size (int): The requested font size in points.
    """

    if not isinstance(image, torch.Tensor):
        raise TypeError(f"Tensor expected, got {type(image)}")
    elif image.dtype != torch.uint8:
        raise ValueError(f"Tensor uint8 expected, got {image.dtype}")
    elif image.dim() != 3:
        raise ValueError("Pass individual images, not batches")

    ndarr = image.permute(1, 2, 0).numpy()
    img_to_draw = Image.fromarray(ndarr)

    img_boxes = boxes.to(torch.int64).tolist()

    draw = ImageDraw.Draw(img_to_draw)

    pixel_ratio = max(1, (max(ndarr.shape[0], ndarr.shape[1]) // 1000))

    for i, bbox in enumerate(img_boxes):
        color = None if colors is None else colors[i]
        draw.rectangle(bbox, width=width * pixel_ratio, outline=color)

        if labels is not None:
            txt_font = (
                ImageFont.load_default()
                if font is None
                else ImageFont.truetype(font=font, size=font_size * pixel_ratio)
            )
            draw.text((bbox[0], bbox[1]), labels[i], fill=color, font=txt_font)

    return torch.from_numpy(np.array(img_to_draw)).permute(2, 0, 1), np.array(
        img_to_draw
    )

process(self, dir_path, transforms=ConvertImageDtype())

Generate torch Dataset object from list of file paths or image Tensors. This provides clear tensor input representations for compatible models.

Returns a Dataset

  • dir_path - String path to directory of images you'd like to process
Source code in fastnn/processors/cv/object_detection.py
def process(
    self,
    dir_path: str,
    transforms: Optional[Callable] = ConvertImageDtype(torch.float),
) -> Dataset:
    """Generate torch `Dataset` object from list of file paths or image Tensors.
    This provides clear tensor input representations for compatible models.

    Returns a Dataset

    * **dir_path** - String path to directory of images you'd like to process
    """

    dataset = ImageDataset(root=dir_path, transforms=transforms)

    return dataset

process_batch(self, dir_path, transforms=ConvertImageDtype(), mini_batch_size=8, use_gpu=False)

Generate torch Dataloader object from data directory path. This provides clear tensor input representations for compatible models.

Returns a Dataloader

  • dir_path - String path to directory of images you'd like to process
  • mini_batch_size - Batch size for inference
  • use_gpu - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
Source code in fastnn/processors/cv/object_detection.py
def process_batch(
    self,
    dir_path: str,
    transforms: Optional[Callable] = ConvertImageDtype(torch.float),
    mini_batch_size: int = 8,
    use_gpu: bool = False,
) -> DataLoader:
    """Generate torch `Dataloader` object from data directory path.
    This provides clear tensor input representations for compatible models.

    Returns a `Dataloader`

    * **dir_path** - String path to directory of images you'd like to process
    * **mini_batch_size** - Batch size for inference
    * **use_gpu** - Bool for using gpu or cpu. If set True but no gpu devices available, model will default to using cpu
    """

    if use_gpu:
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            logger.info("GPU not available")
            device = torch.device("cpu")
    else:
        device = torch.device("cpu")

    dataset = self.process(dir_path=dir_path, transforms=transforms)

    # Instead of a tensor batch, the lambda collate_fn will provide a list batch
    dataloader = DataLoader(
        dataset,
        batch_size=mini_batch_size,
        collate_fn=lambda x: [[t.to(device) for t in self._od_collate_fn(x)]],
    )

    return dataloader

process_output_batch(self, outputs, dataset)

Process output of object detection model into human legible results. Outputs from FasterRCNNModule

Returns batched results of list of list of tuples containing boxed images in tensor and numpy format

  • outputs - List of batch output tensors from a model's forward pass
  • dataset - Corresponding dataset with originial images matched with model outputs
Source code in fastnn/processors/cv/object_detection.py
def process_output_batch(
    self, outputs: List[List[torch.Tensor]], dataset: Dataset
) -> List[List[Tuple[torch.Tensor, np.array]]]:
    """Process output of object detection model into human legible results.
    Outputs from `FasterRCNNModule`


    Returns batched results of list of list of tuples containing boxed images in tensor and numpy format

    * **outputs** - List of batch output tensors from a model's forward pass
    * **dataset** - Corresponding dataset with originial images matched with model outputs

    """
    # Labeled Images
    results = []

    for idx, out in enumerate(outputs):
        labeled_images = []
        for label_idx in range(1, len(out), 3):
            labels = [self.label_strings[o] for o in out[label_idx]]

            unique_labels = set(labels)
            label_colors_map = {}
            for label in unique_labels:
                label_colors_map[label] = tuple(
                    np.random.choice(range(256), size=3)
                )

            label_colors = [label_colors_map[label] for label in labels]

            output_tensor, output_numpy = self.draw_bounding_boxes(
                ConvertImageDtype(torch.uint8)(
                    dataset[idx * (len(out) // 3) + label_idx // 3]
                ),
                out[label_idx - 1],
                labels=labels,
                colors=label_colors,
            )
            labeled_images.append((output_tensor, output_numpy))
        results.append(labeled_images)

    return results