Buckets:

rtrm's picture
|
download
raw
13 kB
# 모델
이번 섹션에서는 모델을 생성하고 사용하는 방법에 대해 자세히 알아보겠습니다. 체크포인트를 토대로 모델을 인스턴스화하는 데 유용한 `AutoModel` 클래스를 사용해 보겠습니다.
## 트랜스포머 생성하기[[creating-a-transformer]]
우선 `AutoModel`을 인스턴스화하면 어떤 일이 발생하는지 알아봅시다.
```py
from transformers import AutoModel
model = AutoModel.from_pretrained("bert-base-cased")
```
`from_pretrained()` 메소드를 실행하면 토크나이저처럼 모델 데이터를 허깅페이스 허브에서 다운로드한후 캐싱합니다. 앞서 언급한 것처럼 체크포인트의 이름은 특정 모델 아키텍쳐와 가중치에 대응되며, 지금의 경우에는 기본적인 아키텍쳐(12 layers, 768 hidden size, 12 attention heads)와 대소문자를 입력에서 구분하는 BERT 모델입니다. 다양한 체크포인트들을 [허브](https://huggingface.co/models)에서 찾아볼 수 있습니다.
사실 `AutoModel`과 관련 클래스들은 체크포인트가 주어졌을 때, 해당 체크포인트에 적합한 모델의 아키텍쳐를 불러오는 래퍼 클래스입니다. 이렇게 자동으로 모델 아키텍쳐를 추측해서 인스턴스화하기 때문에 이름에 "auto"가 붙었습니다. 만약 특정 모델을 사용하고 싶다면, 다음과 같이 직접 아키텍쳐를 정의할 수 있는 클래스를 사용할 수 있습니다.
```py
from transformers import BertModel
model = BertModel.from_pretrained("bert-base-cased")
```
## 불러오고 저장하기[[loading-and-saving]]
토크나이저를 저장하는 것처럼 모델을 저장하는 것도 매우 간단합니다. 사실, 모델도 `save_pretrained()` 메소드를 이용해 가중치와 아키텍쳐에 대한 구성정보를 저장할 수 있습니다.
```py
model.save_pretrained("directory_on_my_computer")
```
두 개의 파일이 디스크에 저장됩니다.
```
ls directory_on_my_computer
config.json model.safetensors
```
_config.json_ 파일 내부를 들여다보면, 모델 아키텍쳐를 빌드하는데 필요한 모든 요소들을 확인할 수 있습니다. 또한 체크포인트의 출처가 어디인지, 체크포인트를 저장했을 때 어떤 🤗 트랜스포머 버전을 사용하고 있었는지와 같은 메타데이터도 포함하고 있습니다.
_pytorch_model.safetensors_ 파일은 모델의 가중치 상태 저장소입니다. 따라서 이 두 파일을 각각 모델의 아키텍쳐와 모델의 파라미터에 필요한 가중치를 저장하는 역할을 합니다.
저장된 모델을 다시 사용하기 위해서는 앞서 언급했던 `from_pretrained()` 메소드를 사용합니다.
```py
from transformers import AutoModel
model = AutoModel.from_pretrained("directory_on_my_computer")
```
🤗 트랜스포머 라이브러리는 커뮤니티에 모델과 토크나이저를 공유할 수 있는 환상적인 기능을 제공합니다. 이 기능을 사용하기 위해서는 우선 [허깅페이스](https://huggingface.co) 계정이 필요합니다. notebook을 사용하고 있다면, 다음과 같이 손쉽게 로그인할 수 있습니다.
```python
from huggingface_hub import notebook_login
notebook_login()
```
또는 터미널에서 다음 코드를 실행합니다.
```bash
huggingface-cli login
```
이후에는 `push_to_hub()` 메소드를 이용해 모델을 허브에 푸시할 수 있습니다.
```py
model.push_to_hub("my-awesome-model")
```
위 코드를 실행하면 본인의 namespace에 있는 *my-awesome-model*이라는 이름의 레포지토리에 모델이 업로드됩니다. 이제 모두가 `from_pretrained()` 메소드를 이용해 당신의 모델을 불러올 수 있습니다.
```py
from transformers import AutoModel
model = AutoModel.from_pretrained("your-username/my-awesome-model")
```
허깅페이스 허브 API를 사용하면 이외에도 다양한 것들을 할 수 있습니다.
- 로컬 레포지토리로부터 모델 푸시하기
- 특정 파일만을 다시 업로드하기
- 모델의 능력, 한계점, 알려진 편향등을 기록하는 모델 카드 추가하기
보다 자세한 설명은 [공식문서](https://huggingface.co/docs/huggingface_hub/how-to-upstream)나 [챕터 4](/course/chapter4)를 참고하세요.
## 텍스트 인코딩하기[[encoding-text]]
트랜스포머 모델은 텍스트를 숫자로 변환해 다룹니다. 이번에는 토크나이저가 텍스트를 어떻게 처리하는지 자세히 알아보겠습니다. [챕터 1](/course/chapter1)에서 살펴본 것처럼 토크나이저는 텍스트를 토큰들로 변환하고 이 토큰들을 숫자로 다시 변환합니다. 이러한 처리 과정을 다음과 같은 간단한 토크나이저를 통해 살펴보겠습니다.
```py
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
encoded_input = tokenizer("Hello, I'm a single sentence!")
print(encoded_input)
```
```python out
{'input_ids': [101, 8667, 117, 1000, 1045, 1005, 1049, 2235, 17662, 12172, 1012, 102],
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
```
우리는 다음의 필드들을 가지는 딕셔너리를 얻었습니다.
- input_ids: 각 토큰의 수치적인 값
- token_type_ids: 입력의 어떤 부분이 각각 문장 A와 B에 속하는지 (다음 차례에서 자세히 다룹니다)
- attention_mask: 어떤 토큰에 주목해야하는지 (잠시 후에 더 자세히 설명합니다)
`inputs_ids`를 디코딩하면 원문 텍스트를 복원할 수 있습니다.
```py
tokenizer.decode(encoded_input["input_ids"])
```
```python out
"[CLS] Hello, I'm a single sentence! [SEP]"
```
토크나이저는 모델에게 필요한 `[CLS]``[SEP]` 같은 특별한 토큰들도 생성했습니다. 토크나이저는 이런 특별한 토큰들을 현재 사용하는 모델이 사전 학습 단계에서 사용했을 때 알맞게 추가해줘야 합니다.
여러개의 문장을 한번에 처리하거나 리스트로 만들어서 인코딩할 수도 있습니다:
```py
encoded_input = tokenizer("How are you?", "I'm fine, thank you!")
print(encoded_input)
```
```python out
{'input_ids': [[101, 1731, 1132, 1128, 136, 102], [101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]],
'token_type_ids': [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
'attention_mask': [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
```
토크나이저에게 여러 문장을 전달하면 딕셔너리에 리스트로 각 문장에 대응하는 값들을 반환합니다. PyTorch를 사용해서 토크나이저가 텐서를 바로 반환하도록 할 수도 있습니다:
```py
encoded_input = tokenizer("How are you?", "I'm fine, thank you!", return_tensors="pt")
print(encoded_input)
```
```python out
{'input_ids': tensor([[ 101, 1731, 1132, 1128, 136, 102],
[ 101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0],
[0, 0, 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]])}
```
하지만 두 리스트의 크기가 다르다는 문제가 있습니다! PyTorch의 텐서(또는 NumPy array)로 변경하려면 배열과 텐서들은 직사각형이어야 합니다. 이 문제를 해결하기 위해 토크나이저에는 padding이라는 기능이 있습니다.
### 입력 패딩하기[[padding-inputs]]
토크나이저는 특별한 패딩 토큰을 문장에 추가해 모든 문장들이 길이가 가장 긴 문장과 동일한 길이를 가지도록 수정합니다.
```py
encoded_input = tokenizer(
["How are you?", "I'm fine, thank you!"], padding=True, return_tensors="pt"
)
print(encoded_input)
```
```python out
{'input_ids': tensor([[ 101, 1731, 1132, 1128, 136, 102, 0, 0, 0, 0],
[ 101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
```
마침대 직사각 텐서를 얻었습니다! 패딩 토큰들은 실제 문장의 일부분이 아니기 때문에 모델이 분석할 필요가 없습니다. 따라서 `input_ids`의 값과 `attention_mask` 즉 주목도의 값이 모두 0인걸 확인할 수 있습니다.
### 입력 크기 자르기[[truncating-inputs]]
모델이 처리할 수 있는 입력의 크기보다 텐서가 더 클 수도 있습니다. 예를 들어, BERT는 최대 512개의 토큰만을 사용하도록 사전 학습됐기 때문에 이보다 긴 문장은 처리할 수 없습니다. 이런 경우에는 `truncation` 파라미터를 사용해 크기를 조절할 수 있습니다:
```py
encoded_input = tokenizer(
"This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long sentence.",
truncation=True,
)
print(encoded_input["input_ids"])
```
```python out
[101, 1188, 1110, 170, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1179, 5650, 119, 102]
```
`padding``truncation` 인자를 함께 사용해 텐서를 원하는 크기로 조절할 수 있습니다.
```py
encoded_input = tokenizer(
["How are you?", "I'm fine, thank you!"],
padding=True,
truncation=True,
max_length=5,
return_tensors="pt",
)
print(encoded_input)
```
```python out
{'input_ids': tensor([[ 101, 1731, 1132, 1128, 102],
[ 101, 1045, 1005, 1049, 102]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]),
'attention_mask': tensor([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])}
```
### 특별한 토큰 추가하기
BERT와 그 파생 모델들에서 특별한 토큰들은 굉장히 중요합니다. 예를 들어, 문장의 시작(`[CLS]`)이나 문장 사이의 구분(`[SEP]`)을 도와주는 토큰들로 문장끼리 구분을 도와줍니다. 간단한 예제를 함께 살펴보겠습니다.
```py
encoded_input = tokenizer("How are you?")
print(encoded_input["input_ids"])
tokenizer.decode(encoded_input["input_ids"])
```
```python out
[101, 1731, 1132, 1128, 136, 102]
'[CLS] How are you? [SEP]'
```
토크나이저가 방금 전 언급한 토큰들을 자동으로 추가했습니다. 앞서 설명한 것처럼 토크나이저는 모델이 이런 특별한 토큰들을 이용해 사전 학습됐을 경우에만 추가합니다.
### 왜 이렇게 복잡한 과정을 거쳐야 할까요??
구체적인 예시와 함께 살펴보겠습니다.
```py
sequences = [
"I've been waiting for a HuggingFace course my whole life.",
"I hate this so much!",
]
```
토큰화된 이후에 우린 다음과 같은 결과를 얻습니다.
```python
encoded_sequences = [
[
101,
1045,
1005,
2310,
2042,
3403,
2005,
1037,
17662,
12172,
2607,
2026,
2878,
2166,
1012,
102,
],
[101, 1045, 5223, 2023, 2061, 2172, 999, 102],
]
```
이는 인코딩된 결과를 나타내는 이차원 배열입니다. 텐서는 직사각형 형태(마치 행렬처럼)만을 입력으로 받는데, 앞선 과정을 거치면 배열들이 이미 직사각형이기 때문에 텐서로 쉽게 변환할 수 있습니다.
```py
import torch
model_inputs = torch.tensor(encoded_sequences)
```
### 텐서를 모델의 입력으로 사용하기[[using-the-tensors-as-inputs-to-the-model]]
이렇게 만들어진 텐서는 모델을 호출할 때 인자로 사용할 수 있습니다!
```py
output = model(model_inputs)
```
모델의 다양한 인자 중 `input_ids`는 반드시 필요합니다. 다른 인자에 대한 설명은 추후에 다루겠습니다.
그 전에 토크나이저가 어떻게 트랜스포머 모델이 이해할 수 있는 input을 만드는지 자세히 살펴보겠습니다.

Xet Storage Details

Size:
13 kB
·
Xet hash:
6d62becbbdf6981bea85ff48428af85a9609e8a4806ef72fe3e17867ac9da853

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.