자연어 처리 기법과 활용

SF영화를 보면 인공지능이 사람의 말을 모두 알아듣고 이해하고 행동하는 것을 쉽게 볼 수 있다. 심지어 몇몇 영화에서는 보통 사람보다 더 인간적이고 철학적인 생각을 하는 인공지능 로봇들도 등장한다.

“정말 영화에서 나온 것처럼 인공지능이 사람의 언어와 감정을 모두 이해할 수 있을까? “

인간의 언어는 수천년의 역사를 가지고 다양하게 분화되고 발전해 왔다. 그리고 많은 부분 설명하기 힘든 감정이나 암묵적인 지식들로 구성되어 있기 때문에 정성적인 성질이 강하다. 그래서 정량적 데이터가 필요한 현재의 인공지능 학습 방법으로는 이러한 언어의 요소들을 이해시키기 어렵다.

그러면, SF영화에 나오는 것들은 허황된 이야기일 뿐인 것일까?

꼭 그렇지만은 않다. 우리 주변을 잘 살펴보자. 가장 가깝게 AI 스피커를 발견할 수 있을 것이다. 복잡한 대화는 아직 어렵지만 일상적이고 반복적인 간단한 말 들은 아주 잘 이해 한다.

예를들어 잠자리에 들기 전에 다음과 같은 대화를 할 수 있다.

나: (잠자리에 누우며)”OO야! 나 이제 잘래”

AI 스피커: “알람은 몇 시로 할까요?”

나: “내일 아침 7시에 깨워줘”

AI 스피커: “내일 아침 7시로 알람 설정 되었습니다.”

나: “방에 불 꺼줘”

AI 스피커 : (방에 불을 끄며)”수면에 좋은 음악을 틀어 드리겠습니다.”
(약 30분정도 잔잔한 음악 재생 후 종료됨.)

AI 스피커를 사용하기 전에는 이런 것들을 직접 손으로 해야 했다. 휴대폰에 알림을 맞추고, 잠들기 전에 들을 음악을 리스트에 담고 타이머를 맞춘다. 그러고 나서야 방에 불을 끄고 잠자리에 눕는다. 하지만 이젠 바로 잠자리 누워서 말로만 하면 된다.

어떻게 가능한 것일까?

이것을 이해 하기 위해서는 먼저 컴퓨터가 사람의 언어를 이해하기 위해서 시도 되었던 기계번역에 대해서 알아볼 필요가 있다.

초기에는 정해진 규칙에 의해서 번역을 해주는 ‘규칙기반(혹은 중성언어 기반)’으로 언어를 컴퓨터가 다루도록 하였다. 말 그대로 개발자가 정한 규칙에 의해서 원문을 타겟 언어로 번역해 주는 것인데, 앞서 언급한 말로 설명하기 힘든 감정적인 부분과 암묵적인 지식들을 개발자가 모두를 규칙으로 담기에는 한계가 있었다.

이러한 한계를 뛰어 넘기 위해서 나온 것이 ‘말뭉치 기반’으로 번역하는 방식이다. 말뭉치 기반은 크게 ‘예시 기반’‘통계 기반’ 2가지로 나누어 진다.

‘예시 기반’은 원문과 번역문을 저장해 두었다가 똑같은 원문 요청이 왔을때, 이를 활용하는 방식이다. 그리고 ‘통계 기반’은 원문과 번역문의 상관관계 빈도수를 통계화하고 이 수치를 활용하는 방식이다.

말뭉치 기반으로 번역을 하게 되면, 사용을 하면 할 수록 새로운 말뭉치 데이터가 누적 되기 때문에 사람의 개입 없이 컴퓨터가 스스로 언어의 정보를 익히고 처리해준다. 뿐만 아니라 번역 완성도도 점점 높아지게 된다.

“어떻게 말뭉치 기반이라는 것이 앞서 언급한 사람 언어의 정성적인 부분을 상관관계 형태로 통계화 하고 수치로 만든다는 것일까?”

컴퓨터에게 ‘사과’‘배’라는 두 단어를 보여준다면, 단지 유니코드 집합으로 해석 할 뿐 두 단어의 개념적 차이를 이해할 수는 없다.


그러면 유니코드가 아닌 컴퓨터가 이해 할 수 있는 수치를 사용해야 한다. 그것이 바로 벡터로 표현 하는 것이다. 벡터를 만드는 방식 중 하나인 One-Hot 인코딩 방식을 이용하여 간단히 설명해 보면, 다음과 같다.

문장에 의도를 파악하기 위해 필요한 요소가 [왕, 여왕, 남자, 여자]라면 ‘왕’를 표현하는 벡터는 [1, 0, 0, 0]이 되는 것이다. 그리고 ‘여왕’를 표현하는 벡터는 [0, 1, 0, 0]이 된다. 이런 식으로 벡터가 만들어지면 단어들이 실수 공간에 들어오기 때문에 각 단어들의 사이의 유사도를 측정 할 수 있게 된다. 그리고 문장속 단어의 의미 자체가 수치화 되어 있기 때문에 벡터 연산을 통해서 추론을 내릴 수도 있게 된다.

Male – Female

예를 들어 ‘왕(King)’에 대한 벡터에서 ‘남자(Male)’을 빼고 ‘여자(Female)’을 더하면, 벡터 연산을 통해서 ‘여왕(Queen)’이라는 결과를 얻을 수 있게 된다.

벡터 연산

이로써 컴퓨터가 사람의 언어적 정보를 단순히 저장하고 읽는 것만 하는 것이 아니라 의도를 파악할 수 있게 된 것이다.

이러한 처리 방식을 통해서 많은 관심을 받게 된 분야가 대표적으로 챗봇이다. 챗봇이 사람의 말의 의도를 파악할 수 있게 되면서 단순한 작업에 대해서 많은 도움을 줄 수 있게 되었다.

최근 가장 성공적인 사례인 ‘코로나-19’ 챗봇을 이야기 해보자.

그 동안의 민원 처리 방식은 모든 민원 내용을 사람이 일일이 읽어보고 취합한 뒤 공지를 통해서 한번에 알리는 방식이 일반적이었다. 이런 경우 민원을 넣고 처리가 되길 기다려야 한다. 질병관리본부에 들어오는 코로나-19에 대한 민원도 마찬가지 였지만 챗봇 도입을 통해서 이러한 문제점에 대해서 많은 어려움을 해소 할 수 있었다.

민원을 하는 사람이 “자가격리자는 어떻게 해야 할까?”라는 질문이 들어오면, 챗봇은 자연어 처리를 통해 사람의 의도를 파악하고 질병관리본부에서 제공하는 생활 수칙 가이드를 찾아서 제공을 해주는 것이다.

해결하고 싶거나 알고 싶은 정보들을 기다리지 않고 챗봇을 통해 바로 안내를 받게 해주면서 사람들 대부분의 민원을 지연없이 해결하게 된 것이다. 그로인해서 질병관리본부의 코로나-19 챗봇 등록자 수가 70만명을 넘어 섰다.

이 뿐만이 아니다. 사용자 층의 챗봇을 바라보는 시선이 전반적으로 달라졌다. 챗봇 초창기에 사람의 말을 제대로 이해하지 못하여서 좋은 사용자 경험을 전달하지 못했다. 그래서 좋은 기능으로 발전했음에도 불구하고 사람들로부터 외면 받고 있었다. 하지만 코로나-19 챗봇에 대한 좋은 사용자 경험으로 인해서 챗봇이 사용할 만하다는 인식이 생겨 났다.

국내 대표적인 소셜미디어 회사인 카카오와 네이버의 경우 코로나 사태 직전대비 챗봇 사용량이 각각 50%, 18%씩 증가 한 것으로 나타났다.

이는 컴퓨터가 사람의 말을 알아 들을 수 있게 되면서 사용자의 서비스 소비 패러다임이 변하고 있다는 것을 반영한다고 본다. 이러한 패러다임 변화에 대해서 기업들은 많은 관심을 가져야 할 것이다. 챗봇을 통해 기업 비즈니스를 고객들에게 어떻게 서비스 할 것인지 깊게 고민해 볼 필요가 있을 것 같다.

Python redact sensitive information in text

text 데이터를 처리하다 보면 그 안에 개인정보(phone, email 등) 등의 민감정보가 포함 되어 있는 경우가 있다. 이것들은 정규식(regular expression)을 사용하여 알아 볼 수 없도록 편집 (masking) 할 수 있다.

import re

text = '안녕하세요. 문의드릴 것이 있어서 연락드렸습니다. 제 연락처는 010-1234-1234 / thenewth@gmail.com 입니다. 연락가능 하실때 연락 부탁 드립니다. 감사합니다.'

phoneRegular = "\d{2,3}-\d{3,4}-\d{4}"
emailReqular = "(\w+\.)*\w+@(\w+\.)+[A-Za-z]+"

phonePattern = re.compile(phoneRegular)
emailPattern = re.compile(emailReqular)

#Masking 문자 대신 공백을 사용하면 민감정보 표시 자체를 삭제 할 수 있다.
redactedPhoneText = re.sub(phonePattern, "***-****-****", text)
redactedEmailText = re.sub(emailPattern , "****@****.***", text)

#전화번호 정보 masking 결과 확인
print(redactedPhoneText)

#이메일 정보 masking 결과 확인
print(redactedEmailText)

출력한 결과를 확인해 보면 정규식에 해당하는 민감정보가 편집(Masking)된 것을 확인 할 수 있다.

Python connect to MS-SQL with pymssql

Python에서 MS-SQL을 사용하려면 일단, MS-SQL DB를 지원하는 Python 모듈을 설치해야 한다. MS-SQL에 대한 모듈은 크게 pyodbc와 pymssql 두가지가 있는데 여기서는 pymssql을 사용 할 것이다.

(DB에 관련된 모듈은 무수히 많은 것들이 있다. 참고: https://www.lfd.uci.edu/~gohlke/pythonlibs/)

다음과 같이 pymssql을 설치한다.

(설치 방법은 Ubuntu Linux대상 이다. 다른 OS를 사용하는 경우는 여기를 참고하면 된다.)

$ apt-get --assume-yes update
$ apt-get --assume-yes install freetds-dev freetds-bin
$ pip install pymssql

이제 Python에서 설치한 모듈을 가지고 MS-SQL에 접근해 보자.

import json
import pymssql 

#[Tip]json 문자열을 환경변수 파일로 저장하여 사용한다면 서버정보를 노출 하지 않을 수 있다.
json_string = 
'{
    "host":"Server Address",
    "port":1433,
    "user":"User ID@Server Name",
    "password":"P@ssW0rd",
    "database":"Database Name"
}'
json_data = json.load(json_string)

#pymssql 모듈을 이용하여 Connection 생성을 한다.
conn = pymssql.connect(host=json_data['host'], port=json_data['port'], user=json_data['user'], password=json_data['password'], database=json_data['database'])

여기까지 하면 MS-SQL서버에 접근(Connection 완료) 한 것이다.
다음으로 Select query문을 실행하여 데이터를 가져와 보자.

#Connection으로부터 cursor 생성
cursor = conn.cursor() 

#Select Query 실행
cursor.execute('select * from [Target Table Name]') 

#결과 데이터를 데이터프레임에 저장
df = pd.DataFrame(cursor.fetchall())

#실행이 끝나면 항상 연결 객체를 닫아 주어야 한다.
conn.close() 

잘 실행 되었다면 결과를 담은 데이터프레임을 출력 해보자.

#결과 출력
print(df)

실행한 Select Query한 결과를 확인 할 수 있을 것이다.

MS-SQL Table Copy

학습 데이터를 준비 하려다 보면 기존의 데이터를 변형해야 될 때가 있다. 이때 원본 테이블을 가지고 바로 작업을 하게 되면 데이터가 손실 될 수 있다.
백업 데이터가 있다고 하면 그나마 다행이지만 보통 학습에 사용되는 데이터는 양이 많기 때문에 100% 복구하려면 시간이 걸린다.
이런 점들 때문에 될 수 있으면 테이블(혹은 데이터)을 복사해서 사용하면 좋다.

  1. 새 테이블을 생성 하면서 데이터 복사
select * into [New Table Name] from [Source Data]
  1. 테이블 구조만 복사
select * into [New Table Name] from [Source Table Name] where 1=2
  1. 기존 테이블에 데이터만 복사
insert into [Destination Table Name] select * from [Source Table Name]

MS-SQL Select random rows from Table

머신러닝 혹은 딥 러닝 학습을 하기 위해서는 우선 학습할 데이터를 탐색해 보아야 한다. 만약, 많은 양의 Row 데이터를 가지고 있는 SQL Table을 가지고 해야 한다면 일부 표본만 추출해서 테스트를 해보는 것이 필요하다.

이런 경우 테이블에서 랜덤으로 데이터를 추출할 때 다음 Query를 사용하면, 간단하게 일정 비율로 랜덤한 데이터를 추출해 낼 수 있다.

select top 10 percent * from [Table Name] order by newid()

No-SQL Database 란?

No-SQL (Not only SQL) 시작

1998년 카를로 스트로찌(Carlo Strozzi)라는 엔지니어가 공개한 표준 SQL 인터페이스를 채용하지 않은 자신의 경량 Open Source 관계형 데이터베이스를 No-SQL이라고 명명한데서 유래되었다고 한며, 이후 2009년에는 요한 오스칼손(Johan Oskarsson)이라는 엔지니어가 Open Source기반의 분산 데이터베이스 관련 행사를 준비하면서 No-SQL이라는 용어를 널리 사용하기 시작하였다고 한다.​

초기 No-SQL은 기존의 관계형 데이터베이스 시스템의 주요 특성을 보장하는 ACID(Atomicity, Consistency, Isolation, Durability) 특성을 제공하지 않았다. 때문에 No-SQL이 등장한 이후에도 시장에서는 관계형 데이터베이스가 데이터를 처리하는데 가장 최적의 시스템으로 받아들여졌다.

기업 데이터의 정확한 처리가 필수적이기 때문에 기업 시스템에서는 현재도 관계형 데이터베이스를 훨씬 많이 사용한다. 무엇보다도 표준 SQL 이라고 하는 데이터를 처리하는 언어의 편이성 때문에 No-SQL 등 다른 데이터베이스 시스템들은 많이 활용 되지 않았다.​

2000년 후반으로 넘어오면서 인터넷이 활성화되고, 소셜네트워크 서비스(SNS)등이 등장하면서 관계형 데이터 또는 정형데이터가 아닌 데이터, 즉 비정형데이터라는 것을 보다 쉽게 담아서 저장하고 처리할 수 있는 구조를 가진 데이터 베이스들이 관심을 받게 되었고, 해당 기술이 점점 더 발전하게 되면서, No-SQL 데이터베이스가 각광을 받기 시작했다.

기존의 관계형 데이터베이스 보다 더 융통성 있는 데이터 모델이 요구되며, 데이터의 저장 및 검색을 위한 특화된 매커니즘이 필요 해지기 시작했고, No-SQL은 단순 검색 및 추가 작업에 있어서 매우 최적화된 키 값 저장 기법을 사용하여, 응답속도나, 처리 효율 등에 있어서 매우 뛰어난 성능을 내주면서, 비정형 데이터를 다루는 SNS, 머신러닝 등 AI 산업에 많이 사용되기 시작했다.

SQL VS No-SQL

SQLVSNo-SQL
정해진 규격에 의한 정적 정의Schema정해진 규격 없음. 동적 정의
가능Data Join불가능
표준SQL비표준
보장Transcation미보장
어려움Distribute쉬움

No-SQL 종류

1. Key-Value DB

  • Key와 Value의 쌍으로 데이터가 저장되는 가장 단순한 형태이다.
    (ex) Dictionary, Hash 자료 구조
  • 데이터를 하나의 불투명한 컬렉션으로 처리하며 각 레코드마다 각기 다른 필드를 가질 수 있는 Column Family 데이터 모델이다.
  • 선택적인 값들이 대부분의 DB에서처럼 placeholder로 표현되지 않기 때문에 Key-Value DB는 동일한 데이터베이스 저장을 위해 메모리를 훨씬 덜 사용하기도 하므로 특정한 부하에서 큰 성능 상의 이점이 있을 수 있다.

2. Wide Column DB

  • Key-Value DB에서 발전된 형태의 Column Family 데이터 모델을 사용한다.
  • 하나의 Row Key 안에 다양한 컬럼과 값을 저장 할 수 있도록 한다.
  • 대량의 데이터의 압축, 분산처리, 집계 쿼리 (SUM, COUNT, AVG 등)및 쿼리 동작 속도 그리고 확장성이 뛰어나다.

3. Document(-oriented) DB

  • 문서 데이터베이스는 JSON/XML 유사 형식의 문서로 데이터를 저장 및 쿼리하도록 설계된 비관계형 데이터베이스 유형으로 트리형 구조로 레코드를 저장하거나 검색하는 것에 효과적이다.

4. Graph DB

  • 18세기 오일러의 그래프 이론에서 시작되었다.
  • 데이터를 노드로 표현하며 노드 사이의 관계를 엣지로 표현한다.
  • 기존의 RDB로는 표현하기 어려웠던 각 데이터간의 연결점들을 이어주고 표현(Visualizing)해주는데 용이하다.

Inverted Search Index

검색엔진에서 많이 사용하는 방법인데, 검색엔진은 사이트의 모든 페이지를 검색 로봇이 검색해서 문서내의 단어들을 색인하여 URL에 맵핑해서 저장해놓는다.

Key Value
bcho.tistory.com/nosqlnosql, cassandra, riak
bcho.tistory.com/cloudamazon, azure, google
facebook.com/group/serversideamazon, google, riak
highscalability.com/bigdatanosql, riak
http://www.basho.com/riakriak

검색은 단어를 키로 검색이 되기 때문에, 위의 테이블 구조에서는 value에 검색 키워드들이 들어가 있기 때문에, 효과적인 검색을 할 수 없다.이 검색 키워드를 키로 해서 URL을 value로 하는 테이블을 다시 만들어 보면, 아래와 같은 식으로 표현되고, 검색 키워드로 검색을 하면 빠르게, 검색 키워드를 가지고 있는 URL을 찾아낼 수 있다.

KeyValue
riak bcho.tistory.com/nosql
facebook.com/group/serverside
highscalability.com/bigdata
http://www.basho.com/riak
nosql bcho.tistory.com/nosql
highscalability.com/bigdata

이렇게 value의 내용을 key로 하고, key의 내용을 반대로 value로 하는 패턴을 inverted search index라고 한다.