init
This commit is contained in:
363
transformers/docs/source/en/tasks/asr.md
Normal file
363
transformers/docs/source/en/tasks/asr.md
Normal file
@@ -0,0 +1,363 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Automatic speech recognition
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="TksaY_FDgnk"/>
|
||||
|
||||
Automatic speech recognition (ASR) converts a speech signal to text, mapping a sequence of audio inputs to text outputs. Virtual assistants like Siri and Alexa use ASR models to help users every day, and there are many other useful user-facing applications like live captioning and note-taking during meetings.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Fine-tune [Wav2Vec2](https://huggingface.co/facebook/wav2vec2-base) on the [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) dataset to transcribe audio to text.
|
||||
2. Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/automatic-speech-recognition)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate jiwer
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load MInDS-14 dataset
|
||||
|
||||
Start by loading a smaller subset of the [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) dataset from the 🤗 Datasets library. This will give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train[:100]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> minds = minds.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at the dataset:
|
||||
|
||||
```py
|
||||
>>> minds
|
||||
DatasetDict({
|
||||
train: Dataset({
|
||||
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
|
||||
num_rows: 16
|
||||
})
|
||||
test: Dataset({
|
||||
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
|
||||
num_rows: 4
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
While the dataset contains a lot of useful information, like `lang_id` and `english_transcription`, this guide focuses on the `audio` and `transcription`. Remove the other columns with the [`~datasets.Dataset.remove_columns`] method:
|
||||
|
||||
```py
|
||||
>>> minds = minds.remove_columns(["english_transcription", "intent_class", "lang_id"])
|
||||
```
|
||||
|
||||
Review the example again:
|
||||
|
||||
```py
|
||||
>>> minds["train"][0]
|
||||
{'audio': {'array': array([-0.00024414, 0. , 0. , ..., 0.00024414,
|
||||
0.00024414, 0.00024414], dtype=float32),
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
|
||||
'sampling_rate': 8000},
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
|
||||
'transcription': "hi I'm trying to use the banking app on my phone and currently my checking and savings account balance is not refreshing"}
|
||||
```
|
||||
|
||||
There are two fields:
|
||||
|
||||
- `audio`: a 1-dimensional `array` of the speech signal that must be called to load and resample the audio file.
|
||||
- `transcription`: the target text.
|
||||
|
||||
## Preprocess
|
||||
|
||||
The next step is to load a Wav2Vec2 processor to process the audio signal:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base")
|
||||
```
|
||||
|
||||
The MInDS-14 dataset has a sampling rate of 8000Hz (you can find this information in its [dataset card](https://huggingface.co/datasets/PolyAI/minds14)), which means you'll need to resample the dataset to 16000Hz to use the pretrained Wav2Vec2 model:
|
||||
|
||||
```py
|
||||
>>> minds = minds.cast_column("audio", Audio(sampling_rate=16_000))
|
||||
>>> minds["train"][0]
|
||||
{'audio': {'array': array([-2.38064706e-04, -1.58618059e-04, -5.43987835e-06, ...,
|
||||
2.78103951e-04, 2.38446111e-04, 1.18740834e-04], dtype=float32),
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
|
||||
'sampling_rate': 16000},
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
|
||||
'transcription': "hi I'm trying to use the banking app on my phone and currently my checking and savings account balance is not refreshing"}
|
||||
```
|
||||
|
||||
As you can see in the `transcription` above, the text contains a mix of uppercase and lowercase characters. The Wav2Vec2 tokenizer is only trained on uppercase characters so you'll need to make sure the text matches the tokenizer's vocabulary:
|
||||
|
||||
```py
|
||||
>>> def uppercase(example):
|
||||
... return {"transcription": example["transcription"].upper()}
|
||||
|
||||
|
||||
>>> minds = minds.map(uppercase)
|
||||
```
|
||||
|
||||
Now create a preprocessing function that:
|
||||
|
||||
1. Calls the `audio` column to load and resample the audio file.
|
||||
2. Extracts the `input_values` from the audio file and tokenize the `transcription` column with the processor.
|
||||
|
||||
```py
|
||||
>>> def prepare_dataset(batch):
|
||||
... audio = batch["audio"]
|
||||
... batch = processor(audio["array"], sampling_rate=audio["sampling_rate"], text=batch["transcription"])
|
||||
... batch["input_length"] = len(batch["input_values"][0])
|
||||
... return batch
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] function. You can speed up `map` by increasing the number of processes with the `num_proc` parameter. Remove the columns you don't need with the [`~datasets.Dataset.remove_columns`] method:
|
||||
|
||||
```py
|
||||
>>> encoded_minds = minds.map(prepare_dataset, remove_columns=minds.column_names["train"], num_proc=4)
|
||||
```
|
||||
|
||||
🤗 Transformers doesn't have a data collator for ASR, so you'll need to adapt the [`DataCollatorWithPadding`] to create a batch of examples. It'll also dynamically pad your text and labels to the length of the longest element in its batch (instead of the entire dataset) so they are a uniform length. While it is possible to pad your text in the `tokenizer` function by setting `padding=True`, dynamic padding is more efficient.
|
||||
|
||||
Unlike other data collators, this specific data collator needs to apply a different padding method to `input_values` and `labels`:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> from dataclasses import dataclass, field
|
||||
>>> from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
|
||||
>>> @dataclass
|
||||
... class DataCollatorCTCWithPadding:
|
||||
... processor: AutoProcessor
|
||||
... padding: Union[bool, str] = "longest"
|
||||
|
||||
... def __call__(self, features: list[dict[str, Union[list[int], torch.Tensor]]]) -> dict[str, torch.Tensor]:
|
||||
... # split inputs and labels since they have to be of different lengths and need
|
||||
... # different padding methods
|
||||
... input_features = [{"input_values": feature["input_values"][0]} for feature in features]
|
||||
... label_features = [{"input_ids": feature["labels"]} for feature in features]
|
||||
|
||||
... batch = self.processor.pad(input_features, padding=self.padding, return_tensors="pt")
|
||||
|
||||
... labels_batch = self.processor.pad(labels=label_features, padding=self.padding, return_tensors="pt")
|
||||
|
||||
... # replace padding with -100 to ignore loss correctly
|
||||
... labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)
|
||||
|
||||
... batch["labels"] = labels
|
||||
|
||||
... return batch
|
||||
```
|
||||
|
||||
Now instantiate your `DataCollatorForCTCWithPadding`:
|
||||
|
||||
```py
|
||||
>>> data_collator = DataCollatorCTCWithPadding(processor=processor, padding="longest")
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load an evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [word error rate](https://huggingface.co/spaces/evaluate-metric/wer) (WER) metric (refer to the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about loading and computing metrics):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> wer = evaluate.load("wer")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the WER:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def compute_metrics(pred):
|
||||
... pred_logits = pred.predictions
|
||||
... pred_ids = np.argmax(pred_logits, axis=-1)
|
||||
|
||||
... pred.label_ids[pred.label_ids == -100] = processor.tokenizer.pad_token_id
|
||||
|
||||
... pred_str = processor.batch_decode(pred_ids)
|
||||
... label_str = processor.batch_decode(pred.label_ids, group_tokens=False)
|
||||
|
||||
... wer_score = wer.compute(predictions=pred_str, references=label_str)
|
||||
|
||||
... return {"wer": wer_score}
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You are now ready to start training your model! Load Wav2Vec2 with [`AutoModelForCTC`]. Specify the reduction to apply with the `ctc_loss_reduction` parameter. It is often better to use the average instead of the default summation:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCTC, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForCTC.from_pretrained(
|
||||
... "facebook/wav2vec2-base",
|
||||
... ctc_loss_reduction="mean",
|
||||
... pad_token_id=processor.tokenizer.pad_token_id,
|
||||
... )
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the WER and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to fine-tune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_asr_mind_model",
|
||||
... per_device_train_batch_size=8,
|
||||
... gradient_accumulation_steps=2,
|
||||
... learning_rate=1e-5,
|
||||
... warmup_steps=500,
|
||||
... max_steps=2000,
|
||||
... gradient_checkpointing=True,
|
||||
... fp16=True,
|
||||
... group_by_length=True,
|
||||
... eval_strategy="steps",
|
||||
... per_device_eval_batch_size=8,
|
||||
... save_steps=1000,
|
||||
... eval_steps=1000,
|
||||
... logging_steps=25,
|
||||
... load_best_model_at_end=True,
|
||||
... metric_for_best_model="wer",
|
||||
... greater_is_better=False,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=encoded_minds["train"],
|
||||
... eval_dataset=encoded_minds["test"],
|
||||
... processing_class=processor,
|
||||
... data_collator=data_collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so it can be accessible to everyone:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to fine-tune a model for automatic speech recognition, take a look at this blog [post](https://huggingface.co/blog/fine-tune-wav2vec2-english) for English ASR and this [post](https://huggingface.co/blog/fine-tune-xlsr-wav2vec2) for multilingual ASR.
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've fine-tuned a model, you can use it for inference!
|
||||
|
||||
Load an audio file you'd like to run inference on. Remember to resample the sampling rate of the audio file to match the sampling rate of the model if you need to!
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> dataset = load_dataset("PolyAI/minds14", "en-US", split="train")
|
||||
>>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
|
||||
>>> sampling_rate = dataset.features["audio"].sampling_rate
|
||||
>>> audio_file = dataset[0]["audio"]["path"]
|
||||
```
|
||||
|
||||
The simplest way to try out your fine-tuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for automatic speech recognition with your model, and pass your audio file to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> transcriber = pipeline("automatic-speech-recognition", model="stevhliu/my_awesome_asr_minds_model")
|
||||
>>> transcriber(audio_file)
|
||||
{'text': 'I WOUD LIKE O SET UP JOINT ACOUNT WTH Y PARTNER'}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
The transcription is decent, but it could be better! Try finetuning your model on more examples to get even better results!
|
||||
|
||||
</Tip>
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Load a processor to preprocess the audio file and transcription and return the `input` as PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("stevhliu/my_awesome_asr_mind_model")
|
||||
>>> inputs = processor(dataset[0]["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the logits:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCTC
|
||||
|
||||
>>> model = AutoModelForCTC.from_pretrained("stevhliu/my_awesome_asr_mind_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
Get the predicted `input_ids` with the highest probability, and use the processor to decode the predicted `input_ids` back into text:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> predicted_ids = torch.argmax(logits, dim=-1)
|
||||
>>> transcription = processor.batch_decode(predicted_ids)
|
||||
>>> transcription
|
||||
['I WOUL LIKE O SET UP JOINT ACOUNT WTH Y PARTNER']
|
||||
```
|
||||
315
transformers/docs/source/en/tasks/audio_classification.md
Normal file
315
transformers/docs/source/en/tasks/audio_classification.md
Normal file
@@ -0,0 +1,315 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Audio classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="KWwzcmG98Ds"/>
|
||||
|
||||
Audio classification - just like with text - assigns a class label as output from the input data. The only difference is instead of text inputs, you have raw audio waveforms. Some practical applications of audio classification include identifying speaker intent, language classification, and even animal species by their sounds.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Fine-tune [Wav2Vec2](https://huggingface.co/facebook/wav2vec2-base) on the [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) dataset to classify speaker intent.
|
||||
2. Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/audio-classification)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load MInDS-14 dataset
|
||||
|
||||
Start by loading the MInDS-14 dataset from the 🤗 Datasets library:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a smaller train and test set with the [`~datasets.Dataset.train_test_split`] method. This will give you a chance to experiment and make sure everything works before spending more time on the full dataset.
|
||||
|
||||
```py
|
||||
>>> minds = minds.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at the dataset:
|
||||
|
||||
```py
|
||||
>>> minds
|
||||
DatasetDict({
|
||||
train: Dataset({
|
||||
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
|
||||
num_rows: 450
|
||||
})
|
||||
test: Dataset({
|
||||
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
|
||||
num_rows: 113
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
While the dataset contains a lot of useful information, like `lang_id` and `english_transcription`, you will focus on the `audio` and `intent_class` in this guide. Remove the other columns with the [`~datasets.Dataset.remove_columns`] method:
|
||||
|
||||
```py
|
||||
>>> minds = minds.remove_columns(["path", "transcription", "english_transcription", "lang_id"])
|
||||
```
|
||||
|
||||
Here's an example:
|
||||
|
||||
```py
|
||||
>>> minds["train"][0]
|
||||
{'audio': {'array': array([ 0. , 0. , 0. , ..., -0.00048828,
|
||||
-0.00024414, -0.00024414], dtype=float32),
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602b9a5fbb1e6d0fbce91f52.wav',
|
||||
'sampling_rate': 8000},
|
||||
'intent_class': 2}
|
||||
```
|
||||
|
||||
There are two fields:
|
||||
|
||||
- `audio`: a 1-dimensional `array` of the speech signal that must be called to load and resample the audio file.
|
||||
- `intent_class`: represents the class id of the speaker's intent.
|
||||
|
||||
To make it easier for the model to get the label name from the label id, create a dictionary that maps the label name to an integer and vice versa:
|
||||
|
||||
```py
|
||||
>>> labels = minds["train"].features["intent_class"].names
|
||||
>>> label2id, id2label = dict(), dict()
|
||||
>>> for i, label in enumerate(labels):
|
||||
... label2id[label] = str(i)
|
||||
... id2label[str(i)] = label
|
||||
```
|
||||
|
||||
Now you can convert the label id to a label name:
|
||||
|
||||
```py
|
||||
>>> id2label[str(2)]
|
||||
'app_error'
|
||||
```
|
||||
|
||||
## Preprocess
|
||||
|
||||
The next step is to load a Wav2Vec2 feature extractor to process the audio signal:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoFeatureExtractor
|
||||
|
||||
>>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")
|
||||
```
|
||||
|
||||
The MInDS-14 dataset has a sampling rate of 8kHz (you can find this information in its [dataset card](https://huggingface.co/datasets/PolyAI/minds14)), which means you'll need to resample the dataset to 16kHz to use the pretrained Wav2Vec2 model:
|
||||
|
||||
```py
|
||||
>>> minds = minds.cast_column("audio", Audio(sampling_rate=16_000))
|
||||
>>> minds["train"][0]
|
||||
{'audio': {'array': array([ 2.2098757e-05, 4.6582241e-05, -2.2803260e-05, ...,
|
||||
-2.8419291e-04, -2.3305941e-04, -1.1425107e-04], dtype=float32),
|
||||
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602b9a5fbb1e6d0fbce91f52.wav',
|
||||
'sampling_rate': 16000},
|
||||
'intent_class': 2}
|
||||
```
|
||||
|
||||
Now create a preprocessing function that:
|
||||
|
||||
1. Calls the `audio` column to load, and if necessary, resample the audio file.
|
||||
2. Checks if the sampling rate of the audio file matches the sampling rate of the audio data a model was pretrained with. You can find this information in the Wav2Vec2 [model card](https://huggingface.co/facebook/wav2vec2-base).
|
||||
3. Set a maximum input length to batch longer inputs without truncating them.
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... audio_arrays = [x["array"] for x in examples["audio"]]
|
||||
... inputs = feature_extractor(
|
||||
... audio_arrays, sampling_rate=feature_extractor.sampling_rate, max_length=16000, truncation=True
|
||||
... )
|
||||
... return inputs
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] function. You can speed up `map` by setting `batched=True` to process multiple elements of the dataset at once. Remove unnecessary columns and rename `intent_class` to `label`, as required by the model:
|
||||
|
||||
```py
|
||||
>>> encoded_minds = minds.map(preprocess_function, remove_columns="audio", batched=True)
|
||||
>>> encoded_minds = encoded_minds.rename_column("intent_class", "label")
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load an evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the accuracy:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def compute_metrics(eval_pred):
|
||||
... predictions = np.argmax(eval_pred.predictions, axis=1)
|
||||
... return accuracy.compute(predictions=predictions, references=eval_pred.label_ids)
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load Wav2Vec2 with [`AutoModelForAudioClassification`] along with the number of expected labels, and the label mappings:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForAudioClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> num_labels = len(id2label)
|
||||
>>> model = AutoModelForAudioClassification.from_pretrained(
|
||||
... "facebook/wav2vec2-base", num_labels=num_labels, label2id=label2id, id2label=id2label
|
||||
... )
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir`, which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the accuracy and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to fine-tune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_mind_model",
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... learning_rate=3e-5,
|
||||
... per_device_train_batch_size=32,
|
||||
... gradient_accumulation_steps=4,
|
||||
... per_device_eval_batch_size=32,
|
||||
... num_train_epochs=10,
|
||||
... warmup_ratio=0.1,
|
||||
... logging_steps=10,
|
||||
... load_best_model_at_end=True,
|
||||
... metric_for_best_model="accuracy",
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=encoded_minds["train"],
|
||||
... eval_dataset=encoded_minds["test"],
|
||||
... processing_class=feature_extractor,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to fine-tune a model for audio classification, take a look at the corresponding [PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've fine-tuned a model, you can use it for inference!
|
||||
|
||||
Load an audio file for inference. Remember to resample the sampling rate of the audio file to match the model's sampling rate, if necessary.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")
|
||||
>>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
|
||||
>>> sampling_rate = dataset.features["audio"].sampling_rate
|
||||
>>> audio_file = dataset[0]["audio"]["path"]
|
||||
```
|
||||
|
||||
The simplest way to try out your fine-tuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for audio classification with your model, and pass your audio file to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> classifier = pipeline("audio-classification", model="stevhliu/my_awesome_minds_model")
|
||||
>>> classifier(audio_file)
|
||||
[
|
||||
{'score': 0.09766869246959686, 'label': 'cash_deposit'},
|
||||
{'score': 0.07998877018690109, 'label': 'app_error'},
|
||||
{'score': 0.0781070664525032, 'label': 'joint_account'},
|
||||
{'score': 0.07667109370231628, 'label': 'pay_bill'},
|
||||
{'score': 0.0755252093076706, 'label': 'balance'}
|
||||
]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Load a feature extractor to preprocess the audio file and return the `input` as PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoFeatureExtractor
|
||||
|
||||
>>> feature_extractor = AutoFeatureExtractor.from_pretrained("stevhliu/my_awesome_minds_model")
|
||||
>>> inputs = feature_extractor(dataset[0]["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the logits:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForAudioClassification
|
||||
|
||||
>>> model = AutoModelForAudioClassification.from_pretrained("stevhliu/my_awesome_minds_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
Get the class with the highest probability, and use the model's `id2label` mapping to convert it to a label:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> predicted_class_ids = torch.argmax(logits).item()
|
||||
>>> predicted_label = model.config.id2label[predicted_class_ids]
|
||||
>>> predicted_label
|
||||
'cash_deposit'
|
||||
```
|
||||
493
transformers/docs/source/en/tasks/document_question_answering.md
Normal file
493
transformers/docs/source/en/tasks/document_question_answering.md
Normal file
@@ -0,0 +1,493 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Document Question Answering
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Document Question Answering, also referred to as Document Visual Question Answering, is a task that involves providing
|
||||
answers to questions posed about document images. The input to models supporting this task is typically a combination of an image and
|
||||
a question, and the output is an answer expressed in natural language. These models utilize multiple modalities, including
|
||||
text, the positions of words (bounding boxes), and the image itself.
|
||||
|
||||
This guide illustrates how to:
|
||||
|
||||
- Fine-tune [LayoutLMv2](../model_doc/layoutlmv2) on the [DocVQA dataset](https://huggingface.co/datasets/nielsr/docvqa_1200_examples_donut).
|
||||
- Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/image-to-text)
|
||||
|
||||
</Tip>
|
||||
|
||||
LayoutLMv2 solves the document question-answering task by adding a question-answering head on top of the final hidden
|
||||
states of the tokens, to predict the positions of the start and end tokens of the
|
||||
answer. In other words, the problem is treated as extractive question answering: given the context, extract which piece
|
||||
of information answers the question. The context comes from the output of an OCR engine, here it is Google's Tesseract.
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed. LayoutLMv2 depends on detectron2, torchvision and tesseract.
|
||||
|
||||
```bash
|
||||
pip install -q transformers datasets
|
||||
```
|
||||
|
||||
```bash
|
||||
pip install 'git+https://github.com/facebookresearch/detectron2.git'
|
||||
pip install torchvision
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo apt install tesseract-ocr
|
||||
pip install -q pytesseract
|
||||
```
|
||||
|
||||
Once you have installed all of the dependencies, restart your runtime.
|
||||
|
||||
We encourage you to share your model with the community. Log in to your Hugging Face account to upload it to the 🤗 Hub.
|
||||
When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
Let's define some global variables.
|
||||
|
||||
```py
|
||||
>>> model_checkpoint = "microsoft/layoutlmv2-base-uncased"
|
||||
>>> batch_size = 4
|
||||
```
|
||||
|
||||
## Load the data
|
||||
|
||||
In this guide we use a small sample of preprocessed DocVQA that you can find on 🤗 Hub. If you'd like to use the full
|
||||
DocVQA dataset, you can register and download it on [DocVQA homepage](https://rrc.cvc.uab.es/?ch=17). If you do so, to
|
||||
proceed with this guide check out [how to load files into a 🤗 dataset](https://huggingface.co/docs/datasets/loading#local-and-remote-files).
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> dataset = load_dataset("nielsr/docvqa_1200_examples")
|
||||
>>> dataset
|
||||
DatasetDict({
|
||||
train: Dataset({
|
||||
features: ['id', 'image', 'query', 'answers', 'words', 'bounding_boxes', 'answer'],
|
||||
num_rows: 1000
|
||||
})
|
||||
test: Dataset({
|
||||
features: ['id', 'image', 'query', 'answers', 'words', 'bounding_boxes', 'answer'],
|
||||
num_rows: 200
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
As you can see, the dataset is split into train and test sets already. Take a look at a random example to familiarize
|
||||
yourself with the features.
|
||||
|
||||
```py
|
||||
>>> dataset["train"].features
|
||||
```
|
||||
|
||||
Here's what the individual fields represent:
|
||||
* `id`: the example's id
|
||||
* `image`: a PIL.Image.Image object containing the document image
|
||||
* `query`: the question string - natural language asked question, in several languages
|
||||
* `answers`: a list of correct answers provided by human annotators
|
||||
* `words` and `bounding_boxes`: the results of OCR, which we will not use here
|
||||
* `answer`: an answer matched by a different model which we will not use here
|
||||
|
||||
Let's leave only English questions, and drop the `answer` feature which appears to contain predictions by another model.
|
||||
We'll also take the first of the answers from the set provided by the annotators. Alternatively, you can randomly sample it.
|
||||
|
||||
```py
|
||||
>>> updated_dataset = dataset.map(lambda example: {"question": example["query"]["en"]}, remove_columns=["query"])
|
||||
>>> updated_dataset = updated_dataset.map(
|
||||
... lambda example: {"answer": example["answers"][0]}, remove_columns=["answer", "answers"]
|
||||
... )
|
||||
```
|
||||
|
||||
Note that the LayoutLMv2 checkpoint that we use in this guide has been trained with `max_position_embeddings = 512` (you can
|
||||
find this information in the [checkpoint's `config.json` file](https://huggingface.co/microsoft/layoutlmv2-base-uncased/blob/main/config.json#L18)).
|
||||
We can truncate the examples but to avoid the situation where the answer might be at the end of a large document and end up truncated,
|
||||
here we'll remove the few examples where the embedding is likely to end up longer than 512.
|
||||
If most of the documents in your dataset are long, you can implement a sliding window strategy - check out [this notebook](https://github.com/huggingface/notebooks/blob/main/examples/question_answering.ipynb) for details.
|
||||
|
||||
```py
|
||||
>>> updated_dataset = updated_dataset.filter(lambda x: len(x["words"]) + len(x["question"].split()) < 512)
|
||||
```
|
||||
|
||||
At this point let's also remove the OCR features from this dataset. These are a result of OCR for fine-tuning a different
|
||||
model. They would still require some processing if we wanted to use them, as they do not match the input requirements
|
||||
of the model we use in this guide. Instead, we can use the [`LayoutLMv2Processor`] on the original data for both OCR and
|
||||
tokenization. This way we'll get the inputs that match model's expected input. If you want to process images manually,
|
||||
check out the [`LayoutLMv2` model documentation](../model_doc/layoutlmv2) to learn what input format the model expects.
|
||||
|
||||
```py
|
||||
>>> updated_dataset = updated_dataset.remove_columns("words")
|
||||
>>> updated_dataset = updated_dataset.remove_columns("bounding_boxes")
|
||||
```
|
||||
|
||||
Finally, the data exploration won't be complete if we don't peek at an image example.
|
||||
|
||||
```py
|
||||
>>> updated_dataset["train"][11]["image"]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/docvqa_example.jpg" alt="DocVQA Image Example"/>
|
||||
</div>
|
||||
|
||||
## Preprocess the data
|
||||
|
||||
The Document Question Answering task is a multimodal task, and you need to make sure that the inputs from each modality
|
||||
are preprocessed according to the model's expectations. Let's start by loading the [`LayoutLMv2Processor`], which internally combines an image processor that can handle image data and a tokenizer that can encode text data.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
### Preprocessing document images
|
||||
|
||||
First, let's prepare the document images for the model with the help of the `image_processor` from the processor.
|
||||
By default, image processor resizes the images to 224x224, makes sure they have the correct order of color channels,
|
||||
applies OCR with tesseract to get words and normalized bounding boxes. In this tutorial, all of these defaults are exactly what we need.
|
||||
Write a function that applies the default image processing to a batch of images and returns the results of OCR.
|
||||
|
||||
```py
|
||||
>>> image_processor = processor.image_processor
|
||||
|
||||
|
||||
>>> def get_ocr_words_and_boxes(examples):
|
||||
... images = [image.convert("RGB") for image in examples["image"]]
|
||||
... encoded_inputs = image_processor(images)
|
||||
|
||||
... examples["image"] = encoded_inputs.pixel_values
|
||||
... examples["words"] = encoded_inputs.words
|
||||
... examples["boxes"] = encoded_inputs.boxes
|
||||
|
||||
... return examples
|
||||
```
|
||||
|
||||
To apply this preprocessing to the entire dataset in a fast way, use [`~datasets.Dataset.map`].
|
||||
|
||||
```py
|
||||
>>> dataset_with_ocr = updated_dataset.map(get_ocr_words_and_boxes, batched=True, batch_size=2)
|
||||
```
|
||||
|
||||
### Preprocessing text data
|
||||
|
||||
Once we have applied OCR to the images, we need to encode the text part of the dataset to prepare it for the model.
|
||||
This involves converting the words and boxes that we got in the previous step to token-level `input_ids`, `attention_mask`,
|
||||
`token_type_ids` and `bbox`. For preprocessing text, we'll need the `tokenizer` from the processor.
|
||||
|
||||
```py
|
||||
>>> tokenizer = processor.tokenizer
|
||||
```
|
||||
|
||||
On top of the preprocessing mentioned above, we also need to add the labels for the model. For `xxxForQuestionAnswering` models
|
||||
in 🤗 Transformers, the labels consist of the `start_positions` and `end_positions`, indicating which token is at the
|
||||
start and which token is at the end of the answer.
|
||||
|
||||
Let's start with that. Define a helper function that can find a sublist (the answer split into words) in a larger list (the words list).
|
||||
|
||||
This function will take two lists as input, `words_list` and `answer_list`. It will then iterate over the `words_list` and check
|
||||
if the current word in the `words_list` (words_list[i]) is equal to the first word of answer_list (answer_list[0]) and if
|
||||
the sublist of `words_list` starting from the current word and of the same length as `answer_list` is equal `to answer_list`.
|
||||
If this condition is true, it means that a match has been found, and the function will record the match, its starting index (idx),
|
||||
and its ending index (idx + len(answer_list) - 1). If more than one match was found, the function will return only the first one.
|
||||
If no match is found, the function returns (`None`, 0, and 0).
|
||||
|
||||
```py
|
||||
>>> def subfinder(words_list, answer_list):
|
||||
... matches = []
|
||||
... start_indices = []
|
||||
... end_indices = []
|
||||
... for idx, i in enumerate(range(len(words_list))):
|
||||
... if words_list[i] == answer_list[0] and words_list[i : i + len(answer_list)] == answer_list:
|
||||
... matches.append(answer_list)
|
||||
... start_indices.append(idx)
|
||||
... end_indices.append(idx + len(answer_list) - 1)
|
||||
... if matches:
|
||||
... return matches[0], start_indices[0], end_indices[0]
|
||||
... else:
|
||||
... return None, 0, 0
|
||||
```
|
||||
|
||||
To illustrate how this function finds the position of the answer, let's use it on an example:
|
||||
|
||||
```py
|
||||
>>> example = dataset_with_ocr["train"][1]
|
||||
>>> words = [word.lower() for word in example["words"]]
|
||||
>>> match, word_idx_start, word_idx_end = subfinder(words, example["answer"].lower().split())
|
||||
>>> print("Question: ", example["question"])
|
||||
>>> print("Words:", words)
|
||||
>>> print("Answer: ", example["answer"])
|
||||
>>> print("start_index", word_idx_start)
|
||||
>>> print("end_index", word_idx_end)
|
||||
Question: Who is in cc in this letter?
|
||||
Words: ['wie', 'baw', 'brown', '&', 'williamson', 'tobacco', 'corporation', 'research', '&', 'development', 'internal', 'correspondence', 'to:', 'r.', 'h.', 'honeycutt', 'ce:', 't.f.', 'riehl', 'from:', '.', 'c.j.', 'cook', 'date:', 'may', '8,', '1995', 'subject:', 'review', 'of', 'existing', 'brainstorming', 'ideas/483', 'the', 'major', 'function', 'of', 'the', 'product', 'innovation', 'graup', 'is', 'to', 'develop', 'marketable', 'nove!', 'products', 'that', 'would', 'be', 'profitable', 'to', 'manufacture', 'and', 'sell.', 'novel', 'is', 'defined', 'as:', 'of', 'a', 'new', 'kind,', 'or', 'different', 'from', 'anything', 'seen', 'or', 'known', 'before.', 'innovation', 'is', 'defined', 'as:', 'something', 'new', 'or', 'different', 'introduced;', 'act', 'of', 'innovating;', 'introduction', 'of', 'new', 'things', 'or', 'methods.', 'the', 'products', 'may', 'incorporate', 'the', 'latest', 'technologies,', 'materials', 'and', 'know-how', 'available', 'to', 'give', 'then', 'a', 'unique', 'taste', 'or', 'look.', 'the', 'first', 'task', 'of', 'the', 'product', 'innovation', 'group', 'was', 'to', 'assemble,', 'review', 'and', 'categorize', 'a', 'list', 'of', 'existing', 'brainstorming', 'ideas.', 'ideas', 'were', 'grouped', 'into', 'two', 'major', 'categories', 'labeled', 'appearance', 'and', 'taste/aroma.', 'these', 'categories', 'are', 'used', 'for', 'novel', 'products', 'that', 'may', 'differ', 'from', 'a', 'visual', 'and/or', 'taste/aroma', 'point', 'of', 'view', 'compared', 'to', 'canventional', 'cigarettes.', 'other', 'categories', 'include', 'a', 'combination', 'of', 'the', 'above,', 'filters,', 'packaging', 'and', 'brand', 'extensions.', 'appearance', 'this', 'category', 'is', 'used', 'for', 'novel', 'cigarette', 'constructions', 'that', 'yield', 'visually', 'different', 'products', 'with', 'minimal', 'changes', 'in', 'smoke', 'chemistry', 'two', 'cigarettes', 'in', 'cne.', 'emulti-plug', 'te', 'build', 'yaur', 'awn', 'cigarette.', 'eswitchable', 'menthol', 'or', 'non', 'menthol', 'cigarette.', '*cigarettes', 'with', 'interspaced', 'perforations', 'to', 'enable', 'smoker', 'to', 'separate', 'unburned', 'section', 'for', 'future', 'smoking.', '«short', 'cigarette,', 'tobacco', 'section', '30', 'mm.', '«extremely', 'fast', 'buming', 'cigarette.', '«novel', 'cigarette', 'constructions', 'that', 'permit', 'a', 'significant', 'reduction', 'iretobacco', 'weight', 'while', 'maintaining', 'smoking', 'mechanics', 'and', 'visual', 'characteristics.', 'higher', 'basis', 'weight', 'paper:', 'potential', 'reduction', 'in', 'tobacco', 'weight.', '«more', 'rigid', 'tobacco', 'column;', 'stiffing', 'agent', 'for', 'tobacco;', 'e.g.', 'starch', '*colored', 'tow', 'and', 'cigarette', 'papers;', 'seasonal', 'promotions,', 'e.g.', 'pastel', 'colored', 'cigarettes', 'for', 'easter', 'or', 'in', 'an', 'ebony', 'and', 'ivory', 'brand', 'containing', 'a', 'mixture', 'of', 'all', 'black', '(black', 'paper', 'and', 'tow)', 'and', 'ail', 'white', 'cigarettes.', '499150498']
|
||||
Answer: T.F. Riehl
|
||||
start_index 17
|
||||
end_index 18
|
||||
```
|
||||
|
||||
Once examples are encoded, however, they will look like this:
|
||||
|
||||
```py
|
||||
>>> encoding = tokenizer(example["question"], example["words"], example["boxes"])
|
||||
>>> tokenizer.decode(encoding["input_ids"])
|
||||
[CLS] who is in cc in this letter? [SEP] wie baw brown & williamson tobacco corporation research & development ...
|
||||
```
|
||||
|
||||
We'll need to find the position of the answer in the encoded input.
|
||||
* `token_type_ids` tells us which tokens are part of the question, and which ones are part of the document's words.
|
||||
* `tokenizer.cls_token_id` will help find the special token at the beginning of the input.
|
||||
* `word_ids` will help match the answer found in the original `words` to the same answer in the full encoded input and determine
|
||||
the start/end position of the answer in the encoded input.
|
||||
|
||||
With that in mind, let's create a function to encode a batch of examples in the dataset:
|
||||
|
||||
```py
|
||||
>>> def encode_dataset(examples, max_length=512):
|
||||
... questions = examples["question"]
|
||||
... words = examples["words"]
|
||||
... boxes = examples["boxes"]
|
||||
... answers = examples["answer"]
|
||||
|
||||
... # encode the batch of examples and initialize the start_positions and end_positions
|
||||
... encoding = tokenizer(questions, words, boxes, max_length=max_length, padding="max_length", truncation=True)
|
||||
... start_positions = []
|
||||
... end_positions = []
|
||||
|
||||
... # loop through the examples in the batch
|
||||
... for i in range(len(questions)):
|
||||
... cls_index = encoding["input_ids"][i].index(tokenizer.cls_token_id)
|
||||
|
||||
... # find the position of the answer in example's words
|
||||
... words_example = [word.lower() for word in words[i]]
|
||||
... answer = answers[i]
|
||||
... match, word_idx_start, word_idx_end = subfinder(words_example, answer.lower().split())
|
||||
|
||||
... if match:
|
||||
... # if match is found, use `token_type_ids` to find where words start in the encoding
|
||||
... token_type_ids = encoding["token_type_ids"][i]
|
||||
... token_start_index = 0
|
||||
... while token_type_ids[token_start_index] != 1:
|
||||
... token_start_index += 1
|
||||
|
||||
... token_end_index = len(encoding["input_ids"][i]) - 1
|
||||
... while token_type_ids[token_end_index] != 1:
|
||||
... token_end_index -= 1
|
||||
|
||||
... word_ids = encoding.word_ids(i)[token_start_index : token_end_index + 1]
|
||||
... start_position = cls_index
|
||||
... end_position = cls_index
|
||||
|
||||
... # loop over word_ids and increase `token_start_index` until it matches the answer position in words
|
||||
... # once it matches, save the `token_start_index` as the `start_position` of the answer in the encoding
|
||||
... for id in word_ids:
|
||||
... if id == word_idx_start:
|
||||
... start_position = token_start_index
|
||||
... else:
|
||||
... token_start_index += 1
|
||||
|
||||
... # similarly loop over `word_ids` starting from the end to find the `end_position` of the answer
|
||||
... for id in word_ids[::-1]:
|
||||
... if id == word_idx_end:
|
||||
... end_position = token_end_index
|
||||
... else:
|
||||
... token_end_index -= 1
|
||||
|
||||
... start_positions.append(start_position)
|
||||
... end_positions.append(end_position)
|
||||
|
||||
... else:
|
||||
... start_positions.append(cls_index)
|
||||
... end_positions.append(cls_index)
|
||||
|
||||
... encoding["image"] = examples["image"]
|
||||
... encoding["start_positions"] = start_positions
|
||||
... encoding["end_positions"] = end_positions
|
||||
|
||||
... return encoding
|
||||
```
|
||||
|
||||
Now that we have this preprocessing function, we can encode the entire dataset:
|
||||
|
||||
```py
|
||||
>>> encoded_train_dataset = dataset_with_ocr["train"].map(
|
||||
... encode_dataset, batched=True, batch_size=2, remove_columns=dataset_with_ocr["train"].column_names
|
||||
... )
|
||||
>>> encoded_test_dataset = dataset_with_ocr["test"].map(
|
||||
... encode_dataset, batched=True, batch_size=2, remove_columns=dataset_with_ocr["test"].column_names
|
||||
... )
|
||||
```
|
||||
|
||||
Let's check what the features of the encoded dataset look like:
|
||||
|
||||
```py
|
||||
>>> encoded_train_dataset.features
|
||||
{'image': Sequence(feature=Sequence(feature=Sequence(feature=Value(dtype='uint8', id=None), length=-1, id=None), length=-1, id=None), length=-1, id=None),
|
||||
'input_ids': Sequence(feature=Value(dtype='int32', id=None), length=-1, id=None),
|
||||
'token_type_ids': Sequence(feature=Value(dtype='int8', id=None), length=-1, id=None),
|
||||
'attention_mask': Sequence(feature=Value(dtype='int8', id=None), length=-1, id=None),
|
||||
'bbox': Sequence(feature=Sequence(feature=Value(dtype='int64', id=None), length=-1, id=None), length=-1, id=None),
|
||||
'start_positions': Value(dtype='int64', id=None),
|
||||
'end_positions': Value(dtype='int64', id=None)}
|
||||
```
|
||||
|
||||
## Evaluation
|
||||
|
||||
Evaluation for document question answering requires a significant amount of postprocessing. To avoid taking up too much
|
||||
of your time, this guide skips the evaluation step. The [`Trainer`] still calculates the evaluation loss during training so
|
||||
you're not completely in the dark about your model's performance. Extractive question answering is typically evaluated using F1/exact match.
|
||||
If you'd like to implement it yourself, check out the [Question Answering chapter](https://huggingface.co/course/chapter7/7?fw=pt#postprocessing)
|
||||
of the Hugging Face course for inspiration.
|
||||
|
||||
## Train
|
||||
|
||||
Congratulations! You've successfully navigated the toughest part of this guide and now you are ready to train your own model.
|
||||
Training involves the following steps:
|
||||
* Load the model with [`AutoModelForDocumentQuestionAnswering`] using the same checkpoint as in the preprocessing.
|
||||
* Define your training hyperparameters in [`TrainingArguments`].
|
||||
* Define a function to batch examples together, here the [`DefaultDataCollator`] will do just fine
|
||||
* Pass the training arguments to [`Trainer`] along with the model, dataset, and data collator.
|
||||
* Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForDocumentQuestionAnswering
|
||||
|
||||
>>> model = AutoModelForDocumentQuestionAnswering.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
In the [`TrainingArguments`] use `output_dir` to specify where to save your model, and configure hyperparameters as you see fit.
|
||||
If you wish to share your model with the community, set `push_to_hub` to `True` (you must be signed in to Hugging Face to upload your model).
|
||||
In this case the `output_dir` will also be the name of the repo where your model checkpoint will be pushed.
|
||||
|
||||
```py
|
||||
>>> from transformers import TrainingArguments
|
||||
|
||||
>>> # REPLACE THIS WITH YOUR REPO ID
|
||||
>>> repo_id = "MariaK/layoutlmv2-base-uncased_finetuned_docvqa"
|
||||
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir=repo_id,
|
||||
... per_device_train_batch_size=4,
|
||||
... num_train_epochs=20,
|
||||
... save_steps=200,
|
||||
... logging_steps=50,
|
||||
... eval_strategy="steps",
|
||||
... learning_rate=5e-5,
|
||||
... save_total_limit=2,
|
||||
... remove_unused_columns=False,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
```
|
||||
|
||||
Define a simple data collator to batch examples together.
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
Finally, bring everything together, and call [`~Trainer.train`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import Trainer
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... data_collator=data_collator,
|
||||
... train_dataset=encoded_train_dataset,
|
||||
... eval_dataset=encoded_test_dataset,
|
||||
... processing_class=processor,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
To add the final model to 🤗 Hub, create a model card and call `push_to_hub`:
|
||||
|
||||
```py
|
||||
>>> trainer.create_model_card()
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## Inference
|
||||
|
||||
Now that you have finetuned a LayoutLMv2 model, and uploaded it to the 🤗 Hub, you can use it for inference. The simplest
|
||||
way to try out your finetuned model for inference is to use it in a [`Pipeline`].
|
||||
|
||||
Let's take an example:
|
||||
|
||||
```py
|
||||
>>> example = dataset["test"][2]
|
||||
>>> question = example["query"]["en"]
|
||||
>>> image = example["image"]
|
||||
>>> print(question)
|
||||
>>> print(example["answers"])
|
||||
'Who is ‘presiding’ TRRF GENERAL SESSION (PART 1)?'
|
||||
['TRRF Vice President', 'lee a. waller']
|
||||
```
|
||||
|
||||
Next, instantiate a pipeline for
|
||||
document question answering with your model, and pass the image + question combination to it.
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> qa_pipeline = pipeline("document-question-answering", model="MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
|
||||
>>> qa_pipeline(image, question)
|
||||
[{'score': 0.9949808120727539,
|
||||
'answer': 'Lee A. Waller',
|
||||
'start': 55,
|
||||
'end': 57}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the pipeline if you'd like:
|
||||
1. Take an image and a question, prepare them for the model using the processor from your model.
|
||||
2. Forward the result or preprocessing through the model.
|
||||
3. The model returns `start_logits` and `end_logits`, which indicate which token is at the start of the answer and
|
||||
which token is at the end of the answer. Both have shape (batch_size, sequence_length).
|
||||
4. Take an argmax on the last dimension of both the `start_logits` and `end_logits` to get the predicted `start_idx` and `end_idx`.
|
||||
5. Decode the answer with the tokenizer.
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
>>> from transformers import AutoProcessor
|
||||
>>> from transformers import AutoModelForDocumentQuestionAnswering
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
|
||||
>>> model = AutoModelForDocumentQuestionAnswering.from_pretrained("MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... encoding = processor(image.convert("RGB"), question, return_tensors="pt")
|
||||
... outputs = model(**encoding)
|
||||
... start_logits = outputs.start_logits
|
||||
... end_logits = outputs.end_logits
|
||||
... predicted_start_idx = start_logits.argmax(-1).item()
|
||||
... predicted_end_idx = end_logits.argmax(-1).item()
|
||||
|
||||
>>> processor.tokenizer.decode(encoding.input_ids.squeeze()[predicted_start_idx : predicted_end_idx + 1])
|
||||
'lee a. waller'
|
||||
```
|
||||
423
transformers/docs/source/en/tasks/idefics.md
Normal file
423
transformers/docs/source/en/tasks/idefics.md
Normal file
@@ -0,0 +1,423 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image tasks with IDEFICS
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
While individual tasks can be tackled by fine-tuning specialized models, an alternative approach
|
||||
that has recently emerged and gained popularity is to use large models for a diverse set of tasks without fine-tuning.
|
||||
For instance, large language models can handle such NLP tasks as summarization, translation, classification, and more.
|
||||
This approach is no longer limited to a single modality, such as text, and in this guide, we will illustrate how you can
|
||||
solve image-text tasks with a large multimodal model called IDEFICS.
|
||||
|
||||
[IDEFICS](../model_doc/idefics) is an open-access vision and language model based on [Flamingo](https://huggingface.co/papers/2204.14198),
|
||||
a state-of-the-art visual language model initially developed by DeepMind. The model accepts arbitrary sequences of image
|
||||
and text inputs and generates coherent text as output. It can answer questions about images, describe visual content,
|
||||
create stories grounded in multiple images, and so on. IDEFICS comes in two variants - [80 billion parameters](https://huggingface.co/HuggingFaceM4/idefics-80b)
|
||||
and [9 billion parameters](https://huggingface.co/HuggingFaceM4/idefics-9b), both of which are available on the 🤗 Hub. For each variant, you can also find fine-tuned instructed
|
||||
versions of the model adapted for conversational use cases.
|
||||
|
||||
This model is exceptionally versatile and can be used for a wide range of image and multimodal tasks. However,
|
||||
being a large model means it requires significant computational resources and infrastructure. It is up to you to decide whether
|
||||
this approach suits your use case better than fine-tuning specialized models for each individual task.
|
||||
|
||||
In this guide, you'll learn how to:
|
||||
- [Load IDEFICS](#loading-the-model) and [load the quantized version of the model](#quantized-model)
|
||||
- Use IDEFICS for:
|
||||
- [Image captioning](#image-captioning)
|
||||
- [Prompted image captioning](#prompted-image-captioning)
|
||||
- [Few-shot prompting](#few-shot-prompting)
|
||||
- [Visual question answering](#visual-question-answering)
|
||||
- [Image classification](#image-classification)
|
||||
- [Image-guided text generation](#image-guided-text-generation)
|
||||
- [Run inference in batch mode](#running-inference-in-batch-mode)
|
||||
- [Run IDEFICS instruct for conversational use](#idefics-instruct-for-conversational-use)
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed.
|
||||
|
||||
```bash
|
||||
pip install -q bitsandbytes sentencepiece accelerate transformers
|
||||
```
|
||||
|
||||
<Tip>
|
||||
To run the following examples with a non-quantized version of the model checkpoint you will need at least 20GB of GPU memory.
|
||||
</Tip>
|
||||
|
||||
## Loading the model
|
||||
|
||||
Let's start by loading the model's 9 billion parameters checkpoint:
|
||||
|
||||
```py
|
||||
>>> checkpoint = "HuggingFaceM4/idefics-9b"
|
||||
```
|
||||
|
||||
Just like for other Transformers models, you need to load a processor and the model itself from the checkpoint.
|
||||
The IDEFICS processor wraps a [`LlamaTokenizer`] and IDEFICS image processor into a single processor to take care of
|
||||
preparing text and image inputs for the model.
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> from transformers import IdeficsForVisionText2Text, AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
|
||||
>>> model = IdeficsForVisionText2Text.from_pretrained(checkpoint, dtype=torch.bfloat16, device_map="auto")
|
||||
```
|
||||
|
||||
Setting `device_map` to `"auto"` will automatically determine how to load and store the model weights in the most optimized
|
||||
manner given existing devices.
|
||||
|
||||
### Quantized model
|
||||
|
||||
If high-memory device availability is an issue, you can load the quantized version of the model. To load the model and the
|
||||
processor in 4bit precision, pass a `BitsAndBytesConfig` to the `from_pretrained` method and the model will be compressed
|
||||
on the fly while loading.
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
>>> from transformers import IdeficsForVisionText2Text, AutoProcessor, BitsAndBytesConfig
|
||||
|
||||
>>> quantization_config = BitsAndBytesConfig(
|
||||
... load_in_4bit=True,
|
||||
... bnb_4bit_compute_dtype=torch.float16,
|
||||
... )
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
|
||||
>>> model = IdeficsForVisionText2Text.from_pretrained(
|
||||
... checkpoint,
|
||||
... quantization_config=quantization_config,
|
||||
... device_map="auto"
|
||||
... )
|
||||
```
|
||||
|
||||
Now that you have the model loaded in one of the suggested ways, let's move on to exploring tasks that you can use IDEFICS for.
|
||||
|
||||
## Image captioning
|
||||
Image captioning is the task of predicting a caption for a given image. A common application is to aid visually impaired
|
||||
people navigate through different situations, for instance, explore image content online.
|
||||
|
||||
To illustrate the task, get an image to be captioned, e.g.:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-im-captioning.jpg" alt="Image of a puppy in a flower bed"/>
|
||||
</div>
|
||||
|
||||
Photo by [Hendo Wang](https://unsplash.com/@hendoo).
|
||||
|
||||
IDEFICS accepts text and image prompts. However, to caption an image, you do not have to provide a text prompt to the
|
||||
model, only the preprocessed input image. Without a text prompt, the model will start generating text from the
|
||||
BOS (beginning-of-sequence) token thus creating a caption.
|
||||
|
||||
As image input to the model, you can use either an image object (`PIL.Image`) or a url from which the image can be retrieved.
|
||||
|
||||
```py
|
||||
>>> prompt = [
|
||||
... "https://images.unsplash.com/photo-1583160247711-2191776b4b91?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3542&q=80",
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=10, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
A puppy in a flower bed
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
It is a good idea to include the `bad_words_ids` in the call to `generate` to avoid errors arising when increasing
|
||||
the `max_new_tokens`: the model will want to generate a new `<image>` or `<fake_token_around_image>` token when there
|
||||
is no image being generated by the model.
|
||||
You can set it on-the-fly as in this guide, or store in the `GenerationConfig` as described in the [Text generation strategies](../generation_strategies) guide.
|
||||
</Tip>
|
||||
|
||||
## Prompted image captioning
|
||||
|
||||
You can extend image captioning by providing a text prompt, which the model will continue given the image. Let's take
|
||||
another image to illustrate:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-prompted-im-captioning.jpg" alt="Image of the Eiffel Tower at night"/>
|
||||
</div>
|
||||
|
||||
Photo by [Denys Nevozhai](https://unsplash.com/@dnevozhai).
|
||||
|
||||
Textual and image prompts can be passed to the model's processor as a single list to create appropriate inputs.
|
||||
|
||||
```py
|
||||
>>> prompt = [
|
||||
... "https://images.unsplash.com/photo-1543349689-9a4d426bee8e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3501&q=80",
|
||||
... "This is an image of ",
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=10, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
This is an image of the Eiffel Tower in Paris, France.
|
||||
```
|
||||
|
||||
## Few-shot prompting
|
||||
|
||||
While IDEFICS demonstrates great zero-shot results, your task may require a certain format of the caption, or come with
|
||||
other restrictions or requirements that increase task's complexity. Few-shot prompting can be used to enable in-context learning.
|
||||
By providing examples in the prompt, you can steer the model to generate results that mimic the format of given examples.
|
||||
|
||||
Let's use the previous image of the Eiffel Tower as an example for the model and build a prompt that demonstrates to the model
|
||||
that in addition to learning what the object in an image is, we would also like to get some interesting information about it.
|
||||
Then, let's see, if we can get the same response format for an image of the Statue of Liberty:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-few-shot.jpg" alt="Image of the Statue of Liberty"/>
|
||||
</div>
|
||||
|
||||
Photo by [Juan Mayobre](https://unsplash.com/@jmayobres).
|
||||
|
||||
```py
|
||||
>>> prompt = ["User:",
|
||||
... "https://images.unsplash.com/photo-1543349689-9a4d426bee8e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3501&q=80",
|
||||
... "Describe this image.\nAssistant: An image of the Eiffel Tower at night. Fun fact: the Eiffel Tower is the same height as an 81-storey building.\n",
|
||||
... "User:",
|
||||
... "https://images.unsplash.com/photo-1524099163253-32b7f0256868?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3387&q=80",
|
||||
... "Describe this image.\nAssistant:"
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=30, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
User: Describe this image.
|
||||
Assistant: An image of the Eiffel Tower at night. Fun fact: the Eiffel Tower is the same height as an 81-storey building.
|
||||
User: Describe this image.
|
||||
Assistant: An image of the Statue of Liberty. Fun fact: the Statue of Liberty is 151 feet tall.
|
||||
```
|
||||
|
||||
Notice that just from a single example (i.e., 1-shot) the model has learned how to perform the task. For more complex tasks,
|
||||
feel free to experiment with a larger number of examples (e.g., 3-shot, 5-shot, etc.).
|
||||
|
||||
## Visual question answering
|
||||
|
||||
Visual Question Answering (VQA) is the task of answering open-ended questions based on an image. Similar to image
|
||||
captioning it can be used in accessibility applications, but also in education (reasoning about visual materials), customer
|
||||
service (questions about products based on images), and image retrieval.
|
||||
|
||||
Let's get a new image for this task:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-vqa.jpg" alt="Image of a couple having a picnic"/>
|
||||
</div>
|
||||
|
||||
Photo by [Jarritos Mexican Soda](https://unsplash.com/@jarritos).
|
||||
|
||||
You can steer the model from image captioning to visual question answering by prompting it with appropriate instructions:
|
||||
|
||||
```py
|
||||
>>> prompt = [
|
||||
... "Instruction: Provide an answer to the question. Use the image to answer.\n",
|
||||
... "https://images.unsplash.com/photo-1623944889288-cd147dbb517c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3540&q=80",
|
||||
... "Question: Where are these people and what's the weather like? Answer:"
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=20, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
Instruction: Provide an answer to the question. Use the image to answer.
|
||||
Question: Where are these people and what's the weather like? Answer: They're in a park in New York City, and it's a beautiful day.
|
||||
```
|
||||
|
||||
## Image classification
|
||||
|
||||
IDEFICS is capable of classifying images into different categories without being explicitly trained on data containing
|
||||
labeled examples from those specific categories. Given a list of categories and using its image and text understanding
|
||||
capabilities, the model can infer which category the image likely belongs to.
|
||||
|
||||
Say, we have this image of a vegetable stand:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-classification.jpg" alt="Image of a vegetable stand"/>
|
||||
</div>
|
||||
|
||||
Photo by [Peter Wendt](https://unsplash.com/@peterwendt).
|
||||
|
||||
We can instruct the model to classify the image into one of the categories that we have:
|
||||
|
||||
```py
|
||||
>>> categories = ['animals','vegetables', 'city landscape', 'cars', 'office']
|
||||
>>> prompt = [f"Instruction: Classify the following image into a single category from the following list: {categories}.\n",
|
||||
... "https://images.unsplash.com/photo-1471193945509-9ad0617afabf?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3540&q=80",
|
||||
... "Category: "
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=6, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
Instruction: Classify the following image into a single category from the following list: ['animals', 'vegetables', 'city landscape', 'cars', 'office'].
|
||||
Category: Vegetables
|
||||
```
|
||||
|
||||
In the example above we instruct the model to classify the image into a single category, however, you can also prompt the model to do rank classification.
|
||||
|
||||
## Image-guided text generation
|
||||
|
||||
For more creative applications, you can use image-guided text generation to generate text based on an image. This can be
|
||||
useful to create descriptions of products, ads, descriptions of a scene, etc.
|
||||
|
||||
Let's prompt IDEFICS to write a story based on a simple image of a red door:
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-story-generation.jpg" alt="Image of a red door with a pumpkin on the steps"/>
|
||||
</div>
|
||||
|
||||
Photo by [Craig Tidball](https://unsplash.com/@devonshiremedia).
|
||||
|
||||
```py
|
||||
>>> prompt = ["Instruction: Use the image to write a story. \n",
|
||||
... "https://images.unsplash.com/photo-1517086822157-2b0358e7684a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2203&q=80",
|
||||
... "Story: \n"]
|
||||
|
||||
>>> inputs = processor(prompt, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, num_beams=2, max_new_tokens=200, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> print(generated_text[0])
|
||||
Instruction: Use the image to write a story.
|
||||
Story:
|
||||
Once upon a time, there was a little girl who lived in a house with a red door. She loved her red door. It was the prettiest door in the whole world.
|
||||
|
||||
One day, the little girl was playing in her yard when she noticed a man standing on her doorstep. He was wearing a long black coat and a top hat.
|
||||
|
||||
The little girl ran inside and told her mother about the man.
|
||||
|
||||
Her mother said, “Don’t worry, honey. He’s just a friendly ghost.”
|
||||
|
||||
The little girl wasn’t sure if she believed her mother, but she went outside anyway.
|
||||
|
||||
When she got to the door, the man was gone.
|
||||
|
||||
The next day, the little girl was playing in her yard again when she noticed the man standing on her doorstep.
|
||||
|
||||
He was wearing a long black coat and a top hat.
|
||||
|
||||
The little girl ran
|
||||
```
|
||||
|
||||
Looks like IDEFICS noticed the pumpkin on the doorstep and went with a spooky Halloween story about a ghost.
|
||||
|
||||
<Tip>
|
||||
|
||||
For longer outputs like this, you will greatly benefit from tweaking the text generation strategy. This can help
|
||||
you significantly improve the quality of the generated output. Check out [Text generation strategies](../generation_strategies)
|
||||
to learn more.
|
||||
</Tip>
|
||||
|
||||
## Running inference in batch mode
|
||||
|
||||
All of the earlier sections illustrated IDEFICS for a single example. In a very similar fashion, you can run inference
|
||||
for a batch of examples by passing a list of prompts:
|
||||
|
||||
```py
|
||||
>>> prompts = [
|
||||
... [ "https://images.unsplash.com/photo-1543349689-9a4d426bee8e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3501&q=80",
|
||||
... "This is an image of ",
|
||||
... ],
|
||||
... [ "https://images.unsplash.com/photo-1623944889288-cd147dbb517c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3540&q=80",
|
||||
... "This is an image of ",
|
||||
... ],
|
||||
... [ "https://images.unsplash.com/photo-1471193945509-9ad0617afabf?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3540&q=80",
|
||||
... "This is an image of ",
|
||||
... ],
|
||||
... ]
|
||||
|
||||
>>> inputs = processor(prompts, return_tensors="pt").to(model.device)
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=10, bad_words_ids=bad_words_ids)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> for i,t in enumerate(generated_text):
|
||||
... print(f"{i}:\n{t}\n")
|
||||
0:
|
||||
This is an image of the Eiffel Tower in Paris, France.
|
||||
|
||||
1:
|
||||
This is an image of a couple on a picnic blanket.
|
||||
|
||||
2:
|
||||
This is an image of a vegetable stand.
|
||||
```
|
||||
|
||||
## IDEFICS instruct for conversational use
|
||||
|
||||
For conversational use cases, you can find fine-tuned instructed versions of the model on the 🤗 Hub:
|
||||
`HuggingFaceM4/idefics-80b-instruct` and `HuggingFaceM4/idefics-9b-instruct`.
|
||||
|
||||
These checkpoints are the result of fine-tuning the respective base models on a mixture of supervised and instruction
|
||||
fine-tuning datasets, which boosts the downstream performance while making the models more usable in conversational settings.
|
||||
|
||||
The use and prompting for the conversational use is very similar to using the base models:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
>>> from transformers import IdeficsForVisionText2Text, AutoProcessor
|
||||
|
||||
>>> checkpoint = "HuggingFaceM4/idefics-9b-instruct"
|
||||
>>> model = IdeficsForVisionText2Text.from_pretrained(checkpoint, dtype=torch.bfloat16, device_map="auto")
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
|
||||
>>> prompts = [
|
||||
... [
|
||||
... "User: What is in this image?",
|
||||
... "https://upload.wikimedia.org/wikipedia/commons/8/86/Id%C3%A9fix.JPG",
|
||||
... "<end_of_utterance>",
|
||||
|
||||
... "\nAssistant: This picture depicts Idefix, the dog of Obelix in Asterix and Obelix. Idefix is running on the ground.<end_of_utterance>",
|
||||
|
||||
... "\nUser:",
|
||||
... "https://static.wikia.nocookie.net/asterix/images/2/25/R22b.gif/revision/latest?cb=20110815073052",
|
||||
... "And who is that?<end_of_utterance>",
|
||||
|
||||
... "\nAssistant:",
|
||||
... ],
|
||||
... ]
|
||||
|
||||
>>> # --batched mode
|
||||
>>> inputs = processor(prompts, add_end_of_utterance_token=False, return_tensors="pt").to(model.device)
|
||||
>>> # --single sample mode
|
||||
>>> # inputs = processor(prompts[0], return_tensors="pt").to(model.device)
|
||||
|
||||
>>> # Generation args
|
||||
>>> exit_condition = processor.tokenizer("<end_of_utterance>", add_special_tokens=False).input_ids
|
||||
>>> bad_words_ids = processor.tokenizer(["<image>", "<fake_token_around_image>"], add_special_tokens=False).input_ids
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, eos_token_id=exit_condition, bad_words_ids=bad_words_ids, max_length=100)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
>>> for i, t in enumerate(generated_text):
|
||||
... print(f"{i}:\n{t}\n")
|
||||
```
|
||||
269
transformers/docs/source/en/tasks/image_captioning.md
Normal file
269
transformers/docs/source/en/tasks/image_captioning.md
Normal file
@@ -0,0 +1,269 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image captioning
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Image captioning is the task of predicting a caption for a given image. Common real world applications of it include
|
||||
aiding visually impaired people that can help them navigate through different situations. Therefore, image captioning
|
||||
helps to improve content accessibility for people by describing images to them.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
* Fine-tune an image captioning model.
|
||||
* Use the fine-tuned model for inference.
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate -q
|
||||
pip install jiwer -q
|
||||
```
|
||||
|
||||
We encourage you to log in to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```python
|
||||
from huggingface_hub import notebook_login
|
||||
|
||||
notebook_login()
|
||||
```
|
||||
|
||||
## Load the Pokémon BLIP captions dataset
|
||||
|
||||
Use the 🤗 Dataset library to load a dataset that consists of {image-caption} pairs. To create your own image captioning dataset
|
||||
in PyTorch, you can follow [this notebook](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/GIT/Fine_tune_GIT_on_an_image_captioning_dataset.ipynb).
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
ds = load_dataset("lambdalabs/pokemon-blip-captions")
|
||||
ds
|
||||
```
|
||||
|
||||
```bash
|
||||
DatasetDict({
|
||||
train: Dataset({
|
||||
features: ['image', 'text'],
|
||||
num_rows: 833
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
The dataset has two features, `image` and `text`.
|
||||
|
||||
<Tip>
|
||||
|
||||
Many image captioning datasets contain multiple captions per image. In those cases, a common strategy is to randomly sample a caption amongst the available ones during training.
|
||||
|
||||
</Tip>
|
||||
|
||||
Split the dataset's train split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```python
|
||||
ds = ds["train"].train_test_split(test_size=0.1)
|
||||
train_ds = ds["train"]
|
||||
test_ds = ds["test"]
|
||||
```
|
||||
|
||||
Let's visualize a couple of samples from the training set.
|
||||
|
||||
```python
|
||||
from textwrap import wrap
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
def plot_images(images, captions):
|
||||
plt.figure(figsize=(20, 20))
|
||||
for i in range(len(images)):
|
||||
ax = plt.subplot(1, len(images), i + 1)
|
||||
caption = captions[i]
|
||||
caption = "\n".join(wrap(caption, 12))
|
||||
plt.title(caption)
|
||||
plt.imshow(images[i])
|
||||
plt.axis("off")
|
||||
|
||||
|
||||
sample_images_to_visualize = [np.array(train_ds[i]["image"]) for i in range(5)]
|
||||
sample_captions = [train_ds[i]["text"] for i in range(5)]
|
||||
plot_images(sample_images_to_visualize, sample_captions)
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/sample_training_images_image_cap.png" alt="Sample training images"/>
|
||||
</div>
|
||||
|
||||
## Preprocess the dataset
|
||||
|
||||
Since the dataset has two modalities (image and text), the pre-processing pipeline will preprocess images and the captions.
|
||||
|
||||
To do so, load the processor class associated with the model you are about to fine-tune.
|
||||
|
||||
```python
|
||||
from transformers import AutoProcessor
|
||||
|
||||
checkpoint = "microsoft/git-base"
|
||||
processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
The processor will internally pre-process the image (which includes resizing, and pixel scaling) and tokenize the caption.
|
||||
|
||||
```python
|
||||
def transforms(example_batch):
|
||||
images = [x for x in example_batch["image"]]
|
||||
captions = [x for x in example_batch["text"]]
|
||||
inputs = processor(images=images, text=captions, padding="max_length")
|
||||
inputs.update({"labels": inputs["input_ids"]})
|
||||
return inputs
|
||||
|
||||
|
||||
train_ds.set_transform(transforms)
|
||||
test_ds.set_transform(transforms)
|
||||
```
|
||||
|
||||
With the dataset ready, you can now set up the model for fine-tuning.
|
||||
|
||||
## Load a base model
|
||||
|
||||
Load the ["microsoft/git-base"](https://huggingface.co/microsoft/git-base) into a [`AutoModelForCausalLM`](https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoModelForCausalLM) object.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Image captioning models are typically evaluated with the [Rouge Score](https://huggingface.co/spaces/evaluate-metric/rouge) or [Word Error Rate](https://huggingface.co/spaces/evaluate-metric/wer). For this guide, you will use the Word Error Rate (WER).
|
||||
|
||||
We use the 🤗 Evaluate library to do so. For potential limitations and other gotchas of the WER, refer to [this guide](https://huggingface.co/spaces/evaluate-metric/wer).
|
||||
|
||||
```python
|
||||
from evaluate import load
|
||||
import torch
|
||||
|
||||
wer = load("wer")
|
||||
|
||||
|
||||
def compute_metrics(eval_pred):
|
||||
logits, labels = eval_pred
|
||||
predicted = logits.argmax(-1)
|
||||
decoded_labels = processor.batch_decode(labels, skip_special_tokens=True)
|
||||
decoded_predictions = processor.batch_decode(predicted, skip_special_tokens=True)
|
||||
wer_score = wer.compute(predictions=decoded_predictions, references=decoded_labels)
|
||||
return {"wer_score": wer_score}
|
||||
```
|
||||
|
||||
## Train!
|
||||
|
||||
Now, you are ready to start fine-tuning the model. You will use the 🤗 [`Trainer`] for this.
|
||||
|
||||
First, define the training arguments using [`TrainingArguments`].
|
||||
|
||||
```python
|
||||
from transformers import TrainingArguments, Trainer
|
||||
|
||||
model_name = checkpoint.split("/")[1]
|
||||
|
||||
training_args = TrainingArguments(
|
||||
output_dir=f"{model_name}-pokemon",
|
||||
learning_rate=5e-5,
|
||||
num_train_epochs=50,
|
||||
fp16=True,
|
||||
per_device_train_batch_size=32,
|
||||
per_device_eval_batch_size=32,
|
||||
gradient_accumulation_steps=2,
|
||||
save_total_limit=3,
|
||||
eval_strategy="steps",
|
||||
eval_steps=50,
|
||||
save_strategy="steps",
|
||||
save_steps=50,
|
||||
logging_steps=50,
|
||||
remove_unused_columns=False,
|
||||
push_to_hub=True,
|
||||
label_names=["labels"],
|
||||
load_best_model_at_end=True,
|
||||
)
|
||||
```
|
||||
|
||||
Then pass them along with the datasets and the model to 🤗 Trainer.
|
||||
|
||||
```python
|
||||
trainer = Trainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
train_dataset=train_ds,
|
||||
eval_dataset=test_ds,
|
||||
compute_metrics=compute_metrics,
|
||||
)
|
||||
```
|
||||
|
||||
To start training, simply call [`~Trainer.train`] on the [`Trainer`] object.
|
||||
|
||||
```python
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
You should see the training loss drop smoothly as training progresses.
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```python
|
||||
trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## Inference
|
||||
|
||||
Take a sample image from `test_ds` to test the model.
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
url = "https://huggingface.co/datasets/sayakpaul/sample-datasets/resolve/main/pokemon.png"
|
||||
image = Image.open(requests.get(url, stream=True).raw)
|
||||
image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/test_image_image_cap.png" alt="Test image"/>
|
||||
</div>
|
||||
|
||||
Prepare image for the model.
|
||||
|
||||
```python
|
||||
from transformers import infer_device
|
||||
|
||||
device = infer_device()
|
||||
inputs = processor(images=image, return_tensors="pt").to(device)
|
||||
pixel_values = inputs.pixel_values
|
||||
```
|
||||
|
||||
Call [`generate`] and decode the predictions.
|
||||
|
||||
```python
|
||||
generated_ids = model.generate(pixel_values=pixel_values, max_length=50)
|
||||
generated_caption = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
print(generated_caption)
|
||||
```
|
||||
|
||||
```bash
|
||||
a drawing of a pink and blue pokemon
|
||||
```
|
||||
|
||||
Looks like the fine-tuned model generated a pretty good caption!
|
||||
303
transformers/docs/source/en/tasks/image_classification.md
Normal file
303
transformers/docs/source/en/tasks/image_classification.md
Normal file
@@ -0,0 +1,303 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="tjAIM7BOYhw"/>
|
||||
|
||||
Image classification assigns a label or class to an image. Unlike text or audio classification, the inputs are the
|
||||
pixel values that comprise an image. There are many applications for image classification, such as detecting damage
|
||||
after a natural disaster, monitoring crop health, or helping screen medical images for signs of disease.
|
||||
|
||||
This guide illustrates how to:
|
||||
|
||||
1. Fine-tune [ViT](../model_doc/vit) on the [Food-101](https://huggingface.co/datasets/food101) dataset to classify a food item in an image.
|
||||
2. Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/image-classification)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate accelerate pillow torchvision scikit-learn
|
||||
```
|
||||
|
||||
We encourage you to log in to your Hugging Face account to upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load Food-101 dataset
|
||||
|
||||
Start by loading a smaller subset of the Food-101 dataset from the 🤗 Datasets library. This will give you a chance to
|
||||
experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> food = load_dataset("food101", split="train[:5000]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> food = food.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> food["train"][0]
|
||||
{'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=512x512 at 0x7F52AFC8AC50>,
|
||||
'label': 79}
|
||||
```
|
||||
|
||||
Each example in the dataset has two fields:
|
||||
|
||||
- `image`: a PIL image of the food item
|
||||
- `label`: the label class of the food item
|
||||
|
||||
To make it easier for the model to get the label name from the label id, create a dictionary that maps the label name
|
||||
to an integer and vice versa:
|
||||
|
||||
```py
|
||||
>>> labels = food["train"].features["label"].names
|
||||
>>> label2id, id2label = dict(), dict()
|
||||
>>> for i, label in enumerate(labels):
|
||||
... label2id[label] = str(i)
|
||||
... id2label[str(i)] = label
|
||||
```
|
||||
|
||||
Now you can convert the label id to a label name:
|
||||
|
||||
```py
|
||||
>>> id2label[str(79)]
|
||||
'prime_rib'
|
||||
```
|
||||
|
||||
## Preprocess
|
||||
|
||||
The next step is to load a ViT image processor to process the image into a tensor:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
|
||||
>>> checkpoint = "google/vit-base-patch16-224-in21k"
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
Apply some image transformations to the images to make the model more robust against overfitting. Here you'll use torchvision's [`transforms`](https://pytorch.org/vision/stable/transforms.html) module, but you can also use any image library you like.
|
||||
|
||||
Crop a random part of the image, resize it, and normalize it with the image mean and standard deviation:
|
||||
|
||||
```py
|
||||
>>> from torchvision.transforms import RandomResizedCrop, Compose, Normalize, ToTensor
|
||||
|
||||
>>> normalize = Normalize(mean=image_processor.image_mean, std=image_processor.image_std)
|
||||
>>> size = (
|
||||
... image_processor.size["shortest_edge"]
|
||||
... if "shortest_edge" in image_processor.size
|
||||
... else (image_processor.size["height"], image_processor.size["width"])
|
||||
... )
|
||||
>>> _transforms = Compose([RandomResizedCrop(size), ToTensor(), normalize])
|
||||
```
|
||||
|
||||
Then create a preprocessing function to apply the transforms and return the `pixel_values` - the inputs to the model - of the image:
|
||||
|
||||
```py
|
||||
>>> def transforms(examples):
|
||||
... examples["pixel_values"] = [_transforms(img.convert("RGB")) for img in examples["image"]]
|
||||
... del examples["image"]
|
||||
... return examples
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.with_transform`] method. The transforms are applied on the fly when you load an element of the dataset:
|
||||
|
||||
```py
|
||||
>>> food = food.with_transform(transforms)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DefaultDataCollator`]. Unlike other data collators in 🤗 Transformers, the `DefaultDataCollator` does not apply additional preprocessing such as padding.
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load an
|
||||
evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load
|
||||
the [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the accuracy:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def compute_metrics(eval_pred):
|
||||
... predictions, labels = eval_pred
|
||||
... predictions = np.argmax(predictions, axis=1)
|
||||
... return accuracy.compute(predictions=predictions, references=labels)
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you set up your training.
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load ViT with [`AutoModelForImageClassification`]. Specify the number of labels along with the number of expected labels, and the label mappings:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForImageClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForImageClassification.from_pretrained(
|
||||
... checkpoint,
|
||||
... num_labels=len(labels),
|
||||
... id2label=id2label,
|
||||
... label2id=label2id,
|
||||
... )
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. It is important you don't remove unused columns because that'll drop the `image` column. Without the `image` column, you can't create `pixel_values`. Set `remove_unused_columns=False` to prevent this behavior! The only other required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the accuracy and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_food_model",
|
||||
... remove_unused_columns=False,
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... learning_rate=5e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... gradient_accumulation_steps=4,
|
||||
... per_device_eval_batch_size=16,
|
||||
... num_train_epochs=3,
|
||||
... warmup_ratio=0.1,
|
||||
... logging_steps=10,
|
||||
... load_best_model_at_end=True,
|
||||
... metric_for_best_model="accuracy",
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... data_collator=data_collator,
|
||||
... train_dataset=food["train"],
|
||||
... eval_dataset=food["test"],
|
||||
... processing_class=image_processor,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for image classification, take a look at the corresponding [PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've fine-tuned a model, you can use it for inference!
|
||||
|
||||
Load an image you'd like to run inference on:
|
||||
|
||||
```py
|
||||
>>> ds = load_dataset("food101", split="validation[:10]")
|
||||
>>> image = ds["image"][0]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/beignets-task-guide.png" alt="image of beignets"/>
|
||||
</div>
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for image classification with your model, and pass your image to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> classifier = pipeline("image-classification", model="my_awesome_food_model")
|
||||
>>> classifier(image)
|
||||
[{'score': 0.31856709718704224, 'label': 'beignets'},
|
||||
{'score': 0.015232225880026817, 'label': 'bruschetta'},
|
||||
{'score': 0.01519392803311348, 'label': 'chicken_wings'},
|
||||
{'score': 0.013022331520915031, 'label': 'pork_chop'},
|
||||
{'score': 0.012728818692266941, 'label': 'prime_rib'}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Load an image processor to preprocess the image and return the `input` as PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
>>> import torch
|
||||
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained("my_awesome_food_model")
|
||||
>>> inputs = image_processor(image, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the logits:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForImageClassification
|
||||
|
||||
>>> model = AutoModelForImageClassification.from_pretrained("my_awesome_food_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
Get the predicted label with the highest probability, and use the model's `id2label` mapping to convert it to a label:
|
||||
|
||||
```py
|
||||
>>> predicted_label = logits.argmax(-1).item()
|
||||
>>> model.config.id2label[predicted_label]
|
||||
'beignets'
|
||||
```
|
||||
133
transformers/docs/source/en/tasks/image_feature_extraction.md
Normal file
133
transformers/docs/source/en/tasks/image_feature_extraction.md
Normal file
@@ -0,0 +1,133 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image Feature Extraction
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Image feature extraction is the task of extracting semantically meaningful features given an image. This has many use cases, including image similarity and image retrieval. Moreover, most computer vision models can be used for image feature extraction, where one can remove the task-specific head (image classification, object detection etc) and get the features. These features are very useful on a higher level: edge detection, corner detection and so on. They may also contain information about the real world (e.g. what a cat looks like) depending on how deep the model is. Therefore, these outputs can be used to train new classifiers on a specific dataset.
|
||||
|
||||
In this guide, you will:
|
||||
|
||||
- Learn to build a simple image similarity system on top of the `image-feature-extraction` pipeline.
|
||||
- Accomplish the same task with bare model inference.
|
||||
|
||||
## Image Similarity using `image-feature-extraction` Pipeline
|
||||
|
||||
We have two images of cats sitting on top of fish nets, one of them is generated.
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
img_urls = ["https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png", "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.jpeg"]
|
||||
image_real = Image.open(requests.get(img_urls[0], stream=True).raw).convert("RGB")
|
||||
image_gen = Image.open(requests.get(img_urls[1], stream=True).raw).convert("RGB")
|
||||
```
|
||||
|
||||
Let's see the pipeline in action. First, initialize the pipeline. If you don't pass any model to it, the pipeline will be automatically initialized with [google/vit-base-patch16-224](google/vit-base-patch16-224). If you'd like to calculate similarity, set `pool` to True.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import pipeline, infer_device
|
||||
# automatically detects the underlying device type (CUDA, CPU, XPU, MPS, etc.)
|
||||
DEVICE = infer_device()
|
||||
pipe = pipeline(task="image-feature-extraction", model_name="google/vit-base-patch16-384", device=DEVICE, pool=True)
|
||||
```
|
||||
|
||||
To infer with `pipe` pass both images to it.
|
||||
|
||||
```python
|
||||
outputs = pipe([image_real, image_gen])
|
||||
```
|
||||
|
||||
The output contains pooled embeddings of those two images.
|
||||
|
||||
```python
|
||||
# get the length of a single output
|
||||
print(len(outputs[0][0]))
|
||||
# show outputs
|
||||
print(outputs)
|
||||
|
||||
# 768
|
||||
# [[[-0.03909236937761307, 0.43381670117378235, -0.06913255900144577,
|
||||
```
|
||||
|
||||
To get the similarity score, we need to pass them to a similarity function.
|
||||
|
||||
```python
|
||||
from torch.nn.functional import cosine_similarity
|
||||
|
||||
similarity_score = cosine_similarity(torch.Tensor(outputs[0]),
|
||||
torch.Tensor(outputs[1]), dim=1)
|
||||
|
||||
print(similarity_score)
|
||||
|
||||
# tensor([0.6043])
|
||||
```
|
||||
|
||||
If you want to get the last hidden states before pooling, avoid passing any value for the `pool` parameter, as it is set to `False` by default. These hidden states are useful for training new classifiers or models based on the features from the model.
|
||||
|
||||
```python
|
||||
pipe = pipeline(task="image-feature-extraction", model_name="google/vit-base-patch16-224", device=DEVICE)
|
||||
outputs = pipe(image_real)
|
||||
```
|
||||
|
||||
Since the outputs are unpooled, we get the last hidden states where the first dimension is the batch size, and the last two are the embedding shape.
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
print(np.array(outputs).shape)
|
||||
# (1, 197, 768)
|
||||
```
|
||||
|
||||
## Getting Features and Similarities using `AutoModel`
|
||||
|
||||
We can also use `AutoModel` class of transformers to get the features. `AutoModel` loads any transformers model with no task-specific head, and we can use this to get the features.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor, AutoModel
|
||||
|
||||
processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
|
||||
model = AutoModel.from_pretrained("google/vit-base-patch16-224").to(DEVICE)
|
||||
```
|
||||
|
||||
Let's write a simple function for inference. We will pass the inputs to the `processor` first and pass its outputs to the `model`.
|
||||
|
||||
```python
|
||||
def infer(image):
|
||||
inputs = processor(image, return_tensors="pt").to(DEVICE)
|
||||
outputs = model(**inputs)
|
||||
return outputs.pooler_output
|
||||
```
|
||||
|
||||
We can pass the images directly to this function and get the embeddings.
|
||||
|
||||
```python
|
||||
embed_real = infer(image_real)
|
||||
embed_gen = infer(image_gen)
|
||||
```
|
||||
|
||||
We can get the similarity again over the embeddings.
|
||||
|
||||
```python
|
||||
from torch.nn.functional import cosine_similarity
|
||||
|
||||
similarity_score = cosine_similarity(embed_real, embed_gen, dim=1)
|
||||
print(similarity_score)
|
||||
|
||||
# tensor([0.6061], device='cuda:0', grad_fn=<SumBackward1>)
|
||||
```
|
||||
312
transformers/docs/source/en/tasks/image_text_to_text.md
Normal file
312
transformers/docs/source/en/tasks/image_text_to_text.md
Normal file
@@ -0,0 +1,312 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image-text-to-text
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Image-text-to-text models, also known as vision language models (VLMs), are language models that take an image input. These models can tackle various tasks, from visual question answering to image segmentation. This task shares many similarities with image-to-text, but with some overlapping use cases like image captioning. Image-to-text models only take image inputs and often accomplish a specific task, whereas VLMs take open-ended text and image inputs and are more generalist models.
|
||||
|
||||
In this guide, we provide a brief overview of VLMs and show how to use them with Transformers for inference.
|
||||
|
||||
To begin with, there are multiple types of VLMs:
|
||||
- base models used for fine-tuning
|
||||
- chat fine-tuned models for conversation
|
||||
- instruction fine-tuned models
|
||||
|
||||
This guide focuses on inference with an instruction-tuned model.
|
||||
|
||||
Let's begin installing the dependencies.
|
||||
|
||||
```bash
|
||||
pip install -q transformers accelerate flash_attn
|
||||
```
|
||||
|
||||
Let's initialize the model and the processor.
|
||||
|
||||
```python
|
||||
from transformers import AutoProcessor, AutoModelForImageTextToText, infer_device
|
||||
import torch
|
||||
|
||||
device = torch.device(infer_device())
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"HuggingFaceM4/idefics2-8b",
|
||||
dtype=torch.bfloat16,
|
||||
attn_implementation="flash_attention_2",
|
||||
).to(device)
|
||||
|
||||
processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b")
|
||||
```
|
||||
|
||||
This model has a [chat template](./chat_templating) that helps user parse chat outputs. Moreover, the model can also accept multiple images as input in a single conversation or message. We will now prepare the inputs.
|
||||
|
||||
The image inputs look like the following.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png" alt="Two cats sitting on a net"/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg" alt="A bee on a pink flower"/>
|
||||
</div>
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
img_urls =["https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png",
|
||||
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"]
|
||||
images = [Image.open(requests.get(img_urls[0], stream=True).raw),
|
||||
Image.open(requests.get(img_urls[1], stream=True).raw)]
|
||||
```
|
||||
|
||||
Below is an example of the chat template. We can feed conversation turns and the last message as an input by appending it at the end of the template.
|
||||
|
||||
```python
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image"},
|
||||
{"type": "text", "text": "What do we see in this image?"},
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "text": "In this image we can see two cats on the nets."},
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image"},
|
||||
{"type": "text", "text": "And how about this image?"},
|
||||
]
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
We will now call the processors' [`~ProcessorMixin.apply_chat_template`] method to preprocess its output along with the image inputs.
|
||||
|
||||
```python
|
||||
prompt = processor.apply_chat_template(messages, add_generation_prompt=True)
|
||||
inputs = processor(text=prompt, images=[images[0], images[1]], return_tensors="pt").to(device)
|
||||
```
|
||||
|
||||
We can now pass the preprocessed inputs to the model.
|
||||
|
||||
```python
|
||||
with torch.no_grad():
|
||||
generated_ids = model.generate(**inputs, max_new_tokens=500)
|
||||
generated_texts = processor.batch_decode(generated_ids, skip_special_tokens=True)
|
||||
|
||||
print(generated_texts)
|
||||
## ['User: What do we see in this image? \nAssistant: In this image we can see two cats on the nets. \nUser: And how about this image? \nAssistant: In this image we can see flowers, plants and insect.']
|
||||
```
|
||||
|
||||
## Pipeline
|
||||
|
||||
The fastest way to get started is to use the [`Pipeline`] API. Specify the `"image-text-to-text"` task and the model you want to use.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
pipe = pipeline("image-text-to-text", model="llava-hf/llava-interleave-qwen-0.5b-hf")
|
||||
```
|
||||
|
||||
The example below uses chat templates to format the text inputs.
|
||||
|
||||
```python
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "image",
|
||||
"image": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg",
|
||||
},
|
||||
{"type": "text", "text": "Describe this image."},
|
||||
],
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "text", "text": "There's a pink flower"},
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Pass the chat template formatted text and image to [`Pipeline`] and set `return_full_text=False` to remove the input from the generated output.
|
||||
|
||||
```python
|
||||
outputs = pipe(text=messages, max_new_tokens=20, return_full_text=False)
|
||||
outputs[0]["generated_text"]
|
||||
# with a yellow center in the foreground. The flower is surrounded by red and white flowers with green stems
|
||||
```
|
||||
|
||||
If you prefer, you can also load the images separately and pass them to the pipeline like so:
|
||||
|
||||
```python
|
||||
pipe = pipeline("image-text-to-text", model="HuggingFaceTB/SmolVLM-256M-Instruct")
|
||||
|
||||
img_urls = [
|
||||
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png",
|
||||
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg",
|
||||
]
|
||||
images = [
|
||||
Image.open(requests.get(img_urls[0], stream=True).raw),
|
||||
Image.open(requests.get(img_urls[1], stream=True).raw),
|
||||
]
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image"},
|
||||
{"type": "image"},
|
||||
{"type": "text", "text": "What do you see in these images?"},
|
||||
],
|
||||
}
|
||||
]
|
||||
outputs = pipe(text=messages, images=images, max_new_tokens=50, return_full_text=False)
|
||||
outputs[0]["generated_text"]
|
||||
" In the first image, there are two cats sitting on a plant. In the second image, there are flowers with a pinkish hue."
|
||||
```
|
||||
|
||||
The images will still be included in the `"input_text"` field of the output:
|
||||
|
||||
```python
|
||||
outputs[0]['input_text']
|
||||
"""
|
||||
[{'role': 'user',
|
||||
'content': [{'type': 'image',
|
||||
'image': <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=622x412>},
|
||||
{'type': 'image',
|
||||
'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=5184x3456>},
|
||||
{'type': 'text', 'text': 'What do you see in these images?'}]}]## Streaming
|
||||
"""
|
||||
```
|
||||
|
||||
We can use [text streaming](./generation_strategies#streaming) for a better generation experience. Transformers supports streaming with the [`TextStreamer`] or [`TextIteratorStreamer`] classes. We will use the [`TextIteratorStreamer`] with IDEFICS-8B.
|
||||
|
||||
Assume we have an application that keeps chat history and takes in the new user input. We will preprocess the inputs as usual and initialize [`TextIteratorStreamer`] to handle the generation in a separate thread. This allows you to stream the generated text tokens in real-time. Any generation arguments can be passed to [`TextIteratorStreamer`].
|
||||
|
||||
```python
|
||||
import time
|
||||
from transformers import TextIteratorStreamer
|
||||
from threading import Thread
|
||||
|
||||
def model_inference(
|
||||
user_prompt,
|
||||
chat_history,
|
||||
max_new_tokens,
|
||||
images
|
||||
):
|
||||
user_prompt = {
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image"},
|
||||
{"type": "text", "text": user_prompt},
|
||||
]
|
||||
}
|
||||
chat_history.append(user_prompt)
|
||||
streamer = TextIteratorStreamer(
|
||||
processor.tokenizer,
|
||||
skip_prompt=True,
|
||||
timeout=5.0,
|
||||
)
|
||||
|
||||
generation_args = {
|
||||
"max_new_tokens": max_new_tokens,
|
||||
"streamer": streamer,
|
||||
"do_sample": False
|
||||
}
|
||||
|
||||
# add_generation_prompt=True makes model generate bot response
|
||||
prompt = processor.apply_chat_template(chat_history, add_generation_prompt=True)
|
||||
inputs = processor(
|
||||
text=prompt,
|
||||
images=images,
|
||||
return_tensors="pt",
|
||||
).to(device)
|
||||
generation_args.update(inputs)
|
||||
|
||||
thread = Thread(
|
||||
target=model.generate,
|
||||
kwargs=generation_args,
|
||||
)
|
||||
thread.start()
|
||||
|
||||
acc_text = ""
|
||||
for text_token in streamer:
|
||||
time.sleep(0.04)
|
||||
acc_text += text_token
|
||||
if acc_text.endswith("<end_of_utterance>"):
|
||||
acc_text = acc_text[:-18]
|
||||
yield acc_text
|
||||
|
||||
thread.join()
|
||||
```
|
||||
|
||||
Now let's call the `model_inference` function we created and stream the values.
|
||||
|
||||
```python
|
||||
generator = model_inference(
|
||||
user_prompt="And what is in this image?",
|
||||
chat_history=messages[:2],
|
||||
max_new_tokens=100,
|
||||
images=images
|
||||
)
|
||||
|
||||
for value in generator:
|
||||
print(value)
|
||||
|
||||
# In
|
||||
# In this
|
||||
# In this image ...
|
||||
```
|
||||
|
||||
## Fit models in smaller hardware
|
||||
|
||||
VLMs are often large and need to be optimized to fit on smaller hardware. Transformers supports many model quantization libraries, and here we will only show int8 quantization with [Quanto](./quantization/quanto#quanto). int8 quantization offers memory improvements up to 75 percent (if all weights are quantized). However it is no free lunch, since 8-bit is not a CUDA-native precision, the weights are quantized back and forth on the fly, which adds up to latency.
|
||||
|
||||
First, install dependencies.
|
||||
|
||||
```bash
|
||||
pip install -U quanto bitsandbytes
|
||||
```
|
||||
|
||||
To quantize a model during loading, we need to first create [`QuantoConfig`]. Then load the model as usual, but pass `quantization_config` during model initialization.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageTextToText, QuantoConfig
|
||||
|
||||
model_id = "HuggingFaceM4/idefics2-8b"
|
||||
quantization_config = QuantoConfig(weights="int8")
|
||||
quantized_model = AutoModelForImageTextToText.from_pretrained(
|
||||
model_id, device_map="auto", quantization_config=quantization_config
|
||||
)
|
||||
```
|
||||
|
||||
And that's it, we can use the model the same way with no changes.
|
||||
|
||||
## Further Reading
|
||||
|
||||
Here are some more resources for the image-text-to-text task.
|
||||
|
||||
- [Image-text-to-text task page](https://huggingface.co/tasks/image-text-to-text) covers model types, use cases, datasets, and more.
|
||||
- [Vision Language Models Explained](https://huggingface.co/blog/vlms) is a blog post that covers everything about vision language models and supervised fine-tuning using [TRL](https://huggingface.co/docs/trl/en/index).
|
||||
139
transformers/docs/source/en/tasks/image_to_image.md
Normal file
139
transformers/docs/source/en/tasks/image_to_image.md
Normal file
@@ -0,0 +1,139 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image-to-Image Task Guide
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Image-to-Image task is the task where an application receives an image and outputs another image. This has various subtasks, including image enhancement (super resolution, low light enhancement, deraining and so on), image inpainting, and more.
|
||||
|
||||
This guide will show you how to:
|
||||
- Use an image-to-image pipeline for super resolution task,
|
||||
- Run image-to-image models for same task without a pipeline.
|
||||
|
||||
Note that as of the time this guide is released, `image-to-image` pipeline only supports super resolution task.
|
||||
|
||||
Let's begin by installing the necessary libraries.
|
||||
|
||||
```bash
|
||||
pip install transformers
|
||||
```
|
||||
|
||||
We can now initialize the pipeline with a [Swin2SR model](https://huggingface.co/caidas/swin2SR-lightweight-x2-64). We can then infer with the pipeline by calling it with an image. As of now, only [Swin2SR models](https://huggingface.co/models?sort=trending&search=swin2sr) are supported in this pipeline.
|
||||
|
||||
```python
|
||||
from transformers import pipeline, infer_device
|
||||
import torch
|
||||
# automatically detects the underlying device type (CUDA, CPU, XPU, MPS, etc.)
|
||||
device = infer_device()
|
||||
pipe = pipeline(task="image-to-image", model="caidas/swin2SR-lightweight-x2-64", device=device)
|
||||
```
|
||||
|
||||
Now, let's load an image.
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/cat.jpg"
|
||||
image = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
print(image.size)
|
||||
```
|
||||
|
||||
```bash
|
||||
# (532, 432)
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/cat.jpg" alt="Photo of a cat"/>
|
||||
</div>
|
||||
|
||||
We can now do inference with the pipeline. We will get an upscaled version of the cat image.
|
||||
|
||||
```python
|
||||
upscaled = pipe(image)
|
||||
print(upscaled.size)
|
||||
```
|
||||
|
||||
```bash
|
||||
# (1072, 880)
|
||||
```
|
||||
|
||||
If you wish to do inference yourself with no pipeline, you can use the `Swin2SRForImageSuperResolution` and `Swin2SRImageProcessor` classes of transformers. We will use the same model checkpoint for this. Let's initialize the model and the processor.
|
||||
|
||||
```python
|
||||
from transformers import Swin2SRForImageSuperResolution, Swin2SRImageProcessor
|
||||
|
||||
model = Swin2SRForImageSuperResolution.from_pretrained("caidas/swin2SR-lightweight-x2-64").to(device)
|
||||
processor = Swin2SRImageProcessor("caidas/swin2SR-lightweight-x2-64")
|
||||
```
|
||||
|
||||
`pipeline` abstracts away the preprocessing and postprocessing steps that we have to do ourselves, so let's preprocess the image. We will pass the image to the processor and then move the pixel values to GPU.
|
||||
|
||||
```python
|
||||
pixel_values = processor(image, return_tensors="pt").pixel_values
|
||||
print(pixel_values.shape)
|
||||
|
||||
pixel_values = pixel_values.to(device)
|
||||
```
|
||||
|
||||
We can now infer the image by passing pixel values to the model.
|
||||
|
||||
```python
|
||||
import torch
|
||||
|
||||
with torch.no_grad():
|
||||
outputs = model(pixel_values)
|
||||
```
|
||||
|
||||
Output is an object of type `ImageSuperResolutionOutput` that looks like below 👇
|
||||
|
||||
```text
|
||||
(loss=None, reconstruction=tensor([[[[0.8270, 0.8269, 0.8275, ..., 0.7463, 0.7446, 0.7453],
|
||||
[0.8287, 0.8278, 0.8283, ..., 0.7451, 0.7448, 0.7457],
|
||||
[0.8280, 0.8273, 0.8269, ..., 0.7447, 0.7446, 0.7452],
|
||||
...,
|
||||
[0.5923, 0.5933, 0.5924, ..., 0.0697, 0.0695, 0.0706],
|
||||
[0.5926, 0.5932, 0.5926, ..., 0.0673, 0.0687, 0.0705],
|
||||
[0.5927, 0.5914, 0.5922, ..., 0.0664, 0.0694, 0.0718]]]],
|
||||
device='cuda:0'), hidden_states=None, attentions=None)
|
||||
```
|
||||
|
||||
We need to get the `reconstruction` and post-process it for visualization. Let's see how it looks like.
|
||||
|
||||
```python
|
||||
outputs.reconstruction.data.shape
|
||||
# torch.Size([1, 3, 880, 1072])
|
||||
```
|
||||
|
||||
We need to squeeze the output and get rid of axis 0, clip the values, then convert it to be numpy float. Then we will arrange axes to have the shape [1072, 880], and finally, bring the output back to range [0, 255].
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# squeeze, take to CPU and clip the values
|
||||
output = outputs.reconstruction.data.squeeze().cpu().clamp_(0, 1).numpy()
|
||||
# rearrange the axes
|
||||
output = np.moveaxis(output, source=0, destination=-1)
|
||||
# bring values back to pixel values range
|
||||
output = (output * 255.0).round().astype(np.uint8)
|
||||
Image.fromarray(output)
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/cat_upscaled.png" alt="Upscaled photo of a cat"/>
|
||||
</div>
|
||||
152
transformers/docs/source/en/tasks/keypoint_detection.md
Normal file
152
transformers/docs/source/en/tasks/keypoint_detection.md
Normal file
@@ -0,0 +1,152 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Keypoint Detection
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Keypoint detection identifies and locates specific points of interest within an image. These keypoints, also known as landmarks, represent meaningful features of objects, such as facial features or object parts. These models take an image input and return the following outputs:
|
||||
|
||||
- **Keypoints and Scores**: Points of interest and their confidence scores.
|
||||
- **Descriptors**: A representation of the image region surrounding each keypoint, capturing its texture, gradient, orientation and other properties.
|
||||
|
||||
In this guide, we will show how to extract keypoints from images.
|
||||
|
||||
For this tutorial, we will use [SuperPoint](./model_doc/superpoint), a foundation model for keypoint detection.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor, SuperPointForKeypointDetection
|
||||
processor = AutoImageProcessor.from_pretrained("magic-leap-community/superpoint")
|
||||
model = SuperPointForKeypointDetection.from_pretrained("magic-leap-community/superpoint")
|
||||
```
|
||||
|
||||
Let's test the model on the images below.
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
alt="Bee"
|
||||
style="height: 200px; object-fit: contain; margin-right: 10px;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png"
|
||||
alt="Cats"
|
||||
style="height: 200px; object-fit: contain;">
|
||||
</div>
|
||||
|
||||
```python
|
||||
import torch
|
||||
from PIL import Image
|
||||
import requests
|
||||
import cv2
|
||||
|
||||
|
||||
url_image_1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
image_1 = Image.open(requests.get(url_image_1, stream=True).raw)
|
||||
url_image_2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png"
|
||||
image_2 = Image.open(requests.get(url_image_2, stream=True).raw)
|
||||
|
||||
images = [image_1, image_2]
|
||||
```
|
||||
|
||||
We can now process our inputs and infer.
|
||||
|
||||
```python
|
||||
inputs = processor(images,return_tensors="pt").to(model.device, model.dtype)
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
|
||||
The model output has relative keypoints, descriptors, masks and scores for each item in the batch. The mask highlights areas of the image where keypoints are present.
|
||||
|
||||
```python
|
||||
SuperPointKeypointDescriptionOutput(loss=None, keypoints=tensor([[[0.0437, 0.0167],
|
||||
[0.0688, 0.0167],
|
||||
[0.0172, 0.0188],
|
||||
...,
|
||||
[0.5984, 0.9812],
|
||||
[0.6953, 0.9812]]]),
|
||||
scores=tensor([[0.0056, 0.0053, 0.0079, ..., 0.0125, 0.0539, 0.0377],
|
||||
[0.0206, 0.0058, 0.0065, ..., 0.0000, 0.0000, 0.0000]],
|
||||
grad_fn=<CopySlices>), descriptors=tensor([[[-0.0807, 0.0114, -0.1210, ..., -0.1122, 0.0899, 0.0357],
|
||||
[-0.0807, 0.0114, -0.1210, ..., -0.1122, 0.0899, 0.0357],
|
||||
[-0.0807, 0.0114, -0.1210, ..., -0.1122, 0.0899, 0.0357],
|
||||
...],
|
||||
grad_fn=<CopySlices>), mask=tensor([[1, 1, 1, ..., 1, 1, 1],
|
||||
[1, 1, 1, ..., 0, 0, 0]], dtype=torch.int32), hidden_states=None)
|
||||
```
|
||||
|
||||
To plot actual keypoints in the image, we need to postprocess the output. To do so, we have to pass the actual image sizes to `post_process_keypoint_detection` along with outputs.
|
||||
|
||||
```python
|
||||
image_sizes = [(image.size[1], image.size[0]) for image in images]
|
||||
outputs = processor.post_process_keypoint_detection(outputs, image_sizes)
|
||||
```
|
||||
|
||||
The outputs are now a list of dictionaries where each dictionary is a processed output of keypoints, scores and descriptors.
|
||||
|
||||
```python
|
||||
[{'keypoints': tensor([[ 226, 57],
|
||||
[ 356, 57],
|
||||
[ 89, 64],
|
||||
...,
|
||||
[3604, 3391]], dtype=torch.int32),
|
||||
'scores': tensor([0.0056, 0.0053, ...], grad_fn=<IndexBackward0>),
|
||||
'descriptors': tensor([[-0.0807, 0.0114, -0.1210, ..., -0.1122, 0.0899, 0.0357],
|
||||
[-0.0807, 0.0114, -0.1210, ..., -0.1122, 0.0899, 0.0357]],
|
||||
grad_fn=<IndexBackward0>)},
|
||||
{'keypoints': tensor([[ 46, 6],
|
||||
[ 78, 6],
|
||||
[422, 6],
|
||||
[206, 404]], dtype=torch.int32),
|
||||
'scores': tensor([0.0206, 0.0058, 0.0065, 0.0053, 0.0070, ...,grad_fn=<IndexBackward0>),
|
||||
'descriptors': tensor([[-0.0525, 0.0726, 0.0270, ..., 0.0389, -0.0189, -0.0211],
|
||||
[-0.0525, 0.0726, 0.0270, ..., 0.0389, -0.0189, -0.0211]}]
|
||||
```
|
||||
|
||||
We can use these to plot the keypoints.
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import torch
|
||||
|
||||
for i in range(len(images)):
|
||||
keypoints = outputs[i]["keypoints"]
|
||||
scores = outputs[i]["scores"]
|
||||
descriptors = outputs[i]["descriptors"]
|
||||
keypoints = outputs[i]["keypoints"].detach().numpy()
|
||||
scores = outputs[i]["scores"].detach().numpy()
|
||||
image = images[i]
|
||||
image_width, image_height = image.size
|
||||
|
||||
plt.axis('off')
|
||||
plt.imshow(image)
|
||||
plt.scatter(
|
||||
keypoints[:, 0],
|
||||
keypoints[:, 1],
|
||||
s=scores * 100,
|
||||
c='cyan',
|
||||
alpha=0.4
|
||||
)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
Below you can see the outputs.
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee_keypoint.png"
|
||||
alt="Bee"
|
||||
style="height: 200px; object-fit: contain; margin-right: 10px;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats_keypoint.png"
|
||||
alt="Cats"
|
||||
style="height: 200px; object-fit: contain;">
|
||||
</div>
|
||||
129
transformers/docs/source/en/tasks/keypoint_matching.md
Normal file
129
transformers/docs/source/en/tasks/keypoint_matching.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Keypoint matching
|
||||
|
||||
Keypoint matching matches different points of interests that belong to same object appearing in two different images. Most modern keypoint matchers take images as input and output the following:
|
||||
|
||||
- **Keypoint coordinates (x,y):** one-to-one mapping of pixel coordinates between the first and the second image using two lists. Each keypoint at a given index in the first list is matched to the keypoint at the same index in the second list.
|
||||
- **Matching scores:** Scores assigned to the keypoint matches.
|
||||
|
||||
In this tutorial, you will extract keypoint matches with the [`EfficientLoFTR`] model trained with the [MatchAnything framework](https://huggingface.co/zju-community/matchanything_eloftr), and refine the matches. This model is only 16M parameters and can be run on a CPU. You will use the [`AutoModelForKeypointMatching`] class.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor, AutoModelForKeypointMatching
|
||||
import torch
|
||||
|
||||
processor = AutoImageProcessor.from_pretrained("zju-community/matchanything_eloftr")
|
||||
model = AutoModelForKeypointMatching.from_pretrained("zju-community/matchanything_eloftr"))
|
||||
```
|
||||
|
||||
Load two images that have the same object of interest. The second photo is taken a second apart, it's colors are edited, and it is further cropped and rotated.
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
alt="Bee"
|
||||
style="height: 200px; object-fit: contain; margin-right: 10px;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee_edited.jpg"
|
||||
alt="Bee edited"
|
||||
style="height: 200px; object-fit: contain;">
|
||||
</div>
|
||||
|
||||
```python
|
||||
from transformers.image_utils import load_image
|
||||
image1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg")
|
||||
image2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee_edited.jpg")
|
||||
|
||||
images = [image1, image2]
|
||||
```
|
||||
|
||||
We can pass the images to the processor and infer.
|
||||
|
||||
```python
|
||||
inputs = processor(images, return_tensors="pt")
|
||||
with torch.no_grad():
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
|
||||
We can postprocess the outputs. The threshold parameter is used to refine noise (lower confidence thresholds) in the output matches.
|
||||
|
||||
```python
|
||||
image_sizes = [[(image.height, image.width) for image in images]]
|
||||
|
||||
outputs = processor.post_process_keypoint_matching(outputs, image_sizes, threshold=0.2)
|
||||
print(outputs)
|
||||
```
|
||||
|
||||
Here's the outputs.
|
||||
|
||||
```text
|
||||
[{'keypoints0': tensor([[4514, 550],
|
||||
[4813, 683],
|
||||
[1972, 1547],
|
||||
...
|
||||
[3916, 3408]], dtype=torch.int32),
|
||||
'keypoints1': tensor([[2280, 463],
|
||||
[2378, 613],
|
||||
[2231, 887],
|
||||
...
|
||||
[1521, 2560]], dtype=torch.int32),
|
||||
'matching_scores': tensor([0.2189, 0.2073, 0.2414, ...
|
||||
])}]
|
||||
```
|
||||
|
||||
We have trimmed the output but there's 401 matches!
|
||||
|
||||
```python
|
||||
len(outputs[0]["keypoints0"])
|
||||
# 401
|
||||
```
|
||||
|
||||
We can visualize them using the processor's [`~EfficientLoFTRImageProcessor.visualize_keypoint_matching`] method.
|
||||
|
||||
```python
|
||||
plot_images = processor.visualize_keypoint_matching(images, outputs)
|
||||
plot_images
|
||||
```
|
||||
|
||||

|
||||
|
||||
Optionally, you can use the [`Pipeline`] API and set the task to `keypoint-matching`.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
image_1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
image_2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee_edited.jpg"
|
||||
|
||||
pipe = pipeline("keypoint-matching", model="zju-community/matchanything_eloftr")
|
||||
pipe([image_1, image_2])
|
||||
```
|
||||
|
||||
The output looks like following.
|
||||
|
||||
```bash
|
||||
[{'keypoint_image_0': {'x': 2444, 'y': 2869},
|
||||
'keypoint_image_1': {'x': 837, 'y': 1500},
|
||||
'score': 0.9756593704223633},
|
||||
{'keypoint_image_0': {'x': 1248, 'y': 2819},
|
||||
'keypoint_image_1': {'x': 862, 'y': 866},
|
||||
'score': 0.9735618829727173},
|
||||
{'keypoint_image_0': {'x': 1547, 'y': 3317},
|
||||
'keypoint_image_1': {'x': 1436, 'y': 1500},
|
||||
...
|
||||
}
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,184 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
# Knowledge Distillation for Computer Vision
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Knowledge distillation is a technique used to transfer knowledge from a larger, more complex model (teacher) to a smaller, simpler model (student). To distill knowledge from one model to another, we take a pre-trained teacher model trained on a certain task (image classification for this case) and randomly initialize a student model to be trained on image classification. Next, we train the student model to minimize the difference between its outputs and the teacher's outputs, thus making it mimic the behavior. It was first introduced in [Distilling the Knowledge in a Neural Network by Hinton et al](https://huggingface.co/papers/1503.02531). In this guide, we will do task-specific knowledge distillation. We will use the [beans dataset](https://huggingface.co/datasets/beans) for this.
|
||||
|
||||
This guide demonstrates how you can distill a [fine-tuned ViT model](https://huggingface.co/merve/vit-mobilenet-beans-224) (teacher model) to a [MobileNet](https://huggingface.co/google/mobilenet_v2_1.4_224) (student model) using the [Trainer API](https://huggingface.co/docs/transformers/en/main_classes/trainer#trainer) of 🤗 Transformers.
|
||||
|
||||
Let's install the libraries needed for distillation and evaluating the process.
|
||||
|
||||
```bash
|
||||
pip install transformers datasets accelerate tensorboard evaluate --upgrade
|
||||
```
|
||||
|
||||
In this example, we are using the `merve/beans-vit-224` model as teacher model. It's an image classification model, based on `google/vit-base-patch16-224-in21k` fine-tuned on beans dataset. We will distill this model to a randomly initialized MobileNetV2.
|
||||
|
||||
We will now load the dataset.
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
dataset = load_dataset("beans")
|
||||
```
|
||||
|
||||
We can use an image processor from either of the models, as in this case they return the same output with same resolution. We will use the `map()` method of `dataset` to apply the preprocessing to every split of the dataset.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor
|
||||
teacher_processor = AutoImageProcessor.from_pretrained("merve/beans-vit-224")
|
||||
|
||||
def process(examples):
|
||||
processed_inputs = teacher_processor(examples["image"])
|
||||
return processed_inputs
|
||||
|
||||
processed_datasets = dataset.map(process, batched=True)
|
||||
```
|
||||
|
||||
Essentially, we want the student model (a randomly initialized MobileNet) to mimic the teacher model (fine-tuned vision transformer). To achieve this, we first get the logits output from the teacher and the student. Then, we divide each of them by the parameter `temperature` which controls the importance of each soft target. A parameter called `lambda` weighs the importance of the distillation loss. In this example, we will use `temperature=5` and `lambda=0.5`. We will use the Kullback-Leibler Divergence loss to compute the divergence between the student and teacher. Given two data P and Q, KL Divergence explains how much extra information we need to represent P using Q. If two are identical, their KL divergence is zero, as there's no other information needed to explain P from Q. Thus, in the context of knowledge distillation, KL divergence is useful.
|
||||
|
||||
```python
|
||||
from transformers import TrainingArguments, Trainer, infer_device
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
class ImageDistilTrainer(Trainer):
|
||||
def __init__(self, teacher_model=None, student_model=None, temperature=None, lambda_param=None, *args, **kwargs):
|
||||
super().__init__(model=student_model, *args, **kwargs)
|
||||
self.teacher = teacher_model
|
||||
self.student = student_model
|
||||
self.loss_function = nn.KLDivLoss(reduction="batchmean")
|
||||
device = infer_device()
|
||||
self.teacher.to(device)
|
||||
self.teacher.eval()
|
||||
self.temperature = temperature
|
||||
self.lambda_param = lambda_param
|
||||
|
||||
def compute_loss(self, student, inputs, return_outputs=False):
|
||||
student_output = self.student(**inputs)
|
||||
|
||||
with torch.no_grad():
|
||||
teacher_output = self.teacher(**inputs)
|
||||
|
||||
# Compute soft targets for teacher and student
|
||||
soft_teacher = F.softmax(teacher_output.logits / self.temperature, dim=-1)
|
||||
soft_student = F.log_softmax(student_output.logits / self.temperature, dim=-1)
|
||||
|
||||
# Compute the loss
|
||||
distillation_loss = self.loss_function(soft_student, soft_teacher) * (self.temperature ** 2)
|
||||
|
||||
# Compute the true label loss
|
||||
student_target_loss = student_output.loss
|
||||
|
||||
# Calculate final loss
|
||||
loss = (1. - self.lambda_param) * student_target_loss + self.lambda_param * distillation_loss
|
||||
return (loss, student_output) if return_outputs else loss
|
||||
```
|
||||
|
||||
We will now login to Hugging Face Hub so we can push our model to the Hugging Face Hub through the `Trainer`.
|
||||
|
||||
```python
|
||||
from huggingface_hub import notebook_login
|
||||
|
||||
notebook_login()
|
||||
```
|
||||
|
||||
Let's set the `TrainingArguments`, the teacher model and the student model.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageClassification, MobileNetV2Config, MobileNetV2ForImageClassification
|
||||
|
||||
training_args = TrainingArguments(
|
||||
output_dir="my-awesome-model",
|
||||
num_train_epochs=30,
|
||||
fp16=True,
|
||||
logging_dir=f"{repo_name}/logs",
|
||||
logging_strategy="epoch",
|
||||
eval_strategy="epoch",
|
||||
save_strategy="epoch",
|
||||
load_best_model_at_end=True,
|
||||
metric_for_best_model="accuracy",
|
||||
report_to="tensorboard",
|
||||
push_to_hub=True,
|
||||
hub_strategy="every_save",
|
||||
hub_model_id=repo_name,
|
||||
)
|
||||
|
||||
num_labels = len(processed_datasets["train"].features["labels"].names)
|
||||
|
||||
# initialize models
|
||||
teacher_model = AutoModelForImageClassification.from_pretrained(
|
||||
"merve/beans-vit-224",
|
||||
num_labels=num_labels,
|
||||
ignore_mismatched_sizes=True
|
||||
)
|
||||
|
||||
# training MobileNetV2 from scratch
|
||||
student_config = MobileNetV2Config()
|
||||
student_config.num_labels = num_labels
|
||||
student_model = MobileNetV2ForImageClassification(student_config)
|
||||
```
|
||||
|
||||
We can use `compute_metrics` function to evaluate our model on the test set. This function will be used during the training process to compute the `accuracy` & `f1` of our model.
|
||||
|
||||
```python
|
||||
import evaluate
|
||||
import numpy as np
|
||||
|
||||
accuracy = evaluate.load("accuracy")
|
||||
|
||||
def compute_metrics(eval_pred):
|
||||
predictions, labels = eval_pred
|
||||
acc = accuracy.compute(references=labels, predictions=np.argmax(predictions, axis=1))
|
||||
return {"accuracy": acc["accuracy"]}
|
||||
```
|
||||
|
||||
Let's initialize the `Trainer` with the training arguments we defined. We will also initialize our data collator.
|
||||
|
||||
```python
|
||||
from transformers import DefaultDataCollator
|
||||
|
||||
data_collator = DefaultDataCollator()
|
||||
trainer = ImageDistilTrainer(
|
||||
student_model=student_model,
|
||||
teacher_model=teacher_model,
|
||||
training_args=training_args,
|
||||
train_dataset=processed_datasets["train"],
|
||||
eval_dataset=processed_datasets["validation"],
|
||||
data_collator=data_collator,
|
||||
processing_class=teacher_processor,
|
||||
compute_metrics=compute_metrics,
|
||||
temperature=5,
|
||||
lambda_param=0.5
|
||||
)
|
||||
```
|
||||
|
||||
We can now train our model.
|
||||
|
||||
```python
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
We can evaluate the model on the test set.
|
||||
|
||||
```python
|
||||
trainer.evaluate(processed_datasets["test"])
|
||||
```
|
||||
|
||||
On test set, our model reaches 72 percent accuracy. To have a sanity check over efficiency of distillation, we also trained MobileNet on the beans dataset from scratch with the same hyperparameters and observed 63 percent accuracy on the test set. We invite the readers to try different pre-trained teacher models, student architectures, distillation parameters and report their findings. The training logs and checkpoints for distilled model can be found in [this repository](https://huggingface.co/merve/vit-mobilenet-beans-224), and MobileNetV2 trained from scratch can be found in this [repository](https://huggingface.co/merve/resnet-mobilenet-beans-5).
|
||||
311
transformers/docs/source/en/tasks/language_modeling.md
Normal file
311
transformers/docs/source/en/tasks/language_modeling.md
Normal file
@@ -0,0 +1,311 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Causal language modeling
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
There are two types of language modeling, causal and masked. This guide illustrates causal language modeling.
|
||||
Causal language models are frequently used for text generation. You can use these models for creative applications like
|
||||
choosing your own text adventure or an intelligent coding assistant like Copilot or CodeParrot.
|
||||
|
||||
<Youtube id="Vpjb1lu0MDk"/>
|
||||
|
||||
Causal language modeling predicts the next token in a sequence of tokens, and the model can only attend to tokens on
|
||||
the left. This means the model cannot see future tokens. GPT-2 is an example of a causal language model.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [DistilGPT2](https://huggingface.co/distilbert/distilgpt2) on the [r/askscience](https://www.reddit.com/r/askscience/) subset of the [ELI5](https://huggingface.co/datasets/dany0407/eli5_category) dataset.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/text-generation)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
We encourage you to log in to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load ELI5 dataset
|
||||
|
||||
Start by loading the first 5000 examples from the [ELI5-Category](https://huggingface.co/datasets/dany0407/eli5_category) dataset with the 🤗 Datasets library. This'll give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> eli5 = load_dataset("dany0407/eli5_category", split="train[:5000]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> eli5["train"][0]
|
||||
{'q_id': '7h191n',
|
||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
||||
'selftext': '',
|
||||
'category': 'Economics',
|
||||
'subreddit': 'explainlikeimfive',
|
||||
'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
||||
'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
||||
'score': [21, 19, 5, 3],
|
||||
'text_urls': [[],
|
||||
[],
|
||||
[],
|
||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
|
||||
'title_urls': ['url'],
|
||||
'selftext_urls': ['url']}
|
||||
```
|
||||
|
||||
While this may look like a lot, you're only really interested in the `text` field. What's cool about language modeling
|
||||
tasks is you don't need labels (also known as an unsupervised task) because the next word *is* the label.
|
||||
|
||||
## Preprocess
|
||||
|
||||
<Youtube id="ma1TrR7gE7I"/>
|
||||
|
||||
The next step is to load a DistilGPT2 tokenizer to process the `text` subfield:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilgpt2")
|
||||
```
|
||||
|
||||
You'll notice from the example above, the `text` field is actually nested inside `answers`. This means you'll need to
|
||||
extract the `text` subfield from its nested structure with the [`flatten`](https://huggingface.co/docs/datasets/process#flatten) method:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.flatten()
|
||||
>>> eli5["train"][0]
|
||||
{'q_id': '7h191n',
|
||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
||||
'selftext': '',
|
||||
'category': 'Economics',
|
||||
'subreddit': 'explainlikeimfive',
|
||||
'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
||||
'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
||||
'answers.score': [21, 19, 5, 3],
|
||||
'answers.text_urls': [[],
|
||||
[],
|
||||
[],
|
||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
|
||||
'title_urls': ['url'],
|
||||
'selftext_urls': ['url']}
|
||||
```
|
||||
|
||||
Each subfield is now a separate column as indicated by the `answers` prefix, and the `text` field is a list now. Instead
|
||||
of tokenizing each sentence separately, convert the list to a string so you can jointly tokenize them.
|
||||
|
||||
Here is a first preprocessing function to join the list of strings for each example and tokenize the result:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
||||
```
|
||||
|
||||
To apply this preprocessing function over the entire dataset, use the 🤗 Datasets [`~datasets.Dataset.map`] method. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once, and increasing the number of processes with `num_proc`. Remove any columns you don't need:
|
||||
|
||||
```py
|
||||
>>> tokenized_eli5 = eli5.map(
|
||||
... preprocess_function,
|
||||
... batched=True,
|
||||
... num_proc=4,
|
||||
... remove_columns=eli5["train"].column_names,
|
||||
... )
|
||||
```
|
||||
|
||||
This dataset contains the token sequences, but some of these are longer than the maximum input length for the model.
|
||||
|
||||
You can now use a second preprocessing function to
|
||||
|
||||
- concatenate all the sequences
|
||||
- split the concatenated sequences into shorter chunks defined by `block_size`, which should be both shorter than the maximum input length and short enough for your GPU RAM.
|
||||
|
||||
```py
|
||||
>>> block_size = 128
|
||||
|
||||
|
||||
>>> def group_texts(examples):
|
||||
... # Concatenate all texts.
|
||||
... concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
|
||||
... total_length = len(concatenated_examples[list(examples.keys())[0]])
|
||||
... # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can
|
||||
... # customize this part to your needs.
|
||||
... if total_length >= block_size:
|
||||
... total_length = (total_length // block_size) * block_size
|
||||
... # Split by chunks of block_size.
|
||||
... result = {
|
||||
... k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
|
||||
... for k, t in concatenated_examples.items()
|
||||
... }
|
||||
... result["labels"] = result["input_ids"].copy()
|
||||
... return result
|
||||
```
|
||||
|
||||
Apply the `group_texts` function over the entire dataset:
|
||||
|
||||
```py
|
||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DataCollatorForLanguageModeling`]. It's more efficient to *dynamically pad* the
|
||||
sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length.
|
||||
|
||||
Use the end-of-sequence token as the padding token and set `mlm=False`. This will use the inputs as labels shifted to the right by one element:
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForLanguageModeling
|
||||
|
||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
||||
```
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the [basic tutorial](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load DistilGPT2 with [`AutoModelForCausalLM`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCausalLM, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model).
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, datasets, and data collator.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_eli5_clm-model",
|
||||
... eval_strategy="epoch",
|
||||
... learning_rate=2e-5,
|
||||
... weight_decay=0.01,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=lm_dataset["train"],
|
||||
... eval_dataset=lm_dataset["test"],
|
||||
... data_collator=data_collator,
|
||||
... tokenizer=tokenizer,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, use the [`~transformers.Trainer.evaluate`] method to evaluate your model and get its perplexity:
|
||||
|
||||
```py
|
||||
>>> import math
|
||||
|
||||
>>> eval_results = trainer.evaluate()
|
||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
||||
Perplexity: 49.61
|
||||
```
|
||||
|
||||
Then share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for causal language modeling, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Come up with a prompt you'd like to generate text from:
|
||||
|
||||
```py
|
||||
>>> prompt = "Somatic hypermutation allows the immune system to"
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for text generation with your model, and pass your text to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> generator = pipeline("text-generation", model="username/my_awesome_eli5_clm-model")
|
||||
>>> generator(prompt)
|
||||
[{'generated_text': "Somatic hypermutation allows the immune system to be able to effectively reverse the damage caused by an infection.\n\n\nThe damage caused by an infection is caused by the immune system's ability to perform its own self-correcting tasks."}]
|
||||
```
|
||||
|
||||
Tokenize the text and return the `input_ids` as PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_clm-model")
|
||||
>>> inputs = tokenizer(prompt, return_tensors="pt").input_ids
|
||||
```
|
||||
|
||||
Use the [`~generation.GenerationMixin.generate`] method to generate text.
|
||||
For more details about the different text generation strategies and parameters for controlling generation, check out the [Text generation strategies](../generation_strategies) page.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCausalLM
|
||||
|
||||
>>> model = AutoModelForCausalLM.from_pretrained("username/my_awesome_eli5_clm-model")
|
||||
>>> outputs = model.generate(inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)
|
||||
```
|
||||
|
||||
Decode the generated token ids back into text:
|
||||
|
||||
```py
|
||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
["Somatic hypermutation allows the immune system to react to drugs with the ability to adapt to a different environmental situation. In other words, a system of 'hypermutation' can help the immune system to adapt to a different environmental situation or in some cases even a single life. In contrast, researchers at the University of Massachusetts-Boston have found that 'hypermutation' is much stronger in mice than in humans but can be found in humans, and that it's not completely unknown to the immune system. A study on how the immune system"]
|
||||
```
|
||||
234
transformers/docs/source/en/tasks/mask_generation.md
Normal file
234
transformers/docs/source/en/tasks/mask_generation.md
Normal file
@@ -0,0 +1,234 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Mask Generation
|
||||
|
||||
Mask generation is the task of generating semantically meaningful masks for an image.
|
||||
This task is very similar to [image segmentation](semantic_segmentation), but many differences exist. Image segmentation models are trained on labeled datasets and are limited to the classes they have seen during training; they return a set of masks and corresponding classes, given an image.
|
||||
|
||||
Mask generation models are trained on large amounts of data and operate in two modes.
|
||||
- Prompting mode: In this mode, the model takes in an image and a prompt, where a prompt can be a 2D point location (XY coordinates) in the image within an object or a bounding box surrounding an object. In prompting mode, the model only returns the mask over the object
|
||||
that the prompt is pointing out.
|
||||
- Segment Everything mode: In segment everything, given an image, the model generates every mask in the image. To do so, a grid of points is generated and overlaid on the image for inference.
|
||||
|
||||
Mask generation task is supported by [Segment Anything Model (SAM)](model_doc/sam). It's a powerful model that consists of a Vision Transformer-based image encoder, a prompt encoder, and a two-way transformer mask decoder. Images and prompts are encoded, and the decoder takes these embeddings and generates valid masks.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/sam.png" alt="SAM Architecture"/>
|
||||
</div>
|
||||
|
||||
SAM serves as a powerful foundation model for segmentation as it has large data coverage. It is trained on
|
||||
[SA-1B](https://ai.meta.com/datasets/segment-anything/), a dataset with 1 million images and 1.1 billion masks.
|
||||
|
||||
In this guide, you will learn how to:
|
||||
- Infer in segment everything mode with batching,
|
||||
- Infer in point prompting mode,
|
||||
- Infer in box prompting mode.
|
||||
|
||||
First, let's install `transformers`:
|
||||
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## Mask Generation Pipeline
|
||||
|
||||
The easiest way to infer mask generation models is to use the `mask-generation` pipeline.
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> checkpoint = "facebook/sam-vit-base"
|
||||
>>> mask_generator = pipeline(model=checkpoint, task="mask-generation")
|
||||
```
|
||||
|
||||
Let's see the image.
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
img_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
image = Image.open(requests.get(img_url, stream=True).raw).convert("RGB")
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg" alt="Example Image"/>
|
||||
</div>
|
||||
|
||||
Let's segment everything. `points-per-batch` enables parallel inference of points in segment everything mode. This enables faster inference, but consumes more memory. Moreover, SAM only enables batching over points and not the images. `pred_iou_thresh` is the IoU confidence threshold where only the masks above that certain threshold are returned.
|
||||
|
||||
```python
|
||||
masks = mask_generator(image, points_per_batch=128, pred_iou_thresh=0.88)
|
||||
```
|
||||
|
||||
The `masks` looks like the following:
|
||||
|
||||
```bash
|
||||
{'masks': [array([[False, False, False, ..., True, True, True],
|
||||
[False, False, False, ..., True, True, True],
|
||||
[False, False, False, ..., True, True, True],
|
||||
...,
|
||||
[False, False, False, ..., False, False, False],
|
||||
[False, False, False, ..., False, False, False],
|
||||
[False, False, False, ..., False, False, False]]),
|
||||
array([[False, False, False, ..., False, False, False],
|
||||
[False, False, False, ..., False, False, False],
|
||||
[False, False, False, ..., False, False, False],
|
||||
...,
|
||||
'scores': tensor([0.9972, 0.9917,
|
||||
...,
|
||||
}
|
||||
```
|
||||
|
||||
We can visualize them like this:
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
plt.imshow(image, cmap='gray')
|
||||
|
||||
for i, mask in enumerate(masks["masks"]):
|
||||
plt.imshow(mask, cmap='viridis', alpha=0.1, vmin=0, vmax=1)
|
||||
|
||||
plt.axis('off')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
Below is the original image in grayscale with colorful maps overlaid. Very impressive.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee_segmented.png" alt="Visualized"/>
|
||||
</div>
|
||||
|
||||
## Model Inference
|
||||
|
||||
### Point Prompting
|
||||
|
||||
You can also use the model without the pipeline. To do so, initialize the model and
|
||||
the processor.
|
||||
|
||||
```python
|
||||
from transformers import SamModel, SamProcessor, infer_device
|
||||
import torch
|
||||
device = infer_device()
|
||||
model = SamModel.from_pretrained("facebook/sam-vit-base").to(device)
|
||||
processor = SamProcessor.from_pretrained("facebook/sam-vit-base")
|
||||
```
|
||||
|
||||
To do point prompting, pass the input point to the processor, then take the processor output
|
||||
and pass it to the model for inference. To post-process the model output, pass the outputs and
|
||||
`original_sizes` and `reshaped_input_sizes` we take from the processor's initial output. We need to pass these
|
||||
since the processor resizes the image, and the output needs to be extrapolated.
|
||||
|
||||
```python
|
||||
input_points = [[[2592, 1728]]] # point location of the bee
|
||||
|
||||
inputs = processor(image, input_points=input_points, return_tensors="pt").to(device)
|
||||
with torch.no_grad():
|
||||
outputs = model(**inputs)
|
||||
masks = processor.image_processor.post_process_masks(outputs.pred_masks.cpu(), inputs["original_sizes"].cpu(), inputs["reshaped_input_sizes"].cpu())
|
||||
```
|
||||
|
||||
We can visualize the three masks in the `masks` output.
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
fig, axes = plt.subplots(1, 4, figsize=(15, 5))
|
||||
|
||||
axes[0].imshow(image)
|
||||
axes[0].set_title('Original Image')
|
||||
mask_list = [masks[0][0][0].numpy(), masks[0][0][1].numpy(), masks[0][0][2].numpy()]
|
||||
|
||||
for i, mask in enumerate(mask_list, start=1):
|
||||
overlayed_image = np.array(image).copy()
|
||||
|
||||
overlayed_image[:,:,0] = np.where(mask == 1, 255, overlayed_image[:,:,0])
|
||||
overlayed_image[:,:,1] = np.where(mask == 1, 0, overlayed_image[:,:,1])
|
||||
overlayed_image[:,:,2] = np.where(mask == 1, 0, overlayed_image[:,:,2])
|
||||
|
||||
axes[i].imshow(overlayed_image)
|
||||
axes[i].set_title(f'Mask {i}')
|
||||
for ax in axes:
|
||||
ax.axis('off')
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/masks.png" alt="Visualized"/>
|
||||
</div>
|
||||
|
||||
### Box Prompting
|
||||
|
||||
You can also do box prompting in a similar fashion to point prompting. You can simply pass the input box in the format of a list
|
||||
`[x_min, y_min, x_max, y_max]` format along with the image to the `processor`. Take the processor output and directly pass it
|
||||
to the model, then post-process the output again.
|
||||
|
||||
```python
|
||||
# bounding box around the bee
|
||||
box = [2350, 1600, 2850, 2100]
|
||||
|
||||
inputs = processor(
|
||||
image,
|
||||
input_boxes=[[[box]]],
|
||||
return_tensors="pt"
|
||||
).to(model.device)
|
||||
|
||||
with torch.no_grad():
|
||||
outputs = model(**inputs)
|
||||
|
||||
mask = processor.image_processor.post_process_masks(
|
||||
outputs.pred_masks.cpu(),
|
||||
inputs["original_sizes"].cpu(),
|
||||
inputs["reshaped_input_sizes"].cpu()
|
||||
)[0][0][0].numpy()
|
||||
```
|
||||
|
||||
You can visualize the bounding box around the bee as shown below.
|
||||
|
||||
```python
|
||||
import matplotlib.patches as patches
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(image)
|
||||
|
||||
rectangle = patches.Rectangle((2350, 1600), 500, 500, linewidth=2, edgecolor='r', facecolor='none')
|
||||
ax.add_patch(rectangle)
|
||||
ax.axis("off")
|
||||
plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/bbox.png" alt="Visualized Bbox"/>
|
||||
</div>
|
||||
|
||||
You can see the inference output below.
|
||||
|
||||
```python
|
||||
fig, ax = plt.subplots()
|
||||
ax.imshow(image)
|
||||
ax.imshow(mask, cmap='viridis', alpha=0.4)
|
||||
|
||||
ax.axis("off")
|
||||
plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/box_inference.png" alt="Visualized Inference"/>
|
||||
</div>
|
||||
321
transformers/docs/source/en/tasks/masked_language_modeling.md
Normal file
321
transformers/docs/source/en/tasks/masked_language_modeling.md
Normal file
@@ -0,0 +1,321 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Masked language modeling
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="mqElG5QJWUg"/>
|
||||
|
||||
Masked language modeling predicts a masked token in a sequence, and the model can attend to tokens bidirectionally. This
|
||||
means the model has full access to the tokens on the left and right. Masked language modeling is great for tasks that
|
||||
require a good contextual understanding of an entire sequence. BERT is an example of a masked language model.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [DistilRoBERTa](https://huggingface.co/distilbert/distilroberta-base) on the [r/askscience](https://www.reddit.com/r/askscience/) subset of the [ELI5](https://huggingface.co/datasets/eli5) dataset.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/fill-mask)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
We encourage you to log in to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load ELI5 dataset
|
||||
|
||||
Start by loading the first 5000 examples from the [ELI5-Category](https://huggingface.co/datasets/eli5_category) dataset with the 🤗 Datasets library. This'll give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> eli5 = load_dataset("eli5_category", split="train[:5000]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> eli5["train"][0]
|
||||
{'q_id': '7h191n',
|
||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
||||
'selftext': '',
|
||||
'category': 'Economics',
|
||||
'subreddit': 'explainlikeimfive',
|
||||
'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
||||
'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
||||
'score': [21, 19, 5, 3],
|
||||
'text_urls': [[],
|
||||
[],
|
||||
[],
|
||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
|
||||
'title_urls': ['url'],
|
||||
'selftext_urls': ['url']}
|
||||
```
|
||||
|
||||
While this may look like a lot, you're only really interested in the `text` field. What's cool about language modeling tasks is you don't need labels (also known as an unsupervised task) because the next word *is* the label.
|
||||
|
||||
## Preprocess
|
||||
|
||||
<Youtube id="8PmhEIXhBvI"/>
|
||||
|
||||
For masked language modeling, the next step is to load a DistilRoBERTa tokenizer to process the `text` subfield:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilroberta-base")
|
||||
```
|
||||
|
||||
You'll notice from the example above, the `text` field is actually nested inside `answers`. This means you'll need to extract the `text` subfield from its nested structure with the [`flatten`](https://huggingface.co/docs/datasets/process#flatten) method:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.flatten()
|
||||
>>> eli5["train"][0]
|
||||
{'q_id': '7h191n',
|
||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
||||
'selftext': '',
|
||||
'category': 'Economics',
|
||||
'subreddit': 'explainlikeimfive',
|
||||
'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
||||
'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
||||
'answers.score': [21, 19, 5, 3],
|
||||
'answers.text_urls': [[],
|
||||
[],
|
||||
[],
|
||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
|
||||
'title_urls': ['url'],
|
||||
'selftext_urls': ['url']}
|
||||
```
|
||||
|
||||
Each subfield is now a separate column as indicated by the `answers` prefix, and the `text` field is a list now. Instead
|
||||
of tokenizing each sentence separately, convert the list to a string so you can jointly tokenize them.
|
||||
|
||||
Here is a first preprocessing function to join the list of strings for each example and tokenize the result:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
||||
```
|
||||
|
||||
To apply this preprocessing function over the entire dataset, use the 🤗 Datasets [`~datasets.Dataset.map`] method. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once, and increasing the number of processes with `num_proc`. Remove any columns you don't need:
|
||||
|
||||
```py
|
||||
>>> tokenized_eli5 = eli5.map(
|
||||
... preprocess_function,
|
||||
... batched=True,
|
||||
... num_proc=4,
|
||||
... remove_columns=eli5["train"].column_names,
|
||||
... )
|
||||
```
|
||||
|
||||
This dataset contains the token sequences, but some of these are longer than the maximum input length for the model.
|
||||
|
||||
You can now use a second preprocessing function to
|
||||
- concatenate all the sequences
|
||||
- split the concatenated sequences into shorter chunks defined by `block_size`, which should be both shorter than the maximum input length and short enough for your GPU RAM.
|
||||
|
||||
```py
|
||||
>>> block_size = 128
|
||||
|
||||
|
||||
>>> def group_texts(examples):
|
||||
... # Concatenate all texts.
|
||||
... concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
|
||||
... total_length = len(concatenated_examples[list(examples.keys())[0]])
|
||||
... # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can
|
||||
... # customize this part to your needs.
|
||||
... if total_length >= block_size:
|
||||
... total_length = (total_length // block_size) * block_size
|
||||
... # Split by chunks of block_size.
|
||||
... result = {
|
||||
... k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
|
||||
... for k, t in concatenated_examples.items()
|
||||
... }
|
||||
... return result
|
||||
```
|
||||
|
||||
Apply the `group_texts` function over the entire dataset:
|
||||
|
||||
```py
|
||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DataCollatorForLanguageModeling`]. It's more efficient to *dynamically pad* the sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length.
|
||||
|
||||
Use the end-of-sequence token as the padding token and specify `mlm_probability` to randomly mask tokens each time you iterate over the data:
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForLanguageModeling
|
||||
|
||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
|
||||
```
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load DistilRoBERTa with [`AutoModelForMaskedLM`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMaskedLM
|
||||
|
||||
>>> model = AutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model).
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, datasets, and data collator.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_eli5_mlm_model",
|
||||
... eval_strategy="epoch",
|
||||
... learning_rate=2e-5,
|
||||
... num_train_epochs=3,
|
||||
... weight_decay=0.01,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=lm_dataset["train"],
|
||||
... eval_dataset=lm_dataset["test"],
|
||||
... data_collator=data_collator,
|
||||
... tokenizer=tokenizer,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, use the [`~transformers.Trainer.evaluate`] method to evaluate your model and get its perplexity:
|
||||
|
||||
```py
|
||||
>>> import math
|
||||
|
||||
>>> eval_results = trainer.evaluate()
|
||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
||||
Perplexity: 8.76
|
||||
```
|
||||
|
||||
Then share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for masked language modeling, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Come up with some text you'd like the model to fill in the blank with, and use the special `<mask>` token to indicate the blank:
|
||||
|
||||
```py
|
||||
>>> text = "The Milky Way is a <mask> galaxy."
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for fill-mask with your model, and pass your text to it. If you like, you can use the `top_k` parameter to specify how many predictions to return:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> mask_filler = pipeline("fill-mask", "username/my_awesome_eli5_mlm_model")
|
||||
>>> mask_filler(text, top_k=3)
|
||||
[{'score': 0.5150994658470154,
|
||||
'token': 21300,
|
||||
'token_str': ' spiral',
|
||||
'sequence': 'The Milky Way is a spiral galaxy.'},
|
||||
{'score': 0.07087188959121704,
|
||||
'token': 2232,
|
||||
'token_str': ' massive',
|
||||
'sequence': 'The Milky Way is a massive galaxy.'},
|
||||
{'score': 0.06434620916843414,
|
||||
'token': 650,
|
||||
'token_str': ' small',
|
||||
'sequence': 'The Milky Way is a small galaxy.'}]
|
||||
```
|
||||
|
||||
Tokenize the text and return the `input_ids` as PyTorch tensors. You'll also need to specify the position of the `<mask>` token:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_mlm_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
>>> mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the `logits` of the masked token:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMaskedLM
|
||||
|
||||
>>> model = AutoModelForMaskedLM.from_pretrained("username/my_awesome_eli5_mlm_model")
|
||||
>>> logits = model(**inputs).logits
|
||||
>>> mask_token_logits = logits[0, mask_token_index, :]
|
||||
```
|
||||
|
||||
Then return the three masked tokens with the highest probability and print them out:
|
||||
|
||||
```py
|
||||
>>> top_3_tokens = torch.topk(mask_token_logits, 3, dim=1).indices[0].tolist()
|
||||
|
||||
>>> for token in top_3_tokens:
|
||||
... print(text.replace(tokenizer.mask_token, tokenizer.decode([token])))
|
||||
The Milky Way is a spiral galaxy.
|
||||
The Milky Way is a massive galaxy.
|
||||
The Milky Way is a small galaxy.
|
||||
```
|
||||
159
transformers/docs/source/en/tasks/monocular_depth_estimation.md
Normal file
159
transformers/docs/source/en/tasks/monocular_depth_estimation.md
Normal file
@@ -0,0 +1,159 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Monocular depth estimation
|
||||
|
||||
Monocular depth estimation is a computer vision task that involves predicting the depth information of a scene from a
|
||||
single image. In other words, it is the process of estimating the distance of objects in a scene from
|
||||
a single camera viewpoint.
|
||||
|
||||
Monocular depth estimation has various applications, including 3D reconstruction, augmented reality, autonomous driving,
|
||||
and robotics. It is a challenging task as it requires the model to understand the complex relationships between objects
|
||||
in the scene and the corresponding depth information, which can be affected by factors such as lighting conditions,
|
||||
occlusion, and texture.
|
||||
|
||||
There are two main depth estimation categories:
|
||||
|
||||
- **Absolute depth estimation**: This task variant aims to provide exact depth measurements from the camera. The term is used interchangeably with metric depth estimation, where depth is provided in precise measurements in meters or feet. Absolute depth estimation models output depth maps with numerical values that represent real-world distances.
|
||||
|
||||
- **Relative depth estimation**: Relative depth estimation aims to predict the depth order of objects or points in a scene without providing the precise measurements. These models output a depth map that indicates which parts of the scene are closer or farther relative to each other without the actual distances to A and B.
|
||||
|
||||
In this guide, we will see how to infer with [Depth Anything V2](https://huggingface.co/depth-anything/Depth-Anything-V2-Large), a state-of-the-art zero-shot relative depth estimation model, and [ZoeDepth](https://huggingface.co/docs/transformers/main/en/model_doc/zoedepth), an absolute depth estimation model.
|
||||
|
||||
<Tip>
|
||||
|
||||
Check the [Depth Estimation](https://huggingface.co/tasks/depth-estimation) task page to view all compatible architectures and checkpoints.
|
||||
|
||||
</Tip>
|
||||
|
||||
Before we begin, we need to install the latest version of Transformers:
|
||||
|
||||
```bash
|
||||
pip install -q -U transformers
|
||||
```
|
||||
|
||||
## Depth estimation pipeline
|
||||
|
||||
The simplest way to try out inference with a model supporting depth estimation is to use the corresponding [`pipeline`].
|
||||
Instantiate a pipeline from a [checkpoint on the Hugging Face Hub](https://huggingface.co/models?pipeline_tag=depth-estimation&sort=downloads):
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline, infer_device
|
||||
>>> import torch
|
||||
>>> device = infer_device()
|
||||
>>> checkpoint = "depth-anything/Depth-Anything-V2-base-hf"
|
||||
>>> pipe = pipeline("depth-estimation", model=checkpoint, device=device)
|
||||
```
|
||||
|
||||
Next, choose an image to analyze:
|
||||
|
||||
```py
|
||||
>>> from PIL import Image
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
|
||||
>>> image = Image.open(requests.get(url, stream=True).raw)
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg" alt="Photo of a bee"/>
|
||||
</div>
|
||||
|
||||
Pass the image to the pipeline.
|
||||
|
||||
```py
|
||||
>>> predictions = pipe(image)
|
||||
```
|
||||
|
||||
The pipeline returns a dictionary with two entries. The first one, called `predicted_depth`, is a tensor with the values
|
||||
being the depth expressed in meters for each pixel.
|
||||
The second one, `depth`, is a PIL image that visualizes the depth estimation result.
|
||||
|
||||
Let's take a look at the visualized result:
|
||||
|
||||
```py
|
||||
>>> predictions["depth"]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/depth-visualization.png" alt="Depth estimation visualization"/>
|
||||
</div>
|
||||
|
||||
## Depth estimation inference by hand
|
||||
|
||||
Now that you've seen how to use the depth estimation pipeline, let's see how we can replicate the same result by hand.
|
||||
|
||||
Start by loading the model and associated processor from a [checkpoint on the Hugging Face Hub](https://huggingface.co/models?pipeline_tag=depth-estimation&sort=downloads).
|
||||
Here we'll use the same checkpoint as before:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor, AutoModelForDepthEstimation
|
||||
|
||||
>>> checkpoint = "Intel/zoedepth-nyu-kitti"
|
||||
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
|
||||
>>> model = AutoModelForDepthEstimation.from_pretrained(checkpoint).to(device)
|
||||
```
|
||||
|
||||
Prepare the image input for the model using the `image_processor` that will take care of the necessary image transformations
|
||||
such as resizing and normalization:
|
||||
|
||||
```py
|
||||
>>> pixel_values = image_processor(image, return_tensors="pt").pixel_values.to(device)
|
||||
```
|
||||
|
||||
Pass the prepared inputs through the model:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(pixel_values)
|
||||
```
|
||||
|
||||
Let's post-process the results to remove any padding and resize the depth map to match the original image size. The `post_process_depth_estimation` outputs a list of dicts containing the `"predicted_depth"`.
|
||||
|
||||
```py
|
||||
>>> # ZoeDepth dynamically pads the input image. Thus we pass the original image size as argument
|
||||
>>> # to `post_process_depth_estimation` to remove the padding and resize to original dimensions.
|
||||
>>> post_processed_output = image_processor.post_process_depth_estimation(
|
||||
... outputs,
|
||||
... source_sizes=[(image.height, image.width)],
|
||||
... )
|
||||
|
||||
>>> predicted_depth = post_processed_output[0]["predicted_depth"]
|
||||
>>> depth = (predicted_depth - predicted_depth.min()) / (predicted_depth.max() - predicted_depth.min())
|
||||
>>> depth = depth.detach().cpu().numpy() * 255
|
||||
>>> depth = Image.fromarray(depth.astype("uint8"))
|
||||
```
|
||||
|
||||
<Tip>
|
||||
<p>In the <a href="https://github.com/isl-org/ZoeDepth/blob/edb6daf45458569e24f50250ef1ed08c015f17a7/zoedepth/models/depth_model.py#L131">original implementation</a> ZoeDepth model performs inference on both the original and flipped images and averages out the results. The <code>post_process_depth_estimation</code> function can handle this for us by passing the flipped outputs to the optional <code>outputs_flipped</code> argument:</p>
|
||||
<pre><code class="language-Python">>>> with torch.no_grad():
|
||||
... outputs = model(pixel_values)
|
||||
... outputs_flipped = model(pixel_values=torch.flip(inputs.pixel_values, dims=[3]))
|
||||
>>> post_processed_output = image_processor.post_process_depth_estimation(
|
||||
... outputs,
|
||||
... source_sizes=[(image.height, image.width)],
|
||||
... outputs_flipped=outputs_flipped,
|
||||
... )
|
||||
</code></pre>
|
||||
</Tip>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/depth-visualization-zoe.png" alt="Depth estimation visualization"/>
|
||||
</div>
|
||||
246
transformers/docs/source/en/tasks/multiple_choice.md
Normal file
246
transformers/docs/source/en/tasks/multiple_choice.md
Normal file
@@ -0,0 +1,246 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Multiple choice
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
A multiple choice task is similar to question answering, except several candidate answers are provided along with a context and the model is trained to select the correct answer.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [BERT](https://huggingface.co/google-bert/bert-base-uncased) on the `regular` configuration of the [SWAG](https://huggingface.co/datasets/swag) dataset to select the best answer given multiple options and some context.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load SWAG dataset
|
||||
|
||||
Start by loading the `regular` configuration of the SWAG dataset from the 🤗 Datasets library:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> swag = load_dataset("swag", "regular")
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> swag["train"][0]
|
||||
{'ending0': 'passes by walking down the street playing their instruments.',
|
||||
'ending1': 'has heard approaching them.',
|
||||
'ending2': "arrives and they're outside dancing and asleep.",
|
||||
'ending3': 'turns the lead singer watches the performance.',
|
||||
'fold-ind': '3416',
|
||||
'gold-source': 'gold',
|
||||
'label': 0,
|
||||
'sent1': 'Members of the procession walk down the street holding small horn brass instruments.',
|
||||
'sent2': 'A drum line',
|
||||
'startphrase': 'Members of the procession walk down the street holding small horn brass instruments. A drum line',
|
||||
'video-id': 'anetv_jkn6uvmqwh4'}
|
||||
```
|
||||
|
||||
While it looks like there are a lot of fields here, it is actually pretty straightforward:
|
||||
|
||||
- `sent1` and `sent2`: these fields show how a sentence starts, and if you put the two together, you get the `startphrase` field.
|
||||
- `ending`: suggests a possible ending for how a sentence can end, but only one of them is correct.
|
||||
- `label`: identifies the correct sentence ending.
|
||||
|
||||
## Preprocess
|
||||
|
||||
The next step is to load a BERT tokenizer to process the sentence starts and the four possible endings:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
||||
```
|
||||
|
||||
The preprocessing function you want to create needs to:
|
||||
|
||||
1. Make four copies of the `sent1` field and combine each of them with `sent2` to recreate how a sentence starts.
|
||||
2. Combine `sent2` with each of the four possible sentence endings.
|
||||
3. Flatten these two lists so you can tokenize them, and then unflatten them afterward so each example has a corresponding `input_ids`, `attention_mask`, and `labels` field.
|
||||
|
||||
```py
|
||||
>>> ending_names = ["ending0", "ending1", "ending2", "ending3"]
|
||||
|
||||
|
||||
>>> def preprocess_function(examples):
|
||||
... first_sentences = [[context] * 4 for context in examples["sent1"]]
|
||||
... question_headers = examples["sent2"]
|
||||
... second_sentences = [
|
||||
... [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers)
|
||||
... ]
|
||||
|
||||
... first_sentences = sum(first_sentences, [])
|
||||
... second_sentences = sum(second_sentences, [])
|
||||
|
||||
... tokenized_examples = tokenizer(first_sentences, second_sentences, truncation=True)
|
||||
... return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()}
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] method. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once:
|
||||
|
||||
```py
|
||||
>>> tokenized_swag = swag.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
To create a batch of examples, it's more efficient to *dynamically pad* the sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length. [`DataCollatorForMultipleChoice`] flattens all the model inputs, applies padding, and then unflattens the results.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForMultipleChoice
|
||||
>>> collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load a evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the accuracy:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def compute_metrics(eval_pred):
|
||||
... predictions, labels = eval_pred
|
||||
... predictions = np.argmax(predictions, axis=1)
|
||||
... return accuracy.compute(predictions=predictions, references=labels)
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load BERT with [`AutoModelForMultipleChoice`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the accuracy and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_swag_model",
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... load_best_model_at_end=True,
|
||||
... learning_rate=5e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... per_device_eval_batch_size=16,
|
||||
... num_train_epochs=3,
|
||||
... weight_decay=0.01,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=tokenized_swag["train"],
|
||||
... eval_dataset=tokenized_swag["validation"],
|
||||
... processing_class=tokenizer,
|
||||
... data_collator=collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for multiple choice, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Come up with some text and two candidate answers:
|
||||
|
||||
```py
|
||||
>>> prompt = "France has a bread law, Le Décret Pain, with strict rules on what is allowed in a traditional baguette."
|
||||
>>> candidate1 = "The law does not apply to croissants and brioche."
|
||||
>>> candidate2 = "The law applies to baguettes."
|
||||
```
|
||||
|
||||
Tokenize each prompt and candidate answer pair and return PyTorch tensors. You should also create some `labels`:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
|
||||
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
|
||||
>>> labels = torch.tensor(0).unsqueeze(0)
|
||||
```
|
||||
|
||||
Pass your inputs and labels to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMultipleChoice
|
||||
|
||||
>>> model = AutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
|
||||
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
|
||||
>>> logits = outputs.logits
|
||||
```
|
||||
|
||||
Get the class with the highest probability:
|
||||
|
||||
```py
|
||||
>>> predicted_class = logits.argmax().item()
|
||||
>>> predicted_class
|
||||
0
|
||||
```
|
||||
1542
transformers/docs/source/en/tasks/object_detection.md
Normal file
1542
transformers/docs/source/en/tasks/object_detection.md
Normal file
File diff suppressed because it is too large
Load Diff
266
transformers/docs/source/en/tasks/prompting.md
Normal file
266
transformers/docs/source/en/tasks/prompting.md
Normal file
@@ -0,0 +1,266 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Prompt engineering
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Prompt engineering or prompting, uses natural language to improve large language model (LLM) performance on a variety of tasks. A prompt can steer the model towards generating a desired output. In many cases, you don't even need a [fine-tuned](#finetuning) model for a task. You just need a good prompt.
|
||||
|
||||
Try prompting a LLM to classify some text. When you create a prompt, it's important to provide very specific instructions about the task and what the result should look like.
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(task="text-generation", model="mistralai/Mistal-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Classify the text into neutral, negative or positive.
|
||||
Text: This movie is definitely one of my favorite movies of its kind. The interaction between respectable and morally strong characters is an ode to chivalry and the honor code amongst thieves and policemen.
|
||||
Sentiment:
|
||||
"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=10)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: Classify the text into neutral, negative or positive.
|
||||
Text: This movie is definitely one of my favorite movies of its kind. The interaction between respectable and morally strong characters is an ode to chivalry and the honor code amongst thieves and policemen.
|
||||
Sentiment:
|
||||
Positive
|
||||
```
|
||||
|
||||
The challenge lies in designing prompts that produces the results you're expecting because language is so incredibly nuanced and expressive.
|
||||
|
||||
This guide covers prompt engineering best practices, techniques, and examples for how to solve language and reasoning tasks.
|
||||
|
||||
## Best practices
|
||||
|
||||
1. Try to pick the latest models for the best performance. Keep in mind that LLMs can come in two variants, [base](https://hf.co/mistralai/Mistral-7B-v0.1) and [instruction-tuned](https://hf.co/mistralai/Mistral-7B-Instruct-v0.1) (or chat).
|
||||
|
||||
Base models are excellent at completing text given an initial prompt, but they're not as good at following instructions. Instruction-tuned models are specifically trained versions of the base models on instructional or conversational data. This makes instruction-tuned models a better fit for prompting.
|
||||
|
||||
> [!WARNING]
|
||||
> Modern LLMs are typically decoder-only models, but there are some encoder-decoder LLMs like [Flan-T5](../model_doc/flan-t5) or [BART](../model_doc/bart) that may be used for prompting. For encoder-decoder models, make sure you set the pipeline task identifier to `text2text-generation` instead of `text-generation`.
|
||||
|
||||
2. Start with a short and simple prompt, and iterate on it to get better results.
|
||||
|
||||
3. Put instructions at the beginning or end of a prompt. For longer prompts, models may apply optimizations to prevent attention from scaling quadratically, which places more emphasis at the beginning and end of a prompt.
|
||||
|
||||
4. Clearly separate instructions from the text of interest.
|
||||
|
||||
5. Be specific and descriptive about the task and the desired output, including for example, its format, length, style, and language. Avoid ambiguous descriptions and instructions.
|
||||
|
||||
6. Instructions should focus on "what to do" rather than "what not to do".
|
||||
|
||||
7. Lead the model to generate the correct output by writing the first word or even the first sentence.
|
||||
|
||||
8. Try other techniques like [few-shot](#few-shot) and [chain-of-thought](#chain-of-thought) to improve results.
|
||||
|
||||
9. Test your prompts with different models to assess their robustness.
|
||||
|
||||
10. Version and track your prompt performance.
|
||||
|
||||
## Techniques
|
||||
|
||||
Crafting a good prompt alone, also known as zero-shot prompting, may not be enough to get the results you want. You may need to try a few prompting techniques to get the best performance.
|
||||
|
||||
This section covers a few prompting techniques.
|
||||
|
||||
### Few-shot prompting
|
||||
|
||||
Few-shot prompting improves accuracy and performance by including specific examples of what a model should generate given an input. The explicit examples give the model a better understanding of the task and the output format you're looking for. Try experimenting with different numbers of examples (2, 4, 8, etc.) to see how it affects performance. The example below provides the model with 1 example (1-shot) of the output format (a date in MM/DD/YYYY format) it should return.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Text: The first human went into space and orbited the Earth on April 12, 1961.
|
||||
Date: 04/12/1961
|
||||
Text: The first-ever televised presidential debate in the United States took place on September 28, 1960, between presidential candidates John F. Kennedy and Richard Nixon.
|
||||
Date:"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=12, do_sample=True, top_k=10)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
# Result: Text: The first human went into space and orbited the Earth on April 12, 1961.
|
||||
# Date: 04/12/1961
|
||||
# Text: The first-ever televised presidential debate in the United States took place on September 28, 1960, between presidential candidates John F. Kennedy and Richard Nixon.
|
||||
# Date: 09/28/1960
|
||||
```
|
||||
|
||||
The downside of few-shot prompting is that you need to create lengthier prompts which increases computation and latency. There is also a limit to prompt lengths. Finally, a model can learn unintended patterns from your examples, and it may not work well on complex reasoning tasks.
|
||||
|
||||
To improve few-shot prompting for modern instruction-tuned LLMs, use a model's specific [chat template](../conversations). These models are trained on datasets with turn-based conversations between a "user" and "assistant". Structuring your prompt to align with this can improve performance.
|
||||
|
||||
Structure your prompt as a turn-based conversation and use the [`apply_chat_template`] method to tokenize and format it.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
|
||||
messages = [
|
||||
{"role": "user", "content": "Text: The first human went into space and orbited the Earth on April 12, 1961."},
|
||||
{"role": "assistant", "content": "Date: 04/12/1961"},
|
||||
{"role": "user", "content": "Text: The first-ever televised presidential debate in the United States took place on September 28, 1960, between presidential candidates John F. Kennedy and Richard Nixon."}
|
||||
]
|
||||
|
||||
prompt = pipeline.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=12, do_sample=True, top_k=10)
|
||||
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
```
|
||||
|
||||
While the basic few-shot prompting approach embedded examples within a single text string, the chat template format offers the following benefits.
|
||||
|
||||
- The model may have a potentially improved understanding because it can better recognize the pattern and the expected roles of user input and assistant output.
|
||||
- The model may more consistently output the desired output format because it is structured like its input during training.
|
||||
|
||||
Always consult a specific instruction-tuned model's documentation to learn more about the format of their chat template so that you can structure your few-shot prompts accordingly.
|
||||
|
||||
### Chain-of-thought
|
||||
|
||||
Chain-of-thought (CoT) is effective at generating more coherent and well-reasoned outputs by providing a series of prompts that help a model "think" more thoroughly about a topic.
|
||||
|
||||
The example below provides the model with several prompts to work through intermediate reasoning steps.
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Let's go through this step-by-step:
|
||||
1. You start with 15 muffins.
|
||||
2. You eat 2 muffins, leaving you with 13 muffins.
|
||||
3. You give 5 muffins to your neighbor, leaving you with 8 muffins.
|
||||
4. Your partner buys 6 more muffins, bringing the total number of muffins to 14.
|
||||
5. Your partner eats 2 muffins, leaving you with 12 muffins.
|
||||
If you eat 6 muffins, how many are left?"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=20, do_sample=True, top_k=10)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: Let's go through this step-by-step:
|
||||
1. You start with 15 muffins.
|
||||
2. You eat 2 muffins, leaving you with 13 muffins.
|
||||
3. You give 5 muffins to your neighbor, leaving you with 8 muffins.
|
||||
4. Your partner buys 6 more muffins, bringing the total number of muffins to 14.
|
||||
5. Your partner eats 2 muffins, leaving you with 12 muffins.
|
||||
If you eat 6 muffins, how many are left?
|
||||
Answer: 6
|
||||
```
|
||||
|
||||
Like [few-shot](#few-shot) prompting, the downside of CoT is that it requires more effort to design a series of prompts that help the model reason through a complex task and prompt length increases latency.
|
||||
|
||||
## Fine-tuning
|
||||
|
||||
While prompting is a powerful way to work with LLMs, there are scenarios where a fine-tuned model or even fine-tuning a model works better.
|
||||
|
||||
Here are some examples scenarios where a fine-tuned model makes sense.
|
||||
|
||||
- Your domain is extremely different from what a LLM was pretrained on, and extensive prompting didn't produce the results you want.
|
||||
- Your model needs to work well in a low-resource language.
|
||||
- Your model needs to be trained on sensitive data that have strict regulatory requirements.
|
||||
- You're using a small model due to cost, privacy, infrastructure, or other constraints.
|
||||
|
||||
In all of these scenarios, ensure that you have a large enough domain-specific dataset to train your model with, have enough time and resources, and the cost of fine-tuning is worth it. Otherwise, you may be better off trying to optimize your prompt.
|
||||
|
||||
## Examples
|
||||
|
||||
The examples below demonstrate prompting a LLM for different tasks.
|
||||
|
||||
<hfoptions id="tasks">
|
||||
<hfoption id="named entity recognition">
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Return a list of named entities in the text.
|
||||
Text: The company was founded in 2016 by French entrepreneurs Clément Delangue, Julien Chaumond, and Thomas Wolf in New York City, originally as a company that developed a chatbot app targeted at teenagers.
|
||||
Named entities:
|
||||
"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=50, return_full_text=False)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: [Clément Delangue, Julien Chaumond, Thomas Wolf, company, New York City, chatbot app, teenagers]
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="translation">
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Translate the English text to French.
|
||||
Text: Sometimes, I've believed as many as six impossible things before breakfast.
|
||||
Translation:
|
||||
"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=20, do_sample=True, top_k=10, return_full_text=False)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: À l'occasion, j'ai croyu plus de six choses impossibles
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="summarization">
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Permaculture is a design process mimicking the diversity, functionality and resilience of natural ecosystems. The principles and practices are drawn from traditional ecological knowledge of indigenous cultures combined with modern scientific understanding and technological innovations. Permaculture design provides a framework helping individuals and communities develop innovative, creative and effective strategies for meeting basic needs while preparing for and mitigating the projected impacts of climate change.
|
||||
Write a summary of the above text.
|
||||
Summary:
|
||||
"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=30, do_sample=True, top_k=10, return_full_text=False)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: Permaculture is the design process that involves mimicking natural ecosystems to provide sustainable solutions to basic needs. It is a holistic approach that comb
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="question answering">
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
import torch
|
||||
|
||||
pipeline = pipeline(model="mistralai/Mistral-7B-Instruct-v0.1", dtype=torch.bfloat16, device_map="auto")
|
||||
prompt = """Answer the question using the context below.
|
||||
Context: Gazpacho is a cold soup and drink made of raw, blended vegetables. Most gazpacho includes stale bread, tomato, cucumbers, onion, bell peppers, garlic, olive oil, wine vinegar, water, and salt. Northern recipes often include cumin and/or pimentón (smoked sweet paprika). Traditionally, gazpacho was made by pounding the vegetables in a mortar with a pestle; this more laborious method is still sometimes used as it helps keep the gazpacho cool and avoids the foam and silky consistency of smoothie versions made in blenders or food processors.
|
||||
Question: What modern tool is used to make gazpacho?
|
||||
Answer:
|
||||
"""
|
||||
|
||||
outputs = pipeline(prompt, max_new_tokens=10, do_sample=True, top_k=10, return_full_text=False)
|
||||
for output in outputs:
|
||||
print(f"Result: {output['generated_text']}")
|
||||
Result: A blender or food processor is the modern tool
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
300
transformers/docs/source/en/tasks/question_answering.md
Normal file
300
transformers/docs/source/en/tasks/question_answering.md
Normal file
@@ -0,0 +1,300 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Question answering
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="ajPx5LwJD-I"/>
|
||||
|
||||
Question answering tasks return an answer given a question. If you've ever asked a virtual assistant like Alexa, Siri or Google what the weather is, then you've used a question answering model before. There are two common types of question answering tasks:
|
||||
|
||||
- Extractive: extract the answer from the given context.
|
||||
- Abstractive: generate an answer from the context that correctly answers the question.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) on the [SQuAD](https://huggingface.co/datasets/squad) dataset for extractive question answering.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/question-answering)
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load SQuAD dataset
|
||||
|
||||
Start by loading a smaller subset of the SQuAD dataset from the 🤗 Datasets library. This'll give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> squad = load_dataset("squad", split="train[:5000]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> squad = squad.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> squad["train"][0]
|
||||
{'answers': {'answer_start': [515], 'text': ['Saint Bernadette Soubirous']},
|
||||
'context': 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.',
|
||||
'id': '5733be284776f41900661182',
|
||||
'question': 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?',
|
||||
'title': 'University_of_Notre_Dame'
|
||||
}
|
||||
```
|
||||
|
||||
There are several important fields here:
|
||||
|
||||
- `answers`: the starting location of the answer token and the answer text.
|
||||
- `context`: background information from which the model needs to extract the answer.
|
||||
- `question`: the question a model should answer.
|
||||
|
||||
## Preprocess
|
||||
|
||||
<Youtube id="qgaM0weJHpA"/>
|
||||
|
||||
The next step is to load a DistilBERT tokenizer to process the `question` and `context` fields:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
There are a few preprocessing steps particular to question answering tasks you should be aware of:
|
||||
|
||||
1. Some examples in a dataset may have a very long `context` that exceeds the maximum input length of the model. To deal with longer sequences, truncate only the `context` by setting `truncation="only_second"`.
|
||||
2. Next, map the start and end positions of the answer to the original `context` by setting
|
||||
`return_offset_mapping=True`.
|
||||
3. With the mapping in hand, now you can find the start and end tokens of the answer. Use the [`~tokenizers.Encoding.sequence_ids`] method to
|
||||
find which part of the offset corresponds to the `question` and which corresponds to the `context`.
|
||||
|
||||
Here is how you can create a function to truncate and map the start and end tokens of the `answer` to the `context`:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... questions = [q.strip() for q in examples["question"]]
|
||||
... inputs = tokenizer(
|
||||
... questions,
|
||||
... examples["context"],
|
||||
... max_length=384,
|
||||
... truncation="only_second",
|
||||
... return_offsets_mapping=True,
|
||||
... padding="max_length",
|
||||
... )
|
||||
|
||||
... offset_mapping = inputs.pop("offset_mapping")
|
||||
... answers = examples["answers"]
|
||||
... start_positions = []
|
||||
... end_positions = []
|
||||
|
||||
... for i, offset in enumerate(offset_mapping):
|
||||
... answer = answers[i]
|
||||
... start_char = answer["answer_start"][0]
|
||||
... end_char = answer["answer_start"][0] + len(answer["text"][0])
|
||||
... sequence_ids = inputs.sequence_ids(i)
|
||||
|
||||
... # Find the start and end of the context
|
||||
... idx = 0
|
||||
... while sequence_ids[idx] != 1:
|
||||
... idx += 1
|
||||
... context_start = idx
|
||||
... while sequence_ids[idx] == 1:
|
||||
... idx += 1
|
||||
... context_end = idx - 1
|
||||
|
||||
... # If the answer is not fully inside the context, label it (0, 0)
|
||||
... if offset[context_start][0] > end_char or offset[context_end][1] < start_char:
|
||||
... start_positions.append(0)
|
||||
... end_positions.append(0)
|
||||
... else:
|
||||
... # Otherwise it's the start and end token positions
|
||||
... idx = context_start
|
||||
... while idx <= context_end and offset[idx][0] <= start_char:
|
||||
... idx += 1
|
||||
... start_positions.append(idx - 1)
|
||||
|
||||
... idx = context_end
|
||||
... while idx >= context_start and offset[idx][1] >= end_char:
|
||||
... idx -= 1
|
||||
... end_positions.append(idx + 1)
|
||||
|
||||
... inputs["start_positions"] = start_positions
|
||||
... inputs["end_positions"] = end_positions
|
||||
... return inputs
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] function. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once. Remove any columns you don't need:
|
||||
|
||||
```py
|
||||
>>> tokenized_squad = squad.map(preprocess_function, batched=True, remove_columns=squad["train"].column_names)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DefaultDataCollator`]. Unlike other data collators in 🤗 Transformers, the [`DefaultDataCollator`] does not apply any additional preprocessing such as padding.
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load DistilBERT with [`AutoModelForQuestionAnswering`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model).
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, and data collator.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_qa_model",
|
||||
... eval_strategy="epoch",
|
||||
... learning_rate=2e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... per_device_eval_batch_size=16,
|
||||
... num_train_epochs=3,
|
||||
... weight_decay=0.01,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=tokenized_squad["train"],
|
||||
... eval_dataset=tokenized_squad["test"],
|
||||
... processing_class=tokenizer,
|
||||
... data_collator=data_collator,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for question answering, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Evaluate
|
||||
|
||||
Evaluation for question answering requires a significant amount of postprocessing. To avoid taking up too much of your time, this guide skips the evaluation step. The [`Trainer`] still calculates the evaluation loss during training so you're not completely in the dark about your model's performance.
|
||||
|
||||
If you have more time and you're interested in how to evaluate your model for question answering, take a look at the [Question answering](https://huggingface.co/course/chapter7/7?fw=pt#post-processing) chapter from the 🤗 Hugging Face Course!
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Come up with a question and some context you'd like the model to predict:
|
||||
|
||||
```py
|
||||
>>> question = "How many programming languages does BLOOM support?"
|
||||
>>> context = "BLOOM has 176 billion parameters and can generate text in 46 languages natural languages and 13 programming languages."
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for question answering with your model, and pass your text to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> question_answerer = pipeline("question-answering", model="my_awesome_qa_model")
|
||||
>>> question_answerer(question=question, context=context)
|
||||
{'score': 0.2058267742395401,
|
||||
'start': 10,
|
||||
'end': 95,
|
||||
'answer': '176 billion parameters and can generate text in 46 languages natural languages and 13'}
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Tokenize the text and return PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_qa_model")
|
||||
>>> inputs = tokenizer(question, context, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
>>> from transformers import AutoModelForQuestionAnswering
|
||||
|
||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("my_awesome_qa_model")
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
```
|
||||
|
||||
Get the highest probability from the model output for the start and end positions:
|
||||
|
||||
```py
|
||||
>>> answer_start_index = outputs.start_logits.argmax()
|
||||
>>> answer_end_index = outputs.end_logits.argmax()
|
||||
```
|
||||
|
||||
Decode the predicted tokens to get the answer:
|
||||
|
||||
```py
|
||||
>>> predict_answer_tokens = inputs.input_ids[0, answer_start_index : answer_end_index + 1]
|
||||
>>> tokenizer.decode(predict_answer_tokens)
|
||||
'176 billion parameters and can generate text in 46 languages natural languages and 13'
|
||||
```
|
||||
690
transformers/docs/source/en/tasks/semantic_segmentation.md
Normal file
690
transformers/docs/source/en/tasks/semantic_segmentation.md
Normal file
@@ -0,0 +1,690 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image Segmentation
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="dKE8SIt9C-w"/>
|
||||
|
||||
Image segmentation models separate areas corresponding to different areas of interest in an image. These models work by assigning a label to each pixel. There are several types of segmentation: semantic segmentation, instance segmentation, and panoptic segmentation.
|
||||
|
||||
In this guide, we will:
|
||||
1. [Take a look at different types of segmentation](#types-of-segmentation).
|
||||
2. [Have an end-to-end fine-tuning example for semantic segmentation](#fine-tuning-a-model-for-segmentation).
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```py
|
||||
# uncomment to install the necessary libraries
|
||||
!pip install -q datasets transformers evaluate accelerate
|
||||
```
|
||||
|
||||
We encourage you to log in to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Types of Segmentation
|
||||
|
||||
Semantic segmentation assigns a label or class to every single pixel in an image. Let's take a look at a semantic segmentation model output. It will assign the same class to every instance of an object it comes across in an image, for example, all cats will be labeled as "cat" instead of "cat-1", "cat-2".
|
||||
We can use transformers' image segmentation pipeline to quickly infer a semantic segmentation model. Let's take a look at the example image.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/segmentation_input.jpg"
|
||||
image = Image.open(requests.get(url, stream=True).raw)
|
||||
image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/segmentation_input.jpg" alt="Segmentation Input"/>
|
||||
</div>
|
||||
|
||||
We will use [nvidia/segformer-b1-finetuned-cityscapes-1024-1024](https://huggingface.co/nvidia/segformer-b1-finetuned-cityscapes-1024-1024).
|
||||
|
||||
```python
|
||||
semantic_segmentation = pipeline("image-segmentation", "nvidia/segformer-b1-finetuned-cityscapes-1024-1024")
|
||||
results = semantic_segmentation(image)
|
||||
results
|
||||
```
|
||||
|
||||
The segmentation pipeline output includes a mask for every predicted class.
|
||||
|
||||
```bash
|
||||
[{'score': None,
|
||||
'label': 'road',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'sidewalk',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'building',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'wall',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'pole',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'traffic sign',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'vegetation',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'terrain',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'sky',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': None,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>}]
|
||||
```
|
||||
|
||||
Taking a look at the mask for the car class, we can see every car is classified with the same mask.
|
||||
|
||||
```python
|
||||
results[-1]["mask"]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/semantic_segmentation_output.png" alt="Semantic Segmentation Output"/>
|
||||
</div>
|
||||
|
||||
In instance segmentation, the goal is not to classify every pixel, but to predict a mask for **every instance of an object** in a given image. It works very similar to object detection, where there is a bounding box for every instance, there's a segmentation mask instead. We will use [facebook/mask2former-swin-large-cityscapes-instance](https://huggingface.co/facebook/mask2former-swin-large-cityscapes-instance) for this.
|
||||
|
||||
```python
|
||||
instance_segmentation = pipeline("image-segmentation", "facebook/mask2former-swin-large-cityscapes-instance")
|
||||
results = instance_segmentation(image)
|
||||
results
|
||||
```
|
||||
|
||||
As you can see below, there are multiple cars classified, and there's no classification for pixels other than pixels that belong to car and person instances.
|
||||
|
||||
```bash
|
||||
[{'score': 0.999944,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999945,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999652,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.903529,
|
||||
'label': 'person',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>}]
|
||||
```
|
||||
|
||||
Checking out one of the car masks below.
|
||||
|
||||
```python
|
||||
results[2]["mask"]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/instance_segmentation_output.png" alt="Semantic Segmentation Output"/>
|
||||
</div>
|
||||
|
||||
Panoptic segmentation combines semantic segmentation and instance segmentation, where every pixel is classified into a class and an instance of that class, and there are multiple masks for each instance of a class. We can use [facebook/mask2former-swin-large-cityscapes-panoptic](https://huggingface.co/facebook/mask2former-swin-large-cityscapes-panoptic) for this.
|
||||
|
||||
```python
|
||||
panoptic_segmentation = pipeline("image-segmentation", "facebook/mask2former-swin-large-cityscapes-panoptic")
|
||||
results = panoptic_segmentation(image)
|
||||
results
|
||||
```
|
||||
|
||||
As you can see below, we have more classes. We will later illustrate to see that every pixel is classified into one of the classes.
|
||||
|
||||
```bash
|
||||
[{'score': 0.999981,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999958,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.99997,
|
||||
'label': 'vegetation',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999575,
|
||||
'label': 'pole',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999958,
|
||||
'label': 'building',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999634,
|
||||
'label': 'road',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.996092,
|
||||
'label': 'sidewalk',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.999221,
|
||||
'label': 'car',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>},
|
||||
{'score': 0.99987,
|
||||
'label': 'sky',
|
||||
'mask': <PIL.Image.Image image mode=L size=612x415>}]
|
||||
```
|
||||
|
||||
Let's have a side by side comparison for all types of segmentation.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/segmentation-comparison.png" alt="Segmentation Maps Compared"/>
|
||||
</div>
|
||||
|
||||
Seeing all types of segmentation, let's have a deep dive on fine-tuning a model for semantic segmentation.
|
||||
|
||||
Common real-world applications of semantic segmentation include training self-driving cars to identify pedestrians and important traffic information, identifying cells and abnormalities in medical imagery, and monitoring environmental changes from satellite imagery.
|
||||
|
||||
## Fine-tuning a Model for Segmentation
|
||||
|
||||
We will now:
|
||||
|
||||
1. Finetune [SegFormer](https://huggingface.co/docs/transformers/main/en/model_doc/segformer#segformer) on the [SceneParse150](https://huggingface.co/datasets/scene_parse_150) dataset.
|
||||
2. Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/image-segmentation)
|
||||
|
||||
</Tip>
|
||||
|
||||
### Load SceneParse150 dataset
|
||||
|
||||
Start by loading a smaller subset of the SceneParse150 dataset from the 🤗 Datasets library. This'll give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> ds = load_dataset("scene_parse_150", split="train[:50]")
|
||||
```
|
||||
|
||||
Split the dataset's `train` split into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> ds = ds.train_test_split(test_size=0.2)
|
||||
>>> train_ds = ds["train"]
|
||||
>>> test_ds = ds["test"]
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> train_ds[0]
|
||||
{'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=512x683 at 0x7F9B0C201F90>,
|
||||
'annotation': <PIL.PngImagePlugin.PngImageFile image mode=L size=512x683 at 0x7F9B0C201DD0>,
|
||||
'scene_category': 368}
|
||||
|
||||
# view the image
|
||||
>>> train_ds[0]["image"]
|
||||
```
|
||||
|
||||
- `image`: a PIL image of the scene.
|
||||
- `annotation`: a PIL image of the segmentation map, which is also the model's target.
|
||||
- `scene_category`: a category id that describes the image scene like "kitchen" or "office". In this guide, you'll only need `image` and `annotation`, both of which are PIL images.
|
||||
|
||||
You'll also want to create a dictionary that maps a label id to a label class which will be useful when you set up the model later. Download the mappings from the Hub and create the `id2label` and `label2id` dictionaries:
|
||||
|
||||
```py
|
||||
>>> import json
|
||||
>>> from pathlib import Path
|
||||
>>> from huggingface_hub import hf_hub_download
|
||||
|
||||
>>> repo_id = "huggingface/label-files"
|
||||
>>> filename = "ade20k-id2label.json"
|
||||
>>> id2label = json.loads(Path(hf_hub_download(repo_id, filename, repo_type="dataset")).read_text())
|
||||
>>> id2label = {int(k): v for k, v in id2label.items()}
|
||||
>>> label2id = {v: k for k, v in id2label.items()}
|
||||
>>> num_labels = len(id2label)
|
||||
```
|
||||
|
||||
#### Custom dataset
|
||||
|
||||
You could also create and use your own dataset if you prefer to train with the [run_semantic_segmentation.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py) script instead of a notebook instance. The script requires:
|
||||
|
||||
1. a [`~datasets.DatasetDict`] with two [`~datasets.Image`] columns, "image" and "label"
|
||||
|
||||
```py
|
||||
from datasets import Dataset, DatasetDict, Image
|
||||
|
||||
image_paths_train = ["path/to/image_1.jpg/jpg", "path/to/image_2.jpg/jpg", ..., "path/to/image_n.jpg/jpg"]
|
||||
label_paths_train = ["path/to/annotation_1.png", "path/to/annotation_2.png", ..., "path/to/annotation_n.png"]
|
||||
|
||||
image_paths_validation = [...]
|
||||
label_paths_validation = [...]
|
||||
|
||||
def create_dataset(image_paths, label_paths):
|
||||
dataset = Dataset.from_dict({"image": sorted(image_paths),
|
||||
"label": sorted(label_paths)})
|
||||
dataset = dataset.cast_column("image", Image())
|
||||
dataset = dataset.cast_column("label", Image())
|
||||
return dataset
|
||||
|
||||
# step 1: create Dataset objects
|
||||
train_dataset = create_dataset(image_paths_train, label_paths_train)
|
||||
validation_dataset = create_dataset(image_paths_validation, label_paths_validation)
|
||||
|
||||
# step 2: create DatasetDict
|
||||
dataset = DatasetDict({
|
||||
"train": train_dataset,
|
||||
"validation": validation_dataset,
|
||||
}
|
||||
)
|
||||
|
||||
# step 3: push to Hub (assumes you have ran the hf auth login command in a terminal/notebook)
|
||||
dataset.push_to_hub("your-name/dataset-repo")
|
||||
|
||||
# optionally, you can push to a private repo on the Hub
|
||||
# dataset.push_to_hub("name of repo on the hub", private=True)
|
||||
```
|
||||
|
||||
2. an id2label dictionary mapping the class integers to their class names
|
||||
|
||||
```py
|
||||
import json
|
||||
# simple example
|
||||
id2label = {0: 'cat', 1: 'dog'}
|
||||
with open('id2label.json', 'w') as fp:
|
||||
json.dump(id2label, fp)
|
||||
```
|
||||
|
||||
As an example, take a look at this [example dataset](https://huggingface.co/datasets/nielsr/ade20k-demo) which was created with the steps shown above.
|
||||
|
||||
### Preprocess
|
||||
|
||||
The next step is to load a SegFormer image processor to prepare the images and annotations for the model. Some datasets, like this one, use the zero-index as the background class. However, the background class isn't actually included in the 150 classes, so you'll need to set `do_reduce_labels=True` to subtract one from all the labels. The zero-index is replaced by `255` so it's ignored by SegFormer's loss function:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
|
||||
>>> checkpoint = "nvidia/mit-b0"
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint, do_reduce_labels=True)
|
||||
```
|
||||
|
||||
It is common to apply some data augmentations to an image dataset to make a model more robust against overfitting. In this guide, you'll use the [`ColorJitter`](https://pytorch.org/vision/stable/generated/torchvision.transforms.ColorJitter.html) function from [torchvision](https://pytorch.org/vision/stable/index.html) to randomly change the color properties of an image, but you can also use any image library you like.
|
||||
|
||||
```py
|
||||
>>> from torchvision.transforms import ColorJitter
|
||||
|
||||
>>> jitter = ColorJitter(brightness=0.25, contrast=0.25, saturation=0.25, hue=0.1)
|
||||
```
|
||||
|
||||
Now create two preprocessing functions to prepare the images and annotations for the model. These functions convert the images into `pixel_values` and annotations to `labels`. For the training set, `jitter` is applied before providing the images to the image processor. For the test set, the image processor crops and normalizes the `images`, and only crops the `labels` because no data augmentation is applied during testing.
|
||||
|
||||
```py
|
||||
>>> def train_transforms(example_batch):
|
||||
... images = [jitter(x) for x in example_batch["image"]]
|
||||
... labels = [x for x in example_batch["annotation"]]
|
||||
... inputs = image_processor(images, labels)
|
||||
... return inputs
|
||||
|
||||
|
||||
>>> def val_transforms(example_batch):
|
||||
... images = [x for x in example_batch["image"]]
|
||||
... labels = [x for x in example_batch["annotation"]]
|
||||
... inputs = image_processor(images, labels)
|
||||
... return inputs
|
||||
```
|
||||
|
||||
To apply the `jitter` over the entire dataset, use the 🤗 Datasets [`~datasets.Dataset.set_transform`] function. The transform is applied on the fly which is faster and consumes less disk space:
|
||||
|
||||
```py
|
||||
>>> train_ds.set_transform(train_transforms)
|
||||
>>> test_ds.set_transform(val_transforms)
|
||||
```
|
||||
|
||||
### Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load an evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [mean Intersection over Union](https://huggingface.co/spaces/evaluate-metric/accuracy) (IoU) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> metric = evaluate.load("mean_iou")
|
||||
```
|
||||
|
||||
Then create a function to [`~evaluate.EvaluationModule.compute`] the metrics. Your predictions need to be converted to
|
||||
logits first, and then reshaped to match the size of the labels before you can call [`~evaluate.EvaluationModule.compute`]:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
>>> import torch
|
||||
>>> from torch import nn
|
||||
|
||||
>>> def compute_metrics(eval_pred):
|
||||
... with torch.no_grad():
|
||||
... logits, labels = eval_pred
|
||||
... logits_tensor = torch.from_numpy(logits)
|
||||
... logits_tensor = nn.functional.interpolate(
|
||||
... logits_tensor,
|
||||
... size=labels.shape[-2:],
|
||||
... mode="bilinear",
|
||||
... align_corners=False,
|
||||
... ).argmax(dim=1)
|
||||
|
||||
... pred_labels = logits_tensor.detach().cpu().numpy()
|
||||
... metrics = metric.compute(
|
||||
... predictions=pred_labels,
|
||||
... references=labels,
|
||||
... num_labels=num_labels,
|
||||
... ignore_index=255,
|
||||
... reduce_labels=False,
|
||||
... )
|
||||
... for key, value in metrics.items():
|
||||
... if isinstance(value, np.ndarray):
|
||||
... metrics[key] = value.tolist()
|
||||
... return metrics
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
### Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#finetune-with-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load SegFormer with [`AutoModelForSemanticSegmentation`], and pass the model the mapping between label ids and label classes:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSemanticSegmentation, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForSemanticSegmentation.from_pretrained(checkpoint, id2label=id2label, label2id=label2id)
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. It is important you don't remove unused columns because this'll drop the `image` column. Without the `image` column, you can't create `pixel_values`. Set `remove_unused_columns=False` to prevent this behavior! The only other required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the IoU metric and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="segformer-b0-scene-parse-150",
|
||||
... learning_rate=6e-5,
|
||||
... num_train_epochs=50,
|
||||
... per_device_train_batch_size=2,
|
||||
... per_device_eval_batch_size=2,
|
||||
... save_total_limit=3,
|
||||
... eval_strategy="steps",
|
||||
... save_strategy="steps",
|
||||
... save_steps=20,
|
||||
... eval_steps=20,
|
||||
... logging_steps=1,
|
||||
... eval_accumulation_steps=5,
|
||||
... remove_unused_columns=False,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=train_ds,
|
||||
... eval_dataset=test_ds,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
### Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Reload the dataset and load an image for inference.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> ds = load_dataset("scene_parse_150", split="train[:50]")
|
||||
>>> ds = ds.train_test_split(test_size=0.2)
|
||||
>>> test_ds = ds["test"]
|
||||
>>> image = ds["test"][0]["image"]
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/semantic-seg-image.png" alt="Image of bedroom"/>
|
||||
</div>
|
||||
|
||||
We will now see how to infer without a pipeline. Process the image with an image processor and place the `pixel_values` on a GPU:
|
||||
|
||||
```py
|
||||
>>> from transformers import infer_device
|
||||
>>> device = infer_device()
|
||||
>>> encoding = image_processor(image, return_tensors="pt")
|
||||
>>> pixel_values = encoding.pixel_values.to(device)
|
||||
```
|
||||
|
||||
Pass your input to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> outputs = model(pixel_values=pixel_values)
|
||||
>>> logits = outputs.logits.cpu()
|
||||
```
|
||||
|
||||
Next, rescale the logits to the original image size:
|
||||
|
||||
```py
|
||||
>>> upsampled_logits = nn.functional.interpolate(
|
||||
... logits,
|
||||
... size=image.size[::-1],
|
||||
... mode="bilinear",
|
||||
... align_corners=False,
|
||||
... )
|
||||
|
||||
>>> pred_seg = upsampled_logits.argmax(dim=1)[0]
|
||||
```
|
||||
|
||||
To visualize the results, load the [dataset color palette](https://github.com/tensorflow/models/blob/3f1ca33afe3c1631b733ea7e40c294273b9e406d/research/deeplab/utils/get_dataset_colormap.py#L51) as `ade_palette()` that maps each class to their RGB values.
|
||||
|
||||
```py
|
||||
def ade_palette():
|
||||
return np.asarray([
|
||||
[0, 0, 0],
|
||||
[120, 120, 120],
|
||||
[180, 120, 120],
|
||||
[6, 230, 230],
|
||||
[80, 50, 50],
|
||||
[4, 200, 3],
|
||||
[120, 120, 80],
|
||||
[140, 140, 140],
|
||||
[204, 5, 255],
|
||||
[230, 230, 230],
|
||||
[4, 250, 7],
|
||||
[224, 5, 255],
|
||||
[235, 255, 7],
|
||||
[150, 5, 61],
|
||||
[120, 120, 70],
|
||||
[8, 255, 51],
|
||||
[255, 6, 82],
|
||||
[143, 255, 140],
|
||||
[204, 255, 4],
|
||||
[255, 51, 7],
|
||||
[204, 70, 3],
|
||||
[0, 102, 200],
|
||||
[61, 230, 250],
|
||||
[255, 6, 51],
|
||||
[11, 102, 255],
|
||||
[255, 7, 71],
|
||||
[255, 9, 224],
|
||||
[9, 7, 230],
|
||||
[220, 220, 220],
|
||||
[255, 9, 92],
|
||||
[112, 9, 255],
|
||||
[8, 255, 214],
|
||||
[7, 255, 224],
|
||||
[255, 184, 6],
|
||||
[10, 255, 71],
|
||||
[255, 41, 10],
|
||||
[7, 255, 255],
|
||||
[224, 255, 8],
|
||||
[102, 8, 255],
|
||||
[255, 61, 6],
|
||||
[255, 194, 7],
|
||||
[255, 122, 8],
|
||||
[0, 255, 20],
|
||||
[255, 8, 41],
|
||||
[255, 5, 153],
|
||||
[6, 51, 255],
|
||||
[235, 12, 255],
|
||||
[160, 150, 20],
|
||||
[0, 163, 255],
|
||||
[140, 140, 140],
|
||||
[250, 10, 15],
|
||||
[20, 255, 0],
|
||||
[31, 255, 0],
|
||||
[255, 31, 0],
|
||||
[255, 224, 0],
|
||||
[153, 255, 0],
|
||||
[0, 0, 255],
|
||||
[255, 71, 0],
|
||||
[0, 235, 255],
|
||||
[0, 173, 255],
|
||||
[31, 0, 255],
|
||||
[11, 200, 200],
|
||||
[255, 82, 0],
|
||||
[0, 255, 245],
|
||||
[0, 61, 255],
|
||||
[0, 255, 112],
|
||||
[0, 255, 133],
|
||||
[255, 0, 0],
|
||||
[255, 163, 0],
|
||||
[255, 102, 0],
|
||||
[194, 255, 0],
|
||||
[0, 143, 255],
|
||||
[51, 255, 0],
|
||||
[0, 82, 255],
|
||||
[0, 255, 41],
|
||||
[0, 255, 173],
|
||||
[10, 0, 255],
|
||||
[173, 255, 0],
|
||||
[0, 255, 153],
|
||||
[255, 92, 0],
|
||||
[255, 0, 255],
|
||||
[255, 0, 245],
|
||||
[255, 0, 102],
|
||||
[255, 173, 0],
|
||||
[255, 0, 20],
|
||||
[255, 184, 184],
|
||||
[0, 31, 255],
|
||||
[0, 255, 61],
|
||||
[0, 71, 255],
|
||||
[255, 0, 204],
|
||||
[0, 255, 194],
|
||||
[0, 255, 82],
|
||||
[0, 10, 255],
|
||||
[0, 112, 255],
|
||||
[51, 0, 255],
|
||||
[0, 194, 255],
|
||||
[0, 122, 255],
|
||||
[0, 255, 163],
|
||||
[255, 153, 0],
|
||||
[0, 255, 10],
|
||||
[255, 112, 0],
|
||||
[143, 255, 0],
|
||||
[82, 0, 255],
|
||||
[163, 255, 0],
|
||||
[255, 235, 0],
|
||||
[8, 184, 170],
|
||||
[133, 0, 255],
|
||||
[0, 255, 92],
|
||||
[184, 0, 255],
|
||||
[255, 0, 31],
|
||||
[0, 184, 255],
|
||||
[0, 214, 255],
|
||||
[255, 0, 112],
|
||||
[92, 255, 0],
|
||||
[0, 224, 255],
|
||||
[112, 224, 255],
|
||||
[70, 184, 160],
|
||||
[163, 0, 255],
|
||||
[153, 0, 255],
|
||||
[71, 255, 0],
|
||||
[255, 0, 163],
|
||||
[255, 204, 0],
|
||||
[255, 0, 143],
|
||||
[0, 255, 235],
|
||||
[133, 255, 0],
|
||||
[255, 0, 235],
|
||||
[245, 0, 255],
|
||||
[255, 0, 122],
|
||||
[255, 245, 0],
|
||||
[10, 190, 212],
|
||||
[214, 255, 0],
|
||||
[0, 204, 255],
|
||||
[20, 0, 255],
|
||||
[255, 255, 0],
|
||||
[0, 153, 255],
|
||||
[0, 41, 255],
|
||||
[0, 255, 204],
|
||||
[41, 0, 255],
|
||||
[41, 255, 0],
|
||||
[173, 0, 255],
|
||||
[0, 245, 255],
|
||||
[71, 0, 255],
|
||||
[122, 0, 255],
|
||||
[0, 255, 184],
|
||||
[0, 92, 255],
|
||||
[184, 255, 0],
|
||||
[0, 133, 255],
|
||||
[255, 214, 0],
|
||||
[25, 194, 194],
|
||||
[102, 255, 0],
|
||||
[92, 0, 255],
|
||||
])
|
||||
```
|
||||
|
||||
Then you can combine and plot your image and the predicted segmentation map:
|
||||
|
||||
```py
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> import numpy as np
|
||||
|
||||
>>> color_seg = np.zeros((pred_seg.shape[0], pred_seg.shape[1], 3), dtype=np.uint8)
|
||||
>>> palette = np.array(ade_palette())
|
||||
>>> for label, color in enumerate(palette):
|
||||
... color_seg[pred_seg == label, :] = color
|
||||
>>> color_seg = color_seg[..., ::-1] # convert to BGR
|
||||
|
||||
>>> img = np.array(image) * 0.5 + color_seg * 0.5 # plot the image with the segmentation map
|
||||
>>> img = img.astype(np.uint8)
|
||||
|
||||
>>> plt.figure(figsize=(15, 10))
|
||||
>>> plt.imshow(img)
|
||||
>>> plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/semantic-seg-preds.png" alt="Image of bedroom overlaid with segmentation map"/>
|
||||
</div>
|
||||
254
transformers/docs/source/en/tasks/sequence_classification.md
Normal file
254
transformers/docs/source/en/tasks/sequence_classification.md
Normal file
@@ -0,0 +1,254 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Text classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="leNG9fN9FQU"/>
|
||||
|
||||
Text classification is a common NLP task that assigns a label or class to text. Some of the largest companies run text classification in production for a wide range of practical applications. One of the most popular forms of text classification is sentiment analysis, which assigns a label like 🙂 positive, 🙁 negative, or 😐 neutral to a sequence of text.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) on the [IMDb](https://huggingface.co/datasets/imdb) dataset to determine whether a movie review is positive or negative.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/text-classification).
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate accelerate
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load IMDb dataset
|
||||
|
||||
Start by loading the IMDb dataset from the 🤗 Datasets library:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> imdb = load_dataset("imdb")
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> imdb["test"][0]
|
||||
{
|
||||
"label": 0,
|
||||
"text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, under-appreciated and misunderstood. I tried to like this, I really did, but it is to good TV sci-fi as Babylon 5 is to Star Trek (the original). Silly prosthetics, cheap cardboard sets, stilted dialogues, CG that doesn't match the background, and painfully one-dimensional characters cannot be overcome with a 'sci-fi' setting. (I'm sure there are those of you out there who think Babylon 5 is good sci-fi TV. It's not. It's clichéd and uninspiring.) While US viewers might like emotion and character development, sci-fi is a genre that does not take itself seriously (cf. Star Trek). It may treat important issues, yet not as a serious philosophy. It's really difficult to care about the characters here as they are not simply foolish, just missing a spark of life. Their actions and reactions are wooden and predictable, often painful to watch. The makers of Earth KNOW it's rubbish as they have to always say \"Gene Roddenberry's Earth...\" otherwise people would not continue watching. Roddenberry's ashes must be turning in their orbit as this dull, cheap, poorly edited (watching it without advert breaks really brings this home) trudging Trabant of a show lumbers into space. Spoiler. So, kill off a main character. And then bring him back as another actor. Jeeez! Dallas all over again.",
|
||||
}
|
||||
```
|
||||
|
||||
There are two fields in this dataset:
|
||||
|
||||
- `text`: the movie review text.
|
||||
- `label`: a value that is either `0` for a negative review or `1` for a positive review.
|
||||
|
||||
## Preprocess
|
||||
|
||||
The next step is to load a DistilBERT tokenizer to preprocess the `text` field:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
Create a preprocessing function to tokenize `text` and truncate sequences to be no longer than DistilBERT's maximum input length:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer(examples["text"], truncation=True)
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] function. You can speed up `map` by setting `batched=True` to process multiple elements of the dataset at once:
|
||||
|
||||
```py
|
||||
tokenized_imdb = imdb.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DataCollatorWithPadding`]. It's more efficient to *dynamically pad* the sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorWithPadding
|
||||
|
||||
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load a evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the accuracy:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def compute_metrics(eval_pred):
|
||||
... predictions, labels = eval_pred
|
||||
... predictions = np.argmax(predictions, axis=1)
|
||||
... return accuracy.compute(predictions=predictions, references=labels)
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
Before you start training your model, create a map of the expected ids to their labels with `id2label` and `label2id`:
|
||||
|
||||
```py
|
||||
>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"}
|
||||
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load DistilBERT with [`AutoModelForSequenceClassification`] along with the number of expected labels, and the label mappings:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForSequenceClassification.from_pretrained(
|
||||
... "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
|
||||
... )
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the accuracy and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_model",
|
||||
... learning_rate=2e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... per_device_eval_batch_size=16,
|
||||
... num_train_epochs=2,
|
||||
... weight_decay=0.01,
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... load_best_model_at_end=True,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=tokenized_imdb["train"],
|
||||
... eval_dataset=tokenized_imdb["test"],
|
||||
... processing_class=tokenizer,
|
||||
... data_collator=data_collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`] applies dynamic padding by default when you pass `tokenizer` to it. In this case, you don't need to specify a data collator explicitly.
|
||||
|
||||
</Tip>
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for text classification, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Grab some text you'd like to run inference on:
|
||||
|
||||
```py
|
||||
>>> text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for sentiment analysis with your model, and pass your text to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
|
||||
>>> classifier(text)
|
||||
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Tokenize the text and return PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSequenceClassification
|
||||
|
||||
>>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
Get the class with the highest probability, and use the model's `id2label` mapping to convert it to a text label:
|
||||
|
||||
```py
|
||||
>>> predicted_class_id = logits.argmax().item()
|
||||
>>> model.config.id2label[predicted_class_id]
|
||||
'POSITIVE'
|
||||
```
|
||||
268
transformers/docs/source/en/tasks/summarization.md
Normal file
268
transformers/docs/source/en/tasks/summarization.md
Normal file
File diff suppressed because one or more lines are too long
637
transformers/docs/source/en/tasks/text-to-speech.md
Normal file
637
transformers/docs/source/en/tasks/text-to-speech.md
Normal file
@@ -0,0 +1,637 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Text to speech
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Text-to-speech (TTS) is the task of creating natural-sounding speech from text, where the speech can be generated in multiple
|
||||
languages and for multiple speakers. Several text-to-speech models are currently available in 🤗 Transformers, such as
|
||||
[Bark](../model_doc/bark), [MMS](../model_doc/mms), [VITS](../model_doc/vits) and [SpeechT5](../model_doc/speecht5).
|
||||
|
||||
You can easily generate audio using the `"text-to-audio"` pipeline (or its alias - `"text-to-speech"`). Some models, like Bark,
|
||||
can also be conditioned to generate non-verbal communications such as laughing, sighing and crying, or even add music.
|
||||
Here's an example of how you would use the `"text-to-speech"` pipeline with Bark:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> pipe = pipeline("text-to-speech", model="suno/bark-small")
|
||||
>>> text = "[clears throat] This is a test ... and I just took a long pause."
|
||||
>>> output = pipe(text)
|
||||
```
|
||||
|
||||
Here's a code snippet you can use to listen to the resulting audio in a notebook:
|
||||
|
||||
```python
|
||||
>>> from IPython.display import Audio
|
||||
>>> Audio(output["audio"], rate=output["sampling_rate"])
|
||||
```
|
||||
|
||||
For more examples on what Bark and other pretrained TTS models can do, refer to our
|
||||
[Audio course](https://huggingface.co/learn/audio-course/chapter6/pre-trained_models).
|
||||
|
||||
If you are looking to fine-tune a TTS model, the only text-to-speech models currently available in 🤗 Transformers
|
||||
are [SpeechT5](model_doc/speecht5) and [FastSpeech2Conformer](model_doc/fastspeech2_conformer), though more will be added in the future. SpeechT5 is pre-trained on a combination of speech-to-text and text-to-speech data, allowing it to learn a unified space of hidden representations shared by both text and speech. This means that the same pre-trained model can be fine-tuned for different tasks. Furthermore, SpeechT5 supports multiple speakers through x-vector speaker embeddings.
|
||||
|
||||
The remainder of this guide illustrates how to:
|
||||
|
||||
1. Fine-tune [SpeechT5](../model_doc/speecht5) that was originally trained on English speech on the Dutch (`nl`) language subset of the [VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli) dataset.
|
||||
2. Use your refined model for inference in one of two ways: using a pipeline or directly.
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install datasets soundfile speechbrain accelerate
|
||||
```
|
||||
|
||||
Install 🤗Transformers from source as not all the SpeechT5 features have been merged into an official release yet:
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/huggingface/transformers.git
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
To follow this guide you will need a GPU. If you're working in a notebook, run the following line to check if a GPU is available:
|
||||
|
||||
```bash
|
||||
!nvidia-smi
|
||||
```
|
||||
|
||||
or alternatively for AMD GPUs:
|
||||
|
||||
```bash
|
||||
!rocm-smi
|
||||
```
|
||||
|
||||
</Tip>
|
||||
|
||||
We encourage you to log in to your Hugging Face account to upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load the dataset
|
||||
|
||||
[VoxPopuli](https://huggingface.co/datasets/facebook/voxpopuli) is a large-scale multilingual speech corpus consisting of
|
||||
data sourced from 2009-2020 European Parliament event recordings. It contains labelled audio-transcription data for 15
|
||||
European languages. In this guide, we are using the Dutch language subset, feel free to pick another subset.
|
||||
|
||||
Note that VoxPopuli or any other automated speech recognition (ASR) dataset may not be the most suitable
|
||||
option for training TTS models. The features that make it beneficial for ASR, such as excessive background noise, are
|
||||
typically undesirable in TTS. However, finding top-quality, multilingual, and multi-speaker TTS datasets can be quite
|
||||
challenging.
|
||||
|
||||
Let's load the data:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> dataset = load_dataset("facebook/voxpopuli", "nl", split="train")
|
||||
>>> len(dataset)
|
||||
20968
|
||||
```
|
||||
|
||||
20968 examples should be sufficient for fine-tuning. SpeechT5 expects audio data to have a sampling rate of 16 kHz, so
|
||||
make sure the examples in the dataset meet this requirement:
|
||||
|
||||
```py
|
||||
dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
|
||||
```
|
||||
|
||||
## Preprocess the data
|
||||
|
||||
Let's begin by defining the model checkpoint to use and loading the appropriate processor:
|
||||
|
||||
```py
|
||||
>>> from transformers import SpeechT5Processor
|
||||
|
||||
>>> checkpoint = "microsoft/speecht5_tts"
|
||||
>>> processor = SpeechT5Processor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
### Text cleanup for SpeechT5 tokenization
|
||||
|
||||
Start by cleaning up the text data. You'll need the tokenizer part of the processor to process the text:
|
||||
|
||||
```py
|
||||
>>> tokenizer = processor.tokenizer
|
||||
```
|
||||
|
||||
The dataset examples contain `raw_text` and `normalized_text` features. When deciding which feature to use as the text input,
|
||||
consider that the SpeechT5 tokenizer doesn't have any tokens for numbers. In `normalized_text` the numbers are written
|
||||
out as text. Thus, it is a better fit, and we recommend using `normalized_text` as input text.
|
||||
|
||||
Because SpeechT5 was trained on the English language, it may not recognize certain characters in the Dutch dataset. If
|
||||
left as is, these characters will be converted to `<unk>` tokens. However, in Dutch, certain characters like `à` are
|
||||
used to stress syllables. In order to preserve the meaning of the text, we can replace this character with a regular `a`.
|
||||
|
||||
To identify unsupported tokens, extract all unique characters in the dataset using the `SpeechT5Tokenizer` which
|
||||
works with characters as tokens. To do this, write the `extract_all_chars` mapping function that concatenates
|
||||
the transcriptions from all examples into one string and converts it to a set of characters.
|
||||
Make sure to set `batched=True` and `batch_size=-1` in `dataset.map()` so that all transcriptions are available at once for
|
||||
the mapping function.
|
||||
|
||||
```py
|
||||
>>> def extract_all_chars(batch):
|
||||
... all_text = " ".join(batch["normalized_text"])
|
||||
... vocab = list(set(all_text))
|
||||
... return {"vocab": [vocab], "all_text": [all_text]}
|
||||
|
||||
|
||||
>>> vocabs = dataset.map(
|
||||
... extract_all_chars,
|
||||
... batched=True,
|
||||
... batch_size=-1,
|
||||
... keep_in_memory=True,
|
||||
... remove_columns=dataset.column_names,
|
||||
... )
|
||||
|
||||
>>> dataset_vocab = set(vocabs["vocab"][0])
|
||||
>>> tokenizer_vocab = {k for k, _ in tokenizer.get_vocab().items()}
|
||||
```
|
||||
|
||||
Now you have two sets of characters: one with the vocabulary from the dataset and one with the vocabulary from the tokenizer.
|
||||
To identify any unsupported characters in the dataset, you can take the difference between these two sets. The resulting
|
||||
set will contain the characters that are in the dataset but not in the tokenizer.
|
||||
|
||||
```py
|
||||
>>> dataset_vocab - tokenizer_vocab
|
||||
{' ', 'à', 'ç', 'è', 'ë', 'í', 'ï', 'ö', 'ü'}
|
||||
```
|
||||
|
||||
To handle the unsupported characters identified in the previous step, define a function that maps these characters to
|
||||
valid tokens. Note that spaces are already replaced by `▁` in the tokenizer and don't need to be handled separately.
|
||||
|
||||
```py
|
||||
>>> replacements = [
|
||||
... ("à", "a"),
|
||||
... ("ç", "c"),
|
||||
... ("è", "e"),
|
||||
... ("ë", "e"),
|
||||
... ("í", "i"),
|
||||
... ("ï", "i"),
|
||||
... ("ö", "o"),
|
||||
... ("ü", "u"),
|
||||
... ]
|
||||
|
||||
|
||||
>>> def cleanup_text(inputs):
|
||||
... for src, dst in replacements:
|
||||
... inputs["normalized_text"] = inputs["normalized_text"].replace(src, dst)
|
||||
... return inputs
|
||||
|
||||
|
||||
>>> dataset = dataset.map(cleanup_text)
|
||||
```
|
||||
|
||||
Now that you have dealt with special characters in the text, it's time to shift focus to the audio data.
|
||||
|
||||
### Speakers
|
||||
|
||||
The VoxPopuli dataset includes speech from multiple speakers, but how many speakers are represented in the dataset? To
|
||||
determine this, we can count the number of unique speakers and the number of examples each speaker contributes to the dataset.
|
||||
With a total of 20,968 examples in the dataset, this information will give us a better understanding of the distribution of
|
||||
speakers and examples in the data.
|
||||
|
||||
```py
|
||||
>>> from collections import defaultdict
|
||||
|
||||
>>> speaker_counts = defaultdict(int)
|
||||
|
||||
>>> for speaker_id in dataset["speaker_id"]:
|
||||
... speaker_counts[speaker_id] += 1
|
||||
```
|
||||
|
||||
By plotting a histogram you can get a sense of how much data there is for each speaker.
|
||||
|
||||
```py
|
||||
>>> import matplotlib.pyplot as plt
|
||||
|
||||
>>> plt.figure()
|
||||
>>> plt.hist(speaker_counts.values(), bins=20)
|
||||
>>> plt.ylabel("Speakers")
|
||||
>>> plt.xlabel("Examples")
|
||||
>>> plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/tts_speakers_histogram.png" alt="Speakers histogram"/>
|
||||
</div>
|
||||
|
||||
The histogram reveals that approximately one-third of the speakers in the dataset have fewer than 100 examples, while
|
||||
around ten speakers have more than 500 examples. To improve training efficiency and balance the dataset, we can limit
|
||||
the data to speakers with between 100 and 400 examples.
|
||||
|
||||
```py
|
||||
>>> def select_speaker(speaker_id):
|
||||
... return 100 <= speaker_counts[speaker_id] <= 400
|
||||
|
||||
|
||||
>>> dataset = dataset.filter(select_speaker, input_columns=["speaker_id"])
|
||||
```
|
||||
|
||||
Let's check how many speakers remain:
|
||||
|
||||
```py
|
||||
>>> len(set(dataset["speaker_id"]))
|
||||
42
|
||||
```
|
||||
|
||||
Let's see how many examples are left:
|
||||
|
||||
```py
|
||||
>>> len(dataset)
|
||||
9973
|
||||
```
|
||||
|
||||
You are left with just under 10,000 examples from approximately 40 unique speakers, which should be sufficient.
|
||||
|
||||
Note that some speakers with few examples may actually have more audio available if the examples are long. However,
|
||||
determining the total amount of audio for each speaker requires scanning through the entire dataset, which is a
|
||||
time-consuming process that involves loading and decoding each audio file. As such, we have chosen to skip this step here.
|
||||
|
||||
### Speaker embeddings
|
||||
|
||||
To enable the TTS model to differentiate between multiple speakers, you'll need to create a speaker embedding for each example.
|
||||
The speaker embedding is an additional input into the model that captures a particular speaker's voice characteristics.
|
||||
To generate these speaker embeddings, use the pre-trained [spkrec-xvect-voxceleb](https://huggingface.co/speechbrain/spkrec-xvect-voxceleb)
|
||||
model from SpeechBrain.
|
||||
|
||||
Create a function `create_speaker_embedding()` that takes an input audio waveform and outputs a 512-element vector
|
||||
containing the corresponding speaker embedding.
|
||||
|
||||
```py
|
||||
>>> import os
|
||||
>>> import torch
|
||||
>>> from speechbrain.inference.classifiers import EncoderClassifier
|
||||
>>> from transformers import infer_device
|
||||
|
||||
>>> spk_model_name = "speechbrain/spkrec-xvect-voxceleb"
|
||||
>>> device = infer_device()
|
||||
>>> speaker_model = EncoderClassifier.from_hparams(
|
||||
... source=spk_model_name,
|
||||
... run_opts={"device": device},
|
||||
... savedir=os.path.join("/tmp", spk_model_name),
|
||||
... )
|
||||
|
||||
|
||||
>>> def create_speaker_embedding(waveform):
|
||||
... with torch.no_grad():
|
||||
... speaker_embeddings = speaker_model.encode_batch(torch.tensor(waveform))
|
||||
... speaker_embeddings = torch.nn.functional.normalize(speaker_embeddings, dim=2)
|
||||
... speaker_embeddings = speaker_embeddings.squeeze().cpu().numpy()
|
||||
... return speaker_embeddings
|
||||
```
|
||||
|
||||
It's important to note that the `speechbrain/spkrec-xvect-voxceleb` model was trained on English speech from the VoxCeleb
|
||||
dataset, whereas the training examples in this guide are in Dutch. While we believe that this model will still generate
|
||||
reasonable speaker embeddings for our Dutch dataset, this assumption may not hold true in all cases.
|
||||
|
||||
For optimal results, we recommend training an X-vector model on the target speech first. This will ensure that the model
|
||||
is better able to capture the unique voice characteristics present in the Dutch language.
|
||||
|
||||
### Processing the dataset
|
||||
|
||||
Finally, let's process the data into the format the model expects. Create a `prepare_dataset` function that takes in a
|
||||
single example and uses the `SpeechT5Processor` object to tokenize the input text and load the target audio into a log-mel spectrogram.
|
||||
It should also add the speaker embeddings as an additional input.
|
||||
|
||||
```py
|
||||
>>> def prepare_dataset(example):
|
||||
... audio = example["audio"]
|
||||
|
||||
... example = processor(
|
||||
... text=example["normalized_text"],
|
||||
... audio_target=audio["array"],
|
||||
... sampling_rate=audio["sampling_rate"],
|
||||
... return_attention_mask=False,
|
||||
... )
|
||||
|
||||
... # strip off the batch dimension
|
||||
... example["labels"] = example["labels"][0]
|
||||
|
||||
... # use SpeechBrain to obtain x-vector
|
||||
... example["speaker_embeddings"] = create_speaker_embedding(audio["array"])
|
||||
|
||||
... return example
|
||||
```
|
||||
|
||||
Verify the processing is correct by looking at a single example:
|
||||
|
||||
```py
|
||||
>>> processed_example = prepare_dataset(dataset[0])
|
||||
>>> list(processed_example.keys())
|
||||
['input_ids', 'labels', 'stop_labels', 'speaker_embeddings']
|
||||
```
|
||||
|
||||
Speaker embeddings should be a 512-element vector:
|
||||
|
||||
```py
|
||||
>>> processed_example["speaker_embeddings"].shape
|
||||
(512,)
|
||||
```
|
||||
|
||||
The labels should be a log-mel spectrogram with 80 mel bins.
|
||||
|
||||
```py
|
||||
>>> import matplotlib.pyplot as plt
|
||||
|
||||
>>> plt.figure()
|
||||
>>> plt.imshow(processed_example["labels"].T)
|
||||
>>> plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/tts_logmelspectrogram_1.png" alt="Log-mel spectrogram with 80 mel bins"/>
|
||||
</div>
|
||||
|
||||
Side note: If you find this spectrogram confusing, it may be due to your familiarity with the convention of placing low frequencies
|
||||
at the bottom and high frequencies at the top of a plot. However, when plotting spectrograms as an image using the matplotlib library,
|
||||
the y-axis is flipped and the spectrograms appear upside down.
|
||||
|
||||
Now apply the processing function to the entire dataset. This will take between 5 and 10 minutes.
|
||||
|
||||
```py
|
||||
>>> dataset = dataset.map(prepare_dataset, remove_columns=dataset.column_names)
|
||||
```
|
||||
|
||||
You'll see a warning saying that some examples in the dataset are longer than the maximum input length the model can handle (600 tokens).
|
||||
Remove those examples from the dataset. Here we go even further and to allow for larger batch sizes we remove anything over 200 tokens.
|
||||
|
||||
```py
|
||||
>>> def is_not_too_long(input_ids):
|
||||
... input_length = len(input_ids)
|
||||
... return input_length < 200
|
||||
|
||||
|
||||
>>> dataset = dataset.filter(is_not_too_long, input_columns=["input_ids"])
|
||||
>>> len(dataset)
|
||||
8259
|
||||
```
|
||||
|
||||
Next, create a basic train/test split:
|
||||
|
||||
```py
|
||||
>>> dataset = dataset.train_test_split(test_size=0.1)
|
||||
```
|
||||
|
||||
### Data collator
|
||||
|
||||
In order to combine multiple examples into a batch, you need to define a custom data collator. This collator will pad shorter sequences with padding
|
||||
tokens, ensuring that all examples have the same length. For the spectrogram labels, the padded portions are replaced with the special value `-100`. This special value
|
||||
instructs the model to ignore that part of the spectrogram when calculating the spectrogram loss.
|
||||
|
||||
```py
|
||||
>>> from dataclasses import dataclass
|
||||
>>> from typing import Any, Dict, List, Union
|
||||
|
||||
|
||||
>>> @dataclass
|
||||
... class TTSDataCollatorWithPadding:
|
||||
... processor: Any
|
||||
|
||||
... def __call__(self, features: list[dict[str, Union[list[int], torch.Tensor]]]) -> dict[str, torch.Tensor]:
|
||||
... input_ids = [{"input_ids": feature["input_ids"]} for feature in features]
|
||||
... label_features = [{"input_values": feature["labels"]} for feature in features]
|
||||
... speaker_features = [feature["speaker_embeddings"] for feature in features]
|
||||
|
||||
... # collate the inputs and targets into a batch
|
||||
... batch = processor.pad(input_ids=input_ids, labels=label_features, return_tensors="pt")
|
||||
|
||||
... # replace padding with -100 to ignore loss correctly
|
||||
... batch["labels"] = batch["labels"].masked_fill(batch.decoder_attention_mask.unsqueeze(-1).ne(1), -100)
|
||||
|
||||
... # not used during fine-tuning
|
||||
... del batch["decoder_attention_mask"]
|
||||
|
||||
... # round down target lengths to multiple of reduction factor
|
||||
... if model.config.reduction_factor > 1:
|
||||
... target_lengths = torch.tensor([len(feature["input_values"]) for feature in label_features])
|
||||
... target_lengths = target_lengths.new(
|
||||
... [length - length % model.config.reduction_factor for length in target_lengths]
|
||||
... )
|
||||
... max_length = max(target_lengths)
|
||||
... batch["labels"] = batch["labels"][:, :max_length]
|
||||
|
||||
... # also add in the speaker embeddings
|
||||
... batch["speaker_embeddings"] = torch.tensor(speaker_features)
|
||||
|
||||
... return batch
|
||||
```
|
||||
|
||||
In SpeechT5, the input to the decoder part of the model is reduced by a factor 2. In other words, it throws away every
|
||||
other timestep from the target sequence. The decoder then predicts a sequence that is twice as long. Since the original
|
||||
target sequence length may be odd, the data collator makes sure to round the maximum length of the batch down to be a
|
||||
multiple of 2.
|
||||
|
||||
```py
|
||||
>>> data_collator = TTSDataCollatorWithPadding(processor=processor)
|
||||
```
|
||||
|
||||
## Train the model
|
||||
|
||||
Load the pre-trained model from the same checkpoint as you used for loading the processor:
|
||||
|
||||
```py
|
||||
>>> from transformers import SpeechT5ForTextToSpeech
|
||||
|
||||
>>> model = SpeechT5ForTextToSpeech.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
The `use_cache=True` option is incompatible with gradient checkpointing. Disable it for training.
|
||||
|
||||
```py
|
||||
>>> model.config.use_cache = False
|
||||
```
|
||||
|
||||
Define the training arguments. Here we are not computing any evaluation metrics during the training process. Instead, we'll
|
||||
only look at the loss:
|
||||
|
||||
```python
|
||||
>>> from transformers import Seq2SeqTrainingArguments
|
||||
|
||||
>>> training_args = Seq2SeqTrainingArguments(
|
||||
... output_dir="speecht5_finetuned_voxpopuli_nl", # change to a repo name of your choice
|
||||
... per_device_train_batch_size=4,
|
||||
... gradient_accumulation_steps=8,
|
||||
... learning_rate=1e-5,
|
||||
... warmup_steps=500,
|
||||
... max_steps=4000,
|
||||
... gradient_checkpointing=True,
|
||||
... fp16=True,
|
||||
... eval_strategy="steps",
|
||||
... per_device_eval_batch_size=2,
|
||||
... save_steps=1000,
|
||||
... eval_steps=1000,
|
||||
... logging_steps=25,
|
||||
... report_to=["tensorboard"],
|
||||
... load_best_model_at_end=True,
|
||||
... greater_is_better=False,
|
||||
... label_names=["labels"],
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
```
|
||||
|
||||
Instantiate the `Trainer` object and pass the model, dataset, and data collator to it.
|
||||
|
||||
```py
|
||||
>>> from transformers import Seq2SeqTrainer
|
||||
|
||||
>>> trainer = Seq2SeqTrainer(
|
||||
... args=training_args,
|
||||
... model=model,
|
||||
... train_dataset=dataset["train"],
|
||||
... eval_dataset=dataset["test"],
|
||||
... data_collator=data_collator,
|
||||
... processing_class=processor,
|
||||
... )
|
||||
```
|
||||
|
||||
And with that, you're ready to start training! Training will take several hours. Depending on your GPU,
|
||||
it is possible that you will encounter a CUDA "out-of-memory" error when you start training. In this case, you can reduce
|
||||
the `per_device_train_batch_size` incrementally by factors of 2 and increase `gradient_accumulation_steps` by 2x to compensate.
|
||||
|
||||
```py
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
To be able to use your checkpoint with a pipeline, make sure to save the processor with the checkpoint:
|
||||
|
||||
```py
|
||||
>>> processor.save_pretrained("YOUR_ACCOUNT_NAME/speecht5_finetuned_voxpopuli_nl")
|
||||
```
|
||||
|
||||
Push the final model to the 🤗 Hub:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## Inference
|
||||
|
||||
### Inference with a pipeline
|
||||
|
||||
Great, now that you've fine-tuned a model, you can use it for inference!
|
||||
First, let's see how you can use it with a corresponding pipeline. Let's create a `"text-to-speech"` pipeline with your
|
||||
checkpoint:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> pipe = pipeline("text-to-speech", model="YOUR_ACCOUNT_NAME/speecht5_finetuned_voxpopuli_nl")
|
||||
```
|
||||
|
||||
Pick a piece of text in Dutch you'd like narrated, e.g.:
|
||||
|
||||
```py
|
||||
>>> text = "hallo allemaal, ik praat nederlands. groetjes aan iedereen!"
|
||||
```
|
||||
|
||||
To use SpeechT5 with the pipeline, you'll need a speaker embedding. Let's get it from an example in the test dataset:
|
||||
|
||||
```py
|
||||
>>> example = dataset["test"][304]
|
||||
>>> speaker_embeddings = torch.tensor(example["speaker_embeddings"]).unsqueeze(0)
|
||||
```
|
||||
|
||||
Now you can pass the text and speaker embeddings to the pipeline, and it will take care of the rest:
|
||||
|
||||
```py
|
||||
>>> forward_params = {"speaker_embeddings": speaker_embeddings}
|
||||
>>> output = pipe(text, forward_params=forward_params)
|
||||
>>> output
|
||||
{'audio': array([-6.82714235e-05, -4.26525949e-04, 1.06134125e-04, ...,
|
||||
-1.22392643e-03, -7.76011671e-04, 3.29112721e-04], dtype=float32),
|
||||
'sampling_rate': 16000}
|
||||
```
|
||||
|
||||
You can then listen to the result:
|
||||
|
||||
```py
|
||||
>>> from IPython.display import Audio
|
||||
>>> Audio(output['audio'], rate=output['sampling_rate'])
|
||||
```
|
||||
|
||||
### Run inference manually
|
||||
|
||||
You can achieve the same inference results without using the pipeline, however, more steps will be required.
|
||||
|
||||
Load the model from the 🤗 Hub:
|
||||
|
||||
```py
|
||||
>>> model = SpeechT5ForTextToSpeech.from_pretrained("YOUR_ACCOUNT/speecht5_finetuned_voxpopuli_nl")
|
||||
```
|
||||
|
||||
Pick an example from the test dataset obtain a speaker embedding.
|
||||
|
||||
```py
|
||||
>>> example = dataset["test"][304]
|
||||
>>> speaker_embeddings = torch.tensor(example["speaker_embeddings"]).unsqueeze(0)
|
||||
```
|
||||
|
||||
Define the input text and tokenize it.
|
||||
|
||||
```py
|
||||
>>> text = "hallo allemaal, ik praat nederlands. groetjes aan iedereen!"
|
||||
>>> inputs = processor(text=text, return_tensors="pt")
|
||||
```
|
||||
|
||||
Create a spectrogram with your model:
|
||||
|
||||
```py
|
||||
>>> spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings)
|
||||
```
|
||||
|
||||
Visualize the spectrogram, if you'd like to:
|
||||
|
||||
```py
|
||||
>>> plt.figure()
|
||||
>>> plt.imshow(spectrogram.T)
|
||||
>>> plt.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/tts_logmelspectrogram_2.png" alt="Generated log-mel spectrogram"/>
|
||||
</div>
|
||||
|
||||
Finally, use the vocoder to turn the spectrogram into sound.
|
||||
|
||||
```py
|
||||
>>> with torch.no_grad():
|
||||
... speech = vocoder(spectrogram)
|
||||
|
||||
>>> from IPython.display import Audio
|
||||
|
||||
>>> Audio(speech.numpy(), rate=16000)
|
||||
```
|
||||
|
||||
In our experience, obtaining satisfactory results from this model can be challenging. The quality of the speaker
|
||||
embeddings appears to be a significant factor. Since SpeechT5 was pre-trained with English x-vectors, it performs best
|
||||
when using English speaker embeddings. If the synthesized speech sounds poor, try using a different speaker embedding.
|
||||
|
||||
Increasing the training duration is also likely to enhance the quality of the results. Even so, the speech clearly is Dutch instead of English, and it does
|
||||
capture the voice characteristics of the speaker (compare to the original audio in the example).
|
||||
Another thing to experiment with is the model's configuration. For example, try using `config.reduction_factor = 1` to
|
||||
see if this improves the results.
|
||||
|
||||
Finally, it is essential to consider ethical considerations. Although TTS technology has numerous useful applications, it
|
||||
may also be used for malicious purposes, such as impersonating someone's voice without their knowledge or consent. Please
|
||||
use TTS judiciously and responsibly.
|
||||
400
transformers/docs/source/en/tasks/token_classification.md
Normal file
400
transformers/docs/source/en/tasks/token_classification.md
Normal file
@@ -0,0 +1,400 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Token classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="wVHdVlPScxA"/>
|
||||
|
||||
Token classification assigns a label to individual tokens in a sentence. One of the most common token classification tasks is Named Entity Recognition (NER). NER attempts to find a label for each entity in a sentence, such as a person, location, or organization.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) on the [WNUT 17](https://huggingface.co/datasets/wnut_17) dataset to detect new entities.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/token-classification).
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate seqeval
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load WNUT 17 dataset
|
||||
|
||||
Start by loading the WNUT 17 dataset from the 🤗 Datasets library:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> wnut = load_dataset("wnut_17")
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> wnut["train"][0]
|
||||
{'id': '0',
|
||||
'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
'tokens': ['@paulwalk', 'It', "'s", 'the', 'view', 'from', 'where', 'I', "'m", 'living', 'for', 'two', 'weeks', '.', 'Empire', 'State', 'Building', '=', 'ESB', '.', 'Pretty', 'bad', 'storm', 'here', 'last', 'evening', '.']
|
||||
}
|
||||
```
|
||||
|
||||
Each number in `ner_tags` represents an entity. Convert the numbers to their label names to find out what the entities are:
|
||||
|
||||
```py
|
||||
>>> label_list = wnut["train"].features[f"ner_tags"].feature.names
|
||||
>>> label_list
|
||||
[
|
||||
"O",
|
||||
"B-corporation",
|
||||
"I-corporation",
|
||||
"B-creative-work",
|
||||
"I-creative-work",
|
||||
"B-group",
|
||||
"I-group",
|
||||
"B-location",
|
||||
"I-location",
|
||||
"B-person",
|
||||
"I-person",
|
||||
"B-product",
|
||||
"I-product",
|
||||
]
|
||||
```
|
||||
|
||||
The letter that prefixes each `ner_tag` indicates the token position of the entity:
|
||||
|
||||
- `B-` indicates the beginning of an entity.
|
||||
- `I-` indicates a token is contained inside the same entity (for example, the `State` token is a part of an entity like
|
||||
`Empire State Building`).
|
||||
- `0` indicates the token doesn't correspond to any entity.
|
||||
|
||||
## Preprocess
|
||||
|
||||
<Youtube id="iY2AZYdZAr0"/>
|
||||
|
||||
The next step is to load a DistilBERT tokenizer to preprocess the `tokens` field:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
As you saw in the example `tokens` field above, it looks like the input has already been tokenized. But the input actually hasn't been tokenized yet and you'll need to set `is_split_into_words=True` to tokenize the words into subwords. For example:
|
||||
|
||||
```py
|
||||
>>> example = wnut["train"][0]
|
||||
>>> tokenized_input = tokenizer(example["tokens"], is_split_into_words=True)
|
||||
>>> tokens = tokenizer.convert_ids_to_tokens(tokenized_input["input_ids"])
|
||||
>>> tokens
|
||||
['[CLS]', '@', 'paul', '##walk', 'it', "'", 's', 'the', 'view', 'from', 'where', 'i', "'", 'm', 'living', 'for', 'two', 'weeks', '.', 'empire', 'state', 'building', '=', 'es', '##b', '.', 'pretty', 'bad', 'storm', 'here', 'last', 'evening', '.', '[SEP]']
|
||||
```
|
||||
|
||||
However, this adds some special tokens `[CLS]` and `[SEP]` and the subword tokenization creates a mismatch between the input and labels. A single word corresponding to a single label may now be split into two subwords. You'll need to realign the tokens and labels by:
|
||||
|
||||
1. Mapping all tokens to their corresponding word with the [`word_ids`](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.BatchEncoding.word_ids) method.
|
||||
2. Assigning the label `-100` to the special tokens `[CLS]` and `[SEP]` so they're ignored by the PyTorch loss function (see [CrossEntropyLoss](https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html)).
|
||||
3. Only labeling the first token of a given word. Assign `-100` to other subtokens from the same word.
|
||||
|
||||
Here is how you can create a function to realign the tokens and labels, and truncate sequences to be no longer than DistilBERT's maximum input length:
|
||||
|
||||
```py
|
||||
>>> def tokenize_and_align_labels(examples):
|
||||
... tokenized_inputs = tokenizer(examples["tokens"], truncation=True, is_split_into_words=True)
|
||||
|
||||
... labels = []
|
||||
... for i, label in enumerate(examples[f"ner_tags"]):
|
||||
... word_ids = tokenized_inputs.word_ids(batch_index=i) # Map tokens to their respective word.
|
||||
... previous_word_idx = None
|
||||
... label_ids = []
|
||||
... for word_idx in word_ids: # Set the special tokens to -100.
|
||||
... if word_idx is None:
|
||||
... label_ids.append(-100)
|
||||
... elif word_idx != previous_word_idx: # Only label the first token of a given word.
|
||||
... label_ids.append(label[word_idx])
|
||||
... else:
|
||||
... label_ids.append(-100)
|
||||
... previous_word_idx = word_idx
|
||||
... labels.append(label_ids)
|
||||
|
||||
... tokenized_inputs["labels"] = labels
|
||||
... return tokenized_inputs
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] function. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once:
|
||||
|
||||
```py
|
||||
>>> tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DataCollatorWithPadding`]. It's more efficient to *dynamically pad* the sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForTokenClassification
|
||||
|
||||
>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load a evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [seqeval](https://huggingface.co/spaces/evaluate-metric/seqeval) framework (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric). Seqeval actually produces several scores: precision, recall, F1, and accuracy.
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> seqeval = evaluate.load("seqeval")
|
||||
```
|
||||
|
||||
Get the NER labels first, and then create a function that passes your true predictions and true labels to [`~evaluate.EvaluationModule.compute`] to calculate the scores:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
>>> labels = [label_list[i] for i in example[f"ner_tags"]]
|
||||
|
||||
|
||||
>>> def compute_metrics(p):
|
||||
... predictions, labels = p
|
||||
... predictions = np.argmax(predictions, axis=2)
|
||||
|
||||
... true_predictions = [
|
||||
... [label_list[p] for (p, l) in zip(prediction, label) if l != -100]
|
||||
... for prediction, label in zip(predictions, labels)
|
||||
... ]
|
||||
... true_labels = [
|
||||
... [label_list[l] for (p, l) in zip(prediction, label) if l != -100]
|
||||
... for prediction, label in zip(predictions, labels)
|
||||
... ]
|
||||
|
||||
... results = seqeval.compute(predictions=true_predictions, references=true_labels)
|
||||
... return {
|
||||
... "precision": results["overall_precision"],
|
||||
... "recall": results["overall_recall"],
|
||||
... "f1": results["overall_f1"],
|
||||
... "accuracy": results["overall_accuracy"],
|
||||
... }
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
Before you start training your model, create a map of the expected ids to their labels with `id2label` and `label2id`:
|
||||
|
||||
```py
|
||||
>>> id2label = {
|
||||
... 0: "O",
|
||||
... 1: "B-corporation",
|
||||
... 2: "I-corporation",
|
||||
... 3: "B-creative-work",
|
||||
... 4: "I-creative-work",
|
||||
... 5: "B-group",
|
||||
... 6: "I-group",
|
||||
... 7: "B-location",
|
||||
... 8: "I-location",
|
||||
... 9: "B-person",
|
||||
... 10: "I-person",
|
||||
... 11: "B-product",
|
||||
... 12: "I-product",
|
||||
... }
|
||||
>>> label2id = {
|
||||
... "O": 0,
|
||||
... "B-corporation": 1,
|
||||
... "I-corporation": 2,
|
||||
... "B-creative-work": 3,
|
||||
... "I-creative-work": 4,
|
||||
... "B-group": 5,
|
||||
... "I-group": 6,
|
||||
... "B-location": 7,
|
||||
... "I-location": 8,
|
||||
... "B-person": 9,
|
||||
... "I-person": 10,
|
||||
... "B-product": 11,
|
||||
... "I-product": 12,
|
||||
... }
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load DistilBERT with [`AutoModelForTokenClassification`] along with the number of expected labels, and the label mappings:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForTokenClassification.from_pretrained(
|
||||
... "distilbert/distilbert-base-uncased", num_labels=13, id2label=id2label, label2id=label2id
|
||||
... )
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the seqeval scores and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="my_awesome_wnut_model",
|
||||
... learning_rate=2e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... per_device_eval_batch_size=16,
|
||||
... num_train_epochs=2,
|
||||
... weight_decay=0.01,
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... load_best_model_at_end=True,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=tokenized_wnut["train"],
|
||||
... eval_dataset=tokenized_wnut["test"],
|
||||
... processing_class=tokenizer,
|
||||
... data_collator=data_collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for token classification, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Grab some text you'd like to run inference on:
|
||||
|
||||
```py
|
||||
>>> text = "The Golden State Warriors are an American professional basketball team based in San Francisco."
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for NER with your model, and pass your text to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> classifier = pipeline("ner", model="stevhliu/my_awesome_wnut_model")
|
||||
>>> classifier(text)
|
||||
[{'entity': 'B-location',
|
||||
'score': 0.42658573,
|
||||
'index': 2,
|
||||
'word': 'golden',
|
||||
'start': 4,
|
||||
'end': 10},
|
||||
{'entity': 'I-location',
|
||||
'score': 0.35856336,
|
||||
'index': 3,
|
||||
'word': 'state',
|
||||
'start': 11,
|
||||
'end': 16},
|
||||
{'entity': 'B-group',
|
||||
'score': 0.3064001,
|
||||
'index': 4,
|
||||
'word': 'warriors',
|
||||
'start': 17,
|
||||
'end': 25},
|
||||
{'entity': 'B-location',
|
||||
'score': 0.65523505,
|
||||
'index': 13,
|
||||
'word': 'san',
|
||||
'start': 80,
|
||||
'end': 83},
|
||||
{'entity': 'B-location',
|
||||
'score': 0.4668663,
|
||||
'index': 14,
|
||||
'word': 'francisco',
|
||||
'start': 84,
|
||||
'end': 93}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Tokenize the text and return PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
```
|
||||
|
||||
Pass your inputs to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForTokenClassification
|
||||
|
||||
>>> model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
Get the class with the highest probability, and use the model's `id2label` mapping to convert it to a text label:
|
||||
|
||||
```py
|
||||
>>> predictions = torch.argmax(logits, dim=2)
|
||||
>>> predicted_token_class = [model.config.id2label[t.item()] for t in predictions[0]]
|
||||
>>> predicted_token_class
|
||||
['O',
|
||||
'O',
|
||||
'B-location',
|
||||
'I-location',
|
||||
'B-group',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'O',
|
||||
'B-location',
|
||||
'B-location',
|
||||
'O',
|
||||
'O']
|
||||
```
|
||||
279
transformers/docs/source/en/tasks/translation.md
Normal file
279
transformers/docs/source/en/tasks/translation.md
Normal file
@@ -0,0 +1,279 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Translation
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="1JvfrvZgi6c"/>
|
||||
|
||||
Translation converts a sequence of text from one language to another. It is one of several tasks you can formulate as a sequence-to-sequence problem, a powerful framework for returning some output from an input, like translation or summarization. Translation systems are commonly used for translation between different language texts, but it can also be used for speech or some combination in between like text-to-speech or speech-to-text.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Finetune [T5](https://huggingface.co/google-t5/t5-small) on the English-French subset of the [OPUS Books](https://huggingface.co/datasets/opus_books) dataset to translate English text to French.
|
||||
2. Use your finetuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/translation).
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate sacrebleu
|
||||
```
|
||||
|
||||
We encourage you to login to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to login:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load OPUS Books dataset
|
||||
|
||||
Start by loading the English-French subset of the [OPUS Books](https://huggingface.co/datasets/opus_books) dataset from the 🤗 Datasets library:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> books = load_dataset("opus_books", "en-fr")
|
||||
```
|
||||
|
||||
Split the dataset into a train and test set with the [`~datasets.Dataset.train_test_split`] method:
|
||||
|
||||
```py
|
||||
>>> books = books["train"].train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
Then take a look at an example:
|
||||
|
||||
```py
|
||||
>>> books["train"][0]
|
||||
{'id': '90560',
|
||||
'translation': {'en': 'But this lofty plateau measured only a few fathoms, and soon we reentered Our Element.',
|
||||
'fr': 'Mais ce plateau élevé ne mesurait que quelques toises, et bientôt nous fûmes rentrés dans notre élément.'}}
|
||||
```
|
||||
|
||||
`translation`: an English and French translation of the text.
|
||||
|
||||
## Preprocess
|
||||
|
||||
<Youtube id="XAR8jnZZuUs"/>
|
||||
|
||||
The next step is to load a T5 tokenizer to process the English-French language pairs:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> checkpoint = "google-t5/t5-small"
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
The preprocessing function you want to create needs to:
|
||||
|
||||
1. Prefix the input with a prompt so T5 knows this is a translation task. Some models capable of multiple NLP tasks require prompting for specific tasks.
|
||||
2. Set the target language (French) in the `text_target` parameter to ensure the tokenizer processes the target text correctly. If you don't set `text_target`, the tokenizer processes the target text as English.
|
||||
3. Truncate sequences to be no longer than the maximum length set by the `max_length` parameter.
|
||||
|
||||
```py
|
||||
>>> source_lang = "en"
|
||||
>>> target_lang = "fr"
|
||||
>>> prefix = "translate English to French: "
|
||||
|
||||
|
||||
>>> def preprocess_function(examples):
|
||||
... inputs = [prefix + example[source_lang] for example in examples["translation"]]
|
||||
... targets = [example[target_lang] for example in examples["translation"]]
|
||||
... model_inputs = tokenizer(inputs, text_target=targets, max_length=128, truncation=True)
|
||||
... return model_inputs
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.Dataset.map`] method. You can speed up the `map` function by setting `batched=True` to process multiple elements of the dataset at once:
|
||||
|
||||
```py
|
||||
>>> tokenized_books = books.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
Now create a batch of examples using [`DataCollatorForSeq2Seq`]. It's more efficient to *dynamically pad* the sentences to the longest length in a batch during collation, instead of padding the whole dataset to the maximum length.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForSeq2Seq
|
||||
|
||||
>>> data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=checkpoint)
|
||||
```
|
||||
|
||||
## Evaluate
|
||||
|
||||
Including a metric during training is often helpful for evaluating your model's performance. You can quickly load a evaluation method with the 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) library. For this task, load the [SacreBLEU](https://huggingface.co/spaces/evaluate-metric/sacrebleu) metric (see the 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) to learn more about how to load and compute a metric):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> metric = evaluate.load("sacrebleu")
|
||||
```
|
||||
|
||||
Then create a function that passes your predictions and labels to [`~evaluate.EvaluationModule.compute`] to calculate the SacreBLEU score:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
|
||||
>>> def postprocess_text(preds, labels):
|
||||
... preds = [pred.strip() for pred in preds]
|
||||
... labels = [[label.strip()] for label in labels]
|
||||
|
||||
... return preds, labels
|
||||
|
||||
|
||||
>>> def compute_metrics(eval_preds):
|
||||
... preds, labels = eval_preds
|
||||
... if isinstance(preds, tuple):
|
||||
... preds = preds[0]
|
||||
... decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)
|
||||
|
||||
... labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
|
||||
... decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
|
||||
|
||||
... decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels)
|
||||
|
||||
... result = metric.compute(predictions=decoded_preds, references=decoded_labels)
|
||||
... result = {"bleu": result["score"]}
|
||||
|
||||
... prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds]
|
||||
... result["gen_len"] = np.mean(prediction_lens)
|
||||
... result = {k: round(v, 4) for k, v in result.items()}
|
||||
... return result
|
||||
```
|
||||
|
||||
Your `compute_metrics` function is ready to go now, and you'll return to it when you setup your training.
|
||||
|
||||
## Train
|
||||
|
||||
<Tip>
|
||||
|
||||
If you aren't familiar with finetuning a model with the [`Trainer`], take a look at the basic tutorial [here](../training#train-with-pytorch-trainer)!
|
||||
|
||||
</Tip>
|
||||
|
||||
You're ready to start training your model now! Load T5 with [`AutoModelForSeq2SeqLM`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSeq2SeqLM, Seq2SeqTrainingArguments, Seq2SeqTrainer
|
||||
|
||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`Seq2SeqTrainingArguments`]. The only required parameter is `output_dir` which specifies where to save your model. You'll push this model to the Hub by setting `push_to_hub=True` (you need to be signed in to Hugging Face to upload your model). At the end of each epoch, the [`Trainer`] will evaluate the SacreBLEU metric and save the training checkpoint.
|
||||
2. Pass the training arguments to [`Seq2SeqTrainer`] along with the model, dataset, tokenizer, data collator, and `compute_metrics` function.
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> training_args = Seq2SeqTrainingArguments(
|
||||
... output_dir="my_awesome_opus_books_model",
|
||||
... eval_strategy="epoch",
|
||||
... learning_rate=2e-5,
|
||||
... per_device_train_batch_size=16,
|
||||
... per_device_eval_batch_size=16,
|
||||
... weight_decay=0.01,
|
||||
... save_total_limit=3,
|
||||
... num_train_epochs=2,
|
||||
... predict_with_generate=True,
|
||||
... fp16=True, #change to bf16=True for XPU
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
|
||||
>>> trainer = Seq2SeqTrainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... train_dataset=tokenized_books["train"],
|
||||
... eval_dataset=tokenized_books["test"],
|
||||
... processing_class=tokenizer,
|
||||
... data_collator=data_collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune a model for translation, take a look at the corresponding
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you've finetuned a model, you can use it for inference!
|
||||
|
||||
Come up with some text you'd like to translate to another language. For T5, you need to prefix your input depending on the task you're working on. For translation from English to French, you should prefix your input as shown below:
|
||||
|
||||
```py
|
||||
>>> text = "translate English to French: Legumes share resources with nitrogen-fixing bacteria."
|
||||
```
|
||||
|
||||
The simplest way to try out your finetuned model for inference is to use it in a [`pipeline`]. Instantiate a `pipeline` for translation with your model, and pass your text to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
# Change `xx` to the language of the input and `yy` to the language of the desired output.
|
||||
# Examples: "en" for English, "fr" for French, "de" for German, "es" for Spanish, "zh" for Chinese, etc; translation_en_to_fr translates English to French
|
||||
# You can view all the lists of languages here - https://huggingface.co/languages
|
||||
>>> translator = pipeline("translation_xx_to_yy", model="username/my_awesome_opus_books_model")
|
||||
>>> translator(text)
|
||||
[{'translation_text': 'Legumes partagent des ressources avec des bactéries azotantes.'}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like:
|
||||
|
||||
Tokenize the text and return the `input_ids` as PyTorch tensors:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_opus_books_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt").input_ids
|
||||
```
|
||||
|
||||
Use the [`~generation.GenerationMixin.generate`] method to create the translation. For more details about the different text generation strategies and parameters for controlling generation, check out the [Text Generation](../main_classes/text_generation) API.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSeq2SeqLM
|
||||
|
||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained("username/my_awesome_opus_books_model")
|
||||
>>> outputs = model.generate(inputs, max_new_tokens=40, do_sample=True, top_k=30, top_p=0.95)
|
||||
```
|
||||
|
||||
Decode the generated token ids back into text:
|
||||
|
||||
```py
|
||||
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
|
||||
'Les lignées partagent des ressources avec des bactéries enfixant l'azote.'
|
||||
```
|
||||
514
transformers/docs/source/en/tasks/video_classification.md
Normal file
514
transformers/docs/source/en/tasks/video_classification.md
Normal file
@@ -0,0 +1,514 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Video classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Video classification is the task of assigning a label or class to an entire video. Videos are expected to have only one class for each video. Video classification models take a video as input and return a prediction about which class the video belongs to. These models can be used to categorize what a video is all about. A real-world application of video classification is action / activity recognition, which is useful for fitness applications. It is also helpful for vision-impaired individuals, especially when they are commuting.
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
1. Fine-tune [VideoMAE](https://huggingface.co/docs/transformers/main/en/model_doc/videomae) on a subset of the [UCF101](https://www.crcv.ucf.edu/data/UCF101.php) dataset.
|
||||
2. Use your fine-tuned model for inference.
|
||||
|
||||
<Tip>
|
||||
|
||||
To see all architectures and checkpoints compatible with this task, we recommend checking the [task-page](https://huggingface.co/tasks/video-classification).
|
||||
|
||||
</Tip>
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install -q pytorchvideo transformers evaluate
|
||||
```
|
||||
|
||||
You will use [PyTorchVideo](https://pytorchvideo.org/) (dubbed `pytorchvideo`) to process and prepare the videos.
|
||||
|
||||
We encourage you to log in to your Hugging Face account so you can upload and share your model with the community. When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Load UCF101 dataset
|
||||
|
||||
Start by loading a subset of the [UCF-101 dataset](https://www.crcv.ucf.edu/data/UCF101.php). This will give you a chance to experiment and make sure everything works before spending more time training on the full dataset.
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import hf_hub_download
|
||||
|
||||
>>> hf_dataset_identifier = "sayakpaul/ucf101-subset"
|
||||
>>> filename = "UCF101_subset.tar.gz"
|
||||
>>> file_path = hf_hub_download(repo_id=hf_dataset_identifier, filename=filename, repo_type="dataset")
|
||||
```
|
||||
|
||||
After the subset has been downloaded, you need to extract the compressed archive:
|
||||
|
||||
```py
|
||||
>>> import tarfile
|
||||
|
||||
>>> with tarfile.open(file_path) as t:
|
||||
... t.extractall(".")
|
||||
```
|
||||
|
||||
At a high level, the dataset is organized like so:
|
||||
|
||||
```bash
|
||||
UCF101_subset/
|
||||
train/
|
||||
BandMarching/
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
Archery
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
...
|
||||
val/
|
||||
BandMarching/
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
Archery
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
...
|
||||
test/
|
||||
BandMarching/
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
Archery
|
||||
video_1.mp4
|
||||
video_2.mp4
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
You can then count the number of total videos.
|
||||
|
||||
```py
|
||||
>>> import pathlib
|
||||
>>> dataset_root_path = "UCF101_subset"
|
||||
>>> dataset_root_path = pathlib.Path(dataset_root_path)
|
||||
```
|
||||
|
||||
```py
|
||||
>>> video_count_train = len(list(dataset_root_path.glob("train/*/*.avi")))
|
||||
>>> video_count_val = len(list(dataset_root_path.glob("val/*/*.avi")))
|
||||
>>> video_count_test = len(list(dataset_root_path.glob("test/*/*.avi")))
|
||||
>>> video_total = video_count_train + video_count_val + video_count_test
|
||||
>>> print(f"Total videos: {video_total}")
|
||||
```
|
||||
|
||||
```py
|
||||
>>> all_video_file_paths = (
|
||||
... list(dataset_root_path.glob("train/*/*.avi"))
|
||||
... + list(dataset_root_path.glob("val/*/*.avi"))
|
||||
... + list(dataset_root_path.glob("test/*/*.avi"))
|
||||
... )
|
||||
>>> all_video_file_paths[:5]
|
||||
```
|
||||
|
||||
The (`sorted`) video paths appear like so:
|
||||
|
||||
```bash
|
||||
...
|
||||
'UCF101_subset/train/ApplyEyeMakeup/v_ApplyEyeMakeup_g07_c04.avi',
|
||||
'UCF101_subset/train/ApplyEyeMakeup/v_ApplyEyeMakeup_g07_c06.avi',
|
||||
'UCF101_subset/train/ApplyEyeMakeup/v_ApplyEyeMakeup_g08_c01.avi',
|
||||
'UCF101_subset/train/ApplyEyeMakeup/v_ApplyEyeMakeup_g09_c02.avi',
|
||||
'UCF101_subset/train/ApplyEyeMakeup/v_ApplyEyeMakeup_g09_c06.avi'
|
||||
...
|
||||
```
|
||||
|
||||
You will notice that there are video clips belonging to the same group / scene where group is denoted by `g` in the video file paths. `v_ApplyEyeMakeup_g07_c04.avi` and `v_ApplyEyeMakeup_g07_c06.avi`, for example.
|
||||
|
||||
For the validation and evaluation splits, you wouldn't want to have video clips from the same group / scene to prevent [data leakage](https://www.kaggle.com/code/alexisbcook/data-leakage). The subset that you are using in this tutorial takes this information into account.
|
||||
|
||||
Next up, you will derive the set of labels present in the dataset. Also, create two dictionaries that'll be helpful when initializing the model:
|
||||
|
||||
* `label2id`: maps the class names to integers.
|
||||
* `id2label`: maps the integers to class names.
|
||||
|
||||
```py
|
||||
>>> class_labels = sorted({str(path).split("/")[2] for path in all_video_file_paths})
|
||||
>>> label2id = {label: i for i, label in enumerate(class_labels)}
|
||||
>>> id2label = {i: label for label, i in label2id.items()}
|
||||
|
||||
>>> print(f"Unique classes: {list(label2id.keys())}.")
|
||||
|
||||
# Unique classes: ['ApplyEyeMakeup', 'ApplyLipstick', 'Archery', 'BabyCrawling', 'BalanceBeam', 'BandMarching', 'BaseballPitch', 'Basketball', 'BasketballDunk', 'BenchPress'].
|
||||
```
|
||||
|
||||
There are 10 unique classes. For each class, there are 30 videos in the training set.
|
||||
|
||||
## Load a model to fine-tune
|
||||
|
||||
Instantiate a video classification model from a pretrained checkpoint and its associated image processor. The model's encoder comes with pre-trained parameters, and the classification head is randomly initialized. The image processor will come in handy when writing the preprocessing pipeline for our dataset.
|
||||
|
||||
```py
|
||||
>>> from transformers import VideoMAEImageProcessor, VideoMAEForVideoClassification
|
||||
|
||||
>>> model_ckpt = "MCG-NJU/videomae-base"
|
||||
>>> image_processor = VideoMAEImageProcessor.from_pretrained(model_ckpt)
|
||||
>>> model = VideoMAEForVideoClassification.from_pretrained(
|
||||
... model_ckpt,
|
||||
... label2id=label2id,
|
||||
... id2label=id2label,
|
||||
... ignore_mismatched_sizes=True, # provide this in case you're planning to fine-tune an already fine-tuned checkpoint
|
||||
... )
|
||||
```
|
||||
|
||||
While the model is loading, you might notice the following warning:
|
||||
|
||||
```bash
|
||||
Some weights of the model checkpoint at MCG-NJU/videomae-base were not used when initializing VideoMAEForVideoClassification: [..., 'decoder.decoder_layers.1.attention.output.dense.bias', 'decoder.decoder_layers.2.attention.attention.key.weight']
|
||||
- This IS expected if you are initializing VideoMAEForVideoClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
|
||||
- This IS NOT expected if you are initializing VideoMAEForVideoClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
|
||||
Some weights of VideoMAEForVideoClassification were not initialized from the model checkpoint at MCG-NJU/videomae-base and are newly initialized: ['classifier.bias', 'classifier.weight']
|
||||
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
|
||||
```
|
||||
|
||||
The warning is telling us we are throwing away some weights (e.g. the weights and bias of the `classifier` layer) and randomly initializing some others (the weights and bias of a new `classifier` layer). This is expected in this case, because we are adding a new head for which we don't have pretrained weights, so the library warns us we should fine-tune this model before using it for inference, which is exactly what we are going to do.
|
||||
|
||||
**Note** that [this checkpoint](https://huggingface.co/MCG-NJU/videomae-base-finetuned-kinetics) leads to better performance on this task as the checkpoint was obtained fine-tuning on a similar downstream task having considerable domain overlap. You can check out [this checkpoint](https://huggingface.co/sayakpaul/videomae-base-finetuned-kinetics-finetuned-ucf101-subset) which was obtained by fine-tuning `MCG-NJU/videomae-base-finetuned-kinetics`.
|
||||
|
||||
## Prepare the datasets for training
|
||||
|
||||
For preprocessing the videos, you will leverage the [PyTorchVideo library](https://pytorchvideo.org/). Start by importing the dependencies we need.
|
||||
|
||||
```py
|
||||
>>> import pytorchvideo.data
|
||||
|
||||
>>> from pytorchvideo.transforms import (
|
||||
... ApplyTransformToKey,
|
||||
... Normalize,
|
||||
... RandomShortSideScale,
|
||||
... RemoveKey,
|
||||
... ShortSideScale,
|
||||
... UniformTemporalSubsample,
|
||||
... )
|
||||
|
||||
>>> from torchvision.transforms import (
|
||||
... Compose,
|
||||
... Lambda,
|
||||
... RandomCrop,
|
||||
... RandomHorizontalFlip,
|
||||
... Resize,
|
||||
... )
|
||||
```
|
||||
|
||||
For the training dataset transformations, use a combination of uniform temporal subsampling, pixel normalization, random cropping, and random horizontal flipping. For the validation and evaluation dataset transformations, keep the same transformation chain except for random cropping and horizontal flipping. To learn more about the details of these transformations check out the [official documentation of PyTorchVideo](https://pytorchvideo.org).
|
||||
|
||||
Use the `image_processor` associated with the pre-trained model to obtain the following information:
|
||||
|
||||
* Image mean and standard deviation with which the video frame pixels will be normalized.
|
||||
* Spatial resolution to which the video frames will be resized.
|
||||
|
||||
Start by defining some constants.
|
||||
|
||||
```py
|
||||
>>> mean = image_processor.image_mean
|
||||
>>> std = image_processor.image_std
|
||||
>>> if "shortest_edge" in image_processor.size:
|
||||
... height = width = image_processor.size["shortest_edge"]
|
||||
>>> else:
|
||||
... height = image_processor.size["height"]
|
||||
... width = image_processor.size["width"]
|
||||
>>> resize_to = (height, width)
|
||||
|
||||
>>> num_frames_to_sample = model.config.num_frames
|
||||
>>> sample_rate = 4
|
||||
>>> fps = 30
|
||||
>>> clip_duration = num_frames_to_sample * sample_rate / fps
|
||||
```
|
||||
|
||||
Now, define the dataset-specific transformations and the datasets respectively. Starting with the training set:
|
||||
|
||||
```py
|
||||
>>> train_transform = Compose(
|
||||
... [
|
||||
... ApplyTransformToKey(
|
||||
... key="video",
|
||||
... transform=Compose(
|
||||
... [
|
||||
... UniformTemporalSubsample(num_frames_to_sample),
|
||||
... Lambda(lambda x: x / 255.0),
|
||||
... Normalize(mean, std),
|
||||
... RandomShortSideScale(min_size=256, max_size=320),
|
||||
... RandomCrop(resize_to),
|
||||
... RandomHorizontalFlip(p=0.5),
|
||||
... ]
|
||||
... ),
|
||||
... ),
|
||||
... ]
|
||||
... )
|
||||
|
||||
>>> train_dataset = pytorchvideo.data.Ucf101(
|
||||
... data_path=os.path.join(dataset_root_path, "train"),
|
||||
... clip_sampler=pytorchvideo.data.make_clip_sampler("random", clip_duration),
|
||||
... decode_audio=False,
|
||||
... transform=train_transform,
|
||||
... )
|
||||
```
|
||||
|
||||
The same sequence of workflow can be applied to the validation and evaluation sets:
|
||||
|
||||
```py
|
||||
>>> val_transform = Compose(
|
||||
... [
|
||||
... ApplyTransformToKey(
|
||||
... key="video",
|
||||
... transform=Compose(
|
||||
... [
|
||||
... UniformTemporalSubsample(num_frames_to_sample),
|
||||
... Lambda(lambda x: x / 255.0),
|
||||
... Normalize(mean, std),
|
||||
... Resize(resize_to),
|
||||
... ]
|
||||
... ),
|
||||
... ),
|
||||
... ]
|
||||
... )
|
||||
|
||||
>>> val_dataset = pytorchvideo.data.Ucf101(
|
||||
... data_path=os.path.join(dataset_root_path, "val"),
|
||||
... clip_sampler=pytorchvideo.data.make_clip_sampler("uniform", clip_duration),
|
||||
... decode_audio=False,
|
||||
... transform=val_transform,
|
||||
... )
|
||||
|
||||
>>> test_dataset = pytorchvideo.data.Ucf101(
|
||||
... data_path=os.path.join(dataset_root_path, "test"),
|
||||
... clip_sampler=pytorchvideo.data.make_clip_sampler("uniform", clip_duration),
|
||||
... decode_audio=False,
|
||||
... transform=val_transform,
|
||||
... )
|
||||
```
|
||||
|
||||
**Note**: The above dataset pipelines are taken from the [official PyTorchVideo example](https://pytorchvideo.org/docs/tutorial_classification#dataset). We're using the [`pytorchvideo.data.Ucf101()`](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html#pytorchvideo.data.Ucf101) function because it's tailored for the UCF-101 dataset. Under the hood, it returns a [`pytorchvideo.data.labeled_video_dataset.LabeledVideoDataset`](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html#pytorchvideo.data.LabeledVideoDataset) object. `LabeledVideoDataset` class is the base class for all things video in the PyTorchVideo dataset. So, if you want to use a custom dataset not supported off-the-shelf by PyTorchVideo, you can extend the `LabeledVideoDataset` class accordingly. Refer to the `data` API [documentation to](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html) learn more. Also, if your dataset follows a similar structure (as shown above), then using the `pytorchvideo.data.Ucf101()` should work just fine.
|
||||
|
||||
You can access the `num_videos` argument to know the number of videos in the dataset.
|
||||
|
||||
```py
|
||||
>>> print(train_dataset.num_videos, val_dataset.num_videos, test_dataset.num_videos)
|
||||
# (300, 30, 75)
|
||||
```
|
||||
|
||||
## Visualize the preprocessed video for better debugging
|
||||
|
||||
```py
|
||||
>>> import imageio
|
||||
>>> import numpy as np
|
||||
>>> from IPython.display import Image
|
||||
|
||||
>>> def unnormalize_img(img):
|
||||
... """Un-normalizes the image pixels."""
|
||||
... img = (img * std) + mean
|
||||
... img = (img * 255).astype("uint8")
|
||||
... return img.clip(0, 255)
|
||||
|
||||
>>> def create_gif(video_tensor, filename="sample.gif"):
|
||||
... """Prepares a GIF from a video tensor.
|
||||
...
|
||||
... The video tensor is expected to have the following shape:
|
||||
... (num_frames, num_channels, height, width).
|
||||
... """
|
||||
... frames = []
|
||||
... for video_frame in video_tensor:
|
||||
... frame_unnormalized = unnormalize_img(video_frame.permute(1, 2, 0).numpy())
|
||||
... frames.append(frame_unnormalized)
|
||||
... kargs = {"duration": 0.25}
|
||||
... imageio.mimsave(filename, frames, "GIF", **kargs)
|
||||
... return filename
|
||||
|
||||
>>> def display_gif(video_tensor, gif_name="sample.gif"):
|
||||
... """Prepares and displays a GIF from a video tensor."""
|
||||
... video_tensor = video_tensor.permute(1, 0, 2, 3)
|
||||
... gif_filename = create_gif(video_tensor, gif_name)
|
||||
... return Image(filename=gif_filename)
|
||||
|
||||
>>> sample_video = next(iter(train_dataset))
|
||||
>>> video_tensor = sample_video["video"]
|
||||
>>> display_gif(video_tensor)
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/sample_gif.gif" alt="Person playing basketball"/>
|
||||
</div>
|
||||
|
||||
## Train the model
|
||||
|
||||
Leverage [`Trainer`](https://huggingface.co/docs/transformers/main_classes/trainer) from 🤗 Transformers for training the model. To instantiate a `Trainer`, you need to define the training configuration and an evaluation metric. The most important is the [`TrainingArguments`](https://huggingface.co/transformers/main_classes/trainer.html#transformers.TrainingArguments), which is a class that contains all the attributes to configure the training. It requires an output folder name, which will be used to save the checkpoints of the model. It also helps sync all the information in the model repository on 🤗 Hub.
|
||||
|
||||
Most of the training arguments are self-explanatory, but one that is quite important here is `remove_unused_columns=False`. This one will drop any features not used by the model's call function. By default it's `True` because usually it's ideal to drop unused feature columns, making it easier to unpack inputs into the model's call function. But, in this case, you need the unused features ('video' in particular) in order to create `pixel_values` (which is a mandatory key our model expects in its inputs).
|
||||
|
||||
```py
|
||||
>>> from transformers import TrainingArguments, Trainer
|
||||
|
||||
>>> model_name = model_ckpt.split("/")[-1]
|
||||
>>> new_model_name = f"{model_name}-finetuned-ucf101-subset"
|
||||
>>> num_epochs = 4
|
||||
|
||||
>>> args = TrainingArguments(
|
||||
... new_model_name,
|
||||
... remove_unused_columns=False,
|
||||
... eval_strategy="epoch",
|
||||
... save_strategy="epoch",
|
||||
... learning_rate=5e-5,
|
||||
... per_device_train_batch_size=batch_size,
|
||||
... per_device_eval_batch_size=batch_size,
|
||||
... warmup_ratio=0.1,
|
||||
... logging_steps=10,
|
||||
... load_best_model_at_end=True,
|
||||
... metric_for_best_model="accuracy",
|
||||
... push_to_hub=True,
|
||||
... max_steps=(train_dataset.num_videos // batch_size) * num_epochs,
|
||||
... )
|
||||
```
|
||||
|
||||
The dataset returned by `pytorchvideo.data.Ucf101()` doesn't implement the `__len__` method. As such, we must define `max_steps` when instantiating `TrainingArguments`.
|
||||
|
||||
Next, you need to define a function to compute the metrics from the predictions, which will use the `metric` you'll load now. The only preprocessing you have to do is to take the argmax of our predicted logits:
|
||||
|
||||
```py
|
||||
import evaluate
|
||||
|
||||
metric = evaluate.load("accuracy")
|
||||
|
||||
|
||||
def compute_metrics(eval_pred):
|
||||
predictions = np.argmax(eval_pred.predictions, axis=1)
|
||||
return metric.compute(predictions=predictions, references=eval_pred.label_ids)
|
||||
```
|
||||
|
||||
**A note on evaluation**:
|
||||
|
||||
In the [VideoMAE paper](https://huggingface.co/papers/2203.12602), the authors use the following evaluation strategy. They evaluate the model on several clips from test videos and apply different crops to those clips and report the aggregate score. However, in the interest of simplicity and brevity, we don't consider that in this tutorial.
|
||||
|
||||
Also, define a `collate_fn`, which will be used to batch examples together. Each batch consists of 2 keys, namely `pixel_values` and `labels`.
|
||||
|
||||
```py
|
||||
>>> def collate_fn(examples):
|
||||
... # permute to (num_frames, num_channels, height, width)
|
||||
... pixel_values = torch.stack(
|
||||
... [example["video"].permute(1, 0, 2, 3) for example in examples]
|
||||
... )
|
||||
... labels = torch.tensor([example["label"] for example in examples])
|
||||
... return {"pixel_values": pixel_values, "labels": labels}
|
||||
```
|
||||
|
||||
Then you just pass all of this along with the datasets to `Trainer`:
|
||||
|
||||
```py
|
||||
>>> trainer = Trainer(
|
||||
... model,
|
||||
... args,
|
||||
... train_dataset=train_dataset,
|
||||
... eval_dataset=val_dataset,
|
||||
... processing_class=image_processor,
|
||||
... compute_metrics=compute_metrics,
|
||||
... data_collator=collate_fn,
|
||||
... )
|
||||
```
|
||||
|
||||
You might wonder why you passed along the `image_processor` as a tokenizer when you preprocessed the data already. This is only to make sure the image processor configuration file (stored as JSON) will also be uploaded to the repo on the Hub.
|
||||
|
||||
Now fine-tune our model by calling the `train` method:
|
||||
|
||||
```py
|
||||
>>> train_results = trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~transformers.Trainer.push_to_hub`] method so everyone can use your model:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## Inference
|
||||
|
||||
Great, now that you have fine-tuned a model, you can use it for inference!
|
||||
|
||||
Load a video for inference:
|
||||
|
||||
```py
|
||||
>>> sample_test_video = next(iter(test_dataset))
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/sample_gif_two.gif" alt="Teams playing basketball"/>
|
||||
</div>
|
||||
|
||||
The simplest way to try out your fine-tuned model for inference is to use it in a [`pipeline`](https://huggingface.co/docs/transformers/main/en/main_classes/pipelines#transformers.VideoClassificationPipeline). Instantiate a `pipeline` for video classification with your model, and pass your video to it:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline, infer_device
|
||||
|
||||
>>> video_cls = pipeline(model="my_awesome_video_cls_model")
|
||||
>>> video_cls("https://huggingface.co/datasets/sayakpaul/ucf101-subset/resolve/main/v_BasketballDunk_g14_c06.avi")
|
||||
[{'score': 0.9272987842559814, 'label': 'BasketballDunk'},
|
||||
{'score': 0.017777055501937866, 'label': 'BabyCrawling'},
|
||||
{'score': 0.01663011871278286, 'label': 'BalanceBeam'},
|
||||
{'score': 0.009560945443809032, 'label': 'BandMarching'},
|
||||
{'score': 0.0068979403004050255, 'label': 'BaseballPitch'}]
|
||||
```
|
||||
|
||||
You can also manually replicate the results of the `pipeline` if you'd like.
|
||||
|
||||
```py
|
||||
>>> def run_inference(model, video):
|
||||
... # (num_frames, num_channels, height, width)
|
||||
... perumuted_sample_test_video = video.permute(1, 0, 2, 3)
|
||||
... inputs = {
|
||||
... "pixel_values": perumuted_sample_test_video.unsqueeze(0),
|
||||
... "labels": torch.tensor(
|
||||
... [sample_test_video["label"]]
|
||||
... ), # this can be skipped if you don't have labels available.
|
||||
... }
|
||||
|
||||
... device = torch.device(infer_device())
|
||||
... inputs = {k: v.to(device) for k, v in inputs.items()}
|
||||
... model = model.to(device)
|
||||
|
||||
... # forward pass
|
||||
... with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
... logits = outputs.logits
|
||||
|
||||
... return logits
|
||||
```
|
||||
|
||||
Now, pass your input to the model and return the `logits`:
|
||||
|
||||
```py
|
||||
>>> logits = run_inference(trained_model, sample_test_video["video"])
|
||||
```
|
||||
|
||||
Decoding the `logits`, we get:
|
||||
|
||||
```py
|
||||
>>> predicted_class_idx = logits.argmax(-1).item()
|
||||
>>> print("Predicted class:", model.config.id2label[predicted_class_idx])
|
||||
# Predicted class: BasketballDunk
|
||||
```
|
||||
146
transformers/docs/source/en/tasks/video_text_to_text.md
Normal file
146
transformers/docs/source/en/tasks/video_text_to_text.md
Normal file
@@ -0,0 +1,146 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Video-text-to-text
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Video-text-to-text models, also known as video language models or vision language models with video input, are language models that take a video input. These models can tackle various tasks, from video question answering to video captioning.
|
||||
|
||||
These models have nearly the same architecture as [image-text-to-text](../image_text_to_text) models except for some changes to accept video data, since video data is essentially image frames with temporal dependencies. Some image-text-to-text models take in multiple images, but this alone is inadequate for a model to accept videos. Moreover, video-text-to-text models are often trained with all vision modalities. Each example might have videos, multiple videos, images and multiple images. Some of these models can also take interleaved inputs. For example, you can refer to a specific video inside a string of text by adding a video token in text like "What is happening in this video? `<video>`".
|
||||
|
||||
In this guide, we provide a brief overview of video LMs and show how to use them with Transformers for inference.
|
||||
|
||||
To begin with, there are multiple types of video LMs:
|
||||
- base models used for fine-tuning
|
||||
- chat fine-tuned models for conversation
|
||||
- instruction fine-tuned models
|
||||
|
||||
This guide focuses on inference with an instruction-tuned model, [llava-hf/llava-interleave-qwen-7b-hf](https://huggingface.co/llava-hf/llava-interleave-qwen-7b-hf) which can take in interleaved data. Alternatively, you can try [llava-interleave-qwen-0.5b-hf](https://huggingface.co/llava-hf/llava-interleave-qwen-0.5b-hf) if your hardware doesn't allow running a 7B model.
|
||||
|
||||
Let's begin installing the dependencies.
|
||||
|
||||
```bash
|
||||
pip install -q transformers accelerate flash_attn
|
||||
```
|
||||
|
||||
Let's initialize the model and the processor.
|
||||
|
||||
```python
|
||||
from transformers import LlavaProcessor, LlavaForConditionalGeneration
|
||||
import torch
|
||||
model_id = "llava-hf/llava-interleave-qwen-0.5b-hf"
|
||||
|
||||
processor = LlavaProcessor.from_pretrained(model_id)
|
||||
|
||||
model = LlavaForConditionalGeneration.from_pretrained(model_id, device_map="auto", dtype=torch.float16)
|
||||
```
|
||||
|
||||
Some models directly consume the `<video>` token, and others accept `<image>` tokens equal to the number of sampled frames. This model handles videos in the latter fashion. We will write a simple utility to handle image tokens, and another utility to get a video from a url and sample frames from it.
|
||||
|
||||
```python
|
||||
import uuid
|
||||
import requests
|
||||
import cv2
|
||||
from PIL import Image
|
||||
|
||||
def replace_video_with_images(text, frames):
|
||||
return text.replace("<video>", "<image>" * frames)
|
||||
|
||||
def sample_frames(url, num_frames):
|
||||
|
||||
response = requests.get(url)
|
||||
path_id = str(uuid.uuid4())
|
||||
|
||||
path = f"./{path_id}.mp4"
|
||||
|
||||
with open(path, "wb") as f:
|
||||
f.write(response.content)
|
||||
|
||||
video = cv2.VideoCapture(path)
|
||||
total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
interval = total_frames // num_frames
|
||||
frames = []
|
||||
for i in range(total_frames):
|
||||
ret, frame = video.read()
|
||||
pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
||||
if not ret:
|
||||
continue
|
||||
if i % interval == 0:
|
||||
frames.append(pil_img)
|
||||
video.release()
|
||||
return frames[:num_frames]
|
||||
```
|
||||
|
||||
Let's get our inputs. We will sample frames and concatenate them.
|
||||
|
||||
```python
|
||||
video_1 = "https://huggingface.co/spaces/merve/llava-interleave/resolve/main/cats_1.mp4"
|
||||
video_2 = "https://huggingface.co/spaces/merve/llava-interleave/resolve/main/cats_2.mp4"
|
||||
|
||||
video_1 = sample_frames(video_1, 6)
|
||||
video_2 = sample_frames(video_2, 6)
|
||||
|
||||
videos = video_1 + video_2
|
||||
|
||||
videos
|
||||
|
||||
# [<PIL.Image.Image image mode=RGB size=1920x1080>,
|
||||
# <PIL.Image.Image image mode=RGB size=1920x1080>,
|
||||
# <PIL.Image.Image image mode=RGB size=1920x1080>, ...]
|
||||
```
|
||||
|
||||
Both videos have cats.
|
||||
|
||||
<div class="container">
|
||||
<div class="video-container">
|
||||
<video width="400" controls>
|
||||
<source src="https://huggingface.co/spaces/merve/llava-interleave/resolve/main/cats_1.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<div class="video-container">
|
||||
<video width="400" controls>
|
||||
<source src="https://huggingface.co/spaces/merve/llava-interleave/resolve/main/cats_2.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Now we can preprocess the inputs.
|
||||
|
||||
This model has a prompt template that looks like following. First, we'll put all the sampled frames into one list. Since we have eight frames in each video, we will insert 12 `<image>` tokens to our prompt. Add `assistant` at the end of the prompt to trigger the model to give answers. Then we can preprocess.
|
||||
|
||||
```python
|
||||
user_prompt = "Are these two cats in these two videos doing the same thing?"
|
||||
toks = "<image>" * 12
|
||||
prompt = "<|im_start|>user"+ toks + f"\n{user_prompt}<|im_end|><|im_start|>assistant"
|
||||
inputs = processor(text=prompt, images=videos, return_tensors="pt").to(model.device, model.dtype)
|
||||
```
|
||||
|
||||
We can now call [`~GenerationMixin.generate`] for inference. The model outputs the question in our input and answer, so we only take the text after the prompt and `assistant` part from the model output.
|
||||
|
||||
```python
|
||||
output = model.generate(**inputs, max_new_tokens=100, do_sample=False)
|
||||
print(processor.decode(output[0][2:], skip_special_tokens=True)[len(user_prompt)+10:])
|
||||
|
||||
# The first cat is shown in a relaxed state, with its eyes closed and a content expression, while the second cat is shown in a more active state, with its mouth open wide, possibly in a yawn or a vocalization.
|
||||
|
||||
|
||||
```
|
||||
|
||||
And voila!
|
||||
|
||||
To learn more about chat templates and token streaming for video-text-to-text models, refer to the [image-text-to-text](../tasks/image_text_to_text) task guide because these models work similarly.
|
||||
147
transformers/docs/source/en/tasks/visual_document_retrieval.md
Normal file
147
transformers/docs/source/en/tasks/visual_document_retrieval.md
Normal file
@@ -0,0 +1,147 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
# Visual document retrieval
|
||||
|
||||
Documents can contain multimodal data if they include charts, tables, and visuals in addition to text. Retrieving information from these documents is challenging because text retrieval models alone can't handle visual data and image retrieval models lack the granularity and document processing capabilities.
|
||||
|
||||
Visual document retrieval can help retrieve information from all types of documents, including multimodal retrieval augmented generation (RAG). These models accept documents (as images) and texts and calculates the similarity scores between them.
|
||||
|
||||
This guide demonstrates how to index and retrieve documents with [ColPali](../model_doc/colpali).
|
||||
|
||||
> [!TIP]
|
||||
> For large scale use cases, you may want to index and retrieve documents with a vector database.
|
||||
|
||||
Make sure Transformers and Datasets is installed.
|
||||
|
||||
```bash
|
||||
pip install -q datasets transformers
|
||||
```
|
||||
|
||||
We will index a dataset of documents related to UFO sightings. We filter the examples where our column of interest is missing. It contains several columns, we are interested in the column `specific_detail_query` where it contains short summary of the document, and `image` column that contains our documents.
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
dataset = load_dataset("davanstrien/ufo-ColPali")
|
||||
dataset = dataset["train"]
|
||||
dataset = dataset.filter(lambda example: example["specific_detail_query"] is not None)
|
||||
print(dataset)
|
||||
```
|
||||
|
||||
```text
|
||||
Dataset({
|
||||
features: ['image', 'raw_queries', 'broad_topical_query', 'broad_topical_explanation', 'specific_detail_query', 'specific_detail_explanation', 'visual_element_query', 'visual_element_explanation', 'parsed_into_json'],
|
||||
num_rows: 2172
|
||||
})
|
||||
```
|
||||
|
||||
Let's load the model and the tokenizer.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import ColPaliForRetrieval, ColPaliProcessor, infer_device
|
||||
|
||||
device = infer_device()
|
||||
|
||||
model_name = "vidore/colpali-v1.2-hf"
|
||||
|
||||
processor = ColPaliProcessor.from_pretrained(model_name)
|
||||
|
||||
model = ColPaliForRetrieval.from_pretrained(
|
||||
model_name,
|
||||
dtype=torch.bfloat16,
|
||||
device_map="auto",
|
||||
).eval()
|
||||
```
|
||||
|
||||
Pass the text query to the processor and return the indexed text embeddings from the model. For image-to-text search, replace the `text` parameter in [`ColPaliProcessor`] with the `images` parameter to pass images.
|
||||
|
||||
```python
|
||||
inputs = processor(text="a document about Mars expedition").to(model.device)
|
||||
with torch.no_grad():
|
||||
text_embeds = model(**inputs, return_tensors="pt").embeddings
|
||||
```
|
||||
|
||||
Index the images offline, and during inference, return the query text embeddings to get its closest image embeddings.
|
||||
|
||||
Store the image and image embeddings by writing them to the dataset with [`~datasets.Dataset.map`] as shown below. Add an `embeddings` column that contains the indexed embeddings. ColPali embeddings take up a lot of storage, so remove them from the accelerator and store them in the CPU as NumPy vectors.
|
||||
|
||||
```python
|
||||
ds_with_embeddings = dataset.map(lambda example: {'embeddings': model(**processor(images=example["image"]).to(device), return_tensors="pt").embeddings.to(torch.float32).detach().cpu().numpy()})
|
||||
```
|
||||
|
||||
For online inference, create a function to search the image embeddings in batches and retrieve the k-most relevant images. The function below returns the indices in the dataset and their scores for a given indexed dataset, text embeddings, number of top results, and the batch size.
|
||||
|
||||
```python
|
||||
def find_top_k_indices_batched(dataset, text_embedding, processor, k=10, batch_size=4):
|
||||
scores_and_indices = []
|
||||
|
||||
for start_idx in range(0, len(dataset), batch_size):
|
||||
|
||||
end_idx = min(start_idx + batch_size, len(dataset))
|
||||
batch = dataset[start_idx:end_idx]
|
||||
batch_embeddings = [torch.tensor(emb[0], dtype=torch.float32) for emb in batch["embeddings"]]
|
||||
scores = processor.score_retrieval(text_embedding.to("cpu").to(torch.float32), batch_embeddings)
|
||||
|
||||
if hasattr(scores, "tolist"):
|
||||
scores = scores.tolist()[0]
|
||||
|
||||
for i, score in enumerate(scores):
|
||||
scores_and_indices.append((score, start_idx + i))
|
||||
|
||||
sorted_results = sorted(scores_and_indices, key=lambda x: -x[0])
|
||||
|
||||
topk = sorted_results[:k]
|
||||
indices = [idx for _, idx in topk]
|
||||
scores = [score for score, _ in topk]
|
||||
|
||||
return indices, scores
|
||||
```
|
||||
|
||||
Generate the text embeddings and pass them to the function above to return the dataset indices and scores.
|
||||
|
||||
```python
|
||||
with torch.no_grad():
|
||||
text_embeds = model(**processor(text="a document about Mars expedition").to(model.device), return_tensors="pt").embeddings
|
||||
indices, scores = find_top_k_indices_batched(ds_with_embeddings, text_embeds, processor, k=3, batch_size=4)
|
||||
print(indices, scores)
|
||||
```
|
||||
|
||||
```text
|
||||
([440, 442, 443],
|
||||
[14.370786666870117,
|
||||
13.675487518310547,
|
||||
12.9899320602417])
|
||||
```
|
||||
|
||||
Display the images to view the Mars related documents.
|
||||
|
||||
```python
|
||||
for i in indices:
|
||||
display(dataset[i]["image"])
|
||||
```
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/doc_1.png"
|
||||
alt="Document 1"
|
||||
style="height: 200px; object-fit: contain; margin-right: 10px;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/doc_2.png"
|
||||
alt="Document 2"
|
||||
style="height: 200px; object-fit: contain;">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/doc_3.png"
|
||||
alt="Document 3"
|
||||
style="height: 200px; object-fit: contain;">
|
||||
</div>
|
||||
400
transformers/docs/source/en/tasks/visual_question_answering.md
Normal file
400
transformers/docs/source/en/tasks/visual_question_answering.md
Normal file
@@ -0,0 +1,400 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Visual Question Answering
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Visual Question Answering (VQA) is the task of answering open-ended questions based on an image.
|
||||
The input to models supporting this task is typically a combination of an image and a question, and the output is an
|
||||
answer expressed in natural language.
|
||||
|
||||
Some noteworthy use case examples for VQA include:
|
||||
* Accessibility applications for visually impaired individuals.
|
||||
* Education: posing questions about visual materials presented in lectures or textbooks. VQA can also be utilized in interactive museum exhibits or historical sites.
|
||||
* Customer service and e-commerce: VQA can enhance user experience by letting users ask questions about products.
|
||||
* Image retrieval: VQA models can be used to retrieve images with specific characteristics. For example, the user can ask "Is there a dog?" to find all images with dogs from a set of images.
|
||||
|
||||
In this guide you'll learn how to:
|
||||
|
||||
- Fine-tune a classification VQA model, specifically [ViLT](../model_doc/vilt), on the [`Graphcore/vqa` dataset](https://huggingface.co/datasets/Graphcore/vqa).
|
||||
- Use your fine-tuned ViLT for inference.
|
||||
- Run zero-shot VQA inference with a generative model, like BLIP-2.
|
||||
|
||||
## Fine-tuning ViLT
|
||||
|
||||
ViLT model incorporates text embeddings into a Vision Transformer (ViT), allowing it to have a minimal design for
|
||||
Vision-and-Language Pre-training (VLP). This model can be used for several downstream tasks. For the VQA task, a classifier
|
||||
head is placed on top (a linear layer on top of the final hidden state of the `[CLS]` token) and randomly initialized.
|
||||
Visual Question Answering is thus treated as a **classification problem**.
|
||||
|
||||
More recent models, such as BLIP, BLIP-2, and InstructBLIP, treat VQA as a generative task. Later in this guide we
|
||||
illustrate how to use them for zero-shot VQA inference.
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed.
|
||||
|
||||
```bash
|
||||
pip install -q transformers datasets
|
||||
```
|
||||
|
||||
We encourage you to share your model with the community. Log in to your Hugging Face account to upload it to the 🤗 Hub.
|
||||
When prompted, enter your token to log in:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
Let's define the model checkpoint as a global variable.
|
||||
|
||||
```py
|
||||
>>> model_checkpoint = "dandelin/vilt-b32-mlm"
|
||||
```
|
||||
|
||||
## Load the data
|
||||
|
||||
For illustration purposes, in this guide we use a very small sample of the annotated visual question answering `Graphcore/vqa` dataset.
|
||||
You can find the full dataset on [🤗 Hub](https://huggingface.co/datasets/Graphcore/vqa).
|
||||
|
||||
As an alternative to the [`Graphcore/vqa` dataset](https://huggingface.co/datasets/Graphcore/vqa), you can download the
|
||||
same data manually from the official [VQA dataset page](https://visualqa.org/download.html). If you prefer to follow the
|
||||
tutorial with your custom data, check out how to [Create an image dataset](https://huggingface.co/docs/datasets/image_dataset#loading-script)
|
||||
guide in the 🤗 Datasets documentation.
|
||||
|
||||
Let's load the first 200 examples from the validation split and explore the dataset's features:
|
||||
|
||||
```python
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> dataset = load_dataset("Graphcore/vqa", split="validation[:200]")
|
||||
>>> dataset
|
||||
Dataset({
|
||||
features: ['question', 'question_type', 'question_id', 'image_id', 'answer_type', 'label'],
|
||||
num_rows: 200
|
||||
})
|
||||
```
|
||||
|
||||
Let's take a look at an example to understand the dataset's features:
|
||||
|
||||
```py
|
||||
>>> dataset[0]
|
||||
{'question': 'Where is he looking?',
|
||||
'question_type': 'none of the above',
|
||||
'question_id': 262148000,
|
||||
'image_id': '/root/.cache/huggingface/datasets/downloads/extracted/ca733e0e000fb2d7a09fbcc94dbfe7b5a30750681d0e965f8e0a23b1c2f98c75/val2014/COCO_val2014_000000262148.jpg',
|
||||
'answer_type': 'other',
|
||||
'label': {'ids': ['at table', 'down', 'skateboard', 'table'],
|
||||
'weights': [0.30000001192092896,
|
||||
1.0,
|
||||
0.30000001192092896,
|
||||
0.30000001192092896]}}
|
||||
```
|
||||
|
||||
The features relevant to the task include:
|
||||
* `question`: the question to be answered from the image
|
||||
* `image_id`: the path to the image the question refers to
|
||||
* `label`: the annotations
|
||||
|
||||
We can remove the rest of the features as they won't be necessary:
|
||||
|
||||
```py
|
||||
>>> dataset = dataset.remove_columns(['question_type', 'question_id', 'answer_type'])
|
||||
```
|
||||
|
||||
As you can see, the `label` feature contains several answers to the same question (called `ids` here) collected by different human annotators.
|
||||
This is because the answer to a question can be subjective. In this case, the question is "where is he looking?". Some people
|
||||
annotated this with "down", others with "at table", another one with "skateboard", etc.
|
||||
|
||||
Take a look at the image and consider which answer would you give:
|
||||
|
||||
```python
|
||||
>>> from PIL import Image
|
||||
|
||||
>>> image = Image.open(dataset[0]['image_id'])
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/vqa-example.png" alt="VQA Image Example"/>
|
||||
</div>
|
||||
|
||||
Due to the questions' and answers' ambiguity, datasets like this are treated as a multi-label classification problem (as
|
||||
multiple answers are possibly valid). Moreover, rather than just creating a one-hot encoded vector, one creates a
|
||||
soft encoding, based on the number of times a certain answer appeared in the annotations.
|
||||
|
||||
For instance, in the example above, because the answer "down" is selected way more often than other answers, it has a
|
||||
score (called `weight` in the dataset) of 1.0, and the rest of the answers have scores < 1.0.
|
||||
|
||||
To later instantiate the model with an appropriate classification head, let's create two dictionaries: one that maps
|
||||
the label name to an integer and vice versa:
|
||||
|
||||
```py
|
||||
>>> import itertools
|
||||
|
||||
>>> labels = [item['ids'] for item in dataset['label']]
|
||||
>>> flattened_labels = list(itertools.chain(*labels))
|
||||
>>> unique_labels = list(set(flattened_labels))
|
||||
|
||||
>>> label2id = {label: idx for idx, label in enumerate(unique_labels)}
|
||||
>>> id2label = {idx: label for label, idx in label2id.items()}
|
||||
```
|
||||
|
||||
Now that we have the mappings, we can replace the string answers with their ids, and flatten the dataset for a more convenient further preprocessing.
|
||||
|
||||
```python
|
||||
>>> def replace_ids(inputs):
|
||||
... inputs["label"]["ids"] = [label2id[x] for x in inputs["label"]["ids"]]
|
||||
... return inputs
|
||||
|
||||
|
||||
>>> dataset = dataset.map(replace_ids)
|
||||
>>> flat_dataset = dataset.flatten()
|
||||
>>> flat_dataset.features
|
||||
{'question': Value(dtype='string', id=None),
|
||||
'image_id': Value(dtype='string', id=None),
|
||||
'label.ids': Sequence(feature=Value(dtype='int64', id=None), length=-1, id=None),
|
||||
'label.weights': Sequence(feature=Value(dtype='float64', id=None), length=-1, id=None)}
|
||||
```
|
||||
|
||||
## Preprocessing data
|
||||
|
||||
The next step is to load a ViLT processor to prepare the image and text data for the model.
|
||||
[`ViltProcessor`] wraps a BERT tokenizer and ViLT image processor into a convenient single processor:
|
||||
|
||||
```py
|
||||
>>> from transformers import ViltProcessor
|
||||
|
||||
>>> processor = ViltProcessor.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
To preprocess the data we need to encode the images and questions using the [`ViltProcessor`]. The processor will use
|
||||
the [`BertTokenizerFast`] to tokenize the text and create `input_ids`, `attention_mask` and `token_type_ids` for the text data.
|
||||
As for images, the processor will leverage [`ViltImageProcessor`] to resize and normalize the image, and create `pixel_values` and `pixel_mask`.
|
||||
|
||||
All these preprocessing steps are done under the hood, we only need to call the `processor`. However, we still need to
|
||||
prepare the target labels. In this representation, each element corresponds to a possible answer (label). For correct answers, the element holds
|
||||
their respective score (weight), while the remaining elements are set to zero.
|
||||
|
||||
The following function applies the `processor` to the images and questions and formats the labels as described above:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> def preprocess_data(examples):
|
||||
... image_paths = examples['image_id']
|
||||
... images = [Image.open(image_path) for image_path in image_paths]
|
||||
... texts = examples['question']
|
||||
|
||||
... encoding = processor(images, texts, padding="max_length", truncation=True, return_tensors="pt")
|
||||
|
||||
... for k, v in encoding.items():
|
||||
... encoding[k] = v.squeeze()
|
||||
|
||||
... targets = []
|
||||
|
||||
... for labels, scores in zip(examples['label.ids'], examples['label.weights']):
|
||||
... target = torch.zeros(len(id2label))
|
||||
|
||||
... for label, score in zip(labels, scores):
|
||||
... target[label] = score
|
||||
|
||||
... targets.append(target)
|
||||
|
||||
... encoding["labels"] = targets
|
||||
|
||||
... return encoding
|
||||
```
|
||||
|
||||
To apply the preprocessing function over the entire dataset, use 🤗 Datasets [`~datasets.map`] function. You can speed up `map` by
|
||||
setting `batched=True` to process multiple elements of the dataset at once. At this point, feel free to remove the columns you don't need.
|
||||
|
||||
```py
|
||||
>>> processed_dataset = flat_dataset.map(preprocess_data, batched=True, remove_columns=['question','question_type', 'question_id', 'image_id', 'answer_type', 'label.ids', 'label.weights'])
|
||||
>>> processed_dataset
|
||||
Dataset({
|
||||
features: ['input_ids', 'token_type_ids', 'attention_mask', 'pixel_values', 'pixel_mask', 'labels'],
|
||||
num_rows: 200
|
||||
})
|
||||
```
|
||||
|
||||
As a final step, create a batch of examples using [`DefaultDataCollator`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
## Train the model
|
||||
|
||||
You're ready to start training your model now! Load ViLT with [`ViltForQuestionAnswering`]. Specify the number of labels
|
||||
along with the label mappings:
|
||||
|
||||
```py
|
||||
>>> from transformers import ViltForQuestionAnswering
|
||||
|
||||
>>> model = ViltForQuestionAnswering.from_pretrained(model_checkpoint, num_labels=len(id2label), id2label=id2label, label2id=label2id)
|
||||
```
|
||||
|
||||
At this point, only three steps remain:
|
||||
|
||||
1. Define your training hyperparameters in [`TrainingArguments`]:
|
||||
|
||||
```py
|
||||
>>> from transformers import TrainingArguments
|
||||
|
||||
>>> repo_id = "MariaK/vilt_finetuned_200"
|
||||
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir=repo_id,
|
||||
... per_device_train_batch_size=4,
|
||||
... num_train_epochs=20,
|
||||
... save_steps=200,
|
||||
... logging_steps=50,
|
||||
... learning_rate=5e-5,
|
||||
... save_total_limit=2,
|
||||
... remove_unused_columns=False,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
```
|
||||
|
||||
2. Pass the training arguments to [`Trainer`] along with the model, dataset, processor, and data collator.
|
||||
|
||||
```py
|
||||
>>> from transformers import Trainer
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... data_collator=data_collator,
|
||||
... train_dataset=processed_dataset,
|
||||
... processing_class=processor,
|
||||
... )
|
||||
```
|
||||
|
||||
3. Call [`~Trainer.train`] to finetune your model.
|
||||
|
||||
```py
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
Once training is completed, share your model to the Hub with the [`~Trainer.push_to_hub`] method to share your final model on the 🤗 Hub:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## Inference
|
||||
|
||||
Now that you have fine-tuned a ViLT model, and uploaded it to the 🤗 Hub, you can use it for inference. The simplest
|
||||
way to try out your fine-tuned model for inference is to use it in a [`Pipeline`].
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> pipe = pipeline("visual-question-answering", model="MariaK/vilt_finetuned_200")
|
||||
```
|
||||
|
||||
The model in this guide has only been trained on 200 examples, so don't expect a lot from it. Let's see if it at least
|
||||
learned something from the data and take the first example from the dataset to illustrate inference:
|
||||
|
||||
```py
|
||||
>>> example = dataset[0]
|
||||
>>> image = Image.open(example['image_id'])
|
||||
>>> question = example['question']
|
||||
>>> print(question)
|
||||
>>> pipe(image, question, top_k=1)
|
||||
"Where is he looking?"
|
||||
[{'score': 0.5498199462890625, 'answer': 'down'}]
|
||||
```
|
||||
|
||||
Even though not very confident, the model indeed has learned something. With more examples and longer training, you'll get far better results!
|
||||
|
||||
You can also manually replicate the results of the pipeline if you'd like:
|
||||
1. Take an image and a question, prepare them for the model using the processor from your model.
|
||||
2. Forward the result or preprocessing through the model.
|
||||
3. From the logits, get the most likely answer's id, and find the actual answer in the `id2label`.
|
||||
|
||||
```py
|
||||
>>> processor = ViltProcessor.from_pretrained("MariaK/vilt_finetuned_200")
|
||||
|
||||
>>> image = Image.open(example['image_id'])
|
||||
>>> question = example['question']
|
||||
|
||||
>>> # prepare inputs
|
||||
>>> inputs = processor(image, question, return_tensors="pt")
|
||||
|
||||
>>> model = ViltForQuestionAnswering.from_pretrained("MariaK/vilt_finetuned_200")
|
||||
|
||||
>>> # forward pass
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
|
||||
>>> logits = outputs.logits
|
||||
>>> idx = logits.argmax(-1).item()
|
||||
>>> print("Predicted answer:", model.config.id2label[idx])
|
||||
Predicted answer: down
|
||||
```
|
||||
|
||||
## Zero-shot VQA
|
||||
|
||||
The previous model treated VQA as a classification task. Some recent models, such as BLIP, BLIP-2, and InstructBLIP approach
|
||||
VQA as a generative task. Let's take [BLIP-2](../model_doc/blip-2) as an example. It introduced a new visual-language pre-training
|
||||
paradigm in which any combination of pre-trained vision encoder and LLM can be used (learn more in the [BLIP-2 blog post](https://huggingface.co/blog/blip-2)).
|
||||
This enables achieving state-of-the-art results on multiple visual-language tasks including visual question answering.
|
||||
|
||||
Let's illustrate how you can use this model for VQA. First, let's load the model. Here we'll explicitly send the model to a
|
||||
GPU, if available, which we didn't need to do earlier when training, as [`Trainer`] handles this automatically:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, Blip2ForConditionalGeneration, infer_device
|
||||
>>> import torch
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("Salesforce/blip2-opt-2.7b")
|
||||
>>> model = Blip2ForConditionalGeneration.from_pretrained("Salesforce/blip2-opt-2.7b", dtype=torch.float16)
|
||||
>>> device = infer_device()
|
||||
>>> model.to(device)
|
||||
```
|
||||
|
||||
The model takes image and text as input, so let's use the exact same image/question pair from the first example in the VQA dataset:
|
||||
|
||||
```py
|
||||
>>> example = dataset[0]
|
||||
>>> image = Image.open(example['image_id'])
|
||||
>>> question = example['question']
|
||||
```
|
||||
|
||||
To use BLIP-2 for visual question answering task, the textual prompt has to follow a specific format: `Question: {} Answer:`.
|
||||
|
||||
```py
|
||||
>>> prompt = f"Question: {question} Answer:"
|
||||
```
|
||||
|
||||
Now we need to preprocess the image/prompt with the model's processor, pass the processed input through the model, and decode the output:
|
||||
|
||||
```py
|
||||
>>> inputs = processor(image, text=prompt, return_tensors="pt").to(device, torch.float16)
|
||||
|
||||
>>> generated_ids = model.generate(**inputs, max_new_tokens=10)
|
||||
>>> generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
|
||||
>>> print(generated_text)
|
||||
"He is looking at the crowd"
|
||||
```
|
||||
|
||||
As you can see, the model recognized the crowd, and the direction of the face (looking down), however, it seems to miss
|
||||
the fact the crowd is behind the skater. Still, in cases where acquiring human-annotated datasets is not feasible, this
|
||||
approach can quickly produce useful results.
|
||||
@@ -0,0 +1,149 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Zero-shot image classification
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Zero-shot image classification is a task that involves classifying images into different categories using a model that was
|
||||
not explicitly trained on data containing labeled examples from those specific categories.
|
||||
|
||||
Traditionally, image classification requires training a model on a specific set of labeled images, and this model learns to
|
||||
"map" certain image features to labels. When there's a need to use such model for a classification task that introduces a
|
||||
new set of labels, fine-tuning is required to "recalibrate" the model.
|
||||
|
||||
In contrast, zero-shot or open vocabulary image classification models are typically multi-modal models that have been trained on a large
|
||||
dataset of images and associated descriptions. These models learn aligned vision-language representations that can be used for many downstream tasks including zero-shot image classification.
|
||||
|
||||
This is a more flexible approach to image classification that allows models to generalize to new and unseen categories
|
||||
without the need for additional training data and enables users to query images with free-form text descriptions of their target objects .
|
||||
|
||||
In this guide you'll learn how to:
|
||||
|
||||
* create a zero-shot image classification pipeline
|
||||
* run zero-shot image classification inference by hand
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install -q "transformers[torch]" pillow
|
||||
```
|
||||
|
||||
## Zero-shot image classification pipeline
|
||||
|
||||
The simplest way to try out inference with a model supporting zero-shot image classification is to use the corresponding [`pipeline`].
|
||||
Instantiate a pipeline from a [checkpoint on the Hugging Face Hub](https://huggingface.co/models?pipeline_tag=zero-shot-image-classification&sort=downloads):
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> checkpoint = "openai/clip-vit-large-patch14"
|
||||
>>> detector = pipeline(model=checkpoint, task="zero-shot-image-classification")
|
||||
```
|
||||
|
||||
Next, choose an image you'd like to classify.
|
||||
|
||||
```py
|
||||
>>> from PIL import Image
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://unsplash.com/photos/g8oS8-82DxI/download?ixid=MnwxMjA3fDB8MXx0b3BpY3x8SnBnNktpZGwtSGt8fHx8fDJ8fDE2NzgxMDYwODc&force=true&w=640"
|
||||
>>> image = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/owl.jpg" alt="Photo of an owl"/>
|
||||
</div>
|
||||
|
||||
Pass the image and the candidate object labels to the pipeline. Here we pass the image directly; other suitable options
|
||||
include a local path to an image or an image url.
|
||||
The candidate labels can be simple words like in this example, or more descriptive.
|
||||
|
||||
```py
|
||||
>>> predictions = detector(image, candidate_labels=["fox", "bear", "seagull", "owl"])
|
||||
>>> predictions
|
||||
[{'score': 0.9996670484542847, 'label': 'owl'},
|
||||
{'score': 0.000199399160919711, 'label': 'seagull'},
|
||||
{'score': 7.392891711788252e-05, 'label': 'fox'},
|
||||
{'score': 5.96074532950297e-05, 'label': 'bear'}]
|
||||
```
|
||||
|
||||
## Zero-shot image classification by hand
|
||||
|
||||
Now that you've seen how to use the zero-shot image classification pipeline, let's take a look how you can run zero-shot
|
||||
image classification manually.
|
||||
|
||||
Start by loading the model and associated processor from a [checkpoint on the Hugging Face Hub](https://huggingface.co/models?pipeline_tag=zero-shot-image-classification&sort=downloads).
|
||||
Here we'll use the same checkpoint as before:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, AutoModelForZeroShotImageClassification
|
||||
|
||||
>>> model = AutoModelForZeroShotImageClassification.from_pretrained(checkpoint)
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
Let's take a different image to switch things up.
|
||||
|
||||
```py
|
||||
>>> from PIL import Image
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://unsplash.com/photos/xBRQfR2bqNI/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjc4Mzg4ODEx&force=true&w=640"
|
||||
>>> image = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg" alt="Photo of a car"/>
|
||||
</div>
|
||||
|
||||
Use the processor to prepare the inputs for the model. The processor combines an image processor that prepares the
|
||||
image for the model by resizing and normalizing it, and a tokenizer that takes care of the text inputs.
|
||||
|
||||
```py
|
||||
>>> candidate_labels = ["tree", "car", "bike", "cat"]
|
||||
# follows the pipeline prompt template to get same results
|
||||
>>> candidate_labels = [f'This is a photo of {label}.' for label in candidate_labels]
|
||||
>>> inputs = processor(images=image, text=candidate_labels, return_tensors="pt", padding=True)
|
||||
```
|
||||
|
||||
Pass the inputs through the model, and post-process the results:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
|
||||
>>> logits = outputs.logits_per_image[0]
|
||||
>>> probs = logits.softmax(dim=-1).numpy()
|
||||
>>> scores = probs.tolist()
|
||||
|
||||
>>> result = [
|
||||
... {"score": score, "label": candidate_label}
|
||||
... for score, candidate_label in sorted(zip(probs, candidate_labels), key=lambda x: -x[0])
|
||||
... ]
|
||||
|
||||
>>> result
|
||||
[{'score': 0.998572, 'label': 'car'},
|
||||
{'score': 0.0010570387, 'label': 'bike'},
|
||||
{'score': 0.0003393686, 'label': 'tree'},
|
||||
{'score': 3.1572064e-05, 'label': 'cat'}]
|
||||
```
|
||||
314
transformers/docs/source/en/tasks/zero_shot_object_detection.md
Normal file
314
transformers/docs/source/en/tasks/zero_shot_object_detection.md
Normal file
@@ -0,0 +1,314 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Zero-shot object detection
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Traditionally, models used for [object detection](object_detection) require labeled image datasets for training,
|
||||
and are limited to detecting the set of classes from the training data.
|
||||
|
||||
Zero-shot object detection is a computer vision task to detect objects and their classes in images, without any
|
||||
prior training or knowledge of the classes. Zero-shot object detection models receive an image as input, as well
|
||||
as a list of candidate classes, and output the bounding boxes and labels where the objects have been detected.
|
||||
|
||||
> [!NOTE]
|
||||
> Hugging Face houses many such [open vocabulary zero shot object detectors](https://huggingface.co/models?pipeline_tag=zero-shot-object-detection).
|
||||
|
||||
In this guide, you will learn how to use such models:
|
||||
- to detect objects based on text prompts
|
||||
- for batch object detection
|
||||
- for image-guided object detection
|
||||
|
||||
Before you begin, make sure you have all the necessary libraries installed:
|
||||
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## Zero-shot object detection pipeline
|
||||
|
||||
The simplest way to try out inference with models is to use it in a [`pipeline`]. Instantiate a pipeline
|
||||
for zero-shot object detection from a [checkpoint on the Hugging Face Hub](https://huggingface.co/models?pipeline_tag=zero-shot-object-detection):
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> # Use any checkpoint from the hf.co/models?pipeline_tag=zero-shot-object-detection
|
||||
>>> checkpoint = "iSEE-Laboratory/llmdet_large"
|
||||
>>> detector = pipeline(model=checkpoint, task="zero-shot-object-detection")
|
||||
```
|
||||
|
||||
Next, choose an image you'd like to detect objects in. Here we'll use the image of astronaut Eileen Collins that is
|
||||
a part of the [NASA](https://www.nasa.gov/multimedia/imagegallery/index.html) Great Images dataset.
|
||||
|
||||
```py
|
||||
>>> from transformers.image_utils import load_image
|
||||
|
||||
>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_1.png"
|
||||
>>> image = load_image(url)
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_1.png" alt="Astronaut Eileen Collins"/>
|
||||
</div>
|
||||
|
||||
Pass the image and the candidate object labels to look for to the pipeline.
|
||||
Here we pass the image directly; other suitable options include a local path to an image or an image url. We also pass text descriptions for all items we want to query the image for.
|
||||
|
||||
```py
|
||||
>>> predictions = detector(
|
||||
... image,
|
||||
... candidate_labels=["human face", "rocket", "nasa badge", "star-spangled banner"],
|
||||
... threshold=0.45,
|
||||
... )
|
||||
>>> predictions
|
||||
[{'score': 0.8409242033958435,
|
||||
'label': 'human face',
|
||||
'box': {'xmin': 179, 'ymin': 74, 'xmax': 272, 'ymax': 179}},
|
||||
{'score': 0.7380027770996094,
|
||||
'label': 'rocket',
|
||||
'box': {'xmin': 353, 'ymin': 0, 'xmax': 466, 'ymax': 284}},
|
||||
{'score': 0.5850900411605835,
|
||||
'label': 'star-spangled banner',
|
||||
'box': {'xmin': 0, 'ymin': 0, 'xmax': 96, 'ymax': 511}},
|
||||
{'score': 0.5697067975997925,
|
||||
'label': 'human face',
|
||||
'box': {'xmin': 18, 'ymin': 15, 'xmax': 366, 'ymax': 511}},
|
||||
{'score': 0.47813931107521057,
|
||||
'label': 'star-spangled banner',
|
||||
'box': {'xmin': 353, 'ymin': 0, 'xmax': 459, 'ymax': 274}},
|
||||
{'score': 0.46597740054130554,
|
||||
'label': 'nasa badge',
|
||||
'box': {'xmin': 353, 'ymin': 0, 'xmax': 462, 'ymax': 279}},
|
||||
{'score': 0.4585932493209839,
|
||||
'label': 'nasa badge',
|
||||
'box': {'xmin': 132, 'ymin': 348, 'xmax': 208, 'ymax': 423}}]
|
||||
```
|
||||
|
||||
Let's visualize the predictions:
|
||||
|
||||
```py
|
||||
>>> from PIL import ImageDraw
|
||||
|
||||
>>> draw = ImageDraw.Draw(image)
|
||||
|
||||
>>> for prediction in predictions:
|
||||
... box = prediction["box"]
|
||||
... label = prediction["label"]
|
||||
... score = prediction["score"]
|
||||
|
||||
... xmin, ymin, xmax, ymax = box.values()
|
||||
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
|
||||
... draw.text((xmin, ymin), f"{label}: {round(score,2)}", fill="white")
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_2.png" alt="Visualized predictions on NASA image"/>
|
||||
</div>
|
||||
|
||||
## Text-prompted zero-shot object detection by hand
|
||||
|
||||
Now that you've seen how to use the zero-shot object detection pipeline, let's replicate the same result manually.
|
||||
|
||||
Start by loading the model and associated processor from a [checkpoint on the Hugging Face Hub](hf.co/iSEE-Laboratory/llmdet_large).
|
||||
Here we'll use the same checkpoint as before:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection
|
||||
|
||||
>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint, device_map="auto")
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
Let's take a different image to switch things up.
|
||||
|
||||
```py
|
||||
>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_3.png"
|
||||
>>> image = load_image(url)
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_3.png" alt="Beach photo"/>
|
||||
</div>
|
||||
|
||||
Use the processor to prepare the inputs for the model.
|
||||
|
||||
```py
|
||||
>>> text_labels = ["hat", "book", "sunglasses", "camera"]
|
||||
>>> inputs = processor(text=text_labels, images=image, return_tensors="pt")to(model.device)
|
||||
```
|
||||
|
||||
Pass the inputs through the model, post-process, and visualize the results. Since the image processor resized images before
|
||||
feeding them to the model, you need to use the `post_process_object_detection` method to make sure the predicted bounding
|
||||
boxes have the correct coordinates relative to the original image:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> with torch.inference_mode():
|
||||
... outputs = model(**inputs)
|
||||
|
||||
>>> results = processor.post_process_grounded_object_detection(
|
||||
... outputs, threshold=0.50, target_sizes=[(image.height, image.width)], text_labels=text_labels,
|
||||
...)[0]
|
||||
|
||||
>>> draw = ImageDraw.Draw(image)
|
||||
|
||||
>>> scores = results["scores"]
|
||||
>>> text_labels = results["text_labels"]
|
||||
>>> boxes = results["boxes"]
|
||||
|
||||
>>> for box, score, text_label in zip(boxes, scores, text_labels):
|
||||
... xmin, ymin, xmax, ymax = box
|
||||
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
|
||||
... draw.text((xmin, ymin), f"{text_label}: {round(score.item(),2)}", fill="white")
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_4.png" alt="Beach photo with detected objects"/>
|
||||
</div>
|
||||
|
||||
## Batch processing
|
||||
|
||||
You can pass multiple sets of images and text queries to search for different (or same) objects in several images.
|
||||
Let's use both an astronaut image and the beach image together.
|
||||
For batch processing, you should pass text queries as a nested list to the processor and images as lists of PIL images,
|
||||
PyTorch tensors, or NumPy arrays.
|
||||
|
||||
```py
|
||||
>>> url1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_1.png"
|
||||
>>> url2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_3.png"
|
||||
>>> images = [load_image(url1), load_image(url2)]
|
||||
>>> text_queries = [
|
||||
... ["human face", "rocket", "nasa badge", "star-spangled banner"],
|
||||
... ["hat", "book", "sunglasses", "camera", "can"],
|
||||
... ]
|
||||
>>> inputs = processor(text=text_queries, images=images, return_tensors="pt", padding=True)
|
||||
```
|
||||
|
||||
Previously for post-processing you passed the single image's size as a tensor, but you can also pass a tuple, or, in case
|
||||
of several images, a list of tuples. Let's create predictions for the two examples, and visualize the second one (`image_idx = 1`).
|
||||
|
||||
```py
|
||||
>>> with torch.no_grad():
|
||||
>>> outputs = model(**inputs)
|
||||
|
||||
>>> target_sizes = [(image.height, image.width) for image in images]
|
||||
>>> results = processor.post_process_grounded_object_detection(
|
||||
... outputs, threshold=0.3, target_sizes=target_sizes, text_labels=text_labels,
|
||||
... )
|
||||
```
|
||||
|
||||
Let's visualize the results:
|
||||
|
||||
```py
|
||||
>>> image_idx = 1
|
||||
>>> draw = ImageDraw.Draw(images[image_idx])
|
||||
|
||||
>>> scores = results[image_idx]["scores"].tolist()
|
||||
>>> text_labels = results[image_idx]["text_labels"]
|
||||
>>> boxes = results[image_idx]["boxes"].tolist()
|
||||
|
||||
>>> for box, score, text_label in zip(boxes, scores, text_labels):
|
||||
>>> xmin, ymin, xmax, ymax = box
|
||||
>>> draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
|
||||
>>> draw.text((xmin, ymin), f"{text_label}: {round(score,2)}", fill="white")
|
||||
|
||||
>>> images[image_idx]
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_4.png" alt="Beach photo with detected objects"/>
|
||||
</div>
|
||||
|
||||
## Image-guided object detection
|
||||
|
||||
In addition to zero-shot object detection with text queries, models like [OWL-ViT](https://huggingface.co/collections/ariG23498/owlvit-689b0d0872a7634a6ea17ae7) and [OWLv2](https://huggingface.co/collections/ariG23498/owlv2-689b0d27bd7d96ba3c7f7530) offers image-guided object detection. This means you can use an image query to find similar
|
||||
objects in the target image.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection
|
||||
|
||||
>>> checkpoint = "google/owlv2-base-patch16-ensemble"
|
||||
>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint, device_map="auto")
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
Unlike text queries, only a single example image is allowed.
|
||||
|
||||
Let's take an image with two cats on a couch as a target image, and an image of a single cat
|
||||
as a query:
|
||||
|
||||
```py
|
||||
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
||||
>>> image_target = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
>>> query_url = "http://images.cocodataset.org/val2017/000000524280.jpg"
|
||||
>>> query_image = Image.open(requests.get(query_url, stream=True).raw)
|
||||
```
|
||||
|
||||
Let's take a quick look at the images:
|
||||
|
||||
```py
|
||||
>>> import matplotlib.pyplot as plt
|
||||
|
||||
>>> fig, ax = plt.subplots(1, 2)
|
||||
>>> ax[0].imshow(image_target)
|
||||
>>> ax[1].imshow(query_image)
|
||||
>>> fig.show()
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_5.png" alt="Cats"/>
|
||||
</div>
|
||||
|
||||
In the preprocessing step, instead of text queries, you now need to use `query_images`:
|
||||
|
||||
```py
|
||||
>>> inputs = processor(images=image_target, query_images=query_image, return_tensors="pt")
|
||||
```
|
||||
|
||||
For predictions, instead of passing the inputs to the model, pass them to [`~OwlViTForObjectDetection.image_guided_detection`]. Draw the predictions
|
||||
as before except now there are no labels.
|
||||
|
||||
```py
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model.image_guided_detection(**inputs)
|
||||
... target_sizes = torch.tensor([image_target.size[::-1]])
|
||||
... results = processor.post_process_image_guided_detection(outputs=outputs, target_sizes=target_sizes)[0]
|
||||
|
||||
>>> draw = ImageDraw.Draw(image_target)
|
||||
|
||||
>>> scores = results["scores"].tolist()
|
||||
>>> boxes = results["boxes"].tolist()
|
||||
|
||||
>>> for box, score in zip(boxes, scores):
|
||||
... xmin, ymin, xmax, ymax = box
|
||||
... draw.rectangle((xmin, ymin, xmax, ymax), outline="white", width=4)
|
||||
|
||||
>>> image_target
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/zero-sh-obj-detection_6.png" alt="Cats with bounding boxes"/>
|
||||
</div>
|
||||
Reference in New Issue
Block a user