728x90

시계열 문제

시계열 분석이란 시간에 따라 변하는 데이터를 사용하여 추이를 분석하는 것

ARIMA 모델

SARIMAX Results                                
==============================================================================
Dep. Variable:                  Sales   No. Observations:                   36
Model:                 ARIMA(5, 1, 0)   Log Likelihood                -199.651
Date:                Tue, 22 Aug 2023   AIC                            411.302
Time:                        08:02:02   BIC                            420.634
Sample:                    01-01-1991   HQIC                           414.523
                         - 12-01-1993                                         
Covariance Type:                  opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.L1         -0.8788      0.227     -3.876      0.000      -1.323      -0.434
ar.L2         -0.2787      0.232     -1.203      0.229      -0.733       0.176
ar.L3         -0.0076      0.270     -0.028      0.978      -0.536       0.521
ar.L4          0.3483      0.294      1.185      0.236      -0.228       0.924
ar.L5          0.3772      0.207      1.826      0.068      -0.028       0.782
sigma2      5049.2115   1540.731      3.277      0.001    2029.435    8068.988
===================================================================================
Ljung-Box (L1) (Q):                   0.39   Jarque-Bera (JB):                 1.60
Prob(Q):                              0.53   Prob(JB):                         0.45
Heteroskedasticity (H):               1.43   Skew:                             0.38
Prob(H) (two-sided):                  0.54   Kurtosis:                         2.28
===================================================================================
  • Sales를 종속변수로 가지고 있음
  • ARIMA 모델 사용
  • P>|z| : 통계적으로 유의미한지 평가할 떄 사용 (작을 수록 유의미)
  • JB 잔차의 정규성 평가
  • Hetero skedasticity 이상값 검정

RNN

RNN(Recurrent Neural Network)은 시간적으로 연속성이 있는 데이터를 처리하려고 고안된
인공 신경망
RNN이 기존 네트워크와 다른 점은 ‘기억(memory)’을 갖는다는 것

RNN은 외부 입력과 자신의 이전 상태를 받아서 갱신

출력 유형
1대1
1대다: 이미지 캡션
다대1: 감성 분석기
다대다: 언어 자동 번역기
동기화 다대다: 문장에서 다음에 나올 단어를 예측하는 언어 모델, 즉 프레임 수준의 비디오 분류

RNN은 셀 개념 숙지 (nn.RNNCell)
window 크기가 3개면 cell 3개가 1개 단위가 됨
3개를 input으로 넣고 4번째의 값을 예측

RNN 계층과 셀

RNN 셀은 하나의 단계(time step)만 처리

nn.RNNCell: SimpleRNN 계층에 대응되는 RNN 셀
nn.GRUCell: GRU 계층에 대응되는 GRU 셀
nn.LSTMCell: LSTM 계층에 대응되는 LSTM 셀

RNN의 활용 분야: 자연어 처리, 손글씨, 센서 데이터 등 시계열 데이터 처리

  • 입력 x 가 들어와서 y가 출력되는 구조
  • xt-1에서 ht-1을 얻고 다음 단계에서 ht-1과 xt를 사용하여 과거 정보와 현재 정보를 모두 반영
  • ht와 xt+1의 정보를 이용하여 과거와 현재 정보를 반복해서 반영
  • RNN의 오차(E)는 심층 신경망에서 전방향(feedforward) 학습과 달리 각 단계(t)마다 오차를 측정
  • RNN에서 역전파는 BPTT(BackPropagation Through Time)를 이용하여 모든 단계마다 처음부터 끝까지 역전파
  • 오차를 이용하여 Wxh, Whh, Why 및 바이어스를 업데이트

  • BPTT는 vanishing gradient problem이 발생
  • 기울기 소멸 문제를 보완하기 위해 오차를 몇 단계까지만 전파시키는 생략된-BPTT(truncated BPTT)를 사용할 수도 있고, 근본적으로는 LSTM 및 GRU를 많이 사용
start = time.time()
TEXT = torchtext.legacy.data.Field(lower=True, fix_length=200, batch_first=False)
LABEL = torchtext.legacy.data.Field(sequential=False)

batch_first: 신경망에 입력되는 텐서의 첫 번째 차원 값이 배치 크기(batch_size)가 되도록 함

# False
([seq_len, batch_size, hidden_size])
# [시퀀스 길이, 배치 크기, 은닉층의 뉴런 개수]

# True
([batch_size, seq_len, hidden_size])
# [배치 크기, 시퀀스 길이, 은닉층의 뉴런 개수]

RNN 셀 구현

TEXT.build_vocab(train_data, max_size=10000, min_freq=10, vectors=None)
LABEL.build_vocab(train_data)

print(f"Unique tokens in TEXT vocabulary: {len(TEXT.vocab)}")
print(f"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}")
  • build_vocab(훈련 데이터셋, max_size=단어 집합의 크기로 단어 집합에 포함되는 어휘 수,
  • min_freq=훈련 데이터셋에서 특정 단어의 최소 등장 횟수-10개 이상있는 단어만 추가,
  • vectors=임베딩 벡터)
class RNNCell_Encoder(nn.Module):
    def __init__(self, input_dim, hidden_size):
        super(RNNCell_Encoder, self).__init__()
        self.rnn = nn.RNNCell(input_dim, hidden_size)

    def forward(self, inputs): #------ inputs는 입력 시퀀스로 (시퀀스 길이, 배치, 임베딩(seq,batch, embedding))의 형태를 갖습니다.
        bz = inputs.shape[1] #------ 배치를 가져옵니다.
        ht = torch.zeros((bz, hidden_size)).to(device)# ------ 배치와 은닉층 뉴런의 크기를 0으로 초기화
        for word in inputs:
            ht = self.rnn(word, ht) #------ ②
        return ht
def training(epoch, model, trainloader, validloader):
    correct = 0
    total = 0
    running_loss = 0

    model.train()
    for b in trainloader:
        x, y = b.text, b.label
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()
    epoch_loss = running_loss / len(trainloader.dataset)
    epoch_acc = correct / total

    valid_correct = 0
    valid_total = 0
    valid_running_loss = 0

    model.eval()
    with torch.no_grad():
        for b in validloader:
            x, y = b.text, b.label
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            valid_correct += (y_pred == y).sum().item()
            valid_total += y.size(0)
            valid_running_loss += loss.item()

    epoch_valid_loss = valid_running_loss / len(validloader.dataset)
    epoch_valid_acc = valid_correct / valid_total

    print('epoch: ', epoch,
          'loss: ', round(epoch_loss, 3),
          'accuracy:', round(epoch_acc, 3),
          'valid_loss: ', round(epoch_valid_loss, 3),
          'valid_accuracy:', round(epoch_valid_acc, 3)
          )
    return epoch_loss, epoch_acc, epoch_valid_loss, epoch_valid_acc
  • model.train() : train 모드로 변경하면 dropout 기능 활성화됨
  • with torch.no_grad(): 기울기 계산 끄기
  • y_pred = torch.argmax(y_pred, dim=1) 최대값의 인덱스 반환
  • valid_correct += (y_pred == y).sum().item() 맞은 수 더하기
  • model.eval(): evaluation 모드로 변경

RNN 계층 네트워크

모델

class BasicRNN(nn.Module):
    def __init__(self, n_layers, hidden_dim, n_vocab, embed_dim, n_classes, dropout_p = 0.2):
        super(BasicRNN, self).__init__()
        self.n_layers = n_layers 
        self.embed = nn.Embedding(n_vocab, embed_dim) 
        self.hidden_dim = hidden_dim
        self.dropout = nn.Dropout(dropout_p)
        self.rnn = nn.RNN(embed_dim, self.hidden_dim, num_layers = self.n_layers, batch_first = True) 
        self.out = nn.Linear(self.hidden_dim, n_classes) 

    def forward(self, x):
        x = self.embed(x) 
        h_0 = self._init_state(batch_size = x.size(0)) 
        x, _ = self.rnn(x, h_0) 
        h_t = x[:, -1, :] 
        self.dropout(h_t)
        logit = torch.sigmoid(self.out(h_t))
        return logit

    def _init_state(self, batch_size = 1):
        weight = next(self.parameters()).data 
        return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_()
  • dropout 일부 뉴런을 비활성화

  • nn.RNN()

  • nn.Linear()에서 선형구조로 변환하여 최종 출력

  • forward 네트워크의 순전파 진행

  • 임베딩: 단어를 숫자로 변경

  • logit: 완전연결상태를 입력값으로 받아서 sigmoid를 적용하여 예측 logit을 반환

  • logit은 2진분류에서 출력값(0, 1)으로 사건이 일어날 확률

loss, optimizer 세팅

model = BasicRNN(n_layers = 1, hidden_dim = 256, n_vocab = vocab_size, embed_dim = 128, n_classes = n_classes, dropout_p = 0.5)
model.to(device)

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)

학습

def train(model, optimizer, train_iter):
    model.train()
    for b, batch in enumerate(train_iter):
        x, y = batch.text.to(device), batch.label.to(device)
        y.data.sub_(1)
        optimizer.zero_grad()

        logit = model(x)
        loss = F.cross_entropy(logit, y)
        loss.backward()
        optimizer.step()

        if b % 50 == 0:
            print("Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format(e,
                                                                           b * len(x),
                                                                           len(train_iter.dataset),
                                                                           100. * b / len(train_iter),
                                                                           loss.item()))
  • y.data.sub_(1) 레이블 값을 1씩 감소 시켜서 덮어쓰기
  • 앞에서 IMDB의 레이블의 경우 긍정은 2, 부정은 1의 값을 갖는다고 했음
  • y.data에서 1을 뺀다는 것은 레이블 값을 0과 1로 변환하겠다는 의미
def evaluate(model, val_iter):
    model.eval()
    corrects, total, total_loss = 0, 0, 0

    for batch in val_iter:
        x, y = batch.text.to(device), batch.label.to(device)
        y.data.sub_(1) 
        logit = model(x)
        loss = F.cross_entropy(logit, y, reduction = "sum")
        total += y.size(0)
        total_loss += loss.item()
        corrects += (logit.max(1)[1].view(y.size()).data == y.data).sum()
        
    avg_loss = total_loss / len(val_iter.dataset)
    avg_accuracy = corrects / total
    return avg_loss, avg_accuracy
  • evaluate 모드로 바꿔서 dropout 해제
  • 맞은 수, 전체, 손실값을 0으로 초기화
  • val_iter에서 배치만큼 돌림
  • 장치에서 x, y 값 가져오기
  • inplace 연산을하여 레이블 값을 0,1로 변환
  • 모델에 집어넣어서 logit 값구함
  • cross entropy loss를 구하는데 (logit과 y의 차이) sum은 모든 오차값을 합한다는 뜻
  • total은 배치에서 전체 누적
  • loss item은 손실값을 계속 누적
  • logit.max(1)[1] => 최댓값의 인덱싱
  • view()는 텐서를 y.size()로 reshape
  • 텐서끼리 비교해서 맞은 개수만큼 sum()함
반응형

'Education > ICT AI 중급' 카테고리의 다른 글

4주차_17 필기 (LSTM)  (0) 2023.10.15
4주차_15 필기 (ResNet)  (0) 2023.10.15
4주차_14 필기 (VGGNet)  (0) 2023.10.15
3주차_13 필기 (LeNet, Alexnet)  (0) 2023.10.15
3주차_12 필기 (전이학습)  (1) 2023.10.15