relu

* 모든 코드는 제 깃허브 (cdjs1432/DeepLearningBasic: Deep Learning from scratch)에서 확인할 수 있습니다.

 

이번에는 ReLU 계열의 활성화 함수를 구현해 보겠습니다.

 

 

ReLU, Leaky ReLU, ELU

위 그래프는 ReLU 계열의 활성화 함수를 그래프로 나타낸 것입니다.

ReLU, Leaky ReLU, ELU 모두 입력값이 0보다 크면 그대로 y=x를 사용하지만,

0보다 작을때는 ReLU는 그냥 모든 입력에서 0, Leaky ReLU는 약 0.001x, ELU는 $e^x - 1$을 나타냅니다.

 

 

그렇다면 바로 Layers.py 구현부로 가서 활성화 함수들을 구현해 봅시다.

이번 시간에 구현할 것들은 좀 쉬워서, 사실 안보고도 하실 수 있을 겁니다. 글을 보지 않고, 스스로 한번 만들어 보셔도 좋겠습니다.

 

 

class ReLU:
    def __init__(self):
        self.out = None

    def forward(self, z):
        self.out = z
        self.out[self.out <= 0] = 0
        return self.out

    def backward(self, dout):
        self.out[self.out > 0] = 1
        return self.out * dout

우선, ReLU 함수입니다.

z값이 0보다 클때는 그대로 z를 출력하고, 0보다 작을 때는 0을 출력합니다.

forward의 구현은 그것을 그대로 따라갔습니다.

 

 

backward의 경우, 당연히 ReLU함수가 0보다 클 때는 1, 작을 때는 0이 됩니다만...

ReLU가 0일 경우 미분값을 어떻게 처리해 주어야 할까요?

사실 원래는 0일 경우 미분값을 구할 수는 없지만, 보통 그냥 0으로 만들어 줍니다.

딱히 큰 의미가 있는 것은 아니고, 어차피 뭘 해도 정확도에 큰 영향이 없기 때문입니다.

 

 

 

class LeakyReLU:
    def __init__(self):
        self.out = None

    def forward(self, z):
        self.out = z
        self.out[self.out <= 0] *= 0.001
        return self.out

    def backward(self, dout):
        self.out[self.out > 0] = 1
        self.out[self.out <= 0] = 0.001
        return self.out * dout

다음은 Leaky ReLU입니다.

위의 ReLU를 그대로 복사한 뒤, self.out <= 0 부분에서 0을 만들어 버리는 대신, 0.001을 곱해주면 됩니다.

backward도 마찬가지로, 0보다 작은 경우의 미분값은 당연히 0.001이 되게 됩니다.

 

 

class ELU:
    def __init__(self):
        self.out = None

    def forward(self, z):
        self.out = z
        self.out[self.out <= 0] = np.exp(self.out[self.out <= 0]) - 1
        return self.out

    def backward(self, dout):
        self.out[self.out > 0] = 1
        self.out[self.out <= 0] += 1
        return self.out * dout

ELU도 전혀 다를 것이 없습니다.

forward 함수에서는 값이 0보다 작으면 $e^x - 1$을 출력값으로 내놓습니다.

그리고 해당 값을 미분하면 $e^x$이 나오므로, 그냥 원래 $e^x - 1$이었던 값에다가 1만 더해주면, 그것이 미분값이 됩니다.

 

 

사실 이번 활성화 함수 제작은 여기서 끝입니다.

보통 실제 훈련 시킬 때는 ReLU계열의 활성화 함수만 사용하기 때문에, 이렇게만 준비해 봤습니다.

하지만, 다른 Activation function도 위의 방식을 따라만 간다면 만들기에 크게 어렵지 않을 겁니다.

다른 활성화 함수를 구현해 보고 싶으시다면, 직접 forward와 backward를 구현하는 것도 꽤 재밌는 일입니다.

 

+ Recent posts