init
This commit is contained in:
367
transformers/docs/source/ko/tasks/asr.md
Normal file
367
transformers/docs/source/ko/tasks/asr.md
Normal file
@@ -0,0 +1,367 @@
|
||||
<!--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)은 음성 신호를 텍스트로 변환하여 음성 입력 시퀀스를 텍스트 출력에 매핑합니다.
|
||||
Siri와 Alexa와 같은 가상 어시스턴트는 ASR 모델을 사용하여 일상적으로 사용자를 돕고 있으며, 회의 중 라이브 캡션 및 메모 작성과 같은 유용한 사용자 친화적 응용 프로그램도 많이 있습니다.
|
||||
|
||||
이 가이드에서 소개할 내용은 아래와 같습니다:
|
||||
|
||||
1. [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) 데이터 세트에서 [Wav2Vec2](https://huggingface.co/facebook/wav2vec2-base)를 미세 조정하여 오디오를 텍스트로 변환합니다.
|
||||
2. 미세 조정한 모델을 추론에 사용합니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/automatic-speech-recognition)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate jiwer
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하면 모델을 업로드하고 커뮤니티에 공유할 수 있습니다. 토큰을 입력하여 로그인하세요.
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## MInDS-14 데이터 세트 가져오기[[load-minds-14-dataset]]
|
||||
|
||||
먼저, 🤗 Datasets 라이브러리에서 [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) 데이터 세트의 일부분을 가져오세요.
|
||||
이렇게 하면 전체 데이터 세트에 대한 훈련에 시간을 들이기 전에 모든 것이 작동하는지 실험하고 검증할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train[:100]")
|
||||
```
|
||||
|
||||
[`~Dataset.train_test_split`] 메소드를 사용하여 데이터 세트의 `train`을 훈련 세트와 테스트 세트로 나누세요:
|
||||
|
||||
```py
|
||||
>>> minds = minds.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
그리고 데이터 세트를 확인하세요:
|
||||
|
||||
```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
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
데이터 세트에는 `lang_id`와 `english_transcription`과 같은 유용한 정보가 많이 포함되어 있지만, 이 가이드에서는 `audio`와 `transcription`에 초점을 맞출 것입니다. 다른 열은 [`~datasets.Dataset.remove_columns`] 메소드를 사용하여 제거하세요:
|
||||
|
||||
```py
|
||||
>>> minds = minds.remove_columns(["english_transcription", "intent_class", "lang_id"])
|
||||
```
|
||||
|
||||
예시를 다시 한번 확인해보세요:
|
||||
|
||||
```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"}
|
||||
```
|
||||
|
||||
두 개의 필드가 있습니다:
|
||||
|
||||
- `audio`: 오디오 파일을 가져오고 리샘플링하기 위해 호출해야 하는 음성 신호의 1차원 `array(배열)`
|
||||
- `transcription`: 목표 텍스트
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
다음으로 오디오 신호를 처리하기 위한 Wav2Vec2 프로세서를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base")
|
||||
```
|
||||
|
||||
MInDS-14 데이터 세트의 샘플링 레이트는 8000kHz이므로([데이터 세트 카드](https://huggingface.co/datasets/PolyAI/minds14)에서 확인), 사전 훈련된 Wav2Vec2 모델을 사용하려면 데이터 세트를 16000kHz로 리샘플링해야 합니다:
|
||||
|
||||
```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"}
|
||||
```
|
||||
|
||||
위의 'transcription'에서 볼 수 있듯이 텍스트는 대문자와 소문자가 섞여 있습니다. Wav2Vec2 토크나이저는 대문자 문자에 대해서만 훈련되어 있으므로 텍스트가 토크나이저의 어휘와 일치하는지 확인해야 합니다:
|
||||
|
||||
```py
|
||||
>>> def uppercase(example):
|
||||
... return {"transcription": example["transcription"].upper()}
|
||||
|
||||
|
||||
>>> minds = minds.map(uppercase)
|
||||
```
|
||||
|
||||
이제 다음 작업을 수행할 전처리 함수를 만들어보겠습니다:
|
||||
|
||||
1. `audio` 열을 호출하여 오디오 파일을 가져오고 리샘플링합니다.
|
||||
2. 오디오 파일에서 `input_values`를 추출하고 프로세서로 `transcription` 열을 토큰화합니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
전체 데이터 세트에 전처리 함수를 적용하려면 🤗 Datasets [`~datasets.Dataset.map`] 함수를 사용하세요. `num_proc` 매개변수를 사용하여 프로세스 수를 늘리면 `map`의 속도를 높일 수 있습니다. [`~datasets.Dataset.remove_columns`] 메소드를 사용하여 필요하지 않은 열을 제거하세요:
|
||||
|
||||
```py
|
||||
>>> encoded_minds = minds.map(prepare_dataset, remove_columns=minds.column_names["train"], num_proc=4)
|
||||
```
|
||||
|
||||
🤗 Transformers에는 자동 음성 인식용 데이터 콜레이터가 없으므로 예제 배치를 생성하려면 [`DataCollatorWithPadding`]을 조정해야 합니다. 이렇게 하면 데이터 콜레이터는 텍스트와 레이블을 배치에서 가장 긴 요소의 길이에 동적으로 패딩하여 길이를 균일하게 합니다. `tokenizer` 함수에서 `padding=True`를 설정하여 텍스트를 패딩할 수 있지만, 동적 패딩이 더 효율적입니다.
|
||||
|
||||
다른 데이터 콜레이터와 달리 이 특정 데이터 콜레이터는 `input_values`와 `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]:
|
||||
... # 입력과 레이블을 분할합니다
|
||||
... # 길이가 다르고, 각각 다른 패딩 방법을 사용해야 하기 때문입니다
|
||||
... 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")
|
||||
|
||||
... # 패딩에 대해 손실을 적용하지 않도록 -100으로 대체합니다
|
||||
... labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)
|
||||
|
||||
... batch["labels"] = labels
|
||||
|
||||
... return batch
|
||||
```
|
||||
|
||||
이제 `DataCollatorForCTCWithPadding`을 인스턴스화합니다:
|
||||
|
||||
```py
|
||||
>>> data_collator = DataCollatorCTCWithPadding(processor=processor, padding="longest")
|
||||
```
|
||||
|
||||
## 평가하기[[evaluate]]
|
||||
|
||||
훈련 중에 평가 지표를 포함하면 모델의 성능을 평가하는 데 도움이 되는 경우가 많습니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하면 평가 방법을 빠르게 불러올 수 있습니다.
|
||||
이 작업에서는 [단어 오류율(Word Error Rate, WER)](https://huggingface.co/spaces/evaluate-metric/wer) 평가 지표를 가져옵니다.
|
||||
(평가 지표를 불러오고 계산하는 방법은 🤗 Evaluate [둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> wer = evaluate.load("wer")
|
||||
```
|
||||
|
||||
그런 다음 예측값과 레이블을 [`~evaluate.EvaluationModule.compute`]에 전달하여 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 = wer.compute(predictions=pred_str, references=label_str)
|
||||
|
||||
... return {"wer": wer}
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었으며, 훈련을 설정할 때 이 함수로 되돌아올 것입니다.
|
||||
|
||||
## 훈련하기[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]로 모델을 미세 조정하는 것이 익숙하지 않다면, [여기](../training#train-with-pytorch-trainer)에서 기본 튜토리얼을 확인해보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델 훈련을 시작할 준비가 되었습니다! [`AutoModelForCTC`]로 Wav2Vec2를 가져오세요. `ctc_loss_reduction` 매개변수로 CTC 손실에 적용할 축소(reduction) 방법을 지정하세요. 기본값인 합계 대신 평균을 사용하는 것이 더 좋은 경우가 많습니다:
|
||||
|
||||
```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,
|
||||
... )
|
||||
```
|
||||
|
||||
이제 세 단계만 남았습니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 훈련 하이퍼파라미터를 정의하세요. `output_dir`은 모델을 저장할 경로를 지정하는 유일한 필수 매개변수입니다. `push_to_hub=True`를 설정하여 모델을 Hub에 업로드 할 수 있습니다(모델을 업로드하려면 Hugging Face에 로그인해야 합니다). [`Trainer`]는 각 에폭마다 WER을 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. 모델, 데이터 세트, 토크나이저, 데이터 콜레이터, `compute_metrics` 함수와 함께 [`Trainer`]에 훈련 인수를 전달하세요.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정하세요.
|
||||
|
||||
```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.feature_extractor,
|
||||
... data_collator=data_collator,
|
||||
... compute_metrics=compute_metrics,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
훈련이 완료되면 모두가 모델을 사용할 수 있도록 [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 Hub에 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
자동 음성 인식을 위해 모델을 미세 조정하는 더 자세한 예제는 영어 자동 음성 인식을 위한 [블로그 포스트](https://huggingface.co/blog/fine-tune-wav2vec2-english)와 다국어 자동 음성 인식을 위한 [포스트](https://huggingface.co/blog/fine-tune-xlsr-wav2vec2)를 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론하기[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론에 사용할 오디오 파일을 가져오세요. 필요한 경우 오디오 파일의 샘플링 비율을 모델의 샘플링 레이트에 맞게 리샘플링하는 것을 잊지 마세요!
|
||||
|
||||
```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"]
|
||||
```
|
||||
|
||||
추론을 위해 미세 조정된 모델을 시험해보는 가장 간단한 방법은 [`pipeline`]을 사용하는 것입니다. 모델을 사용하여 자동 음성 인식을 위한 `pipeline`을 인스턴스화하고 오디오 파일을 전달하세요:
|
||||
|
||||
```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>
|
||||
|
||||
텍스트로 변환된 결과가 꽤 괜찮지만 더 좋을 수도 있습니다! 더 나은 결과를 얻으려면 더 많은 예제로 모델을 미세 조정하세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
`pipeline`의 결과를 수동으로 재현할 수도 있습니다:
|
||||
|
||||
오디오 파일과 텍스트를 전처리하고 PyTorch 텐서로 `input`을 반환할 프로세서를 가져오세요:
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
입력을 모델에 전달하고 로짓을 반환하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCTC
|
||||
|
||||
>>> model = AutoModelForCTC.from_pretrained("stevhliu/my_awesome_asr_mind_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
가장 높은 확률의 `input_ids`를 예측하고, 프로세서를 사용하여 예측된 `input_ids`를 다시 텍스트로 디코딩하세요:
|
||||
|
||||
```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']
|
||||
```
|
||||
316
transformers/docs/source/ko/tasks/audio_classification.md
Normal file
316
transformers/docs/source/ko/tasks/audio_classification.md
Normal file
@@ -0,0 +1,316 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
# 오디오 분류[[audio_classification]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="KWwzcmG98Ds"/>
|
||||
|
||||
오디오 분류는 텍스트와 마찬가지로 입력 데이터에 클래스 레이블 출력을 할당합니다. 유일한 차이점은 텍스트 입력 대신 원시 오디오 파형이 있다는 것입니다. 오디오 분류의 실제 적용 분야에는 화자의 의도 파악, 언어 분류, 소리로 동물 종을 식별하는 것 등이 있습니다.
|
||||
|
||||
이 문서에서 방법을 알아보겠습니다:
|
||||
|
||||
1. [MInDS-14](https://huggingface.co/datasets/PolyAI/minds14) 데이터 세트를 [Wav2Vec2](https://huggingface.co/facebook/wav2vec2-base)로 미세 조정하여 화자의 의도를 분류합니다.
|
||||
2. 추론에 미세 조정된 모델을 사용하세요.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/audio-classification)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
모델을 업로드하고 커뮤니티와 공유할 수 있도록 허깅페이스 계정에 로그인하는 것이 좋습니다. 메시지가 표시되면 토큰을 입력하여 로그인합니다:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## MInDS-14 데이터셋 불러오기[[load_minds_14_dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 MinDS-14 데이터 세트를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset, Audio
|
||||
|
||||
>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train")
|
||||
```
|
||||
|
||||
데이터 세트의 `train` 분할을 [`~datasets.Dataset.train_test_split`] 메소드를 사용하여 더 작은 훈련 및 테스트 집합으로 분할합니다. 이렇게 하면 전체 데이터 세트에 더 많은 시간을 소비하기 전에 모든 것이 작동하는지 실험하고 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> minds = minds.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
이제 데이터 집합을 살펴볼게요:
|
||||
|
||||
```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
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
데이터 세트에는 `lang_id` 및 `english_transcription`과 같은 유용한 정보가 많이 포함되어 있지만 이 가이드에서는 `audio` 및 `intent_class`에 중점을 둘 것입니다. 다른 열은 [`~datasets.Dataset.remove_columns`] 메소드를 사용하여 제거합니다:
|
||||
|
||||
```py
|
||||
>>> minds = minds.remove_columns(["path", "transcription", "english_transcription", "lang_id"])
|
||||
```
|
||||
|
||||
예시를 살펴보겠습니다:
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
두 개의 필드가 있습니다:
|
||||
|
||||
- `audio`: 오디오 파일을 가져오고 리샘플링하기 위해 호출해야 하는 음성 신호의 1차원 `배열`입니다.
|
||||
- `intent_class`: 화자의 의도에 대한 클래스 ID를 나타냅니다.
|
||||
|
||||
모델이 레이블 ID에서 레이블 이름을 쉽게 가져올 수 있도록 레이블 이름을 정수로 매핑하는 사전을 만들거나 그 반대로 매핑하는 사전을 만듭니다:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
이제 레이블 ID를 레이블 이름으로 변환할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> id2label[str(2)]
|
||||
'app_error'
|
||||
```
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
다음 단계는 오디오 신호를 처리하기 위해 Wav2Vec2 특징 추출기를 가져오는 것입니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoFeatureExtractor
|
||||
|
||||
>>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")
|
||||
```
|
||||
|
||||
MinDS-14 데이터 세트의 샘플링 속도는 8khz이므로(이 정보는 [데이터세트 카드](https://huggingface.co/datasets/PolyAI/minds14)에서 확인할 수 있습니다), 사전 훈련된 Wav2Vec2 모델을 사용하려면 데이터 세트를 16kHz로 리샘플링해야 합니다:
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
이제 전처리 함수를 만듭니다:
|
||||
|
||||
1. 가져올 `오디오` 열을 호출하고 필요한 경우 오디오 파일을 리샘플링합니다.
|
||||
2. 오디오 파일의 샘플링 속도가 모델에 사전 훈련된 오디오 데이터의 샘플링 속도와 일치하는지 확인합니다. 이 정보는 Wav2Vec2 [모델 카드](https://huggingface.co/facebook/wav2vec2-base)에서 확인할 수 있습니다.
|
||||
3. 긴 입력이 잘리지 않고 일괄 처리되도록 최대 입력 길이를 설정합니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
전체 데이터 세트에 전처리 기능을 적용하려면 🤗 Datasets [`~datasets.Dataset.map`] 함수를 사용합니다. `batched=True`를 설정하여 데이터 집합의 여러 요소를 한 번에 처리하면 `map`의 속도를 높일 수 있습니다. 필요하지 않은 열을 제거하고 `intent_class`의 이름을 모델이 예상하는 이름인 `label`로 변경합니다:
|
||||
|
||||
```py
|
||||
>>> encoded_minds = minds.map(preprocess_function, remove_columns="audio", batched=True)
|
||||
>>> encoded_minds = encoded_minds.rename_column("intent_class", "label")
|
||||
```
|
||||
|
||||
## 평가하기[[evaluate]]
|
||||
|
||||
훈련 중에 메트릭을 포함하면 모델의 성능을 평가하는 데 도움이 되는 경우가 많습니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하여 평가 방법을 빠르게 가져올 수 있습니다. 이 작업에서는 [accuracy(정확도)](https://huggingface.co/spaces/evaluate-metric/accuracy) 메트릭을 가져옵니다(메트릭을 가져오고 계산하는 방법에 대한 자세한 내용은 🤗 Evalutate [빠른 둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour) 참조하세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
그런 다음 예측과 레이블을 [`~evaluate.EvaluationModule.compute`]에 전달하여 정확도를 계산하는 함수를 만듭니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었으며, 트레이닝을 설정할 때 이 함수를 사용합니다.
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]로 모델을 미세 조정하는 데 익숙하지 않다면 기본 튜토리얼 [여기](../training#train-with-pytorch-trainer)을 살펴보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델 훈련을 시작할 준비가 되었습니다! [`AutoModelForAudioClassification`]을 이용해서 Wav2Vec2를 불러옵니다. 예상되는 레이블 수와 레이블 매핑을 지정합니다:
|
||||
|
||||
```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
|
||||
... )
|
||||
```
|
||||
|
||||
이제 세 단계만 남았습니다:
|
||||
|
||||
1. 훈련 하이퍼파라미터를 [`TrainingArguments`]에 정의합니다. 유일한 필수 매개변수는 모델을 저장할 위치를 지정하는 `output_dir`입니다. `push_to_hub = True`를 설정하여 이 모델을 허브로 푸시합니다(모델을 업로드하려면 허깅 페이스에 로그인해야 합니다). 각 에폭이 끝날 때마다 [`Trainer`]가 정확도를 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. 모델, 데이터 세트, 토크나이저, 데이터 콜레이터, `compute_metrics` 함수와 함께 훈련 인자를 [`Trainer`]에 전달합니다.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정합니다.
|
||||
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
훈련이 완료되면 모든 사람이 모델을 사용할 수 있도록 [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 허브에 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
For a more in-depth example of how to finetune 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]]
|
||||
|
||||
이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론을 실행할 오디오 파일을 가져옵니다. 필요한 경우 오디오 파일의 샘플링 속도를 모델의 샘플링 속도와 일치하도록 리샘플링하는 것을 잊지 마세요!
|
||||
|
||||
```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"]
|
||||
```
|
||||
|
||||
추론을 위해 미세 조정한 모델을 시험해 보는 가장 간단한 방법은 [`pipeline`]에서 사용하는 것입니다. 모델을 사용하여 오디오 분류를 위한 `pipeline`을 인스턴스화하고 오디오 파일을 전달합니다:
|
||||
|
||||
```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'}
|
||||
]
|
||||
```
|
||||
|
||||
원하는 경우 `pipeline`의 결과를 수동으로 복제할 수도 있습니다:
|
||||
|
||||
특징 추출기를 가져와서 오디오 파일을 전처리하고 `입력`을 PyTorch 텐서로 반환합니다:
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
모델에 입력을 전달하고 로짓을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForAudioClassification
|
||||
|
||||
>>> model = AutoModelForAudioClassification.from_pretrained("stevhliu/my_awesome_minds_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
확률이 가장 높은 클래스를 가져온 다음 모델의 `id2label` 매핑을 사용하여 이를 레이블로 변환합니다:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> predicted_class_ids = torch.argmax(logits).item()
|
||||
>>> predicted_label = model.config.id2label[predicted_class_ids]
|
||||
>>> predicted_label
|
||||
'cash_deposit'
|
||||
```
|
||||
476
transformers/docs/source/ko/tasks/document_question_answering.md
Normal file
476
transformers/docs/source/ko/tasks/document_question_answering.md
Normal file
@@ -0,0 +1,476 @@
|
||||
<!--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) [[document_question_answering]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
문서 시각적 질의 응답(Document Visual Question Answering)이라고도 하는
|
||||
문서 질의 응답(Document Question Answering)은 문서 이미지에 대한 질문에 답변을 주는 태스크입니다.
|
||||
이 태스크를 지원하는 모델의 입력은 일반적으로 이미지와 질문의 조합이고, 출력은 자연어로 된 답변입니다. 이러한 모델은 텍스트, 단어의 위치(바운딩 박스), 이미지 등 다양한 모달리티를 활용합니다.
|
||||
|
||||
이 가이드는 다음 내용을 설명합니다:
|
||||
|
||||
- [DocVQA dataset](https://huggingface.co/datasets/nielsr/docvqa_1200_examples_donut)을 사용해 [LayoutLMv2](../model_doc/layoutlmv2) 미세 조정하기
|
||||
- 추론을 위해 미세 조정된 모델을 사용하기
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/image-to-text)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
LayoutLMv2는 토큰의 마지막 은닉층 위에 질의 응답 헤드를 추가해 답변의 시작 토큰과 끝 토큰의 위치를 예측함으로써 문서 질의 응답 태스크를 해결합니다. 즉, 문맥이 주어졌을 때 질문에 답하는 정보를 추출하는 추출형 질의 응답(Extractive question answering)으로 문제를 처리합니다.
|
||||
문맥은 OCR 엔진의 출력에서 가져오며, 여기서는 Google의 Tesseract를 사용합니다.
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요. LayoutLMv2는 detectron2, torchvision 및 테서랙트를 필요로 합니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
필요한 라이브러리들을 모두 설치한 후 런타임을 다시 시작합니다.
|
||||
|
||||
커뮤니티에 당신의 모델을 공유하는 것을 권장합니다. Hugging Face 계정에 로그인해서 모델을 🤗 Hub에 업로드하세요.
|
||||
프롬프트가 실행되면, 로그인을 위해 토큰을 입력하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
몇 가지 전역 변수를 정의해 보겠습니다.
|
||||
|
||||
```py
|
||||
>>> model_checkpoint = "microsoft/layoutlmv2-base-uncased"
|
||||
>>> batch_size = 4
|
||||
```
|
||||
|
||||
## 데이터 불러오기 [[load-the-data]]
|
||||
|
||||
이 가이드에서는 🤗 Hub에서 찾을 수 있는 전처리된 DocVQA의 작은 샘플을 사용합니다.
|
||||
DocVQA의 전체 데이터 세트를 사용하고 싶다면, [DocVQA homepage](https://rrc.cvc.uab.es/?ch=17)에 가입 후 다운로드 할 수 있습니다. 전체 데이터 세트를 다운로드 했다면, 이 가이드를 계속 진행하기 위해 [🤗 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
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
보시다시피, 데이터 세트는 이미 훈련 세트와 테스트 세트로 나누어져 있습니다. 무작위로 예제를 살펴보면서 특성을 확인해보세요.
|
||||
|
||||
```py
|
||||
>>> dataset["train"].features
|
||||
```
|
||||
|
||||
각 필드가 나타내는 내용은 다음과 같습니다:
|
||||
* `id`: 예제의 id
|
||||
* `image`: 문서 이미지를 포함하는 PIL.Image.Image 객체
|
||||
* `query`: 질문 문자열 - 여러 언어의 자연어로 된 질문
|
||||
* `answers`: 사람이 주석을 단 정답 리스트
|
||||
* `words` and `bounding_boxes`: OCR의 결과값들이며 이 가이드에서는 사용하지 않을 예정
|
||||
* `answer`: 다른 모델과 일치하는 답변이며 이 가이드에서는 사용하지 않을 예정
|
||||
|
||||
영어로 된 질문만 남기고 다른 모델에 대한 예측을 포함하는 `answer` 특성을 삭제하겠습니다.
|
||||
그리고 주석 작성자가 제공한 데이터 세트에서 첫 번째 답변을 가져옵니다. 또는 무작위로 샘플을 추출할 수도 있습니다.
|
||||
|
||||
```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"]
|
||||
... )
|
||||
```
|
||||
|
||||
이 가이드에서 사용하는 LayoutLMv2 체크포인트는 `max_position_embeddings = 512`로 훈련되었습니다(이 정보는 [체크포인트의 `config.json` 파일](https://huggingface.co/microsoft/layoutlmv2-base-uncased/blob/main/config.json#L18)에서 확인할 수 있습니다).
|
||||
바로 예제를 잘라낼 수도 있지만, 긴 문서의 끝에 답변이 있어 잘리는 상황을 피하기 위해 여기서는 임베딩이 512보다 길어질 가능성이 있는 몇 가지 예제를 제거하겠습니다.
|
||||
데이터 세트에 있는 대부분의 문서가 긴 경우 슬라이딩 윈도우 방법을 사용할 수 있습니다 - 자세한 내용을 확인하고 싶으면 이 [노트북](https://github.com/huggingface/notebooks/blob/main/examples/question_answering.ipynb)을 확인하세요.
|
||||
|
||||
```py
|
||||
>>> updated_dataset = updated_dataset.filter(lambda x: len(x["words"]) + len(x["question"].split()) < 512)
|
||||
```
|
||||
|
||||
이 시점에서 이 데이터 세트의 OCR 특성도 제거해 보겠습니다. OCR 특성은 다른 모델을 미세 조정하기 위한 것으로, 이 가이드에서 사용하는 모델의 입력 요구 사항과 일치하지 않기 때문에 이 특성을 사용하기 위해서는 일부 처리가 필요합니다.
|
||||
대신, 원본 데이터에 [`LayoutLMv2Processor`]를 사용하여 OCR 및 토큰화를 모두 수행할 수 있습니다.
|
||||
이렇게 하면 모델이 요구하는 입력을 얻을 수 있습니다.
|
||||
이미지를 수동으로 처리하려면, [`LayoutLMv2` model documentation](../model_doc/layoutlmv2)에서 모델이 요구하는 입력 포맷을 확인해보세요.
|
||||
|
||||
```py
|
||||
>>> updated_dataset = updated_dataset.remove_columns("words")
|
||||
>>> updated_dataset = updated_dataset.remove_columns("bounding_boxes")
|
||||
```
|
||||
|
||||
마지막으로, 데이터 탐색을 완료하기 위해 이미지 예시를 살펴봅시다.
|
||||
|
||||
```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]]
|
||||
|
||||
|
||||
문서 질의 응답 태스크는 멀티모달 태스크이며, 각 모달리티의 입력이 모델의 요구에 맞게 전처리 되었는지 확인해야 합니다.
|
||||
이미지 데이터를 처리할 수 있는 이미지 프로세서와 텍스트 데이터를 인코딩할 수 있는 토크나이저를 결합한 [`LayoutLMv2Processor`]를 가져오는 것부터 시작해 보겠습니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
### 문서 이미지 전처리 [[preprocessing-document-images]]
|
||||
|
||||
먼저, 프로세서의 `image_processor`를 사용해 모델에 대한 문서 이미지를 준비해 보겠습니다.
|
||||
기본값으로, 이미지 프로세서는 이미지 크기를 224x224로 조정하고 색상 채널의 순서가 올바른지 확인한 후 단어와 정규화된 바운딩 박스를 얻기 위해 테서랙트를 사용해 OCR를 적용합니다.
|
||||
이 튜토리얼에서 우리가 필요한 것과 기본값은 완전히 동일합니다. 이미지 배치에 기본 이미지 처리를 적용하고 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
|
||||
```
|
||||
|
||||
이 전처리를 데이터 세트 전체에 빠르게 적용하려면 [`~datasets.Dataset.map`]를 사용하세요.
|
||||
|
||||
```py
|
||||
>>> dataset_with_ocr = updated_dataset.map(get_ocr_words_and_boxes, batched=True, batch_size=2)
|
||||
```
|
||||
|
||||
### 텍스트 데이터 전처리 [[preprocessing-text-data]]
|
||||
|
||||
이미지에 OCR을 적용했으면 데이터 세트의 텍스트 부분을 모델에 맞게 인코딩해야 합니다.
|
||||
이 인코딩에는 이전 단계에서 가져온 단어와 박스를 토큰 수준의 `input_ids`, `attention_mask`, `token_type_ids` 및 `bbox`로 변환하는 작업이 포함됩니다.
|
||||
텍스트를 전처리하려면 프로세서의 `tokenizer`가 필요합니다.
|
||||
|
||||
```py
|
||||
>>> tokenizer = processor.tokenizer
|
||||
```
|
||||
|
||||
위에서 언급한 전처리 외에도 모델을 위해 레이블을 추가해야 합니다. 🤗 Transformers의 `xxxForQuestionAnswering` 모델의 경우, 레이블은 `start_positions`와 `end_positions`로 구성되며 어떤 토큰이 답변의 시작과 끝에 있는지를 나타냅니다.
|
||||
|
||||
레이블 추가를 위해서, 먼저 더 큰 리스트(단어 리스트)에서 하위 리스트(단어로 분할된 답변)을 찾을 수 있는 헬퍼 함수를 정의합니다.
|
||||
|
||||
이 함수는 `words_list`와 `answer_list`, 이렇게 두 리스트를 입력으로 받습니다.
|
||||
그런 다음 `words_list`를 반복하여 `words_list`의 현재 단어(words_list[i])가 `answer_list`의 첫 번째 단어(answer_list[0])와 같은지,
|
||||
현재 단어에서 시작해 `answer_list`와 같은 길이만큼의 `words_list`의 하위 리스트가 `answer_list`와 일치하는지 확인합니다.
|
||||
이 조건이 참이라면 일치하는 항목을 발견했음을 의미하며, 함수는 일치 항목, 시작 인덱스(idx) 및 종료 인덱스(idx + len(answer_list) - 1)를 기록합니다. 일치하는 항목이 두 개 이상 발견되면 함수는 첫 번째 항목만 반환합니다. 일치하는 항목이 없다면 함수는 (`None`, 0, 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
|
||||
```
|
||||
|
||||
이 함수가 어떻게 정답의 위치를 찾는지 설명하기 위해 다음 예제에서 함수를 사용해 보겠습니다:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
한편, 위 예제가 인코딩되면 다음과 같이 표시됩니다:
|
||||
|
||||
```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 ...
|
||||
```
|
||||
|
||||
이제 인코딩된 입력에서 정답의 위치를 찾아야 합니다.
|
||||
* `token_type_ids`는 어떤 토큰이 질문에 속하는지, 그리고 어떤 토큰이 문서의 단어에 포함되는지를 알려줍니다.
|
||||
* `tokenizer.cls_token_id` 입력의 시작 부분에 있는 특수 토큰을 찾는 데 도움을 줍니다.
|
||||
* `word_ids`는 원본 `words`에서 찾은 답변을 전체 인코딩된 입력의 동일한 답과 일치시키고 인코딩된 입력에서 답변의 시작/끝 위치를 결정합니다.
|
||||
|
||||
위 내용들을 염두에 두고 데이터 세트 예제의 배치를 인코딩하는 함수를 만들어 보겠습니다:
|
||||
|
||||
```py
|
||||
>>> def encode_dataset(examples, max_length=512):
|
||||
... questions = examples["question"]
|
||||
... words = examples["words"]
|
||||
... boxes = examples["boxes"]
|
||||
... answers = examples["answer"]
|
||||
|
||||
... # 예제 배치를 인코딩하고 start_positions와 end_positions를 초기화합니다
|
||||
... encoding = tokenizer(questions, words, boxes, max_length=max_length, padding="max_length", truncation=True)
|
||||
... start_positions = []
|
||||
... end_positions = []
|
||||
|
||||
... # 배치의 예제를 반복합니다
|
||||
... for i in range(len(questions)):
|
||||
... cls_index = encoding["input_ids"][i].index(tokenizer.cls_token_id)
|
||||
|
||||
... # 예제의 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:
|
||||
... # 일치하는 항목을 발견하면, `token_type_ids`를 사용해 인코딩에서 단어가 시작하는 위치를 찾습니다
|
||||
... 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
|
||||
|
||||
... # words의 답변 위치와 일치할 때까지 word_ids를 반복하고 `token_start_index`를 늘립니다
|
||||
... # 일치하면 `token_start_index`를 인코딩에서 답변의 `start_position`으로 저장합니다
|
||||
... for id in word_ids:
|
||||
... if id == word_idx_start:
|
||||
... start_position = token_start_index
|
||||
... else:
|
||||
... token_start_index += 1
|
||||
|
||||
... # 비슷하게, 끝에서 시작해 `word_ids`를 반복하며 답변의 `end_position`을 찾습니다
|
||||
... 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
|
||||
```
|
||||
|
||||
이제 이 전처리 함수가 있으니 전체 데이터 세트를 인코딩할 수 있습니다:
|
||||
|
||||
```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
|
||||
... )
|
||||
```
|
||||
|
||||
인코딩된 데이터 세트의 특성이 어떻게 생겼는지 확인해 보겠습니다:
|
||||
|
||||
```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]]
|
||||
|
||||
문서 질의 응답을 평가하려면 상당한 양의 후처리가 필요합니다. 시간이 너무 많이 걸리지 않도록 이 가이드에서는 평가 단계를 생략합니다.
|
||||
[`Trainer`]가 훈련 과정에서 평가 손실(evaluation loss)을 계속 계산하기 때문에 모델의 성능을 대략적으로 알 수 있습니다.
|
||||
추출적(Extractive) 질의 응답은 보통 F1/exact match 방법을 사용해 평가됩니다.
|
||||
직접 구현해보고 싶으시다면, Hugging Face course의 [Question Answering chapter](https://huggingface.co/course/chapter7/7?fw=pt#postprocessing)을 참고하세요.
|
||||
|
||||
## 훈련 [[train]]
|
||||
|
||||
축하합니다! 이 가이드의 가장 어려운 부분을 성공적으로 처리했으니 이제 나만의 모델을 훈련할 준비가 되었습니다.
|
||||
훈련은 다음과 같은 단계로 이루어져 있습니다:
|
||||
* 전처리에서의 동일한 체크포인트를 사용하기 위해 [`AutoModelForDocumentQuestionAnswering`]으로 모델을 가져옵니다.
|
||||
* [`TrainingArguments`]로 훈련 하이퍼파라미터를 정합니다.
|
||||
* 예제를 배치 처리하는 함수를 정의합니다. 여기서는 [`DefaultDataCollator`]가 적당합니다.
|
||||
* 모델, 데이터 세트, 데이터 콜레이터(Data collator)와 함께 [`Trainer`]에 훈련 인수들을 전달합니다.
|
||||
* [`~Trainer.train`]을 호출해서 모델을 미세 조정합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForDocumentQuestionAnswering
|
||||
|
||||
>>> model = AutoModelForDocumentQuestionAnswering.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
[`TrainingArguments`]에서 `output_dir`을 사용하여 모델을 저장할 위치를 지정하고, 적절한 하이퍼파라미터를 설정합니다.
|
||||
모델을 커뮤니티와 공유하려면 `push_to_hub`를 `True`로 설정하세요 (모델을 업로드하려면 Hugging Face에 로그인해야 합니다).
|
||||
이 경우 `output_dir`은 모델의 체크포인트를 푸시할 레포지토리의 이름이 됩니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import TrainingArguments
|
||||
|
||||
>>> # 본인의 레포지토리 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,
|
||||
... )
|
||||
```
|
||||
|
||||
간단한 데이터 콜레이터를 정의하여 예제를 함께 배치합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
마지막으로, 모든 것을 한 곳에 모아 [`~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()
|
||||
```
|
||||
|
||||
최종 모델을 🤗 Hub에 추가하려면, 모델 카드를 생성하고 `push_to_hub`를 호출합니다:
|
||||
|
||||
```py
|
||||
>>> trainer.create_model_card()
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## 추론 [[inference]]
|
||||
|
||||
이제 LayoutLMv2 모델을 미세 조정하고 🤗 Hub에 업로드했으니 추론에도 사용할 수 있습니다.
|
||||
추론을 위해 미세 조정된 모델을 사용해 보는 가장 간단한 방법은 [`Pipeline`]을 사용하는 것 입니다.
|
||||
|
||||
예를 들어 보겠습니다:
|
||||
```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']
|
||||
```
|
||||
|
||||
그 다음, 모델로 문서 질의 응답을 하기 위해 파이프라인을 인스턴스화하고 이미지 + 질문 조합을 전달합니다.
|
||||
|
||||
```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}]
|
||||
```
|
||||
|
||||
원한다면 파이프라인의 결과를 수동으로 복제할 수도 있습니다:
|
||||
1. 이미지와 질문을 가져와 모델의 프로세서를 사용해 모델에 맞게 준비합니다.
|
||||
2. 모델을 통해 결과 또는 전처리를 전달합니다.
|
||||
3. 모델은 어떤 토큰이 답변의 시작에 있는지, 어떤 토큰이 답변이 끝에 있는지를 나타내는 `start_logits`와 `end_logits`를 반환합니다. 둘 다 (batch_size, sequence_length) 형태를 갖습니다.
|
||||
4. `start_logits`와 `end_logits`의 마지막 차원을 최대로 만드는 값을 찾아 예상 `start_idx`와 `end_idx`를 얻습니다.
|
||||
5. 토크나이저로 답변을 디코딩합니다.
|
||||
|
||||
```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'
|
||||
```
|
||||
389
transformers/docs/source/ko/tasks/idefics.md
Normal file
389
transformers/docs/source/ko/tasks/idefics.md
Normal file
@@ -0,0 +1,389 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
# IDEFICS를 이용한 이미지 작업[[image-tasks-with-idefics]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
개별 작업은 특화된 모델을 미세 조정하여 처리할 수 있지만, 최근 등장하여 인기를 얻고 있는 방식은 대규모 모델을 미세 조정 없이 다양한 작업에 사용하는 것입니다. 예를 들어, 대규모 언어 모델은 요약, 번역, 분류 등과 같은 자연어처리 (NLP) 작업을 처리할 수 있습니다. 이 접근 방식은 텍스트와 같은 단일 모달리티에 국한되지 않으며, 이 가이드에서는 IDEFICS라는 대규모 멀티모달 모델을 사용하여 이미지-텍스트 작업을 다루는 방법을 설명합니다.
|
||||
|
||||
[IDEFICS](../model_doc/idefics)는 [Flamingo](https://huggingface.co/papers/2204.14198)를 기반으로 하는 오픈 액세스 비전 및 언어 모델로, DeepMind에서 처음 개발한 최신 시각 언어 모델입니다. 이 모델은 임의의 이미지 및 텍스트 입력 시퀀스를 받아 일관성 있는 텍스트를 출력으로 생성합니다. 이미지에 대한 질문에 답변하고, 시각적인 내용을 설명하며, 여러 이미지에 기반한 이야기를 생성하는 등 다양한 작업을 수행할 수 있습니다. IDEFICS는 [800억 파라미터](https://huggingface.co/HuggingFaceM4/idefics-80b)와 [90억 파라미터](https://huggingface.co/HuggingFaceM4/idefics-9b) 두 가지 버전을 제공하며, 두 버전 모두 🤗 Hub에서 이용할 수 있습니다. 각 버전에는 대화형 사용 사례에 맞게 미세 조정된 버전도 있습니다.
|
||||
|
||||
이 모델은 매우 다재다능하며 광범위한 이미지 및 멀티모달 작업에 사용될 수 있습니다. 그러나 대규모 모델이기 때문에 상당한 컴퓨팅 자원과 인프라가 필요합니다. 각 개별 작업에 특화된 모델을 미세 조정하는 것보다 모델을 그대로 사용하는 것이 더 적합한지는 사용자가 판단해야 합니다.
|
||||
|
||||
이 가이드에서는 다음을 배우게 됩니다:
|
||||
- [IDEFICS 로드하기](#loading-the-model) 및 [양자화된 버전의 모델 로드하기](#quantized-model)
|
||||
- IDEFICS를 사용하여:
|
||||
- [이미지 캡셔닝](#image-captioning)
|
||||
- [프롬프트 이미지 캡셔닝](#prompted-image-captioning)
|
||||
- [퓨샷 프롬프트](#few-shot-prompting)
|
||||
- [시각적 질의 응답](#visual-question-answering)
|
||||
- [이미지 분류](#image-classification)
|
||||
- [이미지 기반 텍스트 생성](#image-guided-text-generation)
|
||||
- [배치 모드에서 추론 실행](#running-inference-in-batch-mode)
|
||||
- [대화형 사용을 위한 IDEFICS 인스트럭트 실행](#idefics-instruct-for-conversational-use)
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되어 있는지 확인하세요.
|
||||
|
||||
```bash
|
||||
pip install -q bitsandbytes sentencepiece accelerate transformers
|
||||
```
|
||||
|
||||
<Tip>
|
||||
다음 예제를 비양자화된 버전의 모델 체크포인트로 실행하려면 최소 20GB의 GPU 메모리가 필요합니다.
|
||||
</Tip>
|
||||
|
||||
## 모델 로드[[loading-the-model]]
|
||||
|
||||
모델을 90억 파라미터 버전의 체크포인트로 로드해 봅시다:
|
||||
|
||||
```py
|
||||
>>> checkpoint = "HuggingFaceM4/idefics-9b"
|
||||
```
|
||||
|
||||
다른 Transformers 모델과 마찬가지로, 체크포인트에서 프로세서와 모델 자체를 로드해야 합니다.
|
||||
IDEFICS 프로세서는 [`LlamaTokenizer`]와 IDEFICS 이미지 프로세서를 하나의 프로세서로 감싸서 텍스트와 이미지 입력을 모델에 맞게 준비합니다.
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> from transformers import IdeficsForVisionText2Text, AutoProcessor
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
|
||||
>>> model = IdeficsForVisionText2Text.from_pretrained(checkpoint, dtype=torch.bfloat16, device_map="auto")
|
||||
```
|
||||
|
||||
`device_map`을 `"auto"`로 설정하면 사용 중인 장치를 고려하여 모델 가중치를 가장 최적화된 방식으로 로드하고 저장하는 방법을 자동으로 결정합니다.
|
||||
|
||||
### 양자화된 모델[[quantized-model]]
|
||||
|
||||
고용량 GPU 사용이 어려운 경우, 모델의 양자화된 버전을 로드할 수 있습니다. 모델과 프로세서를 4비트 정밀도로 로드하기 위해서, `from_pretrained` 메소드에 `BitsAndBytesConfig`를 전달하면 모델이 로드되는 동안 실시간으로 압축됩니다.
|
||||
|
||||
```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"
|
||||
... )
|
||||
```
|
||||
|
||||
이제 모델을 제안된 방법 중 하나로 로드했으니, IDEFICS를 사용할 수 있는 작업들을 탐구해봅시다.
|
||||
|
||||
## 이미지 캡셔닝[[image-captioning]]
|
||||
이미지 캡셔닝은 주어진 이미지에 대한 캡션을 예측하는 작업입니다. 일반적인 응용 분야는 시각 장애인이 다양한 상황을 탐색할 수 있도록 돕는 것입니다. 예를 들어, 온라인에서 이미지 콘텐츠를 탐색하는 데 도움을 줄 수 있습니다.
|
||||
|
||||
작업을 설명하기 위해 캡션을 달 이미지 예시를 가져옵니다. 예시:
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [Hendo Wang](https://unsplash.com/@hendoo).
|
||||
|
||||
IDEFICS는 텍스트 및 이미지 프롬프트를 모두 수용합니다. 그러나 이미지를 캡션하기 위해 모델에 텍스트 프롬프트를 제공할 필요는 없습니다. 전처리된 입력 이미지만 제공하면 됩니다. 텍스트 프롬프트 없이 모델은 BOS(시퀀스 시작) 토큰부터 텍스트 생성을 시작하여 캡션을 만듭니다.
|
||||
|
||||
모델에 이미지 입력으로는 이미지 객체(`PIL.Image`) 또는 이미지를 가져올 수 있는 URL을 사용할 수 있습니다.
|
||||
|
||||
```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>
|
||||
|
||||
`max_new_tokens`의 크기를 증가시킬 때 발생할 수 있는 오류를 피하기 위해 `generate` 호출 시 `bad_words_ids`를 포함하는 것이 좋습니다. 모델로부터 생성된 이미지가 없을 때 새로운 `<image>` 또는 `<fake_token_around_image>` 토큰을 생성하려고 하기 때문입니다.
|
||||
이 가이드에서처럼 `bad_words_ids`를 함수 호출 시에 매개변수로 설정하거나, [텍스트 생성 전략](../generation_strategies) 가이드에 설명된 대로 `GenerationConfig`에 저장할 수도 있습니다.
|
||||
</Tip>
|
||||
|
||||
## 프롬프트 이미지 캡셔닝[[prompted-image-captioning]]
|
||||
|
||||
텍스트 프롬프트를 이용하여 이미지 캡셔닝을 확장할 수 있으며, 모델은 주어진 이미지를 바탕으로 텍스트를 계속 생성합니다. 다음 이미지를 예시로 들어보겠습니다:
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [Denys Nevozhai](https://unsplash.com/@dnevozhai).
|
||||
|
||||
텍스트 및 이미지 프롬프트는 적절한 입력을 생성하기 위해 모델의 프로세서에 하나의 목록으로 전달될 수 있습니다.
|
||||
|
||||
```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]]
|
||||
|
||||
IDEFICS는 훌륭한 제로샷 결과를 보여주지만, 작업에 특정 형식의 캡션이 필요하거나 작업의 복잡성을 높이는 다른 제한 사항이나 요구 사항이 있을 수 있습니다. 이럴 때 퓨샷 프롬프트를 사용하여 맥락 내 학습(In-Context Learning)을 가능하게 할 수 있습니다.
|
||||
프롬프트에 예시를 제공함으로써 모델이 주어진 예시의 형식을 모방한 결과를 생성하도록 유도할 수 있습니다.
|
||||
|
||||
이전의 에펠탑 이미지를 모델에 예시로 사용하고, 모델에게 이미지의 객체를 학습하는 것 외에도 흥미로운 정보를 얻고 싶다는 것을 보여주는 프롬프트를 작성해 봅시다.
|
||||
그런 다음 자유의 여신상 이미지에 대해 동일한 응답 형식을 얻을 수 있는지 확인해 봅시다:
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [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.
|
||||
```
|
||||
|
||||
단 하나의 예시만으로도(즉, 1-shot) 모델이 작업 수행 방법을 학습했다는 점이 주목할 만합니다. 더 복잡한 작업의 경우, 더 많은 예시(예: 3-shot, 5-shot 등)를 사용하여 실험해 보는 것도 좋은 방법입니다.
|
||||
|
||||
## 시각적 질의 응답[[visual-question-answering]]
|
||||
|
||||
시각적 질의 응답(VQA)은 이미지를 기반으로 개방형 질문에 답하는 작업입니다. 이미지 캡셔닝과 마찬가지로 접근성 애플리케이션에서 사용할 수 있지만, 교육(시각 자료에 대한 추론), 고객 서비스(이미지를 기반으로 한 제품 질문), 이미지 검색 등에서도 사용할 수 있습니다.
|
||||
|
||||
이 작업을 위해 새로운 이미지를 가져옵니다:
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [Jarritos Mexican Soda](https://unsplash.com/@jarritos).
|
||||
|
||||
적절한 지시문을 사용하면 이미지 캡셔닝에서 시각적 질의 응답으로 모델을 유도할 수 있습니다:
|
||||
|
||||
```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는 특정 카테고리의 라벨이 포함된 데이터로 명시적으로 학습되지 않아도 이미지를 다양한 카테고리로 분류할 수 있습니다. 카테고리 목록이 주어지면, 모델은 이미지와 텍스트 이해 능력을 사용하여 이미지가 속할 가능성이 높은 카테고리를 추론할 수 있습니다.
|
||||
|
||||
여기에 야채 가판대 이미지가 있습니다.
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [Peter Wendt](https://unsplash.com/@peterwendt).
|
||||
|
||||
우리는 모델에게 우리가 가진 카테고리 중 하나로 이미지를 분류하도록 지시할 수 있습니다:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
위 예제에서는 모델에게 이미지를 단일 카테고리로 분류하도록 지시했지만, 순위 분류를 하도록 모델에 프롬프트를 제공할 수도 있습니다.
|
||||
|
||||
## 이미지 기반 텍스트 생성[[image-guided-text-generation]]
|
||||
|
||||
이미지를 활용한 텍스트 생성 기술을 사용하면 더욱 창의적인 작업이 가능합니다. 이 기술은 이미지를 바탕으로 텍스트를 만들어내며, 제품 설명, 광고 문구, 장면 묘사 등 다양한 용도로 활용할 수 있습니다.
|
||||
|
||||
간단한 예로, 빨간 문 이미지를 IDEFICS에 입력하여 이야기를 만들어보겠습니다:
|
||||
|
||||
<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>
|
||||
|
||||
사진 제공: [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
|
||||
```
|
||||
|
||||
IDEFICS가 문 앞에 있는 호박을 보고 유령에 대한 으스스한 할로윈 이야기를 만든 것 같습니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이처럼 긴 텍스트를 생성할 때는 텍스트 생성 전략을 조정하는 것이 좋습니다. 이렇게 하면 생성된 결과물의 품질을 크게 향상시킬 수 있습니다. 자세한 내용은 [텍스트 생성 전략](../generation_strategies)을 참조하세요.
|
||||
</Tip>
|
||||
|
||||
## 배치 모드에서 추론 실행[[running-inference-in-batch-mode]]
|
||||
|
||||
앞선 모든 섹션에서는 단일 예시에 대해 IDEFICS를 설명했습니다. 이와 매우 유사한 방식으로, 프롬프트 목록을 전달하여 여러 예시에 대한 추론을 실행할 수 있습니다:
|
||||
|
||||
```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 인스트럭트 실행[[idefics-instruct-for-conversational-use]]
|
||||
|
||||
대화형 사용 사례를 위해, 🤗 Hub에서 명령어 수행에 최적화된 버전의 모델을 찾을 수 있습니다. 이곳에는 `HuggingFaceM4/idefics-80b-instruct`와 `HuggingFaceM4/idefics-9b-instruct`가 있습니다.
|
||||
|
||||
이 체크포인트는 지도 학습 및 명령어 미세 조정 데이터셋의 혼합으로 각각의 기본 모델을 미세 조정한 결과입니다. 이를 통해 모델의 하위 작업 성능을 향상시키는 동시에 대화형 환경에서 모델을 더 사용하기 쉽게 합니다.
|
||||
|
||||
대화형 사용을 위한 사용법 및 프롬프트는 기본 모델을 사용하는 것과 매우 유사합니다.
|
||||
|
||||
```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(device)
|
||||
>>> # --single sample mode
|
||||
>>> # inputs = processor(prompts[0], return_tensors="pt").to(device)
|
||||
|
||||
>>> # 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")
|
||||
```
|
||||
281
transformers/docs/source/ko/tasks/image_captioning.md
Normal file
281
transformers/docs/source/ko/tasks/image_captioning.md
Normal file
@@ -0,0 +1,281 @@
|
||||
<!--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)은 주어진 이미지에 대한 캡션을 예측하는 작업입니다.
|
||||
이미지 캡셔닝은 시각 장애인이 다양한 상황을 탐색하는 데 도움을 줄 수 있도록 시각 장애인을 보조하는 등 실생활에서 흔히 활용됩니다.
|
||||
따라서 이미지 캡셔닝은 이미지를 설명함으로써 사람들의 콘텐츠 접근성을 개선하는 데 도움이 됩니다.
|
||||
|
||||
이 가이드에서는 소개할 내용은 아래와 같습니다:
|
||||
|
||||
* 이미지 캡셔닝 모델을 파인튜닝합니다.
|
||||
* 파인튜닝된 모델을 추론에 사용합니다.
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate -q
|
||||
pip install jiwer -q
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하면 모델을 업로드하고 커뮤니티에 공유할 수 있습니다.
|
||||
토큰을 입력하여 로그인하세요.
|
||||
|
||||
|
||||
```python
|
||||
from huggingface_hub import notebook_login
|
||||
|
||||
notebook_login()
|
||||
```
|
||||
|
||||
## 포켓몬 BLIP 캡션 데이터세트 가져오기[[load-the-pokmon-blip-captions-dataset]]
|
||||
|
||||
{이미지-캡션} 쌍으로 구성된 데이터세트를 가져오려면 🤗 Dataset 라이브러리를 사용합니다.
|
||||
PyTorch에서 자신만의 이미지 캡션 데이터세트를 만들려면 [이 노트북](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
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
이 데이터세트는 `image`와 `text`라는 두 특성을 가지고 있습니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
많은 이미지 캡션 데이터세트에는 이미지당 여러 개의 캡션이 포함되어 있습니다.
|
||||
이러한 경우, 일반적으로 학습 중에 사용 가능한 캡션 중에서 무작위로 샘플을 추출합니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
[`~datasets.Dataset.train_test_split`] 메소드를 사용하여 데이터세트의 학습 분할을 학습 및 테스트 세트로 나눕니다:
|
||||
|
||||
|
||||
```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]]
|
||||
|
||||
데이터세트에는 이미지와 텍스트라는 두 가지 양식이 있기 때문에, 전처리 파이프라인에서 이미지와 캡션을 모두 전처리합니다.
|
||||
|
||||
전처리 작업을 위해, 파인튜닝하려는 모델에 연결된 프로세서 클래스를 가져옵니다.
|
||||
|
||||
```python
|
||||
from transformers import AutoProcessor
|
||||
|
||||
checkpoint = "microsoft/git-base"
|
||||
processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
프로세서는 내부적으로 크기 조정 및 픽셀 크기 조정을 포함한 이미지 전처리를 수행하고 캡션을 토큰화합니다.
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
데이터세트가 준비되었으니 이제 파인튜닝을 위해 모델을 설정할 수 있습니다.
|
||||
|
||||
## 기본 모델 가져오기[[load-a-base-model]]
|
||||
|
||||
["microsoft/git-base"](https://huggingface.co/microsoft/git-base)를 [`AutoModelForCausalLM`](https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoModelForCausalLM) 객체로 가져옵니다.
|
||||
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
## 평가[[evaluate]]
|
||||
|
||||
이미지 캡션 모델은 일반적으로 [Rouge 점수](https://huggingface.co/spaces/evaluate-metric/rouge) 또는 [단어 오류율(Word Error Rate)](https://huggingface.co/spaces/evaluate-metric/wer)로 평가합니다.
|
||||
이 가이드에서는 단어 오류율(WER)을 사용합니다.
|
||||
|
||||
이를 위해 🤗 Evaluate 라이브러리를 사용합니다.
|
||||
WER의 잠재적 제한 사항 및 기타 문제점은 [이 가이드](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!]]
|
||||
|
||||
이제 모델 파인튜닝을 시작할 준비가 되었습니다. 이를 위해 🤗 [`Trainer`]를 사용합니다.
|
||||
|
||||
먼저, [`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,
|
||||
)
|
||||
```
|
||||
|
||||
학습 인수를 데이터세트, 모델과 함께 🤗 Trainer에 전달합니다.
|
||||
|
||||
```python
|
||||
trainer = Trainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
train_dataset=train_ds,
|
||||
eval_dataset=test_ds,
|
||||
compute_metrics=compute_metrics,
|
||||
)
|
||||
```
|
||||
|
||||
학습을 시작하려면 [`Trainer`] 객체에서 [`~Trainer.train`]을 호출하기만 하면 됩니다.
|
||||
|
||||
```python
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
학습이 진행되면서 학습 손실이 원활하게 감소하는 것을 볼 수 있습니다.
|
||||
|
||||
학습이 완료되면 모든 사람이 모델을 사용할 수 있도록 [`~Trainer.push_to_hub`] 메소드를 사용하여 모델을 허브에 공유하세요:
|
||||
|
||||
|
||||
```python
|
||||
trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
`test_ds`에서 샘플 이미지를 가져와 모델을 테스트합니다.
|
||||
|
||||
|
||||
```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>
|
||||
|
||||
모델에 사용할 이미지를 준비합니다.
|
||||
|
||||
```python
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
|
||||
inputs = processor(images=image, return_tensors="pt").to(device)
|
||||
pixel_values = inputs.pixel_values
|
||||
```
|
||||
|
||||
[`generate`]를 호출하고 예측을 디코딩합니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
파인튜닝된 모델이 꽤 괜찮은 캡션을 생성한 것 같습니다!
|
||||
305
transformers/docs/source/ko/tasks/image_classification.md
Normal file
305
transformers/docs/source/ko/tasks/image_classification.md
Normal file
@@ -0,0 +1,305 @@
|
||||
<!--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"/>
|
||||
|
||||
이미지 분류는 이미지에 레이블 또는 클래스를 할당합니다. 텍스트 또는 오디오 분류와 달리 입력은
|
||||
이미지를 구성하는 픽셀 값입니다. 이미지 분류에는 자연재해 후 피해 감지, 농작물 건강 모니터링, 의료 이미지에서 질병의 징후 검사 지원 등
|
||||
다양한 응용 사례가 있습니다.
|
||||
|
||||
이 가이드에서는 다음을 설명합니다:
|
||||
|
||||
1. [Food-101](https://huggingface.co/datasets/food101) 데이터 세트에서 [ViT](model_doc/vit)를 미세 조정하여 이미지에서 식품 항목을 분류합니다.
|
||||
2. 추론을 위해 미세 조정 모델을 사용합니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/image-classification)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에, 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하여 모델을 업로드하고 커뮤니티에 공유하는 것을 권장합니다. 메시지가 표시되면, 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## Food-101 데이터 세트 가져오기[[load-food101-dataset]]
|
||||
|
||||
🤗 Datasets 라이브러리에서 Food-101 데이터 세트의 더 작은 부분 집합을 가져오는 것으로 시작합니다. 이렇게 하면 전체 데이터 세트에 대한
|
||||
훈련에 많은 시간을 할애하기 전에 실험을 통해 모든 것이 제대로 작동하는지 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> food = load_dataset("food101", split="train[:5000]")
|
||||
```
|
||||
|
||||
데이터 세트의 `train`을 [`~datasets.Dataset.train_test_split`] 메소드를 사용하여 훈련 및 테스트 세트로 분할하세요:
|
||||
|
||||
```py
|
||||
>>> food = food.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
그리고 예시를 살펴보세요:
|
||||
|
||||
```py
|
||||
>>> food["train"][0]
|
||||
{'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=512x512 at 0x7F52AFC8AC50>,
|
||||
'label': 79}
|
||||
```
|
||||
|
||||
데이터 세트의 각 예제에는 두 개의 필드가 있습니다:
|
||||
|
||||
- `image`: 식품 항목의 PIL 이미지
|
||||
- `label`: 식품 항목의 레이블 클래스
|
||||
|
||||
모델이 레이블 ID에서 레이블 이름을 쉽게 가져올 수 있도록
|
||||
레이블 이름을 정수로 매핑하고, 정수를 레이블 이름으로 매핑하는 사전을 만드세요:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
이제 레이블 ID를 레이블 이름으로 변환할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> id2label[str(79)]
|
||||
'prime_rib'
|
||||
```
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
다음 단계는 이미지를 텐서로 처리하기 위해 ViT 이미지 프로세서를 가져오는 것입니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
|
||||
>>> checkpoint = "google/vit-base-patch16-224-in21k"
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
이미지에 몇 가지 이미지 변환을 적용하여 과적합에 대해 모델을 더 견고하게 만듭니다. 여기서 Torchvision의 [`transforms`](https://pytorch.org/vision/stable/transforms.html) 모듈을 사용하지만, 원하는 이미지 라이브러리를 사용할 수도 있습니다.
|
||||
|
||||
이미지의 임의 부분을 크롭하고 크기를 조정한 다음, 이미지 평균과 표준 편차로 정규화하세요:
|
||||
|
||||
```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])
|
||||
```
|
||||
|
||||
그런 다음 전처리 함수를 만들어 변환을 적용하고 이미지의 `pixel_values`(모델에 대한 입력)를 반환하세요:
|
||||
|
||||
```py
|
||||
>>> def transforms(examples):
|
||||
... examples["pixel_values"] = [_transforms(img.convert("RGB")) for img in examples["image"]]
|
||||
... del examples["image"]
|
||||
... return examples
|
||||
```
|
||||
|
||||
전체 데이터 세트에 전처리 기능을 적용하려면 🤗 Datasets [`~datasets.Dataset.with_transform`]을 사용합니다. 데이터 세트의 요소를 가져올 때 변환이 즉시 적용됩니다:
|
||||
|
||||
```py
|
||||
>>> food = food.with_transform(transforms)
|
||||
```
|
||||
|
||||
이제 [`DefaultDataCollator`]를 사용하여 예제 배치를 만듭니다. 🤗 Transformers의 다른 데이터 콜레이터와 달리, `DefaultDataCollator`는 패딩과 같은 추가적인 전처리를 적용하지 않습니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
|
||||
## 평가[[evaluate]]
|
||||
|
||||
훈련 중에 평가 지표를 포함하면 모델의 성능을 평가하는 데 도움이 되는 경우가 많습니다.
|
||||
🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리로 평가 방법을 빠르게 가져올 수 있습니다. 이 작업에서는
|
||||
[accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) 평가 지표를 가져옵니다. (🤗 Evaluate [빠른 둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하여 평가 지표를 가져오고 계산하는 방법에 대해 자세히 알아보세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
그런 다음 예측과 레이블을 [`~evaluate.EvaluationModule.compute`]에 전달하여 정확도를 계산하는 함수를 만듭니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었으며, 훈련을 설정하면 이 함수로 되돌아올 것입니다.
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]를 사용하여 모델을 미세 조정하는 방법에 익숙하지 않은 경우, [여기](../training#train-with-pytorch-trainer)에서 기본 튜토리얼을 확인하세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델을 훈련시킬 준비가 되었습니다! [`AutoModelForImageClassification`]로 ViT를 가져옵니다. 예상되는 레이블 수, 레이블 매핑 및 레이블 수를 지정하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForImageClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForImageClassification.from_pretrained(
|
||||
... checkpoint,
|
||||
... num_labels=len(labels),
|
||||
... id2label=id2label,
|
||||
... label2id=label2id,
|
||||
... )
|
||||
```
|
||||
|
||||
이제 세 단계만 거치면 끝입니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 훈련 하이퍼파라미터를 정의하세요. `image` 열이 삭제되기 때문에 미사용 열을 제거하지 않는 것이 중요합니다. `image` 열이 없으면 `pixel_values`을 생성할 수 없습니다. 이 동작을 방지하려면 `remove_unused_columns=False`로 설정하세요! 다른 유일한 필수 매개변수는 모델 저장 위치를 지정하는 `output_dir`입니다. `push_to_hub=True`로 설정하면 이 모델을 허브에 푸시합니다(모델을 업로드하려면 Hugging Face에 로그인해야 합니다). 각 에폭이 끝날 때마다, [`Trainer`]가 정확도를 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. [`Trainer`]에 모델, 데이터 세트, 토크나이저, 데이터 콜레이터 및 `compute_metrics` 함수와 함께 훈련 인수를 전달하세요.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정하세요.
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
훈련이 완료되면, 모든 사람이 모델을 사용할 수 있도록 [`~transformers.Trainer.push_to_hub`] 메소드로 모델을 허브에 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
|
||||
<Tip>
|
||||
|
||||
이미지 분류를 위한 모델을 미세 조정하는 자세한 예제는 다음 [PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)을 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론을 수행하고자 하는 이미지를 가져와봅시다:
|
||||
|
||||
```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>
|
||||
|
||||
미세 조정 모델로 추론을 시도하는 가장 간단한 방법은 [`pipeline`]을 사용하는 것입니다. 모델로 이미지 분류를 위한 `pipeline`을 인스턴스화하고 이미지를 전달합니다:
|
||||
|
||||
```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'}]
|
||||
```
|
||||
|
||||
원한다면, `pipeline`의 결과를 수동으로 복제할 수도 있습니다:
|
||||
|
||||
이미지를 전처리하기 위해 이미지 프로세서를 가져오고 `input`을 PyTorch 텐서로 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
>>> import torch
|
||||
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained("my_awesome_food_model")
|
||||
>>> inputs = image_processor(image, return_tensors="pt")
|
||||
```
|
||||
|
||||
입력을 모델에 전달하고 logits을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForImageClassification
|
||||
|
||||
>>> model = AutoModelForImageClassification.from_pretrained("my_awesome_food_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
확률이 가장 높은 예측 레이블을 가져오고, 모델의 `id2label` 매핑을 사용하여 레이블로 변환합니다:
|
||||
|
||||
```py
|
||||
>>> predicted_label = logits.argmax(-1).item()
|
||||
>>> model.config.id2label[predicted_label]
|
||||
'beignets'
|
||||
```
|
||||
136
transformers/docs/source/ko/tasks/image_feature_extraction.md
Normal file
136
transformers/docs/source/ko/tasks/image_feature_extraction.md
Normal file
@@ -0,0 +1,136 @@
|
||||
<!--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` 파이프라인을 활용하여 간단한 이미지 유사성 시스템을 구축하는 방법을 배웁니다.
|
||||
- 기본 모델 추론으로 동일한 작업을 수행합니다.
|
||||
|
||||
## `image-feature-extraction` 파이프라인을 이용한 이미지 유사성[[image-similarity-using-image-feature-extraction-pipeline]]
|
||||
|
||||
물고기 그물 위에 앉아 있는 두 장의 고양이 사진이 있습니다. 이 중 하나는 생성된 이미지입니다.
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
파이프라인을 실행해 봅시다. 먼저 파이프라인을 초기화하세요. 모델을 지정하지 않으면, 파이프라인은 자동으로 [google/vit-base-patch16-224](google/vit-base-patch16-224) 모델로 초기화됩니다. 유사도를 계산하려면 `pool`을 True로 설정하세요.
|
||||
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import pipeline, infer_device
|
||||
|
||||
DEVICE = infer_device()
|
||||
pipe = pipeline(task="image-feature-extraction", model_name="google/vit-base-patch16-384", device=DEVICE, pool=True)
|
||||
```
|
||||
|
||||
`pipe`를 사용하여 추론하려면 두 이미지를 모두 전달하세요.
|
||||
|
||||
```python
|
||||
outputs = pipe([image_real, image_gen])
|
||||
```
|
||||
|
||||
출력에는 두 이미지의 풀링된(pooled) 임베딩이 포함되어 있습니다.
|
||||
|
||||
```python
|
||||
# 단일 출력의 길이 구하기
|
||||
print(len(outputs[0][0]))
|
||||
# 출력 결과 표시하기
|
||||
print(outputs)
|
||||
|
||||
# 768
|
||||
# [[[-0.03909236937761307, 0.43381670117378235, -0.06913255900144577,
|
||||
```
|
||||
|
||||
유사도 점수를 얻으려면, 이들을 유사도 함수에 전달해야 합니다.
|
||||
|
||||
```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])
|
||||
```
|
||||
|
||||
풀링 이전의 마지막 은닉 상태를 얻고 싶다면, `pool` 매개변수에 아무 값도 전달하지 마세요. 또한, 기본값은 `False`로 설정되어 있습니다. 이 은닉 상태는 모델의 특징을 기반으로 새로운 분류기나 모델을 훈련시키는 데 유용합니다.
|
||||
|
||||
```python
|
||||
pipe = pipeline(task="image-feature-extraction", model_name="google/vit-base-patch16-224", device=DEVICE)
|
||||
output = pipe(image_real)
|
||||
```
|
||||
|
||||
아직 출력이 풀링되지 않았기 때문에, 첫 번째 차원은 배치 크기이고 마지막 두 차원은 임베딩 형태인 마지막 은닉 상태를 얻을 수 있습니다.
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
print(np.array(outputs).shape)
|
||||
# (1, 197, 768)
|
||||
```
|
||||
|
||||
## `AutoModel`을 사용하여 특징과 유사성 얻기[[getting-features-and-similarities-using-automodel]]
|
||||
|
||||
transformers의 `AutoModel` 클래스를 사용하여 특징을 얻을 수도 있습니다. `AutoModel`은 작업 특화 헤드 없이 모든 transformers 모델을 로드할 수 있으며, 이를 통해 특징을 추출할 수 있습니다.
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
추론을 위한 간단한 함수를 작성해 보겠습니다. 먼저 입력값을 `processor`에 전달한 다음, 그 출력값을 `model`에 전달할 것입니다.
|
||||
|
||||
```python
|
||||
def infer(image):
|
||||
inputs = processor(image, return_tensors="pt").to(DEVICE)
|
||||
outputs = model(**inputs)
|
||||
return outputs.pooler_output
|
||||
```
|
||||
|
||||
이 함수에 이미지를 직접 전달하여 임베딩을 얻을 수 있습니다.
|
||||
|
||||
```python
|
||||
embed_real = infer(image_real)
|
||||
embed_gen = infer(image_gen)
|
||||
```
|
||||
|
||||
그리고 이 임베딩을 사용하여 다시 유사도를 계산할 수 있습니다.
|
||||
|
||||
```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>)
|
||||
```
|
||||
132
transformers/docs/source/ko/tasks/image_to_image.md
Normal file
132
transformers/docs/source/ko/tasks/image_to_image.md
Normal file
@@ -0,0 +1,132 @@
|
||||
<!--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 작업 가이드 [[image-to-image-task-guide]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Image-to-Image 작업은 애플리케이션이 이미지를 입력받아 또 다른 이미지를 출력하는 작업입니다. 여기에는 이미지 향상(초고해상도, 저조도 향상, 빗줄기 제거 등), 이미지 복원 등 다양한 하위 작업이 포함됩니다.
|
||||
|
||||
이 가이드에서는 다음을 수행하는 방법을 보여줍니다.
|
||||
- 초고해상도 작업을 위한 image-to-image 파이프라인 사용,
|
||||
- 파이프라인 없이 동일한 작업을 위한 image-to-image 모델 실행
|
||||
|
||||
이 가이드가 발표된 시점에서는, `image-to-image` 파이프라인은 초고해상도 작업만 지원한다는 점을 유의하세요.
|
||||
|
||||
필요한 라이브러리를 설치하는 것부터 시작하겠습니다.
|
||||
|
||||
```bash
|
||||
pip install transformers
|
||||
```
|
||||
|
||||
이제 [Swin2SR 모델](https://huggingface.co/caidas/swin2SR-lightweight-x2-64)을 사용하여 파이프라인을 초기화할 수 있습니다. 그런 다음 이미지와 함께 호출하여 파이프라인으로 추론할 수 있습니다. 현재 이 파이프라인에서는 [Swin2SR 모델](https://huggingface.co/caidas/swin2SR-lightweight-x2-64)만 지원됩니다.
|
||||
|
||||
```python
|
||||
from transformers import pipeline
|
||||
|
||||
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
pipe = pipeline(task="image-to-image", model="caidas/swin2SR-lightweight-x2-64", device=device)
|
||||
```
|
||||
|
||||
이제 이미지를 불러와 봅시다.
|
||||
|
||||
```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>
|
||||
|
||||
이제 파이프라인으로 추론을 수행할 수 있습니다. 고양이 이미지의 업스케일된 버전을 얻을 수 있습니다.
|
||||
|
||||
```python
|
||||
upscaled = pipe(image)
|
||||
print(upscaled.size)
|
||||
```
|
||||
```bash
|
||||
# (1072, 880)
|
||||
```
|
||||
|
||||
파이프라인 없이 직접 추론을 수행하려면 Transformers의 `Swin2SRForImageSuperResolution` 및 `Swin2SRImageProcessor` 클래스를 사용할 수 있습니다. 이를 위해 동일한 모델 체크포인트를 사용합니다. 모델과 프로세서를 초기화해 보겠습니다.
|
||||
|
||||
```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` 우리가 직접 수행해야 하는 전처리와 후처리 단계를 추상화하므로, 이미지를 전처리해 보겠습니다. 이미지를 프로세서에 전달한 다음 픽셀값을 GPU로 이동시키겠습니다.
|
||||
|
||||
```python
|
||||
pixel_values = processor(image, return_tensors="pt").pixel_values
|
||||
print(pixel_values.shape)
|
||||
|
||||
pixel_values = pixel_values.to(device)
|
||||
```
|
||||
|
||||
이제 픽셀값을 모델에 전달하여 이미지를 추론할 수 있습니다.
|
||||
|
||||
```python
|
||||
import torch
|
||||
|
||||
with torch.no_grad():
|
||||
outputs = model(pixel_values)
|
||||
```
|
||||
출력은 아래와 같은 `ImageSuperResolutionOutput` 유형의 객체입니다 👇
|
||||
|
||||
```
|
||||
(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)
|
||||
```
|
||||
`reconstruction`를 가져와 시각화를 위해 후처리해야 합니다. 어떻게 생겼는지 살펴봅시다.
|
||||
|
||||
```python
|
||||
outputs.reconstruction.data.shape
|
||||
# torch.Size([1, 3, 880, 1072])
|
||||
```
|
||||
|
||||
출력 텐서의 차원을 축소하고 0번째 축을 제거한 다음, 값을 클리핑하고 NumPy 부동소수점 배열로 변환해야 합니다. 그런 다음 [1072, 880] 모양을 갖도록 축을 재정렬하고 마지막으로 출력을 0과 255 사이의 값을 갖도록 되돌립니다.
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# 크기를 줄이고, CPU로 이동하고, 값을 클리핑
|
||||
output = outputs.reconstruction.data.squeeze().cpu().clamp_(0, 1).numpy()
|
||||
# 축을 재정렬
|
||||
output = np.moveaxis(output, source=0, destination=-1)
|
||||
# 값을 픽셀값 범위로 되돌리기
|
||||
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>
|
||||
155
transformers/docs/source/ko/tasks/keypoint_detection.md
Normal file
155
transformers/docs/source/ko/tasks/keypoint_detection.md
Normal file
@@ -0,0 +1,155 @@
|
||||
<!--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)은 이미지 내의 특정 포인트를 식별하고 위치를 탐지합니다. 이러한 키포인트는 랜드마크라고도 불리며 얼굴 특징이나 물체의 일부와 같은 의미 있는 특징을 나타냅니다.
|
||||
키포인트 감지 모델들은 이미지를 입력으로 받아 아래와 같은 출력을 반환합니다.
|
||||
|
||||
- **키포인트들과 점수**: 관심 포인트들과 해당 포인트에 대한 신뢰도 점수
|
||||
- **디스크립터(Descriptors)**: 각 키포인트를 둘러싼 이미지 영역의 표현으로 텍스처, 그라데이션, 방향 및 기타 속성을 캡처합니다.
|
||||
|
||||
이번 가이드에서는 이미지에서 키포인트를 추출하는 방법을 다루어 보겠습니다.
|
||||
|
||||
이번 튜토리얼에서는 키포인트 감지의 기본이 되는 모델인 [SuperPoint](./model_doc/superpoint)를 사용해보겠습니다.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor, SuperPointForKeypointDetection
|
||||
processor = AutoImageProcessor.from_pretrained("magic-leap-community/superpoint")
|
||||
model = SuperPointForKeypointDetection.from_pretrained("magic-leap-community/superpoint")
|
||||
```
|
||||
아래의 이미지로 모델을 테스트 해보겠습니다.
|
||||
|
||||
<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]
|
||||
```
|
||||
|
||||
이제 입력을 처리하고 추론을 할 수 있습니다.
|
||||
|
||||
|
||||
```python
|
||||
inputs = processor(images,return_tensors="pt").to(model.device, model.dtype)
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
모델 출력에는 배치 내의 각 항목에 대한 상대적인 키포인트, 디스크립터, 마스크와 점수가 있습니다. 마스크는 이미지에서 키포인트가 있는 영역을 강조하는 역할을 합니다.
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
이미지에 실제 키포인트를 표시하기 위해선 결과값을 후처리 해야합니다. 이를 위해 실제 이미지 크기를 결과값과 함께 `post_process_keypoint_detection`에 전달해야 합니다.
|
||||
|
||||
```python
|
||||
image_sizes = [(image.size[1], image.size[0]) for image in images]
|
||||
outputs = processor.post_process_keypoint_detection(outputs, image_sizes)
|
||||
```
|
||||
|
||||
위 코드를 통해 결과값은 딕셔너리를 갖는 리스트가 되고, 각 딕셔너리들은 후처리된 키포인트, 점수 및 디스크립터로 이루어져있습니다.
|
||||
|
||||
|
||||
```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]}]
|
||||
```
|
||||
|
||||
이제 위 딕셔너리를 사용하여 키포인트를 표시할 수 있습니다.
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
아래에서 결과를 확인할 수 있습니다.
|
||||
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<!--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)는 더 크고 복잡한 모델(교사)에서 더 작고 간단한 모델(학생)로 지식을 전달하는 기술입니다. 한 모델에서 다른 모델로 지식을 증류하기 위해, 특정 작업(이 경우 이미지 분류)에 대해 학습된 사전 훈련된 교사 모델을 사용하고, 랜덤으로 초기화된 학생 모델을 이미지 분류 작업에 대해 학습합니다. 그다음, 학생 모델이 교사 모델의 출력을 모방하여 두 모델의 출력 차이를 최소화하도록 훈련합니다. 이 기법은 Hinton 등 연구진의 [Distilling the Knowledge in a Neural Network](https://huggingface.co/papers/1503.02531)에서 처음 소개되었습니다. 이 가이드에서는 특정 작업에 맞춘 지식 증류를 수행할 것입니다. 이번에는 [beans dataset](https://huggingface.co/datasets/beans)을 사용할 것입니다.
|
||||
|
||||
이 가이드는 [미세 조정된 ViT 모델](https://huggingface.co/merve/vit-mobilenet-beans-224) (교사 모델)을 [MobileNet](https://huggingface.co/google/mobilenet_v2_1.4_224) (학생 모델)으로 증류하는 방법을 🤗 Transformers의 [Trainer API](https://huggingface.co/docs/transformers/en/main_classes/trainer#trainer) 를 사용하여 보여줍니다.
|
||||
|
||||
증류와 과정 평가를 위해 필요한 라이브러리를 설치해 봅시다.
|
||||
|
||||
|
||||
```bash
|
||||
pip install transformers datasets accelerate tensorboard evaluate --upgrade
|
||||
```
|
||||
|
||||
이 예제에서는 `merve/beans-vit-224` 모델을 교사 모델로 사용하고 있습니다. 이 모델은 beans 데이터셋에서 파인 튜닝된 `google/vit-base-patch16-224-in21k` 기반의 이미지 분류 모델입니다. 이 모델을 무작위로 초기화된 MobileNetV2로 증류해볼 것입니다.
|
||||
|
||||
이제 데이터셋을 로드하겠습니다.
|
||||
|
||||
```python
|
||||
from datasets import load_dataset
|
||||
|
||||
dataset = load_dataset("beans")
|
||||
```
|
||||
|
||||
이 경우 두 모델의 이미지 프로세서가 동일한 해상도로 동일한 출력을 반환하기 때문에, 두가지를 모두 사용할 수 있습니다. 데이터셋의 모든 분할마다 전처리를 적용하기 위해 `dataset`의 `map()` 메소드를 사용할 것 입니다.
|
||||
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
학생 모델(무작위로 초기화된 MobileNet)이 교사 모델(파인 튜닝된 비전 트랜스포머)을 모방하도록 할 것 입니다. 이를 위해 먼저 교사와 학생 모델의 로짓 출력값을 구합니다. 그런 다음 각 출력값을 매개변수 `temperature` 값으로 나누는데, 이 매개변수는 각 소프트 타겟의 중요도를 조절하는 역할을 합니다. 매개변수 `lambda` 는 증류 손실의 중요도에 가중치를 줍니다. 이 예제에서는 `temperature=5`와 `lambda=0.5`를 사용할 것입니다. 학생과 교사 간의 발산을 계산하기 위해 Kullback-Leibler Divergence 손실을 사용합니다. 두 데이터 P와 Q가 주어졌을 때, KL Divergence는 Q를 사용하여 P를 표현하는 데 얼만큼의 추가 정보가 필요한지를 말해줍니다. 두 데이터가 동일하다면, KL Divergence는 0이며, Q로 P를 설명하는 데 추가 정보가 필요하지 않음을 의미합니다. 따라서 지식 증류의 맥락에서 KL Divergence는 유용합니다.
|
||||
|
||||
|
||||
```python
|
||||
from transformers import TrainingArguments, Trainer
|
||||
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 = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
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)
|
||||
|
||||
# 교사와 학생의 소프트 타겟(soft targets) 계산
|
||||
|
||||
soft_teacher = F.softmax(teacher_output.logits / self.temperature, dim=-1)
|
||||
soft_student = F.log_softmax(student_output.logits / self.temperature, dim=-1)
|
||||
|
||||
# 손실(loss) 계산
|
||||
distillation_loss = self.loss_function(soft_student, soft_teacher) * (self.temperature ** 2)
|
||||
|
||||
# 실제 레이블 손실 계산
|
||||
student_target_loss = student_output.loss
|
||||
|
||||
# 최종 손실 계산
|
||||
loss = (1. - self.lambda_param) * student_target_loss + self.lambda_param * distillation_loss
|
||||
return (loss, student_output) if return_outputs else loss
|
||||
```
|
||||
|
||||
이제 Hugging Face Hub에 로그인하여 `Trainer`를 통해 Hugging Face Hub에 모델을 푸시할 수 있도록 하겠습니다.
|
||||
|
||||
|
||||
```python
|
||||
from huggingface_hub import notebook_login
|
||||
|
||||
notebook_login()
|
||||
```
|
||||
|
||||
이제 `TrainingArguments`, 교사 모델과 학생 모델을 설정하겠습니다.
|
||||
|
||||
|
||||
```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)
|
||||
|
||||
# 모델 초기화
|
||||
teacher_model = AutoModelForImageClassification.from_pretrained(
|
||||
"merve/beans-vit-224",
|
||||
num_labels=num_labels,
|
||||
ignore_mismatched_sizes=True
|
||||
)
|
||||
|
||||
# MobileNetV2 밑바닥부터 학습
|
||||
student_config = MobileNetV2Config()
|
||||
student_config.num_labels = num_labels
|
||||
student_model = MobileNetV2ForImageClassification(student_config)
|
||||
```
|
||||
|
||||
`compute_metrics` 함수를 사용하여 테스트 세트에서 모델을 평가할 수 있습니다. 이 함수는 훈련 과정에서 모델의 `accuracy`와 `f1`을 계산하는 데 사용됩니다.
|
||||
|
||||
|
||||
```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"]}
|
||||
```
|
||||
|
||||
정의한 훈련 인수로 `Trainer`를 초기화해봅시다. 또한 데이터 콜레이터(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,
|
||||
tokenizer=teacher_processor,
|
||||
compute_metrics=compute_metrics,
|
||||
temperature=5,
|
||||
lambda_param=0.5
|
||||
)
|
||||
```
|
||||
|
||||
이제 모델을 훈련할 수 있습니다.
|
||||
|
||||
```python
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
모델을 테스트 세트에서 평가할 수 있습니다.
|
||||
|
||||
```python
|
||||
trainer.evaluate(processed_datasets["test"])
|
||||
```
|
||||
|
||||
|
||||
테스트 세트에서 모델의 정확도는 72%에 도달했습니다. 증류의 효율성을 검증하기 위해 동일한 하이퍼파라미터로 beans 데이터셋에서 MobileNet을 처음부터 훈련하였고, 테스트 세트에서의 정확도는 63% 였습니다. 다양한 사전 훈련된 교사 모델, 학생 구조, 증류 매개변수를 시도해보시고 결과를 보고하기를 권장합니다. 증류된 모델의 훈련 로그와 체크포인트는 [이 저장소](https://huggingface.co/merve/vit-mobilenet-beans-224)에서 찾을 수 있으며, 처음부터 훈련된 MobileNetV2는 이 [저장소](https://huggingface.co/merve/resnet-mobilenet-beans-5)에서 찾을 수 있습니다.
|
||||
296
transformers/docs/source/ko/tasks/language_modeling.md
Normal file
296
transformers/docs/source/ko/tasks/language_modeling.md
Normal file
@@ -0,0 +1,296 @@
|
||||
<!--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]]
|
||||
|
||||
언어 모델링은 인과적 언어 모델링과 마스크드 언어 모델링, 두 가지 유형으로 나뉩니다. 이 가이드에서는 인과적 언어 모델링을 설명합니다.
|
||||
인과 언어 모델은 텍스트 생성에 자주 사용됩니다. 또 창의적인 방향으로 응용할 수 있습니다.
|
||||
직접 사용하며 재미있는 탐구를 해보거나, Copilot 또는 CodeParrot와 같은 지능형 코딩 어시스턴트의 기반이 되기도 합니다.
|
||||
|
||||
<Youtube id="Vpjb1lu0MDk"/>
|
||||
|
||||
인과 언어 모델링은 토큰 시퀀스에서 다음 토큰을 예측하며, 모델은 왼쪽의 토큰에만 접근할 수 있습니다.
|
||||
이는 모델이 미래의 토큰을 볼 수 없다는 것을 의미합니다. 인과 언어 모델의 예로 GPT-2가 있죠.
|
||||
|
||||
이 가이드에서는 다음 작업을 수행하는 방법을 안내합니다:
|
||||
|
||||
1. [DistilGPT2](https://huggingface.co/distilbert/distilgpt2) 모델을 [ELI5](https://huggingface.co/datasets/eli5) 데이터 세트의 [r/askscience](https://www.reddit.com/r/askscience/) 하위 집합으로 미세 조정
|
||||
2. 미세 조정된 모델을 추론에 사용
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/text-generation)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
커뮤니티에 모델을 업로드하고 공유하기 위해 Hugging Face 계정에 로그인하는 것을 권장합니다. 알림이 표시되면 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## ELI5 데이터 세트 불러오기[[load-eli5-dataset]]
|
||||
|
||||
먼저, 🤗 Datasets 라이브러리에서 r/askscience의 작은 하위 집합인 ELI5 데이터 세트를 불러옵니다.
|
||||
이를 통해 전체 데이터 세트에서 학습하는 데 더 많은 시간을 투자하기 전에, 실험해봄으로써 모든 것이 작동하는지 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> eli5 = load_dataset("eli5", split="train_asks[:5000]")
|
||||
```
|
||||
|
||||
데이터 세트의 `train_asks` 분할을 [`~datasets.Dataset.train_test_split`] 메소드를 사용하여 학습 및 테스트 세트로 분할합니다:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
그런 다음 예제를 살펴보세요:
|
||||
|
||||
```py
|
||||
>>> eli5["train"][0]
|
||||
{'answers': {'a_id': ['c3d1aib', 'c3d4lya'],
|
||||
'score': [6, 3],
|
||||
'text': ["The velocity needed to remain in orbit is equal to the square root of Newton's constant times the mass of earth divided by the distance from the center of the earth. I don't know the altitude of that specific mission, but they're usually around 300 km. That means he's going 7-8 km/s.\n\nIn space there are no other forces acting on either the shuttle or the guy, so they stay in the same position relative to each other. If he were to become unable to return to the ship, he would presumably run out of oxygen, or slowly fall into the atmosphere and burn up.",
|
||||
"Hope you don't mind me asking another question, but why aren't there any stars visible in this photo?"]},
|
||||
'answers_urls': {'url': []},
|
||||
'document': '',
|
||||
'q_id': 'nyxfp',
|
||||
'selftext': '_URL_0_\n\nThis was on the front page earlier and I have a few questions about it. Is it possible to calculate how fast the astronaut would be orbiting the earth? Also how does he stay close to the shuttle so that he can return safely, i.e is he orbiting at the same speed and can therefore stay next to it? And finally if his propulsion system failed, would he eventually re-enter the atmosphere and presumably die?',
|
||||
'selftext_urls': {'url': ['http://apod.nasa.gov/apod/image/1201/freeflyer_nasa_3000.jpg']},
|
||||
'subreddit': 'askscience',
|
||||
'title': 'Few questions about this space walk photograph.',
|
||||
'title_urls': {'url': []}}
|
||||
```
|
||||
|
||||
많아 보일 수 있지만, 실제로는 `text` 필드만 중요합니다. 언어 모델링 작업의 장점은 레이블이 필요하지 않다는 것입니다. 다음 단어 *자체가* 레이블입니다. (이렇게 레이블을 제공하지 않아도 되는 학습을 비지도 학습이라고 일컫습니다)
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
<Youtube id="ma1TrR7gE7I"/>
|
||||
|
||||
다음 단계는 `text` 필드를 전처리하기 위해 DistilGPT2 토크나이저를 불러오는 것입니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilgpt2")
|
||||
```
|
||||
|
||||
위의 예제에서 알 수 있듯이, `text` 필드는 `answers` 아래에 중첩되어 있습니다. 따라서 [`flatten`](https://huggingface.co/docs/datasets/process#flatten) 메소드를 사용하여 중첩 구조에서 `text` 하위 필드를 추출해야 합니다.
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.flatten()
|
||||
>>> eli5["train"][0]
|
||||
{'answers.a_id': ['c3d1aib', 'c3d4lya'],
|
||||
'answers.score': [6, 3],
|
||||
'answers.text': ["The velocity needed to remain in orbit is equal to the square root of Newton's constant times the mass of earth divided by the distance from the center of the earth. I don't know the altitude of that specific mission, but they're usually around 300 km. That means he's going 7-8 km/s.\n\nIn space there are no other forces acting on either the shuttle or the guy, so they stay in the same position relative to each other. If he were to become unable to return to the ship, he would presumably run out of oxygen, or slowly fall into the atmosphere and burn up.",
|
||||
"Hope you don't mind me asking another question, but why aren't there any stars visible in this photo?"],
|
||||
'answers_urls.url': [],
|
||||
'document': '',
|
||||
'q_id': 'nyxfp',
|
||||
'selftext': '_URL_0_\n\nThis was on the front page earlier and I have a few questions about it. Is it possible to calculate how fast the astronaut would be orbiting the earth? Also how does he stay close to the shuttle so that he can return safely, i.e is he orbiting at the same speed and can therefore stay next to it? And finally if his propulsion system failed, would he eventually re-enter the atmosphere and presumably die?',
|
||||
'selftext_urls.url': ['http://apod.nasa.gov/apod/image/1201/freeflyer_nasa_3000.jpg'],
|
||||
'subreddit': 'askscience',
|
||||
'title': 'Few questions about this space walk photograph.',
|
||||
'title_urls.url': []}
|
||||
```
|
||||
|
||||
각 하위 필드는 이제 `answers` 접두사를 가진 별도의 열로 나뉘었으며, `text` 필드는 이제 리스트입니다. 각 문장을 개별적으로 토큰화하는 대신, 먼저 리스트를 문자열로 변환하여 한꺼번에 토큰화할 수 있습니다.
|
||||
|
||||
다음은 문자열 리스트를 결합하고 결과를 토큰화하는 첫 번째 전처리 함수입니다:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
||||
```
|
||||
|
||||
이 전처리 함수를 전체 데이터 세트에 적용하려면 🤗 Datasets [`~datasets.Dataset.map`] 메소드를 사용하세요. `batched=True`로 설정하여 데이터셋의 여러 요소를 한 번에 처리하고, `num_proc`를 증가시켜 프로세스 수를 늘릴 수 있습니다. 필요 없는 열은 제거하세요:
|
||||
|
||||
```py
|
||||
>>> tokenized_eli5 = eli5.map(
|
||||
... preprocess_function,
|
||||
... batched=True,
|
||||
... num_proc=4,
|
||||
... remove_columns=eli5["train"].column_names,
|
||||
... )
|
||||
```
|
||||
|
||||
이제 데이터 세트는 시퀀스가 토큰화됐지만, 일부 시퀀스는 모델의 최대 입력 길이보다 길 수 있습니다.
|
||||
|
||||
이제 두 번째 전처리 함수를 사용하여
|
||||
- 모든 시퀀스를 연결하고,
|
||||
- `block_size`로 정의된 길이로 연결된 시퀀스를 여러 개의 짧은 묶음으로 나눕니다. 이 값은 최대 입력 길이와 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
|
||||
```
|
||||
|
||||
전체 데이터 세트에 `group_texts` 함수를 적용하세요:
|
||||
|
||||
```py
|
||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
||||
```
|
||||
|
||||
그런 다음 [`DataCollatorForLanguageModeling`]을 사용하여 예제의 배치를 만듭니다. 데이터 세트 전체를 최대 길이로 패딩하는 것보다, 취합 단계에서 각 배치의 최대 길이로 문장을 *동적으로 패딩*하는 것이 더 효율적입니다.
|
||||
|
||||
패딩 토큰으로 종결 토큰을 사용하고 `mlm=False`로 설정하세요. 이렇게 하면 입력을 오른쪽으로 한 칸씩 시프트한 값을 레이블로 사용합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForLanguageModeling
|
||||
|
||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]를 사용하여 모델을 미세 조정하는 방법을 잘 모르신다면 [기본 튜토리얼](../training#train-with-pytorch-trainer)을 확인해보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델을 훈련하기 준비가 되었습니다! [`AutoModelForCausalLM`]를 사용하여 DistilGPT2를 불러옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCausalLM, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")
|
||||
```
|
||||
|
||||
여기까지 진행하면 세 단계만 남았습니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 훈련 하이퍼파라미터를 정의하세요. `output_dir`은 유일한 필수 매개변수로, 모델을 저장할 위치를 지정합니다. (먼저 Hugging Face에 로그인 필수) `push_to_hub=True`로 설정하여 이 모델을 허브에 업로드할 수 있습니다.
|
||||
2. 훈련 인수를 [`Trainer`]에 모델, 데이터 세트 및 데이터 콜레이터와 함께 전달하세요.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정하세요.
|
||||
|
||||
```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,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
훈련이 완료되면 [`~transformers.Trainer.evaluate`] 메소드를 사용하여 모델을 평가하고 퍼플렉서티를 얻을 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> import math
|
||||
|
||||
>>> eval_results = trainer.evaluate()
|
||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
||||
Perplexity: 49.61
|
||||
```
|
||||
|
||||
그런 다음 [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 허브에 공유하세요. 이렇게 하면 누구나 모델을 사용할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
인과 언어 모델링을 위해 모델을 미세 조정하는 더 자세한 예제는 해당하는 [PyTorch 노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) 또는 [TensorFlow 노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)을 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 미세 조정했으므로 추론에 사용할 수 있습니다!
|
||||
|
||||
생성할 텍스트를 위한 프롬프트를 만들어보세요:
|
||||
|
||||
```py
|
||||
>>> prompt = "Somatic hypermutation allows the immune system to"
|
||||
```
|
||||
|
||||
추론을 위해 미세 조정된 모델을 간단히 사용하는 가장 간단한 방법은 [`pipeline`]에서 사용하는 것입니다. 모델과 함께 텍스트 생성을 위한 `pipeline`을 인스턴스화하고 텍스트를 전달하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> generator = pipeline("text-generation", model="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."}]
|
||||
```
|
||||
|
||||
텍스트를 토큰화하고 `input_ids`를 PyTorch 텐서로 반환하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_eli5_clm-model")
|
||||
>>> inputs = tokenizer(prompt, return_tensors="pt").input_ids
|
||||
```
|
||||
|
||||
[`~generation.GenerationMixin.generate`] 메소드를 사용하여 텍스트를 생성하세요. 생성을 제어하는 다양한 텍스트 생성 전략과 매개변수에 대한 자세한 내용은 [텍스트 생성 전략](../generation_strategies) 페이지를 확인하세요.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForCausalLM
|
||||
|
||||
>>> model = AutoModelForCausalLM.from_pretrained("my_awesome_eli5_clm-model")
|
||||
>>> outputs = model.generate(inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)
|
||||
```
|
||||
|
||||
생성된 토큰 ID를 다시 텍스트로 디코딩하세요:
|
||||
|
||||
```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"]
|
||||
```
|
||||
228
transformers/docs/source/ko/tasks/mask_generation.md
Normal file
228
transformers/docs/source/ko/tasks/mask_generation.md
Normal file
@@ -0,0 +1,228 @@
|
||||
<!--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)은 이미지에 대한 의미 있는 마스크를 생성하는 작업입니다.
|
||||
이 작업은 [이미지 분할](semantic_segmentation)과 매우 유사하지만, 많은 차이점이 있습니다. 이미지 분할 모델은 라벨이 달린 데이터셋으로 학습되며, 학습 중에 본 클래스들로만 제한됩니다. 이미지가 주어지면, 이미지 분할 모델은 여러 마스크와 그에 해당하는 클래스를 반환합니다.
|
||||
|
||||
반면, 마스크 생성 모델은 대량의 데이터로 학습되며 두 가지 모드로 작동합니다.
|
||||
- 프롬프트 모드(Prompting mode): 이 모드에서는 모델이 이미지와 프롬프트를 입력받습니다. 프롬프트는 이미지 내 객체의 2D 좌표(XY 좌표)나 객체를 둘러싼 바운딩 박스가 될 수 있습니다. 프롬프트 모드에서는 모델이 프롬프트가 가리키는 객체의 마스크만 반환합니다.
|
||||
- 전체 분할 모드(Segment Everything mode): 이 모드에서는 주어진 이미지 내에서 모든 마스크를 생성합니다. 이를 위해 그리드 형태의 점들을 생성하고 이를 이미지에 오버레이하여 추론합니다.
|
||||
|
||||
마스크 생성 작업은 [전체 분할 모드(Segment Anything Model, SAM)](model_doc/sam)에 의해 지원됩니다. SAM은 Vision Transformer 기반 이미지 인코더, 프롬프트 인코더, 그리고 양방향 트랜스포머 마스크 디코더로 구성된 강력한 모델입니다. 이미지와 프롬프트는 인코딩되고, 디코더는 이러한 임베딩을 받아 유효한 마스크를 생성합니다.
|
||||
|
||||
<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은 대규모 데이터를 다룰 수 있는 강력한 분할 기반 모델입니다. 이 모델은 100만 개의 이미지와 11억 개의 마스크를 포함하는 [SA-1B](https://ai.meta.com/datasets/segment-anything/) 데이터 세트로 학습되었습니다.
|
||||
|
||||
이 가이드에서는 다음과 같은 내용을 배우게 됩니다:
|
||||
- 배치 처리와 함께 전체 분할 모드에서 추론하는 방법
|
||||
- 포인트 프롬프팅 모드에서 추론하는 방법
|
||||
- 박스 프롬프팅 모드에서 추론하는 방법
|
||||
|
||||
먼저, `transformers`를 설치해 봅시다:
|
||||
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## 마스크 생성 파이프라인[[mask-generation-pipeline]]
|
||||
|
||||
마스크 생성 모델로 추론하는 가장 쉬운 방법은 `mask-generation` 파이프라인을 사용하는 것입니다.
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> checkpoint = "facebook/sam-vit-base"
|
||||
>>> mask_generator = pipeline(model=checkpoint, task="mask-generation")
|
||||
```
|
||||
|
||||
이미지를 예시로 봅시다.
|
||||
|
||||
```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>
|
||||
|
||||
전체적으로 분할해봅시다. `points-per-batch`는 전체 분할 모드에서 점들의 병렬 추론을 가능하게 합니다. 이를 통해 추론 속도가 빨라지지만, 더 많은 메모리를 소모하게 됩니다. 또한, SAM은 이미지가 아닌 점들에 대해서만 배치 처리를 지원합니다. `pred_iou_thresh`는 IoU 신뢰 임계값으로, 이 임계값을 초과하는 마스크만 반환됩니다.
|
||||
|
||||
```python
|
||||
masks = mask_generator(image, points_per_batch=128, pred_iou_thresh=0.88)
|
||||
```
|
||||
|
||||
`masks` 는 다음과 같이 생겼습니다:
|
||||
|
||||
```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,
|
||||
...,
|
||||
}
|
||||
```
|
||||
|
||||
위 내용을 아래와 같이 시각화할 수 있습니다:
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
아래는 회색조 원본 이미지에 다채로운 색상의 맵을 겹쳐놓은 모습입니다. 매우 인상적인 결과입니다.
|
||||
|
||||
<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]]
|
||||
|
||||
파이프라인 없이도 모델을 사용할 수 있습니다. 이를 위해 모델과 프로세서를 초기화해야 합니다.
|
||||
|
||||
```python
|
||||
from transformers import SamModel, SamProcessor
|
||||
import torch
|
||||
|
||||
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
||||
|
||||
model = SamModel.from_pretrained("facebook/sam-vit-base").to(device)
|
||||
processor = SamProcessor.from_pretrained("facebook/sam-vit-base")
|
||||
```
|
||||
|
||||
포인트 프롬프팅을 하기 위해, 입력 포인트를 프로세서에 전달한 다음, 프로세서 출력을 받아 모델에 전달하여 추론합니다. 모델 출력을 후처리하려면, 출력과 함께 프로세서의 초기 출력에서 가져온 `original_sizes`와 `reshaped_input_sizes`를 전달해야 합니다. 왜냐하면, 프로세서가 이미지 크기를 조정하고 출력을 추정해야 하기 때문입니다.
|
||||
|
||||
```python
|
||||
input_points = [[[2592, 1728]]] # 벌의 포인트 위치
|
||||
|
||||
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())
|
||||
```
|
||||
|
||||
`masks` 출력으로 세 가지 마스크를 시각화할 수 있습니다.
|
||||
|
||||
```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]]
|
||||
|
||||
박스 프롬프팅도 포인트 프롬프팅과 유사한 방식으로 할 수 있습니다. 입력 박스를 `[x_min, y_min, x_max, y_max]` 형식의 리스트로 작성하여 이미지와 함께 `processor`에 전달할 수 있습니다. 프로세서 출력을 받아 모델에 직접 전달한 후, 다시 출력을 후처리해야 합니다.
|
||||
|
||||
```python
|
||||
# 벌 주위의 바운딩 박스
|
||||
box = [2350, 1600, 2850, 2100]
|
||||
|
||||
inputs = processor(
|
||||
image,
|
||||
input_boxes=[[[box]]],
|
||||
return_tensors="pt"
|
||||
).to("cuda")
|
||||
|
||||
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()
|
||||
```
|
||||
|
||||
이제 아래와 같이, 벌 주위의 바운딩 박스를 시각화할 수 있습니다.
|
||||
|
||||
```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>
|
||||
|
||||
아래에서 추론 결과를 확인할 수 있습니다.
|
||||
|
||||
```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>
|
||||
319
transformers/docs/source/ko/tasks/masked_language_modeling.md
Normal file
319
transformers/docs/source/ko/tasks/masked_language_modeling.md
Normal file
@@ -0,0 +1,319 @@
|
||||
<!--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)[[masked-language-modeling]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="mqElG5QJWUg"/>
|
||||
|
||||
마스킹된 언어 모델링은 시퀀스에서 마스킹된 토큰을 예측하며, 모델은 양방향으로 토큰에 액세스할 수 있습니다.
|
||||
즉, 모델은 토큰의 왼쪽과 오른쪽 양쪽에서 접근할 수 있습니다.
|
||||
마스킹된 언어 모델링은 전체 시퀀스에 대한 문맥적 이해가 필요한 작업에 적합하며, BERT가 그 예에 해당합니다.
|
||||
|
||||
이번 가이드에서 다룰 내용은 다음과 같습니다:
|
||||
|
||||
1. [ELI5](https://huggingface.co/datasets/eli5) 데이터 세트에서 [r/askscience](https://www.reddit.com/r/askscience/) 부분을 사용해 [DistilRoBERTa](https://huggingface.co/distilbert/distilroberta-base) 모델을 미세 조정합니다.
|
||||
2. 추론 시에 직접 미세 조정한 모델을 사용합니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/fill-mask)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하여 모델을 업로드하고 커뮤니티와의 공유를 권장합니다. 메시지가 표시되면(When prompted) 토큰을 입력하여 로그인합니다:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## ELI5 데이터 세트 가져오기[[load-eli5-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 ELI5 데이터 세트의 r/askscience 중 일부만 가져옵니다.
|
||||
이렇게 하면 전체 데이터 세트 학습에 더 많은 시간을 할애하기 전에 모든 것이 작동하는지 실험하고 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> eli5 = load_dataset("eli5", split="train_asks[:5000]")
|
||||
```
|
||||
|
||||
데이터 세트의 `train_asks`를 [`~datasets.Dataset.train_test_split`] 메소드를 사용해 훈련 데이터와 테스트 데이터로 분할합니다:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
그리고 아래 예시를 살펴보세요:
|
||||
|
||||
```py
|
||||
>>> eli5["train"][0]
|
||||
{'answers': {'a_id': ['c3d1aib', 'c3d4lya'],
|
||||
'score': [6, 3],
|
||||
'text': ["The velocity needed to remain in orbit is equal to the square root of Newton's constant times the mass of earth divided by the distance from the center of the earth. I don't know the altitude of that specific mission, but they're usually around 300 km. That means he's going 7-8 km/s.\n\nIn space there are no other forces acting on either the shuttle or the guy, so they stay in the same position relative to each other. If he were to become unable to return to the ship, he would presumably run out of oxygen, or slowly fall into the atmosphere and burn up.",
|
||||
"Hope you don't mind me asking another question, but why aren't there any stars visible in this photo?"]},
|
||||
'answers_urls': {'url': []},
|
||||
'document': '',
|
||||
'q_id': 'nyxfp',
|
||||
'selftext': '_URL_0_\n\nThis was on the front page earlier and I have a few questions about it. Is it possible to calculate how fast the astronaut would be orbiting the earth? Also how does he stay close to the shuttle so that he can return safely, i.e is he orbiting at the same speed and can therefore stay next to it? And finally if his propulsion system failed, would he eventually re-enter the atmosphere and presumably die?',
|
||||
'selftext_urls': {'url': ['http://apod.nasa.gov/apod/image/1201/freeflyer_nasa_3000.jpg']},
|
||||
'subreddit': 'askscience',
|
||||
'title': 'Few questions about this space walk photograph.',
|
||||
'title_urls': {'url': []}}
|
||||
```
|
||||
|
||||
많아 보일 수 있지만 실제로는 `text` 필드에만 집중하면 됩나다.
|
||||
언어 모델링 작업의 멋진 점은 (비지도 학습으로) *다음 단어가 레이블*이기 때문에 레이블이 따로 필요하지 않습니다.
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
<Youtube id="8PmhEIXhBvI"/>
|
||||
|
||||
마스킹된 언어 모델링을 위해, 다음 단계로 DistilRoBERTa 토크나이저를 가져와서 `text` 하위 필드를 처리합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilroberta-base")
|
||||
```
|
||||
|
||||
위의 예제에서와 마찬가지로, `text` 필드는 `answers` 안에 중첩되어 있습니다.
|
||||
따라서 중첩된 구조에서 [`flatten`](https://huggingface.co/docs/datasets/process#flatten) 메소드를 사용하여 `text` 하위 필드를 추출합니다:
|
||||
|
||||
```py
|
||||
>>> eli5 = eli5.flatten()
|
||||
>>> eli5["train"][0]
|
||||
{'answers.a_id': ['c3d1aib', 'c3d4lya'],
|
||||
'answers.score': [6, 3],
|
||||
'answers.text': ["The velocity needed to remain in orbit is equal to the square root of Newton's constant times the mass of earth divided by the distance from the center of the earth. I don't know the altitude of that specific mission, but they're usually around 300 km. That means he's going 7-8 km/s.\n\nIn space there are no other forces acting on either the shuttle or the guy, so they stay in the same position relative to each other. If he were to become unable to return to the ship, he would presumably run out of oxygen, or slowly fall into the atmosphere and burn up.",
|
||||
"Hope you don't mind me asking another question, but why aren't there any stars visible in this photo?"],
|
||||
'answers_urls.url': [],
|
||||
'document': '',
|
||||
'q_id': 'nyxfp',
|
||||
'selftext': '_URL_0_\n\nThis was on the front page earlier and I have a few questions about it. Is it possible to calculate how fast the astronaut would be orbiting the earth? Also how does he stay close to the shuttle so that he can return safely, i.e is he orbiting at the same speed and can therefore stay next to it? And finally if his propulsion system failed, would he eventually re-enter the atmosphere and presumably die?',
|
||||
'selftext_urls.url': ['http://apod.nasa.gov/apod/image/1201/freeflyer_nasa_3000.jpg'],
|
||||
'subreddit': 'askscience',
|
||||
'title': 'Few questions about this space walk photograph.',
|
||||
'title_urls.url': []}
|
||||
```
|
||||
|
||||
이제 각 하위 필드는 `answers` 접두사(prefix)로 표시된 대로 별도의 열이 되고, `text` 필드는 이제 리스트가 되었습니다.
|
||||
각 문장을 개별적으로 토큰화하는 대신 리스트를 문자열로 변환하여 한번에 토큰화할 수 있습니다.
|
||||
|
||||
다음은 각 예제에 대해 문자열로 이루어진 리스트를 `join`하고 결과를 토큰화하는 첫 번째 전처리 함수입니다:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
||||
```
|
||||
|
||||
이 전처리 함수를 전체 데이터 세트에 적용하기 위해 🤗 Datasets [`~datasets.Dataset.map`] 메소드를 사용합니다.
|
||||
데이터 세트의 여러 요소를 한 번에 처리하도록 `batched=True`를 설정하고 `num_proc`로 처리 횟수를 늘리면 `map` 함수의 속도를 높일 수 있습니다.
|
||||
필요하지 않은 열은 제거합니다:
|
||||
|
||||
```py
|
||||
>>> tokenized_eli5 = eli5.map(
|
||||
... preprocess_function,
|
||||
... batched=True,
|
||||
... num_proc=4,
|
||||
... remove_columns=eli5["train"].column_names,
|
||||
... )
|
||||
```
|
||||
|
||||
이 데이터 세트에는 토큰 시퀀스가 포함되어 있지만 이 중 일부는 모델의 최대 입력 길이보다 깁니다.
|
||||
|
||||
이제 두 번째 전처리 함수를 사용해
|
||||
- 모든 시퀀스를 연결하고
|
||||
- 연결된 시퀀스를 정의한 `block_size` 보다 더 짧은 덩어리로 분할하는데, 이 덩어리는 모델의 최대 입력 길이보다 짧고 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
|
||||
```
|
||||
|
||||
전체 데이터 세트에 `group_texts` 함수를 적용합니다:
|
||||
|
||||
```py
|
||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
||||
```
|
||||
|
||||
이제 [`DataCollatorForLanguageModeling`]을 사용하여 데이터 예제의 배치를 생성합니다.
|
||||
데이터 세트 전체를 최대 길이로 패딩하는 것보다 collation 단계에서 매 배치안에서의 최대 길이로 문장을 *동적으로 패딩*하는 것이 더 효율적입니다.
|
||||
|
||||
|
||||
시퀀스 끝 토큰을 패딩 토큰으로 사용하고 데이터를 반복할 때마다 토큰을 무작위로 마스킹하도록 `mlm_-probability`를 지정합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForLanguageModeling
|
||||
|
||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
|
||||
```
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]로 모델을 미세 조정하는 데 익숙하지 않다면 기본 튜토리얼 [여기](../training#train-with-pytorch-trainer)를 살펴보세요!
|
||||
</Tip>
|
||||
|
||||
이제 모델 훈련을 시작할 준비가 되었습니다! [`AutoModelForMaskedLM`]를 사용해 DistilRoBERTa 모델을 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMaskedLM
|
||||
|
||||
>>> model = AutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")
|
||||
```
|
||||
|
||||
이제 세 단계가 남았습니다:
|
||||
|
||||
1. [`TrainingArguments`]의 훈련 하이퍼파라미터를 정의합니다. 모델 저장 위치를 지정하는 `output_dir`은 유일한 필수 파라미터입니다. `push_to_hub=True`를 설정하여 이 모델을 Hub에 업로드합니다 (모델을 업로드하려면 Hugging Face에 로그인해야 합니다).
|
||||
2. 모델, 데이터 세트 및 데이터 콜레이터(collator)와 함께 훈련 인수를 [`Trainer`]에 전달합니다.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정합니다.
|
||||
|
||||
```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,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
훈련이 완료되면 [`~transformers.Trainer.evaluate`] 메소드를 사용하여 펄플렉서티(perplexity)를 계산하고 모델을 평가합니다:
|
||||
|
||||
```py
|
||||
>>> import math
|
||||
|
||||
>>> eval_results = trainer.evaluate()
|
||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
||||
Perplexity: 8.76
|
||||
```
|
||||
|
||||
그리고 [`~transformers.Trainer.push_to_hub`] 메소드를 사용해 다른 사람들이 사용할 수 있도록, Hub로 모델을 업로드합니다.
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
마스킹된 언어 모델링을 위해 모델을 미세 조정하는 방법에 대한 보다 심층적인 예제는
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)
|
||||
또는 [TensorFlow notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)을 참조하세요.
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
지금까지 모델 미세 조정을 잘 했으니, 추론에 사용할 수 있습니다!
|
||||
|
||||
모델이 빈칸을 채울 텍스트를 스페셜 토큰(special token)인 `<mask>` 토큰으로 표시합니다:
|
||||
|
||||
|
||||
```py
|
||||
>>> text = "The Milky Way is a <mask> galaxy."
|
||||
```
|
||||
추론을 위해 미세 조정한 모델을 테스트하는 가장 간단한 방법은 [`pipeline`]에서 사용하는 것입니다.
|
||||
`fill-mask`태스크로 `pipeline`을 인스턴스화하고 텍스트를 전달합니다.
|
||||
`top_k` 매개변수를 사용하여 반환하는 예측의 수를 지정할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> mask_filler = pipeline("fill-mask", "stevhliu/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.'}]
|
||||
```
|
||||
|
||||
텍스트를 토큰화하고 `input_ids`를 PyTorch 텐서 형태로 반환합니다.
|
||||
또한, `<mask>` 토큰의 위치를 지정해야 합니다:
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_eli5_mlm_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
>>> mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
|
||||
```
|
||||
|
||||
모델에 `inputs`를 입력하고, 마스킹된 토큰의 `logits`를 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMaskedLM
|
||||
|
||||
>>> model = AutoModelForMaskedLM.from_pretrained("stevhliu/my_awesome_eli5_mlm_model")
|
||||
>>> logits = model(**inputs).logits
|
||||
>>> mask_token_logits = logits[0, mask_token_index, :]
|
||||
```
|
||||
|
||||
그런 다음 가장 높은 확률은 가진 마스크 토큰 3개를 반환하고, 출력합니다:
|
||||
```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.
|
||||
```
|
||||
144
transformers/docs/source/ko/tasks/monocular_depth_estimation.md
Normal file
144
transformers/docs/source/ko/tasks/monocular_depth_estimation.md
Normal file
@@ -0,0 +1,144 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
# 단일 영상 기반 깊이 추정[[depth-estimation-pipeline]]
|
||||
|
||||
단일 영상 기반 깊이 추정은 한 장면의 단일 이미지에서 장면의 깊이 정보를 예측하는 컴퓨터 비전 작업입니다.
|
||||
즉, 단일 카메라 시점의 장면에 있는 물체의 거리를 예측하는 과정입니다.
|
||||
|
||||
단일 영상 기반 깊이 추정은 3D 재구성, 증강 현실, 자율 주행, 로봇 공학 등 다양한 분야에서 응용됩니다.
|
||||
조명 조건, 가려짐, 텍스처와 같은 요소의 영향을 받을 수 있는 장면 내 물체와 해당 깊이 정보 간의 복잡한 관계를 모델이 이해해야 하므로 까다로운 작업입니다.
|
||||
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/depth-estimation)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
이번 가이드에서 배울 내용은 다음과 같습니다:
|
||||
|
||||
* 깊이 추정 파이프라인 만들기
|
||||
* 직접 깊이 추정 추론하기
|
||||
|
||||
시작하기 전에, 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## 깊이 추정 파이프라인[[depth-estimation-inference-by-hand]]
|
||||
|
||||
깊이 추정을 추론하는 가장 간단한 방법은 해당 기능을 제공하는 [`pipeline`]을 사용하는 것입니다.
|
||||
[Hugging Face Hub 체크포인트](https://huggingface.co/models?pipeline_tag=depth-estimation&sort=downloads)에서 파이프라인을 초기화합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> checkpoint = "vinvino02/glpn-nyu"
|
||||
>>> depth_estimator = pipeline("depth-estimation", model=checkpoint)
|
||||
```
|
||||
|
||||
|
||||
다음으로, 분석할 이미지를 한 장 선택하세요:
|
||||
|
||||
```py
|
||||
>>> from PIL import Image
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://unsplash.com/photos/HwBAsSbPBDU/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MzR8fGNhciUyMGluJTIwdGhlJTIwc3RyZWV0fGVufDB8MHx8fDE2Nzg5MDEwODg&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/depth-estimation-example.jpg" alt="Photo of a busy street"/>
|
||||
</div>
|
||||
|
||||
이미지를 파이프라인으로 전달합니다.
|
||||
|
||||
```py
|
||||
>>> predictions = depth_estimator(image)
|
||||
```
|
||||
|
||||
파이프라인은 두 개의 항목을 가지는 딕셔너리를 반환합니다.
|
||||
첫 번째는 `predicted_depth`로 각 픽셀의 깊이를 미터로 표현한 값을 가지는 텐서입니다.
|
||||
두 번째는 `depth`로 깊이 추정 결과를 시각화하는 PIL 이미지입니다.
|
||||
|
||||
이제 시각화한 결과를 살펴보겠습니다:
|
||||
|
||||
```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]]
|
||||
|
||||
이제 깊이 추정 파이프라인 사용법을 살펴보았으니 동일한 결과를 복제하는 방법을 살펴보겠습니다.
|
||||
[Hugging Face Hub 체크포인트](https://huggingface.co/models?pipeline_tag=depth-estimation&sort=downloads)에서 모델과 관련 프로세서를 가져오는 것부터 시작합니다.
|
||||
여기서 이전에 사용한 체크포인트와 동일한 것을 사용합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor, AutoModelForDepthEstimation
|
||||
|
||||
>>> checkpoint = "vinvino02/glpn-nyu"
|
||||
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
|
||||
>>> model = AutoModelForDepthEstimation.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
필요한 이미지 변환을 처리하는 `image_processor`를 사용하여 모델에 대한 이미지 입력을 준비합니다.
|
||||
`image_processor`는 크기 조정 및 정규화 등 필요한 이미지 변환을 처리합니다:
|
||||
|
||||
```py
|
||||
>>> pixel_values = image_processor(image, return_tensors="pt").pixel_values
|
||||
```
|
||||
|
||||
준비한 입력을 모델로 전달합니다:
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(pixel_values)
|
||||
... predicted_depth = outputs.predicted_depth
|
||||
```
|
||||
|
||||
결과를 시각화합니다:
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
|
||||
>>> # 원본 사이즈로 복원
|
||||
>>> prediction = torch.nn.functional.interpolate(
|
||||
... predicted_depth.unsqueeze(1),
|
||||
... size=image.size[::-1],
|
||||
... mode="bicubic",
|
||||
... align_corners=False,
|
||||
... ).squeeze()
|
||||
>>> output = prediction.numpy()
|
||||
|
||||
>>> formatted = (output * 255 / np.max(output)).astype("uint8")
|
||||
>>> depth = Image.fromarray(formatted)
|
||||
>>> 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>
|
||||
247
transformers/docs/source/ko/tasks/multiple_choice.md
Normal file
247
transformers/docs/source/ko/tasks/multiple_choice.md
Normal file
@@ -0,0 +1,247 @@
|
||||
<!--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]]
|
||||
|
||||
객관식 과제는 문맥과 함께 여러 개의 후보 답변이 제공되고 모델이 정답을 선택하도록 학습된다는 점을 제외하면 질의응답과 유사합니다.
|
||||
|
||||
진행하는 방법은 아래와 같습니다:
|
||||
|
||||
1. [SWAG](https://huggingface.co/datasets/swag) 데이터 세트의 'regular' 구성으로 [BERT](https://huggingface.co/google-bert/bert-base-uncased)를 미세 조정하여 여러 옵션과 일부 컨텍스트가 주어졌을 때 가장 적합한 답을 선택합니다.
|
||||
2. 추론에 미세 조정된 모델을 사용합니다.
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
모델을 업로드하고 커뮤니티와 공유할 수 있도록 허깅페이스 계정에 로그인하는 것이 좋습니다. 메시지가 표시되면 토큰을 입력하여 로그인합니다:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## SWAG 데이터 세트 가져오기[[load-swag-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 SWAG 데이터셋의 '일반' 구성을 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> swag = load_dataset("swag", "regular")
|
||||
```
|
||||
|
||||
이제 데이터를 살펴봅니다:
|
||||
|
||||
```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'}
|
||||
```
|
||||
|
||||
여기에는 많은 필드가 있는 것처럼 보이지만 실제로는 매우 간단합니다:
|
||||
|
||||
- `sent1` 및 `sent2`: 이 필드는 문장이 어떻게 시작되는지 보여주며, 이 두 필드를 합치면 `시작 구절(startphrase)` 필드가 됩니다.
|
||||
- `종료 구절(ending)`: 문장이 어떻게 끝날 수 있는지에 대한 가능한 종료 구절를 제시하지만 그 중 하나만 정답입니다.
|
||||
- `레이블(label)`: 올바른 문장 종료 구절을 식별합니다.
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
다음 단계는 문장의 시작과 네 가지 가능한 구절을 처리하기 위해 BERT 토크나이저를 불러옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
||||
```
|
||||
|
||||
생성하려는 전처리 함수는 다음과 같아야 합니다:
|
||||
|
||||
1. `sent1` 필드를 네 개 복사한 다음 각각을 `sent2`와 결합하여 문장이 시작되는 방식을 재현합니다.
|
||||
2. `sent2`를 네 가지 가능한 문장 구절 각각과 결합합니다.
|
||||
3. 이 두 목록을 토큰화할 수 있도록 평탄화(flatten)하고, 각 예제에 해당하는 `input_ids`, `attention_mask` 및 `labels` 필드를 갖도록 다차원화(unflatten) 합니다.
|
||||
|
||||
```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()}
|
||||
```
|
||||
|
||||
전체 데이터 집합에 전처리 기능을 적용하려면 🤗 Datasets [`~datasets.Dataset.map`] 메소드를 사용합니다. `batched=True`를 설정하여 데이터 집합의 여러 요소를 한 번에 처리하면 `map` 함수의 속도를 높일 수 있습니다:
|
||||
|
||||
```py
|
||||
tokenized_swag = swag.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
[`DataCollatorForMultipleChoice`]는 모든 모델 입력을 평탄화하고 패딩을 적용하며 그 결과를 결과를 다차원화합니다:
|
||||
```py
|
||||
>>> from transformers import DataCollatorForMultipleChoice
|
||||
>>> collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## 평가 하기[[evaluate]]
|
||||
|
||||
훈련 중에 메트릭을 포함하면 모델의 성능을 평가하는 데 도움이 되는 경우가 많습니다. 🤗[Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하여 평가 방법을 빠르게 가져올 수 있습니다. 이 작업에서는 [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) 지표를 가져옵니다(🤗 Evaluate [둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하여 지표를 가져오고 계산하는 방법에 대해 자세히 알아보세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
그리고 예측과 레이블을 [`~evaluate.EvaluationModule.compute`]에 전달하여 정확도를 계산하는 함수를 만듭니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었으며, 훈련을 설정할 때 이 함수로 돌아가게 됩니다.
|
||||
|
||||
## 훈련 하기[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]로 모델을 미세 조정하는 데 익숙하지 않다면 기본 튜토리얼 [여기](../training#train-with-pytorch-trainer)를 살펴보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델 훈련을 시작할 준비가 되었습니다! [`AutoModelForMultipleChoice`]로 BERT를 로드합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
|
||||
```
|
||||
|
||||
이제 세 단계만 남았습니다:
|
||||
|
||||
1. 훈련 하이퍼파라미터를 [`TrainingArguments`]에 정의합니다. 유일한 필수 매개변수는 모델을 저장할 위치를 지정하는 `output_dir`입니다. `push_to_hub=True`를 설정하여 이 모델을 허브에 푸시합니다(모델을 업로드하려면 허깅 페이스에 로그인해야 합니다). 각 에폭이 끝날 때마다 [`Trainer`]가 정확도를 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. 모델, 데이터 세트, 토크나이저, 데이터 콜레이터, `compute_metrics` 함수와 함께 훈련 인자를 [`Trainer`]에 전달합니다.
|
||||
3. [`~Trainer.train`]을 사용하여 모델을 미세 조정합니다.
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
훈련이 완료되면 모든 사람이 모델을 사용할 수 있도록 [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 허브에 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
|
||||
<Tip>
|
||||
|
||||
객관식 모델을 미세 조정하는 방법에 대한 보다 심층적인 예는 아래 문서를 참조하세요.
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)
|
||||
또는 [TensorFlow notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb).
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론 하기[[inference]]
|
||||
|
||||
이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
텍스트와 두 개의 후보 답안을 작성합니다:
|
||||
|
||||
```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."
|
||||
```
|
||||
|
||||
각 프롬프트와 후보 답변 쌍을 토큰화하여 PyTorch 텐서를 반환합니다. 또한 `labels`을 생성해야 합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_swag_model")
|
||||
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
|
||||
>>> labels = torch.tensor(0).unsqueeze(0)
|
||||
```
|
||||
|
||||
입력과 레이블을 모델에 전달하고 `logits`을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForMultipleChoice
|
||||
|
||||
>>> model = AutoModelForMultipleChoice.from_pretrained("my_awesome_swag_model")
|
||||
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
|
||||
>>> logits = outputs.logits
|
||||
```
|
||||
|
||||
가장 높은 확률을 가진 클래스를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> predicted_class = logits.argmax().item()
|
||||
>>> predicted_class
|
||||
'0'
|
||||
```
|
||||
583
transformers/docs/source/ko/tasks/object_detection.md
Normal file
583
transformers/docs/source/ko/tasks/object_detection.md
Normal file
@@ -0,0 +1,583 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
# 객체 탐지 [[object-detection]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
객체 탐지는 이미지에서 인스턴스(예: 사람, 건물 또는 자동차)를 감지하는 컴퓨터 비전 작업입니다. 객체 탐지 모델은 이미지를 입력으로 받고 탐지된 바운딩 박스의 좌표와 관련된 레이블을 출력합니다.
|
||||
하나의 이미지에는 여러 객체가 있을 수 있으며 각각은 자체적인 바운딩 박스와 레이블을 가질 수 있습니다(예: 차와 건물이 있는 이미지).
|
||||
또한 각 객체는 이미지의 다른 부분에 존재할 수 있습니다(예: 이미지에 여러 대의 차가 있을 수 있음).
|
||||
이 작업은 보행자, 도로 표지판, 신호등과 같은 것들을 감지하는 자율 주행에 일반적으로 사용됩니다.
|
||||
다른 응용 분야로는 이미지 내 객체 수 계산 및 이미지 검색 등이 있습니다.
|
||||
|
||||
이 가이드에서 다음을 배울 것입니다:
|
||||
|
||||
1. 합성곱 백본(인풋 데이터의 특성을 추출하는 합성곱 네트워크)과 인코더-디코더 트랜스포머 모델을 결합한 [DETR](https://huggingface.co/docs/transformers/model_doc/detr) 모델을 [CPPE-5](https://huggingface.co/datasets/cppe-5) 데이터 세트에 대해 미세조정 하기
|
||||
2. 미세조정 한 모델을 추론에 사용하기.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/object-detection)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
```bash
|
||||
pip install -q datasets transformers evaluate timm albumentations
|
||||
```
|
||||
|
||||
허깅페이스 허브에서 데이터 세트를 가져오기 위한 🤗 Datasets과 모델을 학습하기 위한 🤗 Transformers, 데이터를 증강하기 위한 `albumentations`를 사용합니다.
|
||||
DETR 모델의 합성곱 백본을 가져오기 위해서는 현재 `timm`이 필요합니다.
|
||||
|
||||
커뮤니티에 모델을 업로드하고 공유할 수 있도록 Hugging Face 계정에 로그인하는 것을 권장합니다. 프롬프트가 나타나면 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## CPPE-5 데이터 세트 가져오기 [[load-the-CPPE-5-dataset]]
|
||||
|
||||
[CPPE-5](https://huggingface.co/datasets/cppe-5) 데이터 세트는 COVID-19 대유행 상황에서 의료 전문인력 보호 장비(PPE)를 식별하는 어노테이션이 포함된 이미지를 담고 있습니다.
|
||||
|
||||
데이터 세트를 가져오세요:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> cppe5 = load_dataset("cppe-5")
|
||||
>>> cppe5
|
||||
DatasetDict({
|
||||
train: Dataset({
|
||||
features: ['image_id', 'image', 'width', 'height', 'objects'],
|
||||
num_rows: 1000
|
||||
})
|
||||
test: Dataset({
|
||||
features: ['image_id', 'image', 'width', 'height', 'objects'],
|
||||
num_rows: 29
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
이 데이터 세트는 학습 세트 이미지 1,000개와 테스트 세트 이미지 29개를 갖고 있습니다.
|
||||
|
||||
데이터에 익숙해지기 위해, 예시가 어떻게 구성되어 있는지 살펴보세요.
|
||||
|
||||
```py
|
||||
>>> cppe5["train"][0]
|
||||
{'image_id': 15,
|
||||
'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=943x663 at 0x7F9EC9E77C10>,
|
||||
'width': 943,
|
||||
'height': 663,
|
||||
'objects': {'id': [114, 115, 116, 117],
|
||||
'area': [3796, 1596, 152768, 81002],
|
||||
'bbox': [[302.0, 109.0, 73.0, 52.0],
|
||||
[810.0, 100.0, 57.0, 28.0],
|
||||
[160.0, 31.0, 248.0, 616.0],
|
||||
[741.0, 68.0, 202.0, 401.0]],
|
||||
'category': [4, 4, 0, 0]}}
|
||||
```
|
||||
|
||||
데이터 세트에 있는 예시는 다음의 영역을 가지고 있습니다:
|
||||
|
||||
- `image_id`: 예시 이미지 id
|
||||
- `image`: 이미지를 포함하는 `PIL.Image.Image` 객체
|
||||
- `width`: 이미지의 너비
|
||||
- `height`: 이미지의 높이
|
||||
- `objects`: 이미지 안의 객체들의 바운딩 박스 메타데이터를 포함하는 딕셔너리:
|
||||
- `id`: 어노테이션 id
|
||||
- `area`: 바운딩 박스의 면적
|
||||
- `bbox`: 객체의 바운딩 박스 ([COCO 포맷](https://albumentations.ai/docs/getting_started/bounding_boxes_augmentation/#coco)으로)
|
||||
- `category`: 객체의 카테고리, 가능한 값으로는 `Coverall (0)`, `Face_Shield (1)`, `Gloves (2)`, `Goggles (3)` 및 `Mask (4)` 가 포함됩니다.
|
||||
|
||||
`bbox` 필드가 DETR 모델이 요구하는 COCO 형식을 따른다는 것을 알 수 있습니다.
|
||||
그러나 `objects` 내부의 필드 그룹은 DETR이 요구하는 어노테이션 형식과 다릅니다. 따라서 이 데이터를 학습에 사용하기 전에 전처리를 적용해야 합니다.
|
||||
|
||||
데이터를 더 잘 이해하기 위해서 데이터 세트에서 한 가지 예시를 시각화하세요.
|
||||
|
||||
```py
|
||||
>>> import numpy as np
|
||||
>>> import os
|
||||
>>> from PIL import Image, ImageDraw
|
||||
|
||||
>>> image = cppe5["train"][0]["image"]
|
||||
>>> annotations = cppe5["train"][0]["objects"]
|
||||
>>> draw = ImageDraw.Draw(image)
|
||||
|
||||
>>> categories = cppe5["train"].features["objects"].feature["category"].names
|
||||
|
||||
>>> id2label = {index: x for index, x in enumerate(categories, start=0)}
|
||||
>>> label2id = {v: k for k, v in id2label.items()}
|
||||
|
||||
>>> for i in range(len(annotations["id"])):
|
||||
... box = annotations["bbox"][i - 1]
|
||||
... class_idx = annotations["category"][i - 1]
|
||||
... x, y, w, h = tuple(box)
|
||||
... draw.rectangle((x, y, x + w, y + h), outline="red", width=1)
|
||||
... draw.text((x, y), id2label[class_idx], fill="white")
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://i.imgur.com/TdaqPJO.png" alt="CPPE-5 Image Example"/>
|
||||
</div>
|
||||
|
||||
바운딩 박스와 연결된 레이블을 시각화하려면 데이터 세트의 메타 데이터, 특히 `category` 필드에서 레이블을 가져와야 합니다.
|
||||
또한 레이블 ID를 레이블 클래스에 매핑하는 `id2label`과 반대로 매핑하는 `label2id` 딕셔너리를 만들어야 합니다.
|
||||
모델을 설정할 때 이러한 매핑을 사용할 수 있습니다. 이러한 매핑은 허깅페이스 허브에서 모델을 공유했을 때 다른 사람들이 재사용할 수 있습니다.
|
||||
|
||||
데이터를 더 잘 이해하기 위한 최종 단계로, 잠재적인 문제를 찾아보세요.
|
||||
객체 감지를 위한 데이터 세트에서 자주 발생하는 문제 중 하나는 바운딩 박스가 이미지의 가장자리를 넘어가는 것입니다.
|
||||
이러한 바운딩 박스를 "넘어가는 것(run away)"은 훈련 중에 오류를 발생시킬 수 있기에 이 단계에서 처리해야 합니다.
|
||||
이 데이터 세트에도 같은 문제가 있는 몇 가지 예가 있습니다. 이 가이드에서는 간단하게하기 위해 데이터에서 이러한 이미지를 제거합니다.
|
||||
|
||||
```py
|
||||
>>> remove_idx = [590, 821, 822, 875, 876, 878, 879]
|
||||
>>> keep = [i for i in range(len(cppe5["train"])) if i not in remove_idx]
|
||||
>>> cppe5["train"] = cppe5["train"].select(keep)
|
||||
```
|
||||
|
||||
## 데이터 전처리하기 [[preprocess-the-data]]
|
||||
|
||||
모델을 미세 조정 하려면, 미리 학습된 모델에서 사용한 전처리 방식과 정확하게 일치하도록 사용할 데이터를 전처리해야 합니다.
|
||||
[`AutoImageProcessor`]는 이미지 데이터를 처리하여 DETR 모델이 학습에 사용할 수 있는 `pixel_values`, `pixel_mask`, 그리고 `labels`를 생성하는 작업을 담당합니다.
|
||||
이 이미지 프로세서에는 걱정하지 않아도 되는 몇 가지 속성이 있습니다:
|
||||
|
||||
- `image_mean = [0.485, 0.456, 0.406 ]`
|
||||
- `image_std = [0.229, 0.224, 0.225]`
|
||||
|
||||
|
||||
이 값들은 모델 사전 훈련 중 이미지를 정규화하는 데 사용되는 평균과 표준 편차입니다.
|
||||
이 값들은 추론 또는 사전 훈련된 이미지 모델을 세밀하게 조정할 때 복제해야 하는 중요한 값입니다.
|
||||
|
||||
사전 훈련된 모델과 동일한 체크포인트에서 이미지 프로세서를 인스턴스화합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
|
||||
>>> checkpoint = "facebook/detr-resnet-50"
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
`image_processor`에 이미지를 전달하기 전에, 데이터 세트에 두 가지 전처리를 적용해야 합니다:
|
||||
|
||||
- 이미지 증강
|
||||
- DETR 모델의 요구에 맞게 어노테이션을 다시 포맷팅
|
||||
|
||||
첫째로, 모델이 학습 데이터에 과적합 되지 않도록 데이터 증강 라이브러리 중 아무거나 사용하여 변환을 적용할 수 있습니다. 여기에서는 [Albumentations](https://albumentations.ai/docs/) 라이브러리를 사용합니다...
|
||||
이 라이브러리는 변환을 이미지에 적용하고 바운딩 박스를 적절하게 업데이트하도록 보장합니다.
|
||||
🤗 Datasets 라이브러리 문서에는 [객체 탐지를 위해 이미지를 보강하는 방법에 대한 자세한 가이드](https://huggingface.co/docs/datasets/object_detection)가 있으며,
|
||||
이 예제와 정확히 동일한 데이터 세트를 사용합니다. 여기서는 각 이미지를 (480, 480) 크기로 조정하고, 좌우로 뒤집고, 밝기를 높이는 동일한 접근법을 적용합니다:
|
||||
|
||||
|
||||
```py
|
||||
>>> import albumentations
|
||||
>>> import numpy as np
|
||||
>>> import torch
|
||||
|
||||
>>> transform = albumentations.Compose(
|
||||
... [
|
||||
... albumentations.Resize(480, 480),
|
||||
... albumentations.HorizontalFlip(p=1.0),
|
||||
... albumentations.RandomBrightnessContrast(p=1.0),
|
||||
... ],
|
||||
... bbox_params=albumentations.BboxParams(format="coco", label_fields=["category"]),
|
||||
... )
|
||||
```
|
||||
|
||||
이미지 프로세서는 어노테이션이 다음과 같은 형식일 것으로 예상합니다: `{'image_id': int, 'annotations': list[Dict]}`, 여기서 각 딕셔너리는 COCO 객체 어노테이션입니다. 단일 예제에 대해 어노테이션의 형식을 다시 지정하는 함수를 추가해 보겠습니다:
|
||||
|
||||
```py
|
||||
>>> def formatted_anns(image_id, category, area, bbox):
|
||||
... annotations = []
|
||||
... for i in range(0, len(category)):
|
||||
... new_ann = {
|
||||
... "image_id": image_id,
|
||||
... "category_id": category[i],
|
||||
... "isCrowd": 0,
|
||||
... "area": area[i],
|
||||
... "bbox": list(bbox[i]),
|
||||
... }
|
||||
... annotations.append(new_ann)
|
||||
|
||||
... return annotations
|
||||
```
|
||||
|
||||
이제 이미지와 어노테이션 전처리 변환을 결합하여 예제 배치에 사용할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> # transforming a batch
|
||||
>>> def transform_aug_ann(examples):
|
||||
... image_ids = examples["image_id"]
|
||||
... images, bboxes, area, categories = [], [], [], []
|
||||
... for image, objects in zip(examples["image"], examples["objects"]):
|
||||
... image = np.array(image.convert("RGB"))[:, :, ::-1]
|
||||
... out = transform(image=image, bboxes=objects["bbox"], category=objects["category"])
|
||||
|
||||
... area.append(objects["area"])
|
||||
... images.append(out["image"])
|
||||
... bboxes.append(out["bboxes"])
|
||||
... categories.append(out["category"])
|
||||
|
||||
... targets = [
|
||||
... {"image_id": id_, "annotations": formatted_anns(id_, cat_, ar_, box_)}
|
||||
... for id_, cat_, ar_, box_ in zip(image_ids, categories, area, bboxes)
|
||||
... ]
|
||||
|
||||
... return image_processor(images=images, annotations=targets, return_tensors="pt")
|
||||
```
|
||||
|
||||
이전 단계에서 만든 전처리 함수를 🤗 Datasets의 [`~datasets.Dataset.with_transform`] 메소드를 사용하여 데이터 세트 전체에 적용합니다.
|
||||
이 메소드는 데이터 세트의 요소를 가져올 때마다 전처리 함수를 적용합니다.
|
||||
|
||||
이 시점에서는 전처리 후 데이터 세트에서 예시 하나를 가져와서 변환 후 모양이 어떻게 되는지 확인해 볼 수 있습니다.
|
||||
이때, `pixel_values` 텐서, `pixel_mask` 텐서, 그리고 `labels`로 구성된 텐서가 있어야 합니다.
|
||||
|
||||
```py
|
||||
>>> cppe5["train"] = cppe5["train"].with_transform(transform_aug_ann)
|
||||
>>> cppe5["train"][15]
|
||||
{'pixel_values': tensor([[[ 0.9132, 0.9132, 0.9132, ..., -1.9809, -1.9809, -1.9809],
|
||||
[ 0.9132, 0.9132, 0.9132, ..., -1.9809, -1.9809, -1.9809],
|
||||
[ 0.9132, 0.9132, 0.9132, ..., -1.9638, -1.9638, -1.9638],
|
||||
...,
|
||||
[-1.5699, -1.5699, -1.5699, ..., -1.9980, -1.9980, -1.9980],
|
||||
[-1.5528, -1.5528, -1.5528, ..., -1.9980, -1.9809, -1.9809],
|
||||
[-1.5528, -1.5528, -1.5528, ..., -1.9980, -1.9809, -1.9809]],
|
||||
|
||||
[[ 1.3081, 1.3081, 1.3081, ..., -1.8431, -1.8431, -1.8431],
|
||||
[ 1.3081, 1.3081, 1.3081, ..., -1.8431, -1.8431, -1.8431],
|
||||
[ 1.3081, 1.3081, 1.3081, ..., -1.8256, -1.8256, -1.8256],
|
||||
...,
|
||||
[-1.3179, -1.3179, -1.3179, ..., -1.8606, -1.8606, -1.8606],
|
||||
[-1.3004, -1.3004, -1.3004, ..., -1.8606, -1.8431, -1.8431],
|
||||
[-1.3004, -1.3004, -1.3004, ..., -1.8606, -1.8431, -1.8431]],
|
||||
|
||||
[[ 1.4200, 1.4200, 1.4200, ..., -1.6476, -1.6476, -1.6476],
|
||||
[ 1.4200, 1.4200, 1.4200, ..., -1.6476, -1.6476, -1.6476],
|
||||
[ 1.4200, 1.4200, 1.4200, ..., -1.6302, -1.6302, -1.6302],
|
||||
...,
|
||||
[-1.0201, -1.0201, -1.0201, ..., -1.5604, -1.5604, -1.5604],
|
||||
[-1.0027, -1.0027, -1.0027, ..., -1.5604, -1.5430, -1.5430],
|
||||
[-1.0027, -1.0027, -1.0027, ..., -1.5604, -1.5430, -1.5430]]]),
|
||||
'pixel_mask': tensor([[1, 1, 1, ..., 1, 1, 1],
|
||||
[1, 1, 1, ..., 1, 1, 1],
|
||||
[1, 1, 1, ..., 1, 1, 1],
|
||||
...,
|
||||
[1, 1, 1, ..., 1, 1, 1],
|
||||
[1, 1, 1, ..., 1, 1, 1],
|
||||
[1, 1, 1, ..., 1, 1, 1]]),
|
||||
'labels': {'size': tensor([800, 800]), 'image_id': tensor([756]), 'class_labels': tensor([4]), 'boxes': tensor([[0.7340, 0.6986, 0.3414, 0.5944]]), 'area': tensor([519544.4375]), 'iscrowd': tensor([0]), 'orig_size': tensor([480, 480])}}
|
||||
```
|
||||
|
||||
각각의 이미지를 성공적으로 증강하고 이미지의 어노테이션을 준비했습니다.
|
||||
그러나 전처리는 아직 끝나지 않았습니다. 마지막 단계로, 이미지를 배치로 만들 사용자 정의 `collate_fn`을 생성합니다.
|
||||
해당 배치에서 가장 큰 이미지에 이미지(현재 `pixel_values` 인)를 패드하고, 실제 픽셀(1)과 패딩(0)을 나타내기 위해 그에 해당하는 새로운 `pixel_mask`를 생성해야 합니다.
|
||||
|
||||
```py
|
||||
>>> def collate_fn(batch):
|
||||
... pixel_values = [item["pixel_values"] for item in batch]
|
||||
... encoding = image_processor.pad(pixel_values, return_tensors="pt")
|
||||
... labels = [item["labels"] for item in batch]
|
||||
... batch = {}
|
||||
... batch["pixel_values"] = encoding["pixel_values"]
|
||||
... batch["pixel_mask"] = encoding["pixel_mask"]
|
||||
... batch["labels"] = labels
|
||||
... return batch
|
||||
```
|
||||
|
||||
## DETR 모델 학습시키기 [[training-the-DETR-model]]
|
||||
|
||||
이전 섹션에서 대부분의 작업을 수행하여 이제 모델을 학습할 준비가 되었습니다!
|
||||
이 데이터 세트의 이미지는 리사이즈 후에도 여전히 용량이 크기 때문에, 이 모델을 미세 조정 하려면 적어도 하나의 GPU가 필요합니다.
|
||||
|
||||
학습은 다음의 단계를 수행합니다:
|
||||
|
||||
1. [`AutoModelForObjectDetection`]을 사용하여 전처리와 동일한 체크포인트를 사용하여 모델을 가져옵니다.
|
||||
2. [`TrainingArguments`]에서 학습 하이퍼파라미터를 정의합니다.
|
||||
3. 모델, 데이터 세트, 이미지 프로세서 및 데이터 콜레이터와 함께 [`Trainer`]에 훈련 인수를 전달합니다.
|
||||
4. [`~Trainer.train`]를 호출하여 모델을 미세 조정 합니다.
|
||||
|
||||
전처리에 사용한 체크포인트와 동일한 체크포인트에서 모델을 가져올 때, 데이터 세트의 메타데이터에서 만든 `label2id`와 `id2label` 매핑을 전달해야 합니다.
|
||||
또한, `ignore_mismatched_sizes=True`를 지정하여 기존 분류 헤드(모델에서 분류에 사용되는 마지막 레이어)를 새 분류 헤드로 대체합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForObjectDetection
|
||||
|
||||
>>> model = AutoModelForObjectDetection.from_pretrained(
|
||||
... checkpoint,
|
||||
... id2label=id2label,
|
||||
... label2id=label2id,
|
||||
... ignore_mismatched_sizes=True,
|
||||
... )
|
||||
```
|
||||
|
||||
[`TrainingArguments`]에서 `output_dir`을 사용하여 모델을 저장할 위치를 지정한 다음, 필요에 따라 하이퍼파라미터를 구성하세요.
|
||||
사용하지 않는 열을 제거하지 않도록 주의해야 합니다. 만약 `remove_unused_columns`가 `True`일 경우 이미지 열이 삭제됩니다.
|
||||
이미지 열이 없는 경우 `pixel_values`를 생성할 수 없기 때문에 `remove_unused_columns`를 `False`로 설정해야 합니다.
|
||||
모델을 Hub에 업로드하여 공유하려면 `push_to_hub`를 `True`로 설정하십시오(허깅페이스에 로그인하여 모델을 업로드해야 합니다).
|
||||
|
||||
|
||||
```py
|
||||
>>> from transformers import TrainingArguments
|
||||
|
||||
>>> training_args = TrainingArguments(
|
||||
... output_dir="detr-resnet-50_finetuned_cppe5",
|
||||
... per_device_train_batch_size=8,
|
||||
... num_train_epochs=10,
|
||||
... fp16=True,
|
||||
... save_steps=200,
|
||||
... logging_steps=50,
|
||||
... learning_rate=1e-5,
|
||||
... weight_decay=1e-4,
|
||||
... save_total_limit=2,
|
||||
... remove_unused_columns=False,
|
||||
... push_to_hub=True,
|
||||
... )
|
||||
```
|
||||
|
||||
마지막으로 `model`, `training_args`, `collate_fn`, `image_processor`와 데이터 세트(`cppe5`)를 모두 가져온 후, [`~transformers.Trainer.train`]를 호출합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import Trainer
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... data_collator=collate_fn,
|
||||
... train_dataset=cppe5["train"],
|
||||
... processing_class=image_processor,
|
||||
... )
|
||||
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
`training_args`에서 `push_to_hub`를 `True`로 설정한 경우, 학습 체크포인트는 허깅페이스 허브에 업로드됩니다.
|
||||
학습 완료 후, [`~transformers.Trainer.push_to_hub`] 메소드를 호출하여 최종 모델을 허깅페이스 허브에 업로드합니다.
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## 평가하기 [[evaluate]]
|
||||
|
||||
객체 탐지 모델은 일반적으로 일련의 <a href="https://cocodataset.org/#detection-eval">COCO-스타일 지표</a>로 평가됩니다.
|
||||
기존에 구현된 평가 지표 중 하나를 사용할 수도 있지만, 여기에서는 허깅페이스 허브에 푸시한 최종 모델을 평가하는 데 `torchvision`에서 제공하는 평가 지표를 사용합니다.
|
||||
|
||||
`torchvision` 평가자(evaluator)를 사용하려면 실측값인 COCO 데이터 세트를 준비해야 합니다.
|
||||
COCO 데이터 세트를 빌드하는 API는 데이터를 특정 형식으로 저장해야 하므로, 먼저 이미지와 어노테이션을 디스크에 저장해야 합니다.
|
||||
학습을 위해 데이터를 준비할 때와 마찬가지로, cppe5["test"]에서의 어노테이션은 포맷을 맞춰야 합니다. 그러나 이미지는 그대로 유지해야 합니다.
|
||||
|
||||
평가 단계는 약간의 작업이 필요하지만, 크게 세 가지 주요 단계로 나눌 수 있습니다.
|
||||
먼저, `cppe5["test"]` 세트를 준비합니다: 어노테이션을 포맷에 맞게 만들고 데이터를 디스크에 저장합니다.
|
||||
|
||||
```py
|
||||
>>> import json
|
||||
|
||||
|
||||
>>> # format annotations the same as for training, no need for data augmentation
|
||||
>>> def val_formatted_anns(image_id, objects):
|
||||
... annotations = []
|
||||
... for i in range(0, len(objects["id"])):
|
||||
... new_ann = {
|
||||
... "id": objects["id"][i],
|
||||
... "category_id": objects["category"][i],
|
||||
... "iscrowd": 0,
|
||||
... "image_id": image_id,
|
||||
... "area": objects["area"][i],
|
||||
... "bbox": objects["bbox"][i],
|
||||
... }
|
||||
... annotations.append(new_ann)
|
||||
|
||||
... return annotations
|
||||
|
||||
|
||||
>>> # Save images and annotations into the files torchvision.datasets.CocoDetection expects
|
||||
>>> def save_cppe5_annotation_file_images(cppe5):
|
||||
... output_json = {}
|
||||
... path_output_cppe5 = f"{os.getcwd()}/cppe5/"
|
||||
|
||||
... if not os.path.exists(path_output_cppe5):
|
||||
... os.makedirs(path_output_cppe5)
|
||||
|
||||
... path_anno = os.path.join(path_output_cppe5, "cppe5_ann.json")
|
||||
... categories_json = [{"supercategory": "none", "id": id, "name": id2label[id]} for id in id2label]
|
||||
... output_json["images"] = []
|
||||
... output_json["annotations"] = []
|
||||
... for example in cppe5:
|
||||
... ann = val_formatted_anns(example["image_id"], example["objects"])
|
||||
... output_json["images"].append(
|
||||
... {
|
||||
... "id": example["image_id"],
|
||||
... "width": example["image"].width,
|
||||
... "height": example["image"].height,
|
||||
... "file_name": f"{example['image_id']}.png",
|
||||
... }
|
||||
... )
|
||||
... output_json["annotations"].extend(ann)
|
||||
... output_json["categories"] = categories_json
|
||||
|
||||
... with open(path_anno, "w") as file:
|
||||
... json.dump(output_json, file, ensure_ascii=False, indent=4)
|
||||
|
||||
... for im, img_id in zip(cppe5["image"], cppe5["image_id"]):
|
||||
... path_img = os.path.join(path_output_cppe5, f"{img_id}.png")
|
||||
... im.save(path_img)
|
||||
|
||||
... return path_output_cppe5, path_anno
|
||||
```
|
||||
|
||||
다음으로, `cocoevaluator`와 함께 사용할 수 있는 `CocoDetection` 클래스의 인스턴스를 준비합니다.
|
||||
|
||||
```py
|
||||
>>> import torchvision
|
||||
|
||||
|
||||
>>> class CocoDetection(torchvision.datasets.CocoDetection):
|
||||
... def __init__(self, img_folder, image_processor, ann_file):
|
||||
... super().__init__(img_folder, ann_file)
|
||||
... self.image_processor = image_processor
|
||||
|
||||
... def __getitem__(self, idx):
|
||||
... # read in PIL image and target in COCO format
|
||||
... img, target = super(CocoDetection, self).__getitem__(idx)
|
||||
|
||||
... # preprocess image and target: converting target to DETR format,
|
||||
... # resizing + normalization of both image and target)
|
||||
... image_id = self.ids[idx]
|
||||
... target = {"image_id": image_id, "annotations": target}
|
||||
... encoding = self.image_processor(images=img, annotations=target, return_tensors="pt")
|
||||
... pixel_values = encoding["pixel_values"].squeeze() # remove batch dimension
|
||||
... target = encoding["labels"][0] # remove batch dimension
|
||||
|
||||
... return {"pixel_values": pixel_values, "labels": target}
|
||||
|
||||
|
||||
>>> im_processor = AutoImageProcessor.from_pretrained("devonho/detr-resnet-50_finetuned_cppe5")
|
||||
|
||||
>>> path_output_cppe5, path_anno = save_cppe5_annotation_file_images(cppe5["test"])
|
||||
>>> test_ds_coco_format = CocoDetection(path_output_cppe5, im_processor, path_anno)
|
||||
```
|
||||
|
||||
마지막으로, 평가 지표를 가져와서 평가를 실행합니다.
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
>>> from tqdm import tqdm
|
||||
|
||||
>>> model = AutoModelForObjectDetection.from_pretrained("devonho/detr-resnet-50_finetuned_cppe5")
|
||||
>>> module = evaluate.load("ybelkada/cocoevaluate", coco=test_ds_coco_format.coco)
|
||||
>>> val_dataloader = torch.utils.data.DataLoader(
|
||||
... test_ds_coco_format, batch_size=8, shuffle=False, num_workers=4, collate_fn=collate_fn
|
||||
... )
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... for idx, batch in enumerate(tqdm(val_dataloader)):
|
||||
... pixel_values = batch["pixel_values"]
|
||||
... pixel_mask = batch["pixel_mask"]
|
||||
|
||||
... labels = [
|
||||
... {k: v for k, v in t.items()} for t in batch["labels"]
|
||||
... ] # these are in DETR format, resized + normalized
|
||||
|
||||
... # forward pass
|
||||
... outputs = model(pixel_values=pixel_values, pixel_mask=pixel_mask)
|
||||
|
||||
... orig_target_sizes = torch.stack([target["orig_size"] for target in labels], dim=0)
|
||||
... results = im_processor.post_process(outputs, orig_target_sizes) # convert outputs of model to Pascal VOC format (xmin, ymin, xmax, ymax)
|
||||
|
||||
... module.add(prediction=results, reference=labels)
|
||||
... del batch
|
||||
|
||||
>>> results = module.compute()
|
||||
>>> print(results)
|
||||
Accumulating evaluation results...
|
||||
DONE (t=0.08s).
|
||||
IoU metric: bbox
|
||||
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.352
|
||||
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.681
|
||||
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.292
|
||||
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.168
|
||||
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.208
|
||||
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.429
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.274
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.484
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.501
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.191
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.323
|
||||
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.590
|
||||
```
|
||||
|
||||
이러한 결과는 [`~transformers.TrainingArguments`]의 하이퍼파라미터를 조정하여 더욱 개선될 수 있습니다. 한번 시도해 보세요!
|
||||
|
||||
## 추론하기 [[inference]]
|
||||
|
||||
DETR 모델을 미세 조정 및 평가하고, 허깅페이스 허브에 업로드 했으므로 추론에 사용할 수 있습니다.
|
||||
|
||||
미세 조정된 모델을 추론에 사용하는 가장 간단한 방법은 [`pipeline`]에서 모델을 사용하는 것입니다.
|
||||
모델과 함께 객체 탐지를 위한 파이프라인을 인스턴스화하고, 이미지를 전달하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://i.imgur.com/2lnWoly.jpg"
|
||||
>>> image = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
>>> obj_detector = pipeline("object-detection", model="devonho/detr-resnet-50_finetuned_cppe5")
|
||||
>>> obj_detector(image)
|
||||
```
|
||||
|
||||
만약 원한다면 수동으로 `pipeline`의 결과를 재현할 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained("devonho/detr-resnet-50_finetuned_cppe5")
|
||||
>>> model = AutoModelForObjectDetection.from_pretrained("devonho/detr-resnet-50_finetuned_cppe5")
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... inputs = image_processor(images=image, return_tensors="pt")
|
||||
... outputs = model(**inputs)
|
||||
... target_sizes = torch.tensor([image.size[::-1]])
|
||||
... results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[0]
|
||||
|
||||
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
||||
... box = [round(i, 2) for i in box.tolist()]
|
||||
... print(
|
||||
... f"Detected {model.config.id2label[label.item()]} with confidence "
|
||||
... f"{round(score.item(), 3)} at location {box}"
|
||||
... )
|
||||
Detected Coverall with confidence 0.566 at location [1215.32, 147.38, 4401.81, 3227.08]
|
||||
Detected Mask with confidence 0.584 at location [2449.06, 823.19, 3256.43, 1413.9]
|
||||
```
|
||||
|
||||
결과를 시각화하겠습니다:
|
||||
```py
|
||||
>>> draw = ImageDraw.Draw(image)
|
||||
|
||||
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
||||
... box = [round(i, 2) for i in box.tolist()]
|
||||
... x, y, x2, y2 = tuple(box)
|
||||
... draw.rectangle((x, y, x2, y2), outline="red", width=1)
|
||||
... draw.text((x, y), model.config.id2label[label.item()], fill="white")
|
||||
|
||||
>>> image
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://i.imgur.com/4QZnf9A.png" alt="Object detection result on a new image"/>
|
||||
</div>
|
||||
384
transformers/docs/source/ko/tasks/prompting.md
Normal file
384
transformers/docs/source/ko/tasks/prompting.md
Normal file
@@ -0,0 +1,384 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
|
||||
# 대규모 언어 모델(LLM) 프롬프팅 가이드 [[llm-prompting-guide]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Falcon, LLaMA 등의 대규모 언어 모델은 사전 훈련된 트랜스포머 모델로, 초기에는 주어진 입력 텍스트에 대해 다음 토큰을 예측하도록 훈련됩니다. 이들은 보통 수십억 개의 매개변수를 가지고 있으며, 장기간에 걸쳐 수조 개의 토큰으로 훈련됩니다. 그 결과, 이 모델들은 매우 강력하고 다재다능해져서, 자연어 프롬프트로 모델에 지시하여 다양한 자연어 처리 작업을 즉시 수행할 수 있습니다.
|
||||
|
||||
최적의 출력을 보장하기 위해 이러한 프롬프트를 설계하는 것을 흔히 "프롬프트 엔지니어링"이라고 합니다. 프롬프트 엔지니어링은 상당한 실험이 필요한 반복적인 과정입니다. 자연어는 프로그래밍 언어보다 훨씬 유연하고 표현력이 풍부하지만, 동시에 모호성을 초래할 수 있습니다. 또한, 자연어 프롬프트는 변화에 매우 민감합니다. 프롬프트의 사소한 수정만으로도 완전히 다른 출력이 나올 수 있습니다.
|
||||
|
||||
모든 경우에 적용할 수 있는 정확한 프롬프트 생성 공식은 없지만, 연구자들은 더 일관되게 최적의 결과를 얻는 데 도움이 되는 여러 가지 모범 사례를 개발했습니다.
|
||||
|
||||
이 가이드에서는 더 나은 대규모 언어 모델 프롬프트를 작성하고 다양한 자연어 처리 작업을 해결하는 데 도움이 되는 프롬프트 엔지니어링 모범 사례를 다룹니다:
|
||||
|
||||
- [프롬프팅의 기초](#basics-of-prompting)
|
||||
- [대규모 언어 모델 프롬프팅의 모범 사례](#best-practices-of-llm-prompting)
|
||||
- [고급 프롬프팅 기법: 퓨샷(Few-shot) 프롬프팅과 생각의 사슬(Chain-of-thought, CoT) 기법](#advanced-prompting-techniques)
|
||||
- [프롬프팅 대신 미세 조정을 해야 하는 경우](#prompting-vs-fine-tuning)
|
||||
|
||||
<Tip>
|
||||
|
||||
프롬프트 엔지니어링은 대규모 언어 모델 출력 최적화 과정의 일부일 뿐입니다. 또 다른 중요한 구성 요소는 최적의 텍스트 생성 전략을 선택하는 것입니다. 학습 가능한 매개변수를 수정하지 않고도 대규모 언어 모델이 텍스트를 생성하리 때 각각의 후속 토큰을 선택하는 방식을 사용자가 직접 정의할 수 있습니다. 텍스트 생성 매개변수를 조정함으로써 생성된 텍스트의 반복을 줄이고 더 일관되고 사람이 말하는 것 같은 텍스트를 만들 수 있습니다. 텍스트 생성 전략과 매개변수는 이 가이드의 범위를 벗어나지만, 다음 가이드에서 이러한 주제에 대해 자세히 알아볼 수 있습니다:
|
||||
|
||||
* [대규모 언어 모델을 이용한 생성](../llm_tutorial)
|
||||
* [텍스트 생성 전략](../generation_strategies)
|
||||
|
||||
</Tip>
|
||||
|
||||
## 프롬프팅의 기초 [[basics-of-prompting]]
|
||||
|
||||
### 모델의 유형 [[types-of-models]]
|
||||
|
||||
현대의 대부분의 대규모 언어 모델은 디코더만을 이용한 트랜스포머입니다. 예를 들어 [LLaMA](../model_doc/llama),
|
||||
[Llama2](../model_doc/llama2), [Falcon](../model_doc/falcon), [GPT2](../model_doc/gpt2) 등이 있습니다. 그러나 [Flan-T5](../model_doc/flan-t5)와 [BART](../model_doc/bart)와 같은 인코더-디코더 기반의 트랜스포머 대규모 언어 모델을 접할 수도 있습니다.
|
||||
|
||||
인코더-디코더 기반의 모델은 일반적으로 출력이 입력에 **크게** 의존하는 생성 작업에 사용됩니다. 예를 들어, 번역과 요약 작업에 사용됩니다. 디코더 전용 모델은 다른 모든 유형의 생성 작업에 사용됩니다.
|
||||
|
||||
파이프라인을 사용하여 대규모 언어 모델으로 텍스트를 생성할 때, 어떤 유형의 대규모 언어 모델을 사용하고 있는지 아는 것이 중요합니다. 왜냐하면 이들은 서로 다른 파이프라인을 사용하기 때문입니다.
|
||||
|
||||
디코더 전용 모델로 추론을 실행하려면 `text-generation` 파이프라인을 사용하세요:
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
>>> import torch
|
||||
|
||||
>>> torch.manual_seed(0) # doctest: +IGNORE_RESULT
|
||||
|
||||
>>> generator = pipeline('text-generation', model = 'openai-community/gpt2')
|
||||
>>> prompt = "Hello, I'm a language model"
|
||||
|
||||
>>> generator(prompt, max_length = 30)
|
||||
[{'generated_text': "Hello, I'm a language model programmer so you can use some of my stuff. But you also need some sort of a C program to run."}]
|
||||
```
|
||||
|
||||
인코더-디코더로 추론을 실행하려면 `text2text-generation` 파이프라인을 사용하세요:
|
||||
|
||||
```python
|
||||
>>> text2text_generator = pipeline("text2text-generation", model = 'google/flan-t5-base')
|
||||
>>> prompt = "Translate from English to French: I'm very happy to see you"
|
||||
|
||||
>>> text2text_generator(prompt)
|
||||
[{'generated_text': 'Je suis très heureuse de vous rencontrer.'}]
|
||||
```
|
||||
|
||||
### 기본 모델 vs 지시/채팅 모델 [[base-vs-instructchat-models]]
|
||||
|
||||
🤗 Hub에서 최근 사용 가능한 대부분의 대규모 언어 모델 체크포인트는 기본 버전과 지시(또는 채팅) 두 가지 버전이 제공됩니다. 예를 들어, [`tiiuae/falcon-7b`](https://huggingface.co/tiiuae/falcon-7b)와 [`tiiuae/falcon-7b-instruct`](https://huggingface.co/tiiuae/falcon-7b-instruct)가 있습니다.
|
||||
|
||||
기본 모델은 초기 프롬프트가 주어졌을 때 텍스트를 완성하는 데 탁월하지만, 지시를 따라야 하거나 대화형 사용이 필요한 자연어 처리작업에는 이상적이지 않습니다. 이때 지시(채팅) 버전이 필요합니다. 이러한 체크포인트는 사전 훈련된 기본 버전을 지시사항과 대화 데이터로 추가 미세 조정한 결과입니다. 이 추가적인 미세 조정으로 인해 많은 자연어 처리 작업에 더 적합한 선택이 됩니다.
|
||||
|
||||
[`tiiuae/falcon-7b-instruct`](https://huggingface.co/tiiuae/falcon-7b-instruct)를 사용하여 일반적인 자연어 처리 작업을 해결하는 데 사용할 수 있는 몇 가지 간단한 프롬프트를 살펴보겠습니다.
|
||||
|
||||
### 자연어 처리 작업 [[nlp-tasks]]
|
||||
|
||||
먼저, 환경을 설정해 보겠습니다:
|
||||
|
||||
```bash
|
||||
pip install -q transformers accelerate
|
||||
```
|
||||
|
||||
다음으로, 적절한 파이프라인("text-generation")을 사용하여 모델을 로드하겠습니다:
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline, AutoTokenizer
|
||||
>>> import torch
|
||||
|
||||
>>> torch.manual_seed(0) # doctest: +IGNORE_RESULT
|
||||
>>> model = "tiiuae/falcon-7b-instruct"
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained(model)
|
||||
>>> pipe = pipeline(
|
||||
... "text-generation",
|
||||
... model=model,
|
||||
... tokenizer=tokenizer,
|
||||
... dtype=torch.bfloat16,
|
||||
... device_map="auto",
|
||||
... )
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
Falcon 모델은 bfloat16 데이터 타입을 사용하여 훈련되었으므로, 같은 타입을 사용하는 것을 권장합니다. 이를 위해서는 최신 버전의 CUDA가 필요하며, 최신 그래픽 카드에서 가장 잘 작동합니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 파이프라인을 통해 모델을 로드했으니, 프롬프트를 사용하여 자연어 처리 작업을 해결하는 방법을 살펴보겠습니다.
|
||||
|
||||
#### 텍스트 분류 [[text-classification]]
|
||||
|
||||
텍스트 분류의 가장 일반적인 형태 중 하나는 감정 분석입니다. 이는 텍스트 시퀀스에 "긍정적", "부정적" 또는 "중립적"과 같은 레이블을 할당합니다. 주어진 텍스트(영화 리뷰)를 분류하도록 모델에 지시하는 프롬프트를 작성해 보겠습니다. 먼저 지시사항을 제공한 다음, 분류할 텍스트를 지정하겠습니다. 여기서 주목할 점은 단순히 거기서 끝내지 않고, 응답의 시작 부분인 `"Sentiment: "`을 추가한다는 것입니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(0)
|
||||
>>> 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:
|
||||
... """
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=10,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"Result: {seq['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
|
||||
```
|
||||
|
||||
결과적으로, 우리가 지시사항에서 제공한 목록에서 선택된 분류 레이블이 정확하게 포함되어 생성된 것을 확인할 수 있습니다!
|
||||
<Tip>
|
||||
|
||||
프롬프트 외에도 `max_new_tokens` 매개변수를 전달하는 것을 볼 수 있습니다. 이 매개변수는 모델이 생성할 토큰의 수를 제어하며, [텍스트 생성 전략](../generation_strategies) 가이드에서 배울 수 있는 여러 텍스트 생성 매개변수 중 하나입니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
#### 개체명 인식 [[named-entity-recognition]]
|
||||
|
||||
개체명 인식(Named Entity Recognition, NER)은 텍스트에서 인물, 장소, 조직과 같은 명명된 개체를 찾는 작업입니다. 프롬프트의 지시사항을 수정하여 대규모 언어 모델이 이 작업을 수행하도록 해보겠습니다. 여기서는 `return_full_text = False`로 설정하여 출력에 프롬프트가 포함되지 않도록 하겠습니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(1) # doctest: +IGNORE_RESULT
|
||||
>>> prompt = """Return a list of named entities in the text.
|
||||
... Text: The Golden State Warriors are an American professional basketball team based in San Francisco.
|
||||
... Named entities:
|
||||
... """
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=15,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"{seq['generated_text']}")
|
||||
- Golden State Warriors
|
||||
- San Francisco
|
||||
```
|
||||
|
||||
보시다시피, 모델이 주어진 텍스트에서 두 개의 명명된 개체를 정확하게 식별했습니다.
|
||||
|
||||
#### 번역 [[translation]]
|
||||
|
||||
대규모 언어 모델이 수행할 수 있는 또 다른 작업은 번역입니다. 이 작업을 위해 인코더-디코더 모델을 사용할 수 있지만, 여기서는 예시의 단순성을 위해 꽤 좋은 성능을 보이는 Falcon-7b-instruct를 계속 사용하겠습니다. 다시 한 번, 모델에게 영어에서 이탈리아어로 텍스트를 번역하도록 지시하는 기본적인 프롬프트를 작성하는 방법은 다음과 같습니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(2) # doctest: +IGNORE_RESULT
|
||||
>>> prompt = """Translate the English text to Italian.
|
||||
... Text: Sometimes, I've believed as many as six impossible things before breakfast.
|
||||
... Translation:
|
||||
... """
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=20,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"{seq['generated_text']}")
|
||||
A volte, ho creduto a sei impossibili cose prima di colazione.
|
||||
```
|
||||
|
||||
여기서는 모델이 출력을 생성할 때 조금 더 유연해질 수 있도록 `do_sample=True`와 `top_k=10`을 추가했습니다.
|
||||
|
||||
#### 텍스트 요약 [[text-summarization]]
|
||||
|
||||
번역과 마찬가지로, 텍스트 요약은 출력이 입력에 크게 의존하는 또 다른 생성 작업이며, 인코더-디코더 기반 모델이 더 나은 선택일 수 있습니다. 그러나 디코더 기반의 모델도 이 작업에 사용될 수 있습니다. 이전에는 프롬프트의 맨 처음에 지시사항을 배치했습니다. 하지만 프롬프트의 맨 끝도 지시사항을 넣을 적절한 위치가 될 수 있습니다. 일반적으로 지시사항을 양 극단 중 하나에 배치하는 것이 더 좋습니다.
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(3) # doctest: +IGNORE_RESULT
|
||||
>>> 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:
|
||||
... """
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=30,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"{seq['generated_text']}")
|
||||
Permaculture is an ecological design mimicking natural ecosystems to meet basic needs and prepare for climate change. It is based on traditional knowledge and scientific understanding.
|
||||
```
|
||||
|
||||
#### 질의 응답 [[question-answering]]
|
||||
|
||||
질의 응답 작업을 위해 프롬프트를 다음과 같은 논리적 구성요소로 구조화할 수 있습니다. 지시사항, 맥락, 질문, 그리고 모델이 답변 생성을 시작하도록 유도하는 선도 단어나 구문(`"Answer:"`) 을 사용할 수 있습니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(4) # doctest: +IGNORE_RESULT
|
||||
>>> 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:
|
||||
... """
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=10,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"Result: {seq['generated_text']}")
|
||||
Result: Modern tools often used to make gazpacho include
|
||||
```
|
||||
|
||||
#### 추론 [[reasoning]]
|
||||
|
||||
추론은 대규모 언어 모델(LLM)에게 가장 어려운 작업 중 하나이며, 좋은 결과를 얻기 위해서는 종종 [생각의 사슬(Chain-of-thought, CoT)](#chain-of-thought)과 같은 고급 프롬프팅 기법을 적용해야 합니다. 간단한 산술 작업에 대해 기본적인 프롬프트로 모델이 추론할 수 있는지 시도해 보겠습니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(5) # doctest: +IGNORE_RESULT
|
||||
>>> prompt = """There are 5 groups of students in the class. Each group has 4 students. How many students are there in the class?"""
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=30,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"Result: {seq['generated_text']}")
|
||||
Result:
|
||||
There are a total of 5 groups, so there are 5 x 4=20 students in the class.
|
||||
```
|
||||
|
||||
정확한 답변이 생성되었습니다! 복잡성을 조금 높여보고 기본적인 프롬프트로도 여전히 해결할 수 있는지 확인해 보겠습니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(6)
|
||||
>>> prompt = """I baked 15 muffins. I ate 2 muffins and gave 5 muffins to a neighbor. My partner then bought 6 more muffins and ate 2. How many muffins do we now have?"""
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=10,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... return_full_text = False,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"Result: {seq['generated_text']}")
|
||||
Result:
|
||||
The total number of muffins now is 21
|
||||
```
|
||||
|
||||
정답은 12여야 하는데 21이라는 잘못된 답변이 나왔습니다. 이 경우, 프롬프트가 너무 기본적이거나 모델의 크기가 작아서 생긴 문제일 수 있습니다. 우리는 Falcon의 가장 작은 버전을 선택했습니다. 추론은 큰 모델에게도 어려운 작업이지만, 더 큰 모델들이 더 나은 성능을 보일 가능성이 높습니다.
|
||||
|
||||
## 대규모 언어 모델 프롬프트 작성의 모범 사례 [[best-practices-of-llm-prompting]]
|
||||
|
||||
이 섹션에서는 프롬프트 결과를 향상시킬 수 있는 모범 사례 목록을 작성했습니다:
|
||||
|
||||
* 작업할 모델을 선택할 때 최신 및 가장 강력한 모델이 더 나은 성능을 발휘할 가능성이 높습니다.
|
||||
* 간단하고 짧은 프롬프트로 시작하여 점진적으로 개선해 나가세요.
|
||||
* 프롬프트의 시작 부분이나 맨 끝에 지시사항을 배치하세요. 대규모 컨텍스트를 다룰 때, 모델들은 어텐션 복잡도가 2차적으로 증가하는 것을 방지하기 위해 다양한 최적화를 적용합니다. 이렇게 함으로써 모델이 프롬프트의 중간보다 시작이나 끝 부분에 더 주의를 기울일 수 있습니다.
|
||||
* 지시사항을 적용할 텍스트와 명확하게 분리해보세요. (이에 대해서는 다음 섹션에서 더 자세히 다룹니다.)
|
||||
* 작업과 원하는 결과에 대해 구체적이고 풍부한 설명을 제공하세요. 형식, 길이, 스타일, 언어 등을 명확하게 작성해야 합니다.
|
||||
* 모호한 설명과 지시사항을 피하세요.
|
||||
* "하지 말라"는 지시보다는 "무엇을 해야 하는지"를 말하는 지시를 사용하는 것이 좋습니다.
|
||||
* 첫 번째 단어를 쓰거나 첫 번째 문장을 시작하여 출력을 올바른 방향으로 "유도"하세요.
|
||||
* [퓨샷(Few-shot) 프롬프팅](#few-shot-prompting) 및 [생각의 사슬(Chain-of-thought, CoT)](#chain-of-thought) 같은 고급 기술을 사용해보세요.
|
||||
* 프롬프트의 견고성을 평가하기 위해 다른 모델로도 테스트하세요.
|
||||
* 프롬프트의 버전을 관리하고 성능을 추적하세요.
|
||||
|
||||
## 고급 프롬프트 기법 [[advanced-prompting-techniques]]
|
||||
|
||||
### 퓨샷(Few-shot) 프롬프팅 [[few-shot-prompting]]
|
||||
|
||||
위 섹션의 기본 프롬프트들은 "제로샷(Zero-shot)" 프롬프트의 예시입니다. 이는 모델에 지시사항과 맥락은 주어졌지만, 해결책이 포함된 예시는 제공되지 않았다는 의미입니다. 지시 데이터셋으로 미세 조정된 대규모 언어 모델은 일반적으로 이러한 "제로샷" 작업에서 좋은 성능을 보입니다. 하지만 여러분의 작업이 더 복잡하거나 미묘한 차이가 있을 수 있고, 아마도 지시사항만으로는 모델이 포착하지 못하는 출력에 대한 요구사항이 있을 수 있습니다. 이런 경우에는 퓨샷(Few-shot) 프롬프팅이라는 기법을 시도해 볼 수 있습니다.
|
||||
|
||||
퓨샷 프롬프팅에서는 프롬프트에 예시를 제공하여 모델에 더 많은 맥락을 주고 성능을 향상시킵니다. 이 예시들은 모델이 예시의 패턴을 따라 출력을 생성하도록 조건화합니다.
|
||||
|
||||
다음은 예시입니다:
|
||||
|
||||
```python
|
||||
>>> torch.manual_seed(0) # doctest: +IGNORE_RESULT
|
||||
>>> 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:"""
|
||||
|
||||
>>> sequences = pipe(
|
||||
... prompt,
|
||||
... max_new_tokens=8,
|
||||
... do_sample=True,
|
||||
... top_k=10,
|
||||
... )
|
||||
|
||||
>>> for seq in sequences:
|
||||
... print(f"Result: {seq['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
|
||||
```
|
||||
|
||||
위의 코드 스니펫에서는 모델에 원하는 출력을 보여주기 위해 단일 예시를 사용했으므로, 이를 "원샷(One-shot)" 프롬프팅이라고 부를 수 있습니다. 그러나 작업의 복잡성에 따라 하나 이상의 예시를 사용해야 할 수도 있습니다.
|
||||
|
||||
퓨샷 프롬프팅 기법의 한계:
|
||||
- 대규모 언어 모델이 예시의 패턴을 파악할 수 있지만, 이 기법은 복잡한 추론 작업에는 잘 작동하지 않습니다.
|
||||
- 퓨샷 프롬프팅을 적용하면 프롬프트의 길이가 길어집니다. 토큰 수가 많은 프롬프트는 계산량과 지연 시간을 증가시킬 수 있으며 프롬프트 길이에도 제한이 있습니다.
|
||||
- 때로는 여러 예시가 주어질 때, 모델은 의도하지 않은 패턴을 학습할 수 있습니다. 예를 들어, 세 번째 영화 리뷰가 항상 부정적이라고 학습할 수 있습니다.
|
||||
|
||||
### 생각의 사슬(Chain-of-thought, CoT) [[chain-of-thought]]
|
||||
|
||||
생각의 사슬(Chain-of-thought, CoT) 프롬프팅은 모델이 중간 추론 단계를 생성하도록 유도하는 기법으로, 복잡한 추론 작업의 결과를 개선합니다.
|
||||
|
||||
모델이 추론 단계를 생성하도록 유도하는 두 가지 방법이 있습니다:
|
||||
- 질문에 대한 상세한 답변을 예시로 제시하는 퓨샷 프롬프팅을 통해 모델에게 문제를 어떻게 해결해 나가는지 보여줍니다.
|
||||
- "단계별로 생각해 봅시다" 또는 "깊게 숨을 쉬고 문제를 단계별로 해결해 봅시다"와 같은 문구를 추가하여 모델에게 추론하도록 지시합니다.
|
||||
|
||||
[reasoning section](#reasoning)의 머핀 예시에 생각의 사슬(Chain-of-thought, CoT) 기법을 적용하고 [HuggingChat](https://huggingface.co/chat/)에서 사용할 수 있는 (`tiiuae/falcon-180B-chat`)과 같은 더 큰 모델을 사용하면, 추론 결과가 크게 개선됩니다:
|
||||
|
||||
```text
|
||||
단계별로 살펴봅시다:
|
||||
1. 처음에 15개의 머핀이 있습니다.
|
||||
2. 2개의 머핀을 먹으면 13개의 머핀이 남습니다.
|
||||
3. 이웃에게 5개의 머핀을 주면 8개의 머핀이 남습니다.
|
||||
4. 파트너가 6개의 머핀을 더 사오면 총 머핀 수는 14개가 됩니다.
|
||||
5. 파트너가 2개의 머핀을 먹으면 12개의 머핀이 남습니다.
|
||||
따라서, 현재 12개의 머핀이 있습니다.
|
||||
```
|
||||
|
||||
## 프롬프팅 vs 미세 조정 [[prompting-vs-fine-tuning]]
|
||||
|
||||
프롬프트를 최적화하여 훌륭한 결과를 얻을 수 있지만, 여전히 모델을 미세 조정하는 것이 더 좋을지 고민할 수 있습니다. 다음은 더 작은 모델을 미세 조정하는 것이 선호되는 시나리오입니다:
|
||||
|
||||
- 도메인이 대규모 언어 모델이 사전 훈련된 것과 크게 다르고 광범위한 프롬프트 최적화로도 충분한 결과를 얻지 못한 경우.
|
||||
- 저자원 언어에서 모델이 잘 작동해야 하는 경우.
|
||||
- 엄격한 규제 하에 있는 민감한 데이터로 모델을 훈련해야 하는 경우.
|
||||
- 비용, 개인정보 보호, 인프라 또는 기타 제한으로 인해 작은 모델을 사용해야 하는 경우.
|
||||
|
||||
위의 모든 예시에서, 모델을 미세 조정하기 위해 충분히 큰 도메인별 데이터셋을 이미 가지고 있거나 합리적인 비용으로 쉽게 얻을 수 있는지 확인해야 합니다. 또한 모델을 미세 조정할 충분한 시간과 자원이 필요합니다.
|
||||
|
||||
만약 위의 예시들이 여러분의 경우에 해당하지 않는다면, 프롬프트를 최적화하는 것이 더 유익할 수 있습니다.
|
||||
296
transformers/docs/source/ko/tasks/question_answering.md
Normal file
296
transformers/docs/source/ko/tasks/question_answering.md
Normal file
@@ -0,0 +1,296 @@
|
||||
<!--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)[[question-answering]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="ajPx5LwJD-I"/>
|
||||
|
||||
질의 응답 태스크는 주어진 질문에 대한 답변을 제공합니다. Alexa, Siri 또는 Google과 같은 가상 비서에게 날씨가 어떤지 물어본 적이 있다면 질의 응답 모델을 사용해본 적이 있을 것입니다. 질의 응답 태스크에는 일반적으로 두 가지 유형이 있습니다.
|
||||
|
||||
- 추출적(Extractive) 질의 응답: 주어진 문맥에서 답변을 추출합니다.
|
||||
- 생성적(Abstractive) 질의 응답: 문맥에서 질문에 올바르게 답하는 답변을 생성합니다.
|
||||
|
||||
이 가이드는 다음과 같은 방법들을 보여줍니다.
|
||||
|
||||
1. 추출적 질의 응답을 하기 위해 [SQuAD](https://huggingface.co/datasets/squad) 데이터 세트에서 [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) 미세 조정하기
|
||||
2. 추론에 미세 조정된 모델 사용하기
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/question-answering)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에, 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
여러분의 모델을 업로드하고 커뮤니티에 공유할 수 있도록 Hugging Face 계정에 로그인하는 것이 좋습니다. 메시지가 표시되면 토큰을 입력해서 로그인합니다:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## SQuAD 데이터 세트 가져오기[[load-squad-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 SQuAD 데이터 세트의 일부를 가져옵니다. 이렇게 하면 전체 데이터 세트로 훈련하며 더 많은 시간을 할애하기 전에 모든 것이 잘 작동하는지 실험하고 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> squad = load_dataset("squad", split="train[:5000]")
|
||||
```
|
||||
|
||||
데이터 세트의 분할된 `train`을 [`~datasets.Dataset.train_test_split`] 메소드를 사용해 훈련 데이터 세트와 테스트 데이터 세트로 나누어줍니다:
|
||||
|
||||
```py
|
||||
>>> squad = squad.train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
그리고나서 예시로 데이터를 하나 살펴봅니다:
|
||||
|
||||
```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'
|
||||
}
|
||||
```
|
||||
|
||||
이 중에서 몇 가지 중요한 항목이 있습니다:
|
||||
|
||||
- `answers`: 답안 토큰의 시작 위치와 답안 텍스트
|
||||
- `context`: 모델이 답을 추출하는데 필요한 배경 지식
|
||||
- `question`: 모델이 답해야 하는 질문
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
<Youtube id="qgaM0weJHpA"/>
|
||||
|
||||
다음 단계에서는 `question` 및 `context` 항목을 처리하기 위해 DistilBERT 토크나이저를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
질의 응답 태스크와 관련해서 특히 유의해야할 몇 가지 전처리 단계가 있습니다:
|
||||
|
||||
1. 데이터 세트의 일부 예제에는 모델의 최대 입력 길이를 초과하는 매우 긴 `context`가 있을 수 있습니다. 긴 시퀀스를 다루기 위해서는, `truncation="only_second"`로 설정해 `context`만 잘라내면 됩니다.
|
||||
2. 그 다음, `return_offset_mapping=True`로 설정해 답변의 시작과 종료 위치를 원래의 `context`에 매핑합니다.
|
||||
3. 매핑을 완료하면, 이제 답변에서 시작 토큰과 종료 토큰을 찾을 수 있습니다. 오프셋의 어느 부분이 `question`과 `context`에 해당하는지 찾을 수 있도록 [`~tokenizers.Encoding.sequence_ids`] 메소드를 사용하세요.
|
||||
|
||||
다음은 `answer`의 시작 토큰과 종료 토큰을 잘라내서 `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
|
||||
```
|
||||
|
||||
모든 데이터 세트에 전처리를 적용하려면, 🤗 Datasets [`~datasets.Dataset.map`] 함수를 사용하세요. `batched=True`로 설정해 데이터 세트의 여러 요소들을 한 번에 처리하면 `map` 함수의 속도를 빠르게 할 수 있습니다. 필요하지 않은 열은 모두 제거합니다:
|
||||
|
||||
```py
|
||||
>>> tokenized_squad = squad.map(preprocess_function, batched=True, remove_columns=squad["train"].column_names)
|
||||
```
|
||||
|
||||
이제 [`DefaultDataCollator`]를 이용해 예시 배치를 생성합니다. 🤗 Transformers의 다른 데이터 콜레이터(data collator)와 달리, [`DefaultDataCollator`]는 패딩과 같은 추가 전처리를 적용하지 않습니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]를 이용해 모델을 미세 조정하는 것에 익숙하지 않다면, [여기](../training#train-with-pytorch-trainer)에서 기초 튜토리얼을 살펴보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델 훈련을 시작할 준비가 되었습니다! [`AutoModelForQuestionAnswering`]으로 DistilBERT를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
이제 세 단계만 남았습니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 훈련 하이퍼파라미터를 정합니다. 꼭 필요한 매개변수는 모델을 저장할 위치를 지정하는 `output_dir` 입니다. `push_to_hub=True`로 설정해서 이 모델을 Hub로 푸시합니다 (모델을 업로드하려면 Hugging Face에 로그인해야 합니다).
|
||||
2. 모델, 데이터 세트, 토크나이저, 데이터 콜레이터와 함께 [`Trainer`]에 훈련 인수들을 전달합니다.
|
||||
3. [`~Trainer.train`]을 호출해서 모델을 미세 조정합니다.
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
훈련이 완료되면, [`~transformers.Trainer.push_to_hub`] 매소드를 사용해 모델을 Hub에 공유해서 모든 사람들이 사용할 수 있게 공유해주세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
질의 응답을 위해 모델을 미세 조정하는 방법에 대한 더 자세한 예시는 [PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb) 또는 [TensorFlow notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)을 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 평가[[evaluate]]
|
||||
|
||||
질의 응답을 평가하려면 상당한 양의 후처리가 필요합니다. 시간이 너무 많이 걸리지 않도록 이 가이드에서는 평가 단계를 생략합니다. [`Trainer`]는 훈련 과정에서 평가 손실(evaluation loss)을 계속 계산하기 때문에 모델의 성능을 대략적으로 알 수 있습니다.
|
||||
|
||||
시간에 여유가 있고 질의 응답 모델을 평가하는 방법에 관심이 있다면 🤗 Hugging Face Course의 [Question answering](https://huggingface.co/course/chapter7/7?fw=pt#postprocessing) 챕터를 살펴보세요!
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
질문과 모델이 예측하기 원하는 문맥(context)를 생각해보세요:
|
||||
|
||||
```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."
|
||||
```
|
||||
|
||||
추론을 위해 미세 조정한 모델을 테스트하는 가장 쉬운 방법은 [`pipeline`]을 사용하는 것 입니다. 모델을 사용해 질의 응답을 하기 위해서 `pipeline`을 인스턴스화하고 텍스트를 입력합니다:
|
||||
|
||||
```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'}
|
||||
```
|
||||
|
||||
원한다면 `pipeline`의 결과를 직접 복제할 수도 있습니다:
|
||||
|
||||
텍스트를 토큰화해서 PyTorch 텐서를 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_qa_model")
|
||||
>>> inputs = tokenizer(question, context, return_tensors="pt")
|
||||
```
|
||||
|
||||
모델에 입력을 전달하고 `logits`을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForQuestionAnswering
|
||||
|
||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("my_awesome_qa_model")
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
```
|
||||
|
||||
모델의 출력에서 시작 및 종료 위치가 어딘지 가장 높은 확률을 얻습니다:
|
||||
|
||||
```py
|
||||
>>> answer_start_index = outputs.start_logits.argmax()
|
||||
>>> answer_end_index = outputs.end_logits.argmax()
|
||||
```
|
||||
|
||||
예측된 토큰을 해독해서 답을 얻습니다:
|
||||
|
||||
```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'
|
||||
```
|
||||
345
transformers/docs/source/ko/tasks/semantic_segmentation.md
Normal file
345
transformers/docs/source/ko/tasks/semantic_segmentation.md
Normal file
@@ -0,0 +1,345 @@
|
||||
<!--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.
|
||||
|
||||
-->
|
||||
|
||||
# 의미적 분할(Semantic segmentation)[[semantic-segmentation]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
<Youtube id="dKE8SIt9C-w"/>
|
||||
|
||||
의미적 분할(semantic segmentation)은 이미지의 각 픽셀에 레이블 또는 클래스를 할당합니다. 분할(segmentation)에는 여러 종류가 있으며, 의미적 분할의 경우 동일한 물체의 고유 인스턴스를 구분하지 않습니다. 두 물체 모두 동일한 레이블이 지정됩니다(예시로, "car-1" 과 "car-2" 대신 "car"로 지정합니다).
|
||||
실생활에서 흔히 볼 수 있는 의미적 분할의 적용 사례로는 보행자와 중요한 교통 정보를 식별하는 자율 주행 자동차 학습, 의료 이미지의 세포와 이상 징후 식별, 그리고 위성 이미지의 환경 변화 모니터링등이 있습니다.
|
||||
|
||||
이번 가이드에서 배울 내용은 다음과 같습니다:
|
||||
|
||||
1. [SceneParse150](https://huggingface.co/datasets/scene_parse_150) 데이터 세트를 이용해 [SegFormer](https://huggingface.co/docs/transformers/main/en/model_doc/segformer#segformer) 미세 조정하기.
|
||||
2. 미세 조정된 모델을 추론에 사용하기.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/image-segmentation)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되었는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install -q datasets transformers evaluate
|
||||
```
|
||||
커뮤니티에 모델을 업로드하고 공유할 수 있도록 Hugging Face 계정에 로그인하는 것을 권장합니다. 프롬프트가 나타나면 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## SceneParse150 데이터 세트 불러오기[[load-sceneparse150-dataset]]
|
||||
|
||||
🤗 Datasets 라이브러리에서 SceneParse150 데이터 세트의 더 작은 부분 집합을 가져오는 것으로 시작합니다. 이렇게 하면 데이터 세트 전체에 대한 훈련에 많은 시간을 할애하기 전에 실험을 통해 모든 것이 제대로 작동하는지 확인할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> ds = load_dataset("scene_parse_150", split="train[:50]")
|
||||
```
|
||||
|
||||
데이터 세트의 `train`을 [`~datasets.Dataset.train_test_split`] 메소드를 사용하여 훈련 및 테스트 세트로 분할하세요:
|
||||
|
||||
```py
|
||||
>>> ds = ds.train_test_split(test_size=0.2)
|
||||
>>> train_ds = ds["train"]
|
||||
>>> test_ds = ds["test"]
|
||||
```
|
||||
|
||||
그리고 예시를 살펴보세요:
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
- `image`: 장면의 PIL 이미지입니다.
|
||||
- `annotation`: 분할 지도(segmentation map)의 PIL 이미지입니다. 모델의 타겟이기도 합니다.
|
||||
- `scene_category`: "주방" 또는 "사무실"과 같이 이미지 장면을 설명하는 카테고리 ID입니다. 이 가이드에서는 둘 다 PIL 이미지인 `image`와 `annotation`만을 사용합니다.
|
||||
|
||||
나중에 모델을 설정할 때 유용하게 사용할 수 있도록 레이블 ID를 레이블 클래스에 매핑하는 사전도 만들고 싶을 것입니다. Hub에서 매핑을 다운로드하고 `id2label` 및 `label2id` 사전을 만드세요:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
## 전처리하기[[preprocess]
|
||||
|
||||
다음 단계는 모델에 사용할 이미지와 주석을 준비하기 위해 SegFormer 이미지 프로세서를 불러오는 것입니다. 우리가 사용하는 데이터 세트와 같은 일부 데이터 세트는 배경 클래스로 제로 인덱스를 사용합니다. 하지만 배경 클래스는 150개의 클래스에 실제로는 포함되지 않기 때문에 `do_reduce_labels=True` 를 설정해 모든 레이블에서 배경 클래스를 제거해야 합니다. 제로 인덱스는 `255`로 대체되므로 SegFormer의 손실 함수에서 무시됩니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoImageProcessor
|
||||
|
||||
>>> checkpoint = "nvidia/mit-b0"
|
||||
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint, do_reduce_labels=True)
|
||||
```
|
||||
|
||||
|
||||
이미지 데이터 세트에 데이터 증강을 적용하여 과적합에 대해 모델을 보다 강건하게 만드는 것이 일반적입니다. 이 가이드에서는 [torchvision](https://pytorch.org/vision/stable/index.html)의 [`ColorJitter`](https://pytorch.org/vision/stable/generated/torchvision.transforms.ColorJitter.html)를 사용하여 이미지의 색상 속성을 임의로 변경합니다. 하지만, 자신이 원하는 이미지 라이브러리를 사용할 수도 있습니다.
|
||||
|
||||
```py
|
||||
>>> from torchvision.transforms import ColorJitter
|
||||
|
||||
>>> jitter = ColorJitter(brightness=0.25, contrast=0.25, saturation=0.25, hue=0.1)
|
||||
```
|
||||
|
||||
이제 모델에 사용할 이미지와 주석을 준비하기 위해 두 개의 전처리 함수를 만듭니다. 이 함수들은 이미지를 `pixel_values`로, 주석을 `labels`로 변환합니다. 훈련 세트의 경우 이미지 프로세서에 이미지를 제공하기 전에 `jitter`를 적용합니다. 테스트 세트의 경우 이미지 프로세서는 `images`를 자르고 정규화하며, 테스트 중에는 데이터 증강이 적용되지 않으므로 `labels`만 자릅니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
모든 데이터 세트에 `jitter`를 적용하려면, 🤗 Datasets [`~datasets.Dataset.set_transform`] 함수를 사용하세요. 즉시 변환이 적용되기 때문에 더 빠르고 디스크 공간을 덜 차지합니다:
|
||||
|
||||
```py
|
||||
>>> train_ds.set_transform(train_transforms)
|
||||
>>> test_ds.set_transform(val_transforms)
|
||||
```
|
||||
|
||||
|
||||
## 평가하기[[evaluate]]
|
||||
|
||||
훈련 중에 메트릭을 포함하면 모델의 성능을 평가하는 데 도움이 되는 경우가 많습니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하여 평가 방법을 빠르게 로드할 수 있습니다. 이 태스크에서는 [mean Intersection over Union](https://huggingface.co/spaces/evaluate-metric/accuracy) (IoU) 메트릭을 로드하세요 (메트릭을 로드하고 계산하는 방법에 대해 자세히 알아보려면 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour)를 살펴보세요).
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> metric = evaluate.load("mean_iou")
|
||||
```
|
||||
|
||||
그런 다음 메트릭을 [`~evaluate.EvaluationModule.compute`]하는 함수를 만듭니다. 예측을 먼저 로짓으로 변환한 다음, 레이블의 크기에 맞게 모양을 다시 지정해야 [`~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
|
||||
```
|
||||
|
||||
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었습니다. 트레이닝을 설정할 때 이 함수로 돌아가게 됩니다.
|
||||
|
||||
## 학습하기[[train]]
|
||||
<Tip>
|
||||
|
||||
만약 [`Trainer`]를 사용해 모델을 미세 조정하는 것에 익숙하지 않다면, [여기](../training#finetune-with-trainer)에서 기본 튜토리얼을 살펴보세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델 학습을 시작할 준비가 되었습니다! [`AutoModelForSemanticSegmentation`]로 SegFormer를 불러오고, 모델에 레이블 ID와 레이블 클래스 간의 매핑을 전달합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSemanticSegmentation, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForSemanticSegmentation.from_pretrained(checkpoint, id2label=id2label, label2id=label2id)
|
||||
```
|
||||
|
||||
이제 세 단계만 남았습니다:
|
||||
|
||||
1. 학습 하이퍼파라미터를 [`TrainingArguments`]에 정의합니다. `image` 열이 삭제되기 때문에 사용하지 않는 열을 제거하지 않는 것이 중요합니다. `image` 열이 없으면 `pixel_values`을 생성할 수 없습니다. 이런 경우를 방지하려면 `remove_unused_columns=False`로 설정하세요! 유일하게 필요한 다른 매개변수는 모델을 저장할 위치를 지정하는 `output_dir`입니다. `push_to_hub=True`를 설정하여 이 모델을 Hub에 푸시합니다(모델을 업로드하려면 Hugging Face에 로그인해야 합니다). 각 에포크가 끝날 때마다 [`Trainer`]가 IoU 메트릭을 평가하고 학습 체크포인트를 저장합니다.
|
||||
2. 모델, 데이터 세트, 토크나이저, 데이터 콜레이터, `compute_metrics` 함수와 함께 학습 인자를 [`Trainer`]에 전달하세요.
|
||||
3. 모델을 미세 조정하기 위해 [`~Trainer.train`]를 호출하세요.
|
||||
|
||||
```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()
|
||||
```
|
||||
학습이 완료되면, 누구나 모델을 사용할 수 있도록 [`~transformers.Trainer.push_to_hub`] 메서드를 사용해 Hub에 모델을 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
|
||||
## 추론하기[[inference]]
|
||||
|
||||
이제 모델을 미세 조정했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론할 이미지를 로드하세요:
|
||||
|
||||
```py
|
||||
>>> image = ds[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>
|
||||
|
||||
|
||||
추론을 위해 미세 조정한 모델을 시험해 보는 가장 간단한 방법은 [`pipeline`]에서 사용하는 것입니다. 모델을 사용하여 이미지 분할을 위한 `pipeline`을 인스턴스화하고 이미지를 전달합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> segmenter = pipeline("image-segmentation", model="my_awesome_seg_model")
|
||||
>>> segmenter(image)
|
||||
[{'score': None,
|
||||
'label': 'wall',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062690>},
|
||||
{'score': None,
|
||||
'label': 'sky',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062A50>},
|
||||
{'score': None,
|
||||
'label': 'floor',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062B50>},
|
||||
{'score': None,
|
||||
'label': 'ceiling',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062A10>},
|
||||
{'score': None,
|
||||
'label': 'bed ',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062E90>},
|
||||
{'score': None,
|
||||
'label': 'windowpane',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062390>},
|
||||
{'score': None,
|
||||
'label': 'cabinet',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062550>},
|
||||
{'score': None,
|
||||
'label': 'chair',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062D90>},
|
||||
{'score': None,
|
||||
'label': 'armchair',
|
||||
'mask': <PIL.Image.Image image mode=L size=640x427 at 0x7FD5B2062E10>}]
|
||||
```
|
||||
원하는 경우 `pipeline`의 결과를 수동으로 복제할 수도 있습니다. 이미지 프로세서로 이미지를 처리하고 `pixel_values`을 GPU에 배치합니다:
|
||||
|
||||
```py
|
||||
>>> device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 가능하다면 GPU를 사용하고, 그렇지 않다면 CPU를 사용하세요
|
||||
>>> encoding = image_processor(image, return_tensors="pt")
|
||||
>>> pixel_values = encoding.pixel_values.to(device)
|
||||
```
|
||||
|
||||
모델에 입력을 전달하고 `logits`를 반환합니다:
|
||||
|
||||
```py
|
||||
>>> outputs = model(pixel_values=pixel_values)
|
||||
>>> logits = outputs.logits.cpu()
|
||||
```
|
||||
그런 다음 로짓의 크기를 원본 이미지 크기로 다시 조정합니다:
|
||||
|
||||
```py
|
||||
>>> upsampled_logits = nn.functional.interpolate(
|
||||
... logits,
|
||||
... size=image.size[::-1],
|
||||
... mode="bilinear",
|
||||
... align_corners=False,
|
||||
... )
|
||||
|
||||
>>> pred_seg = upsampled_logits.argmax(dim=1)[0]
|
||||
```
|
||||
|
||||
|
||||
결과를 시각화하려면 [dataset color palette](https://github.com/tensorflow/models/blob/3f1ca33afe3c1631b733ea7e40c294273b9e406d/research/deeplab/utils/get_dataset_colormap.py#L51)를 각 클래스를 RGB 값에 매핑하는 `ade_palette()`로 로드합니다. 그런 다음 이미지와 예측된 분할 지도(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] # BGR로 변환
|
||||
|
||||
>>> img = np.array(image) * 0.5 + color_seg * 0.5 # 분할 지도으로 이미지 구성
|
||||
>>> 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>
|
||||
253
transformers/docs/source/ko/tasks/sequence_classification.md
Normal file
253
transformers/docs/source/ko/tasks/sequence_classification.md
Normal file
@@ -0,0 +1,253 @@
|
||||
<!--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"/>
|
||||
|
||||
텍스트 분류는 자연어 처리의 일종으로, 텍스트에 레이블 또는 클래스를 지정하는 작업입니다. 많은 대기업이 다양한 실용적인 응용 분야에서 텍스트 분류를 운영하고 있습니다. 가장 인기 있는 텍스트 분류 형태 중 하나는 감성 분석으로, 텍스트 시퀀스에 🙂 긍정, 🙁 부정 또는 😐 중립과 같은 레이블을 지정합니다.
|
||||
|
||||
이 가이드에서 학습할 내용은:
|
||||
|
||||
1. [IMDb](https://huggingface.co/datasets/imdb) 데이터셋에서 [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased)를 파인 튜닝하여 영화 리뷰가 긍정적인지 부정적인지 판단합니다.
|
||||
2. 추론을 위해 파인 튜닝 모델을 사용합니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/text-classification)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에, 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하여 모델을 업로드하고 커뮤니티에 공유하는 것을 권장합니다. 메시지가 표시되면, 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## IMDb 데이터셋 가져오기[[load-imdb-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 IMDb 데이터셋을 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> imdb = load_dataset("imdb")
|
||||
```
|
||||
|
||||
그런 다음 예시를 살펴봅시다:
|
||||
|
||||
```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.",
|
||||
}
|
||||
```
|
||||
|
||||
이 데이터셋에는 두 가지 필드가 있습니다:
|
||||
|
||||
- `text`: 영화 리뷰 텍스트
|
||||
- `label`: `0`은 부정적인 리뷰, `1`은 긍정적인 리뷰를 나타냅니다.
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
다음 단계는 DistilBERT 토크나이저를 가져와서 `text` 필드를 전처리하는 것입니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
`text`를 토큰화하고 시퀀스가 DistilBERT의 최대 입력 길이보다 길지 않도록 자르기 위한 전처리 함수를 생성하세요:
|
||||
|
||||
```py
|
||||
>>> def preprocess_function(examples):
|
||||
... return tokenizer(examples["text"], truncation=True)
|
||||
```
|
||||
|
||||
전체 데이터셋에 전처리 함수를 적용하려면, 🤗 Datasets [`~datasets.Dataset.map`] 함수를 사용하세요. 데이터셋의 여러 요소를 한 번에 처리하기 위해 `batched=True`로 설정함으로써 데이터셋 `map`를 더 빠르게 처리할 수 있습니다:
|
||||
|
||||
```py
|
||||
tokenized_imdb = imdb.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
이제 [`DataCollatorWithPadding`]를 사용하여 예제 배치를 만들어봅시다. 데이터셋 전체를 최대 길이로 패딩하는 대신, *동적 패딩*을 사용하여 배치에서 가장 긴 길이에 맞게 문장을 패딩하는 것이 효율적입니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorWithPadding
|
||||
|
||||
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## 평가하기[[evaluate]]
|
||||
|
||||
훈련 중 모델의 성능을 평가하기 위해 메트릭을 포함하는 것이 유용합니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하여 빠르게 평가 방법을 로드할 수 있습니다. 이 작업에서는 [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) 메트릭을 가져옵니다. (메트릭을 가져오고 계산하는 방법에 대해서는 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> accuracy = evaluate.load("accuracy")
|
||||
```
|
||||
|
||||
그런 다음 `compute_metrics` 함수를 만들어서 예측과 레이블을 계산하여 정확도를 계산하도록 [`~evaluate.EvaluationModule.compute`]를 호출합니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수는 준비되었고, 훈련 과정을 설정할 때 다시 살펴볼 예정입니다.
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
모델을 훈련하기 전에, `id2label`와 `label2id`를 사용하여 예상되는 id와 레이블의 맵을 생성하세요:
|
||||
|
||||
```py
|
||||
>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"}
|
||||
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]를 사용하여 모델을 파인 튜닝하는 방법에 익숙하지 않은 경우, [여기](../training#train-with-pytorch-trainer)의 기본 튜토리얼을 확인하세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델을 훈련시킬 준비가 되었습니다! [`AutoModelForSequenceClassification`]로 DistilBERT를 가쳐오고 예상되는 레이블 수와 레이블 매핑을 지정하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForSequenceClassification.from_pretrained(
|
||||
... "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
|
||||
... )
|
||||
```
|
||||
|
||||
이제 세 단계만 거치면 끝입니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 하이퍼파라미터를 정의하세요. `output_dir`는 모델을 저장할 위치를 지정하는 유일한 파라미터입니다. 이 모델을 Hub에 업로드하기 위해 `push_to_hub=True`를 설정합니다. (모델을 업로드하기 위해 Hugging Face에 로그인해야합니다.) 각 에폭이 끝날 때마다, [`Trainer`]는 정확도를 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. [`Trainer`]에 훈련 인수와 모델, 데이터셋, 토크나이저, 데이터 수집기 및 `compute_metrics` 함수를 전달하세요.
|
||||
3. [`~Trainer.train`]를 호출하여 모델은 파인 튜닝하세요.
|
||||
|
||||
```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`]는 `tokenizer`를 전달하면 기본적으로 동적 매핑을 적용합니다. 이 경우, 명시적으로 데이터 수집기를 지정할 필요가 없습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
훈련이 완료되면, [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 Hub에 공유할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
텍스트 분류를 위한 모델을 파인 튜닝하는 자세한 예제는 다음 [PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb) 또는 [TensorFlow notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)를 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 파인 튜닝했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론을 수행하고자 하는 텍스트를 가져와봅시다:
|
||||
|
||||
```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."
|
||||
```
|
||||
|
||||
파인 튜닝된 모델로 추론을 시도하는 가장 간단한 방법은 [`pipeline`]를 사용하는 것입니다. 모델로 감정 분석을 위한 `pipeline`을 인스턴스화하고, 텍스트를 전달해보세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
|
||||
>>> classifier(text)
|
||||
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]
|
||||
```
|
||||
|
||||
원한다면, `pipeline`의 결과를 수동으로 복제할 수도 있습니다.
|
||||
|
||||
텍스트를 토큰화하고 PyTorch 텐서를 반환합니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
```
|
||||
|
||||
입력을 모델에 전달하고 `logits`을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSequenceClassification
|
||||
|
||||
>>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
가장 높은 확률을 가진 클래스를 모델의 `id2label` 매핑을 사용하여 텍스트 레이블로 변환합니다:
|
||||
|
||||
```py
|
||||
>>> predicted_class_id = logits.argmax().item()
|
||||
>>> model.config.id2label[predicted_class_id]
|
||||
'POSITIVE'
|
||||
```
|
||||
282
transformers/docs/source/ko/tasks/summarization.md
Normal file
282
transformers/docs/source/ko/tasks/summarization.md
Normal file
File diff suppressed because one or more lines are too long
399
transformers/docs/source/ko/tasks/token_classification.md
Normal file
399
transformers/docs/source/ko/tasks/token_classification.md
Normal file
@@ -0,0 +1,399 @@
|
||||
<!--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"/>
|
||||
|
||||
토큰 분류는 문장의 개별 토큰에 레이블을 할당합니다. 가장 일반적인 토큰 분류 작업 중 하나는 개체명 인식(Named Entity Recognition, NER)입니다. 개체명 인식은 문장에서 사람, 위치 또는 조직과 같은 각 개체의 레이블을 찾으려고 시도합니다.
|
||||
|
||||
이 가이드에서 학습할 내용은:
|
||||
|
||||
1. [WNUT 17](https://huggingface.co/datasets/wnut_17) 데이터 세트에서 [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased)를 파인 튜닝하여 새로운 개체를 탐지합니다.
|
||||
2. 추론을 위해 파인 튜닝 모델을 사용합니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/token-classification)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에, 필요한 모든 라이브러리가 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate seqeval
|
||||
```
|
||||
|
||||
Hugging Face 계정에 로그인하여 모델을 업로드하고 커뮤니티에 공유하는 것을 권장합니다. 메시지가 표시되면, 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## WNUT 17 데이터 세트 가져오기[[load-wnut-17-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 WNUT 17 데이터 세트를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> wnut = load_dataset("wnut_17")
|
||||
```
|
||||
|
||||
다음 예제를 살펴보세요:
|
||||
|
||||
```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', '.']
|
||||
}
|
||||
```
|
||||
|
||||
`ner_tags`의 각 숫자는 개체를 나타냅니다. 숫자를 레이블 이름으로 변환하여 개체가 무엇인지 확인합니다:
|
||||
|
||||
```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",
|
||||
]
|
||||
```
|
||||
|
||||
각 `ner_tag`의 앞에 붙은 문자는 개체의 토큰 위치를 나타냅니다:
|
||||
|
||||
- `B-`는 개체의 시작을 나타냅니다.
|
||||
- `I-`는 토큰이 동일한 개체 내부에 포함되어 있음을 나타냅니다(예를 들어 `State` 토큰은 `Empire State Building`와 같은 개체의 일부입니다).
|
||||
- `0`는 토큰이 어떤 개체에도 해당하지 않음을 나타냅니다.
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
<Youtube id="iY2AZYdZAr0"/>
|
||||
|
||||
다음으로 `tokens` 필드를 전처리하기 위해 DistilBERT 토크나이저를 가져옵니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
||||
```
|
||||
|
||||
위의 예제 `tokens` 필드를 보면 입력이 이미 토큰화된 것처럼 보입니다. 그러나 실제로 입력은 아직 토큰화되지 않았으므로 단어를 하위 단어로 토큰화하기 위해 `is_split_into_words=True`를 설정해야 합니다. 예제로 확인합니다:
|
||||
|
||||
```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]']
|
||||
```
|
||||
|
||||
그러나 이로 인해 `[CLS]`과 `[SEP]`라는 특수 토큰이 추가되고, 하위 단어 토큰화로 인해 입력과 레이블 간에 불일치가 발생합니다. 하나의 레이블에 해당하는 단일 단어는 이제 두 개의 하위 단어로 분할될 수 있습니다. 토큰과 레이블을 다음과 같이 재정렬해야 합니다:
|
||||
|
||||
1. [`word_ids`](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.BatchEncoding.word_ids) 메소드로 모든 토큰을 해당 단어에 매핑합니다.
|
||||
2. 특수 토큰 `[CLS]`와 `[SEP]`에 `-100` 레이블을 할당하여, PyTorch 손실 함수가 해당 토큰을 무시하도록 합니다.
|
||||
3. 주어진 단어의 첫 번째 토큰에만 레이블을 지정합니다. 같은 단어의 다른 하위 토큰에 `-100`을 할당합니다.
|
||||
|
||||
다음은 토큰과 레이블을 재정렬하고 DistilBERT의 최대 입력 길이보다 길지 않도록 시퀀스를 잘라내는 함수를 만드는 방법입니다:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
전체 데이터 세트에 전처리 함수를 적용하려면, 🤗 Datasets [`~datasets.Dataset.map`] 함수를 사용하세요. `batched=True`로 설정하여 데이터 세트의 여러 요소를 한 번에 처리하면 `map` 함수의 속도를 높일 수 있습니다:
|
||||
```py
|
||||
>>> tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)
|
||||
```
|
||||
|
||||
이제 [`DataCollatorWithPadding`]를 사용하여 예제 배치를 만들어봅시다. 데이터 세트 전체를 최대 길이로 패딩하는 대신, *동적 패딩*을 사용하여 배치에서 가장 긴 길이에 맞게 문장을 패딩하는 것이 효율적입니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForTokenClassification
|
||||
|
||||
>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
## 평가[[evaluation]]
|
||||
|
||||
훈련 중 모델의 성능을 평가하기 위해 평가 지표를 포함하는 것이 유용합니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리를 사용하여 빠르게 평가 방법을 가져올 수 있습니다. 이 작업에서는 [seqeval](https://huggingface.co/spaces/evaluate-metric/seqeval) 평가 지표를 가져옵니다. (평가 지표를 가져오고 계산하는 방법에 대해서는 🤗 Evaluate [빠른 둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하세요). Seqeval은 실제로 정밀도, 재현률, F1 및 정확도와 같은 여러 점수를 산출합니다.
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> seqeval = evaluate.load("seqeval")
|
||||
```
|
||||
|
||||
먼저 NER 레이블을 가져온 다음, [`~evaluate.EvaluationModule.compute`]에 실제 예측과 실제 레이블을 전달하여 점수를 계산하는 함수를 만듭니다:
|
||||
|
||||
```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"],
|
||||
... }
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수를 사용할 준비가 되었으며, 훈련을 설정하면 이 함수로 되돌아올 것입니다.
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
모델을 훈련하기 전에, `id2label`와 `label2id`를 사용하여 예상되는 id와 레이블의 맵을 생성하세요:
|
||||
|
||||
```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>
|
||||
|
||||
[`Trainer`]를 사용하여 모델을 파인 튜닝하는 방법에 익숙하지 않은 경우, [여기](../training#train-with-pytorch-trainer)에서 기본 튜토리얼을 확인하세요!
|
||||
|
||||
</Tip>
|
||||
|
||||
이제 모델을 훈련시킬 준비가 되었습니다! [`AutoModelForSequenceClassification`]로 DistilBERT를 가져오고 예상되는 레이블 수와 레이블 매핑을 지정하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer
|
||||
|
||||
>>> model = AutoModelForTokenClassification.from_pretrained(
|
||||
... "distilbert/distilbert-base-uncased", num_labels=13, id2label=id2label, label2id=label2id
|
||||
... )
|
||||
```
|
||||
|
||||
이제 세 단계만 거치면 끝입니다:
|
||||
|
||||
1. [`TrainingArguments`]에서 하이퍼파라미터를 정의하세요. `output_dir`는 모델을 저장할 위치를 지정하는 유일한 매개변수입니다. 이 모델을 허브에 업로드하기 위해 `push_to_hub=True`를 설정합니다(모델을 업로드하기 위해 Hugging Face에 로그인해야합니다.) 각 에폭이 끝날 때마다, [`Trainer`]는 seqeval 점수를 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. [`Trainer`]에 훈련 인수와 모델, 데이터 세트, 토크나이저, 데이터 콜레이터 및 `compute_metrics` 함수를 전달하세요.
|
||||
3. [`~Trainer.train`]를 호출하여 모델을 파인 튜닝하세요.
|
||||
|
||||
```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()
|
||||
```
|
||||
|
||||
훈련이 완료되면, [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 모델을 허브에 공유할 수 있습니다.
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
토큰 분류를 위한 모델을 파인 튜닝하는 자세한 예제는 다음
|
||||
[PyTorch notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)
|
||||
또는 [TensorFlow notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)를 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 파인 튜닝했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
추론을 수행하고자 하는 텍스트를 가져와봅시다:
|
||||
|
||||
```py
|
||||
>>> text = "The Golden State Warriors are an American professional basketball team based in San Francisco."
|
||||
```
|
||||
|
||||
파인 튜닝된 모델로 추론을 시도하는 가장 간단한 방법은 [`pipeline`]를 사용하는 것입니다. 모델로 NER의 `pipeline`을 인스턴스화하고, 텍스트를 전달해보세요:
|
||||
|
||||
```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}]
|
||||
```
|
||||
|
||||
원한다면, `pipeline`의 결과를 수동으로 복제할 수도 있습니다:
|
||||
|
||||
텍스트를 토큰화하고 PyTorch 텐서를 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
||||
```
|
||||
|
||||
입력을 모델에 전달하고 `logits`을 반환합니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForTokenClassification
|
||||
|
||||
>>> model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
|
||||
>>> with torch.no_grad():
|
||||
... logits = model(**inputs).logits
|
||||
```
|
||||
|
||||
가장 높은 확률을 가진 클래스를 모델의 `id2label` 매핑을 사용하여 텍스트 레이블로 변환합니다:
|
||||
|
||||
```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']
|
||||
```
|
||||
278
transformers/docs/source/ko/tasks/translation.md
Normal file
278
transformers/docs/source/ko/tasks/translation.md
Normal file
@@ -0,0 +1,278 @@
|
||||
<!--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"/>
|
||||
|
||||
번역은 한 언어로 된 시퀀스를 다른 언어로 변환합니다. 번역이나 요약은 입력을 받아 일련의 출력을 반환하는 강력한 프레임워크인 시퀀스-투-시퀀스 문제로 구성할 수 있는 대표적인 태스크입니다. 번역 시스템은 일반적으로 다른 언어로 된 텍스트 간의 번역에 사용되지만, 음성 간의 통역이나 텍스트-음성 또는 음성-텍스트와 같은 조합에도 사용될 수 있습니다.
|
||||
|
||||
이 가이드에서 학습할 내용은:
|
||||
|
||||
1. 영어 텍스트를 프랑스어로 번역하기 위해 [T5](https://huggingface.co/google-t5/t5-small) 모델을 OPUS Books 데이터세트의 영어-프랑스어 하위 집합으로 파인튜닝하는 방법과
|
||||
2. 파인튜닝된 모델을 추론에 사용하는 방법입니다.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/translation)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install transformers datasets evaluate sacrebleu
|
||||
```
|
||||
|
||||
모델을 업로드하고 커뮤니티와 공유할 수 있도록 Hugging Face 계정에 로그인하는 것이 좋습니다. 새로운 창이 표시되면 토큰을 입력하여 로그인하세요.
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## OPUS Books 데이터세트 가져오기[[load-opus-books-dataset]]
|
||||
|
||||
먼저 🤗 Datasets 라이브러리에서 [OPUS Books](https://huggingface.co/datasets/opus_books) 데이터세트의 영어-프랑스어 하위 집합을 가져오세요.
|
||||
|
||||
```py
|
||||
>>> from datasets import load_dataset
|
||||
|
||||
>>> books = load_dataset("opus_books", "en-fr")
|
||||
```
|
||||
|
||||
데이터세트를 [`~datasets.Dataset.train_test_split`] 메서드를 사용하여 훈련 및 테스트 데이터로 분할하세요.
|
||||
|
||||
```py
|
||||
>>> books = books["train"].train_test_split(test_size=0.2)
|
||||
```
|
||||
|
||||
훈련 데이터에서 예시를 살펴볼까요?
|
||||
|
||||
```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` 키가 텍스트의 영어, 프랑스어 버전을 포함하고 있는 것을 볼 수 있습니다.
|
||||
|
||||
## 전처리[[preprocess]]
|
||||
|
||||
<Youtube id="XAR8jnZZuUs"/>
|
||||
|
||||
다음 단계로 영어-프랑스어 쌍을 처리하기 위해 T5 토크나이저를 가져오세요.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> checkpoint = "google-t5/t5-small"
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
만들 전처리 함수는 아래 요구사항을 충족해야 합니다:
|
||||
|
||||
1. T5가 번역 태스크임을 인지할 수 있도록 입력 앞에 프롬프트를 추가하세요. 여러 NLP 태스크를 할 수 있는 모델 중 일부는 이렇게 태스크 프롬프트를 미리 줘야합니다.
|
||||
2. 원어(영어)과 번역어(프랑스어)를 별도로 토큰화하세요. 영어 어휘로 사전 학습된 토크나이저로 프랑스어 텍스트를 토큰화할 수는 없기 때문입니다.
|
||||
3. `max_length` 매개변수로 설정한 최대 길이보다 길지 않도록 시퀀스를 truncate하세요.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
전체 데이터세트에 전처리 함수를 적용하려면 🤗 Datasets의 [`~datasets.Dataset.map`] 메서드를 사용하세요. `map` 함수의 속도를 높이려면 `batched=True`를 설정하여 데이터세트의 여러 요소를 한 번에 처리하는 방법이 있습니다.
|
||||
|
||||
```py
|
||||
>>> tokenized_books = books.map(preprocess_function, batched=True)
|
||||
```
|
||||
|
||||
이제 [`DataCollatorForSeq2Seq`]를 사용하여 예제 배치를 생성합니다. 데이터세트의 최대 길이로 전부를 padding하는 대신, 데이터 정렬 중 각 배치의 최대 길이로 문장을 *동적으로 padding*하는 것이 더 효율적입니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import DataCollatorForSeq2Seq
|
||||
|
||||
>>> data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=checkpoint)
|
||||
```
|
||||
|
||||
## 평가[[evalulate]]
|
||||
|
||||
훈련 중에 메트릭을 포함하면 모델의 성능을 평가하는 데 도움이 됩니다. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) 라이브러리로 평가 방법(evaluation method)을 빠르게 가져올 수 있습니다. 현재 태스크에 적합한 SacreBLEU 메트릭을 가져오세요. (메트릭을 가져오고 계산하는 방법에 대해 자세히 알아보려면 🤗 Evaluate [둘러보기](https://huggingface.co/docs/evaluate/a_quick_tour)를 참조하세요):
|
||||
|
||||
```py
|
||||
>>> import evaluate
|
||||
|
||||
>>> metric = evaluate.load("sacrebleu")
|
||||
```
|
||||
|
||||
그런 다음 [`~evaluate.EvaluationModule.compute`]에 예측값과 레이블을 전달하여 SacreBLEU 점수를 계산하는 함수를 생성하세요:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
이제 `compute_metrics` 함수는 준비되었고, 훈련 과정을 설정할 때 다시 살펴볼 예정입니다.
|
||||
|
||||
## 훈련[[train]]
|
||||
|
||||
<Tip>
|
||||
|
||||
[`Trainer`]로 모델을 파인튜닝하는 방법에 익숙하지 않다면 [여기](../training#train-with-pytorch-trainer)에서 기본 튜토리얼을 살펴보시기 바랍니다!
|
||||
|
||||
</Tip>
|
||||
|
||||
모델을 훈련시킬 준비가 되었군요! [`AutoModelForSeq2SeqLM`]으로 T5를 로드하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSeq2SeqLM, Seq2SeqTrainingArguments, Seq2SeqTrainer
|
||||
|
||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
이제 세 단계만 거치면 끝입니다:
|
||||
|
||||
1. [`Seq2SeqTrainingArguments`]에서 훈련 하이퍼파라미터를 정의하세요. 유일한 필수 매개변수는 모델을 저장할 위치인 `output_dir`입니다. 모델을 Hub에 푸시하기 위해 `push_to_hub=True`로 설정하세요. (모델을 업로드하려면 Hugging Face에 로그인해야 합니다.) [`Trainer`]는 에폭이 끝날때마다 SacreBLEU 메트릭을 평가하고 훈련 체크포인트를 저장합니다.
|
||||
2. [`Seq2SeqTrainer`]에 훈련 인수를 전달하세요. 모델, 데이터 세트, 토크나이저, data collator 및 `compute_metrics` 함수도 덩달아 전달해야 합니다.
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 파인튜닝하세요.
|
||||
|
||||
```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,
|
||||
... 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()
|
||||
```
|
||||
|
||||
학습이 완료되면 [`~transformers.Trainer.push_to_hub`] 메서드로 모델을 Hub에 공유하세요. 이러면 누구나 모델을 사용할 수 있게 됩니다:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
번역을 위해 모델을 파인튜닝하는 방법에 대한 보다 자세한 예제는 해당 [PyTorch 노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb) 또는 [TensorFlow 노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)을 참조하세요.
|
||||
|
||||
</Tip>
|
||||
|
||||
## 추론[[inference]]
|
||||
|
||||
좋아요, 이제 모델을 파인튜닝했으니 추론에 사용할 수 있습니다!
|
||||
|
||||
다른 언어로 번역하고 싶은 텍스트를 써보세요. T5의 경우 원하는 태스크를 입력의 접두사로 추가해야 합니다. 예를 들어 영어에서 프랑스어로 번역하는 경우, 아래와 같은 접두사가 추가됩니다:
|
||||
|
||||
```py
|
||||
>>> text = "translate English to French: Legumes share resources with nitrogen-fixing bacteria."
|
||||
```
|
||||
|
||||
파인튜닝된 모델로 추론하기에 제일 간단한 방법은 [`pipeline`]을 사용하는 것입니다. 해당 모델로 번역 `pipeline`을 만든 뒤, 텍스트를 전달하세요:
|
||||
|
||||
```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="my_awesome_opus_books_model")
|
||||
>>> translator(text)
|
||||
[{'translation_text': 'Legumes partagent des ressources avec des bactéries azotantes.'}]
|
||||
```
|
||||
|
||||
원한다면 `pipeline`의 결과를 직접 복제할 수도 있습니다:
|
||||
|
||||
텍스트를 토큰화하고 `input_ids`를 PyTorch 텐서로 반환하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoTokenizer
|
||||
|
||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_opus_books_model")
|
||||
>>> inputs = tokenizer(text, return_tensors="pt").input_ids
|
||||
```
|
||||
|
||||
[`~generation.GenerationMixin.generate`] 메서드로 번역을 생성하세요. 다양한 텍스트 생성 전략 및 생성을 제어하기 위한 매개변수에 대한 자세한 내용은 [Text Generation](../main_classes/text_generation) API를 살펴보시기 바랍니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoModelForSeq2SeqLM
|
||||
|
||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained("my_awesome_opus_books_model")
|
||||
>>> outputs = model.generate(inputs, max_new_tokens=40, do_sample=True, top_k=30, top_p=0.95)
|
||||
```
|
||||
|
||||
생성된 토큰 ID들을 다시 텍스트로 디코딩하세요:
|
||||
|
||||
```py
|
||||
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
|
||||
'Les lignées partagent des ressources avec des bactéries enfixant l'azote.'
|
||||
```
|
||||
492
transformers/docs/source/ko/tasks/video_classification.md
Normal file
492
transformers/docs/source/ko/tasks/video_classification.md
Normal file
@@ -0,0 +1,492 @@
|
||||
<!--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]]
|
||||
|
||||
|
||||
영상 분류는 영상 전체에 레이블 또는 클래스를 지정하는 작업입니다. 각 영상에는 하나의 클래스가 있을 것으로 예상됩니다. 영상 분류 모델은 영상을 입력으로 받아 어느 클래스에 속하는지에 대한 예측을 반환합니다. 이러한 모델은 영상이 어떤 내용인지 분류하는 데 사용될 수 있습니다. 영상 분류의 실제 응용 예는 피트니스 앱에서 유용한 동작 / 운동 인식 서비스가 있습니다. 이는 또한 시각 장애인이 이동할 때 보조하는데 사용될 수 있습니다
|
||||
|
||||
이 가이드에서는 다음을 수행하는 방법을 보여줍니다:
|
||||
|
||||
1. [UCF101](https://www.crcv.ucf.edu/data/UCF101.php) 데이터 세트의 하위 집합을 통해 [VideoMAE](https://huggingface.co/docs/transformers/main/en/model_doc/videomae) 모델을 미세 조정하기.
|
||||
2. 미세 조정한 모델을 추론에 사용하기.
|
||||
|
||||
<Tip>
|
||||
|
||||
이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 [작업 페이지](https://huggingface.co/tasks/video-classification)를 확인하는 것이 좋습니다.
|
||||
|
||||
</Tip>
|
||||
|
||||
|
||||
시작하기 전에 필요한 모든 라이브러리가 설치되었는지 확인하세요:
|
||||
```bash
|
||||
pip install -q pytorchvideo transformers evaluate
|
||||
```
|
||||
|
||||
영상을 처리하고 준비하기 위해 [PyTorchVideo](https://pytorchvideo.org/)(이하 `pytorchvideo`)를 사용합니다.
|
||||
|
||||
커뮤니티에 모델을 업로드하고 공유할 수 있도록 Hugging Face 계정에 로그인하는 것을 권장합니다. 프롬프트가 나타나면 토큰을 입력하여 로그인하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
## UCF101 데이터셋 불러오기 [[load-ufc101-dataset]]
|
||||
|
||||
[UCF-101](https://www.crcv.ucf.edu/data/UCF101.php) 데이터 세트의 하위 집합(subset)을 불러오는 것으로 시작할 수 있습니다. 전체 데이터 세트를 학습하는데 더 많은 시간을 할애하기 전에 데이터의 하위 집합을 불러와 모든 것이 잘 작동하는지 실험하고 확인할 수 있습니다.
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
데이터 세트의 하위 집합이 다운로드 되면, 압축된 파일의 압축을 해제해야 합니다:
|
||||
```py
|
||||
>>> import tarfile
|
||||
|
||||
>>> with tarfile.open(file_path) as t:
|
||||
... t.extractall(".")
|
||||
```
|
||||
|
||||
전체 데이터 세트는 다음과 같이 구성되어 있습니다.
|
||||
|
||||
```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
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
정렬된 영상의 경로는 다음과 같습니다:
|
||||
|
||||
```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'
|
||||
...
|
||||
```
|
||||
|
||||
동일한 그룹/장면에 속하는 영상 클립은 파일 경로에서 `g`로 표시되어 있습니다. 예를 들면, `v_ApplyEyeMakeup_g07_c04.avi`와 `v_ApplyEyeMakeup_g07_c06.avi` 이 있습니다. 이 둘은 같은 그룹입니다.
|
||||
|
||||
검증 및 평가 데이터 분할을 할 때, [데이터 누출(data leakage)](https://www.kaggle.com/code/alexisbcook/data-leakage)을 방지하기 위해 동일한 그룹 / 장면의 영상 클립을 사용하지 않아야 합니다. 이 튜토리얼에서 사용하는 하위 집합은 이러한 정보를 고려하고 있습니다.
|
||||
|
||||
그 다음으로, 데이터 세트에 존재하는 라벨을 추출합니다. 또한, 모델을 초기화할 때 도움이 될 딕셔너리(dictionary data type)를 생성합니다.
|
||||
|
||||
* `label2id`: 클래스 이름을 정수에 매핑합니다.
|
||||
* `id2label`: 정수를 클래스 이름에 매핑합니다.
|
||||
|
||||
```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'].
|
||||
```
|
||||
|
||||
이 데이터 세트에는 총 10개의 고유한 클래스가 있습니다. 각 클래스마다 30개의 영상이 훈련 세트에 있습니다
|
||||
|
||||
## 미세 조정하기 위해 모델 가져오기 [[load-a-model-to-fine-tune]]
|
||||
|
||||
사전 훈련된 체크포인트와 체크포인트에 연관된 이미지 프로세서를 사용하여 영상 분류 모델을 인스턴스화합니다. 모델의 인코더에는 미리 학습된 매개변수가 제공되며, 분류 헤드(데이터를 분류하는 마지막 레이어)는 무작위로 초기화됩니다. 데이터 세트의 전처리 파이프라인을 작성할 때는 이미지 프로세서가 유용합니다.
|
||||
|
||||
```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
|
||||
... )
|
||||
```
|
||||
|
||||
모델을 가져오는 동안, 다음과 같은 경고를 마주칠 수 있습니다:
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
|
||||
위 경고는 우리가 일부 가중치(예: `classifier` 층의 가중치와 편향)를 버리고 새로운 `classifier` 층의 가중치와 편향을 무작위로 초기화하고 있다는 것을 알려줍니다. 이 경우에는 미리 학습된 가중치가 없는 새로운 헤드를 추가하고 있으므로, 라이브러리가 모델을 추론에 사용하기 전에 미세 조정하라고 경고를 보내는 것은 당연합니다. 그리고 이제 우리는 이 모델을 미세 조정할 예정입니다.
|
||||
|
||||
**참고** 이 [체크포인트](https://huggingface.co/MCG-NJU/videomae-base-finetuned-kinetics)는 도메인이 많이 중첩된 유사한 다운스트림 작업에 대해 미세 조정하여 얻은 체크포인트이므로 이 작업에서 더 나은 성능을 보일 수 있습니다. `MCG-NJU/videomae-base-finetuned-kinetics` 데이터 세트를 미세 조정하여 얻은 [체크포인트](https://huggingface.co/sayakpaul/videomae-base-finetuned-kinetics-finetuned-ucf101-subset)도 있습니다.
|
||||
|
||||
## 훈련을 위한 데이터 세트 준비하기[[prepare-the-datasets-for-training]]
|
||||
|
||||
영상 전처리를 위해 [PyTorchVideo 라이브러리](https://pytorchvideo.org/)를 활용할 것입니다. 필요한 종속성을 가져오는 것으로 시작하세요.
|
||||
|
||||
```py
|
||||
>>> import pytorchvideo.data
|
||||
|
||||
>>> from pytorchvideo.transforms import (
|
||||
... ApplyTransformToKey,
|
||||
... Normalize,
|
||||
... RandomShortSideScale,
|
||||
... RemoveKey,
|
||||
... ShortSideScale,
|
||||
... UniformTemporalSubsample,
|
||||
... )
|
||||
|
||||
>>> from torchvision.transforms import (
|
||||
... Compose,
|
||||
... Lambda,
|
||||
... RandomCrop,
|
||||
... RandomHorizontalFlip,
|
||||
... Resize,
|
||||
... )
|
||||
```
|
||||
|
||||
학습 데이터 세트 변환에는 '균일한 시간 샘플링(uniform temporal subsampling)', '픽셀 정규화(pixel normalization)', '랜덤 잘라내기(random cropping)' 및 '랜덤 수평 뒤집기(random horizontal flipping)'의 조합을 사용합니다. 검증 및 평가 데이터 세트 변환에는 '랜덤 잘라내기'와 '랜덤 뒤집기'를 제외한 동일한 변환 체인을 유지합니다. 이러한 변환에 대해 자세히 알아보려면 [PyTorchVideo 공식 문서](https://pytorchvideo.org)를 확인하세요.
|
||||
|
||||
사전 훈련된 모델과 관련된 이미지 프로세서를 사용하여 다음 정보를 얻을 수 있습니다:
|
||||
|
||||
* 영상 프레임 픽셀을 정규화하는 데 사용되는 이미지 평균과 표준 편차
|
||||
* 영상 프레임이 조정될 공간 해상도
|
||||
|
||||
|
||||
먼저, 몇 가지 상수를 정의합니다.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
이제 데이터 세트에 특화된 전처리(transform)과 데이터 세트 자체를 정의합니다. 먼저 훈련 데이터 세트로 시작합니다:
|
||||
|
||||
```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,
|
||||
... )
|
||||
```
|
||||
|
||||
같은 방식의 작업 흐름을 검증과 평가 세트에도 적용할 수 있습니다.
|
||||
|
||||
```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,
|
||||
... )
|
||||
```
|
||||
|
||||
|
||||
**참고**: 위의 데이터 세트의 파이프라인은 [공식 파이토치 예제](https://pytorchvideo.org/docs/tutorial_classification#dataset)에서 가져온 것입니다. 우리는 UCF-101 데이터셋에 맞게 [`pytorchvideo.data.Ucf101()`](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html#pytorchvideo.data.Ucf101) 함수를 사용하고 있습니다. 내부적으로 이 함수는 [`pytorchvideo.data.labeled_video_dataset.LabeledVideoDataset`](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html#pytorchvideo.data.LabeledVideoDataset) 객체를 반환합니다. `LabeledVideoDataset` 클래스는 PyTorchVideo 데이터셋에서 모든 영상 관련 작업의 기본 클래스입니다. 따라서 PyTorchVideo에서 미리 제공하지 않는 사용자 지정 데이터 세트를 사용하려면, 이 클래스를 적절하게 확장하면 됩니다. 더 자세한 사항이 알고 싶다면 `data` API [문서](https://pytorchvideo.readthedocs.io/en/latest/api/data/data.html) 를 참고하세요. 또한 위의 예시와 유사한 구조를 갖는 데이터 세트를 사용하고 있다면, `pytorchvideo.data.Ucf101()` 함수를 사용하는 데 문제가 없을 것입니다.
|
||||
|
||||
데이터 세트에 영상의 개수를 알기 위해 `num_videos` 인수에 접근할 수 있습니다.
|
||||
|
||||
```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]]
|
||||
|
||||
🤗 Transformers의 [`Trainer`](https://huggingface.co/docs/transformers/main_classes/trainer)를 사용하여 모델을 훈련시켜보세요. `Trainer`를 인스턴스화하려면 훈련 설정과 평가 지표를 정의해야 합니다. 가장 중요한 것은 [`TrainingArguments`](https://huggingface.co/transformers/main_classes/trainer.html#transformers.TrainingArguments)입니다. 이 클래스는 훈련을 구성하는 모든 속성을 포함하며, 훈련 중 체크포인트를 저장할 출력 폴더 이름을 필요로 합니다. 또한 🤗 Hub의 모델 저장소의 모든 정보를 동기화하는 데 도움이 됩니다.
|
||||
|
||||
대부분의 훈련 인수는 따로 설명할 필요는 없습니다. 하지만 여기에서 중요한 인수는 `remove_unused_columns=False` 입니다. 이 인자는 모델의 호출 함수에서 사용되지 않는 모든 속성 열(columns)을 삭제합니다. 기본값은 일반적으로 True입니다. 이는 사용되지 않는 기능 열을 삭제하는 것이 이상적이며, 입력을 모델의 호출 함수로 풀기(unpack)가 쉬워지기 때문입니다. 하지만 이 경우에는 `pixel_values`(모델의 입력으로 필수적인 키)를 생성하기 위해 사용되지 않는 기능('video'가 특히 그렇습니다)이 필요합니다. 따라서 remove_unused_columns을 False로 설정해야 합니다.
|
||||
|
||||
```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,
|
||||
... )
|
||||
```
|
||||
|
||||
`pytorchvideo.data.Ucf101()` 함수로 반환되는 데이터 세트는 `__len__` 메소드가 이식되어 있지 않습니다. 따라서, `TrainingArguments`를 인스턴스화할 때 `max_steps`를 정의해야 합니다.
|
||||
|
||||
다음으로, 평가지표를 불러오고, 예측값에서 평가지표를 계산할 함수를 정의합니다. 필요한 전처리 작업은 예측된 로짓(logits)에 argmax 값을 취하는 것뿐입니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
**평가에 대한 참고사항**:
|
||||
|
||||
[VideoMAE 논문](https://huggingface.co/papers/2203.12602)에서 저자는 다음과 같은 평가 전략을 사용합니다. 테스트 영상에서 여러 클립을 선택하고 그 클립에 다양한 크롭을 적용하여 집계 점수를 보고합니다. 그러나 이번 튜토리얼에서는 간단함과 간결함을 위해 해당 전략을 고려하지 않습니다.
|
||||
|
||||
또한, 예제를 묶어서 배치를 형성하는 `collate_fn`을 정의해야합니다. 각 배치는 `pixel_values`와 `labels`라는 2개의 키로 구성됩니다.
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
그런 다음 이 모든 것을 데이터 세트와 함께 `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,
|
||||
... )
|
||||
```
|
||||
|
||||
데이터를 이미 처리했는데도 불구하고 `image_processor`를 토크나이저 인수로 넣은 이유는 JSON으로 저장되는 이미지 프로세서 구성 파일이 Hub의 저장소에 업로드되도록 하기 위함입니다.
|
||||
|
||||
`train` 메소드를 호출하여 모델을 미세 조정하세요:
|
||||
|
||||
```py
|
||||
>>> train_results = trainer.train()
|
||||
```
|
||||
|
||||
학습이 완료되면, 모델을 [`~transformers.Trainer.push_to_hub`] 메소드를 사용하여 허브에 공유하여 누구나 모델을 사용할 수 있도록 합니다:
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## 추론하기[[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>
|
||||
|
||||
미세 조정된 모델을 추론에 사용하는 가장 간단한 방법은 [`pipeline`](https://huggingface.co/docs/transformers/main/en/main_classes/pipelines#transformers.VideoClassificationPipeline)에서 모델을 사용하는 것입니다. 모델로 영상 분류를 하기 위해 `pipeline`을 인스턴스화하고 영상을 전달하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> 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'}]
|
||||
```
|
||||
|
||||
만약 원한다면 수동으로 `pipeline`의 결과를 재현할 수 있습니다:
|
||||
|
||||
|
||||
```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("cuda" if torch.cuda.is_available() else "cpu")
|
||||
... 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
|
||||
```
|
||||
|
||||
모델에 입력값을 넣고 `logits`을 반환받으세요:
|
||||
|
||||
```py
|
||||
>>> logits = run_inference(trained_model, sample_test_video["video"])
|
||||
```
|
||||
|
||||
`logits`을 디코딩하면, 우리는 다음 결과를 얻을 수 있습니다:
|
||||
|
||||
```py
|
||||
>>> predicted_class_idx = logits.argmax(-1).item()
|
||||
>>> print("Predicted class:", model.config.id2label[predicted_class_idx])
|
||||
# Predicted class: BasketballDunk
|
||||
```
|
||||
375
transformers/docs/source/ko/tasks/visual_question_answering.md
Normal file
375
transformers/docs/source/ko/tasks/visual_question_answering.md
Normal file
@@ -0,0 +1,375 @@
|
||||
<!--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]]
|
||||
|
||||
시각적 질의응답(VQA)은 이미지를 기반으로 개방형 질문에 대응하는 작업입니다. 이 작업을 지원하는 모델의 입력은 대부분 이미지와 질문의 조합이며, 출력은 자연어로 된 답변입니다.
|
||||
|
||||
VQA의 주요 사용 사례는 다음과 같습니다:
|
||||
* 시각 장애인을 위한 접근성 애플리케이션을 구축할 수 있습니다.
|
||||
* 교육: 강의나 교과서에 나온 시각 자료에 대한 질문에 답할 수 있습니다. 또한 체험형 전시와 유적 등에서도 VQA를 활용할 수 있습니다.
|
||||
* 고객 서비스 및 전자상거래: VQA는 사용자가 제품에 대해 질문할 수 있게 함으로써 사용자 경험을 향상시킬 수 있습니다.
|
||||
* 이미지 검색: VQA 모델을 사용하여 원하는 특성을 가진 이미지를 검색할 수 있습니다. 예를 들어 사용자는 "강아지가 있어?"라고 물어봐서 주어진 이미지 묶음에서 강아지가 있는 모든 이미지를 받아볼 수 있습니다.
|
||||
|
||||
이 가이드에서 학습할 내용은 다음과 같습니다:
|
||||
|
||||
- VQA 모델 중 하나인 [ViLT](../../en/model_doc/vilt)를 [`Graphcore/vqa` 데이터셋](https://huggingface.co/datasets/Graphcore/vqa) 에서 미세조정하는 방법
|
||||
- 미세조정된 ViLT 모델로 추론하는 방법
|
||||
- BLIP-2 같은 생성 모델로 제로샷 VQA 추론을 실행하는 방법
|
||||
|
||||
## ViLT 미세 조정 [[finetuning-vilt]]
|
||||
|
||||
ViLT는 Vision Transformer (ViT) 내에 텍스트 임베딩을 포함하여 비전/자연어 사전훈련(VLP; Vision-and-Language Pretraining)을 위한 기본 디자인을 제공합니다.
|
||||
ViLT 모델은 비전 트랜스포머(ViT)에 텍스트 임베딩을 넣어 비전/언어 사전훈련(VLP; Vision-and-Language Pre-training)을 위한 기본적인 디자인을 갖췄습니다. 이 모델은 여러 다운스트림 작업에 사용할 수 있습니다. VQA 태스크에서는 (`[CLS]` 토큰의 최종 은닉 상태 위에 선형 레이어인) 분류 헤더가 있으며 무작위로 초기화됩니다.
|
||||
따라서 여기에서 시각적 질의응답은 **분류 문제**로 취급됩니다.
|
||||
|
||||
최근의 BLIP, BLIP-2, InstructBLIP와 같은 모델들은 VQA를 생성형 작업으로 간주합니다. 가이드의 후반부에서는 이런 모델들을 사용하여 제로샷 VQA 추론을 하는 방법에 대해 설명하겠습니다.
|
||||
|
||||
시작하기 전 필요한 모든 라이브러리를 설치했는지 확인하세요.
|
||||
|
||||
```bash
|
||||
pip install -q transformers datasets
|
||||
```
|
||||
|
||||
커뮤니티에 모델을 공유하는 것을 권장 드립니다. Hugging Face 계정에 로그인하여 🤗 Hub에 업로드할 수 있습니다.
|
||||
메시지가 나타나면 로그인할 토큰을 입력하세요:
|
||||
|
||||
```py
|
||||
>>> from huggingface_hub import notebook_login
|
||||
|
||||
>>> notebook_login()
|
||||
```
|
||||
|
||||
모델 체크포인트를 전역 변수로 선언하세요.
|
||||
|
||||
```py
|
||||
>>> model_checkpoint = "dandelin/vilt-b32-mlm"
|
||||
```
|
||||
|
||||
## 데이터 가져오기 [[load-the-data]]
|
||||
|
||||
이 가이드에서는 `Graphcore/vqa` 데이터세트의 작은 샘플을 사용합니다. 전체 데이터세트는 [🤗 Hub](https://huggingface.co/datasets/Graphcore/vqa) 에서 확인할 수 있습니다.
|
||||
|
||||
[`Graphcore/vqa` 데이터세트](https://huggingface.co/datasets/Graphcore/vqa) 의 대안으로 공식 [VQA 데이터세트 페이지](https://visualqa.org/download.html) 에서 동일한 데이터를 수동으로 다운로드할 수 있습니다. 직접 공수한 데이터로 튜토리얼을 따르고 싶다면 [이미지 데이터세트 만들기](https://huggingface.co/docs/datasets/image_dataset#loading-script) 라는
|
||||
🤗 Datasets 문서를 참조하세요.
|
||||
|
||||
검증 데이터의 첫 200개 항목을 불러와 데이터세트의 특성을 확인해 보겠습니다:
|
||||
|
||||
```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
|
||||
})
|
||||
```
|
||||
|
||||
예제를 하나 뽑아 데이터세트의 특성을 이해해 보겠습니다.
|
||||
|
||||
```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]}}
|
||||
```
|
||||
|
||||
데이터세트에는 다음과 같은 특성이 포함되어 있습니다:
|
||||
* `question`: 이미지에 대한 질문
|
||||
* `image_id`: 질문과 관련된 이미지의 경로
|
||||
* `label`: 데이터의 레이블 (annotations)
|
||||
|
||||
나머지 특성들은 필요하지 않기 때문에 삭제해도 됩니다:
|
||||
|
||||
```py
|
||||
>>> dataset = dataset.remove_columns(['question_type', 'question_id', 'answer_type'])
|
||||
```
|
||||
|
||||
보시다시피 `label` 특성은 같은 질문마다 답변이 여러 개 있을 수 있습니다. 모두 다른 데이터 라벨러들로부터 수집되었기 때문인데요. 질문의 답변은 주관적일 수 있습니다. 이 경우 질문은 "그는 어디를 보고 있나요?" 였지만, 어떤 사람들은 "아래"로 레이블을 달았고, 다른 사람들은 "테이블" 또는 "스케이트보드" 등으로 주석을 달았습니다.
|
||||
|
||||
아래의 이미지를 보고 어떤 답변을 선택할 것인지 생각해 보세요:
|
||||
|
||||
```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>
|
||||
|
||||
질문과 답변의 모호성으로 인해 이러한 데이터세트는 여러 개의 답변이 가능하므로 다중 레이블 분류 문제로 처리됩니다. 게다가, 원핫(one-hot) 인코딩 벡터를 생성하기보다는 레이블에서 특정 답변이 나타나는 횟수를 기반으로 소프트 인코딩을 생성합니다.
|
||||
|
||||
위의 예시에서 "아래"라는 답변이 다른 답변보다 훨씬 더 자주 선택되었기 때문에 데이터세트에서 `weight`라고 불리는 점수로 1.0을 가지며, 나머지 답변들은 1.0 미만의 점수를 가집니다.
|
||||
|
||||
적절한 분류 헤더로 모델을 나중에 인스턴스화하기 위해 레이블을 정수로 매핑한 딕셔너리 하나, 반대로 정수를 레이블로 매핑한 딕셔너리 하나 총 2개의 딕셔너리를 생성하세요:
|
||||
|
||||
```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()}
|
||||
```
|
||||
|
||||
이제 매핑이 완료되었으므로 문자열 답변을 해당 id로 교체하고, 데이터세트의 더 편리한 후처리를 위해 편평화 할 수 있습니다.
|
||||
|
||||
```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]]
|
||||
|
||||
다음 단계는 모델을 위해 이미지와 텍스트 데이터를 준비하기 위해 ViLT 프로세서를 가져오는 것입니다.
|
||||
[`ViltProcessor`]는 BERT 토크나이저와 ViLT 이미지 프로세서를 편리하게 하나의 프로세서로 묶습니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import ViltProcessor
|
||||
|
||||
>>> processor = ViltProcessor.from_pretrained(model_checkpoint)
|
||||
```
|
||||
|
||||
데이터를 전처리하려면 이미지와 질문을 [`ViltProcessor`]로 인코딩해야 합니다. 프로세서는 [`BertTokenizerFast`]로 텍스트를 토크나이즈하고 텍스트 데이터를 위해 `input_ids`, `attention_mask` 및 `token_type_ids`를 생성합니다.
|
||||
이미지는 [`ViltImageProcessor`]로 이미지를 크기 조정하고 정규화하며, `pixel_values`와 `pixel_mask`를 생성합니다.
|
||||
|
||||
이런 전처리 단계는 모두 내부에서 이루어지므로, `processor`를 호출하기만 하면 됩니다. 하지만 아직 타겟 레이블이 완성되지 않았습니다. 타겟의 표현에서 각 요소는 가능한 답변(레이블)에 해당합니다. 정확한 답변의 요소는 해당 점수(weight)를 유지시키고 나머지 요소는 0으로 설정해야 합니다.
|
||||
|
||||
아래 함수가 위에서 설명한대로 이미지와 질문에 `processor`를 적용하고 레이블을 형식에 맞춥니다:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
전체 데이터세트에 전처리 함수를 적용하려면 🤗 Datasets의 [`~datasets.map`] 함수를 사용하십시오. `batched=True`를 설정하여 데이터세트의 여러 요소를 한 번에 처리함으로써 `map`을 더 빠르게 할 수 있습니다. 이 시점에서 필요하지 않은 열은 제거하세요.
|
||||
|
||||
```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
|
||||
})
|
||||
```
|
||||
|
||||
마지막 단계로, [`DefaultDataCollator`]를 사용하여 예제로 쓸 배치를 생성하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import DefaultDataCollator
|
||||
|
||||
>>> data_collator = DefaultDataCollator()
|
||||
```
|
||||
|
||||
## 모델 훈련 [[train-the-model]]
|
||||
|
||||
이제 모델을 훈련하기 위해 준비되었습니다! [`ViltForQuestionAnswering`]으로 ViLT를 가져올 차례입니다. 레이블의 수와 레이블 매핑을 지정하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import ViltForQuestionAnswering
|
||||
|
||||
>>> model = ViltForQuestionAnswering.from_pretrained(model_checkpoint, num_labels=len(id2label), id2label=id2label, label2id=label2id)
|
||||
```
|
||||
|
||||
이 시점에서는 다음 세 단계만 남았습니다:
|
||||
|
||||
1. [`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. 모델, 데이터세트, 프로세서, 데이터 콜레이터와 함께 훈련 인수를 [`Trainer`]에 전달하세요:
|
||||
|
||||
```py
|
||||
>>> from transformers import Trainer
|
||||
|
||||
>>> trainer = Trainer(
|
||||
... model=model,
|
||||
... args=training_args,
|
||||
... data_collator=data_collator,
|
||||
... train_dataset=processed_dataset,
|
||||
... processing_class=processor,
|
||||
... )
|
||||
```
|
||||
|
||||
3. [`~Trainer.train`]을 호출하여 모델을 미세 조정하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.train()
|
||||
```
|
||||
|
||||
훈련이 완료되면, [`~Trainer.push_to_hub`] 메소드를 사용하여 🤗 Hub에 모델을 공유하세요:
|
||||
|
||||
```py
|
||||
>>> trainer.push_to_hub()
|
||||
```
|
||||
|
||||
## 추론 [[inference]]
|
||||
|
||||
ViLT 모델을 미세 조정하고 🤗 Hub에 업로드했다면 추론에 사용할 수 있습니다. 미세 조정된 모델을 추론에 사용해보는 가장 간단한 방법은 [`Pipeline`]에서 사용하는 것입니다.
|
||||
|
||||
```py
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> pipe = pipeline("visual-question-answering", model="MariaK/vilt_finetuned_200")
|
||||
```
|
||||
|
||||
이 가이드의 모델은 200개의 예제에서만 훈련되었으므로 그다지 많은 것을 기대할 수는 없습니다. 데이터세트의 첫 번째 예제를 사용하여 추론 결과를 설명해보겠습니다:
|
||||
|
||||
```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'}]
|
||||
```
|
||||
|
||||
비록 확신은 별로 없지만, 모델은 실제로 무언가를 배웠습니다. 더 많은 예제와 더 긴 훈련 기간이 주어진다면 분명 더 나은 결과를 얻을 수 있을 것입니다!
|
||||
|
||||
원한다면 파이프라인의 결과를 수동으로 복제할 수도 있습니다:
|
||||
1. 이미지와 질문을 가져와서 프로세서를 사용하여 모델에 준비합니다.
|
||||
2. 전처리된 결과를 모델에 전달합니다.
|
||||
3. 로짓에서 가장 가능성 있는 답변의 id를 가져와서 `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
|
||||
```
|
||||
|
||||
## 제로샷 VQA [[zeroshot-vqa]]
|
||||
|
||||
이전 모델은 VQA를 분류 문제로 처리했습니다. BLIP, BLIP-2 및 InstructBLIP와 같은 최근의 모델은 VQA를 생성 작업으로 접근합니다. [BLIP-2](../../en/model_doc/blip-2)를 예로 들어 보겠습니다. 이 모델은 사전훈련된 비전 인코더와 LLM의 모든 조합을 사용할 수 있는 새로운 비전-자연어 사전 학습 패러다임을 도입했습니다. ([BLIP-2 블로그 포스트](https://huggingface.co/blog/blip-2)를 통해 더 자세히 알아볼 수 있어요)
|
||||
이를 통해 시각적 질의응답을 포함한 여러 비전-자연어 작업에서 SOTA를 달성할 수 있었습니다.
|
||||
|
||||
이 모델을 어떻게 VQA에 사용할 수 있는지 설명해 보겠습니다. 먼저 모델을 가져와 보겠습니다. 여기서 GPU가 사용 가능한 경우 모델을 명시적으로 GPU로 전송할 것입니다. 이전에는 훈련할 때 쓰지 않은 이유는 [`Trainer`]가 이 부분을 자동으로 처리하기 때문입니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, Blip2ForConditionalGeneration
|
||||
>>> import torch
|
||||
|
||||
>>> processor = AutoProcessor.from_pretrained("Salesforce/blip2-opt-2.7b")
|
||||
>>> model = Blip2ForConditionalGeneration.from_pretrained("Salesforce/blip2-opt-2.7b", dtype=torch.float16)
|
||||
>>> device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
>>> model.to(device)
|
||||
```
|
||||
|
||||
모델은 이미지와 텍스트를 입력으로 받으므로, VQA 데이터세트의 첫 번째 예제에서와 동일한 이미지/질문 쌍을 사용해 보겠습니다:
|
||||
|
||||
```py
|
||||
>>> example = dataset[0]
|
||||
>>> image = Image.open(example['image_id'])
|
||||
>>> question = example['question']
|
||||
```
|
||||
|
||||
BLIP-2를 시각적 질의응답 작업에 사용하려면 텍스트 프롬프트가 `Question: {} Answer:` 형식을 따라야 합니다.
|
||||
|
||||
```py
|
||||
>>> prompt = f"Question: {question} Answer:"
|
||||
```
|
||||
|
||||
이제 모델의 프로세서로 이미지/프롬프트를 전처리하고, 처리된 입력을 모델을 통해 전달하고, 출력을 디코드해야 합니다:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
보시다시피 모델은 군중을 인식하고, 얼굴의 방향(아래쪽을 보고 있음)을 인식했지만, 군중이 스케이터 뒤에 있다는 사실을 놓쳤습니다. 그러나 사람이 직접 라벨링한 데이터셋을 얻을 수 없는 경우에, 이 접근법은 빠르게 유용한 결과를 생성할 수 있습니다.
|
||||
@@ -0,0 +1,144 @@
|
||||
<!--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) 이미지 분류[[zeroshot-image-classification]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
제로샷(zero-shot) 이미지 분류는 특정 카테고리의 예시가 포함된 데이터를 학습되지 않은 모델을 사용해 이미지 분류를 수행하는 작업입니다.
|
||||
|
||||
일반적으로 이미지 분류를 위해서는 레이블이 달린 특정 이미지 데이터로 모델 학습이 필요하며, 이 모델은 특정 이미지의 특징을 레이블에 "매핑"하는 방법을 학습합니다.
|
||||
새로운 레이블이 있는 분류 작업에 이러한 모델을 사용해야 하는 경우에는, 모델을 "재보정"하기 위해 미세 조정이 필요합니다.
|
||||
|
||||
이와 대조적으로, 제로샷 또는 개방형 어휘(open vocabulary) 이미지 분류 모델은 일반적으로 대규모 이미지 데이터와 해당 설명에 대해 학습된 멀티모달(multimodal) 모델입니다.
|
||||
이러한 모델은 제로샷 이미지 분류를 포함한 많은 다운스트림 작업에 사용할 수 있는 정렬된(aligned) 비전 언어 표현을 학습합니다.
|
||||
|
||||
이는 이미지 분류에 대한 보다 유연한 접근 방식으로, 추가 학습 데이터 없이 새로운 레이블이나 학습하지 못한 카테고리에 대해 모델을 일반화할 수 있습니다.
|
||||
또한, 사용자가 대상 개체에 대한 자유 형식의 텍스트 설명으로 이미지를 검색할 수 있습니다.
|
||||
|
||||
이번 가이드에서 배울 내용은 다음과 같습니다:
|
||||
|
||||
* 제로샷 이미지 분류 파이프라인 만들기
|
||||
* 직접 제로샷 이미지 분류 모델 추론 실행하기
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## 제로샷(zero-shot) 이미지 분류 파이프라인[[zeroshot-image-classification-pipeline]]
|
||||
|
||||
[`pipeline`]을 활용하면 가장 간단하게 제로샷 이미지 분류를 지원하는 모델로 추론해볼 수 있습니다.
|
||||
[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")
|
||||
```
|
||||
|
||||
다음으로, 분류하고 싶은 이미지를 선택하세요.
|
||||
|
||||
```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>
|
||||
|
||||
이미지와 해당 이미지의 후보 레이블인 `candidate_labels`를 파이프라인으로 전달합니다.
|
||||
여기서는 이미지를 직접 전달하지만, 컴퓨터에 저장된 이미지의 경로나 url로 전달할 수도 있습니다.
|
||||
`candidate_labels`는 이 예시처럼 간단한 단어일 수도 있고 좀 더 설명적인 단어일 수도 있습니다.
|
||||
|
||||
```py
|
||||
>>> predictions = classifier(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) 이미지 분류하기[[zeroshot-image-classification-by-hand]]
|
||||
|
||||
이제 제로샷 이미지 분류 파이프라인 사용 방법을 살펴보았으니, 실행하는 방법을 살펴보겠습니다.
|
||||
|
||||
[Hugging Face Hub에 업로드된 체크포인트](https://huggingface.co/models?pipeline_tag=zero-shot-image-classification&sort=downloads)에서 모델과 프로세서를 가져오는 것으로 시작합니다.
|
||||
여기서는 이전과 동일한 체크포인트를 사용하겠습니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, AutoModelForZeroShotImageClassification
|
||||
|
||||
>>> model = AutoModelForZeroShotImageClassification.from_pretrained(checkpoint)
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
다른 이미지를 사용해 보겠습니다.
|
||||
|
||||
```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>
|
||||
|
||||
프로세서를 사용해 모델의 입력을 준비합니다.
|
||||
프로세서는 모델의 입력으로 사용하기 위해 이미지 크기를 변환하고 정규화하는 이미지 프로세서와 텍스트 입력을 처리하는 토크나이저로 구성됩니다.
|
||||
|
||||
```py
|
||||
>>> candidate_labels = ["tree", "car", "bike", "cat"]
|
||||
>>> inputs = processor(images=image, text=candidate_labels, return_tensors="pt", padding=True)
|
||||
```
|
||||
|
||||
모델에 입력을 전달하고, 결과를 후처리합니다:
|
||||
|
||||
```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'}]
|
||||
```
|
||||
307
transformers/docs/source/ko/tasks/zero_shot_object_detection.md
Normal file
307
transformers/docs/source/ko/tasks/zero_shot_object_detection.md
Normal file
@@ -0,0 +1,307 @@
|
||||
<!--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) 객체 탐지[[zeroshot-object-detection]]
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
일반적으로 [객체 탐지](object_detection)에 사용되는 모델을 학습하기 위해서는 레이블이 지정된 이미지 데이터 세트가 필요합니다.
|
||||
그리고 학습 데이터에 존재하는 클래스(레이블)만 탐지할 수 있다는 한계점이 있습니다.
|
||||
|
||||
다른 방식을 사용하는 [OWL-ViT](../model_doc/owlvit) 모델로 제로샷 객체 탐지가 가능합니다.
|
||||
OWL-ViT는 개방형 어휘(open-vocabulary) 객체 탐지기입니다.
|
||||
즉, 레이블이 지정된 데이터 세트에 미세 조정하지 않고 자유 텍스트 쿼리를 기반으로 이미지에서 객체를 탐지할 수 있습니다.
|
||||
|
||||
OWL-ViT 모델은 멀티 모달 표현을 활용해 개방형 어휘 탐지(open-vocabulary detection)를 수행합니다.
|
||||
[CLIP](../model_doc/clip) 모델에 경량화(lightweight)된 객체 분류와 지역화(localization) 헤드를 결합합니다.
|
||||
개방형 어휘 탐지는 CLIP의 텍스트 인코더로 free-text 쿼리를 임베딩하고, 객체 분류와 지역화 헤드의 입력으로 사용합니다.
|
||||
이미지와 해당 텍스트 설명을 연결하면 ViT가 이미지 패치(image patches)를 입력으로 처리합니다.
|
||||
OWL-ViT 모델의 저자들은 CLIP 모델을 처음부터 학습(scratch learning)한 후에, bipartite matching loss를 사용하여 표준 객체 인식 데이터셋으로 OWL-ViT 모델을 미세 조정했습니다.
|
||||
|
||||
이 접근 방식을 사용하면 모델은 레이블이 지정된 데이터 세트에 대한 사전 학습 없이도 텍스트 설명을 기반으로 객체를 탐지할 수 있습니다.
|
||||
|
||||
이번 가이드에서는 OWL-ViT 모델의 사용법을 다룰 것입니다:
|
||||
- 텍스트 프롬프트 기반 객체 탐지
|
||||
- 일괄 객체 탐지
|
||||
- 이미지 가이드 객체 탐지
|
||||
|
||||
시작하기 전에 필요한 라이브러리가 모두 설치되어 있는지 확인하세요:
|
||||
```bash
|
||||
pip install -q transformers
|
||||
```
|
||||
|
||||
## 제로샷(zero-shot) 객체 탐지 파이프라인[[zeroshot-object-detection-pipeline]]
|
||||
|
||||
[`pipeline`]을 활용하면 가장 간단하게 OWL-ViT 모델을 추론해볼 수 있습니다.
|
||||
[Hugging Face Hub에 업로드된 체크포인트](https://huggingface.co/models?pipeline_tag=zero-shot-image-classification&sort=downloads)에서 제로샷(zero-shot) 객체 탐지용 파이프라인을 인스턴스화합니다:
|
||||
|
||||
```python
|
||||
>>> from transformers import pipeline
|
||||
|
||||
>>> checkpoint = "google/owlvit-base-patch32"
|
||||
>>> detector = pipeline(model=checkpoint, task="zero-shot-object-detection")
|
||||
```
|
||||
|
||||
다음으로, 객체를 탐지하고 싶은 이미지를 선택하세요.
|
||||
여기서는 [NASA](https://www.nasa.gov/multimedia/imagegallery/index.html) Great Images 데이터 세트의 일부인 우주비행사 에일린 콜린스(Eileen Collins) 사진을 사용하겠습니다.
|
||||
|
||||
```py
|
||||
>>> import skimage
|
||||
>>> import numpy as np
|
||||
>>> from PIL import Image
|
||||
|
||||
>>> image = skimage.data.astronaut()
|
||||
>>> image = Image.fromarray(np.uint8(image)).convert("RGB")
|
||||
|
||||
>>> 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>
|
||||
|
||||
이미지와 해당 이미지의 후보 레이블을 파이프라인으로 전달합니다.
|
||||
여기서는 이미지를 직접 전달하지만, 컴퓨터에 저장된 이미지의 경로나 url로 전달할 수도 있습니다.
|
||||
candidate_labels는 이 예시처럼 간단한 단어일 수도 있고 좀 더 설명적인 단어일 수도 있습니다.
|
||||
또한, 이미지를 검색(query)하려는 모든 항목에 대한 텍스트 설명도 전달합니다.
|
||||
|
||||
```py
|
||||
>>> predictions = detector(
|
||||
... image,
|
||||
... candidate_labels=["human face", "rocket", "nasa badge", "star-spangled banner"],
|
||||
... )
|
||||
>>> predictions
|
||||
[{'score': 0.3571370542049408,
|
||||
'label': 'human face',
|
||||
'box': {'xmin': 180, 'ymin': 71, 'xmax': 271, 'ymax': 178}},
|
||||
{'score': 0.28099656105041504,
|
||||
'label': 'nasa badge',
|
||||
'box': {'xmin': 129, 'ymin': 348, 'xmax': 206, 'ymax': 427}},
|
||||
{'score': 0.2110239565372467,
|
||||
'label': 'rocket',
|
||||
'box': {'xmin': 350, 'ymin': -1, 'xmax': 468, 'ymax': 288}},
|
||||
{'score': 0.13790413737297058,
|
||||
'label': 'star-spangled banner',
|
||||
'box': {'xmin': 1, 'ymin': 1, 'xmax': 105, 'ymax': 509}},
|
||||
{'score': 0.11950037628412247,
|
||||
'label': 'nasa badge',
|
||||
'box': {'xmin': 277, 'ymin': 338, 'xmax': 327, 'ymax': 380}},
|
||||
{'score': 0.10649408400058746,
|
||||
'label': 'rocket',
|
||||
'box': {'xmin': 358, 'ymin': 64, 'xmax': 424, 'ymax': 280}}]
|
||||
```
|
||||
|
||||
이제 예측값을 시각화해봅시다:
|
||||
|
||||
```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>
|
||||
|
||||
## 텍스트 프롬프트 기반 객체 탐지[[textprompted-zeroshot-object-detection-by-hand]]
|
||||
|
||||
제로샷 객체 탐지 파이프라인 사용법에 대해 살펴보았으니, 이제 동일한 결과를 복제해보겠습니다.
|
||||
|
||||
[Hugging Face Hub에 업로드된 체크포인트](https://huggingface.co/models?other=owlvit)에서 관련 모델과 프로세서를 가져오는 것으로 시작합니다.
|
||||
여기서는 이전과 동일한 체크포인트를 사용하겠습니다:
|
||||
|
||||
```py
|
||||
>>> from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection
|
||||
|
||||
>>> model = AutoModelForZeroShotObjectDetection.from_pretrained(checkpoint)
|
||||
>>> processor = AutoProcessor.from_pretrained(checkpoint)
|
||||
```
|
||||
|
||||
다른 이미지를 사용해 보겠습니다:
|
||||
|
||||
```py
|
||||
>>> import requests
|
||||
|
||||
>>> url = "https://unsplash.com/photos/oj0zeY2Ltk4/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MTR8fHBpY25pY3xlbnwwfHx8fDE2Nzc0OTE1NDk&force=true&w=640"
|
||||
>>> im = Image.open(requests.get(url, stream=True).raw)
|
||||
>>> im
|
||||
```
|
||||
|
||||
<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>
|
||||
|
||||
프로세서를 사용해 모델의 입력을 준비합니다.
|
||||
프로세서는 모델의 입력으로 사용하기 위해 이미지 크기를 변환하고 정규화하는 이미지 프로세서와 텍스트 입력을 처리하는 [`CLIPTokenizer`]로 구성됩니다.
|
||||
|
||||
```py
|
||||
>>> text_queries = ["hat", "book", "sunglasses", "camera"]
|
||||
>>> inputs = processor(text=text_queries, images=im, return_tensors="pt")
|
||||
```
|
||||
|
||||
모델에 입력을 전달하고 결과를 후처리 및 시각화합니다.
|
||||
이미지 프로세서가 모델에 이미지를 입력하기 전에 이미지 크기를 조정했기 때문에, [`~OwlViTImageProcessor.post_process_object_detection`] 메소드를 사용해
|
||||
예측값의 바운딩 박스(bounding box)가 원본 이미지의 좌표와 상대적으로 동일한지 확인해야 합니다.
|
||||
|
||||
```py
|
||||
>>> import torch
|
||||
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
... target_sizes = torch.tensor([im.size[::-1]])
|
||||
... results = processor.post_process_object_detection(outputs, threshold=0.1, target_sizes=target_sizes)[0]
|
||||
|
||||
>>> draw = ImageDraw.Draw(im)
|
||||
|
||||
>>> scores = results["scores"].tolist()
|
||||
>>> labels = results["labels"].tolist()
|
||||
>>> boxes = results["boxes"].tolist()
|
||||
|
||||
>>> for box, score, label in zip(boxes, scores, labels):
|
||||
... xmin, ymin, xmax, ymax = box
|
||||
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
|
||||
... draw.text((xmin, ymin), f"{text_queries[label]}: {round(score,2)}", fill="white")
|
||||
|
||||
>>> im
|
||||
```
|
||||
|
||||
<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]]
|
||||
|
||||
여러 이미지와 텍스트 쿼리를 전달하여 여러 이미지에서 서로 다른(또는 동일한) 객체를 검색할 수 있습니다.
|
||||
일괄 처리를 위해서 텍스트 쿼리는 이중 리스트로, 이미지는 PIL 이미지, PyTorch 텐서, 또는 NumPy 배열로 이루어진 리스트로 프로세서에 전달해야 합니다.
|
||||
|
||||
```py
|
||||
>>> images = [image, im]
|
||||
>>> text_queries = [
|
||||
... ["human face", "rocket", "nasa badge", "star-spangled banner"],
|
||||
... ["hat", "book", "sunglasses", "camera"],
|
||||
... ]
|
||||
>>> inputs = processor(text=text_queries, images=images, return_tensors="pt")
|
||||
```
|
||||
|
||||
이전에는 후처리를 위해 단일 이미지의 크기를 텐서로 전달했지만, 튜플을 전달할 수 있고, 여러 이미지를 처리하는 경우에는 튜플로 이루어진 리스트를 전달할 수도 있습니다.
|
||||
아래 두 예제에 대한 예측을 생성하고, 두 번째 이미지(`image_idx = 1`)를 시각화해 보겠습니다.
|
||||
|
||||
```py
|
||||
>>> with torch.no_grad():
|
||||
... outputs = model(**inputs)
|
||||
... target_sizes = [x.size[::-1] for x in images]
|
||||
... results = processor.post_process_object_detection(outputs, threshold=0.1, target_sizes=target_sizes)
|
||||
|
||||
>>> image_idx = 1
|
||||
>>> draw = ImageDraw.Draw(images[image_idx])
|
||||
|
||||
>>> scores = results[image_idx]["scores"].tolist()
|
||||
>>> labels = results[image_idx]["labels"].tolist()
|
||||
>>> boxes = results[image_idx]["boxes"].tolist()
|
||||
|
||||
>>> for box, score, label in zip(boxes, scores, labels):
|
||||
... xmin, ymin, xmax, ymax = box
|
||||
... draw.rectangle((xmin, ymin, xmax, ymax), outline="red", width=1)
|
||||
... draw.text((xmin, ymin), f"{text_queries[image_idx][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>
|
||||
|
||||
## 이미지 가이드 객체 탐지[[imageguided-object-detection]]
|
||||
|
||||
텍스트 쿼리를 이용한 제로샷 객체 탐지 외에도 OWL-ViT 모델은 이미지 가이드 객체 탐지 기능을 제공합니다.
|
||||
이미지를 쿼리로 사용해 대상 이미지에서 유사한 객체를 찾을 수 있다는 의미입니다.
|
||||
텍스트 쿼리와 달리 하나의 예제 이미지에서만 가능합니다.
|
||||
|
||||
소파에 고양이 두 마리가 있는 이미지를 대상 이미지(target image)로, 고양이 한 마리가 있는 이미지를 쿼리로 사용해보겠습니다:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
다음 이미지를 살펴보겠습니다:
|
||||
|
||||
```py
|
||||
>>> import matplotlib.pyplot as plt
|
||||
|
||||
>>> fig, ax = plt.subplots(1, 2)
|
||||
>>> ax[0].imshow(image_target)
|
||||
>>> ax[1].imshow(query_image)
|
||||
```
|
||||
|
||||
<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>
|
||||
|
||||
전처리 단계에서 텍스트 쿼리 대신에 `query_images`를 사용합니다:
|
||||
|
||||
```py
|
||||
>>> inputs = processor(images=image_target, query_images=query_image, return_tensors="pt")
|
||||
```
|
||||
|
||||
예측의 경우, 모델에 입력을 전달하는 대신 [`~OwlViTForObjectDetection.image_guided_detection`]에 전달합니다.
|
||||
레이블이 없다는 점을 제외하면 이전과 동일합니다.
|
||||
이전과 동일하게 이미지를 시각화합니다.
|
||||
|
||||
```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, label in zip(boxes, scores, labels):
|
||||
... 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>
|
||||
|
||||
OWL-ViT 모델을 추론하고 싶다면 아래 데모를 확인하세요:
|
||||
|
||||
<iframe
|
||||
src="https://adirik-owl-vit.hf.space"
|
||||
frameborder="0"
|
||||
width="850"
|
||||
height="450"
|
||||
></iframe>
|
||||
Reference in New Issue
Block a user