LINE Corporation이 2023년 10월 1일부로 LY Corporation이 되었습니다. LY Corporation의 새로운 기술 블로그를 소개합니다. LY Corporation Tech Blog

Blog


다수의 연합학습을 지원하기 위한 LFL 클라이언트 플랫폼

Tech-Verse 2022에서 장혁재 님이 발표한 다수의 연합학습을 지원하는 LFL 클라이언트 플랫폼 세션 내용을 옮긴 글입니다.

안녕하세요. LINE Plus 메시징 클라이언트 엔지니어링 팀 장혁재입니다. 이번 글에서는 2022년 10월에 출시한 LINE의 연합 학습(LINE federated learning, LFL) 기능 중 클라이언트 플랫폼에 대해 말씀드리겠습니다.

앞으로는 지금까지와는 다르게 복수의 연합 학습이 동시에 운영되는 상황이 보편화될 것으로 예상합니다. 이번 글에서는 다수의 연합 학습을 운영할 때 어떤 문제가 발생할 수 있고, 그 문제를 어떤 식으로 해결할 수 있는지 공유하려고 합니다. 참고로, 연합 학습에서 사용하는 구체적인 머신 러닝 방법이나 개인 정보 보호 방법에 대해 관심 있으시다면 Kikuchi Haruka 님이 발표하신 연합 학습을 이용한 LINE 스티커 추천을 참고하시기 바랍니다.

연합 학습이란

먼저 간략하게 연합 학습이 무엇인지 살펴보겠습니다. 보통 머신 러닝이라고 하면 아래 왼쪽 그림처럼 클라우드 기반을 이야기합니다. 클라우드 서버에서 수집한 사용자 로그로 머신 러닝 모델을 학습시킨 후 그 모델을 서버에서 직접 사용하거나 아니면 모바일 단말로 배포해서 기능을 제공하는 방식입니다. 이 방식에서는 서버에서 사용자 로그를 수집하기 때문에 민감한 개인 정보가 수집될 수 있으며, 사용자에 따라 그와 같은 정보 제공을 거부할 수 있다는 문제가 있습니다.

이에 위 오른쪽 그림과 같은 연합 학습이 대안으로 등장했습니다. 연합 학습에서는 클라우드 서버에서 사용자 로그를 수집하지 않습니다. 대신 사용자 단말로 모델을 배포해서 단말 내에서 사용자 로그로 학습을 수행하고, 그 결과 모델을 다시 서버로 모아서 새 모델을 만든 뒤, 다시 사용자 단말로 배포하는 흐름으로 작업을 진행합니다. 기존 클라우드 기반 머신 러닝과 비교해 개인 정보 보호 측면에서 비교적 유리하다는 특징이 있습니다.

연합 학습 적용 사례

이런 장점 덕분에 Google에서 처음 Gboard라는 키보드 앱에 연합 학습을 도입한 후 Apple과 Meta에서도 활발하게 관련 연구를 진행하고 있습니다. 한국에서도 NAVER에서 앞서 말씀드린 예와 유사한 '스마트 키보드'라는 키보드 앱에 연합 학습을 적용하는 등 관련 사례가 등장하고 있는데요. LINE 역시 여러 기능에 연합 학습 도입을 검토해 왔고, 이번에 그 첫 사례로 프리미엄 스티커 서비스 구독자들을 대상으로 스티커 추천에 연합 학습을 적용했습니다.

기술 관점에서 기존 기능과 차별되는 점은 이전에는 스티커 사용 기록만으로 스티커를 추천했다면, 이제는 연합 학습을 통해 기기에서 스티커 사용 기록으로 머신 러닝 모델을 학습해 기존보다 더 사용자 취향에 잘 맞는 스티커를 추천한다는 점입니다. 지난 10월에 이 기능을 출시한 뒤 최근 진행한 A/B 테스트 결과 스티커 다운로드 비율이 통계적으로 유의미하게 약 5.56% 정도 상승한 것으로 나타났습니다.

연합 학습에 '플랫폼'이 필요한 이유

LINE에는 스티커 외에도 여러 다양한 기능이 있습니다. 앞으로 각 기능에 연합 학습이 적용되는 상황을 쉽게 상상해 볼 수 있을 텐데요. 연합 학습을 구현할 때에는 반드시 필요한 몇 가지 기능이 있습니다. 예를 들어 머신 러닝 모델을 서버에서 다운로드하는 기능이나 학습한 결과를 다시 서버로 전송하는 기능, 사용자 로그를 수집해서 모델을 학습하는 기능 등이 있는데요. 만약 LINE 내 여러 기능에서 연합 학습을 사용한다고 가정할 때, 각 연합 학습이 이런 기능을 각자 만드는 것보다는 어떤 플랫폼 같은 것을 통해서 공통 기능으로 제공받는 것이 당연히 효율적일 것입니다.

게다가 연합 학습은 머신 러닝 모델을 단말기에서 학습하는 '온 디바이스 학습'도 수행해야 하는데요. 이는 상당히 많은 자원을 소비하는 작업입니다. 자원이 한정적인 모바일 환경 특성상 만약 여러 연합 학습 모델이 별다른 제약 없이 동시다발적으로 모델 학습을 실행하면 메모리 부족으로 학습이 실패할 수도 있으며, 배터리가 금방 소진된다거나 사용 중 기기가 버벅거리는 것 같은 여러 문제가 발생할 수 있습니다.

따라서 이런 모델 학습을 한곳에서 조율하고 관리할 주체가 필요합니다. 결론적으로, 여러 연합 학습을 운영하기 위해서는 단순히 공통 기능을 제공해 주는 것뿐 아니라 모델 학습을 효율적으로 진행하기 위해 일종의 플랫폼 구조가 꼭 필요합니다.

다수의 연합 학습을 지원하기 위한 클라이언트 플랫폼

이와 같이 다수의 연합 학습을 지원하기 위해서 클라이언트 플랫폼과 전체 아키텍처를 어떻게 설계했는지 말씀드리겠습니다.

LINE 연합 학습의 아키텍처

아래는 다수의 연합 학습을 지원하기 위한 LINE 연합 학습(LINE federated learning, 이하 LFL)의 아키텍처입니다. 먼저 그림을 크게 좌우로 나눠 보면, 서비스를 제공하는 서비스 영역(왼쪽)과 머신 러닝을 위한 플랫폼(오른쪽)으로 양분되는 구조입니다. 이와 같이 분리한 이유는 여러 서비스의 연합 학습을 지원할 때 각 영역에 맞는 특성을 반영할 수 있는 분리된 구조가 훨씬 효율적이기 때문입니다.

다음으로 구성 요소를 살펴보겠습니다. 구성 요소에는 크게 네 가지가 있습니다.

먼저 왼쪽 위에 위치한 피처 서비스 서버(feature service server)가 있습니다. 스티커 추천 서비스를 예로 들면 스티커 서버가 이 역할을 하며, 여기서 각 사용자에게 맞는 스티커 후보군을 생성합니다. 이와 같이 연합 학습을 위해서 각 서비스에서 추가로 생성하는 정보를 '피처 모델(feature model)'이라고 부르고 있습니다.

두 번째로 왼쪽 아래에 위치한 피처 서비스 클라이언트(feature service client)가 있습니다. LINE 앱에서 실제로 스티커를 추천하는 곳입니다. 여기에서 앞서 말씀드린 피처 모델을 다운로드해서 추천할 때 같이 사용합니다.

세 번째로 오른쪽 위에 위치한, 연합 학습 모델 배포와 수집, 통합을 담당하는 LFL 서버가 있습니다.

마지막으로 이번 글의 핵심이라고 할 수 있는 LFL 클라이언트 플랫폼이 있습니다. LFL 클라이언트 플랫폼은 LFL 서버에서 머신 러닝 모델을 다운로드하고, LINE 앱에서는 추천 요청을 받아서 스티커를 추천하며, 사용자 로그를 받아서 학습을 수행한 뒤 그 결과를 다시 서버로 전송하는 역할을 합니다.

LFL 클라이언트 플랫폼 아키텍처

LFL 클라이언트 플랫폼 내부를 살펴보면 아래 그림에서 보는 것처럼 세 개의 주요 컴포넌트로 나뉘어 있습니다.

이 그림에서 가장 중요한 점은, 공통 기능을 담당하는 공통 모듈(Common mudule)이 위에 위치하고 그 밑에 여러 개의 LFL 애플리케이션 모듈(LFL application module)이 위치하는 구조라는 점입니다. 즉 공통 모듈이 각 연합 학습의 애플리케이션 모듈을 관리하는 일종의 매니저 역할을 합니다. 연합 학습 애플리케이션이 여러 개 있더라도 공통 모듈이 모든 연합 학습에 필요한 머신 러닝 모델과 설정 다운로드, 결과 업로드, 학습 스케줄링과 같은 공통 기능을 전담해서 관리합니다. 애플리케이션 모듈은 각 서비스마다 별도로 구현해야 하는 모델 학습과 추론, 머신 러닝 모델 설정, 사용자 로그 저장 등을 담당합니다. 이렇게 역할을 적절하게 나눈 구조 덕분에 여러 연합 학습을 문제없이 관리할 수 있습니다. 

의존 관계 역전 원칙 적용

공통 모듈이 LFL 애플리케이션 모듈을 관리하는 구조로 설계할 때 중요하게 고려한 점이 하나 있습니다. 클린 아키텍처 같은 곳에서 자주 이야기하는 의존 관계 역전 원칙입니다. 앞서 공통 모듈이 일종의 매니저 역할을 한다고 말씀드렸는데요. 일반적인 경우라면 아래 그림과 같이 상위 계층인 공통 모듈이 하위 계층인 애플리케이션 모듈에 의존하는 형태가 됩니다.

그런데 여기서 애플리케이션 모듈은 LINE 앱에 있는 각 피처 서비스와 직접 연관되기 때문에 서비스 기능 변경이나 추가, 삭제와 같은 잦은 변화에 바로 영향을 받습니다. 아래 왼쪽 그림과 같이 관련 서비스가 사라지면서 애플리케이션 B 모듈이 아예 없어지는 경우를 예로 들어보겠습니다. 이런 경우 상위 계층인 공통 모듈에서도 관련 함수를 다 삭제해야 합니다.

이와 같이 의존 관계 때문에 하위 모듈에서 발생하는 변화가 상위 모듈에 영향을 주는데요. 이때 아래 오른쪽 그림처럼 모듈 간 의존 관계를 역전시키면 인터페이스를 통해서 추상화할 수 있고, 각 애플리케이션은 이 인터페이스를 상속받아서 구현하는 구조로 만들 수 있습니다. 그러면 상위 계층인 공통 모듈이 애플리케이션 모듈로부터 독립할 수 있고, 더 이상 하위 모듈 변경에 영향받지 않습니다.

의존 관계 역전 원칙 적용 후 작동 사례

이제 추상화에 기반한 구현이 실제로 어떻게 작동하는지 모델 학습 실행을 예로 들어보겠습니다. OS에서 트리거한 백그라운드 작업이 공통 모듈에서 시작하면 어떤 애플리케이션을 학습할지 결정하고 학습의 실행을 호출해야 하는데요. 이때 공통 모듈 내에 있는 인터페이스 API를 통해서 애플리리케이션에 접근합니다. 여기서 애플리케이션의 실제 구현체에 접근할 때 의존성 주입 라이브러리를 사용하는데요. 이를 통해 공통 모듈에서는 실제 개별 애플리케이션 구현체에 의존성이 없어도 아무 문제 없이 학습을 시작시킬 수 있습니다.

이와 같이 의존 관계를 역전한 구조에서는 애플리케이션 추가와 삭제도 쉽습니다. 예를 들어 프리미엄 스티커 추천 외에 새로운 연합 학습을 구현해서 넣어야 하는 경우를 생각해 보겠습니다. 이때 이미 선언돼 있는 LFL의 애플리케이션 인터페이스를 구현해서 새로운 애플리케이션 모듈을 만들어 이를 플랫폼에 추가하면 공통 모듈이나 기존 애플리케이션 모듈에 아무 영향 없이 새로운 연합 학습을 넣을 수 있습니다.

온 디바이스 학습을 효율적으로 처리하는 방법

지금까지 LFL 아키텍처와 클라이언트 플랫폼을 어떻게 설계했는지 소개했습니다. 이제 클라이언트 플랫폼에서 온 디바이스(on-device) 학습을 어떻게 효율적으로 처리하고 있는지 소개하겠습니다.

기기에서 온 디바이스 학습을 시작하는 조건

연합 학습에서 온 디바이스 학습은 가장 중요한 키포인트라고 할 수 있습니다. 자원이 제한된 모바일 단말에서 모델 학습을 잘못 운영하면 사용자가 바로 불편함을 느낄 수 있고 LINE 앱 평판에도 나쁜 영향을 끼칠 수 있는데요. 이를 방지하기 위해 모델 학습을 시작하기 위한 몇 가지 기본 조건을 세웠습니다.

먼저 배터리가 부족하지 않거나 충전 상태여야 합니다. 다음으로 저장 공간이 충분히 확보된 상태여야 합니다. 마지막으로 가장 중요한 조건인데요. 사용자가 기기를 사용하지 않는 상황이어야 합니다.

여기서 마지막 조건이 백그라운드 처리(background processing)입니다. 몇 년 전만 해도 구현하기 상당히 어려운 조건이었지만, 다행히 최근 머신 러닝에 대한 관심이 높아지면서 iOS와 Android, 이 양대 OS에서 모두 이를 위한 특별한 API를 제공하고 있습니다. iOS에서는 BGTaskSchedulerBGProcessingTask와 같은 API를, Android에서는 WorkManager라는 API를 이용해 사용자가 기기를 일정 시간 이상 사용하지 않고 배터리가 충전 중인 상태일 때 백그라운드 작업을 실행할 수 있습니다. iOS와 Android 모두 10분 이상 백그라운드 작업을 실행할 수 있게 해 주는데요. 사용자가 다시 기기를 사용하기 시작하면 언제든지 강제로 이 작업이 종료될 수 있다는 점을 개발할 때 유념해야 합니다.

온 디바이스 학습 중 발생할 수 있는 문제와 해결 방법

사용자 간 불균등한 학습 참여로 학습 품질 저하 및 개인 정보 노출 위험 증가: 롤아웃과 업로드 제한 설정

아래 왼쪽 그림은 전체적으로 연합 학습이 어떻게 진행되는지 표현한 그림입니다. 머신 러닝 모델을 여러 단말로 배포하고, 단말에서 사용자 로그로 학습한 후, 다시 서버로 모아서 병합하고 재배포하는 것이 연합 학습의 기본 운영 사이클입니다.

위와 같이 연합 학습을 진행할 때 각 단말에서 아무런 제약 조건 없이 마음대로 학습하도록 놔두면 위 오른쪽 그래프처럼 모델이 배포되자마자 학습이 폭발적으로 진행됩니다. 그 결과 연합 학습 모델에 어떤 특정 시점 혹은 특정 사용자의 영향이 과도하게 반영될 수 있습니다. 이는 모델의 전체 학습 품질이 낮아지는 결과로 이어질 수 있으며, 해당 학습에 특정 사용자만 과도하게 참여하면서 개인 정보가 노출될 위험도 커집니다.

이를 방지하기 위해 아래 그림 오른쪽 설정 파일과 같이 롤아웃(rollout)과 업로드 제한(uploading limit), 두 가지를 설정합니다.

롤아웃은 위 슬라이드 아래에 보이는 수식처럼 개별 사용자의 고유 키값에서 얻은 해시를 이용해서 사용자를 전체적으로 균등한 그룹으로 나누고, 자기가 속해 있는 그룹 차례가 왔을 때에만 학습에 참여하게 합니다. 롤아웃 값을 이용해서 위 슬라이드 왼쪽 그래프와 같이 전체 사용자가 모델 배포 초기에 몰리지 않고 전 기간에 걸쳐 균등하게 학습에 참여하도록 만들었습니다.

업로드 제한은 학습 결과를 일정 횟수 이상 서버로 업로드하는 것을 막기 위한 설정입니다. 이를 통해 개인 정보가 과도하게 노출될 수 있는 위험을 막을 수 있습니다.

백그라운드 작업 시 반복 요청으로 단말과 서버 부하 증가: 재시도 인터벌과 훈련 인터벌 설정

다시 모바일 단말 입장으로 돌아와 생각해 보면 롤아웃과 업로드 제한만으로 아직 해결되지 않은 문제가 있습니다. 바로 모델 학습을 위해서 반복적으로 백그라운드 작업을 시도한다는 점입니다.

이와 관련해 학습을 시작하기 위한 조건이 충족되지 않았을 때의 롤아웃 관련 예시를 살펴보겠습니다. 아래 그림처럼 백그라운드 작업이 시작되면 서버에서 새로 롤아웃 값을 가져와서 그에 따라 학습을 시작할지 말지를 결정합니다.

만약 롤아웃 값이 만족되지 않아 학습을 시작할 수 없다면 반복적으로 백그라운드 작업을 시작해서 서버에서 변경된 롤아웃 값을 받으려고 시도합니다. 이 때문에 모바일 단말과 서버 양쪽의 부하가 매우 커질 수 있습니다.

또 다른 경우로 모델 학습이 성공적으로 끝난 경우를 살펴보겠습니다. 학습이 끝나면 결과를 서버에 업로드하고 학습에 사용한 로그는 개인 정보 보호 차원에서 보통 삭제합니다. 이후 다시 모델을 학습하기 위해서는 사용자 로그가 다시 충분히 쌓여야 하는데요. 문제는 새로운 로그가 다시 충분히 쌓일 때까지 반복해서 백그라운드 작업을 시작해서 학습할 수 있는지 확인한다는 것입니다.

앞서 언급했듯 모델 학습을 위한 백그라운드 처리를 하기 위해서는 기기를 일정 시간 이상 사용하지 않아야 한다는 기기 미사용 조건이 있습니다. 이에 따라 학습은 일반적으로 야간에 사용자가 수면하면서 충전하는 시간에 주로 실행됩니다. 따라서 밤에 학습한 뒤 로그를 다 지웠다면 다시 학습을 위한 충분한 로그가 쌓이기 전까지, 적어도 다음 날 밤까지는 다시 시도할 필요가 없습니다.

정리하면, 학습 시작 조건을 충족하지 못한 상태에서 불필요하게 백그라운드 작업이 반복해서 실행되는 문제가 발생할 수 있습니다.

이를 막기 위해 '재시도 인터벌(retry interval)'과 '훈련 인터벌(train interval)'이라는 시간 설정을 만들었습니다. 즉 백그라운드 작업을 시작했는데 모델 학습 시작 조건이 충족되지 않았다면 최소한 재시도 인터벌 이후에 다시 학습을 시도하며, 만약 학습에 성공했다면 로그가 다시 충분히 쌓일 수 있도록 최소한 훈련 인터벌 이후에 다시 학습을 시도합니다. 이를 통해 모바일 단말과 서버의 부담을 줄일 수가 있었습니다.

여러 애플리케이션을 스케줄링하기 위한 인터벌 기반 스케줄링

앞서 살펴본 것과 같이 여러 설정을 해야 하는 상황에서 학습해야 할 애플리케이션이 여러 개라면 어떻게 해야 할까요?

여러 학습을 스케줄링할 때도 아래 슬라이드 그림처럼 각 애플리케이션의 재시도 인터벌과 훈련 인터벌을 모두 지켜야 합니다. 또한 온 디바이스 학습이 발생시킬 부하를 생각하면 한 번에 하나의 모델 학습만 진행해야 할 테니 각 애플리케이션 학습 시간이 얼마나 걸릴지 예측해서 이를 바탕으로 스케줄링해야 합니다. 그래야 아래 슬라이드 그림처럼 여러 애플리케이션 학습을 서로 겹치지 않게 스케줄링할 수 있습니다.

예를 들어 아래 슬라이드에서 빨간 화살표가 가리키고 있는 것처럼 애플리케이션 C의 학습 시도가 실패했다면, 다시 학습을 스케줄링하기 위해서는 다른 애플리케이션들이 어떤 상황인지 고려해야 합니다.

애플리케이션 A는 훈련 인터벌에 해당해서 큰 문제가 없겠지만 애플리케이션 B는 재시도 인터벌이 끝나가고 있습니다. 곧 학습을 시작할 수 있는 상황이 되니 애플리케이션 B가 학습을 시작했을 때 과연 언제쯤 끝날 것인지 예측해야 하는데요. 위 경우에서는 B의 학습 시간이 애플리케이션 C의 재시도 인터벌보다 깁니다. 이런 경우에는 애플리케이션 B의 학습 종료 시간에 맞춰 애플리케이션 C가 학습을 시작하도록 스케줄링해야 합니다.

그런데 이렇게 설명하고 있는 저조차도 '이거 너무 복잡하다'라는 생각이 듭니다. 더 큰 문제는 애플리케이션 수가 늘어날수록 상황과 변수가 많아지면서 스케줄링과 예외 처리가 복잡해지며 난이도가 기하급수적으로 올라간다는 것입니다.

이에 LFL에서는 아예 관점을 전환해서 각 애플리케이션을 스케줄링하는 게 아니라 하나의 작업 세션을 생성한 후 이걸 모든 애플리케이션이 공유해서 학습에 사용하는 '인터벌 기반 스케줄링(interval-based scheduling)'이라는 것을 고안했습니다.

인터벌 기반 스케줄링에서는 작업 세션에서 매번 인터벌 조건을 충족한 애플리케이션을 골라 그 애플리케이션들로 모델 학습을 진행합니다. 아래 슬라이드 하단에 수식이 있는데요. 이 수식으로 각 애플리케이션의 인터벌 조건을 확인해 가장 빨리 조건이 충족되는 시간을 계산해서 이를 다음 작업까지의 지연 시간으로 고려해 예약하는 방식으로 스케줄링합니다.

이와 같은 인터벌 기반 스케줄링에는 크게 두 가지 장점이 있습니다.

먼저 한 번에 하나의 모델 학습만 진행한다고 확실히 보장할 수 있습니다. 백그라운드 작업 하나를 공유하니 당연한 얘기이기도 합니다.

다음으로 아무리 애플리케이션이 많고 각 애플리케이션 인터벌 조건이 복잡하더라도 내 상황에서 최소 지연 시간만 계산해서 다음 작업을 등록하면 되는 구조입니다. 이를 '등록하고 잊어버리기(register & forget)'이라고 부르는데요. 이렇게 간단하게 학습 스케줄링을 구현할 수 있습니다.

인터벌 기반 스케줄링 단계별 소개

인터벌 기반 스케줄링에서 구체적으로 어떻게 모델 학습을 진행하는지 각 단계별로 설명하겠습니다.

우선 앞서 말씀드렸듯 OS API를 통해 백그라운드 작업이 시작되면, 가장 먼저 인터벌 조건으로 애플리케이션을 필터링해서 학습할 애플리케이션을 고릅니다. 이때 애플리케이션의 우선순위나 마지막 학습 시간 같은 여러 사항을 고려해서 고를 수 있습니다.

다음으로 서버의 모델 버전과 단말의 모델 버전을 비교해서 최신으로 업데이트하고, 지연 시간 계산에 필요한 학습 시도 타임스탬프를 갱신합니다.

이후 학습에 필요한 여러 조건을 확인합니다. 앞서 말씀드린 롤아웃 같은 설정이나 학습에 필요한 로그가 충분한지 등을 확인합니다.

학습 조건을 모두 충족한다면 모델 학습을 시작하고, 무사히 학습을 마쳤다면 지연 시간 계산에 필요한 학습 성공 타임스탬프를 갱신한 뒤 결과를 서버로 업로드합니다.

마지막으로 각종 타임스탬프와 애플리케이션 인터벌 설정을 활용해서 최소 지연 시간을 계산한 후 다음 작업을 예약하고 작업을 마칩니다.

LFL 클라이언트 플랫폼 내부 소개

다음으로 LFL 클라이언트 플랫폼에서 사용한 머신 러닝 라이브러리와, 애플리케이션 모듈 내부 기능을 소개하겠습니다.

LFL 클라이언트 플랫폼에서 사용한 머신 러닝 라이브러리, YFL

LFL의 핵심인 온 디바이스 학습에는 LINE에서 자체 개발한 YUKI 연합 학습(YUKI federated learning), 줄여서 YFL이라는 라이브러리를 사용했습니다.

라이브러리를 자체 개발한 이유는 연합 학습을 위한 전용 라이브러리가 아직 없었고, TensorFlow나 Pytorch 같이 유명한 라이브러리는 용량이 너무 커서 모바일 환경에 적합하지 않았기 때문입니다.

이에 ONNX Runtime을 기반으로 한 새로운 라이브러리를 개발했습니다. ONNX Runtime은 iOS와 Android를 모두 지원하고, TensorFlow나 Pytorch 모델을 변환할 수 있다는 장점이 있습니다.

YFL을 만들면서 가장 중요하게 생각했던 부분은 라이브러리의 크기였습니다. 현재 YFL에서는 몇 가지 제한된 오퍼레이션과 CPU 백엔드만을 지원합니다. 또 하나 중요한 특징은 LDP(local differential privacy)를 지원한다는 것입니다. 이는 개인 정보 보호와 관련이 있으며, 보다 자세한 내용은 연합 학습을 이용한 LINE 스티커 추천 세션을 참고하시기 바랍니다.

LFL 애플리케이션 내부 기능 소개

LFL 애플리케이션 내부에는 LINE 앱 피처 서비스에서 추론할 때 사용할 추론 모델과 학습하기 위한 학습 모델이 존재하며, 각 모델의 설정값과 함께 관리하고 있습니다. 특히 업로드 제한이나 롤아웃, 개인 정보 보호에 사용하는 LDP 관련 설정은 모두 개인 정보와 관련 있기 때문에 이 값들에 문제가 없는지 내부에서 무결점 검사도 시행합니다.

새 버전의 모델이 나와서 업데이트할 때는 업데이트 종류에 따라서 각각 다른 정책을 취합니다.

예를 들어 패치 업데이트 같은 경우 모델 자체 변화는 없기 때문에 설정값만 리셋하고 사용자 로그는 보존하는 반면, 메이저 업데이트같이 전체 모델이 변경되는 경우에는 로고와 설정을 다 리셋합니다. LINE 앱 피처 서비스에서 연합 학습과 연동해서 사용하는 일종의 부가 정보인 피처 모델 같은 게 있다면 해당 모델도 같이 업데이트합니다.

다음으로 사용자 로그 DB에서는 저장 공간 효율과 개인 정보 보호를 위해서 딱 학습에 필요한 개수만 보존합니다. 이보다 많이 들어올 경우 오래된 순으로 삭제하며, 학습에 사용한 로그도 바로바로 삭제합니다.

마치며

마지막으로 약 1년간 LFL 프로젝트에 참여하면서 느꼈던 몇 가지를 공유하려고 합니다.

다양한 조직이 다양한 기능을 만들기 위해 만나면 당연한 얘기지만 복잡도가 굉장히 높아지는데요. 저 역시 제가 개발했던 클라이언트 플랫폼 외에 서버나 머신 러닝, 스티커 기능과 같은 여러 기능을 어느 정도 이해하고 있어야 작업을 잘 진행할 수 있었습니다. 이와 관련해서 이런 큰 프로젝트에 참여하시는 분들에게 드릴 수 있는 한 가지 팁이라면, 다른 조직과 협력해서 결정해야 되는 부분을 주의 깊게 미리미리 살펴보면 좋다는 것입니다. 보통 이런 부분들은 작동 방식이나 방향과 같은 것이 자명한 경우보다는 협의에 따라서, 혹은 어떤 정책을 선택하느냐에 따라서 결정되는 경우가 많습니다. 예를 들어 앞서 얘기했던 머신 러닝 모델을 업데이트할 때 각 업데이트의 종류에 따라서 데이터를 어디까지 삭제할 것인가와 같은 사항은 정책으로 정하는 부분인데요. 이런 사항들을 미리 협의해서 정해 놓으면 프로젝트를 진행할 때 도움이 될 것이라고 생각합니다.

다음으로 두말할 필요도 없이 테스트는 정말 중요하다는 것입니다. 단위 테스트는 필수라고 할 수 있는데요. LFL과 같이 다양한 컴포넌트를 서로 연동하는 경우라면 일종의 샘플 앱 같은 것을 만들어 보는 걸 추천합니다. 클라이언트 플랫폼 같은 경우에도 샘플 앱을 구현해서 LINE 앱이나 LFL 서버와 같이 연동해야 하는 외부 환경을 추상화했는데요. 이를 통해 일종의 엔드 투 엔드(end-to-end) 테스트를 해 볼 수 있고, 추후 문제가 발생했을 때 샘플 앱으로 문제를 재현해 볼 수 있기 때문에 문제의 원인이 어디에 있는지 초기에 빠르게 파악할 수 있습니다.

다음으로 모델 학습에 사용하는 백그라운드 작업을 시작하려면 일정 시간 동안 기기를 사용하지 않는다는 조건을 충족해야 하기 때문에, 학습에 문제가 있더라도 알기 어렵고 한 번 테스트를 하려면 몇 시간씩 기다려야 해서 테스트를 자주 반복하는 게 쉽지 않은데요. Android 같은 경우 이와 관련해서 제공하는 테스트 툴이 있기 때문에 이런 사항을 꼭 확인하고 테스트에 사용해 보시기를 추천합니다.

마지막으로 모델 학습같이 중요한 작업에 대해서는 원격 로깅을 꼭 추가하는 것을 추천합니다. 보통 출시하기 전에 QA 팀과 같이 QA를 진행하실 텐데요. 백그라운드 작업의 특성 때문에 에러 로그를 취득하기가 어렵습니다. 꼭 에러가 아니더라도 백그라운드 작업이 내부 상태에 따라서 시작하지 않는 경우가 많습니다. 따라서 어떤 문제로 백그라운드 작업 자체가 시작하지 않았는지 혹은 백그라운드 작업은 시작했지만 학습에 어떤 문제가 있는지와 같은 사항을 원격 로깅을 통해서 외부에서 볼 수 있으면 QA 팀과 테스트를 좀 더 수월하게 진행할 수 있었습니다.

LFL 프로젝트는 다양한 조직에서 여러 기능을 담당하는 많은 분이 모여 함께 진행했던 프로젝트였는데요. 이렇게 여러 조직이 모여 좋은 성과를 만들어 낼 수 있어서 큰 보람을 느꼈습니다. 이 자리를 빌려서 함께 프로젝트를 진행했던 모든 분께 감사하다고 말씀을 드리며 글을 마치겠습니다. 긴 글 읽어주셔서 감사합니다.