본문 바로가기

호에에엥?/Side Project

꼬맨틀로 NLP(자연어 처리) 찍먹하기 (1) - 꼬맨틀의 단어 유사도 측정의 원리와 유사도가 이상한 이유!

*필자는 자연어 처리 전문가가 아니라 말하는 감자입니다. 틀린 내용이 있다면 너그러히 이해하고 알려주세요.

 

최근에 친한 친구 덕분에 꼬맨틀이라는 게임을 알게 됐습니다. 꼬맨틀은 '단어 유사도 추측 게임'입니다.

 

나중에 시간이 되면 정리해볼 Wordle이라는 게임이 처음으로 하루에 모든 사람들이 동일한 단어를 제한된 기회 안에 맞추는 성격의 게임으로 인기를 얻었던 것 같습니다.

 

그 다음으로 나온 게임이 Semantle 입니다. Wordle이 횟수가 제한되어 있고, 단순히 일치하는 알파벳에 대한 정보를 줬지만,  Semantle은 횟수 제한은 없고 단어를 입력하면 해당 단어가 정답 단어와 의미론적으로(Semantic하게) 얼마나 유사한 지에 대한 정보를 줍니다.

 

꼬맨틀은 Semantle의 한국어 버전이라고 볼 수 있습니다. 

Figure 1. 꼬맨틀 플레이 화면

플레이 하는 모습은 대충 이런 식입니다. 단어를 입력하고 해당 단어의 유사도를 알려줍니다. 유사도를 기준으로 1000위 안의 단어들을 입력하면 저렇게 알려줍니다. 사진을 찍은 날 정답은 '미니'이었는데, 뭐 전화기-스마트폰-옵션-미니 뭐 이런 유사도의 흐름으로 유추하는 형태인게지요. 주변 비전공자 친구들이 이 게임을 하면서 가장 많이 궁금해 한 내용은

"아니 근데 이거 유사도 어떻게 측정 하는 거임...?"

인 것 같습니다. 

 

감사하게도 semantle-ko 제작자들은 소스 코드를 github에 공개해두셔서 분석을 할 수 있었습니다. 직접 코드를 뜯어보고 싶은 분들은 여기!를 보시면 됩니다. 코드를 열어보면 이것저것 전처리를 위한 코드들이 들어있는데, 이 글에서는 비전공자들을 독자라고 생각하고 생각하고 본 글에서는 다루지 않으려 합니다.

 

각설하고 꼬맨틀에서는 기본적인 word embedding을 기반으로 vector의 similarity를 측정하는 방식을 사용하고 있습니다. '그게 뭔데 씹덕아;;' 라고 하실 것 같으니 하나하나 설명을 해보도록 하겠습니다.

 

단어 자체는 text 형태이기 때문에 인공지능을 구현하거나 프로그램 내부적으로 처리하기 수월하도록 단어를 숫자로 변환하는 과정을 거칩니다. 단어가 10,000개가 있다면 이 단어들을 표현할 수 있는 사전을 만듭니다. 생각하고 그중 '사과' 라는 단어가 사전에서 가장 첫 번째에 온다면 이걸 숫자로는 [1 0 0 0...]과 같이 (벡터로) 표현할 수 있게 됩니다. '바나나' 라는 단어가 두 번째에 온다면 [0 1 0 0...]과 같이 표현이 됩니다. 이런식으로 표현을 한다면, 이제 숫자만을 가지고 단어들을 표현할 수 있게 되었습니다. 이런 식으로 사전에서 단어의 위치를 1로 표현하는 방식을 one-hot encoding 방식이라고 부릅니다.

 

하지만 이러한 방식은 단어의 개수가 늘어남에 따라서 사전의 크기가 커진다면, one-hot encoding 방식은 매우 비효율적입니다. 100만 개의 단어가 있으면 단어 하나를 위해 나머지 9,999,999 개의 0을 컴퓨터가 처리해야 하게 되니까요. 실제로 2^13(=8,192) 차원 이상의 벡터들은 연산의 측면에서 꽤나 부담스러운 크기입니다(물론 좋은 컴퓨터가 있다면 그리 큰 건 아니긴 하지만...). 그래서 똑똑하신 분들이 이런 문제를 해결하기 위해서 차원을 축소하여 더 작은 차원의 벡터로 단어들을 표현하는 방식을 만들어뒀고 이것이 embedding의 기본적인 개념입니다. 디테일 한 과정에 대한 본 글에서 다루지 않을 것이고, 잘 정리된 자료가 있어 궁금하신 분들은 들어가서 읽어보시면 될 것 같습니다.

 

그렇다면 단어를 표현하는 것은 '어떻게 벡터의 차원을 잘 축소할거냐?'는 문제로 환원되었습니다. 이 과정은 Word2Vec, FastText, Glove과 같은 다양한 방법이 있습니다. (저도 이쪽은 관심이 없어서 공부를 안 해서 설명을 못합니다.) 꼬맨틀에서는 FastText를 사용해서 단어를 300차원의 벡터로 표현합니다. 완벽한 embedding의 의미는 아닐지 몰라도 저는 rough하게 "고차원의 정보의 관계를 저차원에 표현하는 것"으로 embedding을 이해하고 있습니다. 벡터로 단어를 표현하는 것이 무슨 의미가 있는 지에 대해서 설명하기 위해서 2차원 상에서 '남자', '여자', '남학생', '여학생'이라는 4개의 단어를 표현하는 상황을 생각해봅시다.

 

Figure 2. 워드 임베딩 예시 1

반드시 그런 것은 아니지만, 우리의 목표는 의미론적으로 단어를 잘 표현하는 겁니다. Figure 2에서 '여자'와 '남자'라는 단어가 동일한 단어는 아니니 어느 정도 떨어진 위치에 두 단어가 존재할겁니다(여기서는 벡터와 좌표계를 유사한 개념으로 사용하겠습니다). 이제 '남학생'과 '여학생'의 경우를 본다면, 둘다 '성별'+'학생'의 의미를 가지고 있습니다. 그렇다면 바라건데, '여자'와 '여학생'이 떨어진 방향과 정도는 '남자'와 '남학생'이 떨어진 방향과 정도와 유사하였으면 좋겠고 동시에 '남자'와 '여자'가 떨어진 방향과 정도가 '남학생'과 '여학생'이 떨어진 정도와 유사하게 벡터화 되도록 하는 것이지요. 이런식으로 잘 벡터화, 임베딩 된 벡터들이 가리키는 위치가 가까우면 '유사도가 높다', 멀면 '유사도가 낮다'고 말합니다. 이제 어딘가에 가서 인공지능 챗봇이나 Siri, 빅스비 같은 인공지능 비서 서비스와 관련된 이야기가 나오면 비전공자 수준에서 아는 척은 하실 수 있는 정도이지 않을까 생각합니다.

 

돌아와서 마지막으로 풀어야 하는 문제는 '벡터들의 유사도 혹은 거리를 어떻게 측정하는가?' 입니다. 단순히 직관적으로는 '가까우면 비슷한 것이라고 하면 되는 것 아니냐...?' 라고 할 수 있는데 다음과 같은 상황을 봅시다. 

Figure 3. 워드 임베딩 예시 2

뭔가 대충 말이 되는 것 같습니다. 인간과 성별을 기준으로 4개의 단어들이 나뉘어져 있으니 거기에 '인간'과 '성별'이라는 단어들은 사이 어딘가에 있겠지요. 하지만 이렇게 되면 '인간'-'남자', '인간'-'여자'의 관계가 '인간'-'성별'의 관계보다 가까운 의미인 것 같은데, 벡터상으로는 멀다고 해석해야 할지도 모르겠습니다. 결국 관점의 차이이지만, 인간이 상상할 수 없는 높은 차원상의 벡터에서는 단순 거리를 비교(L2 norm or euclidean distance 등...)하기 보다는 벡터의 각도를 고려하는(cosine similarity, pearson correlation) 측정 방식이 선호 되는 것 같습니다. 꼬맨틀은 cosine similarty를 기준으로 유사도를 측정하는데, 이는 벡터들의 방향만을 고려하는 방식으로 '비슷한 방향에 있는 단어들은 비슷한 단어일 것이다'는 겁니다.

 

의미론적으로 완벽한 embedding은 물론이거니와 유사도를 측정하는 방식도 매우 다양하고 가장 좋은 방식은 무엇인가에 대한 정답은 없습니다. Figure 4를 봅시다.

 

Figure 4. '음식물'과 유사한 단어 리스트

그림은 '음식물'이란 단어와 유사한 단어들을 1위부터 20위까지 정렬한 것인데, 저희의 직관과 조금 다릅니다. '배설물', '분리수거', '개인위생', '분뇨', '처리기', '폐건전지', '상비약', '일회용품', '정화조' 등의 단어들은 딱히 음식물과 유사한 단어 같지 않습니다. 오히려 '음식'은 14위로 유사도는 39.99% 밖에 되지 않았습니다. 감히 유추하건데, '음식물'이라는 단어는 그 자체로 사용되기 보다 '음식물 쓰레기' 같은 형태로 사용된 경우가 많았던 것 같습니다. 그렇다보니 단어들을 학습하는 과정에서 '음식물'이라는 단어는 '쓰레기' 라는 단어와 관계가 깊다고 학습되어서 쓰레기와 연관성이 높은 '배설물', '분리수거' 같은 단어들과 유사도가 높다고 나오게 된 것으로 보입니다. 같은 맥락으로 '음식물 반입 금지'와 같은 단어가 사용되면서 '반입'이라는 단어도 11등에 위치했네요. '금지'는 939등으로 25.85%의 유사도를 보였습니다.

 

'어라? 근데 쓰레기라는 단어는 순위에 없는데? 너의 해석이 틀린듯?'

 

 이라고 하실 수 있습니다. 한 번 '쓰레기'를 입력해봅시다. 그럼 다음과 같은 결과가 나옵니다.

Figure 5. '쓰레기'와 '음식물'의 유사도

유사도가 무려 44.42%로  '가공육'보다 높은 유사도를 보였습니다! 순위는 ???? 라고 나오네요. 이러한 결과가 나오는 이유는, 제작 단계에서 욕설이나 비하 발언, 의미가 모호한 단어들이 정답으로 선택되지 않도록 정답 데이터 정제 과정을 거쳤기 때문입니다. 유사도 순위 책정 또한 해당 데이터들을 기준으로 내기 때문에 유사도 순위에서 제외된 것이지요. 인공지능 윤리 어쩌구 저쩌구 하는 다양한 문제들에 대한 고민도 반영된 게임이라는 사실도 알아 가시면 될 것 같습니다.

 

Figure 6. FAQ

각설하고 '음식물'은 게임 사이트에도 나와있는 데이터에 대한 편향의 좋은 예시인 것 같습니다. 마지막으로, 대부분의 자연어 처리 연구는 영어를 기준으로 되어 있기에 embedding을 비롯한 다양한 기술들은 영어에 대한 성능이 가장 좋습니다. 영어 버전인 Semantle도 그러한 성격이 있는 것 같아 소개 드리려 합니다.

 

Figure 7. Semantle 유사도 순위

정답은 heitage(유산)이었는데, 단편적인 결과긴 하지만 개인적으로는 한국어 버전보다는 산출된 유사도가 납득이 되는 것 같습니다. 다음 글에서는 직접 코드를 까보며 정답을 쉽게 맞히도록 도와주는 프로그램을 만들어 보겠습니다...