대학원 일기

MLP(Multi Layer Perceptron) 과정 본문

AI/인공지능 기초

MLP(Multi Layer Perceptron) 과정

대학원생(노예) 2023. 11. 13. 10:57

1. 데이터 준비
- 데이터셋 불러오기
- 훈련 데이터, 테스트 데이터 나누기
- 입력 이미지 정규화하기
- 이미지 배열 크기 변환하기

2. 가중치 및 편향값 초기화
- MLP의 가중치와 편향을 초기화 함

3. 순전파 함수 정의
- affine layer forward
- relu
- softmax

4. 원 핫 인코딩 및 손실 함수 정의
- change one hot label
- cross entropy error

5. 역전파 함수 정의
- affine layer backword
- relu gradient

6. 파라미터 업데이트 함수 정의
- 가중치와 편향값을 업데이트

7. 훈련 단계 정의
- step에 따라 훈련

8. 예측 및 정확도 함수 정의
- 하이퍼 파라미터를 설정
- 훈련 루프 실행

 

import tensorflow as tf
from tensorflow import keras

# mnist를 불러오고 train_data, train_label, test_data, test_label로 나눠주세요.
mnist = keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

#우리의 모델은 MLP이기 때문에 데이터를 255로 나누고 1차원(60000, n)으로 만들어주세요.
x_train_norm, x_test_norm = x_train / 255.0, x_test / 255.0
x_train_reshaped = x_train_norm.reshape(-1, x_train_norm.shape[1]*x_train_norm.shape[2])
x_test_reshaped = x_test_norm.reshape(-1, x_test_norm.shape[1]*x_test_norm.shape[2])

# 초기화된 파라미터를 정의하는 함수를 만들고 초기값을 만드세요.
def init_params(input_size, hidden_size, output_size, weight_init_std=0.01):
    #W1, b1, W2, b2를 모두 정의해주세요.
    W1 = weight_init_std * np.random.randn(input_size, hidden_size)
    b1 = np.zeros(hidden_size)
    W2 = weight_init_std * np.random.randn(hidden_size, output_size)
    b2 = np.zeros(output_size)
    return W1, b1, W2, b2

W1, b1, W2, b2 = init_params(input_size = 784, hidden_size = 50, output_size = 10)

# MLP를 정의하세요.
def affine_layer_forward(X, W, b):
  y = np.dot(X, W) + b
  cache = (X, W, b)
  return y, cache

# relu를 정의하세요 (np.maximum을 활용하세요)
def relu(x):
  return np.maximum(x, 0)

# softmax를 정의하세요
def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T 

    x = x - np.max(x) # 오버플로 대책
    return np.exp(x) / np.sum(np.exp(x))

# one-hot 인코딩을 정의하세요
def _change_one_hot_label(X, num_category):
    T = np.zeros((X.size, num_category))
    for idx, row in enumerate(T):
        row[X[idx]] = 1
    return T

# cross entropy loss함수를 정의하세요
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
        
    # 훈련 데이터가 원-핫 벡터라면 정답 레이블의 인덱스로 반환
    if t.size == y.size:
        t = t.argmax(axis=1)
             
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t])) / batch_size

# MLP의 backward pass를 정의하세요
def affine_layer_backward(dy, cache):
  X, W, b = cache
  dX = np.dot(dy, W.T)
  dW = np.dot(X.T, dy)
  db = np.sum(dy, axis=0)
  return dX, dW, db

# relu 함수의 backward pass를 정의하세요. (np.where 함수를 활용하세요)
def relu_grad(x):
  data = [1 if value>0 else 0 for value in x]
  return np.array(data, dtype=float)

#파라미터를 업데이트하는 함수를 정의하세요.
def update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, learning_rate):
  W1 = W1 - learning_rate*dW1
  b1 = b1 - learning_rate*db1
  W2 = W2 - learning_rate*dW2
  b2 = b2 - learning_rate*db2
  return W1, b1, W2, b2

# train_step을 정의합니다.
def train_step(X, Y, W1, b1, W2, b2, learning_rate=0.1, verbose=False):
  a1, cache1 = affine_layer_forward(X, W1, b1) # 행렬 곱 수행: wx + b 꼴로 만들기
  z1 = relu(a1) # 활성화 함수 적용: relu
  a2, cache2 = affine_layer_forward(z1, W2, b2)
  y_hat = softmax(a2) # softmax
  t = _change_one_hot_label(Y, 10) 
  Loss = cross_entropy_error(y_hat, t) # cross entropy loss

  if verbose:
      # print('---------')
      # print(y_hat)
      # print(t)
      print('Loss: ', Loss)
      
  dy = (y_hat - t) / X.shape[0]
  dz1, dW2, db2 = affine_layer_backward(dy, cache2)
  da1 = sigmoid_grad(a1) * dz1
  dX, dW1, db1 = affine_layer_backward(da1, cache1)
  
  W1, b1, W2, b2 = update_params(W1, b1, W2, b2, dW1, db1, dW2, db2, learning_rate)
  
  return W1, b1, W2, b2, Loss

# 예측값을 만드는 함수를 정의하세요
def predict(W1, b1, W2, b2, X):
  a1 = np.dot(X, W1) + b1
  z1 = sigmoid(a1)
  a2 = np.dot(z1, W2) + b2
  y = softmax(a2)
  return y

#정확도를 나타내는 함수를 정의하세요
def accuracy(W1, b1, W2, b2, x, y):
  y_hat = predict(W1, b1, W2, b2, x)
  y_hat = np.argmax(y_hat, axis=1)
  
  accuracy = np.sum(y_hat == y) / float(x.shape[0])
  return accuracy

# 하이퍼파라미터
iters_num = 50000  # 반복 횟수를 적절히 설정한다.
train_size = x_train.shape[0]
batch_size = 100   # 미니배치 크기
learning_rate = 0.1

train_loss_list = []
train_acc_list = []
test_acc_list = []

# 1에폭당 반복 수
iter_per_epoch = max(train_size / batch_size, 1)

W1, b1, W2, b2 = init_params(784, 50, 10)

for i in range(iters_num):
  # 미니배치 획득
  batch_mask = np.random.choice(train_size, batch_size)
  x_batch = x_train_reshaped[batch_mask]
  y_batch = y_train[batch_mask]
  

  W1, b1, W2, b2, Loss = train_step(x_batch, y_batch, W1, b1, W2, b2, learning_rate=0.1, verbose=True)

  # 학습 경과 기록
  train_loss_list.append(Loss)
  
  # 1에폭당 정확도 계산
  # train_accuracy와 test_accuracy를 완성해주세요
  if i % iter_per_epoch == 0:
      print('Loss: ', Loss)
      train_acc = accuracy(W1, b1, W2, b2, x_train_reshaped, y_train)
      test_acc = accuracy(W1, b1, W2, b2, x_test_reshaped, y_test)
      train_acc_list.append(train_acc)
      test_acc_list.append(test_acc)
      print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))

 

Accuracy, Loss 변화 시각화

Accuracy 그래프

from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 12, 6 

# Accuracy 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

 

Loss 그래프

# Loss 그래프 그리기
x = np.arange(len(train_loss_list))
plt.plot(x, train_loss_list, label='train acc')
plt.xlabel("epochs")
plt.ylabel("Loss")
plt.ylim(0, 3.0)
plt.legend(loc='best')
plt.show()
Comments