알고리즘
TensorFlow 2.0을 이용한 ANN MNIST 숫자분류기 구현
WDmil
2024. 6. 16. 21:38
728x90
import tensorflow as tf
# MNIST 데이터를 다운로드
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train, x_test = x_train.astype('float32'), x_test.astype('float32')
x_train, x_test = x_train.reshape([-1, 784]), x_test.reshape([-1, 784])
x_train, x_test = x_train / 255., x_test / 255.
y_train, y_test = tf.one_hot(y_train, depth=10), tf.one_hot(y_test, depth=10)
learning_rate = 0.001
num_epochs = 30
batch_size = 256
display_step = 1
input_size = 784
hidden1_size = 256
hidden2_size = 256
output_size = 10
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.shuffle(60000).batch(batch_size)
def random_normal_intializer_with_stddev_1():
return tf.keras.initializers.RandomNormal(mean=0.0, stddev=1.0, seed=None)
class ANN(tf.keras.Model):
def __init__(self):
super(ANN, self).__init__()
self.hidden_layer_1 = tf.keras.layers.Dense(hidden1_size,
activation='relu',
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
self.hidden_layer_2 = tf.keras.layers.Dense(hidden2_size,
activation='relu',
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
self.output_layer = tf.keras.layers.Dense(output_size,
activation=None,
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
def call(self, x):
H1_output = self.hidden_layer_1(x)
H2_output = self.hidden_layer_2(H1_output)
logits = self.output_layer(H2_output)
return logits
@tf.function
def cross_entropy_loss(logits, y):
return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.optimizers.Adam(learning_rate)
@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))
return loss
@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
ANN_model = ANN()
for epoch in range(num_epochs):
average_loss = 0.
total_batch = int(x_train.shape[0] / batch_size)
for batch_x, batch_y in train_data:
current_loss = train_step(ANN_model, batch_x, batch_y)
average_loss += current_loss / total_batch
if epoch % display_step == 0:
print("반복(Epoch): %d, 손실함수(Loss): %f" % ((epoch+1), average_loss))
accuracy = compute_accuracy(ANN_model(x_test), y_test)
print("정확도(Accuracy): %f" % accuracy)
코드 부분을 한부분씩 잘라서 이해해보자.
데이터 전처리
# 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데이터셋을 다운로드하여 사용한다.
데이터타입을 float32형식으로 변환한다.
- 이미지데이터는 기본적으로 uint8형식으로 되어있으나, 신경망 모델은 float32 타입의 데이터를 다루기 때문.
이미지 평탄화(Flattening)
- MNIST이미지는 28x28픽셀 크기의 2D배열 형태이다. 이 이미지를 1D형태로 변환하여 신경만의 입력으로 사용하기 위해 평탄화(flatten)한다.
정규화(Normalize)
- 이미지 픽셀값은 [0, 255](흑백) 값을 가지는데, 모델이 학습할 떄 더 빠르고 안정적으로 학습할 수 있도록 [0, 1] 사이로 정규화한다.
One-Hot 인코딩
- 레이블 데이터는 0에서 9까지의 정수값이다. 이를 신경망 출력과 비교하기 쉽게 One-hot인코딩을 통해 이진벡터로 변환하여 키값을 레이블 해준다.
데이터셋 준비
learning_rate = 0.001
num_epochs = 30
batch_size = 256
display_step = 1
input_size = 784
hidden1_size = 256
hidden2_size = 256
output_size = 10
학습률(learning_rate)
- 모델의 학습 속도를 결정한다. 내려가는 경사도라고 이해하면됨
에포크 수(num_epochs)
- 전체 데이터셋 학습을 몇 번 반복할지 설정한다.
배치 크기(batch_size)
- 한번에 학습할 데이터의 크기를 설정한다. 256개씩 묶음
한번에 모든 데이터를 학습하게 되면 너무 느리기 때문에, 부분부분씩 잘라서 학습한다고 생각하자.
레이어 크기(hidden, output_size)
- 노드의 크기를 설정한다.
모델 정의
class ANN(tf.keras.Model):
def __init__(self):
super(ANN, self).__init__()
self.hidden_layer_1 = tf.keras.layers.Dense(hidden1_size,
activation='relu',
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
self.hidden_layer_2 = tf.keras.layers.Dense(hidden2_size,
activation='relu',
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
self.output_layer = tf.keras.layers.Dense(output_size,
activation=None,
kernel_initializer=random_normal_intializer_with_stddev_1(),
bias_initializer=random_normal_intializer_with_stddev_1())
def call(self, x):
H1_output = self.hidden_layer_1(x)
H2_output = self.hidden_layer_2(H1_output)
logits = self.output_layer(H2_output)
return logits
모델 클래스 정의
- 딥러닝 모델 정의
첫 번째 은닉층
- 256개의 뉴런을 가진 첫 번째 은닉층, ReLU활성화 함수 사용
두 번째 은닉층
-
- 256개의 뉴런을 가진 첫 번째 은닉층, ReLU활성화 함수 사용
출력층
- 10개의 뉴런을 가진 출력층, 나중에 소프트맥스 적용을 위해 활성화 함수가 없다.
손실 함수 정의
@tf.function
def cross_entropy_loss(logits, y):
return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
교차 엔트로피 손실 함수
- 예측값과 실제값 차이를 계산하는 함
학습의 불일치 부분을 확인하고 모델의 성능을 향상시키기 위해 생성함.
옵티마이저 정의
optimizer = tf.optimizers.Adam(learning_rate)
Adam최적화기
- 모델 가중치 학습을 위한 최적화 알고리즘
학습 단계 정의
@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))
return loss
학습 단계
- 모델의 가중치를 업데이트하는 단계 정의, 손실을 계산하고 그에따른 그래디언트를 구해 가중치를 조정한다.
모델 학습 및 평가
ANN_model = ANN()
for epoch in range(num_epochs):
average_loss = 0.
total_batch = int(x_train.shape[0] / batch_size)
for batch_x, batch_y in train_data:
current_loss = train_step(ANN_model, batch_x, batch_y)
average_loss += current_loss / total_batch
if epoch % display_step == 0:
print("반복(Epoch): %d, 손실함수(Loss): %f" % ((epoch+1), average_loss))
accuracy = compute_accuracy(ANN_model(x_test), y_test)
print("정확도(Accuracy): %f" % accuracy)
모델 인스턴스화
- ANN모델 인스턴스 화
모델 학습
- 설정한 에포크 수 만큼 학습한다. 각 배치마다 손실을 계산하고 가중치 업데이트.
모델 평가
- 테스트 데이터로 모델의 정확도를 계산하고 출력.
728x90