[SK쉴더스 루키즈 24기] 머신러닝 기초(5) CNN, DCNN, RNN

아굥·2024년 12월 30일
1

SK Shieldus Rookies

목록 보기
12/32

CNN 개념과 원리

1. 기초 딥러닝의 문제점

① 복잡한 데이터 처리 한계: 초기 신경망은 입력 데이터가 고정된 크기와 구조를 가져야만 했음
ㄴ> 이미지, 텍스트, 시계열 데이터와 같은 복잡한 데이터에 대한 처리 능력 부족
② 비선형 패턴 학습의 부족: 단순한 모델에서는 비선형 관계나 복잡한 패턴을 학습하기 어려움
ㄴ> 은닉층이 부족하거나 활성화 함수가 비효율적이면 모델의 표현력 제한
③ 과적합: 복잡한 문제를 해결하기 위해 뉴런 수를 늘리면 -> 훈련 데이터에 지나치게 적합하여 일반화 성능 감소
④ 기울기 소멸: 역전파 알고리즘에서 기울기가 작어져, 초깊은 신경망의 가중치 업데이트가 어려움
⑤ 연산량 문제: 계산량과 메모리 사용량이 매우 큼 -> 학습 속도 감소, 모델 학습 어려움

=> 이를 위해 등장한 것이 CNN, RNN, DNN

1) CNN(합성곱 신경망, Convolutional Neural Network)이란?

이미지 데이터의 공간적 패턴을 효율적으로 처리하기 위해 설계

특징

  • 공간적 패턴 학습: 이미지 입력 시 위치 정보와 패턴을 유지
  • 효율성: 풀링을 통해 데이터 크기 줄이고 계산량 감소
  • 다양한 적용 분야

개선된 점

  • 지역 연결: 이미지의 일부 영역만 처리하여 중요한 지역적 특징을 학습 -> 전체 데이터 처리 X, 연산량 감소
  • 가중치 공유: 같은 필터를 이미지 전체에서 사용 -> 학습해야 할 가중치의 수가 감소
  • 공간 불변성: 위치나 크기가 약간 달라져도 동일한 패턴을 학습 가능

2) RNN(순환 신경망, Recurrent Neural Network)이란?

순서와 시간 의존성이 중요한 데이터를 처리하기 위해 설계

개선된 점

  • 기억 능력: 은닉 상태를 통해 이전 데이터를 현재 학습에 활용
  • 순서 정보 학습: 시간적 관계를 고려해 데이터의 흐름을 이해
  • 반복 구조: 출력값이 다시 입력으로 연결 -> 데이터의 연속성 학습 가능

3) DNN(심층 신경망, Deep Neural Network)이란?

기존 신경망의 표현력 부족 문제를 해결하기 위해 여러 은닉층을 쌓은 심층 구조 등장

개선된 점

  • 비선형 학습: 여러 은닉층과 활성화 함수를 통해 비선형 관계 학습 가능
  • 표현 학습: 사람이 직접 특징을 설계할 필요 X, 데이터에서 중요한 패턴을 자동 학습
  • 모듈화 가능성: 특정 문제에 맞는 구조로 쉽게 확장 가능

2. CNN의 구성 요소

1) Convolution Layer (합성곱 층)

  • 이미지에서 특정 패턴(특징)을 찾아내는 역할
    ㄴ> 이미지: 픽셀 값으로 이루어진 행렬(2D 배열)
  • 작은 필터(or 커널)가 이미지 위를 이동하여 특정 패턴을 추출

2) Pooling Layer (풀링 층)

  • 이미지의 크기를 줄이고 중요한 정보를 유지하는 역할
  • 데이터의 차원을 축소 -> 계산량 감소, 과적합을 방지
    ㄴ> 보통 Max Pooling(최대값 추출)과 Average Pooling(평균값 추출)을 사용

3) Fully Connected Layer (완전 연결 층)

  • 추출된 특징을 기반으로 최종 결과를 분류하거나 예측하는 역할
  • 합성곱 층과 풀링 층에서 학습한 정보를 활용하여 클래스(종류)를 구분
    ㄴ> 마지막 출력층에서 각 클래스의 확률 값 계산

3. CNN의 구조와 처리 흐름

1) 입력(Input)

  • 이미지 데이터를 입력 -> 픽셀로 이루어진 2D/3D 배열

2) 합성곱 층 (Convolution Layer)

  • 이미지에서 특정 패턴(선, 모서리, 질감)을 자동 추출
  • 필터와 입력 데이터의 값이 곱해진 합(점곱, convolution)을 계산하여 특징 맵 생성

처리 흐름

① 작은 크기의 필터(3x3, 5x5 등)가 이미지 위를 한 칸씩 이동
② 각 필터는 이미지의 특정 패턴(ex. 수직선, 수평선)을 탐지
③ 결과로 생성된 값들이 새로운 행렬(특징 맵)을 생성

3) 활성화 함수 (Activation Function)

  • 특징 맵의 비선형성을 추가, 중요하지 않은 값을 제거함
    ㄴ> 주로 ReLU를 사용 (음수 값 -> 0 변환)
  • 이를 통해 학습 과정에서 비선형 관계를 학습함

4) 풀링 층 (Pooling Layer)

  • 데이터 크기를 줄이고(차원 축소) 주요 정보를 유지
    ㄴ> Max Pooling : 영역 내에서 가장 큰 값을 선택
    ㄴ> Average Pooling : 영역 내 값들의 평균을 계산

처리 흐름

① 풀링 필터(2x2, 3x3 등)가 이미지 위를 이동하며 각 영역의 값을 축소
② 데이터 크기를 줄여 계산 효율성을 높이고 과적합을 방지

5) 완전 연결 층 (Fully Connected Layer)

  • 추출된 특징을 기반으로 최종 분류나 예측 수행
    ㄴ> Flatten: 특징 맵을 1D 벡터로 변환
    ㄴ> Dense Layer: 1D 벡터를 이용하여 예측 결과 생성
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

# 1. 데이터 전처리
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 데이터 정규화 및 차원 변경, 인코딩
x_train = x_train / 255.0
x_test =  x_test / 255.0

x_train = x_train.reshape(-1, 28, 28, 1)
x_test = x_test.reshape(-1, 28, 28, 1)

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

# 2. 모델 정의 및 레이어 추가
# CNN 모델 정의
model = Sequential()

# 첫 번째 합성곱 레이어와 활성화 함수
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)))

# 최대 풀링 레이어
model.add(MaxPooling2D(pool_size=(2, 2)))

# 두 번째 합성곱 레이어와 최대 풀링 레이어
model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

# 평탄화 레이어 (Fully Connected 레이어에 입력하기 위해 1차원으로 변환)
model.add(Flatten())

# 완전 연결층과 출력층
model.add(Dense(128, activation='relu')) 		# 은닉층
model.add(Dense(10, activation='softmax')) 		# 출력층 (10개 클래스)

# 모델 요약
model.summary()

# 3. 모델 컴파일
model.compile(optimizer='adam',
            loss='categorical_crossentropy',
            metrics=['accuracy'])

# 모델 학습
history = model.fit(x_train, y_train, epochs=10, batch_size=32, validation_split=0.2)

# 4. 데이터 시각화
plt.figure(figsize=(12, 4))

# 정확도 그래프
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.title('Model Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()

# 손실 그래프
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title('Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()

plt.show()

# 5. 모델 평가
# 테스트 데이터로 성능 평가
test_loss, test_accuracy = model.evaluate(x_test, y_test)
print(f'테스트 손실: {test_loss}')
print(f'테스트 정확도: {test_accuracy}')

DCNN

기존 CNN을 확장한 형태, 모델의 깊이가 더 깊어진 합성곱 신경망

차이점

  • CNN: 몇 개의 합성곱 레이어와 풀링 레이어로 구성 -> 상대적으로 얕은 네트워크
  • DCNN: CNN 구조를 확장하여 수십, 수백 개의 레이어를 쌓은 심층 네트워크

모델 깊이가 깊어질수록 얻는 이점

  • 복잡한 특성 학습: 더 깊은 레이어는 데이터의 고차원 특징을 학습 -> 복잡한 패턴을 더 잘 인식함
  • 성능 향상: 데이터가 많을수록 깊은 네트워크가 더 높은 정확도 제공
  • 추론 능력 강화: 심층 네트워크는 다양한 데이터 변형에도 강함

1. DCNN의 구성 요소

1) 합성곱 층 (Convolution Layer)

  • 입력 이미지에서 작은 영역을 활용하여 특징 추출
  • 동작: 필터(커널)가 입력 데이터를 슬라이딩하며 작은 영역에서 연산을 수행
    ㄴ> 필터는 특정 특징을 감지하도록 학습
  • 출력: 특징 맵, 입력 데이터의 변형된 형태

2) 풀링 층 (Pooling Layer)

  • 이미지의 공간 크기를 줄이고 중요한 정보를 출력하며 계산량을 줄임 -> 과적합 방지
  • 동작: 흔한 방식은 맥스 풀링(Max Pooling), 작은 영역에서 최댓값 선택
  • 출력: 압축된 특징 맵

3) 완전 연결 층 (Fully Connected Layer)

  • 마지막으로 모든 뉴런을 연결하여 분류 수행
  • 동작: 모든 뉴런이 연결, 이전 레이어에서 학습된 특징을 활용해 결과를 도출
  • 출력: 클래스 확률 또는 결과값

4) 활성화 함수 (Activation Function)

  • 비선형성을 추가하여 더 복잡한 모델링이 가능하도록 만듬

5) 드롭아웃(Dropout)

  • 특정 뉴런을 임의로 비활성화하여 과적합 방지
  • 동작: 학습 과정에서 일부 뉴런을 무작위로 0 설정

2. DCNN 모델 구현

전이 학습

  • 사전 학습된 모델(이미 학습된 가중치와 구조)를 활용하여 새로운 작업에 적합하게 재학습하는 기법
  • Fine-Tuning: 사전 학습된 모델의 상위 레이어를 새 데이터에 맞게 조정, 일부 하위 레이어를 미세 조정하는 과정
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.applications import VGG16, ResNet50
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.utils import to_categorical

# 1. 데이터셋 준비
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

# 데이터 정규화 및 레이블 인코딩
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0

y_train = to_categorical(y_train, num_classes=10)
y_test = to_categorical(y_test, num_classes=10)

# 2. 사전 학습된 VGG16 모델 로드
vgg16_base = VGG16(weights='imagenet',
                   include_top=False,
                   input_shape=(32, 32, 3))

# 모델의 가중치 고정
vgg16_base.trainable = False

# 3. 새로운 모델 정의
model = models.Sequential([
    vgg16_base,                             	# 사전 학습된 VGG16 모델
    layers.Flatten(),                       	# 평탄화: 다차원 데이터를 1차원으로 변환
    layers.Dense(256, activation='relu'),   	# Fully Connected Layer 추가, 256개의 뉴런 사용
    layers.Dropout(0.5), 
    layers.Dense(10, activation='softmax')  	# CIFAR-10 클래스에 맞는 출력, 10개의 뉴런과 softmax 활성화 함수
])

# 모델 컴파일
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# 4. 모델 학습
history = model.fit(x_train, 
                    y_train, 
                    validation_data=(x_test, y_test), 
                    epochs=5, 
                    batch_size=32)

# 5. Fine-Tuning (세부 조정)
for layer in vgg16_base.layers[-4:]:
    layer.trainable = True

# 모델 재컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5), loss='categorical_crossentropy', metrics=['accuracy'])

# Fine-Tuning 학습 진행
fine_tune_history = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=5, batch_size=64)

# 6. 모델 평가
loss, accuracy = model.evaluate(x_test, y_test)
print(f'테스트 손실: {loss}')
print(f'테스트 정확도: {accuracy}')

# 7. 모델 시각화
plt.plot(history.history['accuracy'], label='Initial Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Initial Validation Accuracy')
plt.plot(fine_tune_history.history['accuracy'], label='Fine-Tuning Training Accuracy')
plt.plot(fine_tune_history.history['val_accuracy'], label='Fine-Tuning Validation Accuracy')
plt.title('Model Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

RNN

순환 신경망, 시퀀스 데이터를 처리하고 학습하기 위해 설계된 딥러닝 모델

주요 특징

  • 순환 구조: 각 노드는 자신으로부터 출력된 결과를 다시 입력으로 받음 -> 시간의 흐름에 따라 데이터 처리
    ㄴ> 이전 시점의 정보를 기억하고 현재 시점 예측에 활용할 수 있음
  • 기억 능력: 이전 시점의 상태를 저장 -> 문맥을 이해하거나 패턴 학습
  • 시퀀스 데이터 처리: 자연어 처리, 주가 예측 등 연속적인 데이터를 처리하는데 적합

한계

  • 장기 의존성 문제: 긴 시퀀스에서 초반 정보가 사라지면 영향을 줄 수 없음
  • 기울기 소실: 역전파 중 기울기가 작아져 학습이 제대로 이루어지지 않을 수 있음

1. RNN의 구성 요소

1) 입력(Input)

  • 시간에 따라 변화하는 데이터

2) 순환 셀(Recurrent Cell)

  • 순환 신경망의 핵심, 입력과 이전 상태를 받아 새로운 상태 계산

3) 출력(Output)

  • 각 시점의 상태를 기반으로 최종 출력 yt 생성

2. RNN, LSTM, GRU 차이

  • RNN: 순환 신경망, 시퀀스 데이터를 다루기 위해 설계 -> 긴 시퀀스 학습에는 문제 발생할 수 있음
  • LSTM: RNN의 개선된 버전, 기울기 소실 문제 해결하며 장기 의존성 학습
  • GRU: LSTM보다 간단한 구조, 비슷한 성능을 제공하며 계산량이 적음
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN, LSTM, GRU, Dense, Embedding
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

# 1. 샘플 텍스트 데이터
data = """나는 오늘 기분이 좋아.
나는 내일도 기분이 좋을거야.
기분이 좋은 날엔 춤을 추고 싶어."""

# 2. 토근화 및 시퀀스 변환
tokenizer = Tokenizer()
tokenizer.fit_on_texts(data.split('\n'))
sequences = tokenizer.texts_to_sequences(data.split('\n'))

# 3. 단어 인덱스 확인
word_index = tokenizer.word_index
print('단어 인덱스: ', word_index)

# 4. 시퀀스를 학습 데이터로 변환
input_sequences = []
for sequence in sequences:
    for i in range(1, len(sequence)):
        input_sequences.append(sequence[:i+1])

# 5. 패딩 처리
max_len = max(len(x) for x in input_sequences)
input_sequences = pad_sequences(input_sequences,
                                maxlen=max_len,
                                padding='pre')

# 6. 입력(x)과 출력(y) 분리
x = input_sequences[:, :-1]
y = input_sequences[:, -1]

# 7. 출력(y)을 원-핫 인코딩
y = to_categorical(y, num_classes=len(word_index) + 1)

# 8. RNN 모델 정의
rnn_model = Sequential([
    Embedding(input_dim=len(word_index) + 1,
    output_dim=10,
    input_length=max_len - 1),                      # 임베딩 층
    SimpleRNN(64, return_sequences=False),          # RNN 층
    Dense(len(word_index) + 1, 
        activation='softmax')                       # 출력 층
])

# 모델 컴파일 및 학습
rnn_model.compile(loss='categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
rnn_model.fit(x, y, epochs=20, verbose=1)

# 9. LSTM 모델 정의
lstm_model = Sequential([
    Embedding(input_dim=len(word_index) + 1,
    output_dim=10,
    input_length=max_len - 1),                      # 임베딩 층
    LSTM(64, return_sequences=False),               # LSTM 층
    Dense(len(word_index) + 1,
    activation='softmax')                           # 출력 층
])

lstm_model.compile(loss='categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
lstm_model.fit(x, y, epochs=20, verbose=1)

# 10. GRU 모델 정의
gru_model = Sequential([
    Embedding(input_dim=len(word_index) + 1,
    output_dim=10,
    input_length=max_len - 1),                      # 임베딩 층
    GRU(64, return_sequences=False),                # GRU 층
    Dense(len(word_index) + 1,
    activation='softmax')                           # 출력 층
])

gru_model.compile(loss='categorical_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
gru_model.fit(x, y, epochs=20, verbose=1)

# 11. 텍스트 데이터 예제
def generate_text(model, tokenizer, seed_text, next_words, max_len):
    for _ in range(next_words):
        token_list = tokenizer.texts_to_sequences([seed_text])[0]
        token_list = pad_sequences([token_list], maxlen=max_len - 1, padding='pre')
        predicted = np.argmax(model.predict(token_list, verbose=0), axis=-1)
        for word, index in tokenizer.word_index.items():
            if index == predicted:
                seed_text += " " + word
                break
    return seed_text

# 12. 텍스트 생성 예제
seed_text = "나는 오늘"
print("RNN 생성 결과:", generate_text(rnn_model, tokenizer, seed_text, next_words=5, max_len=max_len))
print("LSTM 생성 결과:", generate_text(lstm_model, tokenizer, seed_text, next_words=5, max_len=max_len))
print("GRU 생성 결과:", generate_text(gru_model, tokenizer, seed_text, next_words=5, max_len=max_len))
profile
열심히 살아보아요

0개의 댓글