본문으로 건너뛰기
아인폴랩 교육 문의
← 블로그 목록
강화학습연재 2026.09.30

[강화학습 기초 4-2] 텐서플로로 첫 신경망 만들기

최신 텐서플로로 MNIST 손글씨 숫자 분류 신경망을 만들며, 강화학습 코드에도 그대로 쓰이는 구조를 익힙니다.

이번 편에서는 텐서플로로 손글씨 숫자(MNIST)를 맞히는 신경망을 직접 만들어 봅니다. 강화학습 코드도 결국 이 구조 위에 올라가므로, 여기서 흐름을 익혀 두면 6장의 DQN 코드가 훨씬 쉽게 읽힙니다.

실습 환경 준비

가장 쉬운 방법은 구글 코랩(Colab)입니다. 브라우저만 있으면 되고, 텐서플로가 이미 설치되어 있습니다. 내 PC에서 하려면 최신 파이썬을 설치한 뒤 아래 명령으로 필요한 패키지를 설치합니다.

pip install tensorflow gymnasium matplotlib notebook

책과 달라진 점

책은 파이썬 3.7, 텐서플로 2.2, OpenAI Gym 기준으로 쓰였습니다. 지금은 Gym 대신 후속 패키지인 Gymnasium을 쓰고, 텐서플로도 버전이 많이 올라갔습니다. 이 연재의 코드는 2026년 기준 최신 버전(텐서플로 2.21, Gymnasium 1.4)에서 실행을 확인했습니다.

텐서플로 2의 장점

텐서플로 1은 계산 그래프를 먼저 정의하고 따로 실행하는 방식이라 초보자가 이해하기 어려웠습니다. 텐서플로 2는 코드를 쓴 순서대로 바로 실행되고(즉시 실행 모드), Keras라는 고수준 API로 기능이 정리되어 구조가 단순합니다.

전체 코드

import tensorflow as tf

# 1. 데이터 불러오기 (훈련 60,000장, 검증 10,000장)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0   # 0~255 → 0~1로 맞추기

# 2. 신경망 구성
model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(28, 28)),
    tf.keras.layers.Flatten(),                        # 28×28 → 784
    tf.keras.layers.Dense(128, activation="relu"),    # 은닉층
    tf.keras.layers.Dense(10, activation="softmax"),  # 0~9 숫자별 확률
])

# 3. 학습 방법 정하기
model.compile(optimizer="adam",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])

# 4. 학습과 검증
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)

프로그램은 네 단계로 이루어집니다. 앞으로 볼 강화학습 코드도 같은 순서를 따릅니다.

1. 데이터 불러오기

MNIST는 28×28 크기의 손글씨 숫자 이미지 70,000장입니다. 60,000장은 훈련용, 10,000장은 검증용으로 나뉘어 있습니다. 나누는 이유는 공부한 문제집으로 시험을 보면 실력을 제대로 잴 수 없기 때문입니다. 픽셀 값(0~255)은 255로 나눠 0~1로 맞춰 주면 학습이 안정적입니다.

2. 신경망 구성

  • Flatten: Dense 층은 1차원 입력을 받으므로 28×28 이미지를 784개 숫자 한 줄로 펼칩니다.
  • Dense(128, relu): 노드 128개짜리 은닉층입니다. ReLU는 시그모이드처럼 비선형성을 더하는 활성 함수인데, 깊은 신경망에서 학습이 더 잘 됩니다. 노드 수는 정답이 없어서 바꿔 가며 찾습니다.
  • Dense(10, softmax): 숫자 0~9에 해당하는 출력 10개입니다. softmax는 출력값을 0~1로 바꾸고 합이 1이 되게 만들어, "이 이미지가 각 숫자일 확률"을 알려 줍니다.

3. 학습 방법 정하기

  • optimizer = "adam": 손실을 줄이는 방법입니다. 기본 경사하강법보다 빠르고 안정적이라 가장 많이 씁니다.
  • loss = "sparse_categorical_crossentropy": 정답이 0~9 같은 정수일 때 쓰는 분류용 손실 함수입니다. 회귀에서 쓴 MSE와 역할은 같고 계산 방식만 다릅니다.
  • metrics = ["accuracy"]: 학습 중에 정확도를 함께 보여 줍니다.

4. 학습과 검증

fit은 훈련 데이터로 학습합니다. epochs = 5면 60,000장을 다섯 번 반복해 봅니다. 화면에 epoch마다 loss(작을수록 좋음)와 accuracy(1에 가까울수록 좋음)가 출력됩니다. evaluate는 학습에 쓰지 않은 검증 데이터로 최종 정확도를 확인합니다.

코드 구성 요약

단계MNIST강화학습(DQN)에서는
데이터미리 준비된 이미지에이전트가 환경에서 행동하며 직접 모음
신경망이미지 → 숫자별 확률상태 → 행동별 Q값
손실크로스엔트로피목표 Q값과 예측 Q값의 MSE
학습fit 한 번모은 데이터로 조금씩 계속

다음 편에서는 신경망이 어떻게 강화학습의 가치함수를 대신하는지, 그 다리 역할을 하는 함수 근사를 봅니다.

교육과 컨설팅을 문의해 주세요

교육 대상과 일정을 알려 주시면 과정 제안과 강의계획서를 보내 드립니다.