[D&A 운영진 딥러닝 스터디] 4주차 2차시

권유진·2022년 1월 27일
0

D&A 운영진 스터디

목록 보기
8/17

문자 데이터를 사용한 모델링에서 고려해야 할 요소

  1. 연속된 데이터의 정보 처리
  2. 단어가 나올 확률은 이전 단어나 주변 단어에 따라 결정(연속적 관계)
  3. 언어적 약속 ex) 먹고 싶습니다 요소 앞에는 먹을 것이 오며 단어에 받침이 있을 경우에는 가 조사로 붙어야 함.

NLP 모델은 언어적 약속을 모델링해야 했고 이를 통계적으로 접근

  • Probability Language Model: 문장이 나타날 수 있는 확률을 각 단어가 동시에 나타나는 확률로 표현
  • n-gram Language Model: 문장의 부분에 대한 조건부 확률로 근사시켜 표현
    • Skip-gram도 이와 같은 지역성 조건부 확률을 활용
      P(나는,회가,먹고,싶습니다)=P(나는<SOS>)P(회가나는)P(먹고나는,회가)P(싶습니다나는,회가,먹고)P(<EOS>나는,회가,먹고,싶습니다)P(나는, 회가, 먹고, 싶습니다) \\= P(나는|<SOS>)P(회가|나는)P(먹고|나는, 회가)\\P(싶습니다|나는, 회가, 먹고)P(<EOS>|나는, 회가, 먹고, 싶습니다)

연속성의 정보를 담을 수 있는 딥러닝 모델

  • 일반적인 딥러닝 모델: One-To-One 문제(input과 output 모두 1개)
  • 문장, 문자 데이터는 여러 개의 연관성 깊은 Token(다수의 벡터)을 활용
    • Many-To-One: ex) 댓글의 악플 가능성 정도를 측정하는 sentence classification
    • One-To-Many: ex) 사진 속 내용을 설명하는 글을 만들어내는 Image Captioning
    • Many-To-Many(token-by-token): ex) 문장의 모든 token에 대한 품사를 예측하는 Pos Tagging
    • Many-To-Many(Encoder-Decoder): ex) 입력 문장에 대한 번역문을 만들어 주는 Translation

RNN(Recurrent Neural Network)

  • Sequential Data를 다루는 가장 대표적인 모델

  • 단어를 순서대로 하나의 Hidden Layer에 입력해 반복 업데이트

    • 데이터의 순서에 대한 정보 담을 수 있음
  • 파라미터: WihW_{ih}, WhhW_{hh}, WhoW_{ho}

    ht=tanh(ht1Whh+xtWih+bhh)h_t = \tanh (h_{t-1}W_{hh} + x_tW_{ih} + b_{hh})
  • Hidden Layer은 이전 Token들의 정보가 자동으로 축적

  • Loss는 Token별로 나오는 Loss를 더한 총합

  • Gradient Vanishing/Exploding 문제 발생(장기 기억력 떨어짐) \because Activation Function

    • Truncated Back Propagation: Token의 과거 지정 개수의 Token까지만 부분적으로 업데이트
    • Gradient Clipping: 너무 큰 Gradient는 조정
    • 적절한 초기값 설정
    • 활성화함수 ReLU 사용
rnn = nn.RNN(input_size, hidden_size)
outputs, _status = rnn(input_data)
  
# input_shape = (batch_size, sequence_length, input_size)
# output_shape = (batch_size, sequence_length, hidden_size)
## input_size: 단어 벡터의 차원
## sequence_length: 문장의 길이
## hidden_size: output(hidden state)의 차원

LSTM(Long Short-Term Memory)

  • RNN의 단기기억만 가능하다는 단점 개선
    • Cell(ctc_t)를 이용해 Gradient가 곱해지는 값의 차이가 심각하지 않게 만듦
      • ctct1\cfrac{\partial c_t}{\partial c_{t-1}}ftf_t를 포함
      • Forget Gate(ftf_t)의 값이 1에 가까울수록 Gradient 값이 작아지는 상황 줄여줌
  • Cell State(ctc_t)와 다수의 Gate(iti_t,ftf_t,c~t\tilde c_t,oto_t)를 통한 필터링 존재
  • 특정 시점에 대한 데이터 xtx_t와 그 이전 시점까지의 정보 ht1h_{t-1}로 각각의 Gate와 현재 시점의 Cell 정보 ctc_t를 만들고 여기에 한 번의 처리를 거쳐 최종 형태의 정보 hth_t를 만들어 냄
ft=σ(Wfxt+Ufht1+bf)it=σ(Wixt+Uiht1+bi)ot=σ(Woxt+Uoht1+bo)c~t=tanh(Wcxt+Ucht1+bc)ct=ftct1+itc~ht=ottanh(ct)f_t = \sigma(W_fx_t + U_fh_{t-1}+ b_f)\\ i_t = \sigma(W_ix_t + U_ih_{t-1}+ b_i)\\ o_t = \sigma(W_ox_t + U_oh_{t-1}+ b_o)\\ \tilde c_t = \tanh(W_cx_t + U_ch_{t-1}+ b_c)\\ c_t = f_t \odot c_{t-1} + i_t \odot \tilde c\\ h_t = o_t \odot \tanh(c_t)
  • Forget Gate(ftf_t): 이전 정보까지의 정보를 담고있는 Cell(ct1c_{t-1})를 얼마나 잊을 것인지 결정
  • Input Gate(iti_t): 현재 Token에 대한 정보(c~\tilde c)를 얼마나 가져올 것인지 결정
  • Cell(ctc_t): 과거의 정보 중 불필요한 부분 지우고 현재 정보를 적당히 합산
  • Output Gate(oto_t): Output Gate를 통해 Cell 정보를 수정을 거쳐 최종적인 h_t 구함

참고
https://medium.datadriveninvestor.com/how-do-lstm-networks-solve-the-problem-of-vanishing-gradients-a6784971a577

Bi-RNN(Bidirectional Recurrent Neural Network)

  • 양방향 정보 모두 이용(왼쪽\rightarrow오른쪽, 왼쪽\leftarrow오른쪽)
  • 양방향의 Hidden Layer를 Concatenate해 사용

GRU(Gated Recurrent Units)

  • LSTM의 Output부분을 제거한 간소화 버전으로 알려진 모델
  • 최종 Hidden Layer를 과거의 누적 정보(ht1h_{t-1})와 현재 정보(h^t\hat h_t)의 Weight Average를 이용해 표현
    zt=σ(Wzxt+Uzht1+bz)rt=σ(Wrxt+Urht1+br)h^t=tanh(Whxt+Ut(rtht1)+bh)ht=(1zt)ht1+zth^tz_t = \sigma(W_zx_t+U_zh_{t-1}+b_z)\\ r_t = \sigma(W_rx_t+U_rh_{t-1}+b_r)\\ \hat h_t = \tanh(W_hx_t + U_t(r_t \odot h_{t-1})+b_h)\\ h_t = (1-z_t) \odot h_{t-1} + z_t \odot \hat h_t

Attention Mechanism

  • RNN Encoder-Decoder 구조의 모델 사용
    • 번역하고자 하는 문장 Source Sentence의 정보를 저장하는 RNN Encoder
    • 위에서 저장된 정보를 바탕으로 번역된 문장을 생성하는 RNN Decoder
  • Decoder에서 원 문장의 어떤 단어에 집중해 단어를 만들어 낼 것인지에 대한 정보(Attention Score) 활용
  • 다른 언어이지만 같은 뜻을 나타내는 Pair에 대한 정보 얻을 수 있음(Attention Score 참조)

Convolution Neural Network for Text Classification

  • 이미지 데이터에 많이 사용되는 CNN을 NLP에 적용
  • RNN의 구조적 한계로 할 수 없었던 병렬 처리를 CNN을 통해 해결
  • Convolution Filter의 사용은 n-gram Feature와 비슷함
  • 구조 특성상 문장 생성이 필요한 task에는 적용이 어려움
  • 텍스트를 이미지처럼 만들어 분류하는 모델 제안

실습코드(charseq문제)

# 다음 character을 예측하는 모델 구축
# charseq 문제
sample = ' if you want you'

# make dictionary
char_set = list(set(sample))
char_dic = {c:i for i,c in enumerate(char_set)}

# hyperparameters
input_size = len(char_set)
dic_size = len(char_dic)
hidden_size = len(char_dic)
learning_rate = 0.1

# data setting
sample_idx = [char_dic[c] for c in sample] # index 가져옴
x_data = [sample_idx[:-1]] # 마지막 character 제외 후 가져옴
x_one_hot = [np.eye(dic_size)[x] for x in x_data] # np.eye는 Identity matrix임-여기서 원하는 vector 가져옴
y_data = [sample_idx[1:]]

# transform as torch tensor variable
X = torch.FloatTensor(x_one_hot)
Y = torch.LongTensor(y_data)

# declare RNN
rnn = torch.nn.RNN(input_size, hidden_size, batch_first=True)

# loss&optimizer setting
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(rnn.parameters(), learning_rate)

# start training
for i in range(100):
    optimizer.zero_grad()
    outputs, _status = rnn(X)
    loss = criterion(outputs.view(-1, input_size), Y.view(-1))
    loss.backward()
    optimizer.step()
  
    result = outputs.data.numpy().argmax(axis=2)
    result_str = ''.join([char_set[c] for c in np.squeeze(result)])
    print(F'{i}, loss: {loss.item()}, prediction: {result}, true Y: {y_data}, prediction str: {result_str}')

실습코드(longseq문제)

  • fixed size로 긴 문장을 자름
  • 'if you want to build a ship, don't drum up people together to '
    • 'if you wan' \rightarrow 'f you want'
    • 'f you want' \rightarrow ' you want '
    • ' you want ' \rightarrow 'you wnat t'
# 문장 자르기
sentence = "if you wnat to build a ship, don't drum up people together to collect wood and don't assign them tasks and work, but rather teach them to long for the endless immensity of the area"
char_set = list(set(sentence))
char_dic = {c:i for i,c in enumerate(char_set)}

sequence_length = 10
input_size = len(char_set)
dic_size = len(char_dic)
hidden_size = len(char_dic)
learning_rate = 0.1

x_data = []
y_data = []
for i in range(0, len(sentence)-sequence_length):
    x_str = sentence[i:i+sequence_length]
    y_str = sentence[i+1:i+sequence_length+1]
    print(i, x_str, '->',y_str)
    x_data.append([char_dic[c] for c in x_str]) # x str to index
    y_data.append([char_dic[c] for c in y_str]) # y str to index
    
x_one_hot = [np.eye(dic_size)[x] for x in x_data] # one_hot vector로 만듦
  
X = torch.FloatTensor(x_one_hot)
Y = torch.LongTensor(y_data)
  
# declare model
class Net(nn.Module): # nn.Module을 상속한 다음 Net이라는 Class로 정의
    def __init__(self, input_dim, hidden_dim, layers): # 모듈의 내부적 하위 모듈 정의
        super(Net, self).__init__()
        self.rnn = nn.RNN(input_dim, hidden_dim, num_layers=layers, batch_first=True)
        self.fc = torch.nn.Linear(hidden_dim, hidden_dim, bias=True)
    def forward(self, x):
        x, _stats = self.rnn(x)
        x = self.fc(x)
        return x
        
net = Net(dic_size, hidden_size, 2)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), learning_rate)

# train
for i in range(100):
    optimizer.zero_grad()
    outputs = net(X)
    loss = criterion(outputs.view(-1, dic_size), Y.view(-1))
    loss.backward()
    optimizer.step()
    
    results = outputs.argmax(dim=2)
    predict_str = ''
    for j, result in enumerate(results):
        print(i, j, ''.join([char_set[t] for t in result]), loss.item())
        if j==0:
            predict_str += ''.join([char_set[t] for t in result])
        else:
            predict_str += char_set[result[-1]]

참고
파이썬 딥러닝 파이토치 (이경택, 방성수, 안상준)
모두를 위한 딥러닝 시즌 2 Lab 11-0, 11-1, 11-3, 11-4

profile
데이터사이언스를 공부하는 권유진입니다.

0개의 댓글