댑덥딥 9주차 정리
Tags: ai, deeplearning, 스터디, 모두를위한딥러닝시즌2
Published: 2023-12-28 11:23:29

> '모두를 위한 딥러닝 시즌 2' 강의를 듣고 공부하는 스터디 입니다. https://deeplearningzerotoall.github.io/season2/lec_tensorflow.html
> 

---

***비대면 7 June, 2023***

# 11-4 RNN time series

time series data? =serial data, 일정한 시간 간격으로 배치된 데이터 ex) 주가 데이터

#### apply RNN: many-to-one

hidden state에 충분한 dimesion을 주고 마지막 output에 fc layer

```python
#스케일링: 0부터 1사이의 상대값으로 변환하여 사용→부담이 줄어듦
def minmax_scaler(data):
	numerator = data - np.min(data, 0)
	denominator = np.max(data, 0) - np.min(data, 0)
	return numerator / (denominator + 1e-7)
```

```python
#Neural Net setting
class Net(torch.nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, layers):
        super(Net, self).__init__()
        self.rnn = torch.nn.LSTM(input_dim, hidden_dim, num_layers=layers, batch_first=True)
        self.fc = torch.nn.Linear(hidden_dim, output_dim, bias=True)

    def forward(self, x):
        x, _status = self.rnn(x)
        x = self.fc(x[:, -1])
        return x

net = Net(data_dim, hidden_dim, output_dim, 1)
```

# 11-5 RNN Seq2seq

### Seq2seq model

? sequence를 입력받고 sequence를 출력. 번역/챗봇 분야에서 많이 활용


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su6vb00vuiwln1xs5nvi.png)

RNN은 문장이 끝나기 전 답변을 만듦. 끝까지 듣고 답하기 위해 seq2seq 모델이 나옴

- encoder와 decoder이라는 두 개의 RNN으로 구성됨
    
    encoder: input을 벡터의 형태로 압축하여 decoder에 전달
    
    decoder: 첫 셀에 전달된 벡터
    


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tet0q3t1ekpzcwn2sm71.png)

```python
# 전체적인 흐름

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

#define encoder, decoder
enc_hidden_size = 16
dec_hidden_size = enc_hidden_size
enc = Encoder(load_source_vocab.n_vocab, enc_hidden_size)
dec = Decoder(dec_hidden_size, load_target_vocab.n_vocab)

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)
```

```python
#data setting-convert sentence to one-hot vector
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)
```

```python
# fix token for "start of sentence" and "end of sentence"
SOS_token = 0
EOS_token = 1

# class for vocabulary related information of data
class Vocab:
    def __init__(self):
        self.vocab2index = {"<SOS>": SOS_token, "<EOS>": EOS_token}
        self.index2vocab = {SOS_token: "<SOS>", EOS_token: "<EOS>"}
        self.vocab_count = {}
        self.n_vocab = len(self.vocab2index)

    def add_vocab(self, sentence):
        for word in sentence.split(" "):
            if word not in self.vocab2index:
                self.vocab2index[word] = self.n_vocab
                self.vocab_count[word] = 1
                self.index2vocab[self.n_vocab] = word
                self.n_vocab += 1
            else:
                self.vocab_count[word] += 1
```

```python
# declare simple encoder
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

# declare simple decoder
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
```

- nn.Embedding: input에 one-hot으로 표현된 vector를 곱하여 거대한 matrix(mxn)를 mx1 vector로 변환함
- GRU: LSTM과 같은 advanced RNN model.
    
    LSTM: RNN보다 성능이 좋다고 알려져 있다.(gradient vanishing문제 일부 해소) 
    
    GRU: LSTM보다 빠르다고 알려져 있다.
    


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc3lbt0usewh8qg4dneq.png)

Q. encoder에서 embedding 했는데 decoder에서 왜 또 embedding 하지? 이미 압축된 형태로 들어오는 거 아닌가? 
A. hidden state의 사이즈를 gru input 사이즈에 맞춰주기 위해서

```python
# training seq2seq
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()    #crossentropy를 사용하기도 함

    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)

        decoder_input = torch.Tensor([[SOS_token]]).long().to(device) #decoder의 첫 셀의 입력값은 start token
        decoder_hidden = encoder_hidden # connect encoder output to decoder input

        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))
```

- nn.NLLLoss: CrossEntropyLoss와 같이 cross-entropy 손실을 구하는 함수이고, 분류문제에서 출력이 확률값일 때 사용. CrossEntropyLoss = LogSoftmax + NLLLoss
- teacher forcing: 실제 정답을 다음 셀에 넣어주는 것.

-일부는 teacher forcing, 일부는 gru의 예측값을 다음 셀에 전달하는 방법을 사용할 수도 있음

# 11-6 RNN PackedSequence

sequential data는 길이가 정해져 있지 않음 → 하나로 tensor로 묶어서 학습시켜야 함

cf) 이미지는 fixed size(예를 들어 32x32)

### padding method

? 가장 긴 sequence의 길이에 맞추어 나머지 sequence의 뒤를 pad라는 토큰으로 채음

### packing method

? seqence 길이의 정보를 저장하여 사용. batch는 길이 내림차순으로 정렬되어야 함. padding method에 비해 효율적이고 pad tocken을 사용하지 않아도 됨.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3taomwewaebcqd58vms.png)

---

***대면 8 April, 2023***

###RNN-timeseries, seq2seq, packedsequence
{% embed https://colab.research.google.com/drive/1cm31F2z7ehVP0VGw1cbyi_dYGNXEpjnT?usp=sharing %}