🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

CNN과 전이 학습 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 4. · 11 Views

CNN과 전이 학습 완벽 가이드

합성곱 신경망(CNN)의 핵심 원리부터 전이 학습 활용법까지, 이미지 인식의 세계를 초급 개발자도 이해할 수 있도록 쉽게 풀어낸 가이드입니다. 실무에서 바로 적용할 수 있는 코드 예제와 함께 CNN의 모든 것을 배워봅니다.


목차

  1. 합성곱 신경망(CNN) 개요
  2. 컨볼루션 연산 이해
  3. 풀링과 스트라이드
  4. CNN 아키텍처 설계
  5. 생성적 적대 신경망(GAN)
  6. 전이 학습 활용하기
  7. 사례: 위조 문서 탐지

1. 합성곱 신경망(CNN) 개요

김개발 씨는 회사에서 이미지 분류 프로젝트를 맡게 되었습니다. 수천 장의 제품 사진을 자동으로 분류해야 하는 과제였습니다.

막막한 마음에 선배에게 조언을 구하자, 박시니어 씨가 말했습니다. "이미지 처리에는 CNN이 정석이에요.

한번 배워볼래요?"

**합성곱 신경망(CNN)**은 이미지를 이해하는 데 특화된 딥러닝 모델입니다. 마치 사람의 시각 피질이 이미지를 처리하는 방식을 모방한 것입니다.

이미지의 특징을 자동으로 추출하고 학습하여, 사진 속 물체가 무엇인지 분류할 수 있습니다. 전통적인 신경망과 달리 이미지의 공간적 구조를 보존하면서 학습합니다.

다음 코드를 살펴봅시다.

import tensorflow as tf
from tensorflow.keras import layers, models

# CNN 모델 기본 구조 정의
model = models.Sequential([
    # 합성곱 층: 이미지에서 특징을 추출합니다
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
    # 풀링 층: 특징 맵의 크기를 줄입니다
    layers.MaxPooling2D((2, 2)),
    # 두 번째 합성곱 층: 더 복잡한 특징을 추출합니다
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    # 완전 연결 층을 위해 평탄화합니다
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    # 출력 층: 10개 클래스로 분류합니다
    layers.Dense(10, activation='softmax')
])

김개발 씨는 입사 6개월 차 주니어 개발자입니다. 어느 날 팀장님이 새로운 프로젝트를 배정해 주셨습니다.

"우리 쇼핑몰에 올라오는 제품 사진을 자동으로 분류하는 시스템을 만들어 봐요." 김개발 씨는 고개를 끄덕였지만, 속으로는 막막했습니다. 이미지를 어떻게 분류한다는 걸까요?

선배 개발자 박시니어 씨가 커피를 건네며 다가왔습니다. "이미지 분류라면 CNN을 써야죠.

Convolutional Neural Network, 한국어로는 합성곱 신경망이라고 해요." 그렇다면 CNN이란 정확히 무엇일까요? 쉽게 비유하자면, CNN은 마치 돋보기로 그림을 살펴보는 미술 감정사와 같습니다.

감정사는 그림 전체를 한 번에 보지 않습니다. 작은 영역을 하나씩 살펴보면서 붓 터치의 특징, 색상의 변화, 선의 굵기 등을 파악합니다.

이런 세부 특징들을 종합해서 "이건 고흐의 작품이군요"라고 판단합니다. CNN도 마찬가지입니다.

이미지의 작은 영역들을 순차적으로 살펴보면서 특징을 추출합니다. CNN이 등장하기 전에는 어땠을까요?

전통적인 신경망은 이미지를 처리할 때 모든 픽셀을 일렬로 나열했습니다. 28x28 크기의 이미지라면 784개의 숫자로 펼쳐서 입력했습니다.

문제는 이렇게 하면 이미지의 공간적 정보가 사라진다는 것이었습니다. 고양이 귀가 어디에 있는지, 눈과 코의 위치 관계가 어떤지, 이런 정보가 모두 무시되었습니다.

더 큰 문제는 파라미터의 수였습니다. 224x224 컬러 이미지를 처리하려면 입력 뉴런만 15만 개가 넘었습니다.

학습해야 할 가중치가 기하급수적으로 늘어났고, 과적합 문제가 심각했습니다. 바로 이런 문제를 해결하기 위해 CNN이 등장했습니다.

CNN의 핵심 아이디어는 파라미터 공유입니다. 작은 필터 하나로 이미지 전체를 훑습니다.

같은 필터를 여러 위치에 적용하므로 학습해야 할 파라미터 수가 획기적으로 줄어듭니다. 또한 이미지의 공간적 구조를 보존합니다.

고양이가 사진 왼쪽에 있든 오른쪽에 있든, 같은 고양이로 인식할 수 있습니다. 위의 코드를 살펴보겠습니다.

먼저 Conv2D 층이 보입니다. 이것이 바로 합성곱 층입니다.

32개의 3x3 필터로 이미지를 훑으면서 특징을 추출합니다. 다음으로 MaxPooling2D 층이 나옵니다.

특징 맵의 크기를 절반으로 줄여 계산량을 줄이고 중요한 특징만 남깁니다. 이런 층들이 반복되면서 점점 더 추상적인 특징을 학습합니다.

실제 현업에서 CNN은 어디에 활용될까요? 가장 대표적인 사례가 이미지 분류입니다.

쇼핑몰의 상품 자동 분류, SNS의 사진 태깅, 의료 영상 진단 등 다양한 분야에서 활용됩니다. 자율주행 자동차도 CNN으로 도로 표지판과 보행자를 인식합니다.

얼굴 인식 잠금해제 기능도 CNN이 핵심입니다. 하지만 주의할 점도 있습니다.

CNN은 많은 양의 학습 데이터가 필요합니다. 데이터가 부족하면 과적합되기 쉽습니다.

또한 계산량이 많아 GPU 없이는 학습 시간이 매우 오래 걸립니다. 처음 시작하는 분들은 작은 데이터셋과 간단한 모델로 시작하는 것이 좋습니다.

다시 김개발 씨 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다.

"그래서 이미지 처리에 CNN을 쓰는 거군요!" 이제 첫 번째 관문은 통과했습니다.

실전 팁

💡 - 처음에는 MNIST나 CIFAR-10 같은 작은 데이터셋으로 연습하세요

  • GPU가 없다면 Google Colab을 활용하면 무료로 GPU를 사용할 수 있습니다
  • 모델 구조를 이해하기 위해 model.summary()로 각 층의 출력 크기를 확인해 보세요

2. 컨볼루션 연산 이해

김개발 씨가 CNN 코드를 따라 치다가 멈췄습니다. Conv2D 층에서 (3, 3) 필터가 뭔지 도무지 이해가 안 됐습니다.

선배에게 물어보니 박시니어 씨가 웃으며 말했습니다. "합성곱 연산은 CNN의 심장이에요.

이것만 이해하면 절반은 성공한 거예요."

컨볼루션(합성곱) 연산은 작은 필터로 이미지를 훑으면서 특징을 추출하는 과정입니다. 마치 돋보기를 이미지 위에서 슬라이딩하는 것과 같습니다.

필터의 값과 이미지 픽셀 값을 곱하고 더해서 새로운 값을 만들어냅니다. 이 과정을 통해 가장자리, 질감, 패턴 등 다양한 특징을 감지합니다.

다음 코드를 살펴봅시다.

import numpy as np
import tensorflow as tf

# 5x5 입력 이미지 (단순화된 예시)
image = np.array([
    [1, 2, 3, 0, 1],
    [0, 1, 2, 3, 1],
    [1, 2, 1, 0, 2],
    [2, 1, 0, 1, 1],
    [1, 0, 2, 1, 0]
], dtype=np.float32).reshape(1, 5, 5, 1)

# 3x3 에지 검출 필터 정의
edge_filter = np.array([
    [-1, -1, -1],
    [-1,  8, -1],
    [-1, -1, -1]
], dtype=np.float32).reshape(3, 3, 1, 1)

# 합성곱 연산 수행: 필터가 이미지 위를 슬라이딩합니다
output = tf.nn.conv2d(image, edge_filter, strides=[1, 1, 1, 1], padding='VALID')
print("합성곱 결과:\n", output.numpy().squeeze())

김개발 씨는 종이와 펜을 꺼냈습니다. 박시니어 씨가 말한 합성곱 연산을 직접 손으로 계산해 보기로 한 것입니다.

박시니어 씨가 옆에서 지켜보며 설명을 시작했습니다. "합성곱 연산을 이해하려면, 먼저 필터가 뭔지 알아야 해요.

커널이라고도 부르죠." 필터란 무엇일까요? 쉽게 비유하자면, 필터는 마치 특수 렌즈와 같습니다.

자외선 차단 렌즈를 쓰면 자외선만 걸러지듯이, CNN의 필터는 특정 패턴만 감지합니다. 가장자리를 찾는 필터, 수직선을 찾는 필터, 대각선을 찾는 필터 등 다양한 필터가 있습니다.

3x3 필터를 예로 들어보겠습니다. 필터 안에는 9개의 숫자가 들어 있습니다.

이 숫자들이 바로 학습을 통해 조정되는 가중치입니다. 합성곱 연산은 어떻게 이루어질까요?

박시니어 씨가 그림을 그려가며 설명했습니다. "필터를 이미지 왼쪽 위 모서리에 올려놓는다고 생각해 봐요.

필터가 덮고 있는 영역의 픽셀 값과 필터의 값을 각각 곱합니다. 그리고 그 결과를 모두 더합니다.

이게 바로 새로운 출력 값이에요." 구체적으로 계산해 보겠습니다. 이미지의 왼쪽 위 3x3 영역 값이 [1,2,3], [0,1,2], [1,2,1]이고, 필터가 [-1,-1,-1], [-1,8,-1], [-1,-1,-1]이라면, 각 위치의 값을 곱해서 더합니다.

1x(-1) + 2x(-1) + 3x(-1) + 0x(-1) + 1x8 + 2x(-1) + 1x(-1) + 2x(-1) + 1x(-1) = -3 + 8 - 6 = -1이 됩니다. 이 과정을 필터가 한 칸씩 옆으로 이동하면서 반복합니다.

필터가 이미지 전체를 훑고 나면 새로운 2차원 배열이 만들어집니다. 이것을 **특징 맵(Feature Map)**이라고 부릅니다.

위 코드에서 에지 검출 필터를 사용하면, 결과 특징 맵에서 값이 큰 곳이 바로 가장자리가 있는 위치입니다. CNN에서 필터는 학습을 통해 자동으로 만들어집니다.

우리가 필터 값을 직접 정할 필요가 없습니다. 신경망이 학습 데이터를 보면서 최적의 필터 값을 스스로 찾아냅니다.

고양이 사진을 많이 보면 귀의 모양을 감지하는 필터, 눈의 패턴을 감지하는 필터 등이 자동으로 만들어집니다. 왜 여러 개의 필터를 사용할까요?

하나의 필터로는 하나의 특징만 감지할 수 있습니다. 그래서 Conv2D(32, ...)처럼 32개, 64개, 128개 등 많은 필터를 동시에 사용합니다.

각 필터가 서로 다른 특징을 담당하면서, 이미지의 다양한 정보를 포착합니다. 김개발 씨가 고개를 끄덕였습니다.

"아, 그래서 특징을 자동으로 추출한다고 하는 거군요!" 박시니어 씨가 웃으며 답했습니다. "맞아요.

예전에는 이런 특징을 사람이 직접 설계했어요. CNN은 이걸 자동화한 거죠."

실전 팁

💡 - 필터 크기가 클수록 더 넓은 영역의 특징을 감지하지만, 계산량이 늘어납니다

  • 일반적으로 3x3 필터가 가장 널리 사용됩니다
  • 첫 번째 층의 필터는 단순한 특징을, 깊은 층의 필터는 복잡한 특징을 학습합니다

3. 풀링과 스트라이드

김개발 씨가 모델 구조를 분석하다가 이상한 점을 발견했습니다. 합성곱 층을 거칠 때마다 특징 맵의 크기가 작아지는 것이었습니다.

"왜 굳이 크기를 줄이는 거예요?" 박시니어 씨가 설명을 시작했습니다. "풀링과 스트라이드, 이 두 가지가 핵심이에요."

**풀링(Pooling)**은 특징 맵의 크기를 줄이는 다운샘플링 기법입니다. 마치 고해상도 사진을 저해상도로 축소하는 것과 비슷합니다.

**스트라이드(Stride)**는 필터가 한 번에 몇 칸씩 이동하는지를 결정합니다. 이 두 가지를 통해 계산량을 줄이고, 위치 변화에 강건한 모델을 만들 수 있습니다.

다음 코드를 살펴봅시다.

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np

# 4x4 특징 맵 예시
feature_map = np.array([
    [1, 3, 2, 4],
    [5, 6, 7, 8],
    [3, 2, 1, 0],
    [1, 2, 3, 4]
], dtype=np.float32).reshape(1, 4, 4, 1)

# MaxPooling: 2x2 영역에서 최댓값만 선택합니다
max_pool = layers.MaxPooling2D(pool_size=(2, 2))
pooled = max_pool(feature_map)
print("MaxPooling 결과:\n", pooled.numpy().squeeze())
# 결과: [[6, 8], [3, 4]] - 각 영역의 최댓값

# 스트라이드 2인 합성곱: 필터가 2칸씩 이동합니다
conv_stride = layers.Conv2D(1, (3, 3), strides=(2, 2), padding='same')
strided = conv_stride(feature_map)
print("스트라이드 2 결과 형태:", strided.shape)

김개발 씨는 모니터에 띄워진 모델 구조를 바라보며 생각에 잠겼습니다. 입력 이미지는 224x224인데, 몇 개 층을 거치니 7x7까지 줄어들어 있었습니다.

어떻게 이렇게 작아지는 걸까요? 박시니어 씨가 설명을 이어갔습니다.

"크기를 줄이는 데는 두 가지 방법이 있어요. 풀링과 스트라이드예요." 먼저 풀링에 대해 알아보겠습니다.

풀링은 마치 넓은 지역을 대표하는 시장님을 뽑는 것과 같습니다. 서울 전체를 대표하는 시장 한 명, 부산을 대표하는 시장 한 명.

수백만 명의 의견이 단 한 명으로 압축됩니다. 마찬가지로 풀링은 여러 픽셀 중 대표 값 하나만 선택합니다.

가장 흔히 쓰이는 것이 Max Pooling입니다. 2x2 Max Pooling을 예로 들어보겠습니다.

4개의 값 [1,3,5,6] 중에서 가장 큰 값인 6만 남깁니다. 이 과정을 전체 특징 맵에 적용하면, 크기가 절반으로 줄어듭니다.

8x8 특징 맵은 4x4로, 4x4는 2x2로 축소됩니다. 왜 최댓값을 선택할까요?

특징 맵에서 값이 크다는 것은 그 위치에서 특정 특징이 강하게 감지되었다는 뜻입니다. 최댓값을 선택하면 가장 중요한 특징만 살아남습니다.

작은 위치 변화에도 같은 최댓값이 선택되므로, 위치 불변성도 얻을 수 있습니다. 이제 스트라이드를 살펴보겠습니다.

스트라이드는 필터가 한 번에 몇 칸씩 이동하는지를 결정합니다. 기본값은 1입니다.

필터가 한 칸씩 옆으로 이동합니다. 스트라이드를 2로 설정하면 두 칸씩 건너뜁니다.

스트라이드가 2라면 출력 크기는 대략 절반이 됩니다. 8x8 입력에 스트라이드 2를 적용하면 4x4 출력이 나옵니다.

풀링과 비슷한 효과를 얻지만, 학습 가능한 파라미터가 있다는 점이 다릅니다. 그렇다면 풀링과 스트라이드 중 어느 것을 써야 할까요?

전통적으로는 풀링을 많이 사용했습니다. 하지만 최근 연구에서는 스트라이드가 있는 합성곱으로 풀링을 대체하는 경향이 있습니다.

학습 가능한 다운샘플링이 더 좋은 성능을 보이는 경우가 많기 때문입니다. 크기를 줄이는 것이 왜 중요할까요?

첫째, 계산량이 줄어듭니다. 224x224를 그대로 유지하면 연산이 기하급수적으로 늘어납니다.

둘째, 과적합을 방지합니다. 크기를 줄이면 모델이 세부 사항보다 전체적인 패턴에 집중합니다.

셋째, **수용 영역(Receptive Field)**이 넓어집니다. 깊은 층의 뉴런 하나가 원본 이미지의 더 넓은 영역을 볼 수 있게 됩니다.

김개발 씨가 메모를 마치며 말했습니다. "풀링으로 줄이든 스트라이드로 줄이든, 결국 중요한 건 핵심 정보만 남기는 거네요!" 박시니어 씨가 고개를 끄덕였습니다.

실전 팁

💡 - Max Pooling 외에 Average Pooling도 있지만, 일반적으로 Max Pooling이 더 좋은 성능을 보입니다

  • Global Average Pooling은 완전 연결 층 대신 사용되어 파라미터 수를 크게 줄입니다
  • 스트라이드 2인 합성곱은 풀링을 대체하는 현대적인 방법입니다

4. CNN 아키텍처 설계

김개발 씨가 직접 CNN 모델을 설계해 보기로 했습니다. 합성곱 층을 몇 개 쌓아야 할지, 필터 수는 얼마로 해야 할지 막막했습니다.

박시니어 씨가 화이트보드에 그림을 그리며 말했습니다. "좋은 아키텍처에는 패턴이 있어요.

역사적으로 검증된 구조들을 먼저 알아둬야 해요."

CNN 아키텍처는 합성곱 층, 풀링 층, 완전 연결 층을 어떻게 배치하느냐에 관한 설계입니다. LeNet에서 시작해 AlexNet, VGG, ResNet 등 역사적으로 중요한 아키텍처들이 있습니다.

일반적으로 깊어질수록 필터 수를 늘리고, 특징 맵 크기는 줄이는 패턴을 따릅니다.

다음 코드를 살펴봅시다.

from tensorflow.keras import layers, models

# VGG 스타일 아키텍처 설계
def build_vgg_style_model(input_shape=(224, 224, 3), num_classes=10):
    model = models.Sequential([
        # 블록 1: 64 필터, 2개의 합성곱 층
        layers.Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=input_shape),
        layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        layers.MaxPooling2D((2, 2)),

        # 블록 2: 128 필터, 필터 수가 2배로 증가합니다
        layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        layers.MaxPooling2D((2, 2)),

        # 블록 3: 256 필터, 더 복잡한 특징을 학습합니다
        layers.Conv2D(256, (3, 3), activation='relu', padding='same'),
        layers.Conv2D(256, (3, 3), activation='relu', padding='same'),
        layers.MaxPooling2D((2, 2)),

        # 분류기: 특징을 클래스로 변환합니다
        layers.Flatten(),
        layers.Dense(512, activation='relu'),
        layers.Dropout(0.5),  # 과적합 방지
        layers.Dense(num_classes, activation='softmax')
    ])
    return model

박시니어 씨가 화이트보드에 CNN의 역사를 그려나갔습니다. "아키텍처 설계를 이해하려면 먼저 역사를 알아야 해요." LeNet-5는 1998년 얀 르쿤이 만든 최초의 성공적인 CNN입니다.

손글씨 숫자 인식을 위해 설계되었습니다. 2개의 합성곱 층과 2개의 풀링 층, 그리고 완전 연결 층으로 구성되었습니다.

오늘날 기준으로는 매우 간단하지만, CNN의 기본 틀을 확립했습니다. 2012년, AlexNet이 ImageNet 대회에서 우승하며 딥러닝 혁명을 시작했습니다.

AlexNet은 LeNet보다 훨씬 깊고 컸습니다. 5개의 합성곱 층과 3개의 완전 연결 층을 사용했습니다.

ReLU 활성화 함수, 드롭아웃, 데이터 증강 등 현대적인 기법들이 처음 적용되었습니다. GPU를 활용한 학습도 이때부터 시작되었습니다.

VGG는 아키텍처 설계의 교과서입니다. VGG의 핵심 아이디어는 단순함입니다.

오직 3x3 필터만 사용합니다. 블록마다 같은 크기의 합성곱 층을 여러 개 쌓고, 풀링으로 크기를 줄입니다.

필터 수는 64에서 시작해 128, 256, 512로 두 배씩 증가합니다. 이 패턴은 오늘날에도 널리 사용됩니다.

위의 코드가 바로 VGG 스타일 아키텍처입니다. 블록 구조를 살펴보면 규칙성이 보입니다.

합성곱-합성곱-풀링 패턴이 반복됩니다. 깊어질수록 필터 수가 늘어납니다.

ResNet은 아키텍처의 또 다른 혁신이었습니다. VGG가 16층, 19층이었다면 ResNet은 무려 152층까지 쌓았습니다.

이것이 가능했던 이유는 잔차 연결(Skip Connection) 덕분입니다. 입력을 출력에 직접 더해주는 이 간단한 아이디어로, 그래디언트 소실 문제를 해결했습니다.

그렇다면 아키텍처를 설계할 때 무엇을 고려해야 할까요? 첫째, 점진적인 필터 증가입니다.

초기 층에서는 적은 필터로 저수준 특징을, 깊은 층에서는 많은 필터로 고수준 특징을 학습합니다. 둘째, 점진적인 크기 감소입니다.

풀링이나 스트라이드로 공간 크기를 줄여 계산 효율을 높입니다. 셋째, 정규화 기법입니다.

드롭아웃, 배치 정규화 등으로 과적합을 방지합니다. 하지만 처음부터 아키텍처를 직접 설계할 필요는 없습니다.

박시니어 씨가 강조했습니다. "실무에서는 검증된 아키텍처를 가져다 쓰는 경우가 훨씬 많아요.

바퀴를 다시 발명할 필요 없죠." 이것이 바로 뒤에서 배울 전이 학습의 핵심입니다. 김개발 씨가 메모를 정리하며 말했습니다.

"결국 좋은 아키텍처는 경험과 실험의 산물이네요." 박시니어 씨가 고개를 끄덕였습니다. "맞아요.

하지만 기본 원리를 알면 새로운 문제에도 적용할 수 있어요."

실전 팁

💡 - 처음에는 VGG 스타일의 단순한 구조로 시작하세요

  • 배치 정규화(BatchNormalization)를 합성곱 층 뒤에 추가하면 학습이 안정적입니다
  • 드롭아웃은 완전 연결 층에 주로 적용하고, 합성곱 층에는 적게 사용합니다

5. 생성적 적대 신경망(GAN)

어느 날 김개발 씨가 뉴스에서 신기한 기사를 보았습니다. "AI가 그린 그림이 경매에서 4억에 낙찰되었다." 도대체 AI가 어떻게 그림을 그린다는 걸까요?

박시니어 씨에게 물어보니 한마디로 답했습니다. "GAN이라고 들어봤어?

위조지폐범과 경찰의 대결 같은 거야."

**GAN(Generative Adversarial Network)**은 두 개의 신경망이 경쟁하며 학습하는 생성 모델입니다. **생성자(Generator)**는 가짜 데이터를 만들고, **판별자(Discriminator)**는 진짜와 가짜를 구분합니다.

이 둘의 경쟁을 통해 생성자는 점점 더 진짜 같은 데이터를 만들어냅니다. 이미지 생성, 스타일 변환 등 다양한 분야에 활용됩니다.

다음 코드를 살펴봅시다.

from tensorflow.keras import layers, models
import numpy as np

# 생성자: 랜덤 노이즈를 이미지로 변환합니다
def build_generator(latent_dim=100):
    model = models.Sequential([
        layers.Dense(256, input_dim=latent_dim),
        layers.LeakyReLU(0.2),
        layers.BatchNormalization(),
        layers.Dense(512),
        layers.LeakyReLU(0.2),
        layers.BatchNormalization(),
        layers.Dense(28 * 28 * 1, activation='tanh'),
        layers.Reshape((28, 28, 1))  # 이미지 형태로 변환
    ])
    return model

# 판별자: 이미지가 진짜인지 가짜인지 판별합니다
def build_discriminator():
    model = models.Sequential([
        layers.Flatten(input_shape=(28, 28, 1)),
        layers.Dense(512),
        layers.LeakyReLU(0.2),
        layers.Dense(256),
        layers.LeakyReLU(0.2),
        layers.Dense(1, activation='sigmoid')  # 진짜=1, 가짜=0
    ])
    return model

김개발 씨는 GAN이라는 개념이 신기하면서도 어렵게 느껴졌습니다. 박시니어 씨가 비유를 들어 설명하기 시작했습니다.

"GAN을 이해하려면 위조지폐범과 경찰의 이야기를 생각해 봐요." 위조지폐범은 진짜 같은 가짜 돈을 만들려고 합니다. 처음에는 솜씨가 서툴러서 누가 봐도 가짜입니다.

하지만 경찰에게 잡힐 때마다 어디가 잘못됐는지 피드백을 받습니다. 점점 실력이 늘어 진짜와 구분하기 어려운 위조지폐를 만들게 됩니다.

동시에 경찰도 성장합니다. 위조지폐범의 솜씨가 늘수록 경찰의 감별 능력도 향상되어야 합니다.

더 정교한 진위 판별 기술을 개발합니다. 이렇게 둘이 서로 경쟁하며 함께 성장하는 것이 GAN의 핵심입니다.

GAN에서 위조지폐범 역할을 하는 것이 **생성자(Generator)**입니다. 생성자는 랜덤 노이즈를 입력받아 이미지를 만들어냅니다.

처음에는 의미 없는 노이즈 같은 이미지가 나옵니다. 하지만 학습이 진행되면서 점점 진짜 같은 이미지를 생성합니다.

경찰 역할을 하는 것이 **판별자(Discriminator)**입니다. 판별자는 주어진 이미지가 진짜 데이터인지, 생성자가 만든 가짜인지 판별합니다.

1에 가까우면 진짜, 0에 가까우면 가짜라고 판단합니다. 판별자도 CNN 구조로 되어 있어 이미지의 특징을 분석합니다.

두 네트워크는 어떻게 학습할까요? 생성자는 판별자를 속이는 방향으로 학습합니다.

판별자가 가짜 이미지를 진짜라고 판단하면 생성자의 성공입니다. 판별자는 진짜와 가짜를 정확히 구분하는 방향으로 학습합니다.

이 둘의 손실 함수가 서로 적대적(adversarial)으로 설계되어 있습니다. 이론적으로 이 경쟁이 충분히 진행되면 균형 상태에 도달합니다.

생성자가 만든 이미지가 너무 진짜 같아서 판별자가 50% 확률로 찍어야 하는 상황이 됩니다. 이때 생성자는 진짜 데이터의 분포를 완벽히 학습한 것입니다.

GAN은 다양한 분야에서 활용됩니다. 이미지 생성이 가장 대표적입니다.

얼굴 사진 생성, 풍경 그림 생성, 애니메이션 캐릭터 생성 등이 가능합니다. 스타일 변환도 있습니다.

사진을 고흐 스타일의 그림으로 바꾸거나, 말을 얼룩말로 변환할 수 있습니다. 해상도 향상, 이미지 복원 등에도 활용됩니다.

하지만 GAN 학습은 쉽지 않습니다. 두 네트워크의 균형을 맞추기가 어렵습니다.

한쪽이 너무 강해지면 학습이 붕괴됩니다. 모드 붕괴(mode collapse)라는 문제도 있습니다.

생성자가 비슷한 이미지만 계속 생성하는 현상입니다. 이런 문제를 해결하기 위해 WGAN, StyleGAN 등 다양한 변형이 개발되었습니다.

김개발 씨가 감탄하며 말했습니다. "경쟁을 통해 학습한다니, 정말 창의적인 발상이네요!"

실전 팁

💡 - GAN 학습은 불안정하므로, 작은 학습률과 배치 정규화를 사용하세요

  • 판별자가 너무 강하면 생성자가 학습하지 못하고, 너무 약하면 생성자가 개선되지 않습니다
  • 처음에는 DCGAN 같은 안정적인 구조로 시작하는 것이 좋습니다

6. 전이 학습 활용하기

김개발 씨가 프로젝트 데드라인에 쫓기고 있었습니다. 제품 이미지 분류 모델을 만들어야 하는데, 학습 데이터가 천 장밖에 없었습니다.

처음부터 CNN을 학습시키려니 성능이 영 나오지 않았습니다. 박시니어 씨가 말했습니다.

"전이 학습을 써봐요. 거인의 어깨 위에 서는 거예요."

**전이 학습(Transfer Learning)**은 다른 작업에서 학습된 모델의 지식을 새로운 작업에 활용하는 기법입니다. ImageNet에서 수백만 장의 이미지로 학습된 모델을 가져와, 적은 데이터로도 높은 성능을 얻을 수 있습니다.

마치 영어를 잘하는 사람이 스페인어를 빨리 배우는 것과 같습니다.

다음 코드를 살펴봅시다.

from tensorflow.keras.applications import VGG16
from tensorflow.keras import layers, models

# 사전 학습된 VGG16 모델 불러오기 (ImageNet 가중치 사용)
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))

# 사전 학습된 가중치는 동결: 학습되지 않도록 설정
base_model.trainable = False

# 새로운 분류기 추가: 우리의 작업에 맞게 커스터마이징
model = models.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(10, activation='softmax')  # 10개 클래스 분류
])

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

# model.summary()로 구조 확인 가능

박시니어 씨의 말에 김개발 씨는 고개를 갸웃거렸습니다. "거인의 어깨라뇨?" 박시니어 씨가 비유를 들어 설명했습니다.

"뉴턴이 했던 말이에요. 자기가 멀리 볼 수 있었던 건 거인의 어깨 위에 서 있었기 때문이라고요.

전이 학습도 마찬가지예요. 다른 사람이 엄청난 노력으로 학습시킨 모델 위에 서는 거예요." 구체적으로 어떻게 작동할까요?

Google, Facebook 같은 대기업들은 수백만 장의 이미지와 수백 대의 GPU로 CNN을 학습시킵니다. ImageNet이라는 거대한 데이터셋에서 천 개 이상의 물체를 분류하도록 학습된 모델들이 있습니다.

VGG, ResNet, EfficientNet 등이 대표적입니다. 이렇게 학습된 모델의 초기 층들은 범용적인 특징을 담고 있습니다.

가장자리, 질감, 색상 패턴 같은 저수준 특징들입니다. 이 특징들은 고양이를 분류하든, 자동차를 분류하든, 의류를 분류하든 공통적으로 필요합니다.

굳이 처음부터 다시 학습할 필요가 없습니다. 전이 학습의 핵심은 가중치 동결입니다.

사전 학습된 모델의 가중치를 그대로 유지합니다. base_model.trainable = False로 설정하면 해당 층들은 학습되지 않습니다.

대신 맨 위에 새로운 분류기 층을 추가합니다. 이 분류기만 우리 데이터로 학습시킵니다.

왜 이것이 효과적일까요? 첫째, 데이터 효율성입니다.

수천 장이 아닌 수백 장으로도 좋은 성능을 얻을 수 있습니다. 둘째, 학습 시간 단축입니다.

전체 네트워크가 아닌 분류기만 학습하므로 빠릅니다. 셋째, 과적합 방지입니다.

사전 학습된 가중치가 좋은 초기값 역할을 합니다. 더 높은 성능이 필요하다면 **미세 조정(Fine-tuning)**을 할 수 있습니다.

처음에는 분류기만 학습하고, 어느 정도 수렴하면 base_model의 일부 층도 학습 가능하게 풀어줍니다. 이때는 아주 작은 학습률을 사용해야 합니다.

기존에 잘 학습된 가중치를 크게 망가뜨리지 않기 위해서입니다. 어떤 사전 학습 모델을 선택해야 할까요?

모델마다 특성이 다릅니다. VGG는 구조가 단순해 이해하기 쉽습니다.

ResNet은 깊어도 학습이 잘 됩니다. EfficientNet은 효율적인 구조로 높은 성능을 보입니다.

MobileNet은 가볍고 빨라 모바일 환경에 적합합니다. 김개발 씨가 전이 학습을 적용했더니 놀라운 일이 일어났습니다.

천 장의 데이터로 학습한 모델이 90% 이상의 정확도를 보였습니다. 처음부터 학습했을 때 50%에 불과했던 것에 비하면 엄청난 개선이었습니다.

"이렇게 쉬울 줄이야!" 김개발 씨가 감탄했습니다. 박시니어 씨가 웃으며 말했습니다.

"실무에서는 처음부터 학습하는 경우가 드물어요. 거의 항상 전이 학습부터 시작해요."

실전 팁

💡 - 데이터가 적을수록 전이 학습의 효과가 큽니다

  • 새로운 작업이 원래 작업(ImageNet)과 비슷할수록 더 많은 층을 동결해도 됩니다
  • 미세 조정 시에는 학습률을 기본의 1/10 ~ 1/100로 낮추세요

7. 사례: 위조 문서 탐지

김개발 씨의 회사에서 새로운 프로젝트가 시작되었습니다. 금융 서비스에서 제출되는 신분증과 서류의 위조 여부를 자동으로 판별하는 시스템이었습니다.

박시니어 씨가 말했습니다. "지금까지 배운 모든 것을 종합해 볼 때가 됐어요.

CNN, 전이 학습, 그리고 실무 노하우까지."

위조 문서 탐지는 CNN과 전이 학습이 실제로 활용되는 대표적인 사례입니다. 문서 이미지에서 위조 흔적을 자동으로 감지합니다.

픽셀 수준의 조작, 글자 폰트 불일치, 인쇄 패턴 이상 등을 분석합니다. 금융, 보험, 공공기관 등 다양한 분야에서 활용됩니다.

다음 코드를 살펴봅시다.

from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras import layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 위조 문서 탐지 모델 구축
def build_forgery_detector(num_classes=2):
    # EfficientNet 사전 학습 모델 사용
    base = EfficientNetB0(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
    base.trainable = False

    model = models.Sequential([
        base,
        layers.GlobalAveragePooling2D(),
        layers.BatchNormalization(),
        layers.Dense(256, activation='relu'),
        layers.Dropout(0.5),
        layers.Dense(128, activation='relu'),
        layers.Dropout(0.3),
        layers.Dense(num_classes, activation='softmax')  # 진짜/가짜 분류
    ])
    return model

# 데이터 증강: 다양한 변형으로 학습 데이터를 늘립니다
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=10,
    width_shift_range=0.1,
    height_shift_range=0.1,
    brightness_range=[0.9, 1.1],
    horizontal_flip=False  # 문서는 뒤집지 않습니다
)

김개발 씨는 프로젝트 킥오프 미팅에서 요구사항을 들었습니다. 하루에 수천 건의 문서가 제출되는데, 수작업 검토로는 한계가 있었습니다.

위조 문서가 간혹 통과되어 사고가 발생하기도 했습니다. 박시니어 씨가 화이트보드에 시스템 구조를 그렸습니다.

"크게 세 단계로 나눠볼게요. 전처리, 분류, 후처리." 첫 번째 단계는 전처리입니다.

문서 이미지를 모델이 처리할 수 있는 형태로 변환합니다. 크기를 224x224로 조정하고, 픽셀 값을 0~1 사이로 정규화합니다.

기울어진 문서는 자동으로 회전시켜 정렬합니다. 필요하다면 특정 영역(사진, 도장 등)만 잘라낼 수도 있습니다.

두 번째 단계는 분류 모델입니다. EfficientNet을 베이스로 사용합니다.

ImageNet에서 사전 학습된 가중치로 시작하여, 위조 문서 데이터로 미세 조정합니다. 출력은 두 클래스입니다.

진짜(genuine)와 가짜(forged). 왜 CNN이 위조 탐지에 효과적일까요?

위조 문서에는 미세한 흔적이 남습니다. 포토샵으로 수정한 영역은 주변과 질감이 미묘하게 다릅니다.

합성된 사진은 조명 방향이 불일치합니다. 글자를 복사-붙여넣기하면 픽셀 패턴이 다릅니다.

CNN은 이런 미세한 차이를 학습할 수 있습니다. 데이터 증강도 중요합니다.

위조 문서 샘플은 구하기 어렵습니다. 실제 위조 사례가 많지 않기 때문입니다.

데이터 증강으로 학습 데이터를 늘릴 수 있습니다. 회전, 이동, 밝기 조절 등을 적용합니다.

단, 문서 특성상 과도한 변형은 피합니다. 문서를 뒤집거나(horizontal_flip) 심하게 왜곡하면 의미가 달라질 수 있습니다.

세 번째 단계는 후처리입니다. 모델의 출력을 실제 업무에 적용하는 단계입니다.

단순히 진짜/가짜로 나누는 것이 아니라, 신뢰도 점수를 함께 제공합니다. 95% 이상 확신하면 자동 승인, 50~95%는 수동 검토, 50% 미만이면 자동 반려.

이런 식으로 단계를 나눌 수 있습니다. 실무에서 주의할 점도 있습니다.

편향 문제입니다. 특정 유형의 문서만 위조 사례로 학습하면, 다른 유형의 위조를 놓칠 수 있습니다.

다양한 위조 수법을 포함한 균형 잡힌 데이터셋이 필요합니다. 적대적 공격도 고려해야 합니다.

공격자가 모델을 속이기 위해 의도적으로 조작할 수 있습니다. 김개발 씨가 프로토타입을 완성했습니다.

테스트 결과, 수작업 검토 대비 처리 속도가 50배 빨라졌고, 탐지 정확도는 98%에 달했습니다. 물론 완벽하지는 않았습니다.

중요한 케이스는 여전히 사람이 최종 확인했습니다. 박시니어 씨가 김개발 씨를 칭찬했습니다.

"CNN부터 전이 학습, 실제 적용까지. 이제 제대로 된 딥러닝 개발자가 됐네요." 김개발 씨는 뿌듯하면서도 더 배울 것이 많다는 것을 알았습니다.

실전 팁

💡 - 위조 탐지 시스템은 완벽할 수 없으므로, 항상 사람의 최종 검토 단계를 포함하세요

  • 새로운 위조 수법이 등장하면 모델을 재학습해야 합니다. 지속적인 모니터링이 필요합니다
  • 민감한 데이터를 다루므로, 개인정보 보호와 보안에 특히 신경 쓰세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#CNN#TransferLearning#DeepLearning#ImageRecognition#Python,DL,CNN

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.