파이토치 자연어처리 BERT-base
이 튜토리얼에서는 자연어처리 모델 중 하나인 BERT의 마스크드 언어모델(masked language model) 태스크를 사용합니다. 마스크드 언어모델은 문장 내에서 마스킹 된 단어를 예측하는 태스크입니다. 이 튜토리얼을 통해 RBLN 컴파일러를 사용하여 허깅페이스 BERT-base 모델을 컴파일하고 RBLN 런타임을 사용하여 추론하는 방법을 배울 수 있습니다.
이 튜토리얼은 두 단계로 구성되어 있습니다:
- 파이토치
BERT-base
모델을 컴파일하고 로컬 저장소에 저장하는 방법
- 컴파일된 모델을 로드하고 추론하는 방법
사전 준비
시작하기에 앞서 아래의 파이썬 패키지들이 설치되어 있는지 확인합니다:
참고
세부 사항을 생략하고, 빠르게 컴파일 및 추론하는 방법을 확인하려면 요약을 참고하세요. 컴파일 및 추론을 위한 모든 코드가 정리되어있어 빠르게 프로젝트를 시작 할 수 있습니다.
네이티브 RBLN API
1단계. 컴파일 방법
모델 준비
허깅페이스에서 제공하는 transformers
라이브러리를 통해 BertForMaskedLM
모델을 로드합니다.
| import torch
from transformers import BertForMaskedLM
import rebel # RBLN 컴파일러
# 허깅페이스 파이토치 BERT-base 모델 준비
bert_model = BertForMaskedLM.from_pretrained("bert-base-uncased", return_dict=False)
bert_model.eval()
|
모델 컴파일
rebel.compile_from_torch()
함수를 이용하여 준비 된 파이토치 모델(torch.nn.Module
)을 컴파일 할 수 있습니다.
| # 모델 컴파일
MAX_SEQ_LEN = 128
input_info = [
("input_ids", [1, MAX_SEQ_LEN], "int64"),
("attention_mask", [1, MAX_SEQ_LEN], "int64"),
("token_type_ids", [1, MAX_SEQ_LEN], "int64"),
]
compiled_model = rebel.compile_from_torch(
bert_model,
input_info,
# 호스트에 NPU가 설치되어 있는 경우, 아래의 `npu`인자는 명시하지 않아도 자동으로 감지됩니다.
npu="RBLN-CA12",
)
|
호스트 머신에 NPU가 설치되어 있는 경우, NPU를 자동으로 감지하여 사용하기 때문에 rebel.compile_from_torch
함수에 npu
인자를 생략할 수 있습니다.
NPU가 설치되지 않은 호스트 머신에서 컴파일을 수행할 경우 컴파일 함수에 npu
인자를 명시해야 합니다. 그렇지 않으면 에러가 발생합니다.
현재 지원하는 NPU는 RBLN-CA02
, RBLN-CA12
입니다. 사용하려는 NPU의 이름은 NPU가 설치된 호스트 머신에서 rbln-stat
명령어를 통해 확인할 수 있습니다.
컴파일된 모델 저장
compiled_model.save()
함수를 통해 컴파일된 모델을 로컬 저장소에 저장할 수 있습니다.
| # 컴파일된 모델 로컬 저장소에 저장
compiled_model.save("bert_base.rbln")
|
2단계. 추론 방법
RBLN 런타임 모듈 rebel.Runtime()
을 통해 이전 단계에서 컴파일된 모델을 로드하고 추론할 수 있습니다.
입력 데이터 준비
transformers
라이브러리에서 제공하는 BertTokenizer
를 사용하여 입력문자열을 토큰화하고, 마스크드 언어모델의 입력문자열로 사용하기 위해 사전처리 과정을 수행합니다.
| import torch
from transformers import BertTokenizer, pipeline
import rebel # RBLN 런타임
# 입력 데이터 준비
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
text = "the color of rose is [MASK]."
MAX_SEQ_LEN = 128
inputs = tokenizer(text, return_tensors="pt", padding="max_length", max_length=MAX_SEQ_LEN)
|
추론
RBLN 런타임 모듈 rebel.Runtime()
을 통해 컴파일된 모델을 로드하고, RBLN 런타임 모듈의 멤버함수 run()
을 통해 추론할 수 있습니다. 사전처리 된 입력 정보들을 numpy 배열로 변환하여 run()
함수의 입력으로 넣어줍니다.
| # 컴파일된 모델 불러오기
module = rebel.Runtime("bert_base.rbln", tensor_type="pt")
# 추론
out = module(**inputs)
|
print(module)
을 통해 로드된 모델의 입출력 형태 및 모델 크기 등 요약된 정보를 확인할 수 있습니다.
결과 확인
transformers
라이브러리의 fill-mask
파이프라인을 사용하여 추론 결과 로짓값 out
으로부터 입력 문자열의 [MASK]
위치에 해당하는 단어를 디코딩할 수 있습니다.
| # 결과 확인
unmasker = pipeline("fill-mask", model="bert-base-uncased", framework="pt")
print(unmasker.postprocess({"input_ids": inputs.input_ids, "logits": out}))
|
최종 결과는 아래와 유사합니다:
| [
{'score': 0.23562490940093994, 'token': 2317, 'token_str': 'white', 'sequence': 'the color of rose is white.'},
{'score': 0.10957575589418411, 'token': 2417, 'token_str': 'red', 'sequence': 'the color of rose is red.'},
{'score': 0.08016733080148697, 'token': 2304, 'token_str': 'black', 'sequence': 'the color of rose is black.'},
{'score': 0.07074742764234543, 'token': 3756, 'token_str': 'yellow', 'sequence': 'the color of rose is yellow.'},
{'score': 0.05175992473959923, 'token': 2630, 'token_str': 'blue', 'sequence': 'the color of rose is blue.'},
]
|
요약
허깅페이스에서 제공하는 파이토치 BERT-base
모델의 컴파일을 위한 완성된 코드는 아래와 같습니다:
| import torch
from transformers import BertForMaskedLM
import rebel # RBLN 컴파일러
# 허깅페이스 파이토치 BERT-base 모델 준비
bert_model = BertForMaskedLM.from_pretrained("bert-base-uncased", return_dict=False)
bert_model.eval()
# 모델 컴파일
MAX_SEQ_LEN = 128
input_info = [
("input_ids", [1, MAX_SEQ_LEN], "int64"),
("attention_mask", [1, MAX_SEQ_LEN], "int64"),
("token_type_ids", [1, MAX_SEQ_LEN], "int64"),
]
compiled_model = rebel.compile_from_torch(
bert_model,
input_info,
# 호스트에 NPU가 설치되어 있는 경우, 아래의 `npu`인자는 명시하지 않아도 자동으로 감지됩니다.
npu="RBLN-CA12",
)
# 컴파일된 모델 로컬 저장소에 저장
compiled_model.save("bert_base.rbln")
|
컴파일된 BERT-base
모델의 추론을 위한 완성된 코드는 아래와 같습니다:
| import torch
from transformers import BertTokenizer, pipeline
import rebel # RBLN 런타임
# 입력 데이터 준비
MAX_SEQ_LEN = 128
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
text = "the color of rose is [MASK]."
inputs = tokenizer(text, return_tensors="pt", padding="max_length", max_length=MAX_SEQ_LEN)
# 컴파일된 모델 불러오기
module = rebel.Runtime("bert_base.rbln", tensor_type="pt")
# 추론
out = module(**inputs)
# 결과 확인
unmasker = pipeline("fill-mask", model="bert-base-uncased", framework="pt")
print(unmasker.postprocess({"input_ids": inputs.input_ids, "logits": out}))
|
torch.compile()
API
RBLN SDK는 자체 API뿐만 아니라 PyTorch의 torch.compile
기능도 지원합니다. 이 통합을 통해 개발자는 PyTorch의 Just-In-Time(JIT) 컴파일을 활용하여 RBLN SDK 내에서 최적화된 모델 실행을 구현할 수 있습니다. torch.compile
을 사용하는 모든 워크플로우에 RBLN의 커스텀 백엔드를 통합하면, RBLN의 기본 기능과 완벽하게 호환되면서도 향상된 성능을 얻을 수 있습니다.
이 가이드는 torch.compile()
API를 사용하여 Hugging Face BERT-base 모델을 컴파일하고 실행하는 방법을 보여줍니다.
모델 준비
먼저, HuggingFace transformers 라이브러리에서 BertForMaskedLM
모델을 가져와 인스턴스화합니다. 이 단계는 RBLN의 네이티브 API에서 사용하는 과정과 동일합니다.
| import torch
from transformers import BertForMaskedLM
import rebel # RBLN 컴파일러 임포트
if torch.__version__ >= "2.5.0":
torch._dynamo.config.inline_inbuilt_nn_modules = False
# Hugging Face BERT-base 모델 인스턴스화
bert_model = BertForMaskedLM.from_pretrained("bert-base-uncased")
bert_model.eval()
|
입력 준비
다음으로, 마스크된 언어 모델링 작업을 위해 입력 텍스트 시퀀스를 토큰화하여 입력 데이터를 준비합니다. 이 과정도 네이티브 API를 사용하는 것과 동일합니다.
| from transformers import BertTokenizer
# 토크나이저 로드
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
# 입력 텍스트 정의
text = "The color of a rose is [MASK]."
# 입력 토큰화 및 준비
MAX_SEQ_LEN = 128
inputs = tokenizer(text, return_tensors="pt", padding="max_length", max_length=MAX_SEQ_LEN)
|
모델 컴파일 및 실행
모델과 입력이 준비되었으면, torch.compile()
을 사용하여 모델을 컴파일하고 실행합니다. 이 단계에서는 첫 추론에서 런타임 시 JIT 컴파일을 활성화합니다.
| # RBLN 백엔드를 사용하여 모델 컴파일
compiled_model = torch.compile(bert_model,
backend="rbln", # RBLN 백엔드 지정
options={"cache_dir": "./rbln_cache_dir"}, # 컴파일된 아티팩트의 캐시 디렉토리 지정
dynamic=False) # 동적 모양 비활성화 (RBLN 백엔드는 현재 지원하지 않음)
# 컴파일된 모델을 사용하여 추론 실행
logits = compiled_model(**inputs).logits
# 예측된 토큰 디코딩
mask_token_index = (inputs.input_ids == tokenizer.mask_token_id)[0].nonzero(as_tuple=True)[0]
predicted_token_id = logits[0, mask_token_index].argmax(axis=-1)
print(f"예측된 단어: {tokenizer.decode(predicted_token_id)}")
|
torch.compile()
파라미터 이해하기
backend="rbln"
:
- 설명: 모델 컴파일에 사용할 백엔드를 지정합니다.
- 목적: 이를
"rbln"
으로 설정하면 RBLN SDK의 커스텀 백엔드를 활용하여, RBLN 환경 내에서 성능이 최적화된 컴파일 프로세스를 사용할 수 있습니다.
options={"cache_dir": "PATH/TO/rbln_cache_dir", "npu" : "TARGET_NPU_DEVICE"}
:
- 설명: 컴파일 프로세스에 추가 옵션을 제공합니다.
- 목적:
cache_dir
: 컴파일된 결과를 저장할 디렉토리를 지정합니다.
- 사용법: 네이티브 API에서
compiled_model.save("resnet50.rbln")
을 사용하는 것과 유사하게, 지정된 경로에 RBLN 아티팩트를 생성합니다.
- 캐싱: 지정된 디렉토리에 이미 컴파일된 모델이 존재하는 경우, RBLN 백엔드는 모델을 다시 컴파일하지 않고 캐시된 버전을 사용합니다. 이는 모델을 재사용할 때 컴파일 시간과 오버헤드를 줄이는 데 도움이 됩니다.
npu
: 타겟 NPU 장치를 지정합니다. 장치 식별자를 지정하는 방법에 대한 자세한 내용은 네이티브 API 문서의 npu
옵션을 참조하십시오.
dynamic=False
:
- 설명: 모델이 동적 입력 모양을 지원할지 여부를 나타냅니다.
- 목적:
dynamic
을 False
로 설정하는 것이 권장되며, RBLN 백엔드는 현재 동적 모양을 지원하지 않습니다.
- 동작: 이 옵션을
False
로 설정하면 모델은 고정된 입력 모양을 가정하며, 다른 모양의 입력은 재컴파일을 트리거합니다. 이를 통해 컴파일이 특정 입력 모양에 대해 최적화되지만, 입력 모양이 변경될 경우 다시 컴파일해야 할 수 있습니다.
요약
torch.compile()
을 이용하여 허깅페이스에서 제공하는 파이토치 BERT-base
모델의 컴파일을 위한 완성된 코드는 아래와 같습니다:
| import argparse
import torch
from transformers import BertForMaskedLM, BertTokenizer
import rebel # torch.compile에서 "rbln" 백엔드를 사용하기 위해 필요
if torch.__version__ >= "2.5.0":
torch._dynamo.config.inline_inbuilt_nn_modules = False
def parse_arguments():
parser = argparse.ArgumentParser(description="RBLN 백엔드를 사용하여 torch.compile로 BERT 모델 실행.")
parser.add_argument("--model_name", type=str, choices=["base", "large"], default="base", help="BERT 모델 크기: 'base' 또는 'large'.")
return parser.parse_args()
def main():
args = parse_arguments()
model_name = f"bert-{args.model_name}-uncased"
MAX_SEQ_LEN = 128
# 모델 인스턴스화 및 컴파일
model = BertForMaskedLM.from_pretrained(model_name)
compiled_model = torch.compile(model, backend="rbln", dynamic=False, options={"cache_dir": "./rbln_cache_dir"})
# 마스크된 언어 모델링을 위한 입력 텍스트 준비
tokenizer = BertTokenizer.from_pretrained(model_name)
text = "The color of a rose is [MASK]."
inputs = tokenizer(text, return_tensors="pt", padding="max_length", max_length=MAX_SEQ_LEN)
# 컴파일된 모델을 사용하여 추론 실행
logits = compiled_model(**inputs).logits
# 예측된 단어 디코딩 및 출력
mask_token_index = (inputs.input_ids == tokenizer.mask_token_id)[0].nonzero(as_tuple=True)[0]
predicted_token_id = logits[0, mask_token_index].argmax(axis=-1)
print(f"예측된 단어: {tokenizer.decode(predicted_token_id)}")
if __name__ == "__main__":
main()
|