LINERVA-WALK : Pixie 기반 랜덤 워크 추천 모델링

안녕하세요, 머신러닝 엔지니어 카터입니다. 라이너 기술 블로그를 통해 연재되고 있는 추천 시스템 포스트에 관심을 가져주신 분들이라면, 라이너가 Pinterest의 기술 발전사에 많은 관심을 가지고 있다는 사실을 쉽게 눈치 채셨을 것 같습니다. 실제로 라이너는 Pinterest가 추천 시스템을 구축해온 과정과 앞으로 해결할 문제에 큰 관심을 가지고 있습니다. 많은 기업들이 Pinterest의 기술을 벤치마크하고 있겠지만, 그 중에서도 라이너가 Pinterest를 관심 있게 보는 이유는 아래와 같습니다.

먼저, “콘텐츠” 중심 플랫폼을 표방하는 Pinterest가 추천하는 대상이 철저히 콘텐츠인 “Pin“에 맞추어져 있기 때문입니다. PinterestTitle, Description, Image, Author 등의 메타 정보로 구성되는 Pin을 사용자에게 최대한 개인화되게 추천해 영감을 불러 일으키겠다는 미션을 지니고 있습니다. 라이너 역시 “Help People Get Smart Faster” 라는 미션을 달성하기 위해 사용자의 성장에 도움이 될 수 있는 생산적 콘텐츠를 최대한의 개인화를 통해 추천해주기 위해 추천 시스템을 개선해나가고 있습니다.

이 과정에 있어 Pinterest가 추천 시스템이 제공하는 핵심 가치가 인물 오브젝트 중심인 Facebook, Instagram, Twitter 등과 달리 콘텐츠 오브젝트 중심인 점이 참고할 점이 많다고 판단하고 있습니다. 따라서 라이너 역시 Pinterest와 마찬가지로 콘텐츠 중심으로 모델링 사고를 하고, 콘텐츠 간 발생하는 Structural Information 등을 고려하는 방향으로 마일스톤을 설정해 문제를 해결해나가고 있습니다.

다음은 그래프 기반의 추천 시스템을 상용 시스템에서 가장 성공적으로 구축한 Pinterest가 보인 Bipartite 그래프의 모습이 라이너에서 관리 중인 엔티티들과 매우 흡사하기 때문입니다. Pinterest는 사용자 플랫폼을 통해 Pin을 저장할 수 있도록 설계되어 있습니다. 그리고 저장한 Pin들을 Board 라는 개념에 모아볼 수 있도록 되어 있습니다. Pinterest의 이러한 Pin-Board 기반의 Bipartite 그래프 개념은 Pinterest가 운용 중인 여러 추천 모델의 토대가 되고 있습니다.

라이너 내 Page-Folder 엔티티

이와 유사하게 라이너는 하이라이트가 칠해진 PagePage들이 모일 수 있는 Folder 엔티티를 설계해 서비스에 활용하고 있습니다. 그리고 두 오브젝트 간 관계를 활용해 Page-Folder 기반의 Bipartite 그래프를 구축한다면, Pinterest가 보여준 그래프 기반의 추천 시스템을 라이너 서비스에도 충분히 이식시킬 수 있다고 판단해 Pinterest의 추천 시스템 발전사를 계속해서 학습하고 라이너 시스템에 녹이기 위해 노력하고 있습니다.

LINERVA-WALK

오늘은 이러한 노력 중에서도 현재 서비스에 실제로 적용 중인, Pixie 기반의 랜덤 워크 추천 모델인 LINERVA-WALK 모듈을 소개해보고자 합니다. Pixie는 많은 분들이 아시듯, 2017년 Pinterest가 현재 추천 시스템의 전신격 모델로 대중에 공개한 마스터 피스 논문입니다. 실제로 많은 기업이 Pixie의 영향을 받아 랜덤 워크 기반 추천 모델을 도입하기도 했죠. 17년 공개된 Pixie는 아직까지도 Pinterst의 추천 시스템의 First-class Citizen으로 Candidate Generation Phase에 기여하고 있습니다.

실제 전사적인 기술 발전 방향으로 많이 언급되는 Pinterest

앞서 언급한 바와 같이 라이너의 데이터 타입과 Pinterest의 데이터 타입은 유사한 점이 많기에 Pin-Board를 벤치마킹하여 Page-Folder 기반의 랜덤 워크 추천 모델을 구축할 수 있겠다는 판단을 하게 되었고, LINERVA-WALK라는 프로젝트명으로 프로젝트를 실행하게 되었습니다.

+) LINERVALINER + MINERVA의 합성어로, 로마 신화 지혜의 여신인 MINERVA의 이름을 차용해 지혜로운 추천 시스템을 만들기 위해 프로젝트명으로 활용하고 있는 이름입니다.

Bipartite Graph: Page-Folder ? Page-User !

당초 계획한 구현안은 PageFolder 간 관계를 활용해 그래프를 구축하고, Pixie 스타일의 랜덤 워크 로직을 입히는 것이었습니다. 따라서 계획한 바에 맞추어 그래프 데이터를 추출해 랜덤 워크 로직을 구현해보았습니다. 하지만 이 과정에서 페인 포인트가 있었는데, 충분한 수의 PageFolder에 속해있지 않았다는 점입니다.

즉, 두 오브젝트 간 관계를 나타낼 수 있는 엣지가 충분하지 않았고, 이에 따라 굉장히 작디 작은 그래프가 빌드되게 되었습니다. 따라서 충분한 수의 엣지가 형성되기 전 까지 해당 관계를 활용한 Bipartite 그래프 구축에는 어려움이 있을 것이라 판단해, Page-User 그래프 실험을 진행하게 되었습니다.

Page-Folder 관계는 페이지에 하이라이트를 한 사용자들에게 폴더링까지 유도할 수 있어야 하기에, 사용자 경험에 서비스가 더 많이 개입해야 합니다. 반면 Page-User 관계는 사용자가 페이지에 하이라이트를 한 순간, 바로 관계가 형성되기 때문에 별 다른 개입 없이 그래프 데이터를 형성할 수 있게 됩니다.

실제로 22년 09월 기준 라이너 텍스트 하이라이트 데이터를 활용해 Page-User 그래프를 구축하게 될 경우, Page-Folder 그래프의 엣지 대비 163배 많은 엣지가 도출되게 됩니다. 따라서 충분히 많은 수의 문서가 후보에 포함될 수 있고 다양한 추천이 가능한 모델링을 위해 Page-User 그래프를 활용해 LINERVA-WALK를 구현하게 되었습니다.

Implementation

LINERVA-WALK의 세부 구현은 모두 Pixie 논문에 소개된 알고리즘 구현법을 따랐습니다. 이 중 그래프 빌드의 경우 AirflowPage-User 그래프를 구축하는 DAG를 구현해 활용하고 있습니다. 보다 상세히 이야기하자면, BigQuery에 덤프되어 있는 프로덕션 데이터베이스 데이터에 쿼리를 수행해 Page-User 엣지들을 추출합니다. 이후, 추출된 엣지를 Cloud Storage에 내려 랜덤 워크 서빙 서버가 내려 받아 활용할 수 있도록 적재합니다.

현재는 DAG를 위와 같이 구성해 활용하고 있습니다. 순차적으로, 이전 배치 작업 시 적재한 그래프를 삭제해줍니다. 이후, 엣지 데이터를 적재하기 위해 BigQuery에 임시 테이블을 생성 후, 해당 테이블에 엣지 데이터를 적재합니다. 생성된 테이블에 적재된 데이터는 Cloud Storage에 적재되게 되고, 앞서 임시로 생성한 테이블을 삭제하며 그래프 빌드가 마무리됩니다.

Go로 작성된 랜덤 워크 서빙 서버는 배포 시, Cloud Storage에 적재된 Page-User 그래프를 내려 받아 모두 RAM에 올려 서빙에 활용하게 됩니다. 현재 그래프 데이터 기준 약 20GB 수준의 RAM을 인스턴스 당 요구하게 됩니다. 앞으로 추가적으로 데이터가 축적되고, 이에 따라 함께 커질 그래프 크기로 인해 인스턴스 당 요구되는 RAM 사이즈가 커지게 될 것입니다. 그리고 이를 위한 유연한 스케일 업을 향후 추가적으로 고민해야 합니다.

allocatedStepsPerDocumentNode := algorithms.AllocateStepsPerDocumentNode(input.TotalSteps, documentNodeIds)

visitedNodes := make([]map[int]int, len(documentNodeIds))

var wg sync.WaitGroup
for i, documentNodeId := range documentNodeIds {
    wg.Add(1)

    i := i
    documentNodeId := documentNodeId

    go func() {
        defer wg.Done()

        result := algorithms.Walk(documentNodeId, allocatedStepsPerDocumentNode[i])
        visitedNodes[i] = result
    }()
}
wg.Wait()

서빙 서버는 입력 받은 문서 아이디들을 노드 아이디로 변환 후, 문서 노드 당 Degree 에 비례해 Total Steps를 나누어 가진 채 병렬적으로 랜덤 워크를 수행하도록 구현하였습니다. Pixie 논문의 경우, 스텝을 쪼갤 때 Timestamp를 가중치로 추가적으로 활용한다고 작성되어 있습니다. 라이너 추천 시스템은 Empirical 하게 학습한 바에 의하면, 하이라이트 한 콘텐츠의 Recency 보다 Frequency 가 더 중요한 바, Timestamp를 가중치로 활용하지 않도록 했습니다.

origin := fromDocumentId

for currentStep < steps {
	...

	if val, ok := Counter[toDocumentId]; ok {
		Counter[toDocumentId] = val + 1
		if val+1 == common.MinimumVisit {
			nHighVisited += 1
		}
	} else {
		Counter[toDocumentId] = 1
	}

	if nHighVisited == common.EarlyStoppingThreshold {
		break
	}

	fromDocumentId = toDocumentId
	currentStep += 1

	if common.GenerateRandomNumber() < common.Alpha {
		fromDocumentId = origin
	}
}

이후, 병렬적으로 수행된 랜덤 워크의 결과들을 병합해 최종 Visit Count를 얻게 되고, 이를 순차적으로 정렬해 추천 문서 후보군으로 반환하여 활용하게 됩니다. 2018년 Pinterest Engineering Blog를 통해 공개된 바에 의하면, Pixie 랜덤 워크 시 너무 말도 안되는 가지로 빠지는 것을 방지하기 위해 50% 확률로 원점으로 돌아오도록 하는 설정을 추가했다고 합니다. Page-User 그래프의 경우, 사용자의 다양한 관심으로 인해 위 같은 상황이 발생할 수 있다고 판단해 블로그에서 제시한 인사이트를 LINERVA-WALK에도 차용하였습니다.

Let’s Randomly Walk

마지막으로 LINERVA-WALK를 라이너 팀원들에게 적용했을 때, 얻게 되는 추론 결과를 간단히 공유하며 글을 마무리 하도록 하겠습니다.

먼저, 라이너를 통해 프로덕트, 머신러닝, 스타트업 등에 하이라이트를 수집하는 카터에게는 위와 같은 추천 결과가 도출되었습니다. 하버드 비즈니스 리뷰, 앰플리튜드 블로그, 피터 노빅의 개인 사이트 등에서 유관한 글이 꽤나 다양하고 연관되게 추출된 모습입니다.

다음으로 라이너에서 프로덕트 디자이너로 근무 중인 헤이즐에게는 디자인 관련 매거진, 커뮤니티 블로그, 프로덕트 매니지먼트 포스트가 추천되었습니다. 마찬가지로 업무 관련된 글이 고른 다양성을 가지고 추천된 것을 확인할 수 있습니다.

이렇게 구축된 LINERVA-WALK는 현재 기존 핵심 Candidate Generator로 활용하고 있던 텍스트 콘텐츠 기반 필터링 모델과 함께 추천 후보군을 추출하는 모듈로 활용하게 되었습니다.

마치며..

LINERVA-WALK는 콘텐츠 기반 추천 모델링으로 추천 시스템을 시작한 제가 인터랙션 데이터를 활용한 추천 시스템까지 구축하게 되는 일련의 과정에 있어 좋은 경험과 배움을 안겨다 준 프로젝트입니다. LINERVA-WALK를 시작으로 라이너 추천 시스템에 훨씬 더 다양한 추천 모델들을 적용하며 사용자에게 효용을 드릴 생각에 벌써부터 설레는 마음입니다.

또 단순 추천 모델만 구축하는 것에 그치지 않고, 실제 서빙 파이프에 녹이기 위해 여러 엔지니어링적 챌린지를 마주하며, 병렬적 성장을 경험할 수 있다는 것 역시 라이너에서 머신러닝 엔지니어로 일하며 얻을 수 있는 큰 장점이라고 생각합니다.

이처럼 라이너 머신러닝 조직은 추천 모델링과 추천 시스템 구축 전반에 큰 관심을 가지고 있기 때문에, 여러 방향으로 성장하고 기여할 수 있는 곳입니다. 라이너에서 저와 함께 마일스톤을 찍어나가며, 성장하실 분을 항상 기다리고 있습니다. "Help People Get Smart Faster"라는 미션을 해결하며, 세상에 제품으로 기여하고, 개인적 성장까지 이루고 싶으신 분들, 편하게 연락주세요!

👉 라이너 채용 페이지 바로가기