ERD 베이스라인 구조

Cramming An·2023년 5월 18일

Early Risk Detection

목록 보기
5/5

💡 Early Risk Detection 베이스라인 코드가 어떤 flow를 가지는지 알아봅시다.

Dataset

데이터셋을 구성하는 방법입니다.

기본적으로 PAN12를 사용하고 있습니다.

이 데이터는 .json 형식으로 구성 돼 있는데

  • train
  • dev
  • test

로 구성되어 있습니다.

ERDDataset class

이 클래스는 raw dataset을 구축하는 역할을 수행합니다.

크게 다음과 같은 순서로 raw dataset을 구축합니다.

  1. load dataset

    1. 주어진 경로에 대한 .json 파일을 로드합니다.
    2. 데이터와 라벨 list를 리턴합니다.
  2. list 만들기

    1. obj를 원소로 갖는 list를 만듭니다.
    2. 구체적으로 다음과 같습니다.
    self.raw_dataset = [{"text": self.diags[idx], "labels": self.labels[idx]} for idx in range(len(self.diags))]
  3. getitem()

    1. self.raw_dataset를 return 합니다.

SentEmbedDataset

이 클래스는 sentence를 embedding하는 역할을 수행합니다.

📌 많은 경우 raw_dataset을 tokenizer로 encoding을 하고 model의 forward에 넣는 과정이 일반적입니다.

하지만, 베이스라인 모델 같은 경우, 모델 내부에 embedding을 하는 장치가 없기 때문에 미리 임베딩된 데이터셋이 필요합니다.

그러나, 이 부분은 모델 내부에서 embedding이 일어나도록 refactoring이 이루어질 필요가 있습니다.

Input

  • raw_dataset
  • tokenizer(BERT 사용)
  • model(BERT 사용)

Output

  • embedded dataset
    • sentence가 BERT의 CLS 토큰으로 embedding 됨
    • embedded dataset = [전체 대화 수 대화 당 문장 수 768]

📌 embedding을 할 때 batch을 구성하여 모델이 넣긴 하지만,
.map 함수를 쓰면 더 빠르게 연산할 수 있지 않을까 생각이 든다.

최종 데이터셋

**.pickle 형태로 저장합니다.**

pan_BERT = {
            "train_dataset": train_dataset.embedded_diags,
            "dev_dataset": dev_dataset.embedded_diags,
            "train_label": train_dataset.embedded_labels,
            "dev_label": dev_dataset.embedded_labels,
            "test_dataset": test_dataset.embedded_diags,
            "test_label": test_dataset.embedded_labels,
        }

📌 일반적으로는 다음과 같은 형태를 따른다.

pan_BERT = {
            "train": {
									"text": ...,
									"label": 1,
						"dev": ...
													}
        }

따라서, 위와 같은 방식으로 refactoring이 필요하다.

Trainer

현재 Huggingface Trainer 대신 custom Trainer를 사용 중 입니다.

📌 확장 가능성과 유지보수를 위해 Huggingface Trainer를 사용하는 것이 좋아보입니다.

하지만, shape이 일정한 dataset만 input으로 받을 수 있는 문제를 해결해야만 migration이 가능할 듯 보입니다.

예를 들어, 나는 [[16 * 512], [8 * 512], [16 * 512], [1 * 512], … ] 같은 dataloader를 구성하고 싶습니다.

그러나, Huggingface Trainer는 오로지 다음과 같이 dataloader를 구성합니다.
[[16 * 512], [16 * 512], [16 * 512], [16 * 512], … ]

IncrementalTrain

train 메서드 입니다.

이 메서드는 기본적으로 GRU 모델을 train을 염두해 두고 있습니다.

특이한 점은 하나의 datapoint가 여러개의 text를 가지고 있습니다.

input_data가 주어지면 다음과 같이 batch를 구성합니다.

input_data = [N * M]
batch_data = [batch_size * M, ...]

그리고 일반적인 경우 다음과 같이 backward가 진행됩니다.

for batch_data in data_loader:
	probs = model(batch_data, ...)
	losses = loss_func(probs)
	losses.backward()

이 때, 모델은 1개의 datapoint를 parallel하게 연산할 수 있습니다.

다시 말해, 1개의 datapoint는 1번만 model에 들어갑니다.

하지만, 베이스라인 모델은 GRU 계열 모델입니다. 따라서 1개의 datapoint를 linear하게 연산합니다.

다른 말로, 1개의 datapoint는 len(datapoint) 만큼 model이 실행됩니다.

문제는 베이스라인 모델은 [batch_size * datapoint] 라는 형태를 input으로 받지 못하게 설계되어있다는 점입니다.

오직 [datapoint] 만 가능합니다.

따라서 for datapoint in batch: model(datapoint) 형태로 설계했습니다.

베이스라인 모델

BiF_AGRU 라는 모델을 사용했습니다.

자세한 구조는 다음 페이지를 참고해주시기 바랍니다.

BiF_AGRU의 구조

🔍 model_opt.zero_grad()

모델 매개변수의 변화도를 재설정합니다. 기본적으로 변화도는 더해지기(add up) 때문에 중복 계산을 막기 위해 반복할 때마다 명시적으로 0으로 설정합니다.

IncrementalEval

1 epoch이 끝날 때 마다 실행됩니다.

Input

  • model
  • dev_dataset
  • dev_label

Output

  • micro_F1
  • loss

save best model

if last_best >= cur_best:
	torch.save(self.model, model_path)
  cur_best = last_best

Prediction

저장된 best model를 가지고 prediction을 진행합니다.

📌 현재 prediction의 경우 단독적인 .py 되어 있습니다.
이 부분은 Trainer의 method로 편입시킬 필요가 있다고 생각합니다.
또한, Trainer는 이미 저장된 model이 있을 경우 resume 할 수 있도록 init을 할 필요가 있다고 보여집니다.

베이스라인 prediction

profile
La Dolce Vita🥂

0개의 댓글