알고리즘

TensorFlow2.0으로 MNIST 숫자분류기 구현

WDmil 2024. 6. 14. 01:13
728x90
import tensorflow as tf

## 
# MNIST 데이터를 다운로드
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 이미지들을 float32 데이터 타입으로 변경
x_train, x_test = x_train.astype('float32'), x_test.astype('float32')
# 28*28 형태의 이미지를 784차원으로 flattening 한다.
x_train, x_test = x_train.reshape([-1, 784]), x_test.reshape([-1, 784])
# [0, 255] 사이의 값을 [0, 1] 사이의 값으로 Normalize한다.
x_train, x_test = x_train / 255., x_test / 255.
# 레이블 데이터에 one-hot encoding을 적용한다.
y_train, y_test = tf.one_hot(y_train, depth=10), tf.one_hot(y_test, depth=10)
## 데이터형태를 학습용 데이터로 재가공.

## 
# tf.data API를 이용해서 데이터를 섞고 batch 형태로 가져온다.
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.repeat().shuffle(60000).batch(100)
train_data_iter = iter(train_data)
## 원하는 배치로 데이터를 끊어서 더 효율적으로 사용

##
# tf.keras.Model을 이용해서 SoftMax Regression 모델을 정의한다.
class SoftmaxRegression(tf.keras.Model):
    def __init__(self):
        super(SoftmaxRegression, self).__init__()
        self.softmax_layer = tf.keras.layers.Dense(10,
                                                   activation=None,
                                                   kernel_initializer='zeros',
                                                   bias_initializer='zeros')
        
    def call(self, x):
        logits = self.softmax_layer(x)
        return tf.nn.softmax(logits)

## 케라스 서브클레싱 방식을 사용해서 생성자로, 
# 하위 API로 모델구조를 정의. call에는 인자값으로 인풋, 출력으로 반환으로 하여 %로 볼 수 있게함


## 
# cross-entropy 손실 함수를 정의한다.
@tf.function
def cross_entropy_loss(y_pred, y):
    return tf.reduce_mean(-tf.reduce_sum(y * tf.math.log(y_pred), axis=[1]))
## 학습가중치에 따른 불일치부분 확인용 손실함수 정의


# 최적화를 위한 그라디언트 디센트 옵티마이저를 정의
optimizer = tf.optimizers.SGD(0.5)

##
# 최적화를 위한 function을 정의.
@tf.function
def train_step(model, x, y):
    with tf.GradientTape() as tape:
        y_pred = model(x)
        loss = cross_entropy_loss(y_pred, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
## 그레이시언 디센트를 직접 수행하는 함수 정의

##
# 모델의 정확도를 출력하는 함수를 정의.
@tf.function
def compute_accuracy(y_pred, y):
    correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.argmax(y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    return accuracy
## 학습이 끝났을 때 정확도를 출력하는 함수


# SoftmaxRegression 모델을 선언
SoftmaxRegression_model = SoftmaxRegression()


## 
# 1000번 반복을 수행하면서 최적화를 수행.
for i in range(1000):
    batch_xs, batch_ys = next(train_data_iter)
    train_step(SoftmaxRegression_model, batch_xs, batch_ys)
## 학습부


# 학습이 끝나면 학습된 모델의 정확도를 출력
accuracy = compute_accuracy(SoftmaxRegression_model(x_test), y_test)
print("정확도(Accuracy): %f" % accuracy)
# 정확도 약 91%


코드 부분을 한부분씩 잘라서 이해해보자.

 

데이터 전처리

# MNIST 데이터를 다운로드
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 이미지들을 float32 데이터 타입으로 변경
x_train, x_test = x_train.astype('float32'), x_test.astype('float32')
# 28*28 형태의 이미지를 784차원으로 flattening 한다.
x_train, x_test = x_train.reshape([-1, 784]), x_test.reshape([-1, 784])
# [0, 255] 사이의 값을 [0, 1] 사이의 값으로 Normalize한다.
x_train, x_test = x_train / 255., x_test / 255.
# 레이블 데이터에 one-hot encoding을 적용한다.
y_train, y_test = tf.one_hot(y_train, depth=10), tf.one_hot(y_test, depth=10)

https://inradestrt.tistory.com/664

 

MNIST 데이터셋

머신러닝 모델을 학습시키기 위해서는 데이터가 필요하다.하지만 데이터 학습에 적합한 형태로 정제하는 것은 많은 시간과 노력이 필요한 일이다. 따라서 많은 연구자가 학습하기 쉬운 형태로

inradestrt.tistory.com

위 MNIST데이터셋을 다운로드하여 사용한다.

 

데이터타입을 float32형식으로 변환한다.

  • 이미지데이터는 기본적으로 uint8형식으로 되어있으나, 신경망 모델은 float32 타입의 데이터를 다루기 때문.

이미지 평탄화(Flattening)

  • MNIST이미지는 28x28픽셀 크기의 2D배열 형태이다. 이 이미지를 1D형태로 변환하여 신경만의 입력으로 사용하기 위해 평탄화(flatten)한다.

정규화(Normalize)

  • 이미지 픽셀값은 [0, 255](흑백) 값을 가지는데, 모델이 학습할 떄 더 빠르고 안정적으로 학습할 수 있도록 [0, 1] 사이로 정규화한다.

One-Hot 인코딩

  • 레이블 데이터는 0에서 9까지의 정수값이다. 이를 신경망 출력과 비교하기 쉽게 One-hot인코딩을 통해 이진벡터로 변환하여 키값을 레이블 해준다.

데이터셋 준비

# tf.data API를 이용해서 데이터를 섞고 batch 형태로 가져온다.
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.repeat().shuffle(60000).batch(100)
train_data_iter = iter(train_data)

 

데이터셋 생성

  • tf.data.Dataset.from_tensor_slices를 사용하여 x_train과 y_train 데이터를 TensorFlow데이터셋 으로 만든다.
    (API에 알맞게 데이터를 정리한다고 이해하면 된다)

반복 및 섞기(shuffle)

  • 데이터셋을 무작위로 섞어서 학습의 편향을 줄이고, 무한 반복하여 학습할 수 있도록 설정한다.
    (학습의 제한사항을 최대한 여유롭게 풀어준다고 이해하면 된다.)

배치 처리(batch(100))

  • 학습 속도를 높이고 메모리 효율성을 높이기 위해 데이터를 일정 크기의 배치로 나눈다. 여기서는 100개씩 묶는다.
    모델이 한번에 처리할 수 있는 적당한 크기의 데이터 덩어리를 만든다.

    한번에 모든 데이터를 학습하게 되면 너무 느리기 때문에, 부분부분씩 잘라서 학습한다고 생각하자.

이터레이터 생성

  • 학습 중에 매번 새로운 배치를 가져오기 위해 이터레이터를 생성한다.
    학습때 필요한 배치를 한개씩 꺼내쓰기 위해 연결고리를 만들어놓는다고 이해하자.

모델 정의

class SoftmaxRegression(tf.keras.Model):
    def __init__(self):
        super(SoftmaxRegression, self).__init__()
        self.softmax_layer = tf.keras.layers.Dense(10,
                                                   activation=None,
                                                   kernel_initializer='zeros',
                                                   bias_initializer='zeros')
        
    def call(self, x):
        logits = self.softmax_layer(x)
        return tf.nn.softmax(logits)

 

모델 클래스 정의

  • 사용자 정의 모델을 생성하기 위해 케라스의 서브클래싱 API를 이용한다.

Dense층 정의

  • 10개의 뉴런을 가진 Dense(완전 연결) 층을 추가한다. 각 뉴런은 하나의 클래스(0-9)를 예측하게 된다.
    입력데이터에 대해 각 클래스에 대한 점수를 계산하는 층이다.

가중치와 바이어스 초기화

  • 가중치와 바이어스를 0으로 초기화한다.
    초기값을 정의하여 학습을 통해 최적값을 찾는다.

출력 정의

  • Dense층의 출력을 Softmax 함수에 통과시켜 클래스 확률을 계산한다.
    각 분포 확률을 얻어 예측할 수 있도록 한다.

손실 함수 정의

@tf.function
def cross_entropy_loss(y_pred, y):
    return tf.reduce_mean(-tf.reduce_sum(y * tf.math.log(y_pred), axis=[1]))

 

손실 함수 정의

  • Cross-entropy 손실 함수는 예측값과 실제값 사이의 차이를 측정한다.
    모델의 예측이 실제값과 얼마나 다른지 평가하여 수정할 수 있도록 한다.

학습의 불일치 부분을 확인하고 모델의 성능을 향상시키기 위해 생성함.


옵티마이저 정의

optimizer = tf.optimizers.SGD(0.5)

옵티마이저 정의

  • 경사 하강법(SGD) 옵티마이저는 손실을 줄이기 위해 모델의 가중치를 업데이트 한다.

학습률(0.5)

  • 가중치를 업데이트 할 때의 스텝 크기를 결정한다.
    적절한 학습률을 통해 빠르고 안정적인 학습을 유도한다.

학습 단계 정의

@tf.function
def train_step(model, x, y):
    with tf.GradientTape() as tape:
        y_pred = model(x)
        loss = cross_entropy_loss(y_pred, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

 

학습 함수 정의

  • train_step함수는 한 번의 학습 단계에서 모델을 업데이트 한다.
    모델을 학습시키기 위한 모든 작업을 하나의 함수에 모음

GradientTape(tape.gradient(...))

  • 자동으로 미분을 계산하여 손실의 기울기를 추적한다.
    모델의 가중치를 업데이트하기 위함.

기울기 계산 및 적용(.apply_gradients(...))

  • 손실의 기울기를 계산하고 옵티마이저로 모델 가중치를 업데이트

정확도 계산 함수 정의

@tf.function
def compute_accuracy(y_pred, y):
    correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.argmax(y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    return accuracy

정확도 함수 정의

  • compute_accuracy 함수는 모델 예측 정확도를 계산한다.

    API를 쓴다고 이해하자.

모델 학습

# SoftmaxRegression 모델을 선언
SoftmaxRegression_model = SoftmaxRegression()

# 1000번 반복을 수행하면서 최적화를 수행.
for i in range(1000):
    batch_xs, batch_ys = next(train_data_iter)
    train_step(SoftmaxRegression_model, batch_xs, batch_ys)

 

모델 인스턴스 생성

  • SoftmaxRegression모델을 인스턴스화 하여 학습에 사용한다.
    모델을 준비

학습 반복

  • 1000번 반복하면서 모델을 학습시킨다.
    충분한 반복을 통해 데이터를 학습하고 손실을 최소화하도록 한다.

배치 학습

  • 매 반복마다 새로운 배치를 가져와서 train_step함수를 호출한다.
    데이터의 일부를 사용하여 모델을 학습시킴으로써 효율적인 학습을 수행한다.

학습처리가 잘 이루어진것 을 확인할 수 있다.

 

728x90