본문 바로가기

AI(Artificial Intelligence)

classification - adagrad + dropout ( 분류 - 아다그라드 + 드랍아웃 )

728x90
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

# 아이리스 데이터셋 로드
iris_data = datasets.load_iris()
input_data = iris_data.data
correct = iris_data.target
n_data = len(correct)

# 입력 데이터 정규화
ave_input = np.average(input_data, axis=0)
std_input = np.std(input_data, axis=0)
input_data = (input_data - ave_input) / std_input

# 정답 데이터를 원-핫 인코딩으로 변환
correct_data = np.zeros((n_data, 3))
for i in range(n_data):
    correct_data[i, correct[i]] = 1.0

# 학습용, 테스트용 데이터 분할
index = np.arange(n_data)
index_train = index[index % 2 == 0]
index_test = index[index % 2 != 0]

input_train = input_data[index_train, :]
correct_train = correct_data[index_train, :]
input_test = input_data[index_test, :]
correct_test = correct_data[index_test, :]

n_train = input_train.shape[0]
n_test = input_test.shape[0]

# 네트워크 매개변수 설정
n_in = 4
n_mid = 25
n_out = 3
wb_width = 0.1
eta = 0.01  # 초기 학습률
epoch = 1000
interval = 100
dropout_ratio = 0.5  # 드롭아웃 비율

# 기본 레이어 클래스 정의 (아다그라드 적용)
class BaseLayer:
    def __init__(self, n_upper, n):
        self.w = wb_width * np.random.randn(n_upper, n)
        self.b = wb_width * np.random.randn(n)
        self.h_w = np.zeros((n_upper, n)) + 1e-8
        self.h_b = np.zeros(n) + 1e-8
   
    def update(self, eta):
        self.h_w += self.grad_w * self.grad_w
        self.w -= eta / np.sqrt(self.h_w) * self.grad_w

        self.h_b += self.grad_b * self.grad_b
        self.b -= eta / np.sqrt(self.h_b) * self.grad_b

# 중간 레이어 클래스 정의 (아다그라드 및 드롭아웃 적용)
class MiddleLayer(BaseLayer):
    def __init__(self, n_upper, n, dropout_ratio):
        super().__init__(n_upper, n)
        self.dropout_ratio = dropout_ratio
        self.dropout_mask = None
   
    def forward(self, x, train_flg=True):
        self.x = x
        self.u = np.dot(x, self.w) + self.b
        self.y = np.where(self.u <= 0, 0, self.u)  # ReLU 활성화 함수

        # 드롭아웃 적용 (훈련 시에만)
        if train_flg:
            self.dropout_mask = np.random.rand(*self.y.shape) > self.dropout_ratio
            self.y *= self.dropout_mask
        else:
            self.y *= 1.0 - self.dropout_ratio  # 테스트 시 드롭아웃 비율에 따라 스케일링
   
    def backward(self, grad_y):
        # 드롭아웃 적용 (드롭아웃된 뉴런은 역전파하지 않음)
        if self.dropout_mask is not None:
            grad_y *= self.dropout_mask
           
        delta = grad_y * np.where(self.u <= 0, 0, 1)  # ReLU 미분
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        self.grad_x = np.dot(delta, self.w.T)

# 출력 레이어 클래스 정의 (아다그라드 적용)
class OutputLayer(BaseLayer):
    def forward(self, x):
        self.x = x
        u = np.dot(x, self.w) + self.b
        self.y = np.exp(u) / np.sum(np.exp(u), axis=1, keepdims=True)
   
    def backward(self, t):
        delta = self.y - t
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        self.grad_x = np.dot(delta, self.w.T)

# 레이어 생성 (드롭아웃 비율 추가)
middle_layer_1 = MiddleLayer(n_in, n_mid, dropout_ratio)
middle_layer_2 = MiddleLayer(n_mid, n_mid, dropout_ratio)
output_layer = OutputLayer(n_mid, n_out)

# 순전파 함수 정의
def forward_propagation(x, train_flg=True):
    middle_layer_1.forward(x, train_flg)
    middle_layer_2.forward(middle_layer_1.y, train_flg)
    output_layer.forward(middle_layer_2.y)

# 역전파 함수 정의
def backpropagation(t):
    output_layer.backward(t)
    middle_layer_2.backward(output_layer.grad_x)
    middle_layer_1.backward(middle_layer_2.grad_x)

# 오류 계산 함수 (교차 엔트로피)
def get_error(t, batch_size):
    return -np.sum(t * np.log(output_layer.y + 1e-7)) / batch_size

# 학습 루프
train_error_x = []
train_error_y = []
test_error_x = []
test_error_y = []

for i in range(epoch):
    # 학습 오류 계산
    forward_propagation(input_train, train_flg=True)
    error_train = get_error(correct_train, n_train)
   
    # 테스트 오류 계산
    forward_propagation(input_test, train_flg=False)
    error_test = get_error(correct_test, n_test)
   
    train_error_x.append(i)
    train_error_y.append(error_train)
    test_error_x.append(i)
    test_error_y.append(error_test)
   
    if i % interval == 0:
        print("에포크:", str(i) + "/" + str(epoch),
              "훈련 오류:", str(error_train),
              "테스트 오류:", str(error_test))

    # 학습 데이터 섞기
    index_random = np.arange(n_train)
    np.random.shuffle(index_random)
   
    # 미니배치 아다그라드 적용
    for j in range(n_train):
        x = input_train[index_random[j], :].reshape(1, -1)
        t = correct_train[index_random[j], :].reshape(1, -1)
       
        forward_propagation(x, train_flg=True)  # 드롭아웃 적용
        backpropagation(t)
        middle_layer_1.update(eta)
        middle_layer_2.update(eta)
        output_layer.update(eta)

# 오류 그래프 그리기
plt.plot(train_error_x, train_error_y, label="Train")
plt.plot(test_error_x, test_error_y, label="Test")
plt.legend()

plt.xlabel("에포크")
plt.ylabel("오류")

plt.show()

# 정확도 계산
forward_propagation(input_train, train_flg=False)
count_train = np.sum(np.argmax(output_layer.y, axis=1) == np.argmax(correct_train, axis=1))

forward_propagation(input_test, train_flg=False)
count_test = np.sum(np.argmax(output_layer.y, axis=1) == np.argmax(correct_test, axis=1))

print("훈련 정확도:", str(count_train / n_train * 100) + "%",
      "테스트 정확도:", str(count_test / n_test * 100) + "%")

 

728x90