morphological-analysis

1 개의 포스트

초경량 클래식 형태소 분석기 개발기 - tech.kakao.com (새 탭에서 열림)

카카오는 모바일 환경의 엄격한 리소스 제한을 극복하기 위해 C++20 기반의 초경량 형태소 분석기를 직접 개발했습니다. 최신 딥러닝 방식 대신 전통적인 Viterbi 알고리즘과 LOUDS 기반의 Trie 압축 기술을 결합하여, 바이너리 크기를 200KB 수준으로 최소화하면서도 효율적인 사전 탐색 성능을 확보하는 데 성공했습니다. ### Rust 대신 C++20을 선택한 이유 * **바이너리 크기 최적화**: Rust는 현대적인 기능을 제공하지만 표준 라이브러리 포함 시 바이너리 크기가 MB 단위로 커지는 경향이 있어, KB 단위의 관리가 필요한 모바일 환경에는 부적합했습니다. * **기존 인프라 활용**: 모바일 OS 환경에 이미 포함된 C++ 표준 라이브러리를 활용함으로써 최종 결과물 크기를 약 200KB 수준으로 억제했습니다. * **현대적 문법 적용**: C++20의 `Concepts`를 사용하여 템플릿 제약을 명확히 하고, `std::span`과 `std::ranges` 등을 통해 메모리 안전성과 코드 가독성을 동시에 높였습니다. ### LOUDS 알고리즘을 통한 사전 데이터 압축 * **비트 시퀀스 기반 트리**: 트리 구조를 포인터 대신 비트열로 표현하는 LOUDS(Level-Order Unary Degree Sequence)를 채택하여 메모리 사용량을 정보 이론적 하한에 가깝게 줄였습니다. * **높은 압축률 달성**: 약 76만 개의 노드를 가진 방대한 사전 데이터를 단 9.4MB로 압축했으며, 이는 일반적인 CSV 방식 대비 훨씬 효율적인 수치입니다. * **한글 최적화 인코딩**: 한글을 2바이트로 처리하고 외국어는 플래그로 구분하는 등 별도의 내부 인코딩 방식을 적용하여 사전의 물리적 크기를 추가로 절감했습니다. ### Select 비트 연산 최적화와 성능 개선 * **병목 지점 파악**: LOUDS 구조에서 특정 노드의 위치를 찾는 `select0` 연산이 전체 사전 탐색 시간의 약 90%를 점유하는 성능 병목임을 확인했습니다. * **인덱싱 기반 탐색**: 비트 시퀀스를 64비트 청크로 나누고 각 구간까지의 '0의 누적 개수'를 미리 기록하여, 바이너리 서치를 통해 탐색 범위를 획기적으로 좁혔습니다. * **비트 병렬 처리**: 청크 내부에서는 비트 연산과 시프트를 조합한 병렬 카운팅 기법을 활용하여 하드웨어 수준에서 연산 속도를 극대화했습니다. ### 실용적인 결론 모바일 클라이언트 환경처럼 리소스가 극도로 제한된 곳에서는 무거운 딥러닝 모델보다 최적화된 클래식 알고리즘이 더 강력한 대안이 될 수 있습니다. 특히 LOUDS와 같은 정적 트리 압축 기법과 비트 수준의 연산 최적화를 결합하면, 성능 손실 없이도 극적인 용량 절감이 가능함을 이 개발 사례가 증명하고 있습니다.