AIFFEL/Exploration

[E-14] 아이유팬이 좋아할 만한 다른 아티스트 찾기(추천 시스템)

알밤바 2022. 2. 24. 16:28
728x90
반응형

해당 포스팅은 AIFFEL에서 제공한 학습자료를 통해 공부한 것을 정리한 것임을 밝힙니다.

 

학습 목표

  • 추천 시스템의 개념과 목적을 이해한다.
  • Implicit 라이브러리를 활용하여 Matrix Factorization(이하 MF) 기반의 추천 모델을 만들어 본다.
  • 음악 감상 기록을 활용하여 비슷한 아티스트를 찾고 아티스트를 추천해 본다.
  • 추천 시스템에서 자주 사용되는 데이터 구조인 CSR Matrix을 익힌다
  • 유저의 행위 데이터 중 Explicit data와 Implicit data의 차이점을 익힌다.
  • 새로운 데이터셋으로 직접 추천 모델을 만들어 본다.

 


1. 추천 시스템이란?

온라인 콘텐츠 서비스에서 데이터 분석과 AI 기술을 접목한 추천 시스템의 활용은 이제 필수가 되고 있다.

음원 서비스, 스트리밍 서비스 등 다양한 곳에서 활용하고 있다.

 

협업 필터링(Collaborative Filtering) 방식과 콘텐츠 기반 필터링(Contents-based Filtering) 방식이 있다.

 

* 협업 필터링

- 다수의 사용자의 '아이템 구매 이력 정보'만으로 사용자 간 유사성 및 아이템 간 유사성을 파악

- 아이템과 사용자 간의 행동 또는 관계에만 주목할 뿐 아이템 자체의 고유한 속성에 주목하지 않음

 

* 콘텐츠 기반 필터링

- 아이템의 고유한 정보'를 바탕으로 '아이템 간 유사성'을 파악

- 아이템 자체의 속성에만 주목하고 사용자와 아이템 간의 관련성에는 주목하지 않음

 

여기서, '협업 필터링'을 바로 사용할 수 없는 제약 조건이 있다.

* 시스템이 충분한 정보를 모으지 못한 사용자나 아이템에 대한 추론을 할 수 없는 상태인 콜드 스타트(Cold Start) 상황

* 계산량이 너무 많아 추천의 효율이 떨어지는 상황

* 사용자의 관심이 저조한 항목의 정보가 부족하여 추천에서 배제되는 상황

 

서비스 시작 시 처음 접속한 사용자에세 관심있는 항목과 관련된 정보를 요구하는 경우가 많다. 

그 이유는 사용자에 대한 초기 정보가 없는 상황이기에 사용자 기반 추천을 전혀 할 수 없다. 그래서 콘텐츠 기반 필터링 방식의 추천만 가능한데, 이를 보완하여 처음부터 사용자 특성에 맞는 맞춤형 서비스를 제공하기 위함이다.

만약 사용자 맞춤형 추천을 제공하지 못한다면 모든 초기 사용자에게 같은 화면을 제시하게 된다.

그렇게 된다면 모든 사용자들이 처음 추천받은 콘텐츠 위주로만 시청하게 되어 추천 시스템이 빠지기 쉬운 '필터 버블'의 문제를 야기하거나 '추천의 다양성을 저해'할 수 있는 위험이 발생한다.

 

추천 시스템은 아이템이 매우 많고 유저의 취향이 다양할 때 유저가 소비할 만한 아이템을 예측하는 모델이다.

예시)

* 유튜브 : 동영상이 매일 엄청나게 많이 올라오고 유저의 취향(게임 선호, 뷰티 선호, 지식 선호, 뉴스 선호)이 다양함

* 페이스북 : 포스팅되는 글이 엄청 많고 유저가 관심 있는 페이지, 친구, 그룹은 전부 다름

* 아마존 : 카테고리를 한정해도 판매 품목이 엄청 많고 좋아하는 브랜드, 구매 기준이 다양

 

2. 사용자의 명시적/암묵적 평가

추천 시스템은 사용자들이 아이템을 얼마나 선호하는지를 모델링 하기 원한다. 그럴려면 사용자의 아이템 선호도를 말해 주는 '유저 행동 데이터셋'이 필요하다.

'좋아요나 별점'처럼 선호도를 명시적(explict)으로 나타내는 데이터도 있지만 서비스를 이용하면서 자연스럽게 발생하는 암묵적(implicit)인 피드백도 사용자의 아이템에 대한 평가를 알 수 있는 단서가 될 수 있다.

 

암묵적 피드백 데이터셋의 특징은 다음과 같다.

* 부정적인 피드백이 없다.

* 애초에 잡음이 많다.

* 수치는 신뢰도를 의미한다.

* 암묵적 피드백 데이터셋의 평가는 적절한 방법을 고민해봐야 한다.

 

암묵적 평가가 될 수 있는 데이터는 플레이 횟수, 플레이 시간, 클릭 수, 구매 여부, 플레이 스킵여부, 검색 기록, 방문 페이지 이력, 구매 내역, 마우스 움직임 기록이 될 수 있다.

 

만약, 어떤 유저가 아티스트의 곡을 한 번만 들었다면 유저는 이 아티스트를 좋아하는 걸까 싫어하는 걸까?

이것에 대한 명확한 정답은 존재하지 않는다. 이런 애매한 암묵적 데이터야말로 도메인 지식과 직관이 활용되어야 하는 영역이다.

 

3. Matrix Factorization(MF)

[ - 출처: CuMF_SGD: Fast and Scalable Matrix Factorization(https://arxiv.org/pdf/1610.05838.pdf) ]

이번 프로젝트에서는 m명의 사용자들이 n명의 아티스트에 대해 평가한 데이터를 포함한 (m,n) 사이지의 평가 행렬(Rating Matrix)을 만든다.

행렬 중 일부는 데이터가 채워져있지만, 나머지는 비어있다. 추천 시스템의 '협업 필터링'이 이런 평가 행렬을 전제로 한다. 만약 우리가 이 평가 행렬의 비어있는 부분을 포함한 완벽한 정보를 얻을 수 있다면 완벽한 추천이 가능해질 것이다.

 

추천 시스템의 다양한 모델 중에 'Matrix Factorization(MF, 행렬 분해)' 모델이 있다.

'MF' 모델은 2006년 Netflix에서 백만 달러의 상금을 걸고 개최한 자사 추천 시스템의 성능을 10% 이상 향상시키는 챌린지를 계기로 알려지게 되었다.

 

(m, n) 사이즈의 행렬 R을 (m, k) 사이즈의 행렬 P와 (k, n) 사이즈의 행렬 Q로 분해한다면 R은 P와 Q의 행렬곱으로 표현이 가능할 수 있다는 아이디어이다. 대체로 k는 m이나 n보다 훨씬 작은 값이기에 계산량 측면으로도 훨씬 유리해진다.

아이디어가 단순함에도 불구하고 MF 모델은 성능이 준수하고 Scalability가 좋아서 많이 사용되는 모델이다.

 

[ 출처: https://developers.google.com/machine-learning/recommendation/collaborative/matrix ]

위의 이미지는 MF 모델을 사용자에게 영화를 추천하는 모델에 대입해서 그린 이미지이다. (m=4, n=5, k=2인 MF 모델)

(m, k) 사이즈의 Feature Matrix P는 k차원의 벡터를 사용자 수만큼 모아놓은 행렬이다.

그렇다면 첫번째 벡터 P0 = (1, 0.1)은 빨간 모자를 쓴 첫 번째 사용자의 특성(feature) 벡터가 된다. Q 행렬의 첫 번째 벡터 Q0 = (0.9, -0.2)는 해리포터 영화의 특성 벡터가 된다. MF 모델은 이 두 벡터를 내적해서 얻어진 0.88이 바로 R0,0으로 정의되는 사용자의 영화 선호도로 보는 모델이다.

 

모델의 목표는 모든 유저와 아이템에 대해 k-dimension의 벡터를 잘 만드는 것이다.

벡터를 잘 만드는 기준은 유저 i의 벡터(Ui)와 아이템 j의 벡터(Ij)를 내적했을 때, 유저 i가 아이템 j에 대해 평가한 수치(Mij)와 비슷한지이다.

 

4. CSR (Compressed Sparse Row) Matrix

유저가 36만명이고 아티스트는 29만명이다. 이를 행렬로 표현하고 행렬의 각 원소에 정수 1개(1byte)가 들어간다면 36만*29만*1byte  97GB가 필요하다. 이렇게 평가행렬 용량이 커진 이유는 유저가 들어보지 않은 아티스트에 대한 정보까지 모두 행렬에 포함되어 계산되기 때문이다.

총 아티스트는 29만 명이 넘기에 평가행렬 내의 대부분의 공간은 0으로 채워진다. 이런 행렬을 'Sparse Matirx'라고 한다. 이런 메모리 낭비를 최소화하기 위해서는 유저가 들어본 아티스트에 대해서만 정보만을 저장하면서 전체 행렬 형태를 유추할 수 있는 데이터 구조가 필요하다.

 

이럴 때, 좋은 대안은 'CSR(Compressed Sparse Row) Matrix'이다. CSR Matrix는 Sparse한 matrix에서 0이 아닌 유효한 데이터로 채워지는 데이터의 값과 좌표 정보만으로 구성하여 메모리 사용량을 최소화하면서도 Sparse한 matrix와 동일한 행렬을 표현할 수 있도록 하는 데이터 구조이다.

 

CSR Matrix는 data, indices, indptr로 행렬을 압축하여 표현한다.

* data : 0이 아닌 원소를 차례로 기입한 값이다.

* indices : data의 각 요소가 어느 열(column)에 있는지를 표현한 index이다.

* indptr : 각 행(row)에서 0이 아닌 첫 번째 원소가 data 리스트에서 몇 번째에 해당하는지와 마지막에 data 벡터의 길이를 추가한 값이다. 이를 통해 data의 요소들이 어느 행(row)에 있는지 알 수 있다. 0이 아닌 원소가 없는 경우, 그 다음 행의 값과 같은 값을 넣는다.

 

data = [1, 2, 3, 4, 5, 6]

indices = [0, 4, 1, 3, 0, 3]

indptr = [0, 2, 4, 4, 6]

 

이를 통해 data[0:2]는 첫 번째 행, data [2:4]는 두 번째 행, data[4:4]는 세번째 행, data[4:6]는 네 번째 행에 위치함을 나타낼 수 있게 된다.

 


Exploration의 경우, 프로젝트를 수행하는 학습 과정이기에 코드 위주이다.

그 중에서 코드를 구현하기 위한 기본 이론들을 정리해보았다. 완성된 프로젝트는 깃헙에 올릴 예정이다.

728x90
반응형

'AIFFEL > Exploration' 카테고리의 다른 글

[E-15] 문자를 읽을 수 있는 딥러닝 (OCR)  (0) 2022.02.25