본문 바로가기

딥러닝/밑바닥부터 시작하는 딥러닝 2

6장 : 게이트가 추가된 RNN

6.1 RNN의 문제점

6.1.1 RNN 복습

 

6.1.2 기울기 소실 또는 기울기 폭발

  • 기울기 소실 : 시간을 거슬러 올라갈수록 기울기가 작아짐
  • 기울기 폭발 : 시간을 거슬러 올라갈수록 기울기가 커짐 

 

6.1.3 기울기 소실과 기울기 폭발의 원인

역전파에서 차례로 tanh -> + -> MatMul 연산 통과

  • tanh

- 미분값 그래프 : 1.0이하, x가 0으로부터 멀어질수록 작아짐

=> 역전파에서 기울기가 tanh 노드를 지날 때마다 값이 계속 작아짐

 

  • MatMul

- 시계열 데이터의 시간 크기만큼 매번 똑같은 Wh가중치가 행렬 곱에 사용됨

N = 2  #미니배치 크기
H = 3  #은닉 상태 벡터의 차원 수
T = 20  #시계열 데이터의 길이

dh = np.ones((N, H))
np.random.seed(3)  #재현할 수 있도록 난수의 시드 고정
Wh = np.random.randn(H, H)

norm_list = []
for t in range(T):  #dh 갱신 
    dh = np.matmul(dh, Wh.T)
    norm = np.sqrt(np.sum(dh**2)) / N  #미니배치의 평균 L2노름 
    norm_list.append(norm)  #각 단계에서 dh크기(노름) 추가 

print(norm_list)

# 그래프 그리기
plt.plot(np.arange(len(norm_list)), norm_list)
plt.xticks([0, 4, 9, 14, 19], [1, 5, 10, 15, 20])
plt.xlabel('time step')
plt.ylabel('norm')
plt.show()

-> 기울기의 크기는 시간에 비례해 지수적으로 증가 => 기울기 폭발 (exploding gradients) 

+) 난수 고정 - seed() : https://antilibrary.org/2481

 

#Wh = np.random.randn(H, H) 변경 전
Wh = np.random.randn(H, H) * 0.5  #변경 후
  • Wh 초깃값 변경

-> 기울기 소실 (vanishing gradients)

=> 기울기가 일정 수준 이하로 작아지면 가중치 매개변수가 더 이상 갱신되지 않음, 장기 의존 관계 학습 불가능

 

  • 이유
    • Wh를 T번 반복해서 곱하기 때문
    • Wh가 행렬이라면 행렬의 특잇값이 척도가 되어 1보다 크면 증가, 작으면 감소
    • 특잇값 : 데이터가 얼마나 퍼져 있는지 나타냄
    • 특잇값 중 최댓값이 1보다 큰지 여부

 

6.1.4 기울기 폭발 대책 

  • 기울기 클리핑 (gradients clipping)

  • g^ : 모든 매개변수의 기울기를 하나로 모은 것
  • threshold : 문턱값
  • 기울기의 L2노름 (||g^||)이 문턱값을 초과하면 기울기 수정 
##기울기 클리핑
dW1 = np.random.rand(3,3)*10
dW2 = np.random.rand(3,3)*10
grads = [dW1, dW2]  #기울기의 리스트
max_norm = 5.0  #문턱값

def clip_grads(grads, max_norm):
    total_norm = 0
    for grad in grads:
        total_norm += np.sum(grad**2)
    total_norm = np.sqrt(total_norm)

    rate = max_norm /(total_norm +1e-6)
    if rate <1:
        for grad in grads:
            grad *= rate

6.2 기울기 소실과 LSTM

6.2.1 LSTM의 인터페이스 

-> 계산 그래프 단순화 

  • c 경로가 있다는  차이
  • c :기억 셀 (memory cell) , LSTM 전용의 기억 메너키즘
    • 데이터를 자기자신으로만 주고받음
    • LSTM 계층 내에서만 완결되고, 다른 계층으로는 출력하지 않음 
    • 반면 은닉 상태 h는 RNN계층과 마찬가지로 다른 계층 (위쪽)으로 출력됨

 

6.2.2 LSTM 계층 조립하기 

  • 기억 셀 ct : 시각 t에서의 LSTM의 기억이 저장, 과거로부터 시각 t까지에 필요한 모든 정보가 저장
  • ct를 바탕으로 은닉 상태 ht를 출력 
  • ht는 기억셀 ct를 tanh함수로 변환한 값
  • ht = tanh(ct)
  • ct의 각 요소에 tanh함수를 적용
  • ct와 ht의 원소 수는 같음
  • 게이트 : 데이터의 흐름 제어, 열기/닫기 뿐 아니라 어느 정도 열지도 조절 
  • 게이트의 열림 상태 - 0.0~1.0 사이 실수로 나타냄 -> 시그모이드 함수 이용
  • 게이트를 얼마나 열지도 데이터로부터 자동으로 학습함

 

6.2.3 output 게이트 

: tanh(ct), 즉 ht의 각 원소에 대해 그것이 다음 시각의 은닉 상태에 얼마나 중요한가를 조정

다음 은닉 상태 ht의 출력을 담당하는 게이트

  • 입력 xt와 이전상태 ht-1로부터 구함
  • 가중치 매개변수와 편향에 output의 첫 글자인 o를 첨자로 추가
  • 시그모이드 함수 σ
  • 출력 게이트의 출력 o

  • ht는 o와 tanh(ct)의 아다마르 곱으로 계산됨
  • 아다마르 곱 : 원소별 곱 Hadamard product
  • tanh의 출력 : -1.0~1.0의 실수 -> 인코딩된 정보의 강약을 표시
  • 게이트에서는 시그모이드 함수, 실질적인 정보를 지니는 데이터에는 tanh함수를 활성화 함수로 사용

 

6.2.4 forget 게이트

: 기억 셀에 무엇을 잊을지 명확하게 지시하는 게이트 

ct-1의 기억 중에 불필요한 기억을 잊게 해줌

  • forget 게이트 전용 가중치 매개변수 W(f)
  • forget게이트의 출력 f
  • Ct = f⊙Ct-1   

 

6.2.5 새로운 기억 셀

: 새로 기억해야 할 정보를 기억셀에 추가 -> tanh 노드 추가

 

  • tanh노드가 계산한 결과 g가 이전 시각의 기억 셀 Ct-1에 더해짐
  • 기억 셀에 새로운 정보가 추가된 것
  • tanh노드는 게이트가 아니며 새로운 정보를 기억 셀에 추가하는 것이 목적이기 때문에 활성화 함수로 tanh 사용

 

6.2.6 input 게이트

: g의 각 원소가 새로 추가되는 정보로써 가치가 얼마나 큰지 판단

새 정보를 모두 수용하는 것이 아니라, 적절히 취사선택하는 것이 역할

input 게이트에 의해 가중된 정보가 새로 추가되는 것

  • input게이트의 출력 i와 g의 원소별 곱 결과를 기억 셀에 추가

 

6.2.7 LSTM의 기울기 흐름

  • 기억 셀의 역전파는 +와 x노드를 지남
  • x노드는 행렬 곱이 아닌 원소별 곱(아마다르 곱)을 계산 
  • 똑같은 가중치 행렬을 사용하여 행렬 곱을 반복했던 RNN의 역전파와 달리 원소별 곱이 이뤄짐
  • 매 시각 다른 게이트 값을 이용해 원소별 곱을 계산하기 때문에 곱셈의 효과 누적 x
    -> 기울기 소실 일어나기 어려움 
  • x노드 계산은 forget 게이트가 제어
    • 잊어야한다고 판단한 기억 셀의 원소에 대해서는 기울기가 작아짐
    • 잊어서 안되는 기억 셀 원소에 대해서는 기울기가 약화되지 않은 채로 과거 방향으로 전해짐
  • LSTM : Long Short -Term Memory 

6.3 LSTM 구현

  • LSTM에서 수행하는 계산 수식들

  • 아핀 변환 (affine transformation) : 행렬 변환과 평행 이동(편향)을 결합한 형태 
    • xW +hW +b
    • 하나의 식으로 정리해 계산

  • 4개의 가중치와 편향을 하나로 모음
  • 4번을 수행하던 아핀 변환을 단 1회의 계산으로 -> 계산 속도 빨라짐
    (행렬 라이브러리는 큰 행렬을 한꺼번에 계산할 때가 각각을 따로 계산할 때보다 빠르기 때문)

  • 처음 4개분의 아핀 변환을 한꺼번에 수행
  • slice노드를 통해 4개의 결과 꺼냄
    • slice 노드 : 아핀 변환의 결과(행렬)을 균등하게 네조각으로 나눠서 꺼내주는 노드

  • RNN과 같이 Wx, Wh, b 세개의 매개변수만 관리하면 되지만 그 형상은 다름 (D*4H, H*4H)

  • np.hstach() 메서드 : 인수로 주어진 배열들을 가로로 연결 
    • vstach() : 세로로 연결 
  • dA = np.hstack((df, dg, di, do))
class LSTM:
    def __init__(self, Wx, Wh, b):
        self.params = [Wx, Wh, b]  #4개분의 가중치
        self.grads = [np.zeros_like(Wx), np.zeros_like(Wh), np.zeros_like(b)]
        self.cache = None  #순전파 결과 보관했다가 역전파 계산에 사용하려는 용도

    def forward(self, x, h_prev, c_prev):
        Wx, Wh, b = self.params
        N, H = h_prev.shape

        A = np.matmul(x, Wx) +np.matmul(h_prev, Wh) +b  #아핀변환

        #slice
        f = A[:, :H]
        g = A[:, H:2*H]
        i = A[:, 2*H:3*H]
        o = A[:, 3*H:]

        f = sigmoid(f)
        g = np.tanh(g)
        i = sigmoid(i)
        o = sigmoid(o)

        c_next = f*c_prev +g*i
        h_next = o*np.tanh(c_next)

        self.cache = (x, h_prev, c_prev, i, f, g, o, c_next)
        return h_next, c_next

    def backward(self, dh_next, dc_next):
        Wx, Wh, b = self.params
        x, h_prev, c_prev, i, f, g, o, c_next = self.cache

        tanh_c_next = np.tanh(c_next)

        ds = dc_next + (dh_next * o) * (1 - tanh_c_next ** 2)

        dc_prev = ds * f

        di = ds * g
        df = ds * c_prev
        do = dh_next * tanh_c_next
        dg = ds * i

        di *= i * (1 - i)
        df *= f * (1 - f)
        do *= o * (1 - o)
        dg *= (1 - g ** 2)

        dA = np.hstack((df, dg, di, do))

        dWh = np.dot(h_prev.T, dA)
        dWx = np.dot(x.T, dA)
        db = dA.sum(axis=0)

        self.grads[0][...] = dWx
        self.grads[1][...] = dWh
        self.grads[2][...] = db

        dx = np.dot(dA, Wx.T)
        dh_prev = np.dot(dA, Wh.T)

        return dx, dh_prev, dc_prev

 

6.3.1 Time LSTM 구현 

: T개분의 시계열 데이터를 한꺼번에 처리하는 계층

  • Truncated BPTT 수행 - 은닉 상태와 기억 셀 인스턴스 변수로 유지
    -> 다음번에 forward()가 불렸을 때 이전 시각의 은닉상태와 기억 셀에서부터 시작 가능

class TimeLSTM:
    def __init__(self, Wx, Wh, b, stateful=False):
        self.params = [Wx, Wh, b]
        self.grads = [np.zeros_like(Wx),np.zeros_like(Wh), np.zeros_like(b)]
        self.layer = None
        self.h, self.c = None, None
        self.dh = None
        self.stateful = stateful

    def forward(self,xs):
        Wx, Wh, b = self.params
        N, T, D = xs.shape
        H = Wh.shape[0]

        self.layers = []
        hs = np.empty((N,T,H), dtype='f')

        if not self.stateful or self.h is None:
            self.h = np.zeros((N, H), dtype='f')
        if not self.stateful or self.c is None:
            self.c = np.zeros((N, H), dtype = 'f')

        for t in range(T):
            layer = LSTM(*self.params)
            self.h, self.c = layer.forward(xs[:, t, :], self.h, self.c)
            hs[:,t, :] = self.h

            self.layers.append(layer)

        return hs

    def backward(self,dhs):
        Wx, Wh, b = self.params
        N, T, H = dhs.shape
        D = Wx.shape[0]

        dxs = np.empty((N, T, D), dtype='f')
        dh, dc = 0,0
        grads = [0,0,0]
        for t in reversed(range(T)):
            layer = self.layers[t]
            dx, dh, dc = layer.backward(dhs[:, t, :]+dh, dc)
            dxs[:, t, :] = dx
            for i , grad in enumerate(layer.grads):
                grads[i] = grad

        for i, grad in enumerate(grads):
            self.grads[i][...] = grad

        self.dh = dh
        return dxs

    def set_state(self, h, c = None):
        self.h, self.c = h, c

    def reset_state(self):
        self.h, self.c = None, None

-> TimeRNN과 흡사


6.4 LSTM을 사용한 언어 모델

  • 5장에서 구현한 언어모델에서 Time RNN-> Time LSTM으로 변경 
class Rnnlm:
    def __init__(self, vocab_size=10000, wordvec_size=100, hidden_size=100):
        V, D, H = vocab_size, wordvec_size, hidden_size
        rn = np.random.randn

        #가중치 초기화
        embed_W = (rn(V, D)/100).astype('f')
        lstm_Wx = (rn(D, 4*H)/ np.sqrt(D)).astype('f')  #H4개, Xavier초깃값 이용
        lstm_Wh = (rn(H, 4*H)/ np.sqrt(H)).astype('f')
        lstm_b = np.zeros(4*H).astype('f')
        affine_W = (rn(H, V)/ np.sqrt(H)).astype('f')
        affine_b = np.zeros(V).astype('f')

        #계층 생성
        self.layers = [
            TimeEmbedding(embed_W),
            TimeLSTM(lstm_Wx, lstm_Wh, lstm_b, stateful=True),
            TimeAffine(affine_W, affine_b)
        ]
        self.loss_layer = TimeSoftmaxWithLoss()
        self.lstm_layer = self.layers[1]

        #모든 가중치와 기울기를 리스트에 모은다.
        self.params, self.grads = [], []
        for layer in self.layers:
            self.params +=layer.params
            self.grads += layer.grads

    def predict(self, xs):  #문장생성에 사용하기 위해 추가한 메서드
        for layer in self.layers:
            xs = layer.forward(xs)
        return xs

    def forward (self, xs, ts):
        score = self.predict(xs)
        loss = self.loss_layer.forward(score, ts)
        return loss

    def backward (self, dout=1):
        dout = self.loss_layer.backward(dout)
        for layer in reversed(self.layers):
            dout = layer.backward(dout)
        return dout

    def reset_state(self):
        self.lstm_layer.reset_state()

    def save_params(self, file_name = 'Rnnlm.pkl'):  #매개변수 쓰기 처리 
        with open(file_name, 'wb') as f:
            pickle.dump(self.params, f)

    def load_params(self, file_name='Rnnlm.pkl'):  #매개변수 읽기 처리
        with open(file_name, 'rb') as f:
            self.params = pickle.load(f)
  • PTB 데이터셋 학습
from common.optimizer import SGD
from common.trainer import RnnlmTrainer
from common.util import eval_perplexity
from dataset import ptb

#하이퍼파라미터 설정
batch_size = 20
wordvec_size = 100
hidden_size = 100  #RNN의 은닉 상태 벡터의 원소 수 
time_size = 35  #RNN을 펼치는 크기
lr = 20.0
max_epoch = 4
max_grad = 0.25

#학습데이터 읽기
corpus, word_to_id, id_to_word = ptb.load_data('train')
corpus_test, _, _ = ptb.load_data('test')
vocab_size = len(word_to_id)
xs = corpus[:-1]  #입력
ts = corpus[1:]  #출력 (정답 레이블)

#모델 생성
model = Rnnlm(vocab_size, wordvec_size, hidden_size)
optimizer = SGD(lr)
trainer = RnnlmTrainer(model, optimizer)

#1. 기울기 클리핑을 적용하여 학습 
trainer.fit(xs, ts, max_epoch, batch_size, time_size, max_grad, eval_interval =20)
#max_grad : 기울기 클리핑 벅용, eval_interval : 20번째 반복마다 퍼플렉서티 평가
trainer.plot(ylim=(0,500))

#2. 테스트 데이터로 평가
model.reset_state()  #모델 상태를 재설정하여 평가 수행
ppl_test = eval_perplexity(model, corpus_test)
print('테스트 퍼플렉서티: ', ppl_test)

#3. 매개변수 저장  
model.save_params()  #학습이 완료된 매개변수들을 파일로 저장

  • 퍼플렉서티 값이 9998.63에서 100정도로 낮아짐 
    책 (10000.84 -> 100정도)
  • 최종 평가의 퍼플렉서티 값 :135.33750373270138
    책 (136.07)
  • 다음에 나올 단어의 후보를 136개 정도로 줄일 때까지 개선된 것
    -> 그렇게 좋은 결과는 아님, 다음 절에서 개선

6.5 RNNLM 추가 개선 

6.5.1 LSTM 계층 다층화

  • LSTM 계층을 깊게 쌓아 정확도 개선

-> 더 복잡한 패턴 학습

  • 몇 층 쌓을지는 하이퍼파라미터
  • 처리할 문제의 복잡도나 준비된 학습 데이터의 양에 따라 적절하게 결정
  • PTB 데이터셋 - 2~4층일 때 좋은 결과

 

6.5.2 드롭아웃에 의한 과적합 억제

  • RNN은 일반적인 피드포워드 신경망보다 쉽게 과적합
  • 과적합 : 훈련 데이터에만 너무 치중해 학습된 상태

-> 훈련 데이터 양 늘리기

-> 모델의 복잡도 줄이기 (정규화)

  • 정규화 방법 중 하나 : 드롭아웃 dropout - 훈련 시 계층 내의 뉴런 몇 개를 무작위로 무시하고 학습
  • 무작위로 뉴런을 선택하여 앞 계층으로부터의 신호 전달을 막음
  • 이러한 제약으로 신경망의 일반화 성능 개선
  • 시간 방향(좌우 방향)으로 드롭아웃을 넣으면 시간의 흐름에 따라 정보가 사라질 수 있음

-> 드롭아웃이 시간축과는 독립적으로 깊이 방향 (상하 방향)에만 영향

  • 최근 연구에서는 다양한 방법 제안되고 있음
    • 변형 드롭아웃 : 시간방향으로 드롭아웃 적용 
    • 언어 모델의 정확도 한층 더 향상
    • 같은 계층에 속한 드롭아웃들은 같은 마스크 mask 공유
    • 마스크 : 데이터의 통과/차단을 결정하는 이진 형태의 무작위 패턴
    • 같은 계층 마스크 고정 -> 정보 잃는 방법도 고정 -> 정보가 지수적으로 손실되는 사태 피할 수 있음

 

6.5.3 가중치 공유

 

 

 

 

 

  • Embedding계층의 가중치 : V x H
    (어휘수 *은닉상태의 차원 수)
  • Affine 계층의 가중치 : H x V 
  • Embedding 계층의 가중치를 전치하여 Affine 계층의 가중치로 설정
  • 매개변수 수 줄일 수 있음
    -> 학습하기 더 쉬워짐 
    -> 과적합 억제 

 

 

 

 

 

 

 

6.5.4 개선된 RNNLN 구현

 

 

 

 

 

 

 

 

세가지 개선점 

 

  • LSTM 계층의 다층화 (2층)
  • 드롭아웃 사용 (깊이 방향으로만 적용)
  • 가중치 공유(Embedding, Affine)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

from common.time_layers import *
from common.np import *
from common.base_model import BaseModel

class BetterRnnlm(BaseModel):
    def __init__(self, vocab_size=10000, wordvec_size=650, hidden_size=650, dropout_ratio = 0.5):
        V, D, H = vocab_size, wordvec_size, hidden_size
        rn = np.random.randn

        #가중치 초기화
        embed_W = (rn(V, D)/100).astype('f')
        lstm_Wx1 = (rn(D, 4*H)/ np.sqrt(D)).astype('f')
        lstm_Wh1 = (rn(H, 4*H)/ np.sqrt(H)).astype('f')
        lstm_b1 = np.zeros(4*H).astype('f')
        lstm_Wx2 = (rn(H, 4*H)/ np.sqrt(H)).astype('f') #lstm계층 2개
        lstm_Wh2 = (rn(H, 4*H)/ np.sqrt(H)).astype('f')
        lstm_b2 = np.zeros(4*H).astype('f')
        affine_b = np.zeros(V).astype('f')


        #계층 생성 #세 가지 개선
        self.layers = [
            TimeEmbedding(embed_W),
            TimeDropout(dropout_ratio),
            TimeLSTM(lstm_Wx1, lstm_Wh1, lstm_b1, stateful=True),
            TimeDropout(dropout_ratio),
            TimeLSTM(lstm_Wx2, lstm_Wh2, lstm_b2, stateful=True),
            TimeDropout(dropout_ratio),
            TimeAffine(embed_W.T, affine_b)  #가중치 공유
        ]
        self.loss_layer = TimeSoftmaxWithLoss()
        self.lstm_layers = [self.layers[2], self.layers[4]]
        self.drop_layers = [self.layers[1], self.layers[3], self.layers[5]]

        #모든 가중치와 기울기를 리스트에 모은다.
        self.params, self.grads = [], []
        for layer in self.layers:
            self.params +=layer.params
            self.grads += layer.grads

    def predict(self, xs, train_flg=False):  #문장생성에 사용하기 위해 추가한 메서드
        for layer in self.drop_layers:
            layer.train_flg = train_flg
        for layer in self.layers:
            xs = layer.forward(xs)
        return xs

    def forward (self, xs, ts, train_flg=True):
        score = self.predict(xs, train_flg)
        loss = self.loss_layer.forward(score, ts)
        return loss

    def backward (self, dout=1):
        dout = self.loss_layer.backward(dout)
        for layer in reversed(self.layers):
            dout = layer.backward(dout)
        return dout

    def reset_state(self):
        for layer in self.lstm_layers:
            layer.reset_state()
  • 개선된 모델로 학습 진행
from common.optimizer import SGD
from common.trainer import RnnlmTrainer
from common.util import eval_perplexity
from dataset import ptb

#하이퍼파라미터 설정
batch_size = 20
wordvec_size = 650
hidden_size = 650  #RNN의 은닉 상태 벡터의 원소 수 
time_size = 35  #RNN을 펼치는 크기
lr = 20.0
max_epoch = 4
max_grad = 0.25
dropout = 0.5

#학습데이터 읽기
corpus, word_to_id, id_to_word = ptb.load_data('train')
corpus_val, _, _ = ptb.load_data('val')
corpus_test, _, _ = ptb.load_data('test')
vocab_size = len(word_to_id)
xs = corpus[:-1]  #입력
ts = corpus[1:]  #출력 (정답 레이블)

#모델 생성
model = BetterRnnlm(vocab_size, wordvec_size, hidden_size, dropout)
optimizer = SGD(lr)
trainer = RnnlmTrainer(model, optimizer)

best_ppl = float('inf')
for epoch in range(max_epoch):
    trainer.fit(xs, ts, max_epoch=1, batch_size=batch_size, time_size=time_size, max_grad=max_grad) 
    model.reset_state()  #모델 상태를 재설정하여 평가 수행
    ppl = eval_perplexity(model, corpus_val)
    print('검증 퍼플렉서티: ', ppl)  #매 에폭마다 검증 데이터로 퍼플렉서티 평가 

    if best_ppl > ppl:   
        best_ppl = ppl
        model.save_params()
    else:  #기존퍼플렉서티보다 나빠졌을 경우에만 학습률 낮춤
        lr /=4.0  #학습률 1/4로 줄임
        optimizer.lr = lr

    model.reset_state()
    print('-'*50)

# 테스트 데이터로 평가
model.reset_state()
ppl_test = eval_perplexity(model, corpus_test)
print('테스트 퍼플렉서티: ', ppl_test)
  • 책) 최종 퍼플렉서티 75.76 -epoch 40번
  • 개선전 136에 비하면 상당히 개선 

내 결과) 109.48257447859318 - epoch 4번만 진행

135.33 -> 109.48 (개선 후)

 

6.5.5 첨단 연구로

  • PTB 데이터셋에 대한 각 모델의 퍼플렉서티 결과
    • 최저 52.8
    • 구현한 모델과 공통점 많음
      • 다층 LSTM
      • 드롭아웃 기반의 정규화
      • 가중치 공유
      • 한층 더 세련된 최적화나 정규화 기법 적용
      • 하이퍼파라미터 튜닝 정밀하게

6.6 정리

  • 단순한 RNN의 학습에서는 기울기 소실과 기울기 폭발이 문제가 된다.
  • 기울기 폭발에는 기울기 클리핑, 기울기 소실에는 게이트가 추가된 RNN이 효과적이다.
  • LSTM에는 input게이트, forget게이트, output게이트 등 3개의 게이트가 있다.
  • 게이트에는 전용 가중치가 있으며, 시그모이드 함수를 사용하여 0.0~1.0 사이의 실수를 출력한다.
  • 언어 모델 개선에는 LSTM계층 다층화, 드롭아웃, 가중치 공유 등의 기법이 효과적이다.
  • RNN의 정규화는 중요한 주제이며, 드롭아웃 기반의 다양한 기법이 제안되고 있다. 

책 참고 : 밑바닥부터 시작하는 딥러닝 (한빛미디어)

 

 

 

 

 

 

 

 

'딥러닝 > 밑바닥부터 시작하는 딥러닝 2' 카테고리의 다른 글

8장 : 어텐션  (1) 2023.09.28
7장 : RNN을 사용한 문장 생성  (2) 2023.09.27
5장 : 순환 신경망(RNN)  (0) 2023.09.26
4장 : word2vec 속도 개선  (0) 2023.09.23
3장 : word2vec  (0) 2023.09.21