이번 Movie Rec은 5월 중순부터 6월 중순까지 이어지는 네이버 AI 부캠 대회이다.
과정에서 성능적인 향상은 이끌어내지 못했지만 깊게 고민해봤던 시도가 있어 적어두었다.
개발한 코드는 다음 레포에서 볼 수 있다.
https://github.com/boostcampaitech5/level2_movierecommendation-recsys-03
💬 간단한 모델 소개
S3Rec은 SASRec에 side info를 사전학습시켜 user-item간 interaction을 학습, 추론 시키는 모델이다.
사전학습할때는 아래 4개의 방식으로 학습하며, loss는 weight를 다르게 해서 더한 값을 쓴다.
📝 기존 구조
레포주소: https://github.com/aHuiWang/CIKM2020-S3Rec/tree/master
S3Rec 레포에서 볼 수 있는 구조는 아래와 같은 구조로 같은 클래스에서 pretrain과 finetune 각각의 메서드를 만들어 사용하는 방식이였다.
때문에 단순히 pretrain한 후 pt파일을 생성하면 finetune하면서 불러올 수 있다.
(같은 클래스니까 당연히 문제될게 없다)
그런데 Lightning을 도입하려 하니 문제가 이만저만이 아니였다.
1. pretrain과 finetune의 학습 과정이 다름
LightningModule 객체를 만들면 우리가 더 이상 각각의 메서드를 만들어 사용할 수 없다.
학습 코드는 LightningModule.training_step에 들어가는데, 마땅히 좋게 분리할 방법이 없다.
2. 새로운 모델 추가 분리
우리는 베이스라인 작성부터 BERT모델을 사용하고 싶은 마음이 있었고, 완전히 동일한 과정으로 모델을 학습하려 했다.
지금의 구조에선 새로운 레이어를 추가할 수 없고 SASRec이외의 다른 모델을 사용할 수 없다. (상속하는 방법이 있지만 좋은 방법이 아니였음)
3. 필요없는 레이어들
Finetune에서 사용하는 레이어와 Pretrain에서 사용하는 레이어가 다르다.
기존 구조에선 Pretrain은 전부를 사용하지만, Finetune은 위 그림에서 핑크색 부분만 사용한다.
Finetune입장에선 공간 활용이 아쉽다.
🧩 상속을 이용한 방법
여러 의견이 나왔지만 처음 해보는 방법들이라 최대한 기존 방식과 유사한 방식을 골랐다.
주요 개념은 "상속을 이용해 분리를 한다는 것"
장점은 아래와 같다.
- 기존 방식과 같이 하나의 클래스에 모든 레이어를 넣는 개념은 동일하다.
- 구현이 간단하고 개념도 간단한 방식이다.
- datamodule, 원한다면 trainer까지 완전한 분리가 가능해보인다.
😣 알지 못했던 문제
코드를 완성하고 실행해보았지만 예상치도 못한 이슈에 부딪쳤다.
우리는 pt파일을 저장할때, lighning에서 제공하는 checkpoint callback을 이용해 lightningModule 자체를 덤핑하는 방식을 사용했는데, pretrain된 모듈을 불러올때 에러가 발생했다.
사실 이유는 간단한데, 우리가 저장한 것은 Pretrain 모듈(이하 S3Rec)이고, Finetune 모듈(이하 SASRec)에서 불러오기를 시도했기 때문이다.
그럼 각 클래스의 super만 pt파일로 저장하면 된다! 라고 생각해도 Lightning은 그런걸 지원하지 않는다. (게다가 DataModule에 대한 정보도 같이 pt파일에 들어가는 것 같다)
상속의 문제를 그대로 답습한 느낌이 들어 아주 괜찮았던 경험이였다.
상속에 관한 문제는 여기 → https://mangkyu.tistory.com/199
🧩 컴포지션을 이용한 방법
사실 멘붕의 순간을 틈타 노리고 있던 컴포지션을 도입해버렸다
이 방식은 멘토님께서 잠시 설명해주신 것과 비슷한 방법인것 같다.
컴포지션은 상속과 달리 사용개념이다. (상속은 is-a, 컴포지션은 has-a)
S3Rec와 SASRec은 SASRecModule을 상속하지 않고 SASRecModule을 사용한다.
얻는 장점은 다음과 같다.
- 클래스 의존도(결합도)를 낮출 수 있다.
- 원하는 부분만 가져올 수 있기 때문에 객체가 가벼워진다.
pt파일로 저장하는 부분은 checkpoint callback을 더이상 사용하지 않았다.
checkpoint callback은 LightningModule을 저장할때만 쓰고, 모델 자체의 파라미터를 저장하는 부분은 따로 함수로 정의했다. (그림에선 표현하지 않았다)
결론적으로는 핑크색 부분만 pt파일로 저장해 SASRec 모듈에서 불러오게 수정했다.
⭐️ S3Rec의 AttributePrediction 분리
기존 S3Rec는 하나의 side info 밖에 활용하지 못한다.
정확히 하면 장르 정보만 활용하는데, 우리는 영화의 발매년도, 감독, 작가도 활용하고 싶었다.
때문에 S3Rec에서 pretrain에 활용하는 AAP, MAP, MIP, SP중 side info를 활용하는 AAP, MAP를 S3RecModule에서 떼어내고,
AttributePredictionModule로 분리해 S3RecModule이 여러개의 AttributePredictionModule를 가지게 하도록 했다.
이렇게 해서 다음과 같이 여러 side info를 pretrain에 활용할 수 있게 되었다.
class S3RecModule:
attributePredictionModules: list[AttributePredictionModule] = []
👏 마무리
그래서 결국 모듈화해서 성능 향상을 이끌어냈냐 하면 알수없는 이유로 모델 성능이 좋지 않았다.
(아마 라이트닝을 도입하면서 뭔가 실수를 한 것이 아닐까 싶다)
또한, 장르의 수는 적지만, 년도나 작가, 감독의 수는 보다 꽤 커서 학습이 정말 오래 걸렸다.
아쉽지만 이렇게 모듈화 할 수 있다는 것을 경험했다고 생각하자.
'프로그래밍 > 부스트캠프 AI' 카테고리의 다른 글
[Imgenie] https와 쿠키를 도입했음 (0) | 2023.09.27 |
---|---|
[Imgenie] 회고 (0) | 2023.08.28 |
[DKT] Github Action 테스트 도입 (1) | 2023.05.20 |
[DKT] lgbm에 label을 feature로 넣으면... (0) | 2023.05.12 |
DKT - EDA 해보기 (1) | 2023.05.06 |