https://karthkk.wordpress.com/2016/03/22/deep-learning-solution-for-netflix-prize/
딥러닝으로 협업 필터링(collaborative filtering) 문제를 푸는 코드입니다.
넷플릭스
는 우리가 다 아는 그 넷플릭스입니다.컨테스트
각 사용자가 영화에 매긴 평점을 학습 데이터로 줍니다. 그리고 사용자가 다른 영화엔 어떤 평점을 줄지를 예측하는 문제입니다. 이걸 이용해서 사용자가 좋아할법한 영화를 추천할 수 있겠죠.
해당 컨테스트는 100만달러의 상금이 걸려있었고 몇차례 잘 진행되었으나 개인정보관련 문제로 소송이 들어와서 중단되었습니다. 이후에도 데이터를 이용해 논문을 쓰는건 막을수가 없어서 사람들이 계속 활용하고 있습니다.
아마 컨텐츠 추천으로는 제일 널리 쓰이는 데이터셋일겁니다.
아마 컨텐츠 추천으로는 제일 널리 쓰이는 데이터셋일겁니다.
요번에 나온 코드
는 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| movie_count = 17771 user_count = 2649430 model_left = Sequential() model_left.add(Embedding(movie_count, 60 , input_length = 1 )) model_right = Sequential() model_right.add(Embedding(user_count, 20 , input_length = 1 )) model = Sequential() model.add(Merge([model_left, model_right], mode = 'concat' )) model.add(Flatten()) model.add(Dense( 64 )) model.add(Activation( 'sigmoid' )) model.add(Dense( 64 )) model.add(Activation( 'sigmoid' )) model.add(Dense( 64 )) model.add(Activation( 'sigmoid' )) model.add(Dense( 1 )) model. compile (loss = 'mean_squared_error' , optimizer = 'adadelta' ) |
별로 아름답게 코드가 안뜨지만 양해 바랍니다.
설명
- [1] 데이터에 있는 전체 영화의 수입니다.
- [2] 데이터에 있는 전체 사용자의 수 입니다.
- [3-6] 영화의 인덱스를 60차원 벡터로, 사용자 인덱스를 20차원 벡터로 바꿔주는 embedding층을 추가합니다. keras문법을 참고하면, 입력은 [[1],[3],[9],[232423],[534]...], 즉 영화의 인덱스를 받고 그 인덱스 하나하나를 60차원의 벡터로 변환해줍니다. 사용자도 마찬가지구요.
- [7-8] 여기에서는 위에서 embedding층의 결과를 다시 입력으로 받습니다. 두 개의 embedding벡터를 이어줍니다.
- [9-16] 그리고 3개의 dense layer, 혹은 fully connected layer, 혹은 일반적인 인공신경망의 층을, 혹은 3개의 MLP를..아무튼 뉴럴넷을 이어줍니다. 최종 출력은 노드가 1개인 스칼라 값이네요. 넷플릭스는 총 5단계 (1,2,3,4,5)로 평가합니다. 따라서 값의 범위가 1-5인데, 이걸 그대로 사용했군요.
- [17] MSE로 loss function을 정해주고 adadelta로 최적화합니다.
여기에서 일어나는 학습을 세 가지로 나눠볼 수 있겠네요.
- 영화 인덱스 → 60차원 벡터
- 사용자 인덱스 → 20차원 벡터
- 80차원의 벡터 [60차원 영화 임베딩 + 20차원 사용자 임베딩] → 스칼라 값 (평점)
이 세 가지 학습의 목표는 평점을 정확히 예측하는 것 이구요.
보통 추천 시스템에서 사용하는 Matrix factorisation과 풀이 과정이 달라서 좀 이해가 안갔는데, 아예 다른 접근법이라고 보면 될 것 같습니다.
생각할 거리
- 출력층의 [1,2,3,4,5]값을 [0.2, 0.4, 0.6, 0.8, 1.0]으로 바꿔주고 (혹은 [0.1, 0.3, 0.5, 0.7, 0.9]가 더 괜찮을지도..) 출력층에도 sigmoid를 적용한 뒤 crossentropy를 쓰거나,
- [1,2,3,4,5]의 범주로 분류하는 분류 문제(classification problem)으로 설정하고 softmax를 쓰면 어떻게 될지 궁금하네요.
- 그 외에 다양한 머신러닝 학습 기법이 어떻게 적용될 수 있을런지도 마찬가지로..
- 이 방법이 정말 테스트셋에서도 잘 된다면 굉장한겁니다. 엔지니어링쪽은 잘 모르지만 일단 새 아이템 엔트리를 추가하기도 아주 간단하고 (학습데이터에 그냥 넣어서 계속 돌리면 되죠) 메모리도 많이 차지할 것 같지 않은데요? 저정도 크기의 파라미터는 GPU메모리에 충분히 들어갈테니...
- 업데이트된 글에 의하면 실제 컨테스트에서 썼던 test set과, 글에 나온것처럼 트레이닝셋을 나눠서 하는것과는 성능 차이가 좀 난다고 하네요. test set의 경우엔 아예 평점을 매긴 날짜 자체가 다르고 등등, 난이도 차이가 있다고 합니다.