TIL Day 25 CNN & RNN

polaris·2024년 10월 17일

TIL

목록 보기
31/43

CNN & RNN

CNN

합성곱 신경망(Convolutional neural network)
이미지와 같은 2차원 데이터의 특징을 효과적으로 추출

개요

  • 풀링 층(Pooling)
  • 완전 연경층(Fully Connected Layer)
    • CNN은 출력에 적합하지 않음, ANN으로 출력

ANN 과의 차이점

  • 이미지 데이터를 ANN에 입력할 경우 데이터가 거대해짐
    • 예시) 1000 x 1000 이미지 -> 1 x 1000000 데이터
  • 이미지의 경우 픽셀들이 연관성을 가지고 있어서 변환되면 연관이 깨짐
    • 예시) 강아지의 귀 부분을 구성하는 여러 픽셀

합성곱 연산의 원리와 필터의 역할

  1. 합성곱 연산
  • 필터와 이미지의 픽셀을 곱하여 특징 맵 생성
  • 필터는 각각 edge, corner, texture 등 다양한 국소적 패턴을 학습
  1. Pooling Layer
  • 특징 맵의 크기를 줄이고 중요한 특징을 추출
  • Max Pooling : 필터 크기 내에서 최대 값을 선택
    • 중요한 특징을 강조, 불필요한 정보 제거
  • Average Pooling : 평균 값
    • 특징 맵의 크기를 줄임, 정보의 손실 최소화
  1. stride : 필터의 움직임
  2. padding
  • CNN 처리를 거듭했을 때 이미지가 너무 작아지는 경우 대비
  • 다양한 값을 넣어 레이어가 깊어졌을 때 이미지 크기가 너무 작아지는 것 방지
  1. CNN 아키텍쳐
  • LeNet : 최초, 손글씨 숫자 인식 / 합성곱 - 풀링 - 완전연결
  • AlexNet : ReLU 활성화 함수, dropout 도입하여 성능향상
  • VGG : 깊고 규칙적인 구조, 3x3 필터 사용하여 깊이 증가 ,VGG16, VGG19

MNIST 데이터 예제

모듈 import

import torch # 핵심 라이브러리
import torch.nn as nn # neural networks 신경망 구성
import torch.optim as optim # 최적화(함수를 최소 또는 최대로 맞추는 변수를 찾는 것)
import torchvision # 이미지 처리
import torchvision.transforms as transforms # 이미지 처리 전처리

데이터셋 전처리

transform = transforms.Compose([
    # 
    transforms.ToTensor(),
    # 이미지를 Tensor(파이토치 자료구조)로 전환
    transforms.Normalize((0.5,), (0.5,)) 
    # 이미지 정규화(평균, 표준편차)
    ])

# MNIST 데이터셋 로드
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
# 경로 # train(학습용) 데이터셋 여부 # 다운로드 여부 #transform 전달-전처리한 상태로
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
# 토치.유틸.데이터 기능.데이터 로더(데이터 셋, batch_size(쪼갠단위로 학습), suffle(섞어서 쪼갬))

testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)

for (X_train, Y_train) in trainloader:
    print(f"X_train: {X_train.size()} type: {X_train.type()}")
    print(f"Y_train: {Y_train.size()} type: {Y_train.type()}")
    break
# batch_size, channel, width, height
# X_train: torch.Size([64, 1, 28, 28]) type: torch.FloatTensor
# Y_train: torch.Size([64]) type: torch.LongTensor

모델 설정

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, padding=1)  
        # 입력 채널(1: 흑백, 3: RGB), 출력 채널(입력채널과 별도), 커널(필터) 크기 3x3
        self.pool = nn.MaxPool2d(2, 2)               
        # 풀링 크기 2x2 # kernel, stride
        # Pooling 크기가 (2, 2) 라면 출력 데이터 크기는 입력 데이터의 행과 열 크기를 2로 나눈 몫
        self.conv2 = nn.Conv2d(32, 64, 3, padding=1) 
        # 입력 채널(이전 출력 채널과 동일) 32, 출력 채널 64, 커널 크기 3x3
        self.fc1 = nn.Linear(64 * 7 * 7, 512)        # 완전 연결 층
        self.fc2 = nn.Linear(512, 10)                # 출력 층 (10개의 클래스)
        # ANN 레이어 여러개 사용 가능

    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))
        x = self.pool(torch.relu(self.conv2(x)))
        x = x.view(-1, 64 * 7 * 7)  # 플래튼 # ANN에 전달하기 위해 변환
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

모델 초기화, 학습

model = SimpleCNN()

# 손실 함수와 최적화 알고리즘 정의
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 최적화, lr- 학습률(적당히 작은값), momentum - 치후 설명

# 모델 학습
for epoch in range(10):  # 10 에포크 동안 학습
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data

        # 기울기 초기화
        optimizer.zero_grad()

        # 순전파 + 역전파 + 최적화
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        # 업데이트를 진행할 방향, 기울기를 찾는 과정
        optimizer.step()
        # 기울기를 바탕으로 가중치를 업데이트
        
        # 손실 출력
        running_loss += loss.item()
        if i % 100 == 99:  # 매 100 미니배치마다 출력
            print(f'[Epoch {epoch + 1}, Batch {i + 1}] loss: {running_loss / 100:.3f}')
            running_loss = 0.0

print('Finished Training')

모델 평가

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
# Accuracy of the network on the 10000 test images: 99.27%

RNN

순환 신경망(Recurrent Neural Network)
시계열 데이터나 순차적인 데이터를 처리 = 시퀀스 데이터

기본 구조와 동작 원리

  1. 기본 구조와 작동 방식

기본 구조

  • 이전 시간 단계의 정보를 현재 시간 단계로 전달
  • 시퀀스 데이터의 패턴을 학습

다른 모델: [내 이름은] -> 분석
          [코난] -> 분석
            [탐정이죠] -> 분석

RNN : [내 이름은] -> 분석
        [(내 이름은) 코난] -> 분석
          [(내 이름은 코난)탐정이죠] - > 분석
# () = 은닉 데이터
# 모든 시점의 데이터에서 분석
# 역전파 - 모든 시점의 가중치를 업데이트

동작 원리

  • 순환구조
    • 입력 데이터 + 이전 시간 단계의 은닉 데이터
    • 현재 시간 단계의 은닉 상태 출력
    • 시퀀스 정보를 저장, 다음 시간 단계로 전달
  • 동작 원리
    • 각 시간 단계에서 동일한 가중치 공유
    • 시퀀스 학습
    • 순전파(Foward Propagation)
    • 역전파(BPTT): Backpropagation Through Time
      • 기존 역전파: Backpropagation

LSTM & GRU

  • gate를 이용해 정보를 체계적으로 관리

장기 의존성 문제(long-term dependency problem)

  • 시퀀스 데이터는 특성상 데이터가 방대
  • 학습 과정에서 소실되는 데이터 발생
  • 방대한 데이터의 학습 과정에서 기울기 소실 문제 발생

LSTM(Long Short-Term Memory)

  • cell state: 각 시점 정보의 흐름 저장, 장기적으로 유지
  • gate: 정보를 선택적으로 저장하거나 삭제
  • input gate: 새로운 정보와 이전 정보가 결합해서 cell 얼마나 반영될지 경정
  • reset gate: cell에서 지울 정보 선택
  • output gate: cell + 입력 데이터 = 출력

GRU(Gated Recurrent Unit)

  • hidden state 만 활용(cell과 hidden state 결함)
  • reset gate: 이전 정보를 얼마나 무시할지
  • update gate: 새로운 정보를 얼마나 반영할지

차이점

  • LSTM 은 cell 과 hidden state 모두 사용, 복잡한 gate
  • GRU는 hidden state만 사용, 간단한 gate 구조
  • GRU가 계산 비용이 적고, 학습이 빠를 수 있음

유의점

  • RNN은 역전파를 통해 가중치를 업데이트
  • LSTM과 GRU의 경우 gate도 가중치로 역할, 학습에 포함

RNN 시계열 데이터 처리

  • 주식 가격 예측, 날씨 예측, 텍스트 생성
  1. 데이터 전처리
  • 데이터를 적절한 형태로 변환
  • 정규화(nomalization)
    • 데이터의 성격에 따라 방법이 다름
  • 입력 시퀀스와 출력 시퀀스 정의
  1. 모델 구축
  • 모델 정의
  • 입력 크기, 은닉 상태 크기, 출력 크기 등 설정
  1. 모델 학습
  • 손실 함수, 최적화 알고리즘 정의
  • 순전파와 역전파를 통해 모델을 학습
  1. 모델 평가
  • 테스트 데이터를 사용하여 모델의 성능을 평가

sine 데이터 예제

모듈 import

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
# 시각화 도구

sine 데이터 생성

# Sine 함수 데이터 생성
def create_sine_wave_data(seq_length, num_samples):
    X = []
    y = []
    for _ in range(num_samples):
        start = np.random.rand()
        x = np.linspace(start, start + 2 * np.pi, seq_length)
        X.append(np.sin(x))
        y.append(np.sin(x + 0.1))
    return np.array(X), np.array(y)

seq_length = 50
num_samples = 1000
X, y = create_sine_wave_data(seq_length, num_samples)

# 데이터셋을 PyTorch 텐서로 변환 / tensor = 기울기를 계산 할 수 있는 데이터 형태
X = torch.tensor(X, dtype=torch.float32).unsqueeze(-1)
y = torch.tensor(y, dtype=torch.float32).unsqueeze(-1)

RNN 모델 설정

class SimpleRNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleRNN, self).__init__()
        self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size) # 출력 레이어이기 때문에 output_size를 정해줌

    def forward(self, x):
        h0 = torch.zeros(1, x.size(0), hidden_size)  # 초기 은닉 상태/제일 처음의 값은 은닉 상태가 없기 떄문에 지정해중
        out, _ = self.rnn(x, h0)
        out = self.fc(out) # 전체
        # out = self.fc(out[:, -1, :])  # 마지막 시간 단계의 출력
        return out

input_size = 1
hidden_size = 32
output_size = 1
model = SimpleRNN(input_size, hidden_size, output_size)

LSTM 모델 설정

class SimpleLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleLSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h0 = torch.zeros(1, x.size(0), hidden_size)  # 초기 은닉 상태
        c0 = torch.zeros(1, x.size(0), hidden_size)  # 초기 셀 상태
        # RNN 모델 에 초기 셀 상태 추가
        out, _ = self.lstm(x, (h0, c0)) # 셀 상태 추가
        out = self.fc(out[:, -1, :])  # 마지막 시간 단계의 출력
        return out

model = SimpleLSTM(input_size, hidden_size, output_size)

모델 초기화, 학습

# 손실 함수와 최적화 알고리즘 정의
criterion = nn.MSELoss()
# 평균 제곱 오차 손실함수
optimizer = optim.Adam(model.parameters(), lr=0.01)
# ADAM 최적화 방식

# 모델 학습
num_epochs = 100
for epoch in range(num_epochs):
    outputs = model(X)
    optimizer.zero_grad() 
    # 이전 단계에서 계산된 기울기 초기화
    loss = criterion(outputs, y)
    loss.backward()
    # 역전파를 통한 기울기 계산
    optimizer.step()
    # 가중치 업데이트

    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

print('Finished Training')

모델 평가

# 모델 평가
model.eval()
with torch.no_grad():
    predicted = model(X).detach().numpy()

# 시각화
plt.figure(figsize=(10, 5))
plt.plot(y.numpy().flatten()[:100], label='True')
plt.plot(predicted.flatten()[:100], label='Predicted')
plt.legend()
plt.show()

0개의 댓글