한국어를 위한 KoBERT 사용기

Nina·2022년 11월 5일

그동안 댓글 데이터를 처리할 일이 많다보니 KcBERT를 사용할 일이 많고 정작 KoBERT로 데이터 처리를 해본 적이 없었다.

아무 생각 없이 이번에도 KcBERT로 테스크 진행하고 있었는데 생각해보니 KoBERT를 사용해도 될 데이터라 이번 기회에 KoBERT로 모델을 바꿔 실험을 진행해 보았다.

Huggingface에서 두 모델을 제공하고 있으니, 모델만 바꿔 끼면 되겠지라고 안일하게 생각했는데..

그게 아니었다는..
게다가 2021년 11월부터 서버에 문제가 생기면서 그동안 잘 돌아가던 Kobert 코드도 잘 안되는 듯 하다. (지금 검색으로 찾을 수 있는 코드 중 대부분은 바뀌기 전 코드)

암튼 각설하고 huggingface KoBERT 돌리는 코드를 공유한다.

huggingface transformer를 설치하고, KoBERT의 경우 토크나이저 사용을 하려면 sentencepice도 설치를 해줘야 한다.

!pip install transformers
!pip install sentencepiece

KcBERT의 경우 transfomer 모듈에서 바로 가져와서 쓸 수 있지만(!!) KoBERT는 공식 깃에서 토크나이저 관련 파일을 받아줘야 한다.

!pip install 'git+https://github.com/SKTBrain/KoBERT.git#egg=kobert_tokenizer&subdirectory=kobert_hf'

이 과정을 거치고 나서야 huggingface에서 모델과 토크나이저를 가져올 수 있다. huggingface에서 Kobert는 'skt/kobert-base-v1' 모델명으로 불러온다.

from kobert_tokenizer import KoBERTTokenizer
from transformers import BertModel

from transformers import AdamW
from transformers.optimization import get_cosine_schedule_with_warmup
tokenizer = KoBERTTokenizer.from_pretrained('skt/kobert-base-v1', last_hidden_states=True)
model = BertModel.from_pretrained('skt/kobert-base-v1', return_dict=False)

토크나이저가 잘 동작하는지 확인을 해보니 다행히 잘 나온다.

inputs = tokenizer("목차를 봤을 때 기억에 오래 남아요", return_tensors="pt")

{'input_ids': tensor([[   2, 2068, 7389, 6116, 2421, 7088, 1844, 1291, 6896, 3422, 1420, 6999,
            3]]), 'token_type_ids': tensor([[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]])}

모델 지정해주고~

import torch.nn as nn
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence

class Bert(nn.Module):
    def __init__(
            self,
            model_name,
            n_classes,
            hidden_size,
            n_layers,
            dropout_p,
    ):
        self.model_name = model_name
        self.n_class = n_classes
        self.hidden_size = hidden_size
        self.n_layers = n_layers
        self.dropout_p = dropout_p

        super().__init__()

        self.bertmodel = BertModel.from_pretrained(self.model_name,  output_attentions = True, output_hidden_states=True)

        self.classifier = nn.Sequential(
            nn.Dropout(p=dropout_p),
            nn.Linear(self.bertmodel.config.hidden_size, self.n_class)
        )

    def forward(self, x):
       
        # |x| = (batch_size, length)
        # encoder_layer= self.bertmodel(x, attention_mask)
        pooled_output = self.bertmodel(x)[1]
      
        x = self.classifier(pooled_output)

        return x

잘 물려서 돌아가는 것까지 확인 :)

model = bert(
            'skt/kobert-base-v1',
            3,
            hidden_size = 100,
            n_layers = 3,
            dropout_p =.25,
        )
encoding = tokenizer("나는 할 수 있다", return_tensors="pt")

x= encoding['input_ids']

outputs = model(x)
print(outputs)

<참고>

KcBERT 공식 깃허브

KoBERT 공식 깃허브

profile
언어를 사랑하고 독서를 즐겨하며 자연어처리를 공부합니다.

1개의 댓글

comment-user-thumbnail
2023년 5월 3일

혹시 python 버전이랑 transformers, sentencepiece 버전 알 수 있을까요.

답글 달기