[신경망] RNN을 이용한 단어 번역 알고리즘 코드

2020. 5. 1. 16:06노트/Python : 프로그래밍

단어 정의 

"""
S : 인코딩 입력의 시작 
E : 디코딩 출력의 끝 
P : 현재 배치되는 데이터의 time step 크기보다 작은 경우 빈 시퀀스를 채우는 심볼 

배치 데이터의 최대 크기 4 인경우, 
word = > ['w','o','r','d']
to => ['t','o','P','P']

"""
char_arr=[c for c in "SEPabcdefghijklmnopqrstuvwxyz단어나무놀이소녀키스사랑"]
num_dic={n:i for i, n in enumerate(char_arr)}
dic_len=len(num_dic)

seq_data=[['word','단어'], ['wood','나무'],
         ['game','놀이'], ['girl','소녀'],
         ['love','사랑'], ['kiss','키스']]

 

단어 매칭 함수 정의 

def make_batch(seq_data):#[['word', '단어']]
    input_batch=[]
    output_batch=[]
    target_batch=[]
    for seq in seq_data: #['word', '단어']   
        inputdata=[num_dic[n] for n in seq[0]]   # word -> [25, 17, 20, 6]    
        #print(input)
        outputdata=[num_dic[n] for n in ('S'+seq[1])]
        targetdata=[num_dic[n] for n in (seq[1]+'E')]
        
        input_batch.append(np.eye(dic_len)[inputdata])
        output_batch.append(np.eye(dic_len)[outputdata])
        target_batch.append(targetdata) #출력값만 원핫이 아님(sparse_사용)
    return input_batch,output_batch,target_batch
    
input_batch,output_batch,target_batch=make_batch(seq_data)

tf.reset_default_graph()

# 모델 옵션 설정 
lr = 0.01 
n_hidden = 128 
total_epoch = 100 
n_class = n_input = dic_len 

 

신경망 구성 

# 신경망 구성  [배치사이즈, 단계, 입력크기 ]
encInput = tf.placeholder(tf.float32, [None, None, n_input ])

decInput = tf.placeholder(tf.float32, [None, None, n_input ])

targets = tf.placeholder(tf.int64, [None, None])


# 인코더 셀을 구성 
enc_cell = tf.nn.rnn_cell.BasicRNNCell(n_hidden,reuse=tf.AUTO_REUSE)
enc_cell = tf.nn.rnn_cell.DropoutWrapper(enc_cell, output_keep_prob=0.5)
outputs, enc_states = tf.nn.dynamic_rnn(enc_cell, encInput, dtype=tf.float32 )

# 디코더 셀을 구성 
dec_cell = tf.nn.rnn_cell.BasicRNNCell(n_hidden, reuse=tf.AUTO_REUSE)
dec_cell = tf.nn.rnn_cell.DropoutWrapper(dec_cell, output_keep_prob=0.5)
outputs, dec_states= tf.nn.dynamic_rnn(dec_cell, decInput, initial_state = enc_states, dtype=tf.float32)

 

모델 학습 

model = tf.layers.dense(outputs, n_class, activation=None)

cost = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=model, labels=targets))

opt = tf.train.AdamOptimizer(lr).minimize(cost)

# 신경망 모델 학습 
sess=tf.Session()
sess.run(tf.global_variables_initializer())

input_batch, output_batch, target_batch = make_batch(seq_data)

for epoch in range(total_epoch):
    _,cv=sess.run([opt, cost], feed_dict = {encInput: input_batch, 
                                      decInput: output_batch,
                                      targets: target_batch})
    print(" epoch: ","%04d" %(epoch+1), "cost: ","{:.5f}".format(cv))

 

번역 결과 

def translate(w):
    seq_data = [w, "P"*len(w)]
    #seq_data = ['love', 'PPPP']
    input_batch, output_batch, target_batch = make_batch([seq_data])
    # input_batch = ['w','o','r','d']
    # output_batch = ['P','P','P','P']
    # target_batch = [2,2,2,2]
    
    # 결과 : [배치사이즈, 스텝, 입력 ]
    # 2번째 차원인 입력차원을 argmax로 적용 -> 확률이 가장 높은 글자가 예측 
    prediction = tf.argmax(model,2)
    #[[[0 0 0 0.9 ..... 0.1]]]
    
    res=sess.run(prediction, feed_dict={
        encInput:input_batch,
        decInput:output_batch,
        targets:target_batch
    }) # 숫자 인덱스가 저장되어 있음 
    decoded = [char_arr[i] for i in res[0]]
    end=decoded.index("E")
    translated="".join(decoded[:end])
    return translated
    
print("word?", translate('word'))
print("wodr?", translate('wodr'))
print("love?", translate('love'))
print("loev?", translate('loev'))
print("like?", translate('like'))

>>>
word? 단어
wodr? 나무
love? 사랑
loev? 사랑
like? 사랑