From 97da4dc619b3bb48baf9b73e93d1f6786dcafc9f Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Mon, 19 Dec 2022 09:50:05 +0900 Subject: [PATCH 01/12] Add Ko chapter2 2.mdx --- chapters/ko/_toctree.yml | 2 + chapters/ko/chapter2/2.mdx | 353 +++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 chapters/ko/chapter2/2.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index bde0efee5..83281fbf3 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -31,3 +31,5 @@ sections: - local: chapter2/1 title: 단원 소개 + - local: chapter2/2 + title: 파이프라인 내부 동작 과정 diff --git a/chapters/ko/chapter2/2.mdx b/chapters/ko/chapter2/2.mdx new file mode 100644 index 000000000..718ea976d --- /dev/null +++ b/chapters/ko/chapter2/2.mdx @@ -0,0 +1,353 @@ + + +# 파이프라인 내부 동작 과정[[behind-the-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +PyTorch를 사용하는지, TensorFlow를 사용하는지에 따라 내용이 약간 달라지는 첫 번째 섹션입니다. 제목 상단 스위치를 이용해 선호하는 플랫폼을 선택하세요! + + +{#if fw === 'pt'} + +{:else} + +{/if} + +완전한 예제를 이용해, 아래의 [제1단원](/course/chapter1) 코드를 수행했을 때 뒤에서 어떤 일이 일어나고 있는지 알아봅시다. + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", + ] +) +``` + +다음과 같은 출력이 나오게 됩니다. + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +[제1단원](/course/chapter1)에서 확인했듯이, 이 파이프라인 그룹은 세 단계(전처리, 입력을 모델에 넘겨주는 것, 후처리)를 함께 수행합니다. + +
+The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. + +
+ +각 단게에 대해 빠르게 살펴보겠습니다. + +## 토크나이저를 이용한 전처리[[preprocessing-with-a-tokenizer]] + +다른 신경망처럼 Transformer 모델도 원시 텍스트를 바로 처리할 수 없기 때문에 파이프라인의 첫 번째 단계는 텍스트 입력을 모델이 이해할 수 있는 숫자로 변환하는 것입니다. 이 과정을 위해 다음 기능들을 수행하는 *토크나이저*를 사용합니다. + +- 입력을 *토큰*이라고 부르는 단어나 하위 단어, 또는 심볼(예-구두점)로 분할 +- 각 토큰을 하나의 정수에 매핑 +- 모델에 유용할 수 있는 부가적인 입력 추가 + +이 모든 전처리 과정은 모델이 사전학습될 때와 완전히 동일한 방식으로 진행되어야 하기 때문에 [Model Hub](https://huggingface.co/models)에서 정보를 다운로드 해야합니다. 전처리를 위해 `AutoTokenizer` 클래스와 AutoTokenizer의 `from_pretrained()` 메서드를 사용합니다. 모델의 체크포인트 이름을 사용하여 모델의 토크나이저와 연관된 데이터를 자동으로 가져와 저장합니다. (따라서 아래 코드를 처음 실행할 때만 다운로드됩니다.) + +`sentiment-analysis` 파이프라인의 기본 체크포인트는 `distilbert-base-uncased-finetuned-sst-2-english`(모델 카드 확인은 [여기](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)서 가능)이므로 아래 코드를 실행합니다. + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +토크나이저가 있다면 문장을 토크나이저에 입력하여 우리의 모델에 전달할 준비가 된 딕셔너리를 출력으로 얻게 됩니다! 남은 것은 입력 ID 목록을 tensor로 변환하는 것입니다. + +여러분은 어떤 ML 프레임워크-PyTorch나 TensorFlow, 또는 몇몇 모델을 위한 Flax-가 백엔드로 사용되는지 걱정하지 않고 🤗 Transformers를 사용할 수 있습니다. 하지만 Transformer 모델은 *tensor*만을 입력으로 받습니다. 만약 tensor에 대해 처음 들어봤다면, NumPy 배열을 생각하면 됩니다. NumPy 배열은 스칼라(0D), 벡터(1D), 행렬(2D) 또는 더 많은 차원을 가질 수 있습니다. 이것은 사실상 텐서입니다. 다른 ML 프레임워크의 텐서도 유사하게 동작하며, NumPy 배열처럼 인스턴스화가 쉽습니다. + +얻고자 하는 tensor의 타입(PyTorch, TensorFlow, 일반 NumPy)을 지정하기 위해, `return_tensors` 전달인자를 사용합니다. + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +padding과 truncation에 대해 벌써 걱정하지 마세요. 나중에 설명하도록 하겠습니다. 여기서 기억해야 할 중요한 점은 하나의 문장 또는 여러 개의 문장 리스트를 토크나이저 함수로 전달할 수 있을 뿐만 아니라 얻고 싶은 텐서 유형까지 지정할 수 있다는 것입니다. (텐서 유형이 지정되지 않으면 이중 리스트를 결과로 얻게 됩니다) + +{#if fw === 'pt'} + +PyTorch tensor로 지정했을 때의 결과입니다. + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_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, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +TensorFlow tensor로 지정했을 때의 결과입니다. + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +출력은 `input_ids`와 `attention_mask` 두 개의 키를 갖는 딕셔너리입니다. `input_ids`는 각 문장 내 토큰의 고유 식별자인 정수로 이루어진 2개의 행(한 행이 하나의 문장)을 가지고 있습니다. `attention_mask`는 이 챕터의 뒤쪽에서 설명할 것입니다. + +## 모델 살펴보기[[going-through-the-model]] + +{#if fw === 'pt'} +토크나이저를 다운받은 방식과 동일한 방식으로 사전학습된 모델을 다운받을 수 있습니다. 🤗 Transformers는 `from_pretrained` 메서드를 가진 `AutoModel` 클래스를 제공합니다. + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +토크나이저를 다운받은 방식과 동일한 방식으로 사전학습된 모델을 다운받을 수 있습니다. 🤗 Transformers는 `from_pretrained` 메서드를 가진 `TFAutoModel` 클래스를 제공합니다. + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +이 코드 스니펫에서 이전 파이프라인에서 사용된 것과 동일한 체크포인트를 다운로드(실제로는 이미 저장되어 있어야 합니다.)하고 그것으로 모델을 인스턴스화했습니다. + +해당 아키텍처는 기본 Transformer 모듈만 포함하고 있습니다. 입력이 주어지면 *features*라고도 불리는 *hidden states*를 출력합니다. 각 모델의 입력에 대해 **Transformer 모델에 의해 수행된 입력의 문맥적 이해**로 표현할 수 있는 고차원 벡터를 가져옵니다. + +이 내용이 이해되지 않더라도 걱정하지 마세요. 뒤에서 설명할 것입니다. + +이러한 hidden states는 그 자체로 유용할 수 있지만 일반적으로 *head*라고 알려진 모델의 다른 부분에 입력으로 들어갑니다. [제1단원](/course/chapter1)에서, 동일한 구조로 다른 태스크를 수행할 수 있었는데 이 태스크들은 서로 다른 헤드와 연관되어 있습니다. + +### 고차원 벡터란?[[a-high-dimensional-vector]] + +Transformer 모듈에 의한 출력 벡터는 일반적으로 크며 보통 3개의 차원을 가집니다. + +- **Batch size**: 한 번에 처리되는 시퀀스의 수 (예제에서는 2) +- **Sequence length**: 시퀀스의 숫자 표현 길이 (예제에서는 16) +- **Hidden size**: 각 모델 입력 벡터 차원 + +위에서 마지막 값으로 인해 "고차원"이라고 불립니다. hidden size는 매우 클 수 있습니다 (작은 모델은 768이 일반적이며 큰 모델은 3072나 그 이상의 값이 될 수 있습니다) + +전처리 과정을 거친 입력을 모델로 넘기면 아래 결과를 확인할 수 있습니다. + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +🤗 Transformers 모델의 출력은 `namedtuple` 또는 딕셔너리 형태입니다. 속성이나 키(`outputs["last_hidden_state"]`)를 이용해 요소에 접근할 수 있고 찾고자 하는 것의 정확한 위치를 안다면 인덱스(`outputs[0]`)도 사용할 수 있습니다. + +### 모델 헤드: 숫자로 이해하기[[model-heads-making-sense-out-of-numbers]] + +모델 헤드는 hidden state의 고차원 벡터를 입력으로 받아 다른 차원으로 투영합니다. 모델 헤드는 보통 하나 이상의 선형 레이어로 이루어져 있습니다. + +
+A Transformer network alongside its head. + +
+ +Transformer 모델의 출력은 처리할 모델 헤드로 바로 전달됩니다. + +이 다이어그램에서, 모델은 모델의 임베딩 레이어와 후속 레이어로 표현됩니다. 임베딩 레이어는 토큰화된 각각의 입력 ID를 연관된 토큰을 나타내는 벡터로 변환합니다. 후속 레이어는 문장의 최종 표현을 만들기 위해 어텐션 메커니즘을 이용해 이 벡터들을 처리합니다. + +🤗 Transformer에는 다양한 아키텍처가 있으며, 각각의 아키텍처는 특정 작업을 처리하도록 설계되었습니다. 아래는 일부 아키텍처입니다. + +- `*Model` (retrieve the hidden states) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- 그 외 🤗 + +{#if fw === 'pt'} +이 예제를 위해서는 문장을 긍정 또는 부정으로 분류할 수 있게 하는 시퀀스 분류 헤드를 가진 모델이 필요합니다. 따라서 `AutoModel` 클래스가 아닌 `AutoModelForSequenceClassification`을 사용할 것입니다. + +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +이 예제를 위해서는 문장을 긍정 또는 부정으로 분류할 수 있게 하는 시퀀스 분류 헤드를 가진 모델이 필요합니다. 따라서 `AutoModel` 클래스가 아닌 `TFAutoModelForSequenceClassification`을 사용할 것입니다. + +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +출력 형태를 보면 차원이 훨씬 적은 것을 알 수 있습니다. 모델 헤드는 이전에 봤던 고차원 벡터를 입력으로 받아 2개의 값(레이블 당 하나)으로 이루어진 벡터를 출력합니다. + +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +우리는 2개의 문장과 2개의 레이블만 있기 때문에 모델로부터 얻은 출력 형태는 2 x 2입니다. + +## 출력 후처리[[postprocessing-the-output]] + +모델의 출력 값이 그 자체로 의미있는 것은 아닙니다. 한 번 보도록 합시다. + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +모델은 첫 번째 문장에 대해 `[-1.5607, 1.6123]`으로 예측했고 두 번째 문장에 대해 `[ 4.1692, -3.3464]`으로 예측했습니다. 이 값들은 확률이 아니라 모델의 마지막 층에 의해 출력된 정규화되지 않은 점수인 *logits*입니다. 확률로 변환되기 위해 logits은 [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) 층을 거쳐야 합니다. 학습을 위한 손실 함수가 일반적으로 SoftMax와 같은 마지막 활성함수와 교차 엔트로피와 같은 실제 손실 함수를 모두 사용하기 때문에 모든 🤗 Transformers 모델의 출력은 logit입니다. + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +모델은 첫 번째 문장에 대해 `[0.0402, 0.9598]`로 예측했고 두 번째 모델에 대해 `[0.9995, 0.0005]`로 예측했습니다. 이 값들은 확실하게 확률값입니다. + +각 위치에 해당하는 레이블을 얻기 위해, 모델 config의 `id2label` 속성을 살펴봅시다. Config에 대한 더 많은 내용은 다음 섹션에서 진행됩니다. + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +모델의 예측 결과를 아래처럼 결론 지을 수 있습니다. + +- 첫 번째 문장: NEGATIVE: 0.0402, POSITIVE: 0.9598 +- 두 번째 문장: NEGATIVE: 0.9995, POSITIVE: 0.0005 + +파이프라인 세 단게-토크나이저를 이용한 전처리, 모델에 입력 넣어주기, 후처리-를 성공적으로 재현했습니다! 이제 각 단계별로 좀 더 깊게 알아보는 시간을 가져봅시다. + + + +✏️ **직접 해보세요!** 2개 이상의 문장을 골라 `sentiment-analysis` 파이프라인을 적용해보세요. 이 챕터에서 본 내용을 그대로 수행해보고 같은 결과가 나오는지 확인해보세요! + + From 367581f13f35a491000394e9bbabc603b54057b2 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Mon, 19 Dec 2022 09:50:05 +0900 Subject: [PATCH 02/12] Add Ko chapter2 2.mdx --- chapters/ko/_toctree.yml | 2 + chapters/ko/chapter2/2.mdx | 353 +++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 chapters/ko/chapter2/2.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index e63d927b6..d1d952c7d 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -31,6 +31,8 @@ sections: - local: chapter2/1 title: 단원 소개 + - local: chapter2/2 + title: 파이프라인 내부 동작 과정 - title: 8. 도움을 요청하는 방법 sections: diff --git a/chapters/ko/chapter2/2.mdx b/chapters/ko/chapter2/2.mdx new file mode 100644 index 000000000..718ea976d --- /dev/null +++ b/chapters/ko/chapter2/2.mdx @@ -0,0 +1,353 @@ + + +# 파이프라인 내부 동작 과정[[behind-the-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +PyTorch를 사용하는지, TensorFlow를 사용하는지에 따라 내용이 약간 달라지는 첫 번째 섹션입니다. 제목 상단 스위치를 이용해 선호하는 플랫폼을 선택하세요! + + +{#if fw === 'pt'} + +{:else} + +{/if} + +완전한 예제를 이용해, 아래의 [제1단원](/course/chapter1) 코드를 수행했을 때 뒤에서 어떤 일이 일어나고 있는지 알아봅시다. + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", + ] +) +``` + +다음과 같은 출력이 나오게 됩니다. + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +[제1단원](/course/chapter1)에서 확인했듯이, 이 파이프라인 그룹은 세 단계(전처리, 입력을 모델에 넘겨주는 것, 후처리)를 함께 수행합니다. + +
+The full NLP pipeline: tokenization of text, conversion to IDs, and inference through the Transformer model and the model head. + +
+ +각 단게에 대해 빠르게 살펴보겠습니다. + +## 토크나이저를 이용한 전처리[[preprocessing-with-a-tokenizer]] + +다른 신경망처럼 Transformer 모델도 원시 텍스트를 바로 처리할 수 없기 때문에 파이프라인의 첫 번째 단계는 텍스트 입력을 모델이 이해할 수 있는 숫자로 변환하는 것입니다. 이 과정을 위해 다음 기능들을 수행하는 *토크나이저*를 사용합니다. + +- 입력을 *토큰*이라고 부르는 단어나 하위 단어, 또는 심볼(예-구두점)로 분할 +- 각 토큰을 하나의 정수에 매핑 +- 모델에 유용할 수 있는 부가적인 입력 추가 + +이 모든 전처리 과정은 모델이 사전학습될 때와 완전히 동일한 방식으로 진행되어야 하기 때문에 [Model Hub](https://huggingface.co/models)에서 정보를 다운로드 해야합니다. 전처리를 위해 `AutoTokenizer` 클래스와 AutoTokenizer의 `from_pretrained()` 메서드를 사용합니다. 모델의 체크포인트 이름을 사용하여 모델의 토크나이저와 연관된 데이터를 자동으로 가져와 저장합니다. (따라서 아래 코드를 처음 실행할 때만 다운로드됩니다.) + +`sentiment-analysis` 파이프라인의 기본 체크포인트는 `distilbert-base-uncased-finetuned-sst-2-english`(모델 카드 확인은 [여기](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english)서 가능)이므로 아래 코드를 실행합니다. + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +토크나이저가 있다면 문장을 토크나이저에 입력하여 우리의 모델에 전달할 준비가 된 딕셔너리를 출력으로 얻게 됩니다! 남은 것은 입력 ID 목록을 tensor로 변환하는 것입니다. + +여러분은 어떤 ML 프레임워크-PyTorch나 TensorFlow, 또는 몇몇 모델을 위한 Flax-가 백엔드로 사용되는지 걱정하지 않고 🤗 Transformers를 사용할 수 있습니다. 하지만 Transformer 모델은 *tensor*만을 입력으로 받습니다. 만약 tensor에 대해 처음 들어봤다면, NumPy 배열을 생각하면 됩니다. NumPy 배열은 스칼라(0D), 벡터(1D), 행렬(2D) 또는 더 많은 차원을 가질 수 있습니다. 이것은 사실상 텐서입니다. 다른 ML 프레임워크의 텐서도 유사하게 동작하며, NumPy 배열처럼 인스턴스화가 쉽습니다. + +얻고자 하는 tensor의 타입(PyTorch, TensorFlow, 일반 NumPy)을 지정하기 위해, `return_tensors` 전달인자를 사용합니다. + +{#if fw === 'pt'} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` +{:else} +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="tf") +print(inputs) +``` +{/if} + +padding과 truncation에 대해 벌써 걱정하지 마세요. 나중에 설명하도록 하겠습니다. 여기서 기억해야 할 중요한 점은 하나의 문장 또는 여러 개의 문장 리스트를 토크나이저 함수로 전달할 수 있을 뿐만 아니라 얻고 싶은 텐서 유형까지 지정할 수 있다는 것입니다. (텐서 유형이 지정되지 않으면 이중 리스트를 결과로 얻게 됩니다) + +{#if fw === 'pt'} + +PyTorch tensor로 지정했을 때의 결과입니다. + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_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, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` +{:else} + +TensorFlow tensor로 지정했을 때의 결과입니다. + +```python out +{ + 'input_ids': , + 'attention_mask': +} +``` +{/if} + +출력은 `input_ids`와 `attention_mask` 두 개의 키를 갖는 딕셔너리입니다. `input_ids`는 각 문장 내 토큰의 고유 식별자인 정수로 이루어진 2개의 행(한 행이 하나의 문장)을 가지고 있습니다. `attention_mask`는 이 챕터의 뒤쪽에서 설명할 것입니다. + +## 모델 살펴보기[[going-through-the-model]] + +{#if fw === 'pt'} +토크나이저를 다운받은 방식과 동일한 방식으로 사전학습된 모델을 다운받을 수 있습니다. 🤗 Transformers는 `from_pretrained` 메서드를 가진 `AutoModel` 클래스를 제공합니다. + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` +{:else} +토크나이저를 다운받은 방식과 동일한 방식으로 사전학습된 모델을 다운받을 수 있습니다. 🤗 Transformers는 `from_pretrained` 메서드를 가진 `TFAutoModel` 클래스를 제공합니다. + +```python +from transformers import TFAutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModel.from_pretrained(checkpoint) +``` +{/if} + +이 코드 스니펫에서 이전 파이프라인에서 사용된 것과 동일한 체크포인트를 다운로드(실제로는 이미 저장되어 있어야 합니다.)하고 그것으로 모델을 인스턴스화했습니다. + +해당 아키텍처는 기본 Transformer 모듈만 포함하고 있습니다. 입력이 주어지면 *features*라고도 불리는 *hidden states*를 출력합니다. 각 모델의 입력에 대해 **Transformer 모델에 의해 수행된 입력의 문맥적 이해**로 표현할 수 있는 고차원 벡터를 가져옵니다. + +이 내용이 이해되지 않더라도 걱정하지 마세요. 뒤에서 설명할 것입니다. + +이러한 hidden states는 그 자체로 유용할 수 있지만 일반적으로 *head*라고 알려진 모델의 다른 부분에 입력으로 들어갑니다. [제1단원](/course/chapter1)에서, 동일한 구조로 다른 태스크를 수행할 수 있었는데 이 태스크들은 서로 다른 헤드와 연관되어 있습니다. + +### 고차원 벡터란?[[a-high-dimensional-vector]] + +Transformer 모듈에 의한 출력 벡터는 일반적으로 크며 보통 3개의 차원을 가집니다. + +- **Batch size**: 한 번에 처리되는 시퀀스의 수 (예제에서는 2) +- **Sequence length**: 시퀀스의 숫자 표현 길이 (예제에서는 16) +- **Hidden size**: 각 모델 입력 벡터 차원 + +위에서 마지막 값으로 인해 "고차원"이라고 불립니다. hidden size는 매우 클 수 있습니다 (작은 모델은 768이 일반적이며 큰 모델은 3072나 그 이상의 값이 될 수 있습니다) + +전처리 과정을 거친 입력을 모델로 넘기면 아래 결과를 확인할 수 있습니다. + +{#if fw === 'pt'} +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` +{:else} +```py +outputs = model(inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +(2, 16, 768) +``` +{/if} + +🤗 Transformers 모델의 출력은 `namedtuple` 또는 딕셔너리 형태입니다. 속성이나 키(`outputs["last_hidden_state"]`)를 이용해 요소에 접근할 수 있고 찾고자 하는 것의 정확한 위치를 안다면 인덱스(`outputs[0]`)도 사용할 수 있습니다. + +### 모델 헤드: 숫자로 이해하기[[model-heads-making-sense-out-of-numbers]] + +모델 헤드는 hidden state의 고차원 벡터를 입력으로 받아 다른 차원으로 투영합니다. 모델 헤드는 보통 하나 이상의 선형 레이어로 이루어져 있습니다. + +
+A Transformer network alongside its head. + +
+ +Transformer 모델의 출력은 처리할 모델 헤드로 바로 전달됩니다. + +이 다이어그램에서, 모델은 모델의 임베딩 레이어와 후속 레이어로 표현됩니다. 임베딩 레이어는 토큰화된 각각의 입력 ID를 연관된 토큰을 나타내는 벡터로 변환합니다. 후속 레이어는 문장의 최종 표현을 만들기 위해 어텐션 메커니즘을 이용해 이 벡터들을 처리합니다. + +🤗 Transformer에는 다양한 아키텍처가 있으며, 각각의 아키텍처는 특정 작업을 처리하도록 설계되었습니다. 아래는 일부 아키텍처입니다. + +- `*Model` (retrieve the hidden states) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- 그 외 🤗 + +{#if fw === 'pt'} +이 예제를 위해서는 문장을 긍정 또는 부정으로 분류할 수 있게 하는 시퀀스 분류 헤드를 가진 모델이 필요합니다. 따라서 `AutoModel` 클래스가 아닌 `AutoModelForSequenceClassification`을 사용할 것입니다. + +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` +{:else} +이 예제를 위해서는 문장을 긍정 또는 부정으로 분류할 수 있게 하는 시퀀스 분류 헤드를 가진 모델이 필요합니다. 따라서 `AutoModel` 클래스가 아닌 `TFAutoModelForSequenceClassification`을 사용할 것입니다. + +```python +from transformers import TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(inputs) +``` +{/if} + +출력 형태를 보면 차원이 훨씬 적은 것을 알 수 있습니다. 모델 헤드는 이전에 봤던 고차원 벡터를 입력으로 받아 2개의 값(레이블 당 하나)으로 이루어진 벡터를 출력합니다. + +```python +print(outputs.logits.shape) +``` + +{#if fw === 'pt'} +```python out +torch.Size([2, 2]) +``` +{:else} +```python out +(2, 2) +``` +{/if} + +우리는 2개의 문장과 2개의 레이블만 있기 때문에 모델로부터 얻은 출력 형태는 2 x 2입니다. + +## 출력 후처리[[postprocessing-the-output]] + +모델의 출력 값이 그 자체로 의미있는 것은 아닙니다. 한 번 보도록 합시다. + +```python +print(outputs.logits) +``` + +{#if fw === 'pt'} +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` +{:else} +```python out + +``` +{/if} + +모델은 첫 번째 문장에 대해 `[-1.5607, 1.6123]`으로 예측했고 두 번째 문장에 대해 `[ 4.1692, -3.3464]`으로 예측했습니다. 이 값들은 확률이 아니라 모델의 마지막 층에 의해 출력된 정규화되지 않은 점수인 *logits*입니다. 확률로 변환되기 위해 logits은 [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) 층을 거쳐야 합니다. 학습을 위한 손실 함수가 일반적으로 SoftMax와 같은 마지막 활성함수와 교차 엔트로피와 같은 실제 손실 함수를 모두 사용하기 때문에 모든 🤗 Transformers 모델의 출력은 logit입니다. + +{#if fw === 'pt'} +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` +{:else} +```py +import tensorflow as tf + +predictions = tf.math.softmax(outputs.logits, axis=-1) +print(predictions) +``` +{/if} + +{#if fw === 'pt'} +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` +{:else} +```python out +tf.Tensor( +[[4.01951671e-02 9.59804833e-01] + [9.9945587e-01 5.4418424e-04]], shape=(2, 2), dtype=float32) +``` +{/if} + +모델은 첫 번째 문장에 대해 `[0.0402, 0.9598]`로 예측했고 두 번째 모델에 대해 `[0.9995, 0.0005]`로 예측했습니다. 이 값들은 확실하게 확률값입니다. + +각 위치에 해당하는 레이블을 얻기 위해, 모델 config의 `id2label` 속성을 살펴봅시다. Config에 대한 더 많은 내용은 다음 섹션에서 진행됩니다. + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +모델의 예측 결과를 아래처럼 결론 지을 수 있습니다. + +- 첫 번째 문장: NEGATIVE: 0.0402, POSITIVE: 0.9598 +- 두 번째 문장: NEGATIVE: 0.9995, POSITIVE: 0.0005 + +파이프라인 세 단게-토크나이저를 이용한 전처리, 모델에 입력 넣어주기, 후처리-를 성공적으로 재현했습니다! 이제 각 단계별로 좀 더 깊게 알아보는 시간을 가져봅시다. + + + +✏️ **직접 해보세요!** 2개 이상의 문장을 골라 `sentiment-analysis` 파이프라인을 적용해보세요. 이 챕터에서 본 내용을 그대로 수행해보고 같은 결과가 나오는지 확인해보세요! + + From 148dc729b09487567fddd03c9ff083b972195e22 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Fri, 30 Dec 2022 16:39:37 +0900 Subject: [PATCH 03/12] Add Ko chapter2 3.mdx & 4.mdx --- chapters/ko/_toctree.yml | 13 ++ chapters/ko/chapter2/3.mdx | 227 +++++++++++++++++++++++++++++++++++ chapters/ko/chapter2/4.mdx | 239 +++++++++++++++++++++++++++++++++++++ 3 files changed, 479 insertions(+) create mode 100644 chapters/ko/chapter2/3.mdx create mode 100644 chapters/ko/chapter2/4.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index d1d952c7d..35ae7e604 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -33,6 +33,19 @@ title: 단원 소개 - local: chapter2/2 title: 파이프라인 내부 동작 과정 + - local: chapter2/3 + title: 모델 + - local: chapter2/4 + title: 토크나이저 + - local: chapter2/5 + title: 다중 시퀀스 처리하기 + - local: chapter2/6 + title: 한 번에 사용하기 + - local: chapter2/7 + title: 기본 사용 완료! + - local: chapter2/8 + title: 단원 마무리 퀴즈 + quiz: 1 - title: 8. 도움을 요청하는 방법 sections: diff --git a/chapters/ko/chapter2/3.mdx b/chapters/ko/chapter2/3.mdx new file mode 100644 index 000000000..1abd1a556 --- /dev/null +++ b/chapters/ko/chapter2/3.mdx @@ -0,0 +1,227 @@ + + +# Models[[models]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +{#if fw === 'pt'} +이 장에서는 모델을 생성하고 사용하는 방법에 대해 자세히 알아볼 것입니다. 체크포인트를 이용해 어떤 모델이든 편리하게 인스턴스화할 수 있는 `AutoModel` 클래스를 사용할 것입니다. + +`AutoModel` 클래스와 이와 관련된 모든 항목들은 라이브러리에서 이용할 수 있는 다양한 모델에 대한 간단한 래퍼입니다. 당신이 선택한 체크포인트로부터 자동으로 모델 구조를 추론하고 그 구조로 모델을 인스턴스화하기 때문에 영리한 래퍼라고 할 수 있습니다. + +{:else} +이 장에서는 모델을 생성하고 사용하는 방법에 대해 자세히 알아볼 것입니다. 체크포인트를 이용해 어떤 모델이든 편리하게 인스턴스화할 수 있는 `TFAutoModel` 클래스를 사용할 것입니다. + +`TFAutoModel` 클래스와 이와 관련된 모든 항목들은 라이브러리에서 이용할 수 있는 다양한 모델에 대한 간단한 래퍼입니다. 당신이 선택한 체크포인트로부터 자동으로 모델 구조를 추론하고 그 구조로 모델을 인스턴스화하기 때문에 영리한 래퍼라고 할 수 있습니다. + +{/if} + +하지만, 사용하고자 하는 모델의 구조를 알고 있다면 해당 구조를 직접 정의하는 클래스를 사용할 수도 있습니다. BERT 모델을 통해 동작 과정을 알아봅시다. + +## Transformer 모델 생성[[creating-a-transformer]] + +BERT 모델을 초기화하기 위해 가장 먼저 해야 할 일은 환경 설정 객체를 불러오는 것입니다. + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +# 환경 설정 생성 +config = BertConfig() + +# 환경 설정을 이용한 모델 생성 +model = BertModel(config) +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +# 환경 설정 생성 +config = BertConfig() + +# 환경 설정을 이용한 모델 생성 +model = TFBertModel(config) +``` +{/if} + +환경 설정은 모델 생성에 사용되는 많은 속성을 포함하고 있습니다. + +```py +print(config) +``` + +```python out +BertConfig { + [...] + "hidden_size": 768, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + [...] +} +``` + +이 속성들이 뭘 하는지는 보지 못했지만 몇 가지는 짚고 넘어가야 합니다. `hidden_size` 속성은 `hidden_states` 벡터의 크기를 결정하고, `num_hidden_layers` 속성은 Transformer 모델이 가지는 레이어 수를 결정합니다. + +### 다른 로딩 메서드[[different-loading-methods]] + +기본 환경 설정으로 모델을 생성하면 임의의 값으로 초기화됩니다. + +{#if fw === 'pt'} +```py +from transformers import BertConfig, BertModel + +config = BertConfig() +model = BertModel(config) + +# 모델은 임의의 값으로 초기화되었습니다! +``` +{:else} +```py +from transformers import BertConfig, TFBertModel + +config = BertConfig() +model = TFBertModel(config) + +# 모델은 임의의 값으로 초기화되었습니다! +``` +{/if} + +모델은 이 상태로 사용될 수 있지만 모델의 출력 결과를 보면 횡설수설할 것입니다. 먼저 모델은 학습되어야 합니다. 우리는 직면한 과제에 대해 처음부터 모델을 학습시킬 수 있지만, [제1단원](/course/chapter1)에서 봤듯이 이 과정은 긴 시간과 많은 데이터를 필요로 하며 환경에 무시할 수 없는 영향을 미칠 것입니다. 불필요하고 중복되는 노력을 피하기 위해서는 이미 학습된 모델을 재사용하고 공유할 수 있어야 합니다. + +학습된 Transformer 모델을 불러오는 것은 간단합니다 - `from_pretrained()` 메서드를 이용할 수 있습니다. + +{#if fw === 'pt'} +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +앞서 본 것처럼 `BertModel`을 동일한 `AutoModel` 클래스로 대체할 수 있습니다. 이렇게 하면 체크포인트에 구애받지 않는 코드를 구현할 수 있기 때문에 지금부터 `AutoModel` 클래스를 사용할 것입니다. 만약 특정 체크포인트에서 코드가 작동한다면 다른 체크포인트에서도 작동이 원활해야 합니다. 체크포인트가 유사한 태스크(예를 들면 감성분석 태스크)에 대해 학습되는 한 모델 구조가 다르더라도 적용됩니다. + +{:else} +```py +from transformers import TFBertModel + +model = TFBertModel.from_pretrained("bert-base-cased") +``` + +앞서 본 것처럼 `BertModel`을 동일한 `AutoModel` 클래스로 대체할 수 있습니다. 이렇게 하면 체크포인트에 구애받지 않는 코드를 구현할 수 있기 때문에 지금부터 `AutoModel` 클래스를 사용할 것입니다. 만약 특정 체크포인트에서 코드가 작동한다면 다른 체크포인트에서도 작동이 원활해야 합니다. 체크포인트가 유사한 태스크(예를 들면 감성분석 태스크)에 대해 학습되는 한 모델 구조가 다르더라도 적용됩니다. + +{/if} + +위의 샘플 코드에서 `BertConfig`를 사용하지 않고 `bert-base-cased` 식별자를 통해 사전학습 모델을 불러왔습니다. 이 체크포인트의 BERT 저자들이 직접 학습시킨 모델 체크포인트입니다. [모델 카드](https://huggingface.co/bert-base-cased)에서 더 자세한 내용을 확인할 수 있습니다. + +이제 이 모델은 체크포인트의 모든 가중치로 초기화됩니다. 학습된 태스크에 대한 추론 시 바로 사용할 수 있으며 새로운 태스크로 파인튜닝할 수 있습니다. 처음부터 직접 학습시키기보다 사전학습된 가중치를 사용하면 좋은 결과를 빨리 얻을 수 있습니다. + +가중치가 다운로드되고 기본 경로가 *~/.cache/huggingface/transformers*인 캐시 폴더에 저장되었기 때문에 이후 `from_pretrained()` 메서드 호출 시 가중치를 다시 다운로드 하지 않습니다. 캐시 폴더는 `HF_HOME` 환경 변수 설정을 통해 변경할 수 있습니다. + +BERT 구조와 호환되는 모델이라면, 모델 허브에 올라온 어떤 모델이라도 식별자로 사용될 수 있습니다. 이용 가능한 BERT 체크포인트 전체 리스트는 [이 곳](https://huggingface.co/models?filter=bert)에서 확인할 수 있습니다. + +### 저장 메서드[[saving-methods]] + +모델 저장은 모델을 불러오는 것만큼 간단합니다 - `from_pretrained()` 메서드와 유사한 `save_pretrained()` 메서드를 사용합니다. + +```py +model.save_pretrained("directory_on_my_computer") +``` + +이 메서드는 당신의 디스크에 두 가지 파일을 저장합니다. + +{#if fw === 'pt'} +``` +ls directory_on_my_computer + +config.json pytorch_model.bin +``` +{:else} +``` +ls directory_on_my_computer + +config.json tf_model.h5 +``` +{/if} + +*config.json* 파일을 자세히 들여다보면, 속성들이 모델 구조 생성에 중요하다는 것을 알게 될 것입니다. 또한, 이 파일에는 체크포인트가 시작된 위치와 체크포인트를 마지막으로 저장할 때 사용한 🤗 Transformers 버전과 같은 메타데이터가 포함되어 있습니다. + +{#if fw === 'pt'} +*pytorch_model.bin* 파일은 *state dictionary*로 알려져 있습니다. 이 파일은 모델의 모든 가중치를 저장하고 있으며 두 개의 파일이 서로 연결되어 있습니다. 모델 가중치는 모델의 파라미터이고 환경 설정은 모델 구조 파악에 중요한 역할을 합니다. + +{:else} +*tf_model.h5* 파일은 *state dictionary*로 알려져 있습니다. 이 파일은 모델의 모든 가중치를 저장하고 있으며 두 개의 파일은 서로 관련이 있습니다. 모델 가중치는 모델의 파라미터이고 환경 설정은 모델 구조 파악에 중요한 역할을 합니다. + +{/if} + +## Transformer 모델을 이용하여 추론하기[[using-a-transformer-model-for-inference]] + +모델을 불러오고 저장하는 방법을 알았기 때문에 이제 모델을 활용하여 몇 가지 예측을 해봅시다. Transformer 모델은 토크나이저가 생성한 숫자만 처리할 수 있는데 토크나이저에 대해 이야기하기 전 모델이 허락하는 입력 형태에 대해 알아보도록 하겠습니다. + +토크나이저는 적절한 프레임워크의 텐서로 입력을 보낼 수 있지만 동작 과정에 대한 이해를 돕기 위해 입력을 모델로 보내기 전 수행해야 할 작업을 간단히 살펴보겠습니다. + +몇 개의 시퀀스가 있다고 가정해봅시다. + +```py +sequences = ["Hello!", "Cool.", "Nice!"] +``` + +토크나이저는 이 시퀀스들을 *입력 ID*라고 하는 단어 인덱스로 변환합니다. 각 시퀀스는 이제 숫자 리스트입니다! 결과는 다음과 같이 출력됩니다. + +```py no-format +encoded_sequences = [ + [101, 7592, 999, 102], + [101, 4658, 1012, 102], + [101, 3835, 999, 102], +] +``` + +이 결과는 인코딩된 시퀀스들로, 리스트 안의 리스트 형태입니다. 텐서는 직사각형 형태(행렬을 생각해보세요)만 사용할 수 있습니다. 인코딩된 시퀀스 "배열"은 이미 직사각형 형태이기 때문에 이 배열을 텐서로 변환하는 것은 쉽습니다. + +{#if fw === 'pt'} +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` +{:else} +```py +import tensorflow as tf + +model_inputs = tf.constant(encoded_sequences) +``` +{/if} + +### 텐서를 모델 입력으로 사용하기[[using-the-tensors-as-inputs-to-the-model]] + +텐서를 모델과 합께 사용하는 것은 매우 간단합니다 - 입력과 함께 모델을 호출합니다. + +```py +output = model(model_inputs) +``` + +모델은 다양한 인자를 입력받지만 여기서는 입력 ID만 필요합니다. 다른 인자들의 역할이나 다른 인자들이 필요한 시점에 대한 설명을 듣기 전에, Transformer 모델이 이해할 수 있는 입력을 생성하는 토크나이저를 자세히 살펴봐야 합니다. diff --git a/chapters/ko/chapter2/4.mdx b/chapters/ko/chapter2/4.mdx new file mode 100644 index 000000000..402035594 --- /dev/null +++ b/chapters/ko/chapter2/4.mdx @@ -0,0 +1,239 @@ + + +# 토크나이저[[tokenizers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +토크나이저는 자연어처리 파이프라인의 핵심 요소 중 하나입니다. 토크나이저의 역할은 텍스트를 모델이 처리할 수 있는 데이터로 변환하는 것입니다. 모델은 숫자만 처리할 수 있기 때문에 토크나이저는 텍스트 입력을 수치형 데이터로 변환해야 합니다. 이 장에서는 토큰화 파이프라인에서 정확히 어떤 일이 일어나고 있는지 알아볼 것입니다. + +자연어처리 태스크에서 처리되는 데이터는 일반적으로 원시 텍스트입니다. 아래는 원시 텍스트의 예시입니다. + +``` +Jim Henson was a puppeteer +``` + +그러나 모델은 숫자만 처리할 수 있기 때문에 우리는 원시 텍스트를 숫자로 바꿀 방법을 찾아야 합니다. 그게 바로 토크나이저가 하는 일이며 이 문제를 해결할 수 있는 다양한 방법이 있습니다. 목표는 모델에 가장 적합하면서 간결한 표현을 찾는 것입니다. + +토큰화 알고리즘의 몇 가지 예시를 살펴보고 당신이 토큰화에 대해 가지는 궁금증에 대한 해답을 찾아봅시다. + +## 단어 기반[[word-based]] + + + +가장 먼저 떠오르는 토큰화 유형은 _단어 기반_입니다. 몇 가지 규칙만으로도 설정 및 사용이 매우 쉽고 종종 괜찮은 결과를 출력합니다. 예를 들어, 아래 보이는 사진에서 목표는 원시 텍스트를 단어로 나누고 단어 각각에 대한 수치 표현을 찾는 것입니다. + +
+ An example of word-based tokenization. + +
+ +텍스트를 나누는 방법은 다양합니다. 예를 들면 파이썬의 `split()` 함수를 이용해 공백 기준으로 텍스트를 나눌 수 있습니다. + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +구두점을 위한 규칙이 추가된 토크나이저도 있습니다. 이러한 종류의 토크나이저를 사용하면 꽤 큰 "단어 사전"을 얻을 수 있는데, 이 때 단어 사전은 우리가 가진 말뭉치(corpus) 내 존재하는 고유한 토큰 수에 의해 정의됩니다. + +각 단어에는 0부터 시작해서 단어 사전 크기까지의 ID가 할당됩니다. 모델은 각 단어를 구별하기 위해 이 ID들을 사용합니다. + +단어 기반 토크나이저로 언어를 완벽하게 처리하고 싶다면 언어의 각 단어에 대한 식별자가 있어야 하며, 이는 엄청난 양의 토큰을 생성할 것입니다. 예를 들어, 영어에 500,000개가 넘는 단어가 있다고 한다면, 각 단어에 입력 ID를 매핑시키기 위해 많은 ID를 추적해야 합니다. 게다가 "dog"와 같은 단어는 "dogs"처럼 다르게 표현되어 모델이 처음에 "dog"와 "dogs"가 유사하다는 것을 알 방법이 없을 것입니다. 모델은 두 단어를 관련이 없다고 인식할 것입니다. "run"과 "running" 같은 다른 유사한 단어에도 적용되는 것으로, 모델은 처음에 두 단어를 유사한 것으로 보지 않습니다. + +마지막으로, 단어 사전에 없는 단어를 표현하기 위한 커스텀 토큰이 필요합니다. "unknown" 토큰으로 알려진 이 토큰은 "[UNK]"이나 ""로 표현됩니다. 토크나이저가 unknown 토큰을 많이 만드는 것은 단어에 적합한 표현을 찾지 못해 정보를 잃어가고 있는 것이기 때문에 일반적으로 좋지 않은 신호입니다. 단어 사전을 생성할 때의 목표는 토크나이저가 단어를 unknown 토큰으로 가능한 한 적게 토큰화하는 것입니다. + +Unknown 토큰 수를 줄이기 위한 한 가지 방법은 한 단계 더 들어가 _문자 기반_ 토크나이저를 사용하는 것입니다. + +## 문자 기반[[character-based]] + + + +문자 기반 토크나이저는 텍스트를 단어가 아닌 문자 단위로 나눕니다. 이 방법은 두 가지 장점이 있습니다. + +- 단어 사전이 간결해진다. +- 모든 단어는 문자로 이루어졌기 때문에 out-of-vocabulary (unknown) 토큰의 수가 훨씬 적다. + +하지만 여기에서도 공백과 구두점에 대한 몇 가지 궁금증을 가질 수 있습니다. + +
+ An example of character-based tokenization. + +
+ +이 방법 또한 완벽하지 않습니다. 이제 표현은 단어가 아닌 문자에 기반을 두고 있기 때문에 누군가는 문자의 의미가 적다고 주장할 수 있습니다. 각각의 단어는 그 자체로 큰 의미가 있지만 문자는 그렇지 않습니다. 그러나 이 점은 다시 언어에 따라 달라집니다. 예를 들어, 중국어에서는 각 문자가 라틴어보다 더 많은 정보를 전달합니다. + +또 다른 고려 사항은 모델이 처리해야 하는 매우 많은 양의 토큰이 생기게 된다는 것입니다. 단어 기반 토크나이저에서 단어는 단 하나의 토큰인 반면, 문자로 변환하면 10개 이상의 토큰으로 쉽게 바뀔 수 있습니다. + +장점만을 최대한 활용하기 위해 두 가지 방법을 결합한 세 번째 기법인 *서브워드 토큰화*를 사용할 것입니다. + +## 서브워드 토큰화[[subword-tokenization]] + + + +서브워드 토큰화 알고리즘은 자주 사용되는 단어는 더 작은 서브워드로 나누면 안되지만, 희귀한 단어는 의미 있는 서브워드로 나눠야 한다는 규칙에 기반합니다. + +예를 들면 "annoyingly"는 흔하지 않은 단어로 여겨질 수 있고 "annoying"과 "ly"로 분해할 수 있을 것입니다. 둘 다 독립적인 서브워드로 자주 등장할 가능성이 있는 반면에 "annoyingly"는 "annoying"과 "ly"의 합성으로만 의미가 유지됩니다. + +다음 예시는 서브워드 토큰화 알고리즘이 "Let's do tokenization!"이라는 문장을 어떻게 토큰화하는지 보여줍니다. + +
+ A subword tokenization algorithm. + +
+ +서브워드는 많은 양의 의미론적 정보를 제공합니다. 위의 예시에서 "tokenization"은 의미론적인 정보를 갖는 두 개의 토큰 "token"과 "ization"으로 분할되었고 긴 단어를 두 단어만으로 표현할 수 있어 공간 효율적입니다. 이 방식을 통해 크기가 작은 단어 사전으로도 많은 토큰을 표현할 수 있고 unknown 토큰도 거의 없습니다. + +서브워드 토큰화를 이용한 접근법은 터키어와 같은 교착어에서 유용합니다. 서브워드를 함께 묶어 길고 복잡한 단어를 형성할 수 있습니다. + +### 더 알아보기![[and-more]] + +아니나 다를까 다양한 토큰화 기법이 존재하는데 몇 가지만 나열해보겠습니다. + +- GPT-2에서 사용된 Byte-level BPE +- BERT에서 사용된 WordPiece +- 여러 다언어 모델에서 사용되는 SentencePiece 또는 Unigram + +API를 알아보기 위해 토크나이저가 작동하는 과정에 대해 충분히 알고 있어야 합니다. + +## 불러오기 및 저장[[loading-and-saving]] + +토크나이저를 불러오고 저장하는 것은 모델에서 했던 것만큼 간단합니다. 사실, 모델과 동일하게 `from_pretrained()`과 `save_pretrained()` 두 메서드에 기반합니다. 이 메서드들은 토크나이저가 사용하는 알고리즘(모델의 *구조*와 약간 유사)과 단어 사전(모델 *가중치*와 약간 유사)을 불러오거나 저장합니다. + +BERT와 동일한 체크포인트로 학습된 BERT 토크나이저를 불러오는 것은 `BertTokenizer` 클래스를 사용하는 것만 제외하면 모델과 동일한 방식으로 수행됩니다. + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +{#if fw === 'pt'} +`AutoModel`과 마찬가지로 `AutoTokenizer` 클래스는 체크포인트 이름에 기반해 적절한 토크나이저 클래스를 가져오고 어떤 체크포인트와도 함께 직접 사용할 수 있습니다. + +{:else} +`TFAutoModel`과 마찬가지로 `AutoTokenizer` 클래스는 체크포인트 이름에 기반해 적절한 토크나이저 클래스를 가져오고 어떤 체크포인트와도 함께 직접 사용할 수 있습니다. +{/if} + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + + +이제 이전 섹션에서 본 것처럼 토크나이저를 사용할 수 있습니다. + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +토크나이저 저장은 모델 저장과 동일합니다. + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +위 출력 결과에서 `token_type_ids`는 [제3단원](/course/chapter3)에서 이야기할 것이고 `attention_mask` 키는 나중에 설명할 것입니다. 그 전에 먼저 `input_ids`가 어떻게 만들어지는지 알아봅시다. 이를 위해 토크나이저의 중간 메서드를 들여다봐야 합니다. + +## 인코딩[[encoding]] + + + +텍스트를 숫자로 바꾸는 것은 _인코딩_으로 알려져 있습니다. 인코딩은 토큰화, 토큰을 입력 ID로 바꾸는 두 단계에 걸쳐 수행됩니다. + +첫 번째 단계는 이미 봤던 것처럼 텍스트를 흔히 *토큰*이라고 부르는 단어(또는 단어의 일부, 구두점 기호 등)로 나누는 것입니다. There are multiple rules that can govern that process, which is why we need to instantiate the tokenizer using the name of the model, to make sure we use the same rules that were used when the model was pretrained. + +두 번째 단계는 생성된 토큰들을 숫자로 변환해 텐서로 만들고 모델로 넘겨주는 것입니다. 이 과정을 위해 토크나이저는 `from_pretrained()` 메서드로 인스턴스화할 때 다운로드한 *단어 사전*을 가지고 있습니다. 여기서도 모델이 사전학습될 때 사용한 것과 동일한 단어 사전을 사용해야 합니다. + +두 단계를 더 잘 이해하기 위해, 단계별로 알아봅시다. Note that we will use some methods that perform parts of the tokenization pipeline separately to show you the intermediate results of those steps, but in practice, you should call the tokenizer directly on your inputs (as shown in the section 2). + +### 토큰화[[tokenization]] + +토큰화 과정은 토크나이저의 `tokenize()` 메서드를 통해 작동합니다. + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +이 메서드의 출력 결과는 문자열 리스트이거나 토큰입니다.: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +이 토크나이저는 서브워드 토크나이저입니다. 단어 사전으로 표현할 수 있는 토큰을 얻을 때까지 단어를 분할합니다. `transformer`의 경우 `transform`과 `##er`로 나눠집니다. + +### 토큰에서 입력 ID까지[[from-tokens-to-input-ids]] + +토크나이저의 `convert_tokens_to_ids()` 메서드를 이용해 토큰을 입력 ID로 변환합니다. + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +적절한 프레임워크의 텐서로 변환되고 나면 이 출력 결과는 이전 장에서 본 것처럼 모델 입력으로 사용될 수 있습니다. + + + +✏️ **직접 해보세요!** 2장에서 사용한 입력 문장("I've been waiting for a HuggingFace course my whole life."과 "I hate this so much!")을 이용해 두 단계(토큰화와 입력 ID로의 변환)를 수행해보세요. 위에서 얻은 결과와 당신이 얻은 결과가 동일한지 확인해보세요! + + + +## 디코딩[[decoding]] + +단어 사전의 인덱스로부터 문자열을 얻고 싶기 때문에 *디코딩*은 인코딩과 반대로 진행됩니다. 아래처럼 `decode()` 메서드를 이용할 수 있습니다. + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +`decode` 메서드는 인덱스를 토큰으로 바꿀 뿐만 아니라, 읽기 좋은 문장을 만들기 위해 같은 단어의 일부인 토큰을 그룹화합니다. 이 과정은 새 텍스트(프롬프트에서 생성된 텍스트 또는 번역이나 요약과 같은 시퀀스 간 문제)를 예측하는 모델을 쓸 때 매우 유용합니다. + +이제 토크나이저가 수행하는 토큰화, ID로의 변환, ID를 다시 문자열로 변환하는 과정을 이해할 수 있어야 합니다. 그러나 이는 빙산의 일각입니다. 이어지는 섹션에서는 이 접근법의 한계를 알아보고, 이를 극복하는 방법을 알아볼 것입니다. From 1e60a630c7000fe76e9e6b78f7ccc2a289af67cf Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Fri, 30 Dec 2022 17:06:02 +0900 Subject: [PATCH 04/12] Modify Ko chapter2 3.mdx & 4.mdx --- chapters/ko/chapter2/3.mdx | 2 +- chapters/ko/chapter2/4.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/ko/chapter2/3.mdx b/chapters/ko/chapter2/3.mdx index 1abd1a556..d63a4fe92 100644 --- a/chapters/ko/chapter2/3.mdx +++ b/chapters/ko/chapter2/3.mdx @@ -1,6 +1,6 @@ -# Models[[models]] +# 모델[[models]] {#if fw === 'pt'} diff --git a/chapters/ko/chapter2/4.mdx b/chapters/ko/chapter2/4.mdx index 402035594..dd712c8ab 100644 --- a/chapters/ko/chapter2/4.mdx +++ b/chapters/ko/chapter2/4.mdx @@ -95,7 +95,7 @@ Unknown 토큰 수를 줄이기 위한 한 가지 방법은 한 단계 더 들 서브워드 토큰화 알고리즘은 자주 사용되는 단어는 더 작은 서브워드로 나누면 안되지만, 희귀한 단어는 의미 있는 서브워드로 나눠야 한다는 규칙에 기반합니다. -예를 들면 "annoyingly"는 흔하지 않은 단어로 여겨질 수 있고 "annoying"과 "ly"로 분해할 수 있을 것입니다. 둘 다 독립적인 서브워드로 자주 등장할 가능성이 있는 반면에 "annoyingly"는 "annoying"과 "ly"의 합성으로만 의미가 유지됩니다. +예를 들면 "annoyingly"는 흔하지 않은 단어로 여겨질 수 있고 "annoying"과 "ly"로 분해할 수 있을 것입니다. 둘다 독립적인 서브워드로 자주 등장할 가능성이 있는 반면에 "annoyingly"는 "annoying"과 "ly"의 합성으로만 의미가 유지됩니다. 다음 예시는 서브워드 토큰화 알고리즘이 "Let's do tokenization!"이라는 문장을 어떻게 토큰화하는지 보여줍니다. From a3dbc7abae78dc7c158d74a9884f094bddbaff71 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Fri, 30 Dec 2022 17:30:37 +0900 Subject: [PATCH 05/12] Modify Ko chapter2 3.mdx & 4.mdx --- chapters/ko/chapter2/4.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ko/chapter2/4.mdx b/chapters/ko/chapter2/4.mdx index dd712c8ab..1e562d9df 100644 --- a/chapters/ko/chapter2/4.mdx +++ b/chapters/ko/chapter2/4.mdx @@ -110,7 +110,7 @@ Unknown 토큰 수를 줄이기 위한 한 가지 방법은 한 단계 더 들 ### 더 알아보기![[and-more]] -아니나 다를까 다양한 토큰화 기법이 존재하는데 몇 가지만 나열해보겠습니다. +다양한 토큰화 기법이 존재하는데 몇 가지만 나열해보겠습니다. - GPT-2에서 사용된 Byte-level BPE - BERT에서 사용된 WordPiece From e578d88d57012c74c10a8414162cfc8b3fa6564d Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Fri, 30 Dec 2022 17:47:01 +0900 Subject: [PATCH 06/12] Modify Ko chapter2 3.mdx & 4.mdx --- chapters/ko/chapter2/3.mdx | 2 +- chapters/ko/chapter2/4.mdx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/ko/chapter2/3.mdx b/chapters/ko/chapter2/3.mdx index d63a4fe92..a6d1a9cc0 100644 --- a/chapters/ko/chapter2/3.mdx +++ b/chapters/ko/chapter2/3.mdx @@ -218,7 +218,7 @@ model_inputs = tf.constant(encoded_sequences) ### 텐서를 모델 입력으로 사용하기[[using-the-tensors-as-inputs-to-the-model]] -텐서를 모델과 합께 사용하는 것은 매우 간단합니다 - 입력과 함께 모델을 호출합니다. +텐서를 모델과 함께 사용하는 것은 매우 간단합니다 - 입력과 함께 모델을 호출합니다. ```py output = model(model_inputs) diff --git a/chapters/ko/chapter2/4.mdx b/chapters/ko/chapter2/4.mdx index 1e562d9df..0c42e38d5 100644 --- a/chapters/ko/chapter2/4.mdx +++ b/chapters/ko/chapter2/4.mdx @@ -35,7 +35,7 @@ Jim Henson was a puppeteer 토큰화 알고리즘의 몇 가지 예시를 살펴보고 당신이 토큰화에 대해 가지는 궁금증에 대한 해답을 찾아봅시다. -## 단어 기반[[word-based]] +## 단어 기반 토큰화[[word-based]] @@ -67,7 +67,7 @@ print(tokenized_text) Unknown 토큰 수를 줄이기 위한 한 가지 방법은 한 단계 더 들어가 _문자 기반_ 토크나이저를 사용하는 것입니다. -## 문자 기반[[character-based]] +## 문자 기반 토큰화[[character-based]] From 4e64466053b8ac58b94b1e8be73fa8dbf6717ef2 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Fri, 30 Dec 2022 20:07:32 +0900 Subject: [PATCH 07/12] Modify _toctree.yml --- chapters/ko/_toctree.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 35ae7e604..584d37066 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -37,15 +37,6 @@ title: 모델 - local: chapter2/4 title: 토크나이저 - - local: chapter2/5 - title: 다중 시퀀스 처리하기 - - local: chapter2/6 - title: 한 번에 사용하기 - - local: chapter2/7 - title: 기본 사용 완료! - - local: chapter2/8 - title: 단원 마무리 퀴즈 - quiz: 1 - title: 8. 도움을 요청하는 방법 sections: From b77ed312b0bbb983149263f17cd3fb0c6e4e982f Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Sat, 31 Dec 2022 15:01:34 +0900 Subject: [PATCH 08/12] Add Ko chapter2 5.mdx --- chapters/ko/_toctree.yml | 2 + chapters/ko/chapter2/5.mdx | 338 +++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 chapters/ko/chapter2/5.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 584d37066..2ac2fb136 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -37,6 +37,8 @@ title: 모델 - local: chapter2/4 title: 토크나이저 + - local: chapter2/5 + title: 다중 시퀀스 처리하기 - title: 8. 도움을 요청하는 방법 sections: diff --git a/chapters/ko/chapter2/5.mdx b/chapters/ko/chapter2/5.mdx new file mode 100644 index 000000000..bde0d809f --- /dev/null +++ b/chapters/ko/chapter2/5.mdx @@ -0,0 +1,338 @@ + + +# 다중 시퀀스 처리하기[[handling-multiple-sequences]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +{#if fw === 'pt'} + +{:else} + +{/if} + +이전 섹션에서, 우리는 가장 간단한 사용 예시를 확인했습니다. 길이가 짧은 단일 시퀀스에 대한 추론을 수행했습니다. 그러나 이미 몇 가지 궁금증이 생깁니다. + +- 여러 개의 시퀀스는 어떻게 처리하나요? +- *서로 다른 길이*를 갖는 다중 시퀀스를 어떻게 처리하나요? +- 단어 사전의 인덱스가 모델이 잘 작동하게 하는 유일한 입력인가요? +- 엄청 긴 시퀀스를 처리하는 방법이 있나요? + +이러한 질문들이 제기하는 문제에 대해 알아보고, 🤗 Transformers API를 이용해 이 문제들을 어떻게 해결할 수 있는지 살펴봅시다. + +## 모델은 배치 입력을 기대합니다[[models-expect-a-batch-of-inputs]] + +우리는 이전 실습에서 시퀀스가 숫자 리스트로 어떻게 바뀌는지 확인했습니다. 이 숫자 리스트를 텐서로 바꾸고 모델로 보내봅시다.: + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = torch.tensor(ids) +# 이 코드는 실행되지 않을 것입니다. +model(input_ids) +``` + +```python out +IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = tf.constant(ids) +# 이 코드는 실행되지 않을 것입니다. +model(input_ids) +``` + +```py out +InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape] +``` +{/if} + +이런! 2장의 파이프라인을 순서대로 따라했는데 왜 실행되지 않는 걸까요? + +🤗 Transformers 모델은 기본적으로 여러 개의 문장을 입력으로 받는데 하나의 시퀀스만을 모델에 넘겨줬기 때문에 발생하는 문제입니다. 여기서 우리는 토크나이저를 `시퀀스`에 적용했을 때 뒤에서 일어나고 있는 모든 일을 수행하려고 했습니다. 하지만 자세히 보면, 토크나이저가 입력 ID 리스트를 텐서로 바꿨을 뿐만 아니라 차원도 추가한 것을 알 수 있습니다. + +{#if fw === 'pt'} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="pt") +print(tokenized_inputs["input_ids"]) +``` + +```python out +tensor([[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, + 2607, 2026, 2878, 2166, 1012, 102]]) +``` +{:else} +```py +tokenized_inputs = tokenizer(sequence, return_tensors="tf") +print(tokenized_inputs["input_ids"]) +``` + +```py out + +``` +{/if} + +새로운 차원을 추가해서 다시 시도해봅시다. + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = torch.tensor([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = tf.constant([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` +{/if} + +입력 ID와 결과 로짓을 출력한 결과입니다. + +{#if fw === 'pt'} +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` +{:else} +```py out +Input IDs: tf.Tensor( +[[ 1045 1005 2310 2042 3403 2005 1037 17662 12172 2607 2026 2878 + 2166 1012]], shape=(1, 14), dtype=int32) +Logits: tf.Tensor([[-2.7276208 2.8789377]], shape=(1, 2), dtype=float32) +``` +{/if} + +*배치*는 한 번에 여러 개의 문장을 모델로 보내는 방법입니다. 만약 단 한 개의 문장을 가지고 있다면 한 문장을 위한 배치를 만들 수 있습니다. + +``` +batched_ids = [ids, ids] +``` + +동일한 문장 2개로 만든 배치입니다! + + + +✏️ **직접 해보세요!** 이 `batched_ids` 리스트를 텐서로 변환하고 모델로 전달해보세요. 이전에 얻은 로짓과 동일한 결과를 얻는지 확인해보세요. (개수는 두 개여야 합니다!) + + + +배치는 여러 개의 문장을 모델로 넘겼을 때도 모델이 작동하게 합니다. 다중 시퀀스를 사용하는 것은 단일 시퀀스로 배치를 만드는 것만큼 간단합니다. 하지만 두 번째 문제가 있습니다. 두 개 이상의 문장을 배치로 만드려고 할 때, 그 문장들은 아마 다른 길이를 가지고 있을 것입니다. 이전에 텐서를 다뤄본 사람이라면, 텐서의 형태가 직사각형이어야 한다는 것을 알고 있습니다. 문장 길이가 다르면 입력 ID 리스트를 텐서로 바로 변환할 수 없습니다. 이 문제를 해결하기 위해, 일반적으로 입력에 *패드*를 추가합니다. + +## 입력에 패딩 추가하기[[padding-the-inputs]] + +아래 보이는 리스트는 텐서로 변환될 수 없습니다. + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +*패딩*을 이용해 텐서가 직사각형 형태를 가질 수 있게 하면 이 문제를 해결할 수 있습니다. 패딩은 길이가 짧은 문장에 *패딩 토큰*이라고 불리는 특별한 토큰을 추가함으로써 모든 문장이 같은 길이를 갖게 합니다. 10개의 단어로 이루어진 문장 10개와 20개의 단어로 이루어진 문장 1개를 가지고 있다고 가정한다면, 패딩은 모든 문장이 20개의 단어를 갖게 하는 역할을 합니다. 우리가 사용하는 예시에서 결과 텐서는 다음과 같습니다. + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +패딩 토큰의 ID는 `tokenizer.pad_token_id` 를 통해 확인할 수 있습니다. 이걸 사용해서 두 문장을 각각 모델로 보내고 하나의 배치로 만들어 봅시다. + +{#if fw === 'pt'} +```py no-format +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence1_ids = [[200, 200, 200]] +sequence2_ids = [[200, 200]] +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +print(model(torch.tensor(sequence1_ids)).logits) +print(model(torch.tensor(sequence2_ids)).logits) +print(model(torch.tensor(batched_ids)).logits) +``` + +```python out +tensor([[ 1.5694, -1.3895]], grad_fn=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` +{:else} +```py no-format +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence1_ids = [[200, 200, 200]] +sequence2_ids = [[200, 200]] +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +print(model(tf.constant(sequence1_ids)).logits) +print(model(tf.constant(sequence2_ids)).logits) +print(model(tf.constant(batched_ids)).logits) +``` + +```py out +tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32) +tf.Tensor([[ 0.5803005 -0.41252428]], shape=(1, 2), dtype=float32) +tf.Tensor( +[[ 1.5693681 -1.3894582] + [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32) +``` +{/if} + +배치되어 있는 예측 결과의 로짓이 뭔가 잘못된 것 같습니다. 두 번째 행은 두 번째 문장의 로짓과 값이 같아야 하는데 완전히 다른 값을 얻었습니다! + +이것은 Transformer 모델의 핵심 기능이 각 토큰을 *문맥화*하는 어텐션 레이어이기 때문입니다. 어텐션 레이어는 시퀀스 내 모든 토큰을 처리하기 때문에 패딩 토큰도 고려합니다. 서로 다른 길이를 가지는 문장 각각을 모델로 전달했을 때와 패딩이 추가되어 길이가 같아진 문장들을 배치로 전달했을 때의 결과가 같기 위해서는 이 어텐션 레이어들에게 패딩 토큰을 무시하라고 알려주어야 합니다. 이 역할을 어텐션 마스크가 수행합니다. + +## 어텐션 마스크[[attention-masks]] + +*어텐션 마스크*는 입력 ID 텐서와 같은 크기를 같는 텐서로, 0과 1로 이루어져 있습니다. 1은 해당 토큰을 주의 깊게 봐야한다는 것을 의미하고 0은 해당 토큰을 신경 쓰지 않아도 된다는 의미입니다. (다시 말해, 0에 해당하는 토큰은 모델의 어텐션 레이어에서 무시되어야 한다는 뜻입니다.) + +어텐션 마스크와 함께 이전 예시를 완성해봅시다. + +{#if fw === 'pt'} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask)) +print(outputs.logits) +``` + +```python out +tensor([[ 1.5694, -1.3895], + [ 0.5803, -0.4125]], grad_fn=) +``` +{:else} +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask)) +print(outputs.logits) +``` + +```py out +tf.Tensor( +[[ 1.5693681 -1.3894582 ] + [ 0.5803021 -0.41252586]], shape=(2, 2), dtype=float32) +``` +{/if} + +이제 배치 내 두 번째 문장과 동일한 로짓을 얻었습니다. + +두 번째 문장의 어텐션 마스크에서 마지막 값인 0은 패딩 ID라는 것을 잊지 마세요. + + + +✏️ **직접 해보세요!** 2장에서 사용한 두 개의 문장("I've been waiting for a HuggingFace course my whole life." and "I hate this so much!")을 이용해 직접 토큰화를 적용해보세요. 토큰화 결과를 모델에 넘기고 2장에서 얻은 것과 동일한 로짓을 얻었는지 확인해보세요. 이제 Now batch them together using the padding token, then create the proper attention mask. Check that you obtain the same results when going through the model! + + + +## 길이가 긴 시퀀스[[longer-sequences]] + +Transformer 모델을 사용할 때, 모델에 넘겨줄 수 있는 시퀀스 길이에 제한이 있습니다. 대부분의 모델은 최대 512개나 1024개의 토큰으로 이루어진 시퀀스를 처리할 수 있으며 더 긴 길이의 시퀀스를 처리해달라는 요청을 받으면 작동하지 않습니다. 이 문제에 대한 해결 방법은 2가지가 있습니다. + +- 긴 시퀀스를 처리할 수 있는 모델을 사용하세요. +- 시퀀스 길이를 최대 길이에 맞게 잘라내세요. + +모델별로 지원하는 시퀀스 길이는 다르고 몇 개의 특별한 모델은 엄청나게 긴 시퀀스를 처리할 수 있습니다. [Longformer](https://huggingface.co/transformers/model_doc/longformer.html) 가 그 중 하나이며, [LED](https://huggingface.co/transformers/model_doc/led.html)도 해당합니다. 만약 매우 긴 길이의 시퀀스를 다뤄야 하는 태스크를 진행하고 있다면, 두 모델을 살펴보세요. + +그렇지 않으면 `max_sequence_length` 파라미터를 이용해 시퀀스 길이를 잘라내는 것이 좋습니다. + +```py +sequence = sequence[:max_sequence_length] +``` From 0b440877652a3c24fb0802d8ebbeb5a74495e7a6 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Sat, 31 Dec 2022 15:17:47 +0900 Subject: [PATCH 09/12] Modify Ko chapter2 4.mdx --- chapters/ko/chapter2/4.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chapters/ko/chapter2/4.mdx b/chapters/ko/chapter2/4.mdx index 0c42e38d5..fed8fc9cf 100644 --- a/chapters/ko/chapter2/4.mdx +++ b/chapters/ko/chapter2/4.mdx @@ -23,6 +23,7 @@ {/if} + 토크나이저는 자연어처리 파이프라인의 핵심 요소 중 하나입니다. 토크나이저의 역할은 텍스트를 모델이 처리할 수 있는 데이터로 변환하는 것입니다. 모델은 숫자만 처리할 수 있기 때문에 토크나이저는 텍스트 입력을 수치형 데이터로 변환해야 합니다. 이 장에서는 토큰화 파이프라인에서 정확히 어떤 일이 일어나고 있는지 알아볼 것입니다. 자연어처리 태스크에서 처리되는 데이터는 일반적으로 원시 텍스트입니다. 아래는 원시 텍스트의 예시입니다. @@ -135,6 +136,7 @@ tokenizer = BertTokenizer.from_pretrained("bert-base-cased") {:else} `TFAutoModel`과 마찬가지로 `AutoTokenizer` 클래스는 체크포인트 이름에 기반해 적절한 토크나이저 클래스를 가져오고 어떤 체크포인트와도 함께 직접 사용할 수 있습니다. + {/if} ```py From 7d2488c7dca24c2778ea7427a79fd8b57c6b9351 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Sat, 31 Dec 2022 15:33:48 +0900 Subject: [PATCH 10/12] Add doc-builder step --- chapters/ko/_toctree.yml | 2 +- chapters/ko/chapter2/5.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 2ac2fb136..dfdbaa712 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -38,7 +38,7 @@ - local: chapter2/4 title: 토크나이저 - local: chapter2/5 - title: 다중 시퀀스 처리하기 + title: 다중 시퀀스 처리 - title: 8. 도움을 요청하는 방법 sections: diff --git a/chapters/ko/chapter2/5.mdx b/chapters/ko/chapter2/5.mdx index bde0d809f..faf950b4f 100644 --- a/chapters/ko/chapter2/5.mdx +++ b/chapters/ko/chapter2/5.mdx @@ -1,6 +1,6 @@ -# 다중 시퀀스 처리하기[[handling-multiple-sequences]] +# 다중 시퀀스 처리[[handling-multiple-sequences]] {#if fw === 'pt'} From a5ebb298efa2896117bdc61e74f4860e0bdc3b99 Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Sun, 1 Jan 2023 22:17:35 +0900 Subject: [PATCH 11/12] Add Ko chapter2 6~8.mdx & Modify Ko chapter2 2.mdx typo --- chapters/ko/_toctree.yml | 7 + chapters/ko/chapter2/2.mdx | 2 +- chapters/ko/chapter2/6.mdx | 164 ++++++++++++++++++++ chapters/ko/chapter2/7.mdx | 18 +++ chapters/ko/chapter2/8.mdx | 310 +++++++++++++++++++++++++++++++++++++ 5 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 chapters/ko/chapter2/6.mdx create mode 100644 chapters/ko/chapter2/7.mdx create mode 100644 chapters/ko/chapter2/8.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index dfdbaa712..274f3cf61 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -39,6 +39,13 @@ title: 토크나이저 - local: chapter2/5 title: 다중 시퀀스 처리 + - local: chapter2/6 + title: 한 번에 실행하기 + - local: chapter2/7 + title: 기본 사용 완료! + - local: chapter2/8 + title: 단원 마무리 퀴즈 + quiz: 2 - title: 8. 도움을 요청하는 방법 sections: diff --git a/chapters/ko/chapter2/2.mdx b/chapters/ko/chapter2/2.mdx index 718ea976d..3f246f672 100644 --- a/chapters/ko/chapter2/2.mdx +++ b/chapters/ko/chapter2/2.mdx @@ -344,7 +344,7 @@ model.config.id2label - 첫 번째 문장: NEGATIVE: 0.0402, POSITIVE: 0.9598 - 두 번째 문장: NEGATIVE: 0.9995, POSITIVE: 0.0005 -파이프라인 세 단게-토크나이저를 이용한 전처리, 모델에 입력 넣어주기, 후처리-를 성공적으로 재현했습니다! 이제 각 단계별로 좀 더 깊게 알아보는 시간을 가져봅시다. +파이프라인 세 단계-토크나이저를 이용한 전처리, 모델에 입력 넣어주기, 후처리-를 성공적으로 재현했습니다! 이제 각 단계별로 좀 더 깊게 알아보는 시간을 가져봅시다. diff --git a/chapters/ko/chapter2/6.mdx b/chapters/ko/chapter2/6.mdx new file mode 100644 index 000000000..e564a39fa --- /dev/null +++ b/chapters/ko/chapter2/6.mdx @@ -0,0 +1,164 @@ + + +# 한 번에 실행하기[[putting-it-all-together]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +지난 섹션에서는 대부분의 과정을 하나씩 수행해왔습니다. 토크나이저의 작동 방식을 살펴보고 토큰화, 입력 ID로의 변환, 패딩, 잘라내기 그리고 어텐션 마스크에 대해 알아봤습니다. + +하지만 2장에서 보았듯이 우리는 🤗 Transformers API의 고수준 함수로 이 모든 것을 처리할 수 있습니다. 문장을 이용해 `tokenizer`를 호출하면 모델로 넘겨줄 수 있는 입력을 얻게 됩니다. + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +이제 `model_inputs` 변수는 모델이 잘 동작하기 위해 필요한 모든 것을 가지고 있습니다. DistilBERT는 어텐션 마스크뿐만 아니라 입력 ID도 포함합니다. 추가적인 입력을 받는 다른 모델들도 `tokenizer` 객체에 의해 생기는 결과물을 가지고 있습니다. + +아래의 예시를 보면 tokenizer 메서드는 매우 강력합니다. 먼저, 이 메서드는 단일 시퀀스를 토큰화할 수 있습니다. + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +또한 API의 변경 없이 여러 개의 시퀀스를 한 번에 처리할 수 있습니다. + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +model_inputs = tokenizer(sequences) +``` + +원하는대로 패딩을 추가할 수 있습니다. + +```py +# 가장 긴 시퀀스의 길이에 맞게 패딩을 추가합니다. +model_inputs = tokenizer(sequences, padding="longest") + +# 모델이 지원하는 최대 시퀀스 길이에 맞게 패딩을 추가합니다. +# (BERT나 DistilBERT의 최대 길이는 512) +model_inputs = tokenizer(sequences, padding="max_length") + +# 지정한 길이에 맞게 패딩을 추가합니다. +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +시퀀스 길이를 잘라낼 수도 있습니다. + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# 모델이 지원하는 최대 시퀀스 길이에 맞게 시퀀스 길이를 잘라냅니다. +# (BERT나 DistilBERT의 최대 길이는 512) +model_inputs = tokenizer(sequences, truncation=True) + +# 지정한 최대 길이에 맞게 시퀀스 길이를 잘라냅니다. +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +`tokenizer` 객체를 이용해 결과를 특정 프레임워크의 텐서로 변환할 수 있으며, 이는 모델에 바로 보내질 수 있습니다. 예를 들어 아래 코드 예시에서 토크나이저가 프레임워크에 따라 다른 텐서를 반환하게 했습니다 - `"pt"`는 PyTorch 텐서를 반환하고 `"tf"`는 TensorFlow 텐서를 반환하며, `"np"`는 NumPy 배열을 반환합니다. + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# PyTorch 텐서를 반환합니다. +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# TensorFlow 텐서를 반환합니다. +model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") + +# NumPy 배열을 반환합니다. +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## 특수 토큰[[special-tokens]] + +토크나이저가 반환한 입력 ID를 자세히 살펴보면 이전에 봤던 결과와 조금 다르다는 것을 알 수 있습니다. + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + +시작과 끝에 추가된 토큰 ID가 있습니다. 두 시퀀스의 ID가 무엇을 의미하는지 확인하기 위해 디코딩해보겠습니다. + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +토크나이저는 문장이 시작할 떄 `[CLS]`라는 특별한 토큰을 붙이고, 끝날 때는 `[SEP]` 토큰을 붙입니다. 이런 특별한 토큰을 사용하는 이유는 모델이 사전학습될 때 이 토큰들을 사용했기 때문에 추론 시 동일한 결과를 얻기 위함입니다. 참고로 몇몇 모델은 특수 토큰을 추가하지 않아도 되고, 어떤 모델은 다른 토큰을 추가하기도 합니다. 또한, 이러한 특수 토큰을 시작 부분이나 끝 부분에만 추가하는 모델도 있습니다. 어떤 경우든 토크나이저는 토크나이저로 어떤 내용이 들어올지 알고 있고 이 내용을 처리해줄 것입니다. + +## 마무리: 토크나이저에서 모델까지[[wrapping-up-from-tokenizer-to-model]] + +지금까지 `tokenizer` 객체가 텍스트에 적용될 때 거치는 개별적인 단계를 모두 살펴보았습니다. 이제 마지막으로 이 객체가 패딩을 이용해 여러 시퀀스를 어떻게 처리하는지, 잘라내기를 통해 매우 긴 문장을 어떻게 처리하는지, 주요 API에 따라 다양한 텐서를 다루는 법을 알아봅시다. + +{#if fw === 'pt'} +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` +{:else} +```py +import tensorflow as tf +from transformers import AutoTokenizer, TFAutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") +output = model(**tokens) +``` +{/if} diff --git a/chapters/ko/chapter2/7.mdx b/chapters/ko/chapter2/7.mdx new file mode 100644 index 000000000..8c6b6349d --- /dev/null +++ b/chapters/ko/chapter2/7.mdx @@ -0,0 +1,18 @@ +# 기본 사용 완료![[basic-usage-completed]] + + + +여기까지 오느라 수고하셨습니다! 이 단원에서 배운 것을 되돌아봅시다. + +- Transformer 모델의 기본 구성 요소에 대해 배웠습니다. +- 토큰화 파이프라인의 구성 요소에 대해 배웠습니다. +- Transformer 모델을 사용하는 방법을 알아보았습니다. +- 토크나이저를 이용해 텍스트를 모델이 이해할 수 있는 텐서로 변환하는 방법을 배웠습니다. +- 원시 텍스트에서 예측 결과를 얻기 위해 토크나이저와 모델을 함께 사용하는 법을 배웠습니다. +- 입력 ID의 한계와 어텐션 마스크에 대해 배웠습니다. +- 다양하고 설정 가능한 토크나이저 메서드를 사용해보았습니다. + +이제부터는 🤗 Transformers 문서 안에서 자유롭게 항해할 수 있어야 합니다. 단어는 익숙하게 들릴 것이고, 사용법을 익히는 데에 이미 충분한 시간을 들였습니다. diff --git a/chapters/ko/chapter2/8.mdx b/chapters/ko/chapter2/8.mdx new file mode 100644 index 000000000..ddc6f4558 --- /dev/null +++ b/chapters/ko/chapter2/8.mdx @@ -0,0 +1,310 @@ + + + + +# 단원 마무리 퀴즈[[end-of-chapter-quiz]] + + + +### 1. 언어 모델링 파이프라인은 어떤 순서로 진행될까요? + + + +### 2. 기본 Transformer 모델에 의해 만들어지는 텐서의 출력은 몇 차원이며, 각 텐서가 무엇을 의미하나요? + + + +### 3. 서브워드 토큰화 예시에 해당하는 것은 무엇인가요? + + + +### 4. 모델 헤드가 무엇인가요? + + + +{#if fw === 'pt'} +### 5. AutoModel이 무엇인가요? + +AutoTrain과 헷갈린 게 아닐까요?" + }, + { + text: "체크포인트에 기반하여 적합한 구조를 반환하는 객체입니다.", + explain: "정확합니다. AutoModel은 적절한 모델 구조를 초기화할 때 필요한 체크포인트만을 필요로 합니다.", + correct: true + }, + { + text: "적합한 가중치를 불러오기 위해 입력에 사용된 언어를 자동으로 감지하는 모델입니다.", + explain: "오답입니다. 몇몇 체크포인트와 모델은 다양한 언어를 처리할 수 있지만, 언어에 따라 체크포인트를 자동으로 선택할 수 있도록 내장된 도구는 없습니다. 태스크에 가장 적합한 체크포인트를 찾으려면 모델 허브에 가보세요!" + } + ]} +/> + +{:else} +### 5. TFAutoModel이 무엇인가요? + +AutoTrain과 헷갈린 게 아닐까요?" + }, + { + text: "체크포인트에 기반하여 적합한 구조를 반환하는 객체입니다.", + explain: "정확합니다. AutoModel은 적절한 모델 구조를 초기화할 때 필요한 체크포인트만을 필요로 합니다.", + correct: true + }, + { + text: "적합한 가중치를 불러오기 위해 입력에 사용된 언어를 자동으로 감지하는 모델입니다.", + explain: "오답입니다. 몇몇 체크포인트와 모델은 다양한 언어를 처리할 수 있지만, 언어에 따라 체크포인트를 자동으로 선택할 수 있도록 내장된 도구는 없습니다. 태스크에 가장 적합한 체크포인트를 찾으려면 모델 허브에 가보세요!" + } + ]} +/> + +{/if} + +### 6. 길이가 다른 시퀀스를 하나의 배치로 만들 때 신경써야 할 부분은 무엇일까요? + + + +### 7. 시퀀스 분류 모델의 로짓 출력 결과에 소프트맥스 함수를 적용하는 핵심적인 이유는 무엇일까요? + + + +### 8. 토크나이저 API의 가장 핵심적인 메서드는 무엇일까요? + +encode입니다.", + explain: "틀렸습니다! encode 메서드가 토크나이저에는 있지만, 모델에는 없습니다." + }, + { + text: "토크나이저 객체를 바로 호출하는 메서드입니다.", + explain: "정확합니다! 토크나이저의 __call__ 메서드는 거의 모든 것을 처리할 수 있는 강력한 메서드입니다. 이 메서드는 또한 모델로부터 예측 결과를 탐색하는 데에 사용되기도 합니다.", + correct: true + }, + { + text: "pad 메서드입니다.", + explain: "틀렸습니다! 패딩은 매우 유용한 방법이지만, 토크나이저 API가 제공하는 기능 중 하나일 뿐입니다." + }, + { + text: "tokenize 메서드입니다.", + explain: "tokenize 메서드가 유용한 것은 틀림없지만, 토크나이저 API의 핵심은 아닙니다." + } + ]} +/> + +### 9. 아래 코드 예시에서 `result` 변수가 포함하고 있는 것은 무엇일까요? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +__call__ 또는 convert_tokens_to_ids 입니다!" + }, + { + text: "모든 토큰을 포함하고 있는 문자열입니다.", + explain: "문자열을 각각의 토큰으로 나누는 것이 목표기 때문에 정확한 정답은 아닙니다." + } + ]} +/> + +{#if fw === 'pt'} +### 10. 아래 코드에서 잘못된 부분이 있을까요? + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{:else} +### 10. 아래 코드에서 잘못된 부분이 있을까요? + +```py +from transformers import AutoTokenizer, TFAutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = TFAutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + + +{/if} From 518068c3454956cc7a04d0434212bcff35c51f2e Mon Sep 17 00:00:00 2001 From: Bo geum Kim Date: Wed, 4 Jan 2023 15:48:16 +0900 Subject: [PATCH 12/12] Modify Ko _toctree.yml --- chapters/ko/_toctree.yml | 7 ++ chapters/ko/chapter2/3.mdx | 227 ------------------------------------- 2 files changed, 7 insertions(+), 227 deletions(-) delete mode 100644 chapters/ko/chapter2/3.mdx diff --git a/chapters/ko/_toctree.yml b/chapters/ko/_toctree.yml index 274f3cf61..b85c72a71 100644 --- a/chapters/ko/_toctree.yml +++ b/chapters/ko/_toctree.yml @@ -47,6 +47,13 @@ title: 단원 마무리 퀴즈 quiz: 2 +- title: 5. 🤗 Datasets 라이브러리 + sections: + - local: chapter5/1 + title: 단원 소개 + - local: chapter5/2 + title: 필요한 데이터셋이 Hub에 없다면 어떻게 할까요? + - title: 8. 도움을 요청하는 방법 sections: - local: chapter8/1 diff --git a/chapters/ko/chapter2/3.mdx b/chapters/ko/chapter2/3.mdx deleted file mode 100644 index a6d1a9cc0..000000000 --- a/chapters/ko/chapter2/3.mdx +++ /dev/null @@ -1,227 +0,0 @@ - - -# 모델[[models]] - -{#if fw === 'pt'} - - - -{:else} - - - -{/if} - -{#if fw === 'pt'} - -{:else} - -{/if} - -{#if fw === 'pt'} -이 장에서는 모델을 생성하고 사용하는 방법에 대해 자세히 알아볼 것입니다. 체크포인트를 이용해 어떤 모델이든 편리하게 인스턴스화할 수 있는 `AutoModel` 클래스를 사용할 것입니다. - -`AutoModel` 클래스와 이와 관련된 모든 항목들은 라이브러리에서 이용할 수 있는 다양한 모델에 대한 간단한 래퍼입니다. 당신이 선택한 체크포인트로부터 자동으로 모델 구조를 추론하고 그 구조로 모델을 인스턴스화하기 때문에 영리한 래퍼라고 할 수 있습니다. - -{:else} -이 장에서는 모델을 생성하고 사용하는 방법에 대해 자세히 알아볼 것입니다. 체크포인트를 이용해 어떤 모델이든 편리하게 인스턴스화할 수 있는 `TFAutoModel` 클래스를 사용할 것입니다. - -`TFAutoModel` 클래스와 이와 관련된 모든 항목들은 라이브러리에서 이용할 수 있는 다양한 모델에 대한 간단한 래퍼입니다. 당신이 선택한 체크포인트로부터 자동으로 모델 구조를 추론하고 그 구조로 모델을 인스턴스화하기 때문에 영리한 래퍼라고 할 수 있습니다. - -{/if} - -하지만, 사용하고자 하는 모델의 구조를 알고 있다면 해당 구조를 직접 정의하는 클래스를 사용할 수도 있습니다. BERT 모델을 통해 동작 과정을 알아봅시다. - -## Transformer 모델 생성[[creating-a-transformer]] - -BERT 모델을 초기화하기 위해 가장 먼저 해야 할 일은 환경 설정 객체를 불러오는 것입니다. - -{#if fw === 'pt'} -```py -from transformers import BertConfig, BertModel - -# 환경 설정 생성 -config = BertConfig() - -# 환경 설정을 이용한 모델 생성 -model = BertModel(config) -``` -{:else} -```py -from transformers import BertConfig, TFBertModel - -# 환경 설정 생성 -config = BertConfig() - -# 환경 설정을 이용한 모델 생성 -model = TFBertModel(config) -``` -{/if} - -환경 설정은 모델 생성에 사용되는 많은 속성을 포함하고 있습니다. - -```py -print(config) -``` - -```python out -BertConfig { - [...] - "hidden_size": 768, - "intermediate_size": 3072, - "max_position_embeddings": 512, - "num_attention_heads": 12, - "num_hidden_layers": 12, - [...] -} -``` - -이 속성들이 뭘 하는지는 보지 못했지만 몇 가지는 짚고 넘어가야 합니다. `hidden_size` 속성은 `hidden_states` 벡터의 크기를 결정하고, `num_hidden_layers` 속성은 Transformer 모델이 가지는 레이어 수를 결정합니다. - -### 다른 로딩 메서드[[different-loading-methods]] - -기본 환경 설정으로 모델을 생성하면 임의의 값으로 초기화됩니다. - -{#if fw === 'pt'} -```py -from transformers import BertConfig, BertModel - -config = BertConfig() -model = BertModel(config) - -# 모델은 임의의 값으로 초기화되었습니다! -``` -{:else} -```py -from transformers import BertConfig, TFBertModel - -config = BertConfig() -model = TFBertModel(config) - -# 모델은 임의의 값으로 초기화되었습니다! -``` -{/if} - -모델은 이 상태로 사용될 수 있지만 모델의 출력 결과를 보면 횡설수설할 것입니다. 먼저 모델은 학습되어야 합니다. 우리는 직면한 과제에 대해 처음부터 모델을 학습시킬 수 있지만, [제1단원](/course/chapter1)에서 봤듯이 이 과정은 긴 시간과 많은 데이터를 필요로 하며 환경에 무시할 수 없는 영향을 미칠 것입니다. 불필요하고 중복되는 노력을 피하기 위해서는 이미 학습된 모델을 재사용하고 공유할 수 있어야 합니다. - -학습된 Transformer 모델을 불러오는 것은 간단합니다 - `from_pretrained()` 메서드를 이용할 수 있습니다. - -{#if fw === 'pt'} -```py -from transformers import BertModel - -model = BertModel.from_pretrained("bert-base-cased") -``` - -앞서 본 것처럼 `BertModel`을 동일한 `AutoModel` 클래스로 대체할 수 있습니다. 이렇게 하면 체크포인트에 구애받지 않는 코드를 구현할 수 있기 때문에 지금부터 `AutoModel` 클래스를 사용할 것입니다. 만약 특정 체크포인트에서 코드가 작동한다면 다른 체크포인트에서도 작동이 원활해야 합니다. 체크포인트가 유사한 태스크(예를 들면 감성분석 태스크)에 대해 학습되는 한 모델 구조가 다르더라도 적용됩니다. - -{:else} -```py -from transformers import TFBertModel - -model = TFBertModel.from_pretrained("bert-base-cased") -``` - -앞서 본 것처럼 `BertModel`을 동일한 `AutoModel` 클래스로 대체할 수 있습니다. 이렇게 하면 체크포인트에 구애받지 않는 코드를 구현할 수 있기 때문에 지금부터 `AutoModel` 클래스를 사용할 것입니다. 만약 특정 체크포인트에서 코드가 작동한다면 다른 체크포인트에서도 작동이 원활해야 합니다. 체크포인트가 유사한 태스크(예를 들면 감성분석 태스크)에 대해 학습되는 한 모델 구조가 다르더라도 적용됩니다. - -{/if} - -위의 샘플 코드에서 `BertConfig`를 사용하지 않고 `bert-base-cased` 식별자를 통해 사전학습 모델을 불러왔습니다. 이 체크포인트의 BERT 저자들이 직접 학습시킨 모델 체크포인트입니다. [모델 카드](https://huggingface.co/bert-base-cased)에서 더 자세한 내용을 확인할 수 있습니다. - -이제 이 모델은 체크포인트의 모든 가중치로 초기화됩니다. 학습된 태스크에 대한 추론 시 바로 사용할 수 있으며 새로운 태스크로 파인튜닝할 수 있습니다. 처음부터 직접 학습시키기보다 사전학습된 가중치를 사용하면 좋은 결과를 빨리 얻을 수 있습니다. - -가중치가 다운로드되고 기본 경로가 *~/.cache/huggingface/transformers*인 캐시 폴더에 저장되었기 때문에 이후 `from_pretrained()` 메서드 호출 시 가중치를 다시 다운로드 하지 않습니다. 캐시 폴더는 `HF_HOME` 환경 변수 설정을 통해 변경할 수 있습니다. - -BERT 구조와 호환되는 모델이라면, 모델 허브에 올라온 어떤 모델이라도 식별자로 사용될 수 있습니다. 이용 가능한 BERT 체크포인트 전체 리스트는 [이 곳](https://huggingface.co/models?filter=bert)에서 확인할 수 있습니다. - -### 저장 메서드[[saving-methods]] - -모델 저장은 모델을 불러오는 것만큼 간단합니다 - `from_pretrained()` 메서드와 유사한 `save_pretrained()` 메서드를 사용합니다. - -```py -model.save_pretrained("directory_on_my_computer") -``` - -이 메서드는 당신의 디스크에 두 가지 파일을 저장합니다. - -{#if fw === 'pt'} -``` -ls directory_on_my_computer - -config.json pytorch_model.bin -``` -{:else} -``` -ls directory_on_my_computer - -config.json tf_model.h5 -``` -{/if} - -*config.json* 파일을 자세히 들여다보면, 속성들이 모델 구조 생성에 중요하다는 것을 알게 될 것입니다. 또한, 이 파일에는 체크포인트가 시작된 위치와 체크포인트를 마지막으로 저장할 때 사용한 🤗 Transformers 버전과 같은 메타데이터가 포함되어 있습니다. - -{#if fw === 'pt'} -*pytorch_model.bin* 파일은 *state dictionary*로 알려져 있습니다. 이 파일은 모델의 모든 가중치를 저장하고 있으며 두 개의 파일이 서로 연결되어 있습니다. 모델 가중치는 모델의 파라미터이고 환경 설정은 모델 구조 파악에 중요한 역할을 합니다. - -{:else} -*tf_model.h5* 파일은 *state dictionary*로 알려져 있습니다. 이 파일은 모델의 모든 가중치를 저장하고 있으며 두 개의 파일은 서로 관련이 있습니다. 모델 가중치는 모델의 파라미터이고 환경 설정은 모델 구조 파악에 중요한 역할을 합니다. - -{/if} - -## Transformer 모델을 이용하여 추론하기[[using-a-transformer-model-for-inference]] - -모델을 불러오고 저장하는 방법을 알았기 때문에 이제 모델을 활용하여 몇 가지 예측을 해봅시다. Transformer 모델은 토크나이저가 생성한 숫자만 처리할 수 있는데 토크나이저에 대해 이야기하기 전 모델이 허락하는 입력 형태에 대해 알아보도록 하겠습니다. - -토크나이저는 적절한 프레임워크의 텐서로 입력을 보낼 수 있지만 동작 과정에 대한 이해를 돕기 위해 입력을 모델로 보내기 전 수행해야 할 작업을 간단히 살펴보겠습니다. - -몇 개의 시퀀스가 있다고 가정해봅시다. - -```py -sequences = ["Hello!", "Cool.", "Nice!"] -``` - -토크나이저는 이 시퀀스들을 *입력 ID*라고 하는 단어 인덱스로 변환합니다. 각 시퀀스는 이제 숫자 리스트입니다! 결과는 다음과 같이 출력됩니다. - -```py no-format -encoded_sequences = [ - [101, 7592, 999, 102], - [101, 4658, 1012, 102], - [101, 3835, 999, 102], -] -``` - -이 결과는 인코딩된 시퀀스들로, 리스트 안의 리스트 형태입니다. 텐서는 직사각형 형태(행렬을 생각해보세요)만 사용할 수 있습니다. 인코딩된 시퀀스 "배열"은 이미 직사각형 형태이기 때문에 이 배열을 텐서로 변환하는 것은 쉽습니다. - -{#if fw === 'pt'} -```py -import torch - -model_inputs = torch.tensor(encoded_sequences) -``` -{:else} -```py -import tensorflow as tf - -model_inputs = tf.constant(encoded_sequences) -``` -{/if} - -### 텐서를 모델 입력으로 사용하기[[using-the-tensors-as-inputs-to-the-model]] - -텐서를 모델과 함께 사용하는 것은 매우 간단합니다 - 입력과 함께 모델을 호출합니다. - -```py -output = model(model_inputs) -``` - -모델은 다양한 인자를 입력받지만 여기서는 입력 ID만 필요합니다. 다른 인자들의 역할이나 다른 인자들이 필요한 시점에 대한 설명을 듣기 전에, Transformer 모델이 이해할 수 있는 입력을 생성하는 토크나이저를 자세히 살펴봐야 합니다.