STUDY/머신러닝 | 딥러닝

[부스트코스] RNN seq2seq

2022. 12. 18. 00:01

파이토치로 시작하는 딥러닝기초

출처: https://www.boostcourse.org/ai214

  • 순환신경망(Recurrent Neural Network)
  • Sequence-To-Sequence

  • 시퀀스를 입력받아서 시퀀스를 출력
  • 대표적인 사용처: 번역이나 챗봇

  • Encoder - Decoder 구조
  • 인코더로 압축된 벡터를 디코더에 전달
  • 스타트 플래그와 함께 모델 시작
  • 아웃풋을 reply에 첫번째에 두고, 이 아웃풋이 다음으로 또 들어간다. -> 완전한 문장 생성
  • 모든 문장을 들은 후에 답변을 생성한다
  • RNN 2개를 생성해서 중간을 연결한 형태
  • pytorch로 구현 가능

마지막 10줄의 코드가 전체 200줄 정도의 내용을 압축하고 있는 코드

이 예시는 번역 task를 수행하는 모델

source text (영문)-> target text(한국어)

train-test로 나눠서 검증

pre-process 보조함수

raw 원문

s, t 문장의 최대길이 제한 

encoder, decoder의 Hidden State도 같은 크기로 정의를 해준다.

encoder, decoder는 각각 클래스로, RNN layer이다. 각각선언하여 학습시킨다.

train 안에 인코더의 출력을 디코더의 첫 입력으로 연결해주는 부분이 있다.

전체 model학습이 끝나면 test를 가지고 evaluation

 

예제 데이터 입력

import random
import torch
import torch.nn as nn
import torch.optim as optim

torch.manual_seed(0)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

raw = ["I feel hungry. 나는배가고프다.",
 "Pytorch is very easy. 파이토치는매우쉽다.",
 "Pytorch is a framework for deep learning. 파이토치는딥러닝을위한프레임워크이다.",
 "Pytorch is very clear to use. 파이토치는사용하기매우직관적이다."]

SOS_token = 0
EOS_token = 1

SOS_token: Start of Sentence 인덱스를 0번으로 설정

End of Sentence: 문장이 끝났다라는 뜻에서 토큰을 붙여서 문장의 종료를 알려줌 (1번 인덱스를 가진 토큰)

 

Preprocessing

def preprocess(corpus, source_max_length, target_max_length):
 	print("reading corpus...")
 	pairs = []
 	for line in corpus:
 		pairs.append([s for s in line.strip().lower().split("\t")])
 	print("Read {} sentence pairs".format(len(pairs)))
 
 	pairs = [pair for pair in pairs if filter_pair(pair, source_max_length, target_max_length)]
 	print("Trimmed to {} sentence pairs".format(len(pairs)))
 
 	source_vocab = Vocab()
 	target_vocab = Vocab()
 
 	print("Counting words...")
 	for pair in pairs:
 		source_vocab.add_vocab(pair[0])
 		target_vocab.add_vocab(pair[1])
 	print("source vocab size =", source_vocab.n_vocab)
 	print("target vocab size =", target_vocab.n_vocab)
 	
    return pairs, source_vocab, target_vocab

데이터 전처리

vocab 선언 단어 갯수, 단어 딕셔너리

 

인코더, 디코더 클래스 선언

class Encoder(nn.Module):
 	def __init__(self, input_size, hidden_size):
 		super(Encoder, self).__init__()
 		self.hidden_size = hidden_size
 		self.embedding = nn.Embedding(input_size, hidden_size)
 		self.gru = nn.GRU(hidden_size, hidden_size)
 
 	def forward(self, x, hidden):
 		x = self.embedding(x).view(1, 1, -1)
 		x, hidden = self.gru(x, hidden)
 		return x, hidden
 
 class Decoder(nn.Module):
 	def __init__(self, hidden_size, output_size):
 		super(Decoder, self).__init__()
 		self.hidden_size = hidden_size
 		self.embedding = nn.Embedding(output_size, hidden_size)
 		self.gru = nn.GRU(hidden_size, hidden_size)
 		self.out = nn.Linear(hidden_size, output_size)
 		self.softmax = nn.LogSoftmax(dim=1)

	def forward(self, x, hidden):
 		x = self.embedding(x).view(1, 1, -1)
 		x, hidden = self.gru(x, hidden)
 		x = self.softmax(self.out(x[0]))
 		return x, hidden

인코더

copus의 길이 만큼의 0을 가지고 있는 원핫 인코딩

embedding이라는 matrix의 input이 된다.

임베딩(embedding)

들어온 input을 hidden size만큼의 vector로 줄인다(적은 차원을 가진 벡터로 표현한다) 

줄어든 벡터가 gru에 들어오게 된다. -> 처리

 

디코더

hidden size 차원의 벡터를 다시 taget text의 index만큼 복원

임베딩 통과, gru 통과, out 통과, softmax 통과

(attention, highway network 추가)

 

학습

def tensorize(vocab, sentence):
 	indexes = [vocab.vocab2index[word] for word in sentence.split(" ")]
	indexes.append(vocab.vocab2index["<EOS>"])
 	return torch.Tensor(indexes).long().to(device).view(-1, 1)

def train(pairs, source_vocab, target_vocab, encoder, decoder, n_iter, print_every=1000, learning_rate=0.01):
 	loss_total = 0
 
 	encoder_optimizer = optim.SGD(encoder.parameters(), lr=learning_rate)
 	decoder_optimizer = optim.SGD(decoder.parameters(), lr=learning_rate)
 
 	training_batch = [random.choice(pairs) for _ in range(n_iter)]
 	training_source = [tensorize(source_vocab, pair[0]) for pair in training_batch]
 	training_target = [tensorize(target_vocab, pair[1]) for pair in training_batch]
 	
    criterion = nn.NLLLoss()

tensorize 보조 함수 : sentence를 원핫벡터, tensor의 형태로 바꿔줌

카테고리 분류 NLL loss

def train(pairs, source_vocab, target_vocab, encoder, decoder, n_iter, print_every=1000, learning_rate=0.01):
 	for i in range(1, n_iter + 1):
		source_tensor = training_source[i - 1]
 		target_tensor = training_target[i - 1]
 
 		encoder_hidden = torch.zeros([1, 1, encoder.hidden_size]).to(device)
 
 		encoder_optimizer.zero_grad()
 		decoder_optimizer.zero_grad()
 
 		source_length = source_tensor.size(0)
 		target_length = target_tensor.size(0)
 
 		loss = 0
 
 		for enc_input in range(source_length):
 			_, encoder_hidden = encoder(source_tensor[enc_input], encoder_hidden)

for 문 루프

encoder_hidden 0 벡터를 넣어준다

encoder에서 hidden state를 꺼내온다.

 

def train(pairs, source_vocab, target_vocab, encoder, decoder, n_iter, print_every=1000, learning_rate=0.01):
 	
    decoder_input = torch.Tensor([[SOS_token]]).long().to(device)
 	decoder_hidden = encoder_hidden
 	
    for di in range(target_length):
 		decoder_output, decoder_hidden = decoder(decoder_input, decoder_hidden)
 		loss += criterion(decoder_output, target_tensor[di])
 		decoder_input = target_tensor[di] # teacher forcing
 	
    loss.backward()
 	
    encoder_optimizer.step()
 	decoder_optimizer.step()
 
 	loss_iter = loss.item() / target_length
 	loss_total += loss_iter
 	
    if i % print_every == 0:
 		loss_avg = loss_total / print_every
 		loss_total = 0
 		print("[{} - {}%] loss = {:05.4f}".format(i, i / n_iter * 100, loss_avg))

decoder_hidden = encoder_hidden

입력값 SOS_token 

# teacher forcing

 

#184~195번줄

SOURCE_MAX_LENGTH = 10
TARGET_MAX_LENGTH = 12
load_pairs, load_source_vocab, load_target_vocab = preprocess(raw, SOURCE_MAX_LENGTH, TARGET_MAX_LENGTH)
print(random.choice(load_pairs))

enc_hidden_size = 16
dec_hidden_size = enc_hidden_size
enc = Encoder(load_source_vocab.n_vocab, enc_hidden_size).to(device)
dec = Decoder(dec_hidden_size, load_target_vocab.n_vocab).to(device)

train(load_pairs, load_source_vocab, load_target_vocab, enc, dec, 5000, print_every=1000)
evaluate(load_pairs, load_source_vocab, load_target_vocab, enc, dec, TARGET_MAX_LENGTH)
  • 예제 데이터 입력
  • Preprocessing
  • 인코더, 디코더 클래스 선언
  • 학습
'STUDY/머신러닝 | 딥러닝' 카테고리의 다른 글
  • [study] BERT, GPT, GAN 개념 이해하기
  • 자연어처리(NLP) 정리(3) 형태소 분석기 KoNLpy, 토크나이저 Tokenizer
  • 자연어처리(NLP) 정리(2) - 문자 전처리(정규표현식 등)
  • 자연어처리(NLP) 정리(1) BOW, TF-IDF
둥둥런
둥둥런
대학원생의 UX, 데이터분석, 개발 공부 기록장📁
둥둥런
Done is better than Perfect
둥둥런
전체
오늘
어제

공지사항

  • About me
  • 분류 전체보기 N
    • TIL
      • 멋사_AI스쿨_TIL
    • 회고
      • 프로젝트 회고
    • STUDY
      • SQL
      • Python
      • Pandas
      • 태블로
      • 통계
      • 머신러닝 | 딥러닝
      • ETC
      • 그로스마케팅 | 광고
      • UX
    • BOOK
    • EVENT

인기 글

블로그 메뉴

  • 태그
  • 관리
hELLO · Designed By 정상우.
둥둥런
[부스트코스] RNN seq2seq
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.