lstm 9. pytorch 사용법

행동하는 개발자·2022년 12월 19일
0

RNN

목록 보기
8/14

base model 외우기

import pandas as pd
import numpy as np
import os

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader

from tqdm.auto import tqdm

from sklearn.model_selection import train_test_split

import warnings
warnings.filterwarnings(action='ignore') 

class BaseModel(nn.Module):
    def __init__(self, embed_dim = 128,
                    seq_dim = 512,
                    lstm_bidirect = True):
        super(BaseModel, self).__init__()

        embed_1 = nn.Embedding(num_embedding = 128,
                                embedding_dim = embed_dim,
                                padding_idx = 0)

        embed_2 = nn.Embedding(num_embedding = 128,
                                embedding_dim = embed_dim,
                                padding_idx = 0)

        lstm_1 = nn.LSTM(input_size = embed_dim,
                        hidden_size = seq_dim,
                        batch_first = True,
                        bidirectional = lstm_bidirect)

        lstm_2 = nn.LSTM(input_size = embed_dim,
                        hidden_size = seq_dim,
                        batch_first = True,
                        bidirectional = lstm_bidirect)

        in_channels = 4 * seq_dim
        self.regressor = nn.Sequential(nn.Linear(in_features=in_channels,
                                                out_features=512),
                                        nn.BatchNorm1d(512),
                                        nn.ReLU(),
                                        nn.Linear(in_features=512,
                                                out_features=1))


    def forward(self, frag1, frag2):
        frag1 = self.embed_1(frag1)
        frag2 = self.embed_2(frag2)

        frag1_hidden, _ = self.frag1_lstm(frag1)
        frag1_hidden = frag1_hidden[:,-1,:]

        frag2_hidden, _ = self.frag2_lstm(frag2)
        frag2_hidden = frag2_hidden[:,-1,:]         

        x = torch.cat([frag1_hidden, frag2_hidden], axis = -1)
        x = self.regressor(x)

        return x                       

양방향 LSTM?

가령 단어 'BOOK'이 있고 B가 21, O가 7, K가 11이라고 하면 BOOK은 21,7,7,11로 인코딩 되어 있을까요? 이 각 정수를 각각 임베딩 층을 거치도록 하여 문자 단위 임베딩을 얻게 됩니다. 임베딩 층은 모델을 설계할 때 추가하므로 정수 인코딩까지만 진행합니다.

'good book'의 정수 인코딩 결과
12, 7, 7, 17

21, 7, 7, 11

[[53 41 48 54 52 34 47 37 52  0  0  0  0  0  0]
 [48 39  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [37 38 46 48 47 52 53 51 34 53 48 51 52  0  0]
 [41 34 55 38  0  0  0  0  0  0  0  0  0  0  0]
 [46 34 51 36 41 38 37  0  0  0  0  0  0  0  0]
 [53 41 51 48 54 40 41  0  0  0  0  0  0  0  0]
 [45 48 47 37 48 47  0  0  0  0  0  0  0  0  0]
 [53 48  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [49 51 48 53 38 52 53  0  0  0  0  0  0  0  0]
 [53 41 38  0  0  0  0  0  0  0  0  0  0  0  0]
 [56 34 51  0  0  0  0  0  0  0  0  0  0  0  0]
 [42 47  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [42 51 34 50  0  0  0  0  0  0  0  0  0  0  0]
 [34 47 37  0  0  0  0  0  0  0  0  0  0  0  0]
 [37 38 46 34 47 37  0  0  0  0  0  0  0  0  0]
 [53 41 38  0  0  0  0  0  0  0  0  0  0  0  0]
 [56 42 53 41 37 51 34 56 34 45  0  0  0  0  0]
 [48 39  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [35 51 42 53 42 52 41  0  0  0  0  0  0  0  0]
 [53 51 48 48 49 52  0  0  0  0  0  0  0  0  0]
 [39 51 48 46  0  0  0  0  0  0  0  0  0  0  0]
 [53 41 34 53  0  0  0  0  0  0  0  0  0  0  0]
 [36 48 54 47 53 51 58  0  0  0  0  0  0  0  0]
 [14  0  0  0  0  0  0  0  0  0  0  0  0  0  0]]

각 행은 각 단어를 의미한다. 단어의 최대 길이를 15로 제한하였으므로 길이가 15보다 짧은 단어는 뒤에 0으로 패딩된다. 53은 t, 41은 h, 48은 o, 54는 u에 각각 해당된다. X_data는 뒤에 0으로 패딩되어 길이가 70인 것에 비해 X_char_data는 0번 단어는 무시되어 길이가 70이 아니다. 즉, 위 출력 결과에서 행의 개수가 70이 아니다.

BiLSTM-CNN

위에서 전처리한 문자 단위 정수 인코딩 입력을 1D CNN의 입력으로 사용하여 문자 임베딩을 얻고 워드 임베딩과 연결하여 양방향 LSTM의 입력으로 사용할 수 있다.

word_ids = Input(shape=(None,),dtype='int32',name='words_input')
word_embeddings = Embedding(input_dim = vocab_size, output_dim = 64)(word_ids)

# char 임베딩
char_ids = Input(shape=(None, max_len_char,),name='char_input')
embed_char_out = TimeDistributed(Embedding(len(char_to_index), 30, embeddings_initializer=RandomUniform(minval=-0.5, maxval=0.5)), name='char_embedding')(char_ids)
dropout = Dropout(0.5)(embed_char_out)

# char 임베딩에 대해서는 Conv1D 수행
conv1d_out= TimeDistributed(Conv1D(kernel_size=3, filters=30, padding='same',activation='tanh', strides=1))(dropout)
maxpool_out=TimeDistributed(MaxPooling1D(max_len_char))(conv1d_out)
char_embeddings = TimeDistributed(Flatten())(maxpool_out)
char_embeddings = Dropout(0.5)(char_embeddings)

# char 임베딩을 Conv1D 수행한 뒤에 워드 임베딩과 연결
output = concatenate([word_embeddings, char_embeddings])

# 연결한 벡터를 가지고 문장의 길이만큼 LSTM을 수행
output = Bidirectional(LSTM(50, return_sequences=True, dropout=0.50, recurrent_dropout=0.25))(output)

# 출력층
output = TimeDistributed(Dense(tag_size, activation='softmax'))(output)

model = Model(inputs=[word_ids, char_ids], outputs=[output])
model.compile(loss='categorical_crossentropy', optimizer='nadam',  metrics=['acc'])

단어의 희소 표현(Sparse Representation)

벡터의 특정 차원에 단어 혹은 의미를 직접 매핑하는 방식

희소 표현은 데이터를 벡터 또는 행렬을 기반으로 수치화하며 표현할 때 극히 일부의 인덱스만 특정 값으로 표현하고, 대부분의 나머지 인덱스는 의미 없는 값으로 표현하는 기법이다. 대표적으로 원 핫 인코딩 방식이 있다.

profile
끊임없이 뭔가를 남기는 사람

0개의 댓글