콘텐츠로 이동

텐서플로우 자연어처리 BERT-base

이 튜토리얼에서는 자연어처리 모델 중 하나인 BERT의 마스크드 언어모델(masked language model) 태스크를 사용합니다. 마스크드 언어모델은 문장 내에서 마스킹 된 단어를 예측하는 태스크입니다. 이 튜토리얼을 통해 RBLN 컴파일러를 사용하여 허깅페이스 BERT-base 모델을 컴파일하고, RBLN 런타임을 사용하여 추론하는 방법을 배울 수 있습니다.

이 튜토리얼은 두 단계로 구성되어 있습니다:

  1. 텐서플로우 BERT-base 모델을 컴파일하고 디스크에 저장하는 방법
  2. 컴파일된 모델을 로드하고 추론하는 방법

사전 준비

시작하기에 앞서 아래의 파이썬 패키지들이 설치되어 있는지 확인합니다:

참고

세부 사항을 생략하고, 빠르게 컴파일 및 추론하는 방법을 확인하려면 요약을 참고하세요. 컴파일 및 추론을 위한 모든 코드가 정리되어있어 빠르게 프로젝트를 시작 할 수 있습니다.

1단계. 컴파일 방법

모델 준비

허깅페이스에서 제공하는 transformers 라이브러리를 통해 TFBertForMaskedLM 모델을 로드하고, tf.function 객체로 변환합니다.

from transformers import TFBertForMaskedLM
import tensorflow as tf
import rebel  # RBLN 컴파일러

# 허깅페이스 텐서플로우 BERT-base 모델 준비
model = TFBertForMaskedLM.from_pretrained("bert-base-uncased")
func = tf.function(
    lambda input_ids, attention_mask, token_type_ids: model(
        input_ids, attention_mask, token_type_ids
    )
)

모델 컴파일

rebel.compile_from_tf_function() 함수를 이용하여 준비 된 텐서플로우 모델(tf.function)을 컴파일 할 수 있습니다.

# 모델 컴파일
MAX_SEQ_LEN = 128
input_info = [
    ("input_ids", [1, MAX_SEQ_LEN], tf.int64),
    ("attention_mask", [1, MAX_SEQ_LEN], tf.int64),
    ("token_type_ids", [1, MAX_SEQ_LEN], tf.int64),
]
compiled_model = rebel.compile_from_tf_function(
    func,
    input_info,
    # 호스트에 NPU가 설치되어 있는 경우, 아래의 `npu`인자는 명시하지 않아도 자동으로 감지됩니다. 
    npu="RBLN-CA12",
)

호스트 머신에 NPU가 설치되어 있는 경우, NPU를 자동으로 감지하여 사용하기 때문에 rebel.compile_from_tf_function 함수에 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를 사용하여 입력문자열을 토큰화하고, 마스크드 언어모델의 입력문자열로 사용하기 위해 사전처리 과정을 수행합니다.

1
2
3
4
5
6
7
8
9
from transformers import BertTokenizer, pipeline
import tensorflow as tf
import rebel # RBLN 런타임

# 입력 데이터 준비
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
text = "The capital of Korea is [MASK]."
MAX_SEQ_LEN = 128
inputs = tokenizer(text, return_tensors="np", padding="max_length", max_length=MAX_SEQ_LEN)

추론

RBLN 런타임 모듈 rebel.Runtime()을 통해 컴파일된 모델을 로드합니다. RBLN 런타임 모듈의 멤버함수 run()을 통해 주어진 문장에 대해 추론할 수 있습니다. 또는 __call__ 매직함수를 사용할 수도 있습니다.

1
2
3
4
5
# 컴파일된 모델 불러오기
module = rebel.Runtime("bert_base.rbln")

# 추론
out = module.run(**inputs)

print(module)을 통해 로드된 모델의 입출력 형태 및 모델크기 등 요약된 정보를 확인할 수 있습니다.

결과 확인

입력 문자열의 [MASK] 토큰의 인덱스를 특정하고, 추론 결과 로짓값 out 으로부터 해당 토큰이 위치한 로짓값을 추출합니다. 추출된 로짓값 중 가장 높은값의 단어를 디코딩하여 최종 결과 단어를 확인할 수 있습니다.

1
2
3
4
5
# 결과 확인
mask_token_index = tf.where((inputs.input_ids == tokenizer.mask_token_id)[0])
selected_logits = tf.gather_nd(out[0], indices=mask_token_index)
predicted_token_id = tf.math.argmax(selected_logits, axis=-1)
print("Masked word is [", tokenizer.decode(predicted_token_id), "].")

최종 결과는 다음과 같습니다:

Masked word is [ seoul ]

요약

허깅페이스에서 제공하는 텐서플로우 BERT-base 모델의 컴파일을 위한 완성된 코드는 아래와 같습니다:

from transformers import TFBertForMaskedLM
import tensorflow as tf
import rebel  # RBLN 컴파일러

# 허깅페이스 텐서플로우 BERT-base 모델 준비
model = TFBertForMaskedLM.from_pretrained("bert-base-uncased")
func = tf.function(
    lambda input_ids, attention_mask, token_type_ids: model(
        input_ids, attention_mask, token_type_ids
    )
)

# 모델 컴파일
MAX_SEQ_LEN = 128
input_info = [
    ("input_ids", [1, MAX_SEQ_LEN], tf.int64),
    ("attention_mask", [1, MAX_SEQ_LEN], tf.int64),
    ("token_type_ids", [1, MAX_SEQ_LEN], tf.int64),
]
compiled_model = rebel.compile_from_tf_function(
    func,
    input_info,
    # 호스트에 NPU가 설치되어 있는 경우, 아래의 `npu`인자는 명시하지 않아도 자동으로 감지됩니다. 
    npu="RBLN-CA12",
)

# 컴파일된 모델 디스크에 저장
compiled_model.save("bert_base.rbln")

컴파일된 BERT-base 모델의 추론을 위한 완성된 코드는 아래와 같습니다:

from transformers import BertTokenizer, pipeline
import tensorflow as tf
import rebel  # RBLN 런타임

# 입력 데이터 준비
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
text = "The capital of Korea is [MASK]."
MAX_SEQ_LEN = 128
inputs = tokenizer(text, return_tensors='np', padding="max_length", max_length=MAX_SEQ_LEN)

# 컴파일된 모델 불러오기
module = rebel.Runtime("bert_base.rbln")

# 추론
out = module.run(**inputs)

# 결과 확인
mask_token_index = tf.where((inputs.input_ids == tokenizer.mask_token_id)[0])
selected_logits = tf.gather_nd(out[0], indices=mask_token_index)
predicted_token_id = tf.math.argmax(selected_logits, axis=-1)
print("Masked word is [", tokenizer.decode(predicted_token_id), "].")