Beomi / KcBERT

🤗 Pretrained BERT model & WordPiece tokenizer trained on Korean Comments 한국어 댓글로 프리트레이닝한 BERT 모델과 데이터셋

Home Page:https://huggingface.co/beomi/kcbert-base

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IndexError: Target 2 is out of bounds. 오류 질문드립니다.

myungchulkang opened this issue · comments

commented

안녕하세요!

NLP를 공부하고있는 학생입니다.

기사 댓글 데이터를 처리하는데 아주 적합한 KcBERT를 찾아서 매우 잘 사용하고 있습니다. 감사합니다 :)

그런데, 공유해주신 NSMC 데이터셋 fine-tuning하는 코드에서 다른 데이터셋을 사용할 때 발생한 에러를 잡지 못하고 있습니다.

처음에는 RuntimeError: CUDA error: device-side assert triggered 에러가 나서 해당 사이트에서 Runtime type을 None으로 변경하면 실제 문제를 보여준다고 합니다. 그 이후 마주친 에러는 다음과 같습니다: IndexError: Target 2 is out of bounds.

  • 코랩환경(공유해주신 네이버 영화평 데이터셋 fine-tuning Large Model): https://colab.research.google.com/drive/1dFC0FL-521m7CL_PSd8RLKq67jgTJVhL?usp=sharing

  • 에러: IndexError: Target 2 is out of bounds.

  • 상황: 제공해주신 코랩 환경에서 네이버 영화평 데이터셋이 아닌 5개의 감성 클래스(매우 부정 0, 부정 1, 중립 2, 긍정 3, 매우 긍정 4)를 가지고 있는 데이터셋으로 fine-tuning 하는 과정에서 해당 에러가 계속 생깁니다.

  • 데이터셋 개수: 댓글 데이터 train: 11,281개 / test: 1,253개

  • 데이터셋 구성: NSMC 데이터셋과 동일하게 id, document, label로 수정하였고, tab으로 띄어쓴 txt 파일입니다.

데이터 경로만 수정하였고, 다른 부분은 건들지 않았습니다.

5개의 레이블을 가진 데이터셋을 해당 코드에서 사용하려면 어떻게 하면 좋을까요?

제가 무엇을 놓치고 있는 것인지 도움 주실수 있으실까요?

에러 코드 전문 공유드립니다.


IndexError Traceback (most recent call last)
in ()
----> 1 main()

18 frames
in main()
18 # tpu_cores=args.tpu_cores if args.tpu_cores else None,
19 )
---> 20 trainer.fit(model)

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/states.py in wrapped_fn(self, *args, **kwargs)
46 if entering is not None:
47 self.state = entering
---> 48 result = fn(self, *args, **kwargs)
49
50 # The INTERRUPTED state can be set inside the run function. To indicate that run was interrupted

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/trainer.py in fit(self, model, train_dataloader, val_dataloaders, datamodule)
1082 self.accelerator_backend = CPUBackend(self)
1083 self.accelerator_backend.setup(model)
-> 1084 results = self.accelerator_backend.train(model)
1085
1086 # on fit end callback

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/accelerators/cpu_backend.py in train(self, model)
37
38 def train(self, model):
---> 39 results = self.trainer.run_pretrain_routine(model)
40 return results

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/trainer.py in run_pretrain_routine(self, model)
1237
1238 # CORE TRAINING LOOP
-> 1239 self.train()
1240
1241 def _run_sanity_check(self, ref_model, model):

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/training_loop.py in train(self)
392 # RUN TNG EPOCH
393 # -----------------
--> 394 self.run_training_epoch()
395
396 if self.max_steps and self.max_steps <= self.global_step:

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/training_loop.py in run_training_epoch(self)
489 # TRAINING_STEP + TRAINING_STEP_END
490 # ------------------------------------
--> 491 batch_output = self.run_training_batch(batch, batch_idx)
492
493 # only track outputs when user implements training_epoch_end

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/training_loop.py in run_training_batch(self, batch, batch_idx)
842 opt_idx,
843 optimizer,
--> 844 self.hiddens
845 )
846 using_results_obj = isinstance(opt_closure_result.training_step_output, Result)

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/training_loop.py in optimizer_closure(self, split_batch, batch_idx, opt_idx, optimizer, hiddens)
1013 else:
1014 training_step_output = self.training_forward(split_batch, batch_idx, opt_idx,
-> 1015 hiddens)
1016
1017 # ----------------------------

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/trainer/training_loop.py in training_forward(self, batch, batch_idx, opt_idx, hiddens)
1224 # CPU forward
1225 else:
-> 1226 output = self.model.training_step(*args)
1227
1228 is_result_obj = isinstance(output, Result)

in training_step(self, batch, batch_idx)
15 def training_step(self, batch, batch_idx):
16 data, labels = batch
---> 17 loss, logits = self(input_ids=data, labels=labels)
18 preds = logits.argmax(dim=-1)
19

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
720 result = self._slow_forward(*input, **kwargs)
721 else:
--> 722 result = self.forward(*input, **kwargs)
723 for hook in itertools.chain(
724 _global_forward_hooks.values(),

in forward(self, **kwargs)
11
12 def forward(self, **kwargs):
---> 13 return self.bert(**kwargs)
14
15 def training_step(self, batch, batch_idx):

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
720 result = self._slow_forward(*input, **kwargs)
721 else:
--> 722 result = self.forward(*input, **kwargs)
723 for hook in itertools.chain(
724 _global_forward_hooks.values(),

/usr/local/lib/python3.6/dist-packages/transformers/modeling_bert.py in forward(self, input_ids, attention_mask, token_type_ids, position_ids, head_mask, inputs_embeds, labels, output_attentions, output_hidden_states, return_dict)
1340 else:
1341 loss_fct = CrossEntropyLoss()
-> 1342 loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
1343
1344 if not return_dict:

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
720 result = self._slow_forward(*input, **kwargs)
721 else:
--> 722 result = self.forward(*input, **kwargs)
723 for hook in itertools.chain(
724 _global_forward_hooks.values(),

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/loss.py in forward(self, input, target)
946 def forward(self, input: Tensor, target: Tensor) -> Tensor:
947 return F.cross_entropy(input, target, weight=self.weight,
--> 948 ignore_index=self.ignore_index, reduction=self.reduction)
949
950

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce, reduction)
2420 if size_average is not None or reduce is not None:
2421 reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 2422 return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
2423
2424

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)
2216 .format(input.size(0), target.size(0)))
2217 if dim == 2:
-> 2218 ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)
2219 elif dim == 4:
2220 ret = torch._C._nn.nll_loss2d(input, target, weight, _Reduction.get_enum(reduction), ignore_index)

IndexError: Target 2 is out of bounds.

안녕하세요 :)

해당 부분은 Model output size가 맞지 않아 발생한 에러입니다.
BertForSequenceClassification은 기본적으로 num_labels=2 라는 옵션으로, Binary Classification으로 설정되어있습니다.
따라서 해당 부분 옵션을

self.bert = Bert~~('beomi/kcbert-base', num_labels=5)

으로 해주시면 됩니다.
(모바일로 작성하는거라서 config가 저기 들어가는지는 확실하진 않습니다. 다시 확인이 필요할 것 같네요.)

commented

정말 빠른 답변 감사드립니다!

말씀 하신대로 num_label의 문제인 것 같습니다.

class Arg:
    random_seed: int = 42  # Random Seed
    pretrained_model: str = 'beomi/kcbert-large'  # Transformers PLM name
    pretrained_tokenizer: str = ''  # Optional, Transformers Tokenizer Name. Overrides `pretrained_model`
    auto_batch_size: str = 'power'  # Let PyTorch Lightening find the best batch size 
    batch_size: int = 0  # Optional, Train/Eval Batch Size. Overrides `auto_batch_size` 
    lr: float = 5e-6  # Starting Learning Rate
    epochs: int = 20  # Max Epochs
    max_length: int = 128  # Max Length input size  # 제공 받은 코드는 원래 150 이였음
    report_cycle: int = 100  # Report (Train Metrics) Cycle
    train_data_path: str = "comments_30K_labeled_train_01234.txt"  # Train Dataset file 
    val_data_path: str = "comments_30K_labeled_test_01234.txt"  # Validation Dataset file 
    cpu_workers: int = os.cpu_count()  # Multi cpu workers
    test_mode: bool = False  # Test Mode enables `fast_dev_run`
    optimizer: str = 'AdamW'  # AdamW vs AdamP
    lr_scheduler: str = 'exp'  # ExponentialLR vs CosineAnnealingWarmRestarts
    fp16: bool = False  # Enable train on FP16
    tpu_cores: int = 0  # Enable TPU with 1 core or 8 cores

args = Arg()
  • pretrained_model: str = 'beomi/kcbert-large' 에서 2개의 component ('beomi/kcbert-base', num_labels=5)를 어떻게 넣는게 좋을까요?

  • 또한, 추가 질문 하나만 더 드려도 될까요? 토크나이져는 어떤 걸 사용하시는 건가요? (arg에서 비워져 있어서 여쭤봅니다.)

아.. 토크나이져는 'beomi/kcbert-large' 를 그대로 넘겨받아서 사용하고, override 하고 싶은 때만 명시하는 것으로 되어 있군요! 그런데 num_labels=5를 추가하려면,

class Model(LightningModule):
    def __init__(self, options):
        super().__init__()
        self.args = options
        self.bert = BertForSequenceClassification.from_pretrained(self.args.pretrained_model)
        self.tokenizer = BertTokenizer.from_pretrained(
            self.args.pretrained_tokenizer
            if self.args.pretrained_tokenizer
            else self.args.pretrained_model
        )

여기서 if self.args.pretrained_tokenizer else self.args.pretrained_model를 지우고, pretrained_tokenizer: str = 'beomi/kcbert-large' 가 되어야할 것 같은데, 맞을까요?

Pretrained Tokenizer가 중요한 것이 아니라,
self.bert = BertForSequenceClassification.from_pretrained(self.args.pretrained_model) <- 이 부분만 수정해주시면 될 것 같습니다 ㅎㅎ

config = BertConfig.from_pretrained('beomi/kcbert-base')
config.num_labels = 5
model = BertForSequenceClassification.from_pretrained('beomi/kcbert-base', config=config)
tokenizer = BertTokenizer.from_pretrained('beomi/kcbert-base')

이런식으로 바꾸면 되는데요.
이것보다 편리한 방법이 있었던것 같은데.. 한번 찾아봐야 할 것 같습니다.

  • Tokenizer세팅은 강제 오버라이딩을 원할때만 수정하는 것이 맞습니다 :)
commented

안녕하세요 :)

도움 주신 덕분에 코드는 돌아갑니다! 정말 감사합니다🙏 수정한 부분은 아래와 같습니다.

class Model(LightningModule):
    def __init__(self, options):
        super().__init__()
        self.args = options

        # multi-label classification을 위해 추가
        self.config = BertConfig.from_pretrained('beomi/kcbert-base')
        self.config.num_labels = 5
        self.bert = BertForSequenceClassification.from_pretrained('beomi/kcbert-base', config=self.config)
        self.tokenizer = BertTokenizer.from_pretrained('beomi/kcbert-base')

accuracy_score를 제외한 3가지(precision_score, recall_score, f1_score) metric 들도 기본 값이 binary 이기 때문에 average 라는 인자를 지정해주었습니다.

metrics로 for 문에 들어가 있어서 각각 따로 직접 지정하였습니다. metrics라는 list는 맞게 구성한 것 같은데, 결과 값에는 4개의 값이 모두 동일하게 나오네요ㅠ

# Acc, Precision, Recall, F1
metrics = [accuracy_score(y_true=y_true, y_pred=y_pred),
    precision_score(y_true=y_true, y_pred=y_pred, average='micro'),
    recall_score(y_true=y_true, y_pred=y_pred, average='micro'),
    f1_score(y_true=y_true, y_pred=y_pred, average='micro')
]

tensorboard_logs = {
    'train_loss': loss.cpu().detach().numpy().tolist(),
    'train_acc': metrics[0],
    'train_precision': metrics[1],
    'train_recall': metrics[2],
    'train_f1': metrics[3],
}

학습 진행되면서 모든 값이 내려가고 값 자체도 매우 작습니다... 제가 시도해볼 부분이 있을까요?

{'train_acc': 0.375,
 'train_f1': 0.375,
 'train_loss': 1.5897319316864014,
 'train_precision': 0.375,
 'train_recall': 0.375}

바쁘신 와중에도 계속 도움 주셔서 감사합니다. 많이 배우고 있습니다.

metric 부분은
https://datascience.stackexchange.com/questions/15989/micro-average-vs-macro-average-performance-in-a-multiclass-classification-settin
위 글을 살펴보면 좋을 것 같습니다.
(Macro avg와 Micro avg가 동작하는 방식이 다릅니다. 간단히 말하자면, multiclass micro는 acc와 같습니다.)

그리고 실제 학습이 되는지 확인하는 것은 loss를 확인해보시면 될것 같습니다.
또, 제가 예시로 보여드린 코드는 bert base model인데 아마 설정값은 bert large기준으로 learning rate가 되어있을 것 같습니다.

learning rate를 batch size에 맞게 적절히 조정해보시면 학습이 제대로 진행되지 싶습니다.

commented

감사합니다! 현재 하이퍼파라미터들을 적절히 조절해보면서 학습 중입니다. 정말 많이 배우고 갑니다. 성과가 생기면 reference로 반드시 남겨두겠습니다 ㅎㅎ

마지막으로, KcBERT 라이센스를 살펴보니까 MIT license 이던데 적혀있는대로 프로젝트 / 논문 / 경진 대회 등에 출처를 밝히고 수정하여 사용하면 되는 걸까요?

다시 한 번 감사드립니다. 건강 유의하세요!

네. KcBERT 인용에 깃헙 주소 등을 표기해주시면 됩니다 :)

commented

네! 모두 해결되었습니다. 해당 이슈는 크로즈하겠습니다ㅎㅎ

감사합니다 :)