boostcampaitech2 / klue-level2-nlp-02

klue-level2-nlp-02 created by GitHub Classroom
0 stars 6 forks source link

실험에서 사용한 Focal loss와 LabelSmoothing loss에 대해서 알아보자! #23

Open j961224 opened 3 years ago

j961224 commented 3 years ago

저는 이번 대회에 loss에 대해 적용습니다. 결론은 전처리 조금(entity marker punct + 한글 ner + 특수문자 보정 및 사우디 등의 언어 삭제)에 3 epoch 시, focal loss 사용 했을 경우에 성능 증가!

But! 전처리 기법 3가지 다 적용 & epoch 3 했을 시, focal loss나 label smooth loss 사용하니 안 할 때보다 성능이 조금 떨어졌습니다!

우선, Focal loss와 LabelSmoothing에 대해 코드로 보면서 알아보기 -> Focal loss LabelSmoothing를 Trainer에 적용한 코드 설명 -> Focal loss와 LabelSmoothing loss 적용 시 결과 순서로 말씀드리겠습니다!

0. Focal loss와 Label Smoothing loss 시도는 왜 했니?

1. Focal loss와 Label Smoothing loss 코드

1-1. Focal loss 코드

Focal loss는 우선 Cross Entropy를 변형한 식으로 class 불균형에 효과를 주고 있습니다. (1−p_t) ^γ 부분이 쉬운 예시에서는 down scaling을 하여 어려운 예시에 집중합니다. => 잘 분류되는 예시를 down scaling해줍니다.

Focal loss 식

xxx

Focal loss 코드

class FocalLoss(nn.Module):
    def __init__(self, weight=None,
                 gamma=2., reduction='mean'):
        nn.Module.__init__(self)
        self.weight = weight
        self.gamma = gamma
        self.reduction = reduction

    def forward(self, input_tensor, target_tensor):
        log_prob = F.log_softmax(input_tensor, dim=-1)
        prob = torch.exp(log_prob)
        return F.nll_loss(
            ((1 - prob) ** self.gamma) * log_prob,
            target_tensor,
            weight=self.weight,
            reduction=self.reduction
        )

F.log_softmax(input_tensor,dim=-1) => log(p_t) torch.exp(log_prob) => p_t

이 값들로 F.nll_loss로 Cross Entropy 역할을 수행하여 예측값 "((1 - prob) * self.gamma) log_prob", 실제값 target_tensor로 loss값 계산을 수행합니다! (F.nll_loss와 torch.nn.CrossEntropyLoss()의 차이는 예측값을 받을 때 다릅니다!)

F.nll_loss의 weight와 reduction은 기본이 None과 mean입니다!

1-2. LabelSmoothingLoss 코드

LabelSmoothingLoss는 hard target([0,1,0,0])을 soft target([0.025, 0.925,0.025,0.025])으로 변경하여 mislabeling 된 데이터를 고려하고 모델 정규화에 도움을 줍니다!

ex) label 0과1이 있는데 label 1이 있다고 100% 확신한다면 반드시 그렇지 않다고 생각하게 해줍니다!

labelsmoothing loss 식

labelsmoothing loss는 Cross Entropy 변형 식입니다!

ls


원래 Cross entropy 식!

본 cross entropy

labelsmoothingloss에는 원래 Cross entropy 식의 y(k) 대신 y(k)' 넣을 예정!

얍


labelsmoothing loss code

class LabelSmoothingLoss(nn.Module):
    def __init__(self, classes=30, smoothing=0.5, dim=-1):
        super(LabelSmoothingLoss, self).__init__()
        self.confidence = 1.0 - smoothing
        self.smoothing = smoothing
        self.cls = classes
        self.dim = dim

    def forward(self, pred, target):
        pred = pred.log_softmax(dim=self.dim)
        with torch.no_grad():
            true_dist = torch.zeros_like(pred)
            true_dist.fill_(self.smoothing / (self.cls - 1))
            true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)
        return torch.mean(torch.sum(-true_dist * pred, dim=self.dim))
pred = pred.log_softmax(dim=self.dim)
true_dist.fill_(self.smoothing / (self.cls - 1))

tensor([[0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172,
         0.0172]])

target 부분에 (1-알파)를 넣습니다!

true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)

tensor([[0.0172, 0.5000, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172, 0.0172,
         0.0172]])
torch.mean(torch.sum(-true_dist * pred, dim=self.dim))

2. Trainer 적용 코드!

이렇게 위에서 짠 loss들을 아래와 같이 dictionary로 불러오면 class를 가져올 수 있게 했습니다!

criterion = {'label_smoothing': LabelSmoothingLoss, 'focal_loss': FocalLoss}

## 원하는 criterion loss 사용!
def use_criterion(criterion_n, **kwargs):
    choose_criterion=criterion[criterion_n]
    return choose_criterion(**kwargs)

HuggingFace 문서를 참고하여 원하는 argument로 받아 criterion loss를 가져올 수 있게 했습니다!


parser.add_argument("--criterion", type=str, default='default', help='criterion type: label_smoothing, focal_loss')

#https://huggingface.co/transformers/main_classes/trainer.html
class MultilabelTrainer(Trainer):
    # Trainer상속을 통한 loss 재정의하는 class!
    def compute_loss(self, model, inputs, return_outputs=False):
        labels = inputs.pop("labels") # "labels" in inputs 기능으로 label 가져오기!
        outputs = model(**inputs) # input으로 모델이 예측!
        logits = outputs.logits # model 결과값
        loss_fn = use_criterion(args.criterion)
        loss = loss_fn(logits, labels)
        return (loss, outputs) if return_outputs else loss

loss를 원래 것을 쓰고 싶다면 args.criterion의 default 값으로 --criterion을 선언 안 하여 원래 Trainer를 사용하고 원하는 loss를 사용하고 싶을 때, --criterion에 loss fucntion 이름을 적어 MultilabelTrainer를 사용합니다!

if args.criterion=='default':
            trainer = Trainer(
                # the instantiated 🤗 Transformers model to be trained
                model=model,
                args=training_args,                  # training arguments, defined above
                train_dataset=RE_train_dataset,         # training dataset
                eval_dataset=RE_dev_dataset,             # evaluation dataset
                compute_metrics=compute_metrics,         # define metrics function
                #data_collator=dynamic_padding,
                tokenizer=tokenizer,
            )

else:
            trainer = MultilabelTrainer(
                # the instantiated 🤗 Transformers model to be trained
                model=model,
                args=training_args,                  # training arguments, defined above
                train_dataset=RE_train_dataset,         # training dataset
                eval_dataset=RE_dev_dataset,             # evaluation dataset
                compute_metrics=compute_metrics,         # define metrics function
                #data_collator=dynamic_padding,
                tokenizer=tokenizer,
            )

3. Focal loss와 LabelSmoothing loss 적용 시 결과

적은 전처리와 Focal loss 유무 결과

focal 적을 때

위의 조건은 entitiy marker (punct) + k_fold 5 + ner(한국어 변형) + 특수문자 보정 및 사우디어, 독일어 삭제는 공통이고 focal loss 유무 결과로 2개 결과 중, 위에 결과가 focal loss 적용한 것으로 조금 더 성능이 올랐습니다!

focal 적을 때 비교

focal loss 유무 loss 변화를 보면, focal loss가 있을 때, 조금 더 안정적으로 loss가 줄어듭니다!

3가지 전처리와 Focal loss와 LabelSmoothing loss 결과

labelsmoothing,focalloss 많을때 비교

형광색 칠한 결과 중, 맨 위의 결과가 기본 loss 쓴 결과로 제일 높고 그 다움 형광색 결과는 labelSmoothing, 맨 아래는 focal loss 결과입니다!

전체f1

micro f1 score 결과로 labelsmoothing loss 결과 > 기본 loss > focal loss 결과 순으로 높습니다!

smoothing

label smoothin loss가 값이 다른 거에 비해 월등히 높은데 찾아보니 loss값 높은 것은 신경 안 쓰셔도 되고 loss 값이 얼마나 안정적으로 떨어지냐가 중요한 것 같습니다!

그래서 보시면 확실히 기본 loss보다는 2개의 loss가 안정적으로 떨어짐을 알 수 있습니다!

4. 향후 방향

label smoothing과 focal loss 둘 다, 예측하는데 hard를 soft하게 변형시키므로 좀 더 epoch 늘릴 때, 유능할 것 같습니다! (저희 5 epoch 시, overfitting이 일어남을 보아 5 epoch 이상 시, 사용하면 좋을 수 있을 것 같습니다.)

추가로 지금 label smoothing loss에서 smoothing을 0.1이나 0.2로 줄여도 될 것 같습니다!

이상입니다! 봐주셔서 감사합니다!

j961224 commented 3 years ago

최대한 focal loss와 labelsmoothingloss가 어떤거고 수식을 코드로 옮긴 것을 최대한 설명하고자 했는데 이해 안 가는 부분은 말씀해 주세요!!

sangHa0411 commented 3 years ago

많이 배워갑니다! 정리해주셔서 감사드려요!