[밑바닥딥러닝] 3. 신경망 구현, 소프트맥스(softmax)

2021. 9. 12. 13:53Deep Learning

본 게시글은 한빛미디어 『밑바닥부터 시작하는 딥러닝, 사이토 고키, 2020』의 내용을 참조하였음을 밝힙니다.

 

이번 장에서는 간단한 신경망을 구현하고 소프트맥스 함수에 대해서 알아보도록 한다.

 

 

신경망 구현 - 순방향(forward)


구현하고자 하는 신경망은 위와 같은 3층 신경망이다. (입력층은 0층부터 시작)

 

첫 입력(input)은 2개가 주어지고, 첫번째 은닉층에 3개의 노드, 두번째 은닉층에 2개의 노드 마지막으로 2개의 출력을

 

생성한다. 출력이 여러 개인 이유는 해당 신경망의 목표가 클래스 분류인 경우일 가능성이 높다. 

 

노드 앞에 달린 작은 원은 활성화 함수를 거친 결과를 출력함을 나타낸다. 

 

입력층에서부터 출력층까지 신호가 흘러가고, 최종적으로 특정값을 출력할 때, 이를 순방향(forward) 전달이라고 한다.

 

이를 파이썬 코드로 나타내면 다음과 같다. 

import numpy as np
from activationFunc import (sigmoid, identity_func)

class neural_network:

    def __init__(self):
        self.x = np.random.rand(1,2)
        self.network = {}
        self.network['W1'] = np.random.rand(2,3)
        self.network['b1'] = np.random.rand(1,3)
        self.network['W2'] = np.random.rand(3,2)
        self.network['b2'] = np.random.rand(1,2)
        self.network['W3'] = np.random.rand(2,2)
        self.network['b3'] = np.random.rand(1,2)

    def forward(self):
        a1 = np.dot(self.x, self.network['W1']) + self.network['b1']
        z1 = sigmoid(a1)
        a2 = np.dot(z1, self.network['W2']) + self.network['b2']
        z2 = sigmoid(a2)
        a3 = np.dot(z2, self.network['W3']) + self.network['b3']
        y = identity_func(a3)
        return y

neural_network 클래스의 클래스 멤버에는 network라는 딕셔너리 변수가 있고, 

        self.network = {}
        self.network['W1'] = np.random.rand(2,3)
        self.network['b1'] = np.random.rand(1,3)

이 딕셔너리에 각 층마다의 가중치(weight)와 편향(bias)을 저장한다. 

 

객체가 생성되자마자 넘파이의 random-rand 모듈을 통해서 괄호 안에 지정된 shape만큼의 0과 1 사이

 

랜덤한 숫자가 생성하여 매개변수들을 초기화한다. 

        a1 = np.dot(self.x, self.network['W1']) + self.network['b1']
        z1 = sigmoid(a1)

forward 함수는 가중치와 이전 노드 input을 곱하고 편향인 b를 각 노드마다 더해준다. 

 

더해진 결과를 sigmoid 함수를 통과시켜서 다음 뉴런으로 전달한다. 

        y = identity_func(a3)
        return y

마지막 출력층에서는 identiti_func이라는 활성화함수를 통과시키는데 원래의 값 그대로를 출력한다. 

    n_network = neural_network()
    y = n_network.forward()
    print(n_network.x, y)
    
    결과>>>
    [[0.02316599 0.5851755 ]] [[1.96730973 0.91362616]]

 

 

 

소프트맥스 함수(Softmax function)


신경망은 무언가를 분류하거나 예측하는 작업을 하는데, 이중에서 분류에 해당하는 신경망일 경우 

 

마지막 출력층에서 소프트맥스(Softmax) 함수를 주로 사용한다. 

 

소프트맥스 함수의 공식은 아래와 같다. 

출처 : https://developer.apple.com/documentation/accelerate/bnnsactivationfunction/2915301-softmax

 

노드에서 출력하는 각 신호(x1, x2, .., xn)를 지수 함수에 통과시킨 값의 합을 분모로, 각 신호마다의 지수함수 값을 

 

분자값으로 한다. 

 

이를 파이썬 코드로 구현하면 다음과 같다. 

def softmax(x):
    c = np.max(x)
    exp_x = np.exp(x-c)
    modified_x = exp_x / np.sum(exp_x)
    return modified_x

중간에 입력값인 x의 최대값(max)인 c를 각각 빼준 것은 오버플로(overflow) 문제를 피하기 위함이다.

>>> x = [1.3, 2.4, 1.07, 1.96]
>>> softmax(x)
array([0.14851135, 0.44615276, 0.11799726, 0.28733863])

여기서 소프트맥스의 중요한 특성이 있다. 

>>> result = softmax(x)
>>> result
array([0.14851135, 0.44615276, 0.11799726, 0.28733863])
>>> import numpy
>>> numpy.sum(result)
1.0000000000000002

소프트맥스 함수에 의해 변환된 리스트 값들의 총합이 1이라는 것이다. 

 

소프트맥스 함수를 사용함으로써 각 출력값들을 '확률'로서 해석이 가능하다. 

 

출처 : https://medium.com/different-types-of-activation-functions-in-a/softmax-classifier-f3f80b8a3228

 

분류를 위한 신경망에서는 분류하고자 하는 클래스(Class)의 개수만큼 출력 노드를 설정하고 

 

이를 소프트맥스 함수로 처리해서 각 클래스별의 확률을 계산한다.