<가설 정의>

1. MNIST 데이터를 불러와 학습하기 적합한 형태로 변형

# -*- coding: utf-8 -*-

import tensorflow as tf

# MNIST 데이터를 다운로드 
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

load_data() 호출 시 MNIST 데이터를 numpy (int)array 형태로 반환해줌

x_train, y_train에는 약 60000개의 트레이닝 데이터, x_test, y_test에는 약 10000개의 테스트 데이터가 있음

 

 

# 이미지들을 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.

astype : 데이터 형변환

reshape(-1,~) : 여기서 -1은 매직넘버. 앞 차원에 알아서 맞춰줌. 기본 옵션이라고 생각

flattening : 2차원 데이터를 한 픽셀씩 펼쳐서 1차원 데이터로 변경하는 것. 28*28 -> 784

 

MNIST 데이터는 픽셀 하나당 0-255까지의 숫자값을 가지므로 ,이를 255로 나누면 0-1 사이로 normalize 됨

 

# 레이블 데이터에 one-hot encoding을 적용
y_train, y_test = tf.one_hot(y_train, depth=10), tf.one_hot(y_test, depth=10)

정답 데이터가 int 형이므로 one-hot encoding 을 적용해준다.

( 1 → 1000000000, 2 → 0100000000, 3 → 0010000000 이런 형식) 

 


2. 전체 데이터를 원하는 mini-batch 개수만큼 묶어줌

# 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 : api. 미니배치 단위로 묶는 과정을 손쉽게 할 수 있도록 함

iter : iterator. 100개씩의 미니배치를 순차적으로 가리키게 됨

 


3. 소프트맥스 회귀 모델 정의

# 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)

tf.keras.Model : 상속받는 클래스

tf.keras.layers.Dense : Wx+b를 추상화 해놓은 api (input을 넣었을 때 output으로 바꿔주는 중간 다리)

→ 10 = units. 출력 값의 크기, activation = 활성화 함수, kernel_initializer = 가중치(W) 초기화 함수, bias_initializer = 편향(b) 초기화 함수

 

call : 클래스 호출 시 동작하는 함수

logits : softmax(Wx+b)가 적용된 10 dimension의 값이 담겨있음

 


<손실함수 정의>

# 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]))
  #return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logtis, labels=y)) # tf.nn.softmax_cross_entropy_with_logits API를 이용한 구현

<최적화>

# 최적화를 위한 그라디언트 디센트 옵티마이저를 정의
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))

SGD : 옵티마이저 종류 중 하나

0.5 : learning rate

 

 

# 모델의 정확도를 출력하는 함수를 정의
@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))  #0~1 사이의 정확도 반환

  return accuracy

argmax :  최대값을 갖는 성분의 인덱스를 반환

y_pred는 softmax 함수 결과 값이 들어있다. [0.01, 0.4, 0.7, 0.04, 0.2, 0.082, 0.03, 0.002, 0.3, 0.06] 

하지만 정답값 y에는 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] 과 같은 형식으로 들어있다.

따라서 y_pred에 argmax 함수를 취하여 최대값을 갖는 성분의 인덱스를 반환하여 비교시키는 작업이 필요하다

 

 

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

# 1000번 반복을 수행하면서 파라미터 최적화를 수행
for i in range(1000):
  batch_xs, batch_ys = next(train_data_iter)  #100개씩의 mini-batch 데이터가 반환
  train_step(SoftmaxRegression_model, batch_xs, batch_ys)

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

batch_xs : (100, 784) MNIST 데이터

batch_ys : 100 dimension의 원-핫 인코딩된 데이터

 

 

 

결과

 

 

+ Recent posts