머신러닝을 맛보다

4월 14일, 2016

시작하기 앞서

저는 머신러닝을 공부한지 1주일 밖에 안된 초짜입니다.

전문적인 내용은 잘 모를 수 있으며 제가 아는 범위 내에서만 글을 작성했음을 알아주시면 감사하겠습니다..

개요

지난달의 이슈를 한단어로 요약하자면 ‘알파고’ 라고 할 수 있을 것 같습니다.

인공지능 IoT 비교
(인공지능과 사물인터넷의 검색량 추이, 출처:네이버 트랜드)

많은 사람들이 알파고의 원리에 관심이 많았고, 기계가 스스로 학습한다는 머신러닝에 대해 신기해했던 사람들도 있을 것입니다.

머신러닝(aka. 기계학습)은 생소한 분야인 것 같지만, 실제로는 많은 곳에서 활용되고 있습니다.스팸메일을 분류하는 기능부터 얼굴인식, 사용자 성향 분석등이 있겠지요.

DeepFace
(정확도가 97%라는 페이스북의 얼굴인식 알고리즘 ‘딥페이스’)

머신러닝에 대한 관심이 높아지는 가운데, 저도 기초적인 개념은 공부할 필요가 있다는 생각하에 머신러닝 공부를 해보게 되었습니다.

머신러닝을 활용하여 운영중인 웹사이트 ‘colorscripter.com‘ 에서 사용자가 코드를 입력하면 자동으로 코드를 분석하여 언어를 추천해주는 기능을 넣으면 좋을 것 같다는 생각이 들었고, 필요한 정보를 찾고 공부하기 시작했습니다.

ColorScripter 스크린샷
(ColorScripter 서비스 화면)

문제 분석

저는 사용자가 코드를 입력하면 자동으로 코드를 분석하여 언어를 추천해주는 기능을 만들어야 합니다. 그렇다면 언어를 탐지하기 위해서는 어떤식으로 프로그램을 설계해야 할까요?

언어별로 사용되는 ‘키워드’를 기억해두었다가, 입력된 코드가 해당 ‘키워드’ 들을 갖고 있으면 그 언어와 비슷하다고 볼 수 있을 것입니다.

예를들어 #include<stdio.h>printf 같은 키워드가 있으면 이 언어는 C언어일 확률이 높아 질 것입니다. 꺽쇠(<, >) 가 많으면 HTML이나 XML등 마크업 언어일 가능성이 높을 것이구요.

popular languages
(코드를 보고 위의 언어를 추출 하는 것이 목표입니다)

베이즈 정리

이와같은 문제를 처리하기 정말 좋은 정리가 있습니다. 아마 확률과 통계시간에 배웠을 ‘베이즈 정리’ 입니다.

bayes_theorem

위 식을 분석하자면 P(A\|B)는 B일때 A일 확률이며, P(B|A)는 A일때 B일 확률입니다. 처음 이 식을 볼 때 어디에 쓰이는지 감이 잘 안잡히는데, 알고보면 이 둘의 차이는 굉장히 큽니다.

기계 학습을 할 때, P(A|B)보다 P(B|A)정보를 구하는 것이 더 쉬울 수 있기 때문입니다.

예를들어 C언어 데이터들을 학습 시키려 할 때, 우리는 이 코드가 C언어인 것을 알고 있습니다. 하지만 사용자가 코드를 입력하고 우리가 어떤 언어인지 추천해주어야 할땐 그 코드가 어떤 언어인지 알지 못합니다.

A를 ‘이 언어가 C언어인 사건’ 이라고 하고, B를 ‘C언어의 키워드를 포함하는 사건’ 이라고 합시다.
그렇다면 P(A|B)C언어의 키워드를 포함했을 때, C언어인 확률이 될 것입니다.
P(B|A)C언어일 때, C언어의 키워드를 포함할 확률이 됩니다.

즉, 사용자가 코드를 입력 하였을 때 P(A|B)를 이용하여 C언어일 확률을 출력해 줄 수 있고,
P(B|A)는 다른 C언어 코드들을 미리 분석하여 구해둘 수 있습니다.

나이브 베이즈 분류

베이즈 정리에서 조건이 여러개가 되면 식을 아래와 같이 쓸 수 있습니다.

나이브 베이즈 이론

이 식을 다시 키워드와 언어에 대응시켜 보자면 “키워드 x1,…xn 이 있을 때 C언어일 확률”“C언어일 확률” × “C언어일때 키워드 x1이 있을 확률” ×× “C언어일때 키워드 xn이 있을 확률” 이라고 볼 수 있습니다.


예시 1

예를들어 “#include, printf, scanf 키워드가 있을 때 C언어일 확률"

"C언어가 #include를 포함할 확률" × "C언어가 printf를 포함할 확률" × "C언어가 scanf를 포함할 확률"에 비례한다고 볼 수 있고,

실제로 이 확률들은 높기 때문에 “#include, printf, scanf 키워드가 있는 언어”“C언어”확률이 높을 것입니다.

예시 2

다른 예로 "System, import 키워드가 있을 때 C언어일 확률"

"C언어가 System를 포함할 확률" × "C언어가 import를 포함할 확률"에 비례한다고 볼 수 있고,

실제로 이 확률들은 낮기 때문에 해당 코드는 “C언어”확률이 낮을 것입니다.




언어를 분석해주는 프로그램은 많은 코드 데이터를 학습하면서 그 언어가 해당 키워드들을 포함할 확률을 계산해 둘 것입니다.
그리고 이것이 많은 학습을 할수록 프로그램이 정확해지는 이유이자, 머신러닝의 핵심이라고 할 수 있습니다.


더 세부적으로 들어가면 log(a * b) = log(a) + log(b) 라는 특징을 이용하여 양변에 로그를 씌워서 구한 확률에 로그를 씌워 더해주는 방법도 이용하는데 상세한 내용은 기술하지 않겠습니다,

나이브 베이즈 분류법에 대해선 위키백과에 자세히 나와 있습니다.

구현

저는 Python을 이용하여 P(C|xi) 를 구하고, 이 값을 데이터베이스에 저장해두었습니다.

저장된 확률

위 사진은 데이터베이스 상에 있는 데이터로 “언어, 키워드, 포함 비율” 이 들어 있습니다. 실제로 Java는 ‘public’, ‘void’, ‘String’ 같은 키워드를 많이 이용하고 c는 ‘int’, ‘#include’, ‘main’과 같은 키워드를 많이 이용하는걸로 집계되었습니다.

이와 같은 확률을 이용하여 코드가 주어졌을때 키워드들에 대응하는 확률 P(C|xi) 를 가져오고 계산하는 방식으로 코드를 짰습니다.

구현된 코드
(확률을 계산하는 코드의 일부)

결과

위 사진은 약 2만개의 데이터로 학습시키고 1만개의 데이터를 테스트 해본 결과입니다. 약 90%의 정확도를 기록 하였으며, 데이터가 많은 C나 Java는 높은 정확도를 기록하고 있습니다.

JavaScript는 안타깝게도 55%정도의 정확도를 기록하고 있는데(…) 데이터를 보니 html문서와 혼용되어 분석 오류율이 높은 것으로 보입니다.

결과물

임시로 이 기능을 테스트해 볼 수 있는 페이지를 만들었습니다. lab.prev.kr/csld/ 에서 언어 탐지 기능을 테스트 해 볼 수 있습니다.

데이터가 더 수집되어 기능이 향상되면 colorscripter.com 에도 이 기능을 넣을 예정입니다.


* 현재(2017년) 해당 기능은 몇 차례 개선되어 ColorScripter에 적용되어 있는 상태입니다.