day 25 Embedding and recurrent

4 minute read

understanding deep learning layers

1) 희소 표현(Sparse Representation) : 벡터의 특정 차원에 단어 혹은 의미를 직접 매핑하는 방식

2) 분포 가설(distribution hypothesis) : 유사한 맥락에서 나타나는 단어는 그 의미도 비슷하다

3) 분산 표현(Distributed Representation) : 유사한 맥락에 나타난 단어들끼리는 두 단어 벡터 사이의 거리를 가깝게 하고, 그렇지 않은 단어들끼리는 멀어지도록 조금씩 조정해 주는 것뿐입니다. 분산 표현을 사용하면 희소 표현과는 다르게 단어 간의 유사도 를 계산으로 구할 수 있다는 장점이 있습니다!

4) Embedding 레이어 : 는 바로 단어의 분산 표현을 구현하기 위한 레이어입니다. ex) ELMo, Word2Vec, Glove, FastText 등

Embedding 레이어

image

Also called a 룩업 테이블(Lookup Table)

원-핫 인코딩(one-hot encoding) is used to find useful pick useful features.

인간, 펭귄, 오리, 문어, 사람을 순서대로 원-핫 인코딩을 사용해서 표현하면 오리는 어떻게 표현되나요?

[ 0, 0, 1, 0, 0 ]

import tensorflow as tf

vocab = {      # 사용할 단어 사전 정의
    "i": 0,
    "need": 1,
    "some": 2,
    "more": 3,
    "coffee": 4,
    "cake": 5,
    "cat": 6,
    "dog": 7
}

sentence = "i i i i need some more coffee coffee coffee"
# 위 sentence
_input = [vocab[w] for w in sentence.split()]  # [0, 0, 0, 0, 1, 2, 3, 4, 4, 4]

vocab_size = len(vocab)   # 8

one_hot = tf.one_hot(_input, vocab_size)
print(one_hot.numpy())    # 원-핫 인코딩 벡터를 출력해 봅시다.
[[1. 0. 0. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0.]]

image 이제 생성된 원-핫 벡터를 Linear 레이어에 넣어보죠

distribution_size = 2   # 보기 좋게 2차원으로 분산 표현하도록 하죠!
linear = tf.keras.layers.Dense(units=distribution_size, use_bias=False)
one_hot_linear = linear(one_hot)

print("Linear Weight")
print(linear.weights[0].numpy())

print("\nOne-Hot Linear Result")
print(one_hot_linear.numpy())
Linear Weight
[[-0.731934    0.0395335 ]
 [ 0.3643812  -0.6953354 ]
 [ 0.44250846 -0.2122699 ]
 [ 0.22742927 -0.10298342]
 [-0.4708743  -0.63299686]
 [-0.02893186 -0.5212294 ]
 [-0.6116508  -0.226277  ]
 [ 0.72263455  0.39730847]]

One-Hot Linear Result
[[-0.731934    0.0395335 ]
 [-0.731934    0.0395335 ]
 [-0.731934    0.0395335 ]
 [-0.731934    0.0395335 ]
 [ 0.3643812  -0.6953354 ]
 [ 0.44250846 -0.2122699 ]
 [ 0.22742927 -0.10298342]
 [-0.4708743  -0.63299686]
 [-0.4708743  -0.63299686]
 [-0.4708743  -0.63299686]]
 단어를 - 인코딩해서 Linear 연산을 하는 것이 바로 파란 선의 정체였습니다
some_words = tf.constant([[3, 57, 35]])
# 3번 단어 / 57번 단어 / 35번 단어로 이루어진 한 문장입니다.

print("Embedding을 진행할 문장:", some_words.shape)
embedding_layer = tf.keras.layers.Embedding(input_dim=64, output_dim=100)
# 총 64개의 단어를 포함한 Embedding 레이어를 선언할 것이고,
# 각 단어는 100차원으로 분산표현 할 것입니다.

print("Embedding된 문장:", embedding_layer(some_words).shape)
print("Embedding Layer의 Weight 형태:", embedding_layer.weights[0].shape)
Embedding을 진행할 문장: (1, 3)
Embedding된 문장: (1, 3, 100)
Embedding Layer의 Weight 형태: (64, 100)

순차적인 데이터! Recurrent 레이어 (1) RNN

순차 데이터를 처리하기 위해 고안된 것이 바로 Recurrent Neural Network 또는 Recurrent 레이어(이하 RNN)

image

위 그림도 그것을 표현하여 첫 입력인 What의 정보가 마지막 입력인 ?에 다다라서는 거의 희석된 모습을 보여주고 있죠. 이것이 RNN의 고질적인 문제점인데, 입력의 앞부분이 뒤로 갈수록 옅어져 손실이 발생합니다. 이를 기울기 소실(Vanishing Gradient) 문제라고 합니다.

sentence = "What time is it ?"
dic = {
    "is": 0,
    "it": 1,
    "What": 2,
    "time": 3,
    "?": 4
}

print("RNN에 입력할 문장:", sentence)

sentence_tensor = tf.constant([[dic[word] for word in sentence.split()]])

print("Embedding을 위해 단어 매핑:", sentence_tensor.numpy())
print("입력 문장 데이터 형태:", sentence_tensor.shape)

embedding_layer = tf.keras.layers.Embedding(input_dim=len(dic), output_dim=100)
emb_out = embedding_layer(sentence_tensor)

print("\nEmbedding 결과:", emb_out.shape)
print("Embedding Layer의 Weight 형태:", embedding_layer.weights[0].shape)

rnn_seq_layer = \
tf.keras.layers.SimpleRNN(units=64, return_sequences=True, use_bias=False)
rnn_seq_out = rnn_seq_layer(emb_out)

print("\nRNN 결과 (모든 Step Output):", rnn_seq_out.shape)
print("RNN Layer의 Weight 형태:", rnn_seq_layer.weights[0].shape)

rnn_fin_layer = tf.keras.layers.SimpleRNN(units=64, use_bias=False)
rnn_fin_out = rnn_fin_layer(emb_out)

print("\nRNN 결과 (최종 Step Output):", rnn_fin_out.shape)
print("RNN Layer의 Weight 형태:", rnn_fin_layer.weights[0].shape)
RNN에 입력할 문장: What time is it ?
Embedding을 위해 단어 매핑: [[2 3 0 1 4]]
입력 문장 데이터 형태: (1, 5)

Embedding 결과: (1, 5, 100)
Embedding Layer의 Weight 형태: (5, 100)

RNN 결과 (모든 Step Output): (1, 5, 64)
RNN Layer의 Weight 형태: (100, 64)

RNN 결과 (최종 Step Output): (1, 64)
RNN Layer의 Weight 형태: (100, 64)

어떤 문장이 긍정인지 부정인지 나누기 위해서라면 문장을 모두 읽은 후, 최종 Step의 Output만 확인해도 판단이 가능합니다. 하지만 문장을 생성하는 경우라면 이전 단어를 입력으로 받아 생성된 모든 다음 단어, 즉 모든 Step에 대한 Output이 필요하죠. 그것은 위 코드에서 tf.keras.layers.SimpleRNN 레이어의 return_sequences 인자를 조절함으로써 조절할 수 있습니다!

lstm_seq_layer = tf.keras.layers.LSTM(units=64, return_sequences=True, use_bias=False)
lstm_seq_out = lstm_seq_layer(emb_out)

print("\nLSTM 결과 (모든 Step Output):", lstm_seq_out.shape)
print("LSTM Layer의 Weight 형태:", lstm_seq_layer.weights[0].shape)

lstm_fin_layer = tf.keras.layers.LSTM(units=64, use_bias=False)
lstm_fin_out = lstm_fin_layer(emb_out)

print("\nLSTM 결과 (최종 Step Output):", lstm_fin_out.shape)
print("LSTM Layer의 Weight 형태:", lstm_fin_layer.weights[0].shape)
WARNING:tensorflow:Layer lstm will not use cuDNN kernel since it doesn't meet the cuDNN kernel criteria. It will use generic GPU kernel as fallback when running on GPU

LSTM 결과 (모든 Step Output): (1, 5, 64)
LSTM Layer의 Weight 형태: (100, 256)
WARNING:tensorflow:Layer lstm_1 will not use cuDNN kernel since it doesn't meet the cuDNN kernel criteria. It will use generic GPU kernel as fallback when running on GPU

LSTM 결과 (최종 Step Output): (1, 64)
LSTM Layer의 Weight 형태: (100, 256)

처음 보는 LSTM이라는 레이어가 등장했습니다! Embedding 벡터의 차원수(unit)의 크기가 동일할 경우(위 예에서는 units=64), Weight의 크기가 위에서 사용했던 SimpleRNN의 4배나 되는 것을 볼 수 있는데, 왜 이런 RNN 레이어가 등장하게 된 것일까요?

순차적인 데이터! Recurrent 레이어 (2) LSTM

LSTM은 Long Short-Term Memory의 약어로 기울기 소실 문제를 해결하기 위해 고안된 RNN 레이어입니다

양방향(Bidirectional) RNN

import tensorflow as tf

sentence = "What time is it ?"
dic = {
    "is": 0,
    "it": 1,
    "What": 2,
    "time": 3,
    "?": 4
}

sentence_tensor = tf.constant([[dic[word] for word in sentence.split()]])

embedding_layer = tf.keras.layers.Embedding(input_dim=len(dic), output_dim=100)
emb_out = embedding_layer(sentence_tensor)

print("입력 문장 데이터 형태:", emb_out.shape)

bi_rnn = \
tf.keras.layers.Bidirectional(
    tf.keras.layers.SimpleRNN(units=64, use_bias=False, return_sequences=True)
)
bi_out = bi_rnn(emb_out)

print("Bidirectional RNN 결과 (최종 Step Output):", bi_out.shape)
입력 문장 데이터 형태: (1, 5, 100)
Bidirectional RNN 결과 (최종 Step Output): (1, 5, 128)

Leave a comment