Potato
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์žก๋‹ˆ๋‹ค?๐Ÿฅ” ^___^ ๐Ÿ˜บ github ๋ฐ”๋กœ๊ฐ€๊ธฐ ๐Ÿ‘‰๐Ÿป

AI study/์ž์—ฐ์–ด ์ฒ˜๋ฆฌ (NLP)

[NLP] ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์‹œํ€€์Šค ๋ชจ๋ธ๋ง (์‹œํ€€์Šค์™€ RNN)

๊ฐ์ž ๐Ÿฅ” 2021. 8. 3. 11:12
๋ฐ˜์‘ํ˜•

-- ๋ณธ ํฌ์ŠคํŒ…์€ ํŒŒ์ดํ† ์น˜๋กœ ๋ฐฐ์šฐ๋Š” ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ (ํ•œ๋น›๋ฏธ๋””์–ด) ์ฑ…์„ ์ฐธ๊ณ ํ•ด์„œ ์ž‘์„ฑ๋œ ๊ธ€์ž…๋‹ˆ๋‹ค.
-- ์†Œ์Šค์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ

 

1. NLP์—์„œ์˜ ์‹œํ€€์Šค

1.1 ์‹œํ€€์Šค๋ž€

  • ์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ํ•ญ๋ชฉ์˜ ๋ชจ์Œ
  • ์ˆœ์ฐจ ๋ฐ์ดํ„ฐ

โ–ถ ์˜ˆ์‹œ

The book is on the table.
The boos are on the table.

์œ„ ๋‘๊ฐœ์˜ ๋ฌธ์žฅ์€ ์˜์–ด์—์„œ ๋‹ค์ˆ˜์ธ์ง€ ๋ณต์ˆ˜์ธ์ง€์— ๋”ฐ๋ผ ๋™์‚ฌ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์ด๋Ÿฐ ๋ฌธ์žฅ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฌธ์žฅ์ด ๊ธธ์–ด์งˆ ์ˆ˜๋ก ์˜์กด์„ฑ์ด ๋” ๋†’์•„์งˆ ์ˆ˜ ์žˆ๋‹ค.

The book that I got yesterday is on the table.
The books read by the second=grade children are shelved in the lower rack.

 

๋”ฅ๋Ÿฌ๋‹์—์„œ์˜ ์‹œํ€€์Šค ๋ชจ๋ธ๋ง์€ ์ˆจ๊ฒจ์ง„ '์ƒํƒœ ์ •๋ณด(์€๋‹‰ ์ƒํƒœ)'๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค. ์‹œํ€€์Šค์— ์žˆ๋Š” ๊ฐ ํ•ญ๋ชฉ์ด ์€๋‹‰ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ , ์‹œํ€€์Šค ํ‘œํ˜„์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ด ์€๋‹‰์ƒํƒœ์˜ ๋ฒกํ„ฐ๋ฅผ ์‹œํ€€์Šค ๋ชจ๋ธ๋ง ์ž‘์—…์— ํ™œ์šฉํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ์‹œํ€€์Šค ์‹ ๊ฒฝ๋ง ๋ชจ๋ธ์€ 'RNN(Recurrent nerual network)'์ด๋‹ค. ๊ทธ๋Ÿผ NLP์—์„œ์˜ ์‹œํ€€์Šค ๋ชจ๋ฐ๋ฃจ RNN์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

 

2. ์ˆœํ™˜ ์‹ ๊ฒฝ๋ง, RNN (recurrent neural network)

  • RNN์˜ ๋ชฉ์ ์€ ์‹œํ€€์Šค ํ…์„œ๋ฅผ ๋ชจ๋ธ๋ง ํ•˜๋Š” ๊ฒƒ
  • ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ์„ ์‹œํ€€์Šค ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌํ•จ
  • RNN์˜ ์ข…๋ฅ˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ, ํ•ด๋‹น ํฌ์ŠคํŒ…์—์„œ๋Š” ์—˜๋งŒRNN์— ๋Œ€ํ•ด ๋‹ค๋ฃฐ ๊ฒƒ์ž„
    • ๋‘๊ฐœ์˜ RNN ์„ ํ™œ์šฉํ•œ sequence2sequence ๋‹ค์–‘ํ•œ RNN๋ชจ๋ธ์ด NLP์˜์—ญ์—์„œ ํ™œ์šฉ๋˜๊ณ  ์žˆ๋‹ค.
  • ๊ฐ™์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ™œ์šฉํ•ด์„œ ํƒ€์ž„ ์Šคํ…๋งˆ๋‹ค ์ถœ๋ ฅ์„ ๊ณ„์‚ฐํ•˜๊ณ , ์ด๋•Œ ์€๋‹‰ ์ƒํƒœ์˜ ๋ฒกํ„ฐ์— ์˜์กดํ•ด์„œ ์‹œํ€€์Šค์˜ ์ƒํƒœ๋ฅผ ๊ฐ์ง€ํ•œ๋‹ค.
  • RNN์˜ ์ฃผ ๋ชฉ์ ์€ ์ฃผ์–ด์ง„ ์€๋‹‰ ์ƒํƒœ ๋ฒกํ„ฐ์™€ ์ž…๋ ฅ ๋ฒกํ„ฐ์— ๋Œ€ํ•œ ์ถœ๋ ฅ์„ ๊ณ„์‚ฐํ•จ์œผ๋กœ์จ ์‹œํ€€์Šค์˜ ๋ถˆ๋ณ€์„ฑ์„ ํ•™์Šตํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

2.1 ๋™์ž‘ ๋ฐฉ์‹

  • ํ”ผ๋“œ ํฌ์›Œ๋“œ ์‹ ๊ฒฝ๋ง๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ, ์€๋‹‰์ธต ๋…ธ๋“œ์—์„œ ํ™œ์„ฑํ™” ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋‚˜์˜จ ๊ฒฐ๊ณผ๊ฐ’์„ ์ถœ๋ ฅ์ธต ๋ฐฉํ–ฅ์œผ๋กœ๋„ ๋ดฌ๋ฉด์„œ ๋™์‹œ์— ๋‹ค์‹œ ์€๋‹‰์ธต ๋…ธ๋“œ์˜ ๋‹ค์Œ ๊ณ„์‚ฐ ์ž…๋ ฅ์œผ๋กœ ๋ณด๋‚ด๋Š” ํŠน์ง•์„ ๊ฐ€์ง
  • ์ฆ‰, ํ˜„์žฌ ์ž…๋ ฅ ๋ฒกํ„ฐ์™€ ์ด์ „ ์€๋‹‰ ์ƒํƒœ ๋ฒกํ„ฐ๋กœ ํ˜„์žฌ์˜ ์€๋‹‰ ์ƒํƒœ ๋ฒกํ„ฐ๋ฅผ ๊ณ„์‚ฐํ•จ
  • ์—˜๋งŒRNN ์—์„œ๋Š” ์€๋‹‰๋ฒกํ„ฐ๊ฐ€ ์˜ˆ์ธก ๋Œ€์ƒ์ด๋‹ค.

ํŒŒ์ดํ† ์น˜๋กœ ๋ฐฐ์šฐ๋Š” ์ž์—ฐ์–ด์ฒ˜๋ฆฌ p183

  • ๊ตฌ์ฒด์ ์ธ ๊ณ„์‚ฐ ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค

ํŒŒ์ดํ† ์น˜๋กœ ๋ฐฐ์šฐ๋Š” ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ p184

  • ์€๋‹‰-์€๋‹‰ ๊ฐ€์ค‘์น˜ ํ–‰๋ ฌ์„ ์‚ฌ์šฉํ•ด ์ด์ „ ์€๋‹‰ ์ƒํƒœ ๋ฒกํ„ฐ๋ฅผ ๋งคํ•‘
  • ์ž…๋ ฅ-์€๋‹‰ ๊ฐ€์ค‘์น˜ ํ–‰๋ ฌ์„ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ์ž…๋ ฅ ๋ฒกํ„ฐ๋ฅผ ๋งคํ•‘
  • ๋‘ ๊ฐœ์˜ ๊ฐ’์„ ๋”ํ•˜์—ฌ ์ƒˆ๋กœ์šด ์€๋‹‰ ๋ฒกํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค.

 

3. RNN ๊ตฌํ˜„ํ•˜๊ธฐ

โ–ถ column_gather ํ•จ์ˆ˜

  • ๋ฐฐ์น˜ ํ–‰ ์ธ๋ฑ์Šค๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ x_lengths์— ์žˆ๋Š” ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ์ธ๋ฑ์Šค ์œ„์น˜ (์ฆ‰, ์‹œํ€€์Šค์˜ ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค์— ์žˆ๋Š”)์˜ ๋ฒกํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
def column_gather(y_out, x_lengths):
    ''' y_out์— ์žˆ๋Š” ๊ฐ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ์—์„œ ๋งˆ์ง€๋ง‰ ๋ฒกํ„ฐ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค

    ์กฐ๊ธˆ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด ๋ฐฐ์น˜ ํ–‰ ์ธ๋ฑ์Šค๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ
    x_lengths์— ์žˆ๋Š” ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ์ธ๋ฑ์Šค ์œ„์น˜์˜ ๋ฒกํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    ๋งค๊ฐœ๋ณ€์ˆ˜:
        y_out (torch.FloatTensor, torch.cuda.FloatTensor)
            shape: (batch, sequence, feature)
        x_lengths (torch.LongTensor, torch.cuda.LongTensor)
            shape: (batch,)

    ๋ฐ˜ํ™˜๊ฐ’:
        y_out (torch.FloatTensor, torch.cuda.FloatTensor)
            shape: (batch, feature)
    '''
    x_lengths = x_lengths.long().detach().cpu().numpy() - 1

    out = []
    for batch_index, column_index in enumerate(x_lengths):
        out.append(y_out[batch_index, column_index])

    return torch.stack(out)

 

 

โ–ถ์—˜๋งŒRNN ํ•จ์ˆ˜

  • RNNCell์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งŒ๋“  RNN ๋ชจ๋ธ
  • ์ตœ์ข…๊ฐ’์œผ๋กœ ๊ฐ ํƒ€์ž„step์—์„œ์˜ ์€๋‹‰๋ฒกํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
class ElmanRNN(nn.Module):
    """ RNNCell์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งŒ๋“  ์—˜๋งŒ RNN """
    def __init__(self, input_size, hidden_size, batch_first=False):
        """
        ๋งค๊ฐœ๋ณ€์ˆ˜:
            input_size (int): ์ž…๋ ฅ ๋ฒกํ„ฐ ํฌ๊ธฐ
            hidden_size (int): ์€๋‹‰ ์ƒํƒœ ๋ฒกํ„ฐ ํฌ๊ธฐ
            batch_first (bool): 0๋ฒˆ์งธ ์ฐจ์›์ด ๋ฐฐ์น˜์ธ์ง€ ์—ฌ๋ถ€
        """
        super(ElmanRNN, self).__init__()
        
        # RNNCell์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž…๋ ฅ-์€๋‹‰ ๊ฐ€์ค‘์น˜ ํ–‰๋ ฌ๊ณผ ์€๋‹‰-์€๋‹‰๊ฐ€์ค‘์น˜ํ–‰๋ ฌ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž„
        # RNNCell์„ ํ˜ธ์ถœํ• ๋•Œ๋งˆ๋‹ค ์ž…๋ ฅ๋ฒกํ„ฐ์™€ ์€๋‹‰ํ–‰๋ ฌ์„ ๋ฐ›๋Š”๋‹ค
        self.rnn_cell = nn.RNNCell(input_size, hidden_size)
        
        self.batch_first = batch_first
        self.hidden_size = hidden_size

    def _initial_hidden(self, batch_size):
        return torch.zeros((batch_size, self.hidden_size))

    def forward(self, x_in, initial_hidden=None):
      # ์ž…๋ ฅํ…์„œ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ํƒ€์ž…์Šคํ…๋งˆ๋‹ค ์€๋‹‰์ƒํƒœ ๋ฒกํ„ฐ๋ฅผ ๊ณ„์‚ฐํ•ด์ฃผ๋Š” forward๋ฉ”์„œ๋“œ
        """ ElmanRNN์˜ ์ •๋ฐฉํ–ฅ ๊ณ„์‚ฐ
        
        ๋งค๊ฐœ๋ณ€์ˆ˜:
            x_in (torch.Tensor): ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ…์„œ 
                If self.batch_first: x_in.shape = (batch_size, seq_size, feat_size)
                Else: x_in.shape = (seq_size, batch_size, feat_size)
            initial_hidden (torch.Tensor): RNN์˜ ์ดˆ๊ธฐ ์€๋‹‰ ์ƒํƒœ
        ๋ฐ˜ํ™˜๊ฐ’:
            hiddens (torch.Tensor): ๊ฐ ํƒ€์ž„ ์Šคํ…์—์„œ RNN ์ถœ๋ ฅ
                If self.batch_first: 
                   hiddens.shape = (batch_size, seq_size, hidden_size)
                Else: hiddens.shape = (seq_size, batch_size, hidden_size)
        """
        # batch_first๊ฐ€ True์ด๋ฉด์ถœ๋ ฅ์€๋‹‰์ƒํƒœ์˜ ๋ฐฐ์น˜ ์ฐจ์›์„ 0๋ฒˆ์งธ๋กœ ๋ฐ”๊ฟˆ(?)
        if self.batch_first:
            batch_size, seq_size, feat_size = x_in.size()
            x_in = x_in.permute(1, 0, 2)
        else:
            seq_size, batch_size, feat_size = x_in.size()
    
        hiddens = []

        if initial_hidden is None:
            initial_hidden = self._initial_hidden(batch_size)
            initial_hidden = initial_hidden.to(x_in.device)

        hidden_t = initial_hidden
                    
        for t in range(seq_size):
            hidden_t = self.rnn_cell(x_in[t], hidden_t)
            hiddens.append(hidden_t)
            
        hiddens = torch.stack(hiddens)

        if self.batch_first:
            hiddens = hiddens.permute(1, 0, 2)

        return hiddens

 

โ–ถํ›ˆ๋ จ์—์„œ ์‚ฌ์šฉํ•  SurnameClassifier ํ•จ์ˆ˜

  • RNN๊ณผ Linear์ธต์œผ๋กœ ๋‚˜๋‰จ
  • RNN์ธต์—์„œ ์‹œํ€€์Šค์˜ ๋ฒกํ„ฐ ํ‘œํ˜„ (ํžˆ๋“ ๋ฒกํ„ฐ)๋ฅผ ๊ณ„์‚ฐํ•ด์ฃผ๊ณ  ์„ฑ์”จ์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์— ํ•ด๋‹นํ•˜๋Š” ๋ฒกํ„ฐ๋ฅผ ์ถ”์ถœํ•ด์ฃผ๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ (์„ฑ์”จ์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์— ํ•ด๋‹นํ•˜๋Š” ๋ฒกํ„ฐ๋ž€, ์ตœ์ข… ๋ฒกํ„ฐ๋ฅผ ๋งํ•œ๋‹ค.)
  • ์ตœ์ข…๋ฒกํ„ฐ๊ฐ€ ์ „์ฒด์‹œํ€€์Šค ์ž…๋ ฅ์„ ๊ฑฐ์ณ ์ „๋‹ฌ๋œ ๊ฒฐ๊ณผ๋ฌผ์ธ ์š”์•ฝ๋ฒกํ„ฐ๋ผ๊ณ  ํ•  ์ˆ˜์žˆ๋‹ค.
  • Linear์ธต์—์„œ ์š”์•ฝ๋ฒกํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์˜ˆ์ธก๋ฒกํ„ฐ๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค.
# RNN์ธต, Linear ์ธต์œผ๋กœ ๋‚˜๋‰จ
class SurnameClassifier(nn.Module):
    """ RNN์œผ๋กœ ํŠน์„ฑ์„ ์ถ”์ถœํ•˜๊ณ  MLP๋กœ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ถ„๋ฅ˜ ๋ชจ๋ธ """
    def __init__(self, embedding_size, num_embeddings, num_classes,
                 rnn_hidden_size, batch_first=True, padding_idx=0):
        """
        ๋งค๊ฐœ๋ณ€์ˆ˜:
            embedding_size (int): ๋ฌธ์ž ์ž„๋ฒ ๋”ฉ์˜ ํฌ๊ธฐ
            num_embeddings (int): ์ž„๋ฒ ๋”ฉํ•  ๋ฌธ์ž ๊ฐœ์ˆ˜
            num_classes (int): ์˜ˆ์ธก ๋ฒกํ„ฐ์˜ ํฌ๊ธฐ
                ๋…ธํŠธ: ๊ตญ์  ๊ฐœ์ˆ˜
            rnn_hidden_size (int): RNN์˜ ์€๋‹‰ ์ƒํƒœ ํฌ๊ธฐ
            batch_first (bool): ์ž…๋ ฅ ํ…์„œ์˜ 0๋ฒˆ์งธ ์ฐจ์›์ด ๋ฐฐ์น˜์ธ์ง€ ์‹œํ€€์Šค์ธ์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ
            padding_idx (int): ํ…์„œ ํŒจ๋”ฉ์„ ์œ„ํ•œ ์ธ๋ฑ์Šค; 
                torch.nn.Embedding์„ ์ฐธ๊ณ ํ•˜์„ธ์š”
        """
        super(SurnameClassifier, self).__init__()

        #๋จผ์ € ์ž„๋ฒ ๋”ฉ์ธต์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •์ˆ˜๋ฅผ ์ž„๋ฒ ๋”ฉํ•ด์คŒ
        self.emb = nn.Embedding(num_embeddings=num_embeddings,
                                embedding_dim=embedding_size,
                                padding_idx=padding_idx)
        # ๊ทธ ๋‹ค์Œ RNN์ธต์œผ๋กœ ์‹œํ€€์Šค์˜ ๋ฒกํ„ฐํ‘œํ˜„์„ ๊ณ„์‚ฐํ•ด์คŒ
        # ์ด ๋ฒกํ„ฐ๋Š” ์„ฑ์”จ์— ์žˆ๋Š” ๊ฐ ๋ฌธ์ž์— ๋Œ€ํ•œ ์€๋‹‰์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ„
        # ์„ฑ์”จ์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์— ํ•ด๋‹นํ•˜๋Š” ๋ฒกํ„ฐ๋ฅผ ์ถ”์ถœ (์ตœ์ข…๋ฒกํ„ฐ)
        # ์ด ์ตœ์ข…๋ฒกํ„ฐ๊ฐ€ ์ „์ฒด ์‹œํ€€์Šค ์ž…๋ ฅ์„ ๊ฑฐ์ณ ์ „๋‹ฌ๋œ ๊ฒฐ๊ณผ๋ฌผ์ด๋ผ๊ณ  ํ•  ์ˆ˜์žˆ์Œ (์„ฑ์”จ๋ฅผ ์š”์•ฝํ•œ ๋ฒกํ„ฐ)
        self.rnn = ElmanRNN(input_size=embedding_size,
                             hidden_size=rnn_hidden_size,
                             batch_first=batch_first)
        # ์š”์•ฝ๋ฒกํ„ฐ๋ฅผ linear ์ธต์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์˜ˆ์ธก๋ฒกํ„ฐ ๊ณ„์‚ฐ
        # ์˜ˆ์ธก๋ฒกํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ softmaxํ•จ์ˆ˜์— ์ ์šฉํ•˜๊ฑฐ๋‚˜, ํ›ˆ๋ จ ์†์‹ค์„ ๊ณ„์‚ฐํ•˜์—ฌ ์„ฑ์”จ์— ๋Œ€ํ•œ ํ™•๋ฅ  ๋ถ„ํฌ๋ฅผ ๋งŒ๋“ ๋‹ค.
        self.fc1 = nn.Linear(in_features=rnn_hidden_size,
                         out_features=rnn_hidden_size)
        self.fc2 = nn.Linear(in_features=rnn_hidden_size,
                          out_features=num_classes)
    
    # ์‹œํ€€์Šค์˜ ๊ธธ์ด x_length๊ฐ€ ํ•„์š” 
    # ์‹œํ€€์Šค์˜ ๊ธธ์ด๋Š” gather_column()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์„œ์—์„œ ์‹œํ€€์Šค๋งˆ๋‹ค ๋งˆ์ง€๋ง‰ ๋ฒกํ„ฐ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜
    def forward(self, x_in, x_lengths=None, apply_softmax=False):
        """ ๋ถ„๋ฅ˜๊ธฐ์˜ ์ •๋ฐฉํ–ฅ ๊ณ„์‚ฐ
        
        ๋งค๊ฐœ๋ณ€์ˆ˜:
            x_in (torch.Tensor): ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ํ…์„œ 
                x_in.shape๋Š” (batch, input_dim)์ž…๋‹ˆ๋‹ค
            x_lengths (torch.Tensor): ๋ฐฐ์น˜์— ์žˆ๋Š” ๊ฐ ์‹œํ€€์Šค์˜ ๊ธธ์ด
                ์‹œํ€€์Šค์˜ ๋งˆ์ง€๋ง‰ ๋ฒกํ„ฐ๋ฅผ ์ฐพ๋Š”๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
            apply_softmax (bool): ์†Œํ”„ํŠธ๋งฅ์Šค ํ™œ์„ฑํ™” ํ•จ์ˆ˜๋ฅผ ์œ„ํ•œ ํ”Œ๋ž˜๊ทธ
                ํฌ๋กœ์Šค-์—”ํŠธ๋กœํ”ผ ์†์‹ค์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด False๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค
        ๋ฐ˜ํ™˜๊ฐ’:
            ๊ฒฐ๊ณผ ํ…์„œ. tensor.shape๋Š” (batch, output_dim)์ž…๋‹ˆ๋‹ค.
        """
        x_embedded = self.emb(x_in)
        y_out = self.rnn(x_embedded)

        if x_lengths is not None:
            # column_gather : ์กฐ๊ธˆ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํ•˜๋ฉด ๋ฐฐ์น˜ ํ–‰ ์ธ๋ฑ์Šค๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ 
            # x_lengths์— ์žˆ๋Š” ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š”(์‹œํ€€์Šค์˜ ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค์— ์žˆ๋Š”) ์ธ๋ฑ์Šค ์œ„์น˜์˜ ๋ฒกํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
            y_out = column_gather(y_out, x_lengths)
        else:
            y_out = y_out[:, -1, :]

        y_out = F.relu(self.fc1(F.dropout(y_out, 0.5)))
        y_out = self.fc2(F.dropout(y_out, 0.5))

        if apply_softmax:
            y_out = F.softmax(y_out, dim=1)

        return y_out

 

 

 

๋ฐ˜์‘ํ˜•