LINE 메신저 앱에 온 디바이스 머신 러닝 적용하기

LINE DEVELOPER DAY 2020에서 장혁재 님이 발표하신 Sharing experience of adopting machine learning to LINE app 세션 내용을 옮긴 글입니다.

들어가며

안녕하세요. 한국에서 LINE을 개발하고 있는 장혁재입니다. 이번 글에서는 머신 러닝 기능을 LINE 앱에 적용해 본 경험을 공유하겠습니다. 개발자가 아닌 분들이 읽어도 도움이 될 수 있도록 상세한 기술 내용보다는 개발 과정에 대한 전반적인 이야기를 다루려고 합니다. 이 글에서 예시로 설명드릴 세 가지 프로젝트와 그 프로젝트를 진행하며 얻은 교훈들이 이번 글에서 특히 중요한 부분일 것 같습니다.

온 디바이스 머신 러닝

온 디바이스(On-device) 머신 러닝이란 서버-클라이언트 관계에서의 모바일 클라이언트, 쉽게 말해 Android나 iOS의 LINE 앱 입장에서의 머신 러닝을 말합니다. 이번 글에서 저는 온 디바이스 머신 러닝에 집중해서 이야기하려고 합니다. 이유는 다음과 같습니다. 

LINE에서는 아래와 같이 스티커 추천이나 텍스트 인식 기능과 같은 여러 가지 머신 러닝 기술을 적용해 왔습니다. 앞으로도 적극적으로 도입할 계획인데요. 이와 같은 기능의 실제 개발 과정을 살펴보면 머신 러닝을 도입할 때 여러 가지 사안을 결정해야 한다는 것을 알 수 있습니다. 

예를 들면 딥 러닝을 사용할 것인지 전통적인 머신 러닝을 사용할 것인지, 서버에서 머신 러닝을 실행할 것인지 아닌지, 미리 결과를 준비해서 사용할 것인지 아니면 실시간으로 만들 것인지와 같은 것들이 있습니다. 앞서 언급한 기능에 머신 러닝을 도입할 때도 아래와 같이 내부에서 이런 결정들을 쌓아가며 만들었습니다. 

그렇다면 어떤 기준으로 각 사안을 결정할 것인지가 중요해집니다. 사실 이건 프로젝트마다 다르다고 할 수 있는데요. 아마도 개발하려는 기능의 목표가 무엇인지에 크게 영향을 받을 것 같습니다. 구체적으로 생각해 보면 사용하려는 데이터의 프라이버시 문제가 있는지와 머신 러닝으로 만들려는 기능이 무엇인지, 어느 정도의 정확도를 기대하는지, 얼마나 빠른 응답성이 필요한지에 따라서 달라질 것입니다. 만약 개발하려는 기능에 딥 러닝을 사용한다면 결과의 정확도는 높아지겠지만 학습할 때 많은 데이터가 필요할 것입니다. 또한 아직까지 딥 러닝은 서버에서만 학습이 가능하다는 점도 고려해야 할 것입니다. 서버에서 학습해야 한다면 프라이버시가 중요한 데이터들은 모으기가 쉽지 않겠죠. 만약 기능의 UX 관점에서 매 실행마다 사용자를 기다리게 할 수 없다면 추론 결과도 미리 만들어 놓아야 할 것입니다. 

이렇듯 각 경우에 따라 고려해야 할 것들이 다르기 때문에 이번 글에서는 온 디바이스 머신 러닝에 집중하려고 합니다. 서버 클라우드나 딥 러닝 자체에 관한 내용은 LINE DEVELOPER DAY 2020의 AI 섹션에 좋은 세션들이 많이 있으니 그쪽을 참고하시면 좋을 것 같습니다. 

이제 온 디바이스 머신 러닝과 관련해서 LINE에서 진행했던 세 가지 프로젝트에 대해서 공유하려는데요. 각 프로젝트를 전부 자세히 말씀드리기에는 지면이 많이 부족할 것 같아서 비교적 최근에 작업했던 비디오 하이라이트 위저드 프로젝트 위주로 말씀드리고 나머지 두 프로젝트에 대해서는 간략하게 개요 정도만 말씀드리겠습니다.

 

비디오 하이라이트 위저드 프로젝트

비디오 하이라이트 위저드는 비디오를 분석해서 자동으로 요약본과 하이라이트를 만들어 주는 기능입니다. 이 기능을 만들게 된 이유를 먼저 말씀드리겠습니다. 인터넷에서 글을 읽다 보면 긴 글의 끝에 ‘TL;DR(Too long, didn’t read)’라는 문구가 적힌 것을 많이 볼 수 있습니다. 이와 비슷하게 요즘 동영상에도 ‘TL;DW(Too long, didn’t watch)’라는 문구를 사용하고 있습니다. 아마 다들 경험해 보셨을 겁니다. 동영상의 길이가 너무 길면 처음부터 끝까지 다 보는 것이 아니라 중간을 스킵하고 본다거나 혹은 아예 보지 않는 경우가 많습니다. LINE의 Timeline 스토리 기능에 15초 제한이 있는 것도 이런 이유 때문이 아닐까 싶습니다. 

또한 휴대폰으로 동영상을 촬영하다 보면 화면이 흔들리거나 초점이 맞춰지는 데 시간이 걸려서, 혹은 촬영 중에 사람이 지나가는 바람에 특히 동영상의 시작과 끝부분에 필요 없는 내용이 들어가는 경우가 많이 있습니다. 그래서 동영상을 공유할 때 편집을 통해 이런 쓸모없는 부분들을 다 잘라내고 핵심 부분만 남겨서 전송하면 좋겠다는 생각을 많이 하셨을 텐데요. 사실 비디오를 편집하는 것은 굉장히 귀찮은 작업이기 때문에 편집하지 않고 그냥 보내 버리는 경우가 많습니다.

저는 이런 상황을 해결하기 위해 비디오를 분석해서 자동으로 요약본과 하이라이트를 만들어 주는 비디오 하이라이트 위저드를 만들었습니다. 요약본과 하이라이트의 차이를 말씀드리자면, 아래 그림에서 보시는 것처럼 비디오의 여러 부분을 잘라내서 하나의 영상으로 만들어 내는 것이 요약본이라면 전체에서 하나의 대표적인 구간을 잘라내는 것이 하이라이트라고 할 수 있습니다.

 

비디오 하이라이트 위저드의 작동 방식

다음으로 비디오 하이라이트 위저드를 어떻게 개발했고 어떤 방식으로 작동하는지 말씀드리겠습니다.

비디오 분석 작업을 하기 위해서 HECATE라는 오픈 소스 라이브러리의 도움을 많이 받았는데요. HECATE 라이브러리는 C++로 구현돼 있어서 Android에 네이티브 코드로 포팅하는 작업이 꼭 필요했습니다. 작업 난이도는 실제 비디오 분석 작업보다 Android 네이티브 코드로 포팅하는 작업이 훨씬 어려운 작업이었습니다. HECATE는 내부적으로 OpenCV라는 라이브러리를 사용합니다. OpenCV는 주로 이미지 관련 처리를 도와주는 굉장히 유명한 오픈 소스 라이브러리입니다. 그런데 OpenCV의 SDK에서는 정적(static) 라이브러리만 제공하기 때문에 저희가 필요했던 동적(shared) 라이브러리를 얻기 위해서는 소스 코드를 크로스 컴파일해야 했습니다.

또한 HECATE는 비디오를 분석하기 위해 비디오 프레임, 즉 비디오의 각 장면을 추출해야 하는데 이때 내부적으로 FFmpeg을 사용합니다. FFmpeg는 대표적인 비디오 인코딩 및 디코딩 라이브러리로 많은 분들이 들어보셨을 것 같습니다. 문제는 FFmpeg이 일반적으로 많이 사용하는 MP4 동영상 포맷의 대표적인 코덱인 H.264 코덱과 특허 문제가 얽혀 있어서 LINE에서 사용할 수 없었다는 점입니다. 이런 이유로 FFmpeg 대신에 Android의 미디어 라이브러리를 사용해서 비디오 프레임 추출 작업을 대신해 줄 필요가 있었습니다.

모든 장면을 추출하고 나면 본격적으로 비디오 분석을 시작합니다. 비디오 분석의 큰 개요를 먼저 말씀드리자면, 추출한 비디오 장면을 살펴보면 누가 봐도 필요 없다고 할 수 있는 장면들이 있을 겁니다. 예를 들어 아래 슬라이드 왼쪽에 X 표시한 부분과 같이 너무 흔들린 장면이나 너무 어두운 장면 혹은 너무 밝게 찍혀서 화면이 아예 하얗게 나와버린 장면들이 있을 것입니다. 

이런 의미 없는 장면들을 모두 제거하면서 최대한 선명한 구간만 추려내는 것이 비디오 분석의 가장 큰 목적입니다. 이때 비디오 분석을 왜 소거법 기반으로 하느냐고 물으실 수 있습니다. 혹은 일반적으로 사용하는 비디오 요약 방법과 많이 다르다고 생각하실 수도 있습니다. 비디오를 요약하는 대표적인 방법 중 하나는 이 비디오가 어떤 장르인지, 예를 들어 스포츠인지 풍경인지와 같은 것들을 먼저 알아내고 그에 기반하여 요약을 하고 각 장르에 맞는 평가를 하는 방식입니다. 그런데 장르 분석과 같은 복잡한 작업은 모바일 기기에서 수행하는 것이 굉장히 어렵습니다. 따라서 그런 분석을 하지 않고 모든 종류의 비디오를 하나의 객관적인 기준으로 분석하면서 비디오 요약을 잘 만드는 것이 이 프로젝트의 목적이었고 그런 목적에 맞게 가능하면 직관적이고 무난한 소거법 기반의 분석 방법을 선택했습니다.

좀 더 구체적으로 각 단계의 분석 과정을 말씀드리겠습니다. 먼저 각 장면의 색을 검사해서 화면 전체가 하나의 색으로만 구성된 장면들을 찾아냅니다. 앞서 말씀드렸던 너무 어둡거나 너무 밝은 장면들일 것입니다. 이후 하나의 장면과 바로 뒤에 있는 장면을 비교해서 픽셀 단위로 미분 값을 구합니다. 미분 값을 장면 단위로 합산하면 해당 장면이 앞 장면과 비교해 얼마나 흔들렸는지, 얼마나 움직였는지 파악할 수 있어서 많이 흔들린 장면을 찾아낼 수 있습니다. 색 검사에서 찾아낸 장면과 흔들린 장면들은 직관적으로 쓸모없는 장면들이라고 판단하고 모두 필터링해서 버립니다.

필터링하고 나면 위 그림에서 두 번째 줄의 A와 B처럼 이어지는 구간이 남게 됩니다. 이번에는 그 안에서 거꾸로 각 구간마다 가장 큰 움직임이 나타난 곳을 찾고 화면의 색이나 모양을 기반으로 클러스터링해서 비슷한 장면들을 그룹별로 모읍니다. 위 슬라이드에서 B 구간의 앞 부분을 보시면 그 뒤와 비교했을 때 눈으로 보기에도 뭔가 다르다는 것을 느낄 수 있는데요. 앞서 말씀드린 분석을 통해서 B 구간을 화면의 특성에 따라 다시 2와 3으로 나눌 수 있습니다. 이렇게 나눈 구간들을 ‘샷(shot)’이라는 개념으로 만듭니다. 이 샷을 만든 후에 요약본과 하이라이트를 만들기 위해서 각각 추가 작업을 진행합니다.

요약본을 만들기 위해서는 앞서 찾았던 1, 2, 3과 같은 샷 구간을 색과 모양, 움직임에 기반해서 한 번 더 클러스터링하고 그중에서 가장 역동적인 부분을 중요 부분이라고 판단하고 추출합니다. 요약본 제작 과정을 시작할 때 15초나 30초와 같이 원하는 요약본의 길이를 입력하는데요. 요약본의 전체 길이를 이 길이에 맞추기 위해 앞서 추출한 각 중요 부분의 길이를 조절한 다음 하나로 합칩니다. 이렇게 요약본을 만들고 나면 앞서 나눴던 1, 2, 3과 같은 각 샷 구간 중에서 가장 큰 비중을 차지하는 구간을 하이라이트로 선별합니다. 이런 과정 중에 수행하는 필터링이나 히스토그램, 클러스터링과 같은 작업들은 대부분 OpenCV에서 제공하는 API를 이용해 처리합니다.

비디오 하이라이트 위저드 프로젝트 요구 사항

간략하게 비디오 하이라이트 위저드의 기술적인 내용에 대해서 말씀드렸습니다. 이제 왜 이런 형태로 기능을 구현하게 됐는지 요구 사항을 살펴보겠습니다.

가장 먼저 데이터의 보안을 유지하기 위해서입니다. 비디오를 분석할 때 보통 비디오를 서버에 업로드해서 서버에서 분석하는 것이 일반적인데요. 비디오 하이라이트 위저드에서는 서버의 도움을 받지 않고 앱 내에서 자체적으로 비디오를 분석했습니다.

두 번째 문제는 비디오 분석 작업이 다른 작업에 비해 굉장히 많은 양의 시스템 자원이 필요하다는 점입니다. 비디오 분석을 보통 모바일 기기가 아니라 서버에서 진행하는 이유이기도 한데요. 앞서 말씀드린 비디오 분석 과정이 필터링 같은 가벼운 처리 과정 위주로 돼 있는 이유도 이런 요구 사항에 맞추기 위해서입니다. 또한 비디오 분석 때문에 사용자가 모바일 기기를 사용할 때 속도가 저하된다거나 배터리가 금방 소모되는 것과 같은 일도 없어야 했습니다.

이런 이유로 기본적으로 사용자가 기기를 사용하지 않고 충전 중일 때만 분석을 진행합니다. 또한 분석 결과가 비디오별로 저장이 가능한 형태이기 때문에 가능하면 각 비디오에 대한 분석을 미리 끝내서 결과를 만들어 놓은 다음 필요할 때 사용하는 형태로 기능을 만들었습니다.

결과 요약

앞서 비디오 분석 결과로 요약본과 하이라이트 구간을 생성한다고 말씀드렸는데요. 사실 프로젝트를 처음 시작할 때는 비디오 요약본만이 목표였습니다. 그런데 요약본은 여러 구간을 편집해서 하나의 영상으로 만드는 것인 만큼 이를 위한 다중 구간 편집 UI를 사용자에게 제공해 주어야 했는데요. 작은 모바일 기기 화면에서 이를 표현하는 게 쉽지 않았습니다. 마침 Timeline 스토리의 15초 제한에 대응하기 위한 목적도 있었기 때문에 요약본 만들기보다는 하이라이트 구간을 추출하고 이를 추천해 주는 것으로 기능을 변경했습니다.

실제로 출시한 기능은 아래 슬라이드 화면 오른쪽에 보이는 것과 같습니다. 비디오를 전송할 때 나타나는 가위 모양의 아이콘을 누르면 트림(trim) 기능으로 들어갑니다. 이때 해당 비디오에 분석 결과가 있다면 어떤 구간을 트림해서 전송하는 것이 좋을지 자동으로 추천해 줍니다. 2020년 초에 출시하였고, LINE Labs 메뉴에서 찾으실 수 있습니다.

 

오토 핀 챗 프로젝트

대화방 목록과 관련해 오토 핀 챗(auto pin chat)이라는 기능이 있었습니다. 오토 핀 챗은 대화방 내의 활동량을 계산해서 활동량이 많다고 판단되는 소수의 대화방을 선정한 다음에 아래와 같이 빨간색 핀을 꼽아서 상단에 고정시켜주는 기능입니다.

LINE을 사용하면서 원하는 대화방을 찾기 위해 스크롤을 마구 넘겨본 경험이 누구나 한 번쯤은 있었을 겁니다. LINE의 사용성 평가 인터뷰 도중에 만났던 한 사용자는 친구가 1,000명이 넘고 매일 대화하는 대화방도 100개가 넘어서 매번 자기가 원하는 대화방을 찾기 위해 많이 고생하고 있다고 말하기도 했습니다. LINE 앱 대화 목록 상단에 위치한 검색 기능의 활용 통계를 보면 이런 불편함을 더 잘 알 수 있는데요. 조사해 보니 검색 기능을 대화방을 찾는 용도로 사용하는 경우가 굉장히 많았습니다. 이와 관련해서 대화방 정렬 기능을 제공하고는 있지만 관련 옵션이 이런 불편함에 비해서 굉장히 초보적인 수준이었습니다. 

오토 핀 챗 기능은 이런 불편함을 개선하기 위해 만들었습니다. 대화 목록 상단에 고정할 대화방을 선정하기 위해 사용자의 활동량을 계산할 때 아래 수식처럼 메시지를 읽는 것보다는 쓰는 것에 중점을 두었는데요. 새로운 메시지를 읽는 건 이미 알림을 통해서 쉽게 접근할 수 있다는 점을 고려했기 때문입니다. 

또한 활동량을 계산할 때 아래와 같은 시그모이드(sigmoid) 함수를 사용해서 개별 메시지의 중요도가 시간이 지남에 따라 점점 낮아지게 설계했습니다. 아래 시그모이드 함수를 사용하면 15일 후에는 0.5, 30일 후에는 0.1로 중요도가 감소하는데요. 그래야 최근의 활동량을 제대로 반영할 수 있습니다. 

 

오토 핀 챗 프로젝트 요구 사항

이 프로젝트에서 가장 중요했던 요구 사항은 외부의 도움 없이 앱 내에서 모든 작업이 이루어져야 한다는 점이었습니다. 아시다시피 LINE에서는 메시지를 전송할 때 ‘레터 실링(letter sealing)’이라는 기능으로 메시지를 전부 암호화해서 전송하기 때문에 대화 목록 기능을 만들 때 서버의 도움을 받을 수가 없었습니다.

또한 LINE에서 가장 빈번히 사용되는 대화 목록 기능이기 때문에 응답 속도가 굉장히 빨라야 했습니다. 이런 이유로 매번 모든 활동량을 전부 계산해서 대화 목록 상단에 고정할 대화방을 찾는 것은 무리였습니다. 그나마 다행이었던 점은 각 대화방의 활동량 비율이 한순간에 갑자기 폭증한다거나 갑자기 낮아지지 않기 때문에 몇 시간 단위로 미리 결과를 만들어 놓고 사용하다가 다시 결과를 갱신하는 형태로 기능을 구현할 수 있었습니다.

여기서 중요한 문제점이 드러나는데요. 앞서 활동량을 계산할 때 개별 메시지의 중요도가 시간에 따라 감소해야 한다고 말씀드렸습니다. 이를 구현하려면 매번 분석할 때마다 메시지마다 달라지는 중요도를 반영하기 위해서 전체 메시지를 전부 다시 분석해야 했는데요. 이 방법은 누가 생각해도 너무 비효율적이었습니다. 이에 계산 과정을 나눠서 중요도를 반영하기 전까지의 중간 결괏값을 뽑아서 저장해 놓고 매번 분석할 때 여기에 중요도만 다시 반영하는 형태로 증분 처리했습니다.

결과 요약

이 프로젝트도 처음 시작할 때와 마지막의 목표가 달랐습니다. 처음에는 단순히 활동량을 사용하는 게 아니라 대화할 때의 시간이나 장소와 같은 여러 가지 요소를 다 활용했으며, 소수의 대화방만 상단에 고정한 것이 아니라 아예 대화 목록 전체를 다시 정렬하도록 구현했습니다.

하지만 개발해서 사용해보니 UX가 생각처럼 효과적이지 못했습니다. 이에 기능을 좀 더 단순화하고 장점에 집중하기 위해 위와 같은 가장 활동량이 많은 소수의 대화방을 뽑아서 상단에 핀을 꼽아 고정하는 형태로 변경했습니다. 이 기능 역시 원래 LINE Labs로 출시할 예정이었는데요. 현재 LINE Labs에 올라와 있는 대화 폴더 기능과 UX가 겹친다는 이유로 아쉽게 출시되지 못했습니다. 개인적으로 굉장히 열심히 준비했던 프로젝트여서 안타깝게 생각하고 있습니다.

 

CardOCR 프로젝트

다음은 CardOCR 프로젝트로, LINE Pay 기능 중 아래 슬라이드 왼쪽에 보이는 것처럼 카메라로 신용카드를 인식하는 기능을 만드는 프로젝트였습니다.

신용카드를 인식하기 위해 card.io라는 오픈 소스 라이브러리를 사용했는데요. card.io는 번호가 양각으로 표시된 신용카드(슬라이드 위쪽 카드)는 굉장히 잘 인식했지만 요새 많이 발급되는, 숫자를 양각이 아닌 인쇄로 표시한 카드(슬라이드 아래쪽 카드)는 전혀 인식하지 못하는 문제가 있었습니다. 이유는 card.io 내부에서 숫자와 위치를 인식할 때 사용하는 FCN(fully connected network)이 양각 카드에 최적화되어 있었기 때문인데요. 이 문제를 CardOCR 프로젝트를 통해서 해결했습니다.

먼저 OpenCV를 이용해 카드 이미지에서 번호가 있는 부분을 찾아내고 해당 부분만 잘라냅니다. 그다음 Google Mobile Vision의 OCR 라이브러리를 사용해서 잘라낸 부분의 숫자를 인식하도록 구현했습니다. 이를 기존 card.io 라이브러리와 동시에 사용하도록 해서 양각된 숫자와 인쇄된 숫자 양쪽 모두를 인식하도록 한 것이 프로젝트의 개요입니다.

CardOCR 프로젝트 요구 사항

이 프로젝트에서 가장 중요했던 점은 빠른 인식 속도였습니다. 카메라로 카드를 비췄을 때 즉시 인식되도록 가능한 한 200ms 이내로 인식하는 것을 목표로 잡았습니다. 앞서 처리 과정에서 OpenCV를 이용해 번호 부분만 잘라낸 이유도 인식 속도를 높이려는 목적이었습니다.

두 번째로 중요했던 점은 서버의 도움 없이 앱 내에서 독립적으로 동작하는 것이었습니다. 마침 Google Mobile Vision의 OCR 라이브러리가 오프라인으로 사용할 수 있었기 때문에 이를 달성할 수 있었습니다.

마지막으로 이 기능을 만들면서 가능하면 앱의 크기가 늘어나지 않았으면 좋겠다는 바람이 있었는데요. 운 좋게도 Google Mobile Vision의 라이브러리가 앱 내부가 아니라 Google Play 서비스를 통해 앱 외부에 설치되는 구조여서 결과적으로 앱 크기를 거의 늘리지 않고 기능을 만들 수 있었습니다.

결과 요약

이 프로젝트 역시 개발 중간에 목표가 조금 변경됐습니다. 원래는 LINE Wallet의 멤버십 카드 관리 기능인 ‘My card’라는 메뉴가 대상이었습니다. 예를 들어 IKEA 패밀리 카드나 코스트코 멤버십 카드 같은 일반적인 멤버십 카드를 포함해서 세상에 존재하는 모든 종류의 카드를 다 인식해보자는 것이 목표였는데요. 정작 LINE의 My card 메뉴에서 실물 카드를 추가하는 기능이 삭제돼 버렸습니다. 만들어 놓은 기능의 사용처가 없어져서 굉장히 난감해 하던 차에 마침 대만의 LINE Pay 팀에서 급한 요청이 들어왔습니다. 대만 LINE Pay에서 출시했던 신용카드를 보시겠습니다.

앞서 말씀드린 것처럼 숫자가 인쇄 형식으로 표시된 신용카드는 잘 인식하지 못하는 문제가 있었기 때문에 LINE에서 출시한 신용카드임에도 LINE 앱에서 인식이 안 되는 해프닝이 있었습니다. 이 문제를 해결하기 위해서 CardOCR 프로젝트의 용도를 신용카드를 인식하는 용도로 변경해 사용하게 되었습니다.

 

세 프로젝트의 공통점

세 가지 사례를 잘 살펴보면 공통적인 요구 사항이 몇 가지 있습니다. 우선 세 프로젝트 모두 서버의 도움을 받지 않고 앱 내에서 모든 처리를 진행해야 했습니다. 또한 모두 빠른 응답 속도가 필요한 UX를 가지고 있었고, 결괏값에 어느 정도 오류가 있더라도 크게 문제가 발생하지 않는 UX라는 공통점이 있었습니다.

제가 경험했던 사례가 세 가지 정도밖에 되지 않기 때문에 이런 요구 사항이 늘 공통적으로 나타난다고 말씀드릴 수는 없습니다만, 그래도 어느 정도 중복으로 나타난 요구 사항이었으니 혹시 앞으로 새로운 프로젝트를 진행할 때 비슷한 요구 사항이 도출된다면 온 디바이스 머신 러닝을 고려해 보시면 어떨까 싶습니다.

 

머신 러닝을 도입할 때 고려해 볼 만한 점

제가 앞서 말씀드린 프로젝트를 포함해 그동안 여러 머신 러닝 관련 프로젝트에 참여하면서 얻은 경험과 교훈을 말씀드리겠습니다.

로드맵을 확인하자

우선 프로젝트를 진행할 때 내가 만드는 그 기능에만 집중해서 보실 것이 아니라 가능하면 좀 더 넓은 시야로 관련 기능들의 전체 로드맵을 파악하면 좋을 것 같습니다. 예를 들어 내가 지금 대화방에서 사용하는 기능을 만들고 있다면, 앞으로 대화방의 전체적인 기능들이 어떤 방향으로 발전해 나갈 것인지를 파악하고 있으면 굉장히 많은 도움이 되는 것 같습니다.

머신 러닝 기능이라는 게 개발하는 데 한 달이나 두 달 정도의 단기간에 끝나지 않는 경우가 대부분입니다. 그러다 보니 프로젝트를 진행하는 도중에 관련된 기능의 전체적인 로드맵 방향이 확 바뀌는 경우가 발생할 수 있습니다. 만약 그렇게 된다면 당연히 만들고 있던 기능도 새로운 방향에 맞춰 변화시켜야 할 필요가 발생합니다.

또한 개발 과정에서 그전에는 파악하지 못했던 사용자들의 새로운 구체적인 요구 사항을 발견할 수도 있습니다. 그러한 구체적인 요구 사항을 목표로 기능을 개발했을 때 가장 좋은 결과를 얻을 수 있었던 것 같습니다. 앞서 소개 드렸던 CardOCR이나 비디오 하이라이트 위저드 모두 개발 도중에 구체적인 사용자 요구 사항을 발견했고 그에 맞춰 기능을 변경한 사례들이었습니다.

기술은 목적이 아니라 수단이다

기술이라는 것은 어디까지나 사용자들의 요구 사항을 해결하기 위한 수단이지 목적이 아니라는 것을 잊으면 안 될 것 같습니다. 개발자인 제 자신도 종종 실수하는 부분인데요. 무언가 멋져 보이는 새로운 기술이 나타나면 그저 이 기능을 한 번 사용해보고 싶다는 관점에서 기능 개발을 시작하는 경우가 있습니다. 그런데 이런 식으로 시작하면 보통 결과가 좋지 않았습니다.

항상 어떤 사용자 기능을 어떤 사용자의 요구 사항을 목표로 어떤 기술을 적용해 개발하고 있는지를 염두에 두는 것이 필요한 것 같습니다. 가능하다면 이런 사용자들의 요구 사항과 기술 사이에서 일종의 중재자 역할을 해주시는 분이 계시면 좋겠다고 생각해 왔는데요. 아마도 기획자분들이 그런 역할을 해주실 수 있겠죠?

UX는 탄력 있게 설계하자

머신 러닝을 사용한 기능을 설계하거나 기획하다 보면 흔히 머신 러닝 기능의 결괏값은 언제나 참이 나올 것이다, 혹은 정답만 나올 것이라고 가정하고 기획하는 경우가 많지만, 실제로는 반드시 일정 수준의 오류를 동반하게 되어 있습니다. 특히 모바일 기기에서 구동되는 온 디바이스 머신 러닝 같은 경우에는 대부분 성능의 한계가 명확하기 때문에 가능하면 오류를 감수할 수 있는 형태로 UX를 설계하는 것이 좋습니다.

예를 들어 CardOCR 같은 경우에 카드를 인식하려고 몇 번이나 시도를 했는데도 인식이 잘 안됐다면 수동으로 번호를 입력할 수 있는 UI를 제공해 줄 수도 있을 것입니다. 아니면 아예 기능의 UX를 추천 형태로 제공하면 사용자가 앱을 사용하는 UX에 크게 방해받지 않기 때문에 이와 같은 형태로 설계하는 것이 좋지 않을까 생각합니다.

가장 쉽고 간편한 접근 방법은 개선이다

사실 가장 쉽고 간편하게 머신 러닝을 적용하는 방법은 기존 기능을 개선하는 것입니다. 기존에 있던 기능의 UX를 최대한 그대로 유지하면서 성능만 높이는 것이 가장 안전하고 쉬운 방법이지 않을까 생각합니다. 물론 이 방법은 임팩트가 큰 새로운 기능을 제공하지는 못한다는 단점이 있긴 합니다.

플랫폼에서 지원하는 기능을 사용하자

마지막으로 되도록 Google ML Kit이나 Apple Core ML처럼 플랫폼 차원에서 지원하는 머신 러닝 기능을 사용하시는 것을 추천드립니다. 여러 가지 장점이 많은데요. 아마 그중에서 가장 좋은 점은 앱 크기가 많이 늘어나지 않는다는 점이라고 생각합니다. Android 같은 경우에는 워크 매니저와 같이 백그라운드 작업을 도와주는 API도 제공하기 때문에 적극적으로 사용해보시면 어떨까 생각합니다.

 

마치며

이번 글에서는 머신 러닝 기능을 LINE 앱에 적용해 본 사례와 그 경험에서 얻은 교훈을 공유드렸습니다. 머신 러닝 도입을 고민하고 계시는 분들께 도움이 될 수 있다면 좋겠습니다. 아래에서 발표 영상도 확인하실 수 있습니다. 긴 글 읽어주셔서 감사합니다.