본문 바로가기
기계학습/자연어 처리 머신러닝

글자단위 예측 모델 - N:N 모델 LSTM

by tryotto 2020. 2. 18.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 파일 읽어오기 - byte 단위로 읽어오기 위해 'rb' 사용
file = open('/content/drive/My Drive/train_char.txt','rb')
 
 
 
 
 
 
# 데이터 전처리해서 새로 저장하기
lines = []
 
for s in file:
  # 소문자로 변형
  s = s.lower()
  
  # \n, \r 제거
  s = s.strip()
  
  # 바이트 열 제거
  s = s.decode('ascii''ignore')
 
  # 전처리한 문장들을 lines 에 저장
  if len(s) > 0:    
      lines.append(s)
 
 
 
 
 
 
# 각각의 문장들을 ' ' 로 구분하지 않고, 하나의 원문으로 뭉치기
text = ' '.join(lines)
 
 
 
 
 
 
# 알파벳 단위로 정렬된 집합 만들기
# set 연산  - 중복되지 않도록 알파벳을 하나의 집합으로 변환
# list 연산 - sorted 연산을 위해서 list 로 변형시키기 위함
char_set = sorted(list(set(text)))
char_size = len(char_set)
 
# 딕셔너리 만들기 (1) - char_to_idx
tmp_dict = []
for idx, c in enumerate(char_set):
  tmp_dict.append([c, idx])
char_to_idx = dict(tmp_dict)
 
# 딕셔너리 만들기 (2) - idx_to_char
idx_to_char = {}
idx = 0
for c in char_to_idx:
 idx_to_char[idx] = c
 idx += 1
 
 
 
 
 
# 훈련 데이터 만들기 - 특정 길이만큼 분할한 뒤, 정수 인코딩을 모두 시켜준다
import numpy as np
 
len_line = 60
num_sentence = int(len(text)/len_line)
 
train_X = []
train_Y = []
tmp_line = []
 
for i in range(num_sentence):
  tmp_line = text[ i * len_line : (i+1* len_line]  
  train_X.append([char_to_idx[c] for c in tmp_line])
  tmp_line=[]
  
  tmp_line = text[ i * len_line + 1: (i+1* len_line + 1]
  train_Y.append([char_to_idx[c] for c in tmp_line])
  tmp_line=[]
 
 
 
 
 
 
# padding 과정 수행하기
from tensorflow.keras.preprocessing.sequence import pad_sequences
 
max_len = 60
train_X = pad_sequences(train_X, maxlen = max_len)
trian_Y = pad_sequences(train_Y, maxlen = max_len)
 
 
 
 
 
 
 
# 원핫벡터로 만들기 - X 값도 원핫벡터로 만들기 때문에, 따로 임베딩 과정이 필요없어진다
from tensorflow.keras.utils import to_categorical
 
onehot_X = to_categorical(train_X)
onehot_Y = to_categorical(train_Y)
 
 
 
 
 
 
 
# 모델 설계
from tensorflow.keras.layers import Dense, LSTM
from tensorflow.keras.models import Sequential
 
model = Sequential()
model.add(LSTM(256, input_shape=(None, char_size), return_sequences=True))
model.add(LSTM(256, return_sequences=True))
model.add(Dense(units=char_size, activation='softmax'))
 
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
model.fit(x=onehot_X, y=onehot_Y, batch_size=100, epochs=10, verbose=2)
cs


1. 임베딩 층이 따로 없다는게 독특하다.
임베딩 층이 없기 때문에, X 값을 원핫벡터로 변환시켜주는 과정이 필요하다

2. LSTM 에서 받아야 하는 argument 값은 오직, "하나의 셀에 있는 은닉 벡터의 차원 수" 다.
따로 input_shape = () 를 통해서 전달받아야 한다면, 
(배치 size, 임베딩 층의 벡터 dimension) 을 전달받는다

3. 그렇다면 LSTM 의 time series 갯수는 어떻게 알 수 있을까?
-> 추측으론, 인풋 값의 shape 를 이용해서 구하는 걸로 보인다.
ex) 저기선, onehot_X 의 shape = (2464, 60, 56) 이었기 때문에,
 총 60번의 time series 를 지난다
(2464 는 데이터의 갯수, 56은 임베딩 층의 벡터 dimension 이다)

4. 저번과 마찬가지로, N:N 모델이기 때문에 return_sequences=True 처리를 해줘야 한다
-> 근데, LSTM 이 두 개가 있는 경우엔 어떻게 되는거지?
둘 다 return_sequences=True 를 해버리면, 출력값의 길이가 이상해지는데...