Notice
Recent Posts
Recent Comments
NeuroWhAI의 잡블로그
[Keras] Seq2Seq 문장 번역 예제 본문
다른 분의 강좌를 보면서 따라했습니다.
사실 따라했다기 보다는 코드 복붙해놓고 이해하려고 노력했다는게 더 정확하지만 ...
코드:
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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | # https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html !pip install -U -q PyDrive from keras import layers, models from keras import datasets from keras import backend import matplotlib.pyplot as plt import numpy as np def get_data(file_id): """ 구글 드라이브에서 file_id에 해당하는 파일을 가져와 읽습니다. Colab에서 돌리기 위해 필요합니다. """ # Install the PyDrive wrapper & import libraries. # This only needs to be done once per notebook. from pydrive.auth import GoogleAuth from pydrive.drive import GoogleDrive from google.colab import auth from oauth2client.client import GoogleCredentials # Authenticate and create the PyDrive client. # This only needs to be done once per notebook. auth.authenticate_user() gauth = GoogleAuth() gauth.credentials = GoogleCredentials.get_application_default() drive = GoogleDrive(gauth) # Download a file based on its file ID. # # A file ID looks like: laggVyWshwcyP6kEI-y_W3P8D26sz downloaded = drive.CreateFile({'id': file_id}) return downloaded.GetContentString() # 학습 정보 batch_size = 64 epochs = 64 latent_dim = 256 num_samples = 1024 # 학습 데이터 개수 # 문장 벡터화 input_texts = [] target_texts = [] input_characters = set() target_characters = set() data_set = { 'kor': '12UL7MH38rxRFskhYuj1B9zU7wUXgv8Q7', 'jpn': '1ULdUnurb_DEDTzJFaycdWHWkYWqPu4Bo' } lines = get_data(data_set['jpn']).split('\n') for line in lines[: min(num_samples, len(lines) - 1)]: input_text, target_text = line.split('\t') # "\t"문자를 시작 문자로, "\n"문자를 종료 문자로 사용. target_text = '\t' + target_text + '\n' input_texts.append(input_text) target_texts.append(target_text) # 문자 집합 생성 for char in input_text: if char not in input_characters: input_characters.add(char) for char in target_text: if char not in target_characters: target_characters.add(char) num_samples = len(input_texts) input_characters = sorted(list(input_characters)) target_characters = sorted(list(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('Number of samples:', num_samples) print('Number of unique input tokens:', num_encoder_tokens) print('Number of unique output tokens:', num_decoder_tokens) print('Max sequence length for inputs:', max_encoder_seq_length) print('Max sequence length for outputs:', max_decoder_seq_length) # 문자 -> 숫자 변환용 사전 input_token_index = dict( [(char, i) for i, char in enumerate(input_characters)]) target_token_index = dict( [(char, i) for i, char in enumerate(target_characters)]) # 학습에 사용할 데이터를 담을 3차원 배열 encoder_input_data = np.zeros( (num_samples, max_encoder_seq_length, num_encoder_tokens), dtype='float32') decoder_input_data = np.zeros( (num_samples, max_decoder_seq_length, num_decoder_tokens), dtype='float32') decoder_target_data = np.zeros( (num_samples, max_decoder_seq_length, num_decoder_tokens), dtype='float32') # 문장을 문자 단위로 원 핫 인코딩하면서 학습용 데이터를 만듬 for i, (input_text, target_text) in enumerate(zip(input_texts, target_texts)): 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_input_data[i, t, target_token_index[char]] = 1. if t > 0: decoder_target_data[i, t - 1, target_token_index[char]] = 1. # 인코더 생성 encoder_inputs = layers.Input(shape=(None, num_encoder_tokens)) encoder = layers.LSTM(latent_dim, return_state=True) encoder_outputs, state_h, state_c = encoder(encoder_inputs) # 인코더의 출력은 필요없고 상태만 중요 encoder_states = [state_h, state_c] # 디코더 생성. decoder_inputs = layers.Input(shape=(None, num_decoder_tokens)) decoder_lstm = layers.LSTM(latent_dim, return_sequences=True, return_state=True) # 디코더의 내부 상태는 학습에 사용하지 않지만 추론(테스트) 단계에서는 필요함. # 디코더의 초기 상태를 인코더의 최종 상태로 설정. decoder_outputs, _, _ = decoder_lstm(decoder_inputs, initial_state=encoder_states) decoder_dense = layers.Dense(num_decoder_tokens, activation='softmax') decoder_outputs = decoder_dense(decoder_outputs) # 모델 생성 model = models.Model([encoder_inputs, decoder_inputs], decoder_outputs) # 학습 model.compile(optimizer='rmsprop', loss='categorical_crossentropy') model.fit([encoder_input_data, decoder_input_data], decoder_target_data, batch_size=batch_size, epochs=epochs, validation_split=0.2, verbose=2) # 추론(테스트) # 추론 모델 생성 encoder_model = models.Model(encoder_inputs, encoder_states) decoder_state_input_h = layers.Input(shape=(latent_dim,)) decoder_state_input_c = layers.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] decoder_outputs = decoder_dense(decoder_outputs) decoder_model = models.Model( [decoder_inputs] + decoder_states_inputs, [decoder_outputs] + decoder_states) # 숫자 -> 문자 변환용 사전 reverse_input_char_index = dict( (i, char) for char, i in input_token_index.items()) reverse_target_char_index = dict( (i, char) for char, i in target_token_index.items()) def decode_sequence(input_seq): # 입력 문장을 인코딩 states_value = encoder_model.predict(input_seq) # 디코더의 입력으로 쓸 단일 문자 target_seq = np.zeros((1, 1, num_decoder_tokens)) # 첫 입력은 시작 문자인 '\t'로 설정 target_seq[0, 0, target_token_index['\t']] = 1. # 문장 생성 stop_condition = False decoded_sentence = '' while not stop_condition: # 이전의 출력, 상태를 디코더에 넣어서 새로운 출력, 상태를 얻음 # 이전 문자와 상태로 다음 문자와 상태를 얻는다고 보면 됨. output_tokens, h, c = decoder_model.predict( [target_seq] + states_value) # 사전을 사용해서 원 핫 인코딩 출력을 실제 문자로 변환 sampled_token_index = np.argmax(output_tokens[0, -1, :]) sampled_char = reverse_target_char_index[sampled_token_index] decoded_sentence += sampled_char # 종료 문자가 나왔거나 문장 길이가 한계를 넘으면 종료 if (sampled_char == '\n' or len(decoded_sentence) > max_decoder_seq_length): stop_condition = True # 디코더의 다음 입력으로 쓸 데이터 갱신 target_seq = np.zeros((1, 1, num_decoder_tokens)) target_seq[0, 0, sampled_token_index] = 1. states_value = [h, c] return decoded_sentence for seq_index in range(30): input_seq = encoder_input_data[seq_index: seq_index + 1] decoded_sentence = decode_sequence(input_seq) print('"{}" -> "{}"'.format(input_texts[seq_index], decoded_sentence.strip())) | cs |
결과:
Number of samples: 1024
Number of unique input tokens: 64
Number of unique output tokens: 485
Max sequence length for inputs: 12
Max sequence length for outputs: 20
Train on 819 samples, validate on 205 samples
Epoch 1/64
- 3s - loss: 1.8982 - val_loss: 1.7415
Epoch 2/64
- 1s - loss: 1.5878 - val_loss: 1.7715
Number of unique input tokens: 64
Number of unique output tokens: 485
Max sequence length for inputs: 12
Max sequence length for outputs: 20
Train on 819 samples, validate on 205 samples
Epoch 1/64
- 3s - loss: 1.8982 - val_loss: 1.7415
Epoch 2/64
- 1s - loss: 1.5878 - val_loss: 1.7715
(중략)
Epoch 63/64
- 1s - loss: 0.3502 - val_loss: 1.4305
Epoch 64/64
- 1s - loss: 0.3327 - val_loss: 1.4706
"Hi." -> "やっておい。"
"Hi." -> "やっておい。"
"Run." -> "走って!"
"Run." -> "走って!"
"Who?" -> "誰?"
"Wow!" -> "すごい!"
"Wow!" -> "すごい!"
"Wow!" -> "すごい!"
"Fire!" -> "火事!"
"Fire!" -> "火事!"
"Help!" -> "助けて!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump." -> "飛び跳ねて!"
"Jump." -> "飛び跳ねて!"
"Stop!" -> "やめろ!"
"Stop!" -> "やめろ!"
"Wait!" -> "待って!"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Hello!" -> "こんにちは!"
"Hello!" -> "こんにちは!"
"Hello!" -> "こんにちは!"
"Hurry!" -> "もちろん!"
"I see." -> "私はそうをいいます。"
- 1s - loss: 0.3502 - val_loss: 1.4305
Epoch 64/64
- 1s - loss: 0.3327 - val_loss: 1.4706
"Hi." -> "やっておい。"
"Hi." -> "やっておい。"
"Run." -> "走って!"
"Run." -> "走って!"
"Who?" -> "誰?"
"Wow!" -> "すごい!"
"Wow!" -> "すごい!"
"Wow!" -> "すごい!"
"Fire!" -> "火事!"
"Fire!" -> "火事!"
"Help!" -> "助けて!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump!" -> "飛び降りろ!"
"Jump." -> "飛び跳ねて!"
"Jump." -> "飛び跳ねて!"
"Stop!" -> "やめろ!"
"Stop!" -> "やめろ!"
"Wait!" -> "待って!"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Go on." -> "進んで。"
"Hello!" -> "こんにちは!"
"Hello!" -> "こんにちは!"
"Hello!" -> "こんにちは!"
"Hurry!" -> "もちろん!"
"I see." -> "私はそうをいいます。"
Colab에서 돌린거라 구글 드라이브의 파일을 읽도록 수정했는데 다른 분들도 불러와질지 모르겠네요.
번역은 왜 일본어로 했냐면 한국어는 데이터가 부족해서 학습이 잘 안되더라고요...
계속 '톰', '자살' 타령;;
구현이 꽤 이해하기 힘드네요 ㅠㅠ
Keras에 익숙하지 않은 탓도 있지만 추론 모델을 만드는 과정은 이론적으론 알지만 코드는 복잡하게 생겨서 이해가;;
주석이 부족한건 제가 이해를 다 못해서 그렇습니다 ㅠ
'개발 및 공부 > 라이브러리&프레임워크' 카테고리의 다른 글
[C#] Selenium을 이용해 YouTube 추천 동영상 파싱하기 (0) | 2018.05.07 |
---|---|
[Keras] 레이어 직접 만들기 (0) | 2018.04.08 |
[Python] PyDrive로 구글 드라이브에 있는 파일 읽기 (2) | 2018.04.01 |
[Keras] ImageDataGenerator 사용해서 학습 데이터 개수 늘리기 (0) | 2018.04.01 |
[TensorFlow] TensorFlow.js 소개 + 예제 실습 (1) | 2018.03.31 |
Comments