AI 그게 뭔데
끄적끄적 개발일지
AI 그게 뭔데
전체 방문자
오늘
어제
  • 분류 전체보기 (342)
    • 논문 (5)
    • DL(Deep-Learning) (34)
      • 개념 (14)
      • Python 기초 (14)
      • Tensorflow (6)
      • Pytorch (0)
    • NLP (10)
    • OpenCV (53)
    • DevOps (10)
      • AWS (2)
      • Docker & Kubernetes (4)
      • Spark (3)
      • SQL (1)
    • MacOS (1)
    • React-Native (2)
    • BI (3)
      • GA(Google Analytics) (3)
      • Tableau (0)
    • 알고리즘 (221)
      • 백준 (76)
      • 프로그래머스 (108)
      • 기타 알고리즘 (37)

인기 글

태그

  • 파이썬
  • 연습문제
  • 프로그래머스
  • 알고리즘
  • 이코테
  • level1
  • Python
  • 백준
  • LEVEL2
  • OpenCV

최근 글

hELLO · Designed By 정상우.
AI 그게 뭔데

끄적끄적 개발일지

[실습] numpy로 만드는 단층 신경망 - 다중 분류2
DL(Deep-Learning)/개념

[실습] numpy로 만드는 단층 신경망 - 다중 분류2

2022. 1. 29. 21:45

우리는 다중 분류 문제를 예측하는 단층 신경망을 만들어 볼 것이다.

 

다중 분류 문제에서는 불량철판문제 데이터를 가지고 불량 철판의 종류를 예측하는 신경망을 구축해 볼 예정이다.
데이터 셋은 Kaggle에 있는 불량 철판 문제 에서 받아서 사용 할 수 있다.

 

 

✔︎  데이터 살펴보기

import numpy as np
import csv
import pandas as pd

data = pd.read_csv('data/faults.csv')

 

독립변수
종속변수

 

독립 변수는 철판의 불량 상태를 의미하는 지표인 총 27가지의 값이 주어지며,

종속 변수로는 one − hot vector 로 표현된 7가지의 불량 종류가 존재하는 1941개의 데이터셋 이다.

 

 

📍  다중 단층 신경망을 만들기 위한 설계도

 

 

1. 모듈 불러오기

import numpy as np  
import csv

# 실험 결과를 재현하기 위해 난수 발생패턴을 고정시키는 np.random.seed()함수값을 설정
np.random.seed(333)

 

 

2. 하이퍼 파라미터 설정

  • learning rate 학습률
  • 정규분포 난숫값 [ 평균 / 표준편차 ]
RND_MEAN = 0  # 평균
RND_STD = 0.003  # 표준편차
Learning_rate = 0.003  # 학습률

 

 

3. 메인함수 정의

def multi_class_exec(epoch_count=10, mb_size=10, report=1,train_rate=0.75):
    multi_load_dataset()
    init_model()
    train_and_test(epoch_count, mb_size, report,train_rate)

 

메인 함수 multi_classification_exec() 함수를 실행하게 되면

#1 데이터를 불러들이는 multi_load_dataset() 함수,

#2 가중치와 편향을 초기화 해주는 init_model() 함수,

#3 학습 및 신경망 성능 테스트를 위한 train_and_test()함수

 

이렇게 세가지 함수가 차례로 실행되며, 신경망 모델을 생성하고 학습 전체 과정을 일괄 처리한다.

 

데이터를 관리하는 함수인 multi_load_dataset()를 제외하고는 모두 이전과 같은 형식으로 작성되었다.

 

 

 

4. 데이터를 불러오는 multi_load_dataset() 정의

# 데이터 받기 > 버퍼로 옮겨주기 > np.asarray()로 감싸주기
def multi_load_dataset():
    with open('/content/faults.csv') as csvfile:
        csvreader = csv.reader(csvfile)
        next(csvreader, None)
        rows = []
        for row in csvreader:
            rows.append(row)
            
    global data, input_cnt, output_cnt
    input_cnt, output_cnt = 27, 7  # 독립변수, 종속변수
    data = np.asarray(rows, dtype='float32') # 배열 구조로 변환하는 과정

 

데이터를 자세히 살펴보면 오직 실수로된 데이터만 존재한다.

이미 원-핫벡터로 변환되어 있기 때문에 원-핫 벡터 표현과정은 생략할 수 있고, 독립변수 input_cnt과 종속변수 output_cnt은 각 27, 7의 값을 가진다.

리스트 구조로 되어있는 변수를 asarray 배열 구조로 변환하게 되면 numpy에서 제공하는 다양한 산술 연산과정을 효율적으로 사용할 수 있게된다.

 

 

 

5. 파라미터 초기화 함수 init_model() 정의

def init_model():
    global weight, bias, input_cnt, output_cnt
    weight = np.random.normal(RND_MEAN, RND_STD,[input_cnt, output_cnt])  
    # normal 메서드 :  (mean, sd, shape)
    
    bias = np.zeros([output_cnt])
    # weight 가중치 행렬은 [8,1] , bias 편향 벡터는 [1]형태

 

 

 

6. 학습을 수행 run_train() 정의

def run_train(x,y):  #신경망 연산
    output, aux_nn = forward_neuralnet(x)  
    loss, aux_pp = forward_postproc(output,y)  
    accuracy = eval_accuracy(output,y)
    
    return loss, accuracy

 

학습을 위해서는 제일 먼저 신경망 연산을 수행하는 forward_neuralnet() 가 동작한다.

 

 

6.1 순전파 forward_neuralnet()

def forward_neuralnet(x):
    global weight, bias
    output = np.matmul(x, weight) + bias
    return output, x

 

이 함수를 통해서 output을 연산하고 값을 돌려받는다. 그리고 이러한 output을 바탕으로 손실값을 계산하는 forward_postproc()가 동작하게 된다. 이 함수에서는 손실을 계산하는 소프트맥스 교차 엔트로피를 연산하는 수식이 필요하다. 그리고 이렇게 구한 값을 바탕으로 np.mean() 를  통해 최종 손실을 도출해낸다.

 

 

6.1 역전파 forward_postproc()

def forward_postproc(output, y):
    entropy = softmax_cross_entropy_with_logits(y, output)
    loss = np.mean(entropy)

    return loss, [y, output, entropy]  # [y, output, entropy]는 역전파 때 활용(받은것을 그대로 반환)

 

소프트맥스 교차 엔트로피를 계산할 수 있는 softmax_cross_entropy_with_logits() 가 사용되는데, 이 함수를 수행하기 위해서는 softmax()를 통과해 얻어진 신경망 연산에 대한 확률분포가 필요하다.

 

 

 

7. softmax() 함수 정의

def softmax(x):
    #output 값 중 최댓값 / axis = 1 ->'열'== '후보값'들 기준하여 가장 큰 값을
    #추출하기 위해 열 기준으로 추출하는 axis = 1을 넣어줌
    #max_elem의 shape은 (10,)  
    max_elem = np.max(x, axis = 1)  # x_k값을 찾는다.

    #i번째 x와 가장 큰 x값을 빼주는 과정에서
    #diff = output - max_elem 이렇게는 연산이 되지 않는다. (10,7) (10,) > (1,10) 행벡터 X
    #그래서 x(output)을 행렬전환하여 연산을 수행한 다음 다시 원상 복귀
    diff = (x.transpose() - max_elem).transpose()
    #diff에 np.exp()를 씌워 분자의 수식을 완성
    exp = np.exp(diff)

    #분모는 이러한 exp를 모두 합산
    sum_exp = np.sum(exp, axis=1)
    #앞서 마찬가지로 분자와 분모의 나눗셈을 위해 행렬전환 후 연산. 그리고 다시 원상복귀를 위해 행렬전환
    probs = (exp.transpose() / sum_exp).transpose()  #softmax를 통과한 확률

    return probs

 

 

7.1 소프트맥스 교차 엔트로피 개선식 정의

def softmax_cross_entropy_with_logits(labels, logits):
    probs = softmax(logits)
    #기존 확률값에 아주 작은 양수를 더해 log함수의 폭주 방지
    return -np.sum(labels * np.log(probs + 1.0e-10), axis=1)

 

 

8. 평가지표 함수 eval_accuracy() 정의

def eval_accuracy(output, y):
    estimate = np.greater(output, 0)
    answer = np.greater(y, 0.5)
    correct = np.equal(estimate, answer)

    return np.mean(correct)

 

np.argmax(axis = 1) 를 통해 신경망의 연산결과 중 가장 높은 값을 가진 위치, 데이터 마다의 종속변수 중 가장 높은 값을 가진 위치를 각각 출력하여 estimate, answer 라는 변수에 저장한다.

신경망의 연산결과를 통해서도 어느 후보가 더 높은 확률값을 갖고 있는지 추론이 가능하기에 이렇게 구한 결과를 비교하는 np.equal()를 활용하여  정확도를 구해낼 수 있다.

 

 

 

9. 역전파를 넣은 run_train() 정의

def run_train(x, y):
    output, aux_nn = forward_neuralnet(x)
    loss, aux_pp = forward_postproc(output, y)
    accuracy = eval_accuracy(output, y)
    #역전파 수행 및 파라미터 갱신 (aux_pp = y, output, entropy)
    G_output = backprop_postproc(aux_pp)
    #aux_nn은 x.transpose()를 위해
    backprop_neuralnet(G_output, aux_nn)

    return loss, accuracy

 

 

9.1 역전파 과정

def backprop_neuralnet(G_output, x):
    global weight, bias
    g_output_w = x.transpose()

    G_w = np.matmul(g_output_w, G_output)
    G_b = np.sum(G_output, axis=0)

    weight -= Learning_rate * G_w
    bias -= Learning_rate * G_b

 

def backprop_postproc(aux_pp):  
    y, output, entropy = aux_pp 
    G_loss = 1.0
    g_loss_entropy = 1.0/np.prod(entropy.shape)
    g_entropy_output = softmax_cross_entropy_with_logits_derv(y,output)

    G_entropy = g_loss_entropy * G_loss
    G_output = g_entropy_output * G_entropy

    return G_output

 

 

9.2 소프트 맥스 크로스 엔트로피 편미분

def softmax_cross_entropy_with_logits_derv(labels,logits):
    return softmax(logits) - labels

 

 

 

10. 학습 및 평가 함수 train_and_test() 정의

def train_and_test(epoch_count, mb_size, report, train_rate):
    #1.데이터 섞어주는 기능(mb_size값을 활용해 한 에폭에 필요한 미니배치 스텝수를 step_count에 저장)
    #학습데이터와 평가 데이터를 섞어주는 기능 수행
    step_count = arrange_data(mb_size, train_rate)  #2. 테스트 데이터를 따로 저장하는 함수
    test_x, test_y = get_test_data()

    # 학습을 수행하는 단계 (에폭 수 만큼)
    for epoch in range(epoch_count):
        #학습을 수행하는 만큼 손실값과 정확도가 생성되니 이것들을 저장해줄 빈 리스트 생성
        losses, accs = [], []

        #step_count(한번의 에폭에 필요한 미니배치 스텝 수)를 활용해 미니배치 처리를 수행
        #step_count가 다 돌면 1에폭 수행
        for n in range(step_count):
            #3. 학습을 수행하기 위한 학습 데이터 분할(1에폭에 대한 n = 미니배치 스텝 수)
            train_x, train_y = get_train_data(mb_size, n)
            #4. 학습 수행
            loss, acc = run_train(train_x, train_y)
            losses.append(loss)
            accs.append(acc)

        #에폭이 돌면서 학습이 수행됨. 즉 모델 학습 #에폭값이 report로 설정한 수에 해당될 때 마다 중간평가 수행
        if report > 0 and (epoch + 1) % report == 0:
            #5.테스트 데이터를 활용한 테스트 수행 - 중간 평가
            #에폭만큼 학습이 수행된 모델을 활용하여 중간평가
            acc = run_test(test_x, test_y)
            print(
                f"Epoch{epoch+1}: Train-loss = {np.mean(losses):5.3f}, accuracy = {np.mean(accs):5.3f} / Test={acc:5.3f}"
            )

    #모든 학습 완료 후 / 최종 모델을 활용한 테스트 수행
    final_acc = run_test(test_x, test_y)
    print(f'\n 최종 테스트 : final accuracy = {final_acc:5.3f}')

 

◼ train_and_test() 안에 정의된 함수

  • arrange_data()
  • get_train_data()
  • get_test_data()
  • run_train()
  • run_test()

 

def arrange_data(mb_size, train_rate):
    global data, shuffle_map, test_begin_idx

    shuffle_map = np.arange(data.shape[0])
    np.random.shuffle(shuffle_map)

    step_count = int(data.shape[0] * train_rate) // mb_size

    test_begin_idx = step_count * mb_size

    return step_count


def get_test_data():
    global data, shuffle_map, test_begin_idx, output_cnt

    test_data = data[shuffle_map[test_begin_idx:]]

    return test_data[:, :-output_cnt], test_data[:, -output_cnt:]


def get_train_data(mb_size, nth):
    global data, shuffle_map, test_begin_idx, output_cnt

    if nth == 0:
        np.random.shuffle(shuffle_map[:test_begin_idx])

    train_data = data[shuffle_map[mb_size * nth:mb_size * (nth + 1)]]

    return train_data[:, :-output_cnt], train_data[:, -output_cnt:]

 

 

 

11. 학습 결과를 테스트 하는 run_test() 정의

def run_test(test_x,test_y):
    output,_ = forward_neuralnet(test_x) 
    accuracy = eval_accuracy(output,test_y)  
    
    return accuracy

 

순전파 과정인 forward_neuralnet()를 진행하여 얻은 output을 평가함수인 eval_accuracy()의 인자로 활용하여 정확도를 계산해 주면된다. 이렇게 run_test()를 통해 얻어진 결과와 더불어 앞서 학습을 통해 얻어진 정확도 및 손실은 print()를 통해 출력된다.

 

 

 

12. 실행하기

Learning_rate = 0.0001
multi_class_exec(epoch_count=1000,mb_size = 100, report=100, train_rate=0.7)

 

하이퍼파라미터를 수정했음에도 불구하고 오히려 더 낮은 결과값을 확인할 수 있다. 이러한 낮은 품질의 원인은 여러가지가 있겠지만 그 중에서도 데이터의 수에 대해 이야기 할 필요가 있다. 지금 신경망의 학습을 위해 사용되어진 데이터의 수는 총 데이터의 70%인 약 1350개 이다. 그리 많은 숫자라고는 할 수 없지만 그래도 적은 숫자는 아니다. 그러나 우리가 가진 27가지의 변수, 즉 27개의 벡터 공간을 통해 종속변수의 크기인 총 7개의 구역으로 적절하게 분할할 수 있어야 한다. 그렇기 위해서는 1350개의 데이터는 그리 많은 숫자가 아니라는 것을 정확도와 손실값이 이야기 해주고 있다.

 

또 한가지 문제점은 단층 퍼셉트론의 구조 자체에 대한 점이다. 단층 퍼셉트론은 지나치게 단순한 구조이기에 복잡한 문제를 풀기 위함에 있어 적합하지 않을 수 있다.

 

'DL(Deep-Learning) > 개념' 카테고리의 다른 글

[실습] numpy로 만드는 다층 신경망  (0) 2022.01.29
[실습] numpy로 만드는 단층 신경망 - 다중 분류1  (0) 2022.01.29
[실습] numpy로 만드는 단층 신경망 - 이진 분류 2  (0) 2022.01.29
[실습] numpy로 만드는 단층 신경망 - 이진 분류 1  (0) 2022.01.29
train/test/validation 나누기 - splitfolders  (0) 2022.01.29
    AI 그게 뭔데
    AI 그게 뭔데
    공부와 개발 그리고 AI가 약간 첨가된 흔적 남기기

    티스토리툴바