목차
반응형
마르코프 체인(Markov Chain)이란?
마르코프 체인은 마르코프 특성을 가지고 이산적인 경우만 고려하는 것을 말한다.
마르코프 특성은 과거 상태와 현재 상태가 주어졌을 때, 미래 상태가 과거 상태와 무관하게 현재 상태에 의해서만 결정되는 것을 말한다.
마르코프 체인으로 문장 생성하기
마르코프 체인으로 문장을 만드는 과정은 다음과 같다.
1. 문장을 단어로 분할(형태소 분석)합니다. 2. 단어의 전후 연결을 딕셔너리에 등록합니다. 3. 사전을 사용해 임의의 문장을 생성합니다. |
사전은 단어 하나씩이 아니라 단어를 몇 개씩 묶어서 사전으로 등록한다.
예를 들면 "나는 커피를 마신다."라는 문장이 있으면 아래와 같이 사전으로 등록한다.
나|는|커피 는|커피|를 커피|를|마신다 |
<실습 1 - 마르코프 체인으로 문장 만들기>
import os
import codecs
from bs4 import BeautifulSoup
from konlpy.tag import Twitter
import urllib.request
import os, re, json, random
#네이버 맞춤법 검사 요청에 user-agent 헤더 추가
import requests
# 마르코프 체인 딕셔너리 만들기 --- (※1)
def make_dic(words):
tmp = ["@"]
dic = {}
for word in words:
tmp.append(word)
if len(tmp) < 3: continue
if len(tmp) > 3: tmp = tmp[1:]
set_word3(dic, tmp)
if word == ".":
tmp = ["@"]
continue
return dic
# 딕셔너리에 데이터 등록하기 --- (※2)
def set_word3(dic, s3):
w1, w2, w3 = s3
if not w1 in dic: dic[w1] = {}
if not w2 in dic[w1]: dic[w1][w2] = {}
if not w3 in dic[w1][w2]: dic[w1][w2][w3] = 0
dic[w1][w2][w3] += 1
# 문장 만들기 --- (※3)
def make_sentence(dic):
ret = []
if not "@" in dic: return "no dic"
top = dic["@"]
w1 = word_choice(top)
w2 = word_choice(top[w1])
ret.append(w1)
ret.append(w2)
while True:
w3 = word_choice(dic[w1][w2])
ret.append(w3)
if w3 == ".": break
w1, w2 = w2, w3
ret = "".join(ret)
# 띄어쓰기
params = urllib.parse.urlencode({
"_callback": "",
"q": ret
})
# 네이버 맞춤법 검사기를 사용합니다.
# data = urllib.request.urlopen("https://m.search.naver.com/p/csearch/ocontent/util/SpellerProxy?" + params)
data = urllib.request.urlopen("https://m.search.naver.com/p/csearch/ocontent/spellchecker.nhn?" + params)
data = data.read().decode("utf-8")[1:-2]
data = json.loads(data)
data = data["message"]["result"]["html"]
data = soup = BeautifulSoup(data, "html.parser").getText()
# 리턴
return data
def word_choice(sel):
keys = sel.keys()
return random.choice(list(keys))
# 문장 읽어 들이기 --- (※4)
toji_file = "toji.txt"
dict_file = "markov-toji.json"
if not os.path.exists(dict_file):
# 토지 텍스트 파일 읽어 들이기
fp = codecs.open("BEXX0003.txt", "r", encoding="utf-16")
soup = BeautifulSoup(fp, "html.parser")
body = soup.select_one("body > text")
text = body.getText()
text = text.replace("…", "") # 현재 koNLPy가 …을 구두점으로 잡지 못하는 문제 임시 해결
# 형태소 분석
# twitter = Twitter()
twitter=Twitter()
malist = twitter.pos(text, norm=True)
words = []
for word in malist:
# 구두점 등은 대상에서 제외(단 마침표는 포함)
if not word[1] in ["Punctuation"]:
words.append(word[0])
if word[0] == ".":
words.append(word[0])
# 딕셔너리 생성
dic = make_dic(words)
json.dump(dic, open(dict_file,"w", encoding="utf-8"))
else:
dic = json.load(open(dict_file,"r"))
# 문장 만들기 --- (※6)
for i in range(3):
s = make_sentence(dic)
print(s)
print("---")
LSTM이란?
LSTM은 RNN을 개선한 알고리즘이다.
RNN은 Recurrent Neral Network의 약자로 스스로 반복하면서 이전 단계에서 얻은 정보를 지속하는 신경망을 말한다.
RNN은 바로 전의 데이터박에 기억하지 못한다는 단점이 있어서 장기적으로 기억할 수 있는 기능을 추가한 LSTM이 만들어진 것이다.
LSTM으로 문장 생성하기
import codecs
from bs4 import BeautifulSoup
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout
from keras.layers import LSTM
from keras.optimizers import RMSprop
from keras.utils.data_utils import get_file
import numpy as np
import random, sys
fp = codecs.open("./BEXX0003.txt", "r", encoding="utf-16")
soup = BeautifulSoup(fp, "html.parser")
body = soup.select_one("body")
text = body.getText() + " "
print('코퍼스의 길이: ', len(text))
# 문자를 하나하나 읽어 들이고 ID 붙이기
chars = sorted(list(set(text)))
print('사용되고 있는 문자의 수:', len(chars))
char_indices = dict((c, i) for i, c in enumerate(chars)) # 문자 → ID
indices_char = dict((i, c) for i, c in enumerate(chars)) # ID → 문자
# 텍스트를 maxlen개의 문자로 자르고 다음에 오는 문자 등록하기
maxlen = 20
step = 3
sentences = []
next_chars = []
for i in range(0, len(text) - maxlen, step):
sentences.append(text[i: i + maxlen])
next_chars.append(text[i + maxlen])
print('학습할 구문의 수:', len(sentences))
print('텍스트를 ID 벡터로 변환합니다...')
X = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
for i, sentence in enumerate(sentences):
for t, char in enumerate(sentence):
X[i, t, char_indices[char]] = 1
y[i, char_indices[next_chars[i]]] = 1
# 모델 구축하기(LSTM)
print('모델을 구축합니다...')
model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))
optimizer = RMSprop(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
# 후보를 배열에서 꺼내기
def sample(preds, temperature=1.0):
preds = np.asarray(preds).astype('float64')
preds = np.log(preds) / temperature
exp_preds = np.exp(preds)
preds = exp_preds / np.sum(exp_preds)
probas = np.random.multinomial(1, preds, 1)
return np.argmax(probas)
# 학습시키고 텍스트 생성하기 반복
for iteration in range(1, 60):
print()
print('-' * 50)
print('반복 =', iteration)
model.fit(X, y, batch_size=128, nb_epoch=1) #
# 임의의 시작 텍스트 선택하기
start_index = random.randint(0, len(text) - maxlen - 1)
# 다양한 다양성의 문장 생성
for diversity in [0.2, 0.5, 1.0, 1.2]:
print()
print('--- 다양성 = ', diversity)
generated = ''
sentence = text[start_index: start_index + maxlen]
generated += sentence
print('--- 시드 = "' + sentence + '"')
sys.stdout.write(generated)
# 시드를 기반으로 텍스트 자동 생성
for i in range(400):
x = np.zeros((1, maxlen, len(chars)))
for t, char in enumerate(sentence):
x[0, t, char_indices[char]] = 1.
# 다음에 올 문자를 예측하기
preds = model.predict(x, verbose=0)[0]
next_index = sample(preds, diversity)
next_char = indices_char[next_index]
# 출력하기
generated += next_char
sentence = sentence[1:] + next_char
sys.stdout.write(next_char)
sys.stdout.flush()
print()
반응형
'Study > 머신러닝' 카테고리의 다른 글
MNIST 데이터셋을 활용해 시각화하기 (0) | 2021.01.11 |
---|---|
딥러닝 학습 과정과 용어 (0) | 2021.01.11 |
[5] 문장의 유사도 분석하기 - 레벤슈타인 거리, N-gram (1) | 2020.08.06 |
[4] MLP(Multi Layer Perceptron)로 텍스트 분류하기 (0) | 2020.07.30 |
[3] 나이브 베이즈 분류를 사용한 텍스트 분류 (0) | 2020.07.25 |