728x90
tensorflow 환경에서 진행했다.
참고사이트
# seq2seq로 영어를 한국어로 번역하는 번역 모델 생성
from keras.models import Model
from keras.layers import Input, LSTM, Dense
from tensorflow.keras.optimizers import Adam
import numpy as np
데이터 읽어오기
data_path = 'eng_kor.txt'
lines = open(data_path, mode='r', encoding='utf-8').read().split('\n')
print(lines[:10])
print(len(lines))
ㅡㅡㅡㅡㅡㅡㅡㅡㅡ
['Go.\t가.', 'Hi.\t안녕.', 'Run!\t뛰어!', 'Run.\t뛰어.', 'Who?\t누구?', 'Wow!\t우와!', 'Fire!\t쏴!', 'Help!\t도와줘!', 'Jump!\t점프!', 'Jump.\t점프해.']
595
샘플 수 10000개를 꺼내어 영어와 번역한글로 나누어준다. / set으로 중복 제거
num_samples = 10000
input_texts = []
target_texts = []
input_characters = set()
target_characters = set()
for line in lines[:min(num_samples, len(lines))]:
input_text, target_text = line.split('\t') # Go. 가.
# print(input_text)
# print(target_text)
target_text ='\t' + target_text + '\n' # \t:<sos> \n:<eos>로 사용
input_texts.append(input_text)
target_texts.append(target_text)
for char in input_text:
input_characters.add(char)
for char in target_text:
target_characters.add(char)
print(input_texts[:10])
print(target_texts[:10])
input_characters = sorted(input_characters)
target_characters = sorted(target_characters)
print(input_characters)
print(target_characters)
num_encoder_tokens = len(input_characters)
num_decoder_tokens = len(target_characters)
max_encoder_seq_length = max([len(txt) for txt in input_texts])
max_decoder_seq_length = max([len(txt) for txt in target_texts])
print('샘플 수:', len(input_texts))
print('영어 글자 수:', num_encoder_tokens)
print('한글 글자 수:', num_decoder_tokens)
print('영어 중 가장 긴 단어 글자 수:', max_encoder_seq_length)
print('한글 중 가장 긴 단어 글자 수:', max_decoder_seq_length)
글자 집합에 글자 단위로 저장된 각 글자에 대해 index 부여
# 글자 집합에 글자 단위로 저장된 각 글자에 대해 index 부여
input_token_index = dict([(char,i) for i, char in enumerate(input_characters)])
print(input_token_index)
target_token_index = dict([(char,i) for i, char in enumerate(target_characters)])
print(target_token_index)
one-hot
# One-hot
encoder_input_data = np.zeros((len(input_texts), max_encoder_seq_length, num_encoder_tokens), dtype='float32')
print(encoder_input_data.shape) # (595, 15, 59)
decoder_input_data = np.zeros((len(input_texts), max_decoder_seq_length, num_decoder_tokens), dtype='float32')
print(decoder_input_data.shape) # (595, 18, 427)
decoder_target_data = np.zeros((len(input_texts), max_decoder_seq_length, num_decoder_tokens), dtype='float32')
print(decoder_target_data.shape) # (595, 18, 427)
# 0으로 채워진 벡터에 해당 글자가 있는 지점은 1을 기억
for i, (input_text, target_text) in enumerate(zip(input_texts, target_texts)):
# print(input_text, target_text)
for t, char in enumerate(input_text):
encoder_input_data[i,t,input_token_index[char]]=1
for t, char in enumerate(target_text):
# decoder_target_index가 encoder_input_text 보다 한 스텝 앞서 입력됨!
decoder_input_data[i,t, target_token_index[char]]=1
if t > 0:
# decoder_target_data는 한 타임 스텝 만큼 앞당겨지며 시작문자를 포함하지 않음
decoder_target_data[i, t-1, target_token_index[char]] = 1
# print(encoder_input_data[5]) # 데이터 있는 부분만 1로 채워진다.
network 설계 - function api 사용
# 인코더 설계
latent_dim = 1024 # 인코딩 공간 차원
encoder_inputs = Input(shape=(None, num_encoder_tokens))
encoder_lstm = LSTM(units=latent_dim, return_state=True)
encoder_outputs, state_h, state_c = encoder_lstm(encoder_inputs)
encoder_states = [state_h, state_c] # LSTM은 RNN과 달리 상태가 두 개. 은닉상태와 셀상태를 기억. 이 것이 바로 context vector
# 디코더의 첫 상태를 인코더의 은닉상태와 셀상태로 설정
decoder_inputs = Input(shape=(None, num_decoder_tokens))
decoder_lstm = LSTM(units=latent_dim, return_state=True, return_sequences=True)
decoder_outputs, _, _ = decoder_lstm(decoder_inputs, initial_state=encoder_states)
decoder_dense = Dense(num_decoder_tokens, activation='softmax')
decoder_outputs = decoder_dense(decoder_outputs)
batch_size=64
epochs = 50
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
print(model.summary())
model.compile(optimizer='Adam', loss='categorical_crossentropy')
model.fit(x=[encoder_input_data, decoder_input_data], y=decoder_target_data,
batch_size=batch_size, epochs=epochs, validation_split=0.2, verbose=2)
model.save('s2s_ek.h5')
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
Model: "model_5"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_21 (InputLayer) [(None, None, 59)] 0 []
input_22 (InputLayer) [(None, None, 427)] 0 []
lstm_20 (LSTM) [(None, 1024), 4440064 ['input_21[0][0]']
(None, 1024),
(None, 1024)]
lstm_21 (LSTM) [(None, None, 1024) 5947392 ['input_22[0][0]',
, (None, 1024), 'lstm_20[0][1]',
(None, 1024)] 'lstm_20[0][2]']
dense_9 (Dense) (None, None, 427) 437675 ['lstm_21[0][0]']
==================================================================================================
Total params: 10,825,131
Trainable params: 10,825,131
Non-trainable params: 0
Epoch 49/50
8/8 - 0s - loss: 1.5384 - val_loss: 2.2864 - 283ms/epoch - 35ms/step
Epoch 50/50
8/8 - 0s - loss: 1.5283 - val_loss: 2.2783 - 250ms/epoch - 31ms/step
번역기 동작
# seq2seq 번역기 동작
# 인코더 모델
encoder_model = Model(inputs=encoder_inputs, outputs=encoder_states)
# 번역 동작 단계
# 1. 번역하고자 하는 입력문장이 인코더에 들어와서 은닉상태와 셀상태를 만든다.
# 2. 상태와 <sos>에 해당하는 '\t'를 디코더로 전달한다.
# 3. 디코더가 <eos>에 해당하는 '\n'이 나올 때까지 다음 문자를 예측하는 행동을 반복한다.
# 디코더 모델
decoder_state_input_h = Input(shape = (latent_dim,))
decoder_state_input_c = Input(shape = (latent_dim,))
decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]
decoder_outputs, state_h, state_c = decoder_lstm(decoder_inputs, initial_state=decoder_states_inputs)
# 문장의 다음 단어를 예측하기 위해서 초기상태를 이전 시점의 상태로 사용
decoder_states = [state_h, state_c]
# 인코더와 다르게 LSTM이 반환하는 은닉상태와 셀 상태를 버리지 않음
decoder_outputs = decoder_dense(decoder_outputs)
decoder_model = Model(inputs=[decoder_inputs] + decoder_states_inputs,
outputs=[decoder_outputs]+decoder_states)
print(decoder_model.summary())
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
Model: "model_7"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_22 (InputLayer) [(None, None, 427)] 0 []
input_23 (InputLayer) [(None, 1024)] 0 []
input_24 (InputLayer) [(None, 1024)] 0 []
lstm_21 (LSTM) [(None, None, 1024) 5947392 ['input_22[0][0]',
, (None, 1024), 'input_23[0][0]',
(None, 1024)] 'input_24[0][0]']
dense_9 (Dense) (None, None, 427) 437675 ['lstm_21[1][0]']
==================================================================================================
Total params: 6,385,067
Trainable params: 6,385,067
Non-trainable params: 0
시퀀스를 다시 디코딩하는 역방향 조회 토큰 인덱스. 단어로 부터 인덱스를 얻는 것이 아니라 인덱스로부터 단어 얻기
reverse_input_char_index = dict((i, char) for char, i in input_token_index.items())
print(reverse_input_char_index)
reverse_target_char_index = dict((i, char) for char, i in target_token_index.items())
print(reverse_target_char_index)
번역기 함수를 생성
def decode_seq_func(input_seq):
# 입력으로 부터 인코더 상태를 얻음
states_value = encoder_model.predict(input_seq)
# print('states_value:', states_value) # [array([[ 2.2908259e-04, 2.2446758e-03, -1.9103340e-03, ...,
target_seq = np.zeros((1,1,num_decoder_tokens)) # 길이가 1인 타겟 시퀀스
# 대상 시퀀스의 첫 번째 문자를 시작문자로 채움
target_seq[0, 0, target_token_index['\t']] = 1. # <sns>에 해당하는 원핫벡터
# print('target_seq:',target_seq) # [[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
# 시퀀스 배치에 대한 샘플링 반복 처리
stop_condition = False
decoded_sentence = ''
while not stop_condition:
# 이전 시점 상태 state_value를 현재의 초기 상태로 사용
output_tokens, h, c = decoder_model.predict([target_seq] + states_value)
# 예측결과를 문자로 변환
sampled_token_index = np.argmax(output_tokens[0, -1, :])
# print('sampled_token_index:',sampled_token_index)
sampled_char = reverse_target_char_index[sampled_token_index]
# print('sampled_char:',sampled_char)
decoded_sentence += sampled_char # 현재 시점의 예측문자를 예측문자에 누적
print('decode_sentence', decoded_sentence)
if sampled_char == '\n' or len(decoded_sentence) > max_decoder_seq_length: # 최대길이 or <eos>를 만나면 종료
stop_condition = True
target_seq = np.zeros((1,1,num_decoder_tokens)) # <sos>에 해당하는 onehot벡터 생성
target_seq[0,0,sampled_token_index] = 1
states_value = [h,c] # states_value 갱신. 현 상태를 다음 시점의 상태로 사용
print('states_value', states_value)
return decoded_sentence
번역
for seq_idx in range(5): #[3,67,8,9,10]
# 디코딩을 위해 하나의 시퀀스 (학습 데이터)를 가져옴
input_seq = encoder_input_data[seq_idx:seq_idx+1]
results = decode_seq_func(input_seq)
print('-------------------------')
print('입력(영어):', input_texts[seq_idx])
print('번역결과(한국어):', results)
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
-------------------------
입력(영어): Hi.
번역결과(한국어): 톰이
>> 적은 양의 데이터라 흐름만 알아둔다
728x90
'데이터분석 > 예시코드' 카테고리의 다른 글
LSTM으로 주식을 예측 (1) | 2022.06.03 |
---|---|
네이버 영화 리뷰 데이터로 감성분류 (0) | 2022.06.02 |
웹 스크래핑 : 네이버 영화 평점 (0) | 2022.06.01 |
웹 스크래핑 : 기초 (0) | 2022.05.29 |
RNN을 이용한 텍스트 생성 (0) | 2022.05.27 |