Open chanmuzi opened 1 year ago
token_type_ids
를 사용하고 있다.tokenizer에 입력을 줄 때, return_token_type_ids=True 옵션을 주어야지 반환된다. 두 개 이상의 문장이 합쳐졌을 때 앞의 문장인지 뒤의 문장인지를 0,1로 구분해준다. 만약 max_len = 10이고 앞 문장의 길이는 3, 뒷 문장의 길이가 5인 경우 다음 결과가 반환된다.
token_type_ids = [0,0,0,1,1,1,1,1,0,0]
marker를 추가하는 아이디어는 Relation Extraction 당시 query에 대한 marker를 추가하던 작업에서 착안한 것이다. 따라서 본 프로젝트에 적용한 것과 Relation Extraction 프로젝트에 적용한 코드를 비교해보았다.
Relation Extraction
def forward(self, input_ids, attention_mask):
last_hidden_state, pooler = self.model(input_ids=input_ids, attention_mask=attention_mask).to_tuple()
logits = self.regressor(pooler)
return logits
여기서는 model에 입력으로 input_ids
, attention_mask
를 사용한다.
따라서 기존 context에 query를 추가함과 동시에 query와 context를 구분해주는 [SEP] 토큰이 들어가고 모델은 이 둘을 구분하게 되어 이 작업이 유의미한 영향을 가졌던 것으로 볼 수 있다.
inputs = {
'input_ids': valid_batch['input_ids'].to(self.device),
'attention_mask': valid_batch['attention_mask'].to(self.device),
'token_type_ids': valid_batch['token_type_ids'].to(self.device),
'bbox': valid_batch["bbox"].to(self.device),
'image': valid_batch["image"].to(self.device),
}
이와 달리 애초에 token_type_ids
또한 모델에 입력으로 주어진다.
즉, question과 context를 구분해주는 embedding이 이미 존재했던 것이다.
따라서 special token을 추가하는 이 작업이 큰 영향을 주지 못한 것으로 볼 수 있다.
작업자의 미숙함으로 dataset의 question 앞뒤에 special token을 추가하는 작업을 train dataset에 대해서만 진행했다.
따라서 validation이나 inference 과정에서 추가된 special token은 오히려 noise
가 되었을 가능성이 높다.
위에서 기술한 바와 같이 이미 token_type_ids
라는 embedding이 존재하는 상황에서 special token을 추가하는 작업 자체가 무의미한 것이 될 수 있으나,
모델이 기존에 비해 question에 더욱 집중할 수 있게 되는지는 valid/test set에 대해서도 동일한 작업을 진행하여 실험한 뒤 결과를 분석해봐야 알 수 있을 것이다.
Question Marker를 추가한 이유
모델이 추론을 질문을 이해하고 답변을 도출하는 과정에서 어떤 부분에 집중하게 되는지 확인한 결과에 따르면, text 기준 Question + Context의 구조에서 Question에는 거의 가중치를 두지 않는 경향이 있음을 알 수 있었다. 따라서 질문에 대한 보다 정확한 이해를 할 수 있도록 Question의 앞뒤에 각각 [QUE], [/QUE] 라는 special token을 추가하고 그 결과를 이전과 비교해보기로 했다.
Question Marker 추가 방법
tokenized_sentences = self.tokenizer( train_data['question'], train_data['words'], train_data['boxes'], truncation="only_second", # max_seq_length까지 truncate한다. pair의 두번째 파트(context)만 잘라냄. max_length=self.max_length, stride=self.stride, return_token_type_ids=True, # BERT 모델일 경우에만 반환 return_overflowing_tokens=True, # (List[int]) : 여러개로 쪼갠 문장들이 하나의 같은 context라는 것을 나타내주는 리스트, batch 단위일때 사용합니다. padding="max_length", add_special_tokens=True # 추가 토큰 반영해주는 옵션 )
이때 dict 형태로 special token 리스트를 전달해야 제대로 반영된다. special token이 추가되었는지는
tokenizer.__call__
을 통해 확인할 수 있다.여기서는 model이 한 번 packaging 되어 있으므로 model.model로 접근을 해야한다. 우리가 추가한 special token은 두 개이므로 기존 tokenizer의 vocab size에 2를 더해준다.
참고로 위 코드를 통해 input_embedding에 대한 정보를 확인할 수 있다.
Question Marker를 적용하기 전후의 결과 비교
적용하기 전
적용한 후
여러 카테고리 중 우리는 'Figure/Diagram' 유형에 집중하기로 했다. 결과 분석 당시에도 해당 유형에 대해 분석을 진행했고 그 결과를 기반으로 작업을 진행했으나 유의미한 성과는 없었다. 'Figure/Diagram'에 대해서는 다소 유의미한 성능 향상이 있지만 다른 유형에 대해서는 오히려 성능이 떨어지게 된 것을 알 수 있다.