세로형
Recent Posts
Recent Comments
Link
03-29 03:47
«   2024/03   »
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
Archives
Today
Total
관리 메뉴

꿈 많은 사람의 이야기

딥러닝을 활용한 번역기를 만들어보자!(python keras seq2seq translate model) 본문

deep learning(딥러닝)

딥러닝을 활용한 번역기를 만들어보자!(python keras seq2seq translate model)

이수진의 블로그 2019. 3. 13. 14:35


어제 텐서플로와 머신러닝으로 시작하는 자연어 처리 책을 보면서 sequence-to-sequence 모델을 공부했습니다.

챗봇을 만들 때 사용하던 모델이었는데 과연 케라스(keras)에서는 어떻게 사용되는지 궁금해서 공부를 했고

지금 정리를 하려고 합니다. 이 자료는 케라스 코리아 운영자이신 김태영님의 블로그를 많이 참고했습니다!

https://tykimos.github.io/2018/09/14/ten-minute_introduction_to_sequence-to-sequence_learning_in_Keras/


기계번역(NMT, Neural Machine Translation)에서 많이 쓰이는 seq2seq 모델은 작성된 소스 문장들(source sentences)을 인코더(Encoder)를 이용해서 생각 벡터 형태로 변환하고 이 생각 벡터를 특징값으로 이용해서 디코더(decoder)가 번역할 언어로 작성된 타겟 문장을 생성하는 방법입니다.

 

예를 들어서 “I am soojin” -> Encoder -> [0.1, 0.5, -0.4, 1.2] -> decoder - > “나는 수진이다이렇게 말이죠

 

이 방법은 번역기 뿐만 아니라 챗봇과 같은 모델에서도 사용이 가능합니다. 자연어 데이터를 주면 자연어 응답을 생성하는 방법이니까요



이 그림에서 보면 차례대로 time step 순으로 데이터가 들어갑니다

앞의 초록색이 인코더 부분이며 단어가 index화 된 상태입니다

그리고 디코더(파란색)로 갈 때 인코더의 마지막 상태 벡터 값을 넘겨받고 이 벡터값을 이용해서 출력이 됩니다

또한, 디코더에서 나온 하나의 출력 값이(예를 들어 am) 그 다음 step에 입력 값으로 들어가게 됩니다.



이 사진을 보면 더 명확합니다. 디코더에서는 나온 출력 값이 다음의 입력 값으로 들어가서 영향을 주게 되고 상태 벡터 + 입력 값을 합쳐서 결과가 나오게 됩니다.

 

보통 이 seq2seq 모델을 만들 때 RNN을 이용하게 됩니다. 진행 순서는 아래와 같이 됩니다.

1.     Encoder 계층은 입력 시퀀스를 처리하고 내부 상태를 반환합니다. encoder에서 나온 결과는 사용하지 않고 상태만 가져옵니다(벡터 값). 이것은 decoder의 입력 값으로 들어갑니다.

2.     Decoderencoder 상태 벡터들을 초기 상태로 사용하고 이전 문자들에 따라 다음 문자들을 예측합니다. Decoder는 주어진 target[..t]을 입력 시퀀스에 맞춰서 target[t+1...]을 생성합니다.


바로 코드로 가보죠!


이 코드는 영어를 프랑스어로 바꿔주는 번역기입니다!



위의 설명처럼 단계별로 진행합니다.

문자 단위로 처리하고 출력하는 모델을 만듭니다.

진행 과정은 아래와 같이 진행됩니다.

  1. 문장들을 3차원 배열(encoder_input, decoder_input, decoder_target)으로 변환합니다.

    • encoder_input은 (num_pairs, max_english_sentence_length, num_elglish_character) 형태의 3차원 배열로 영어 문장의 one-hot 형식 벡터 데이터를 갖고 있습니다.

    • decoder_input은 (num_pairs, max_french_sentece_length, num_french_character) 형태의 3차원 배열로 불어 문장의 one-hot 형식입니다.

    • decoder_target은 decoder_input과 같지만 하나의 time step 만큼 offset 됩니다. decoer_target[:, t, :]는 decoder_input[:, t+1, :]과 같습니다.
  2. 기본 LSTM 기반의 seq2seq model을 주어진 encoder_input과 decoder_input로 decoder_target을 예측합니다.

  3. model이 작동하는지 확인하기 위해 일부 문장을 디코딩합니다.(encdoer_input의 샘플을 decoder_target의 표본으로 변환합니다)

문장을 디코딩 하는 학습 단계와 추론 단계는 좀 다릅니다. 같은 내부 계층을 사용하지만 서로 다른 모델을 사용하죠.

  • return_state : encoder의 출력과 내부 RNN 상태 반환
  • initial_state : decoder의 초기 상태를 지정
  • return_sequences : 전체 시퀀스를 반환



필요한 라이브러리를 호출합니다.

python의 matplotlib, seaborn, keras, numpy, pandas 등 기본적인 라이브러리를 호출합니다.

그리고 나중에 사용할 batch_size, epochs 등의 변수도 미리 선언하겠습니다.

데이터를 with open으로 불러오고 f.read().split("\n") 식으로 불러오면

하나의 배열에 값이 들어가는데 \t(탭)을 기준으로 데이터가 나눠져 있습니다.



이 데이터를 이제 각각 나눠줍니다.

인코더, 디코더에 각각 들어가기 때문에 input, label로 나눠줍니다

input에는 영어, label과 target은 프랑스어가 들어갑니다.

그리고 시작점과 끝점을 알기 위해서 \t를 맨 앞에 \n을 맨 뒤에 놓습니다.

그래서 각 단어 하나하나 별로 값이 set에 들어가게 됩니다.



들어간 값은 위처럼 나옵니다. love면 love 자체가 들어가는게 아니라

l, o, v, e 따로따로 들어가는 것이죠

그걸 이제 정렬을 해주고 배열로 바꿔줍니다.

그리고 최대 길이 값을 알아내고, 들어간 단어의 개수를 가져옵니다



input으로 들어온 unique한 데이터 개수는 69개, target으로 들어온 unique한 개수는 93개입니다.

그리고 영어는 가장길이가 긴게 16이고 프랑스어는 59가 됩니다.



이제 numpy의 np.zero을 통해서 나중에 one-hot 데이터를 넣을 깡통 데이터를 만들어줍니다.

test_input_data는 테스트를 위한 용도입니다. 필요없는 데이터입니다

그래서 shape를 보면 위 처럼 input_text 길이, 최대길이, unique 개수 값이 들어갑니다



이제 이것을 one-hot 형태로 만들어줘야 합니다.

위에는 테스트로 한 것인데요. 위 처럼 해당되는 단어가 있는 곳에 1이 찍히게 됩니다.




그래서 1이 찍히게 하는 one-hot 방식을 input_texts와 target_texts를 zip으로 돌리고 또 enumerate를 하면서 동시에 봅니다.


그리고 이제 모델을 만들어줍니다

인코더(encoder) 부분과 디코더(decoder) 부분을 만들어줍니다.

encoder_inputs는 LSTM을 거쳐서 encoder_outputs와 state_h, state_c를 뱉어내는데요

여기서 출력 상태 벡터(state_h, state_c)만 가져옵니다.


그리고 이 출력 상태 벡터는 디코더(decoder)에 initial_state에 들억게 됩니다.

decoder도 마찬가지로 LSTM을 이용하고 return_sequences=True, return_state = True를 합니다.



만들어진 모델의 모양입니다.

Model에서 inputs으로 encoder_inputs과 decoder_inputs이 같이 들어갑니다. 그리고 output은 decoder_outputs가 들어가게 되죠

model.compile에서는 loss를 categorical_crossentropy를 해주고 optimizer는 adam으로 합니다.

그리고 keras의 EarlyStopping을 이용해서 monitor를 val_loss를 두고 더 이상 loss가 줄어들지 않으면 멈춥니다.

이 early_stopping은 굳이 안하셔도 됩니다.



이렇게 쭉쭉 훈련을 시킵니다.

model.fit을 해놓고 좀 쉬러 갔다왔습니다 ㅎㅎ

input으로 encoder_input_data와 decoder input을 넣습니다. 그리고 label로는 decoder target을 넣어줍니다.

decoder target은 decoder input과 비교하는 값입니다. 그래서 t+1 값을 가지죠



이제 모델을 훈련했으니 추론을 해봐야죠?

encoder_model을 하나 만들어줍니다. 

인코더 input에 대한 모델과 encoder state를 가져와서 넣어줍니다



그리고 decoder 추론할 모델도 만들어줍니다.

디코더 input을 넣어주고 초기 상태의 decoder를 셋팅합니다.

model의 input으론 dedcoer input을 넣고 output으론 decoder output을 넣어줍니다. 그리고 상태값도 더하구요



그리고 훈련할 땐 텍스트가 index로 변환되었지만

예측할 땐 index -> text로 되어야 하기 때문에 반대로 합니다.



그리고 예측하는 함수를 만듭니다.

이 부분은 저도 아직 이해가 완벽하게 되지 않았습니다.

자세한 설명은 주석에 최대한 달아놨으니 참고바랍니다



그렇게 해서 돌리게 되면

영어 값이 들어가고 그에 해당되는 번역이 나오게 됩니다.


딥러닝을 활용한 번역기 만들기

keras로 해봤습니다. keras translate이겠죠? seq2seq 모델을 사용했구요

쉽지 않네요

개념은 대충 이해는 되지만 완벽하게 이해가 되지도 않았구요


더 공부해야겠습니다!



반응형
그리드형
Comments