일지/네부캠 AI 4기(22.09.19~23.02.14)

20221223금 - movie 10, 4강

제로타이 2022. 12. 24. 01:57

로거

어제 이후로 디버거를 잘 활용할 수 있게 됐는데, 이 코드에서는 logger를 계속 쓰고 있다. 실질적으로 print와 유사한데, 시간도 찍어주고 출력하는 레벨도 정할 수 있어서 사용법만 익히면 좋아보이기는 한다. 그리고 이 놈이 계속 쓰니, 나도 익혀야 제대로 활용할 수 있을 것 같다.
[Python] Logger 사용법 — 잡다한 AI 관련 글들 (tistory.com)

라고 해봐야.. 그냥 디버그 단계로 설정만 해두면 아랫것들은 전부 출력이 되는 것으로 알고 있다. 내가 이전에는 거꾸로 설정을 했었던 것이었다. critical이 가장 적게 출력하는 것이었고만..

년도별 정렬. pretrain. 해봄. train시에는 성능이 좋았다. 드롭아웃 비율이 더 높을 수도 있다. 검증셋을 시퀀스 끝에서 자르니까, 리더보드와는 다르다. 애초에 검증셋을 구성하는 방식이 다르게 작동했다. 
드롭아웃.

데일리 스크럼

다음주 월요일까지 제출해야 하는 이력서 다같이 쓰기! 한번도 경험해본 적도 없고, 쓸 만한 내용도 없어서 쓰면서 계속 곤혹을 치뤘다. 결과적으로는 아직 다 쓰지 못 했는데, 참 어렵네. 그래도 한 번 양식을 정해서 쓰면 그 이후부터는 어느 정도 틀이 잡힌 상태로 잘 쓸 수 있게 되지 않을까 한다.

피쳐 그만 좀 없애..

이 놈이 아무래도 의도와 다르게 동작하는 것 같다. config를 통해 수정할 수 있는 사항.

확실히 여기를 들어갔다 나올 때 이상한 문제가 발생한다. 원래 해당 함수는 정직하게 목록에 나와있지 않은 유저와 아이템에 대한 inter 행을 없애주는 역할을 한다. 내가 봐도 분명히 그게 맞다.

아무것도 없는 것을 드랍하는데 뭐가 드랍이 되겠냐. 근데 막상 거쳐나오면 진짜 싹 사라진다..

간단한 해결 방법. 해당 함수 들어가지 말라고 끄면 되지 않을까? 근데 안 된다.

다시 보니 아랫놈에도 뭔가 있다. 이 놈이 아무래도 핵심인 모양이다.

여기다. 여기에서 뭔가 의도하지 않는 동작이 나오고 있다.

이게 해결책이 되어줄 것 같다. 나는 해당 값의 범위를 나타내는 부분이라고 생각하고 작성을 했었는데, 아무래도 값의 범위가 아니라 갯수의 범위였던 모양이다.

본격적인 트러블슈팅

하나를 넘으니 또 하나가 나온다. 그럼 될 때까지 하는 수밖에. 그래도 디버거를 가지고 하다보니 확실히 코드 보는 것에 점차 더 익숙해지고 있다. 
당장 겪고 있는 문제도 문제지만, gpu가 사용이 되지 않는 이 몹쓸 이유도 알아내야 한다. 아무래도 버전의 문제인 것으로 생각이 되는데.. 어느 것의 버전이 문제인지는 감이 오지 않는다.

에러가 뜨는 곳까지 왔다.  sefl.device는 그냥 cuda인지 cpu인지 나타내는 부분인데 type이 왜 있냐..? 원래 다르게 들어가기라도 해야한다는 말인가? 아무래도 내가 직접 device를 수정하는 것을 원하지 않는 듯하다. 해당 코드도 지워야겠네.

다행이 이제 학습이 원활하게 진행된다. 이제 어떤 부분들을 조심해야 하는지 조금씩 알게 되고 있다. 그동안 다시 gpu가 되게 바꾸는 방법이나 생각해야지. 콘다로 새 환경을 만들고 그 위에 pip로 requirement를 설치하는데, 아무래도 그 과정 상에서 문제가 발생하는 게 아닐까 한다. 그러면 버전을 어떻게 해보는 것이 좋을까? 일단 토치는 홈페이지에 나온 코드로 다운을 받고 이후에 requirements를 설치해보자. 

이제 마지막 부분이다. 나는 범용성을 위해서 inference와 모델 학습 부분을 분리했다.즉 save된 모델을 활용하려고 했던 것이다. 그러나 문제가 있었던 것이..

요딴 에러가 계속 뜨더라는 것. 이걸 해결하기 위해 디버거를 활용해야 했고, 그래서 결국 미루던 깃헙 렉볼을 다운 받기에 이른 것이다.

무언가 이상하다. is_sequntial이면 시퀀스 데이터인지의 여부를 묻는 거 아닌가? 시퀀스데이터가 아닐 경우 이쪽으로 들어오게 돼있는데, 막상 안 쪽에서는 히스토리 관련한 부분을 다룬다. 어떤 이유에서 이렇게 만들어진 것인지 잘 파악이 되지 않는다.

아무래도 이 놈이 핵심이다. 이 부분에 들어가는 이유는 결국 이전에 본 것에 대해 추천을 해주지 않기 위해서 들어가는 것으로 보인다. 그런데, 유저가 이전에 봤던 아이템에 대한 정보가 담겨져 있지 않다. 각 유저의 아이템 히스토리! 이건 절대 none값이 있으면 안 될 텐데, 중간에 none값이 있다는 것이 현재 문제의 시발점인 듯하다.

그럼 어디서 만들어지는지부터 찾아가야지. 괴상한 데이터로더를 세번 정도 거쳐서 들어간 메소드에서 함수에서 나오는 반복문에서 찾은 변수. 0 값은 버린다더니, 정말 0 값에 대해서..?

해결해냈다..어디에서 문제가 나는지 겨우 알아냈다..!

이제 드디어 내가 그제부터 가지던 문제에 접근할 수 있게 됐다. 뭐.. 사실 이 문제를 찾은 것은 어제인데 제대로 추천을 하고 있는가에 대해서 의심이 들어서 확인 작업을 거쳤는데 이미 본 것을 추천하는 경우도 있더라는 것이다. 자그마치 만 명 정도에 대해 시청 이력이 있는 아이템을 추천해주고 있다. 이것은 조금도 바람직한 추천이 아니다. 안 그래도 확인했던 바로, 어차피 안 쪽에서 알아서 라벨 인코딩을 진행을 하는 모양이었다. 그래서 오히려 라벨 없이 진행을 해보는 방향으로 해서 조금 더 확인을 용이하게 하고자 한다.

아하.. 데이터가 스플릿되는 과정에서 몇 가지가 없어지니, 자연스럽게 몇 개는 함수 상에서 없는 정보가 되어버린다. 그 상태에서 관측 아이템을 제외하는 방식을 취하니까, 결과적으로 이런 꼴이 나는 것이다. 이를 해결하려면? 처음부터 데이터셋을 잘 받게 만들어야 한다.
내가 9:1로 스플릿하는 것에 대해 저런 결과를 내고 있다. 학습데이터에서 집계된 놈들만 활용하고 있다, 이 말이렷다.

그래서, 그냥 파일을 수정해버렸다. 어차피 저 옵션은 내가 예측할 때 빼고 쓰지 않을 것이니까 상관이 없다고 생각한다. 
그러나 문제가 발생했다. 특정 리스트가 추가되지 않음에 따라 언팩이 제대로 일어나지 않는 문제였는데, 인자만 수정할 게 아니라 안 속의 함수를 바꾸면 될 일이다. 이건 그다지 어려운 작업이 아니다.

일단 나는 해당 수치를 원한다. 해당 수치는 유저가 본 아이템의 갯수. 이게 정확하게 나와줘야 중복 추천을 막을 수 있게 된다.

그리고 지금은 이런 상태. 정확하게 하나씩 빼먹었다. 계속 보면서 드는 생각인데, 이거 recbole 잘못 만든 거 같다. 버그인 것 같은데.. 아무래도 0을 패딩으로 활용하면서 생기는 문제로 보인다. 

(4강) Collaborative Filtering (2)

딥러닝 모델 기반의 CF를 알아보자. 평점 예측과 추천을 나눠서.

딥러닝 모델 기반 CF

딥러닝 모델의 장점!

  • Nonlinear Tranformation
    렐루, 시그모이드 등의 비선형 활성함수를 통해 복잡한 상호 관계를 포착하기에 용이하다.
  • Representation Learning
    미세한 학습을 잘한다. 표현에 대한 학습을 잘하기 때문에 우리가 구태여 피쳐 엔지니어링을 하는 것의 수고를 줄일 수 있다. 또 다양한 비정형 데이터도 활용하는 것이 가능하다.
  • Sequence Modeling
    시계열 모델을 활용해 시간이나 순서를 고려한 추천이 가능하다.
  • Flexibility
    다양한 프레임워크를 통해 유연하게 코드를 짜는 것이 가능하다.

딥러닝 모델의 단점! 

  • Interpretability
    설명가능하지가 않다. 파라미터가 항상 블랙박스의 영역으로 존재한다. 
  • Data Requirement
    유의미한 성능을 위해 데이터의 양을 많이 필요로 한다. 그래도 트랙 별로 따지자면 Recsys는 NLP나 CV에 비해서는 양호한 편이라고 할 수 있다. 
  • Extensive Hyperparameter Tuning
    비단 딥러닝 만의 문제는 아니지만, 하이퍼 파라미터 튜닝을 할 게 많고 또 영향도 많이 가는 편이다.

기본적으로 딥러닝 기반 CF도 유저-아이템 행렬에 주목한다. 기존의 MF에서 잠재요인에 함수를 곱하여 원래 행렬으 만들어나가는 방식이었는데, 이때의 그 함수가 딥러닝 모델로 바뀌었다고 봐도 무방하다. 이렇게 됨에 따라 잠재요인은 임베딩 층이 된다. 

종류는 무엇이 있을까?

다양한 형태의 모델들이 존재한다. NMF는 각각을 임베딩 층을 거친 후에 MLP에 통과시키는 것. AutoRec은 CF에다가 오토 인코더를 쓴 것. DMF는 거의 처음 보는데, NMF에서 임베딩 층이 없는 케이스로 보인다.

딥러닝이 가지는 장점 중 비선형 함수를 쓴다는 것이 어떤 의미를 가지는가? 세 유저가 있고 그들간의 유사도를 선형적으로 표현한다고 쳤을 때, 유저 4번이 등장하게 되면 선형적으로 유저 4번을 유저 잠재 공간으로 보낼 때 문제가 발생한다. 유저 4번은 유저 1과, 3과 비슷한 편이다. 그러나 어떻게 선을 그려도 가장 비슷하지 않은 유저 2번과 가깝게 표현할 수밖에 없는 것이다.

오토인코더에 대해 제대로 알아보자. 오토인코더는 차원 축소 기법이면서 자가 학습 기법 중 하나이다. 오토 인코더는 인코더와 디코더로 이뤄져 있고, 이는 처음 행렬을 잠재적으로 표현한 후에 다시 되돌리는 과정을 통해 학습을 진행한다. 내부 정보를 요약하는 꼴. 
도대체 무얼 요약하고 무얼 재생성하는 걸까? 일단 원래 행렬의 패턴과 희소한 정보를 요약한다. 그 이후에 추천 문제로 치면 상호작용이 발생할 확률을 재구축하는 것이고, 평점 예측으로 치면 평점값을 재구축하는 것이다. 
학습이 잘 됐는지 파악하기 위해서, 부득이하게 존재하는 상호작용 정보를 조금 떼와야 한다. 이건 사실 어디나 당연하지..

수식적으로는 이렇게 생겼다. Ru는 기존 행렬의 한 행, 유저에 대한 정보라고 볼 수 있다.  l2 노름을 씌운 부분은 관측된 값에 대해서만 최적화를 진행한다는 것이다. 사실 이것도 말로는 당연하기는 하다.

한 유저의 행을 넣고, 그 행을 인코디코딩을 거친다. 현재 그림을 기준으로 1번 유저는 1,2,3,4에 대해서만 관측을 했으니 그와 관련된 정보를 통해서만 최적화를 진행해야 한다.  
학습을 완료하면 비어있는 부분에 대해 예측을 진행한다.

평점 예측에 대한 딥러닝 모델 연구

새로운 아이템에 대해 유저는 몇 점을 줄까!

Restricted Boltzmann Machines for Collaborative Filtering(2007)

RBM(이게 뭔지는 모르겠는데, 알아보지는 않겠다)을 활용했다. 2007년, 거의 처음으로 신경망을 추천에 도입한 모델이라고 한다. 
특징적인 것은, 평점을 분류 문제로 접근했다고 한다. 아무래도 손실함수로 소맥크엔을 썼을 것으로 생각된다.
내가 책 평점을 할 때 생각했던 아이디어가 가장 초창기 아이디어구나. 

AutoRec: Autoencoders Meet Collaborative Filtering(2015)

시간 갭이 어마무시하냐.. 아무튼 기본적인 오토인코더를 추천에 적용! 위에서 본 수식과 그림이 이 논문 기반이다.

코드가 진짜 열라 간단하다. 
참고로 현재 코드는 각 유저에 대해 진행을 한다. 그러니 따지자면 아이템 간의 정보를 학습한다. 이를 바꿔서 유저 간의 정보를 학습하게 할 수도 있는데, 전자가 훨씬 좋다고 한다. 유저가 전체 아이템에 내리는 평점의 비율보다, 아이템이 전체 유저에 대해 내려지는 평점의 비율이 더 높기 때문이라 저자는 설명한다. 

Top-K 추천에 대한 딥러닝 모델 연구

Neural Matrix Factorization

GMF + MLP. 이전에도 본 적 있는 유명한 모델이다. MF의 선형성을 보완하기 위해 단순하게 MLP 층을 concat한다.
근데 후속 연구에서 이 모델이 오히려 일반 MF보다 좋지 않다는 결과가 나온다는 걸 밝히기도 했다고.

Collaborative denoising auto-encoders for top-n recommender systems (2016)

줄여서 CDAE. 일부러 노이즈를 걸어 더 어려운 태스크를 모델에게 던져준다. 오염된 입력값에 대해서도 잘 구축할 수 있도록 하여 일반화 성능을 높이는 것이다. 관측된 것 중 일부를 중간에 0으로 돌려버리기!

추가적으로 유저 노드, Vu를 넣어 유저 임베딩 층을 하나더 넣어준다. 어떤 사용자인지에 대한 정도를 조금 더 전달하는 격. 실질적으로는 그냥 학습이 가능한 유저 편향 정도이다.

이게 목적함수. E가 기댓값이었던가.. 아무튼 로스를 줄이는 방향으로 학습을 한다. 
암묵적 피드백의 경우, 정답만이 데이터로 주어진다. 그래서 없는 값이 정말 결측값인지, 오답인지 알 수가 없다. 이에 대해 이러한 모델들은 전부 오답 샘플링을 진행한다. 없는 몇 개 중 대충 몇 개는 오답이라고 간주하고 학습에 사용하는 방식이다.

코드적으로 매우 간단하다. 빨간 박스 부분을 통해 랜덤하게 드랍을 시킨다. 아래 유저 임베딩 층이 인코더에 들어가는 것 역시 확인된다.

Multi-VAE

이건 미션 2에서도 나오는 모델. multinomial distribution을 활용한 Variational AutoEncoder다. 다항 분포.

독립 변수들에 대한 확률 분포. 주사위와 동전 던지기를 같이 활용하는 분포 정도로 생각할 수 있을 것 같다. 

일단 VAE가 무어냐, 명확한 추론이 불가능한 상황에서 확률적으로 추론하는 모델. 생성 모델의 일종으로, 원래대로 재구축한다기보다 새롭게 형성하는 식의 모델이다.

생성 모델 보면서 겪은 고통이 다시 물밀듯이.. 간단하게만 보자. 
ELBO 자체는 최대화해야 하는 것. 앞 항은 오답에 대한 에러. 이는 최대화시키는 것이 좋다.  두번째 항은 규제항이라 볼 수 있다.

또 앞항에서는 z일 때 x로 가는 것이라 볼 수 있고, 뒷항은 x일 때 z로 가는 것이라 할 수 있는데, 이것은 전형적인 오토인코더의 모습이라고 할 수 있다. 그래서 ELBO가 오토인코더의 관점에서 해석이 되는 것이다.

방금이 VAE고, 여기에서 다항 분포를 활용하는 것이 multi-VAE이다. 정규 분포가 아닌, 다항 분포의 활용. 이렇게 하면 아이템 파라미터의 sum이 1이 되도록 소맥을 씌우게 된다. 그로부터 아이템끼리의 경쟁 관계를 모델링할 수 있다(top K 추천에서 아이템 간의 선호도).

여기에 KL annealing 과정이 들어간다. 처음에는 규제항이 작게 작동하다가 점차 커지게 만들어져 있는 것이다.

간단한 정리.

Embarrassingly Shallow Autoencoders

줄여서 EASE. 얼척없게 저자가 맘대로 스펠링 순서를 바꿔서 줄였다. 아무튼 당황스러울 정도로 얕은 오토인코더.
오토인코더이면서 일종의 유저프리 모델이다.

자기 자신에 대한 추천을 해주는 것을 막기위해 대각행렬을 없앤다. 즉, X 행렬은 아이템 간의 유사도 정보를 담은 아이템-아이템 행렬이란 것이렷다. 즉, 유저 프리 모델의 모양을 가지고 있다는 것이다. 

이런 관점에서 오토인코더로도 해석이 된다. B를 통과하며 분해, 구축을 하는 방식.
또한 이 모델은 매우 간단해서 수식만으로 계산이 가능하다. 그래서 프레임워크 필요없이 넘파이만으로도 구현이 가능하다고 한다. 

회고 및 다짐

이야.. 이거 진짜 골 때리네. 내 의욕을 꺾으면서도 도전 정신을 불태우게 만들고 있다. 이제는 물릴 수 없다. 갈 때까지 가보자. 다른 코드들을 봤을 때 따라할 수 있는 구석이 없었기 때문에, 결국 내가 직접 만든다. 하기만 하면, 좋은 결과를 볼 수 있을 것이라 생각한다. 조금만 더 해보자.