05.03.(월) 10:00 ~ 2023. 05. 18. (목) 19:00
문장 내 개체 간 관계 추출 — 문장의 단어(Entity)에 대한 속성과 관계를 예측하는 모델 만들기
KLUE(Korean NLU Benchmark) RE(Relation Extraction) dataset
id | sentence | subject_entity | object_entity | label | source |
---|---|---|---|---|---|
0 | 0 | 〈Something〉는 조지 해리슨이 쓰고 비틀즈가 1969년 앨범 《Abbey Road》에 담은 노래다. | {'word': '비틀즈', 'start_idx': 24, 'end_idx': 26, 'type': 'ORG'} | {'word': '조지 해리슨', 'start_idx': 13, 'end_idx': 18, 'type': 'PER'} | no_relation |
{'no_relation': 0, 'org:top_members/employees': 1, 'org:members': 2, 'org:product': 3, 'per:title': 4, 'org:alternate_names': 5,
'per:employee_of': 6, 'org:place_of_headquarters': 7, 'per:product': 8, 'org:number_of_employees/members': 9, 'per:children': 10,
'per:place_of_residence': 11, 'per:alternate_names': 12, 'per:other_family': 13, 'per:colleagues': 14, 'per:origin': 15,
'per:siblings': 16, 'per:spouse': 17, 'org:founded': 18, 'org:political/religious_affiliation': 19, 'org:member_of': 20,
'per:parents': 21, 'org:dissolved': 22, 'per:schools_attended': 23, 'per:date_of_death': 24, 'per:date_of_birth': 25,
'per:place_of_birth': 26, 'per:place_of_death': 27, 'org:founded_by': 28, 'per:religion': 29}
공통 | EDA 공유, 모델 실험 |
---|---|
문지혜 | loss function 구현 및 실험, PLM 모델 실험 |
박경택 | 프로젝트 전반부 PM, custom model 구현 및 구조 변화 실험 |
박지은 | main code refactoring, 데이터 버저닝, prompt 구현 및 실험, custom model 실험 및 사후 분석 |
송인서 | 프로젝트 후반부 PM, 베이스라인 코드 리팩토링, Sweep 코드 작성 |
윤지환 | entity marker, TAPT, embedding layer 구현, 학습결과 사후분석, 앙상블 |
main 브랜치 하나를 운용하여 빠른 기능 개발 및 지속적인 통합이 가능한 협업 방식
코드에 새로운 기능 추가 시 Issue 추가 후 main에 병합하기 전 pull requests를 통한 코드 리뷰
no_relation
(관계 없음)이 압도적으로 많고 org:top_members/employees
와 per:employee_of
가 뒤를 잇는다.sentence만 | sentence + obj_entity | sentence + sub_entity | sentence + obj + sub | 다 같고 라벨만 다른 경우 | |
---|---|---|---|---|---|
겹친 문장 수 (개) | 3,667 | 877 | 1,263 | 47 | 42 |
no_relation
(29%) —> inference output : no_relation
(60%)LB score 73
)으로 학습시킨 모델 선정klue/roberta-large
모델을 실험을 위한 기본 모델로 설정klue/bert-base
, KcELECTRA
, mdeberta
와 같은 모델들도 실험해보았으나 KLUE 데이터로 이미 사전학습을 거친 klue/roberta-large
모델에 성능이 훨씬 못미침[CLS] sub_entity [SEP] obj_entity [SEP]
prompt가 성능향상에 큰 영향을 주는 것을 확인했고 entity 정보를 더 자세하고 직관적으로 전달해보기 위해 시도함
klue/roberta-large
모델을 기반으로 Bi-directional LSTM
과 GRU
layer를 각각 추가하는 두 가지 custom model을 고려하였음
실험군 아키텍처
Bi-LSTM/GRU의 양방향 next hidden states
→ [Batch Norm]
→ [Activation function (GELU)]
→ [Dropout]
→ FC layer
Dropout 유무, 활성화 함수 유무에 따른 성능 비교 (3가지 시드 사용, 평균치)
기본 구조(실험군) | Dropout 제거 (대조군 1) | GELU 제거 (대조군 2) | GELU & Dropout 제거 (대조군 3) | |
---|---|---|---|---|
Micro F1 | 72.778 | 73.264 | 71.897 | 73.422 |
LayerNorm, BatchNorm 추가 여부에 따른 성능 비교 분석
precision
, recall
, f1 score
가 모두 개선되었음을 확인train 데이터에 class imbalance 문제가 있음을 확인하고 cross-entropy loss 대신 focal loss를 도입함
구분 | 내용 | 달성 여부 |
---|---|---|
실험 | 노션을 통한 체계적인 실험 관리: [가설 수립 → 실험을 통한 가설 검증 → 사후 분석]의 프로세스를 노션에 기록 | ⭕️ |
성능 향상을 위한 실험과 더불어 새로운 아이디어를 기반으로 하는 실험 (decoder로 encoder 따라잡기, TAPT, entity embedding) | 🔺 | |
논리와 근거를 바탕으로 하는 실험 전개 | ⭕️ | |
같은 조건의 실험이라도 seed를 바꿔가며 여러 번 진행한 후 평균을 계산하여 실험 결과의 신뢰성 높이기 | 🔺 | |
실험 이후 적극적인 사후 분석 | ⭕️ | |
nohup을 통한 실험 자동화 | ⭕️ | |
GitHub | Git branching 전략 활용 | ⭕️ |
issue 및 Pull Request를 통해 각자 진행하고 있는 task를 파악하고, 앞으로의 계획 수립 | ⭕️ | |
Commit message / branch name / issue template / PR template convention 합의 후 그에 맞춰 작성 | ⭕️ | |
협업 | 프로젝트 시작 전 전체적인 timeline을 구상함으로써 시간을 효율적으로 사용 | ⭕️ |
PM 제도의 도입으로 원활한 회의 및 프로젝트 진행 | ⭕️ | |
Kanban board를 활용하여 각자 어떤 task를 진행중인지 빠르게 확인 | ⭕️ |
모든 실험들에 대한 사후분석을 진행하지는 못했다. → 기록과 분석의 중요성..
LSTM을 추가함으로써 성능이 어떤식으로 좋아지게 된 것인지는 알아냈지만, LSTM의 어떠한 특징 때문에 그러한 변화가 일어났는지는 알아내지 못했다.
→ architecture에 변화를 줄 때에는 해당 task의 SOTA 모델의 architecture를 참고하자
Decoder 계열의 모델로 encoder 계열의 모델의 성능을 따라잡아보려는 시도를 계획했으나 실험까지 이어지지는 못했다.
TAPT 및 entity embedding 실험을 진행해보았지만, 그 과정에서 발생한 문제들을 완전히 해결하지는 못했다.
ChatGPT와 대화하는 스페셜 미션을 즐겁게 수행하기
Debugger를 적극적으로 활용하기
실험 전 문제에 대한 사전 조사를 통해 보다 다양한 논문을 소화하고 프로젝트에 반영하기
코드 리뷰 철저히 하기
깃 저장소에서 더 완성된 컨벤션 활용하기
가능하다면 여러 대의 GPU를 동시에 효율적으로 활용하는 방법 적용해보기
이전 대회에서 아쉬웠던 문제 정의파트를 강화하기 위해 entity간의 관계를 어떻게 하면 모델이 잘 알아볼 수 있을까 계속 고민했던 것 같다. RE task에서 좋은 성능을 냈던 여러 선행 논문(entity marker, encoder prompt) 내용들을 직접 구현하거나 entity의 위치를 직접 표현해주는 embedding layer를 추가해서 학습시켜보기도 했다.
비록 모든 시도가 성능개선으로 이어진 것은 아니었지만 모델을 가져다쓰는 것보다 모델의 input과 output에 대해 이해하고 원하는데로 바꿔보는 시도들이 새로웠고, 추후엔 좀 더 엄밀하게 가설을 세워서 적용시켜보고 싶다는 생각이 들었다.
이유를 생각하고 논리적인 흐름이 있는 분석을 해본 경험이 굉장히 재밌었다. 예를 들어, 분석 초기에 class imbalance를 해결하기 위해 도입한 focal loss가 여러 인자조합 실험으로도 성능개선이 미미했지만 이유를 알지 못했다. 하지만 후반부로 갈수록 여러 변화를 거치며 모델성능이 나아졌고 valid data 예측결과를 분석해보며 나름의 이유를 찾았다. focal loss는 적은 수의 label에 가중치를 많이 주고 많은 수의 label에 가중치를 적게 줘서 loss를 갱신하는데 모델은 이미 적은 수의 label은 잘 예측하고 있었고 오히려 no_relation이라는 많은 수의 label을 잘못 예측하고 있었다. 따라서 cross entropy loss를 쓰되 no_relation label의 precision과 recall 값을 이후 분석의 주요 쟁점으로 삼고 모델의 성능을 확인하는 것을 고려하게 되었다.
이전과는 달리 칸반보드를 활용해 팀원들이 현재 어떤 작업을 하는 중인지 실시간으로 파악할 수 있게 되었다. 그에 따라 팀원간 소통이 더 원활해졌으며 작업들의 우선순위를 정하고 효율적으로 일정을 관리하기 편해졌다. 팀원과 더 긴밀히 연결된 느낌이 드는 것이 무엇보다 마음에 들었다.
중반부부턴 노션 기록과 함께 깃허브의 Issue와 PR을 적극적으로 활용했다. main 브랜치에 직접 작업하지 않고 구현하고자 하는 기능에 관한 Issue를 발행하고 해당 Issue 이름으로 브랜치(ex. feat/#7-entity_func)를 파서 구현한 다음 Pull Request를 날려 최소 두 명의 리뷰어에게 리뷰를 받고 merge하는 형태를 취했다. 또한 정해진 컨벤션으로 관리가 되다보니 특정 기능과 관련된 Issue나 commit을 찾는 것도 용이했다. 깃허브를 통한 협업이 전엔 잘 이루어지지 않았던 느낌이 있었는데 이번 대회에선 좀 더 체계적으로 관리가 되었던 것 같았다.
Issue들이 시간 순서로 정리되어있어 프로젝트가 어떤 흐름으로 진행되는지 한눈에 파악하기 쉬웠고 팀원들이 지금 어떤 작업을 하는지 알기도 쉬워서 노션만 사용하던 때보다 많이 개선되었던 점이 좋았다. 이전엔 Pull Request라는 작업이 왜 필요한지 살짝 이해되지 않았으나 생각이 바뀌었다. 팀원들의 리뷰를 받으며 생각치 못한 오류를 고치고 더 나은 코드로 바꾸면서 발전시켜나가는 과정이 배워가는 입장에서 효율적이었다. 또한 내가 팀원들의 코드를 리뷰하며 다시 한번 되새기고 코드개선을 위한 토론을 하며 실력을 쌓기에도 적절했다.
대회의 train, test data로 Task adaptive pre-training을 MLM task로 정의해서 30epoch 정도를 진행해봤으나 성능이 반대로 떨어졌었다. 참고한 논문이 제안한 100peoch에 미치지 못하는 학습과 파라미터 설정이 달라서 오히려 역효과가 났었고 이미 KLUE dataset으로 pre-training이 된 모델을 사용해서 TAPT가 큰 의미가 없었던 것 같다. 논문이 좋다고 해서 무조건 내 task에 적용시켜선 안되고 더 엄밀하게 조건을 따져서 맞게 변형시켜 사용해야 한다는 사실을 깨달았다.
다음 대회, 앞으로의 프로젝트에선 최우선으로 ‘문제 정의’를 명확히, 끝나기 직전까지도 지속해서 해야겠다는 생각을 했다. 가설을 세울 때마다 근거를 바탕으로 정확한 문제를 정의하고, 논리적인 흐름에 따라 해결해야한다는 것을 다시 한번 깨닫게 되었다. 왜 모든 마스터, 멘토님들이 강조하고 또 강조하는지 어느 정도 감이 잡히는 것 같다.
마지막으로 시도하는 것을 두려워하지 않을 것이다. 한정된 시간 속이지만 해야하는 것들에 매몰되지 말고 다양하고 새로운 시도들을 체계적으로 해보며 경험을 더 쌓는것이 필요하다. 남들과 같은 방법, 분석, 경험으론 결코 좋은 실력을 쌓을 수 없다. 시도해보는 것에 끝내지 말고 실패에 대한 원인 분석과 개선방안을 마련하고 성공하면 기록과 공유를 생활화해야 할 것이다.