1. 임베딩
■ 컴퓨터는 사람이 사용하는 자연어(한글, 영어 등)를 그대로 이해하지 못한다. 그러므로 컴퓨터가 이해할 수 있는 벡터로 변경해야 한다. 이런 변경을 임베딩이라고 말한다. 그러므로 임베딩이 잘 될수록 높은 모델 성능을 기대할 수 있다.
■ 임베딩과 관련된 다양한 방법들이 있는데, 크게는 '단어 수준'의 임베딩(Word2Vec, FastText)과 '문장 수준'의 임베딩(Elmo, Bert, GPT 등)으로 구분한다.
- 단어 수준의 임베딩은 동음이의어(글자의 소리는 같지만 뜻이 다른 단어 - 눈, 차, 배 등)를 구별할 수 없지만,
- 문장 수준의 임베딩은 사람처럼 문장의 '앞뒤'를 보고 의미를 파악할 수 있다.
■ 단어 수준의 임베딩을 위해 단어, 음절, 형태소 등으로 나누고 이를 수치로 변환한다. 이때 가장 간단한게 토큰을 벡터로 변환할 수 있는 방법은 원-핫(one-hot) 인코딩이다.
■ 다만, 원-핫 인코딩은 [1 0 0 0 0 0 0], [0 1 0 0 0 0 0], ... 처럼 단어가 많아질수록 벡터의 공간(차원)이 커지므로 비효율적이다. 이런 원-핫 인코딩 변환 방법은 행렬의 원소(성분)이 대부분 '0'인 희소행렬(sparse matrix)라고도 부른다.
■ 원-핫 인코딩은 위의 예시처럼 '0'이라는 불필요한 공간이 발생하므로 메모리 낭비가 심하다. 또한, 1 또는 0으로 구성되기 때문에 단어와 단어의 유사도를 계산하기 어렵다는 단점이 있다.
■ 이런 문제로 원-핫 인코딩 대신, 단어를 밀집(dense) 벡터/행렬로 표현한다. 밀집 벡터/행렬의 성분은 0이 아닌 실숫값으로 채워지기 때문에 메모리 낭비가 훨씬 작아지고, 단어와 단어의 유사도를 파악하기 쉽다.
■ 텐서플로 tensorflow.keras.layers에서 제공하는 임베딩 레이어는 밀집 행렬로 구성되어 있다. 이때 두 가지 파라미터 값 설정이 필요하다.
- (1) 첫 번째는 입력 차원(단어의 총 개수)
- (2) 두 번째는 임베딩 차원이다.
- 다음과 같이 \( n \)개의 입력 차원을 3차원 임베딩 공간으로 매핑시키기 위해서이다.
- 위의 예시는 9개의 단어로 구성된 문장을 4개의 원소를 갖는 임베딩 벡터로 변환하는 예시이다.
■ 임베딩 레이어의 input_dim에는 단어의 크기, output_dim에는 출력 벡터의 크기(차원)를 지정한다.
https://www.tensorflow.org/api_docs/python/tf/keras/layers/Embedding
tf.keras.layers.Embedding | TensorFlow v2.16.1
Turns positive integers (indexes) into dense vectors of fixed size.
www.tensorflow.org
- 여기서 input_dim은 단어의 크기. 즉, 사용할 단어의 개수로 maximum integer + 1이다. 예를 들어 다음과 같이 설정할 수 있다.
■ 그리고 사용할 모델에 따라 입력 (시퀀스) 길이(input_length)를 설정해야 할 수도 있고 그렇지 않을 수도 있다.
- 별도의 시드 고정이 없다면 임베딩 레이어의 초기 가중치는 매번 랜덤하게 초기화된다.
■ 예를 들어 다음은 임의의 4개의 숫자를 Embedding Layer에 통과시키면 입력 4개(숫자 4개)가 각각 원소(차원) 3개를 갖는 밀집 행렬로 변환되는 것을 볼 수 있다.
import tensorflow as tf
from tensorflow.keras.layers import Embedding
embedding_layer = Embedding(input_dim = 100, output_dim = 3)
result = embedding_layer(tf.constant([10, 3, 4, 5]))
print(result)
```#결과#```
tf.Tensor(
[[-0.03326149 -0.0138962 0.00638118]
[ 0.00692762 0.02173448 0.00766476]
[ 0.02313616 -0.01571113 0.02268859]
[ 0.04769924 -0.00988016 -0.01320392]], shape=(4, 3), dtype=float32)
````````````
2. 순환신경망(RNN)
■ RNN은 시퀀스 데이터(자연어, 음성 데이터처럼 순서가 있는 데이터)를 순차적으로 처리하는 신경망을 의미한다.
- RNN보다 개선된 LSTM도 같은 맥락이기 때문에 LSTM을 RNN으로, 기본 RNN을 Elman RNN으로 부르기도 한다.
https://hyeon-jae.tistory.com/141
순환 신경망(RNN) (1)
1. 피드포워드(feed forward) 신경망의 문제점■ 지금까지 살펴본 신경망은 신경망의 기본적인 형태인 피드포워드 신경망이다.- 피드포워드 신경망은 다충 퍼셉트론이라고도 불리며, 은닉칭이 하나
hyeon-jae.tistory.com
https://hyeon-jae.tistory.com/145
게이트(gate)가 추가된 RNN - LSTM, GRU
1. RNN의 문제점■ RNN은 순환 경로를 통해 과거 정보를 계승할 수 있어 시퀀스 데이터(순서가 있는 데이터)인 시계열 데이터를 다루기에 적합하다. ■ 하지만, 길이가 긴 시계열 데이터를 사용할
hyeon-jae.tistory.com
■ 순환신경망은 이전의 (은닉)상태가 현 시점에 영향을 주고, 이를 순차적으로 반영해 결과를 계산한다. 즉, 과거의 결과가 현재에 영향을 미친다. 이는 완전연결 신경망(FCN) 및 합성곱 신경망(CNN)과의 큰 차이점이다.
■ 순환신경망 유형은 크게 다음과 같은 5가지 유형으로 구분할 수 있다.
- (1) One to One은 가장 기본적인 순환신경망 Simple RNN의 형태이다.
- (2) One to Many는 이미지 캡션(입력으로 이미지를 넣으면 출력으로 문장이 나오는)에 활용된다.
- (3) Many to One은 문장을 입력으로 넣고 긍정 또는 부정을 출력하는 감성 분류에 활용된다.
- (4) Many to Many는 챗봇, 기계 번역, 품사 예측 등 다양하게 활용되고 있다.
■ 이렇게 순환신경망의 입력과 출력의 길이를 다르게 설계하여 다양한 용도로 사용할 수 있다.
3. 순환신경망 알고리즘
2.1 SimpleRNN, LSTM, GRU
■ SimpleRNN, LSTM, GRU 레이어는 tensorflow.keras.layers에서 불러올 수 있으며, Sequential이나 함수형 API, 모델 서브클래싱을 이용해 모델을 설계할 수 있다.
from tensorflow.keras.layers import Embedding, SimpleRNN, LSTM, GRU, Dense
from tensorflow.keras.models import Sequential
model = tf.keras.Sequential()
model.add(Embedding(100, 3, input_length = 14))
model.add(SimpleRNN(units = 16, return_sequences = True)) # activation 기본값은 'tanh'
# model.add(LSTM(units = 16, return_sequences = True)) # activation 기본값은 'tanh' # recurrent_activation 기본값은 'sigmoid'
model.add(Dense(1))
model.summary()
```#결과#```
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_3 (Embedding) (None, 14, 3) 300
simple_rnn (SimpleRNN) (None, 14, 16) 320
dense (Dense) (None, 14, 1) 17
=================================================================
Total params: 637
Trainable params: 637
Non-trainable params: 0
_________________________________________________________________
````````````
■ 여기서 RNN Layer(이 예에서는 simple_rnn) Embedding Layer로부터 (None, 14, 3)크기를 입력으로 받는데, 이는 '(batch_size(배치 크기), input_length(입력 길이), 출력 벡터(밀집 벡터)의 차원)'이다.
3. 순환신경망 활용
3.1 양방향(Bidirectional) RNN
■ 자연어 데이터는 양방향. 즉, 순서대로 데이터를 처리하고 역순으로 처리할 경우 더 좋은 성능을 발휘한다.
■ 다음 단어를 예측할 때, 앞에 있는 단어의 정보뿐만 아니라 뒤에 있는 단어의 정보도 사용할 수 있기 때문이다.
https://hyeon-jae.tistory.com/156
어텐션(Attention) (2)
1. 양방향 순환 신경망 (Bidirectional RNN)■ 예를 들어 'He always drinks black coffee'라는 문장이 있을 때, 기본적인 RNN/LSTM은 시간축이 왼쪽에서 오른쪽으로, 즉 사람이 보통 글을 왼쪽에서 오른쪽으로 읽
hyeon-jae.tistory.com
■ tensorflow.keras.layers에서 양방향 레이어 Bidirectional를 제공하고 있다. RNN 레이어를 감싸면 양방향 RNN이 된다.
from tensorflow.keras.layers import Bidirectional
model = Sequential()
model.add(Embedding(100, 3, input_length = 14))
model.add(Bidirectional(LSTM(units = 16, return_sequences = True)))
model.add(Dense(1))
model.summary()
```#결과#```
Model: "sequential_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_7 (Embedding) (None, 14, 3) 300
bidirectional (Bidirectiona (None, 14, 32) 2560
l)
dense_9 (Dense) (None, 14, 1) 33
=================================================================
Total params: 2,893
Trainable params: 2,893
Non-trainable params: 0
_________________________________________________________________
````````````
■ LSTM(units = 16)으로, LSTM의 유닛(뉴런) 개수를 16개로 지정했지만, summary( )를 보면 유닛의 개수가 2배인 32개인 것을 확인할 수 있다.
■ 이는, LSTM 모델이 순방향과 역방향으로 각각 만들어졌기 때문이다.
- 이렇게 양방향으로 LSTM을 사용하는 것을 Bidirectional LSTM, 줄여서 Bi-LSTM이라고 부른다.
■ 단, 양방향 RNN은 최신 정보가 과거 정보보다 훨씬 더 중요한 task에는 적합하지 않다. 또한 위의 예시에서 유닛 개수가 2배가 된다. 즉, 해당 부분의 네트워크 용량이 2배가 된다는 의미이다.
■ 하지만 앞서 언급한 것처럼 텍스트 데이터 또는 순서가 중요한 종류의 데이터에는 적합하다.
3.2 스태킹(Stacking) RNN
■ 시간 축 방향이 아닌 깊이 방향으로 RNN 레이어 또는 양방향 RNN 레이어를 여러 층 쌓은 것을 스태킹 RNN이라고 한다.
https://hyeon-jae.tistory.com/156
어텐션(Attention) (2)
1. 양방향 순환 신경망 (Bidirectional RNN)■ 예를 들어 'He always drinks black coffee'라는 문장이 있을 때, 기본적인 RNN/LSTM은 시간축이 왼쪽에서 오른쪽으로, 즉 사람이 보통 글을 왼쪽에서 오른쪽으로 읽
hyeon-jae.tistory.com
■ 다른 RNN 유형과 다른 점은 다음과 같이 RNN 또는 양방향 RNN 레이어를 쌓기 때문에 각 시점별 은닉 상태 값을 모두 출력해야 한다. 이를 가능하게 하는 파라미터가 return_sequences이다.
■ return_sequences의 기본값은 False로, 이는 마지막 은닉 상태 값만 출력한다는 의미이다. 하지만, RNN 레이어를 여러 층 쌓을 경우 각 시점별로 연결되야 하기 때문에 True로 설정해야 한다.
- return_sequences = False일 경우 다음 그림과 같이 마지막 은닉 상태만 다음 RNN 층으로 전달되기 때문에 RNN 레이어를 쌓을 수 없다. (에러가 발생한다)
- return_sequences = True로 설정해야 모든 시점의 은닉 상태 값을 다음 RNN 층으로 전달할 수 있다.
- 만약, 최상단에 있는 RNN 레이어가 마지막 계층이라면 더 이상 모든 상태를 전달할 필요가 없으므로 return_sequences를 True로 지정할 필요가 없다.
model = Sequential()
model.add(Embedding(100, 3, input_length = 14))
model.add(LSTM(units = 32, return_sequences = True)) # 모든 시점의(전체 시퀀스의) 은닉 상태를 출력
model.add(LSTM(units = 32, return_sequences = False)) # 마지막 시점의 은닉 상태만 출력
model.add(Dense(1))
model.summary()
```#결과#```
Model: "sequential_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_8 (Embedding) (None, 14, 3) 300
lstm_1 (LSTM) (None, 14, 32) 4608
lstm_2 (LSTM) (None, 32) 8320
dense_10 (Dense) (None, 1) 33
=================================================================
Total params: 13,261
Trainable params: 13,261
Non-trainable params: 0
_________________________________________________________________
````````````
- 위의 모델 구조를 보면 최상단 RNN 레이어의 return_sequences 는 False이며 출력값은 FC 레이어에 전달되는 것을 볼 수 있다. 이 모델 구조를 도식화하면 다음과 같다.
3.3 순환 드롭아웃
■ 일반적인 '드롭아웃(dropout)'이 아닌 '순환 드롭아웃(recurrent dropout)'을 구분해야 한다.
■ 일반적인 '드롭아웃'은 훈련 데이터를 층에 주입할 때 데이터에 있는 우연한 상관관계를 깨기 위해 입력 층의 유닛을 랜덤하게 비활성화 시키는 기법이다.
■ 하지만, 순환 신경망에 일반적인 드롭아웃 기법을 적용하는 것은 쉽지 않다. 시퀀스 데이터를 사용하기 때문이다.
■ 시퀀스 데이터를 사용하는 순환 신경망에 일반적인 드롭아웃 기법을 적용하면, 오히려 학습을 방해하는 요인으로 작용될 수 있다.
■ 위의 그림처럼 각 시점별 정보가 전달되야 하는데, 학습 과정에서 랜덤으로 연결을 비활성화하면 모든 시점의 정보가 제대로 전달될 수 없다.
■ 이 문제를 해결하기 위해 제안된 것이 바로 '순환 드롭아웃'이다.
■ 순환 드롭아웃은 타임스텝마다 랜덤하게 드롭아웃 마스크를 바꾸는 것이 아니라, 동일한 드롭아웃 마스크를 모든 타임스텝에 적용하는 방법이다. 즉, 랜덤이 아닌 동일한 패턴으로 유닛을 드롭아웃한다.
■ LSTM이나 GRU 같은 순환 게이트에 의해 만들어지는 표현을 규제하려면 순환 층(LSTM이나 GRU 레이어) 내부 계산에 사용되는 활성화 함수에 타임스텝마다 동일한 드롭아웃 마스크를 적용해야 한다.
■ 이렇게 하면 학습 오차를 타임스텝에 걸쳐 적절하게 전파할 수 있다.
■ 텐서플로 케라스에 있는 모든 순환 레이어는 2개의 드롭아웃 매개변수를 가지고 있다. 예를 들어 tf.keras.layers.LSTM은 dropout과 recurrent_dropout 매개변수가 있으며 기본값은 모두 0.0으로 설정되어 있다.
- dropout은 층의 입력에 대한 드롭아웃 비율, recurrent_dropout은 순환 상태의 드롭아웃 비율을 의미한다.
- 두 드롭아웃 매개변수 모두 0과 1사이의 부동 소수점 값을 가진다.
model = Sequential()
model.add(Embedding(100, 3, input_length = 14))
model.add(LSTM(units=32, dropout=0.0, recurrent_dropout=0.0))
model.add(Dense(1))
model.summary()
```#결과#```
Model: "sequential_9"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_13 (Embedding) (None, 14, 3) 300
lstm_7 (LSTM) (None, 32) 4608
dense_15 (Dense) (None, 1) 33
=================================================================
Total params: 4,941
Trainable params: 4,941
Non-trainable params: 0
_________________________________________________________________
````````````
'텐서플로' 카테고리의 다른 글
텐서플로 합성곱 신경망(CNN) (2) (0) | 2024.11.22 |
---|---|
텐서플로 합성곱 신경망(CNN) (1) (0) | 2024.11.15 |
케라스(Keras) (2) (2) | 2024.08.20 |
케라스(Keras) (1) (0) | 2024.08.18 |
텐서(Tensor) (1) (0) | 2024.08.10 |