영화 추천 모바일 웹 플랫폼 제작 후기

Broccolism·2021년 10월 10일
5

회고록

목록 보기
3/12

추천 시스템

한창 뜨고 있는 '그' 시스템

넷플릭스, 왓챠, 유투브 등 콘텐츠를 다루는 서비스에서는 이미 도입한 시스템이다. 아마존 같은 쇼핑몰에서도 사용된다. 대량의 정보를 필터링해서 유저에게 먼저 보여주는 기술, 바로 추천시스템이다. 데이터사이언스 필드에서 최근 활발히 연구되고 있는 분야기도 하다.

미리 말씀드리자면

이번 글은 졸업 프로젝트를 위해 영화 추천 모바일 웹 플랫폼을 제작한 개발기입니다. 추천 시스템에 대한 전문적인 내용은 나오지 않지만, 작고 귀여운 서비스 하나를 완성하기 위한 디자인/아키택처 구성/개발 후기가 모두 모여있습니다.
좁고 깊은 글보다는 얕고 넓은 글이 될 것 같습니다.

구현 내용

전체 아키텍처

⠀⠀추천시스템을 학습시킬 데이터셋으로 MovieLens 데이터셋을 선택했다. Kaggle 사이트에서 다른 데이터셋도 찾아봤지만 무비렌즈 데이터셋이 가장 용량이 컸다. 추천 시스템 학습에 주어진 input 데이터양이 많을수록 성능이 높아지기 때문에 이걸 사용했다. 따라서 전체적인 아키텍처도 우리가 사용할 데이터셋인 MovieLens 데이터셋에 맞춰서 만들어야했다.

전체 아키텍처

타입스크립트로 만든 API 서버가 중심이다.
  - 아나콘다 가상환경에서 실행되는 추천 시스템,
  - 외부 API인 Gravatar, TMDB, OMDB의 데이터,
  - ...그리고 DB에 저장된 데이터셋
과 웹 클라이언트를 연결시켜주는 역할을 한다.

⠀⠀MovieLens 데이터셋은 심플하다. item-user간 rating과 timestamp만 있고 item과 user에 대한 상세 정보는 없다. 이게 장점이될수도 있지만, 우리 프로젝트에서는 단점으로 작용했다. 모바일 웹 플랫폼을 제작하는게 목표였기 때문에 UI상으로 영화와 유저에 대한 상세 정보를 예쁘게 보여주고 싶었다.

⠀⠀이를 보완하기 위해 외부 API 서비스 2가지를 사용했다.

위 사이트에서는 영화 상세 정보를 제공한다. '영화'하면 떠오르는 배우, 감독, 줄거리 등 기본적인 정보뿐만 아니라 유투브 트레일러 링크까지 알려주는 API도 있다! 우리는 이 API를 적극 활용하기로 했다.

⠀⠀유저 프로필을 만들기 위해서는 랜덤 프로필 이미지를 생성해주는 Gravatar API를 사용했다. 입력한 input 값에 따라 고유한 해시값을 만들어서 이미지를 보여주기 때문에 한 유저에 대한 프로필이 계속 바뀌지 않고 유지된다. 이 API를 사용해서 마치 깃허브 기본 프로필처럼 생긴 랜덤 프로필 이미지를 만들어 보여줄 수 있었다.
마이페이지

⠀⠀MySQL을 사용한 데이터베이스에는 초기값으로 무비렌즈 데이터셋뿐만 아니라 랜덤 유저 닉네임도 함께 넣었다. 누군가 파이썬으로 랜덤 닉네임 생성기를 만들어놓아서 프로젝트에 바로 적용할 수 있었다. 위의 마이페이지에서 보이는 프로필 사진과 닉네임이 앞서 소개한 랜덤 프로필 사진, 랜덤 닉네임이다.

⠀⠀마지막으로 추천 시스템은 파이썬 아나콘다 가상환경에서 실행했다. 원래 로컬 환경에서 실시간으로 정보를 업데이트하는 시스템을 구현하고 싶었는데, 사용한 오픈소스의 dependency 목록 및 버전이 우리 팀에서 사용하는 버전과 충돌이 나는 바람에 결국 가상환경에서 실행되는 batch program으로 만들기로 했다. input, output은 파일 형식으로 주고받는다.

추천 시스템은 어떻게?

그래도 추천 시스템을 활용하는게 포인트였으니 여기에 대해 조금 더 짚고 넘어가보자.

추천시스템

⠀⠀데이터사이언스 시간에 배운 말이 하나 있다.

데이터 분석 업무의 70 - 80%는 전처리 작업이다.

그리고 그 말을 이번에 체감했다. 서비스에 사용한 추천 시스템은 2가지다. 그 중 한가지는 NeuRec 라이브러리에서 제공하는 NeuMF(Neural Matrix Factorization)을 커스텀 한 것이다. 기존 라이브러리를 커스텀한다고 해도 input, output 형식에 대한 수정이 필요해서 이를 위한 컨버터 코드도 만들어서 사용했다. 그 코드를 적기 위해 썼던 시간이 라이브러리를 실행하기 위해 기존 코드를 들여다본 시간보다 많았던 것으로 기억한다. (커스텀한 소스코드는 이곳에서 볼 수 있다.)

⠀⠀반면 그림 아래쪽에 표시된 유사도 계산기는 직접 파이썬으로 구현한 코드라 별도 처리 과정이 필요없었다. user-user간 유사도와 item-item간 유사도를 계산하는 간단한 계산기인데, 아래처럼 '나와 비슷한 유저가 좋아한 영화'를 보여주기 위해 구현했다.
메인화면 > 유사도 사용

UI, 서버 로직 구현하기

figma design
⠀⠀메인 컬러는 보라색, 서브 컬러는 노란색, 배경색은 검은색을 썼다. 검은색 배경은 흰 배경보다 포스터에 조금 더 집중하게 만든다. 이 때 글자 색상이 완전히 흰색이면 눈이 아플 수 있기 때문에 #FFFFFF 컬러에서 투명도를 조절해 사용했다.

구글 머터리얼 디자인 가이드에서는 배경색을 검정이 아닌 진한 회색(#121212)을 사용할 것을 권장하고, 애플 휴먼 인터페이스 가이드에서는 검정 배경에 투명도를 조절한 흰색 글자를 사용한 UI를 보여주고 있다.

⠀⠀웹 클라이언트는 리액트 JS, 서버는 node.js 환경에서 typescript로 구현했다. 내가 서버, 팀원이 클라이언트를 집중적으로 만들기로 했는데 빠른 개발을 위해 각자가 편한 언어를 택했다.

⠀⠀웹 구현 시 가장 중점을 둔 부분은 UX를 해치지 않는 것이었다. 가장 대표적으로 사용자 경험을 나쁘게 만들 수 있는 부분이 바로 로딩 시간을 어떻게 처리하느냐라고 생각했다. 대부분 기능이 로컬 환경에서 돌아가기 때문에 로딩 시간은 문제되지 않았다. UI 상에서는 로딩이 되는 동안 facebook shimmer effect를 보여주기로 했고, 다행히 npm에서 리액트에 적용할 수 있는 라이브러리가 있어 이를 사용했다.

shimmer effect

⠀⠀서버 작업에서는, 앞서 보았듯이 타입스크립트 서버가 전체 아키택처의 중심을 담당하기 때문에 API를 잘 정리해두는 것이 중요했다. 그래서 노션으로 input, output 형식과 간단한 기능 명세를 만들어 공유했다.

Trouble Shooting

왜 검색만 하면 가끔 터지지?

⠀⠀검색 결과에 나온 영화 정보를 넘겨주는 api를 만들다가 Promise.all()가끔 reject 되는걸 발견했다. 항상도 아니고.. 가끔?
검색 페이지

⠀⠀MovieLens 데이터셋에 있는 영화 목록과 TMDB에 등록된 영화 목록이 달라서 생기는 문제였다. 당연히 다를 수밖에 없다. 검색 API는 TMDB api를 사용했는데, 여기서 나온 영화 id 목록를 가지고 MovieLens 데이터셋이 저장된 우리팀 DB에서 정보를 조회해야 했다.

⠀⠀그래서 유저가 검색을 통해 우리 DB에 없는 영화를 조회한 경우, 해당 영화 정보를 우리 DB에 쌓게 만들었다. 따라서 DB에는 초기에 넣은 MovieLens 데이터셋에 추가로 계속 데이터가 쌓이는 구조가 되었다. 이렇게 만든 뒤로는 더이상 같은 에러가 나지 않았다.

왜 맥북에서 비행기 소리가..?

⠀⠀프로젝트에 사용한 NeuMF (Neural Matrix Factorization)은 기존의 matrix factorization 방식과 달리 추천 시스템에 딥러닝 기술을 접목한 기술이다. 컴퓨팅파워가 많이 필요하다는 뜻이다. 하지만 우리 팀은 2명 모두 맥북을 사용하고 있었고 아무리 GPU 가속을 해봐도 적당한 시간 안에 실행이 완료되지 않았다. 애꿎은 맥북 온도만 자꾸 올라갈 뿐...

⠀⠀구글 colab도 사용해보고 심지어는 사양 좋은 그래픽카드가 있는 윈도우 PC를 찾아 피씨방까지 전전하다가 조교님 찬스를 사용했다. 문의해본 결과 졸업 프로젝트 수준에서는 데이터셋의 규모가 크게 중요하지 않으니 크기가 작은 데이터셋을 먼저 사용해보라는 답변을 받았다. 결국 MovieLens 데이터셋 중 ml-latest-small 이라는 작은 데이터셋을 사용해서 서비스를 완성했다.

소감

큰 그림 그리기

⠀⠀컴퓨팅 파워를 비롯해 디테일이 부족한 데이터셋, 짧은 기간 등 여러 제약사항이 있었다. 이런 제약사항을 고려해서 최적의 방법을 찾아 전체적인 구조를 짜려고 했다. 프로젝트 규모가 그리 크지는 않았지만, 신입으로써는 하기 힘든 경험을 했다고 생각한다.

⠀⠀개발 도중 크고 작은 문제를 맞닥뜨릴 때마다 조금 머리 아프긴 했지만 그 과정 자체는 즐거웠다. DevOps를 하시는 분들이 이런 기분일까..? 서비스를 완성하고 발표 자료를 만들면서 그동안 생각보다 많은 일을 했구나, 하는 생각에 뿌듯했다. 때로는 큰 그림을 잘 그리는 능력도 중요하다는걸 깨달았다. 🥳

참고 링크

데이터셋

개발에 사용한 외부 API, 라이브러리

개발에 사용한 추천 시스템 코드

UI 제작 관련 링크

서버 API 명세

profile
설계를 좋아합니다. 코드도 적고 그림도 그리고 글도 씁니다. 넓고 얕은 경험을 쌓고 있습니다.

2개의 댓글

comment-user-thumbnail
2021년 10월 18일

유용한 프로젝트 후기네요. 감사합니다

1개의 답글