딥러닝으로 문서 분류기 만들기
목차
Daily Devblog 서비스를 위한 개발 문서 분류기를 개발한 이야기를 공유합니다.
프로젝트 소개
필자는 IT 블로그의 글을 모아서 매일 오전 10시에 이메일로 발송해주는 Daily Devblog라는 좋은 서비스를 구독하고 있습니다. 발송되는 글들은 Awesome Devblog에서 제공받는데, 가끔씩 IT와 관련 없는 글이 등장하기도 합니다. 큰 문제는 아니지만 서비스를 애용하는 구독자로서, 약간의 도움이라도 되었으면 하는 바람으로 딥러닝을 이용하여 간단한 문서 분류기를 만들어보았습니다. 🎉
개발에 사용된 코드 및 데이터는 아래 링크에서 확인하실 수 있습니다.
개발 과정
전체 개발 순서는 데이터 수집 및 전처리, 단어 임베딩 모델 개발 그리고 문서 분류모델 개발 순으로 진행하였습니다.
Data Crawling & Labeling
데이터는 Awesome Devblog에서 제공해주는 데이터를 이용하였습니다.
1 | { |
2020년 2월 초 기준으로 전체 34,620개의 글이 존재하였고, 이 중 10,382개의 글을 직접 라벨링하였습니다. 라벨링 작업이 가장 힘들었습니다.. 전체 데이터의 1/3 밖에 라벨링을 못했지만 일단 결과를 보고 싶어 다음 과정을 진행하였습니다.
1 | 분류 라벨 개수 |
라벨링을 완료한 1만개 데이터 중 개발과 관련있는 글과 관련없는 글의 비율은 약 3:1로 개발과 관련있는 글이 더 많았습니다.
Preprocessing
가장 긴 대표 문장은 358자이고, 가장 짧은 문장은 3글자이며 평균 145글자로 이루어져있습니다. 각 문서의 대표값으로 임베딩된 단어들의 평균값을 사용할 예정이라 특정 길이로 문장을 자르거나 패딩을 채워넣지는 않았습니다.
1 | 문장 길이 최대 값 : 358 |
Awesome Devblog에서 제공하는 데이터 중 link
을 이용하면 본문 html을 받아올 수 있지만, 오래되어 존재하지 link
도 상당히 많아 이번에는 간단히 title
, tags
, description
만을 다음과 같이 전처리하여 이용하였습니다.
1 | 배열로 이루어진 tags를 띄어쓰기를 기준으로 join |
제목에 ‘about’이 단어가 들어간 데이터는 하나같이 블로그 주인에 대한 소개글로 Daily Devblog에 노출될 필요가 없다고 판단하여 제외하였고, tags
, title
, description
을 합쳐서 하나의 대표 문장인 text
를 만들었습니다.
1 | { |
Word Embedding
Word Embedding은 Gensim FastText를 이용하였습니다. 임베딩 모델 학습을 위한 데이터로 처음에는 크롤링한 데이터를 이용해 보았는데, RSS feed로 긁어온 데이터라 문장들이 끊켜있거나 html tag만 들어있는 등 데이터 질도 나쁘고 양도 부족하여 결과가 시원찮았습니다. 그래서 4.49GB의 wiki 한국어 데이터를 이용하여 임베딩 모델을 만들었는데 임베딩 모델의 용량만 14.5GB로 상당히 무거워졌지만 임베딩 결과는 훨씬 좋아졌습니다.
1 | $ python word_embedding.py --predict '파이썬' |
다음으로 임베딩 모델을 이용하여 대표 문장을 벡터로 임베딩할 차례입니다. 임베딩 모델은 한 단어를 (300,) 형태의 벡터로 임베딩해주는데, 앞서 설명한 것과 같이 대표 문장을 이루는 각 단어들을 임베딩한 뒤 평균값을 문장의 벡터로 사용하였습니다.
1 | def embedding(self, we_model, text, embedding_dim=300): |
Classifier 모델 개발
Tensorflow 2.0.1의 tf.keras를 이용하여 레이어를 간단히 Dense Layer 3개만을 쌓아 구현하였습니다. LSTM으로도 구현해봤지만, 성능이 더 안좋아 Dense Layer만 이용하였습니다.
1 | model = Sequential() |
성능 테스트
전체 10,382개의 데이터 중 33%(3,426개)를 test에 이용하여 모델의 성능을 테스트한 결과 validation accuracy 기준 88퍼센트가 측정되었습니다.
1 | loss : 0.278 |
이렇게 만들어진 모델을 실제 Daily Devblog에서 2020년 2월 3일에 발송된 41개의 글의 제목을 이용하여 필터링 해보았습니다.(제목이 숫자로만 이루어진 글은 제외하였습니다.) 다중 predict의 구분자를 쉼표로 사용하여 구현하였기 때문에 제목에 있는 쉼표(,)는 모두 제거하였습니다.
1 | python predict.py --predict '맥북 초보자들이 꼭 알아야 할 단축키 top 5! mac keyboard shortcut 5. feat.맥북을 산 이유, [Spring Boot] 내장 웹 서버 - 2 (스프링부트 HTTPS / HTTP2), 네이버클라우드플랫폼 Certificate Manager 에 LetsEncrypt 인증서 등록, Go로 블록체인 만들기 #1, Ansible 파일 마지 막 변경 일자 확인하기, 엔티티 매핑, [11775]Compactness criteria for clustering, 쿠버네티스 CI/DI 를 위한 오픈소스 프로젝트 알아보기, [Windows] USB 윈도우 10 설치 / 다운로드 방 법, [Spring Boot] JAR파일(독립적으로 실행가능), 케라스(Keras)의 get_file 함수, 웹 서비스 Maintenance Mode (점검 모드) 지원기, Nodejs AES 128 CCM 암호화(복호화) 예제 - crypto, 영어패턴#37, [운영체제(OS)] 7. 쓰레드(Thread), 비동기 처리와 콜백함수 그리고 Promise, docker기반 데이터 시각화툴 Superset 설치하기 (리눅스), Wayland과 Weston, 테스트 주도 개발(Test-Driven Development:By Example) - 1부 : 화폐 예제 (9 ~ 10장), 당신은 정말 의지가 있는가?, [B급 프로그래머] 1월 5주 소식(빅데이터/인공지능 읽을거리 부문), 손흥민 시즌 13호골! epl 25라운드 토트넘 vs 맨체스터시티, [운영체제(OS)] 9. 프로세스 동기화 2, 자바 String StringBuilder 그리고 StringBuffer 차이 비교, (업무)2020년 2월 3일 REACT로 임상시험자동화솔루 션 개발 Start, [운영체제(OS)] 11. 모니터, 필리핀 세부 시티의 맛집! 하우스 오브 레촌 cebu city House of Lechon, [운영체제(OS)] 8. 프로세스 동기화 1, 영어패턴#38, c언어 fopen 함수 : 파일을 연다., 스프링 데이터 JPA와 Querydsl 인프런 강의 정리, [Sprint #10] Server Side Techniques Sprint, 카카오메일 IMAP / POP3 / SMTP 설정방법, [Algorithm] 이진트 리의 구현 과 순회 알고리즘, [운영체제(OS)] 10. 프로세스 동기화 3, [맥북] 트랙패드 제스처, [스프링 부트 개념과 활용] 로깅, 기술 뉴스 #143 : 20-02-03, [스프링 부트 개념과 활용] Profile, 언 덕 너머' |
아래의 결과를 보면, 비개발 문서로 판단한 Ansible 파일 마지막 변경 일자 확인하기
라는 글을 제외하고 전체 40개의 글 중 39개를 정확하게 분류하여 97.5%의 성능을 보였습니다. 🎉🎉
1 | (False, 0.191) 영어패턴#37 |
1 | (True, 0.983) 맥북 초보자들이 꼭 알아야 할 단축키 top 5! mac keyboard shortcut 5. feat.맥북을 산 이유 |
마치며
이번 버전에서는 가볍게 title / tags / description
만 이용하여 분류기를 만들어보았습니다. 진행하면서 명확한 라벨링 규칙이 필요하다고 생각이 들었고, title / tags / description
만 봐서는 사람이 봐도 헷갈리는 데이터가 많아 결과가 잘 나올까 불안했지만, 다행히 실제 데이터에 적용했을 때 생각보다 만족스러운 결과가 나왔습니다. 다음 버전에서는 2만개의 데이터를 추가 및 title / tags / description
가 아닌 데이터의 link
를 이용하여 html 문서를 받아와 학습을 진행해보도록 하겠습니다.
이상 딥러닝으로 문서 분류기 만들기 프로젝트를 마치겠습니다.