[AITech] 20220207 - MLP Basics

4 minute read


학습 내용

Neural Networks

What is Neural Network? 뉴럴 네트워크란 무엇일까요?

일반적으로, 우리는 이 뉴럴 네트워크, 그러니까 딥러닝 구조란 인간의 뇌의 구조를 모방한 데서 왔다고 이야기합니다. 이것이 틀렸다는 것은 아닙니다만, 이 강의에서는 약간 다른 인사이트를 전달해주시고 계십니다.

딥러닝이라는 것이 태동하던 시절에는 그 시작이 인간의 뇌/인지 과정에 대한 모방으로 시작했을지언정, 지금은 ‘굳이 인간의 뇌를 모방한 구조라고 설명해야 하나?’라고 할만큼 딥러닝은 많이 발전해왔고, 그 구조에서 차이를 보입니다. 예를 들면 Backpropagation과 같은 것들은, 딥러닝에서 학습을 위해 필연적으로 사용되지만 우리의 뇌에서 그것이 필수적인 학습 과정이라고 할 수는 없는 것이죠.

그래서, 이 강의에서는 이 Neural Network선형 변환과 비선형 변환 블록들이 쌓여 만들어진 근사 함수를 찾는 모델이라고 전달합니다. 개인적으로도, 이 인사이트가 현대의 뉴럴 네트워크 구조를 설명하는 데 더 적합한 것 같고 그 구조나 목적을 이해하기에 더 적합하다고 생각합니다.

아래 모델은 ResNet이라는 모델의 구조를 나타낸 것입니다.

image-20220207140331447


Linear Neural Networks

이 포스팅에서는 많고 많은 뉴럴 네트워크 구조들 중 Linear Neural Network에 대해 살펴보면서 안에서 무슨 일이 일어나는지 간단히 살펴보겠습니다.

그 옛날 올드스쿨의 모델들이든, 작금의 최신 모델들이든 그 모델을 제대로 정의하기 위해서는 다음의 4가지가 필요합니다.

  • Data: The data that the model can learn from
  • Model: The model how to transform the data
  • Loss: The loss function that quantifies the badness of the model
  • Algorithm: The algorithm to adjust the parameters to minimize the loss

그리고 선형 모델의 그것들은 다음과 같이 나타낼 수 있습니다.

image-20220207140746289

첫번째로, 우리는 주어진 입력을 이용해 출력을 만들어냅니다. 이 때 선형 모델은 출력을 만들기 위해 Affine transforms(어파인/아핀 변환, 직선, 길이의 비, 평행성을 보존하는 선형 변환으로 회전, 평행이동, 스케일 조정, 확대/축소, 반전 등을 포함)를 적용합니다.

선형 모델에서의 아핀 변환은 단순히 행렬곱/행렬 덧셈을 의미하며, 아핀 변환에 대해 더 자세히 알고 싶으신 분들은 아래 참고 자료 를 참조해주세요.

image-20220207141443488

그리고 선형대수 시간에 배웠듯이, 어떤 벡터 x에 행렬을 곱해 다른 벡터 y로 만든다는 것은 x의 차원에서 y의 차원으로의 mapping이 일어나는 것으로 이해할 수 있습니다.

두번째로, 출력값을 얻고 나면 이 출력 값이 실제 정답과 얼마나 다른지를 나타내는 Loss를 계산합니다. 선형 모델의 Loss 식은 보통 MSE를 많이 사용하며, 위 그림에서 본 Loss 식에 해당합니다.

그런데 이 ‘얼마나 다른지’에 대해 우리가 알고만 있다면, 이는 그 어떤 의미도 없습니다. 이 얼마나 다른지를 통해 틀린 것을 계속해서 배워가는 것이 중요하겠죠. 뉴럴 네트워크에서는 이것이 Loss를 각 층의 가중치에 대해 미분함으로써 일어납니다.

image-20220207142015534

세번째로, 위와 같이 계산한 미분치를 통해 해당 층의 가중치를 갱신합니다. 이를 통해 뉴럴 네트워크는 학습을 합니다.

그리고 이렇게 학습을 할 때는 ‘한 번에 얼마나 배울 것인지’를 지정해주는 step size(learning rate, 학습율)를 지정해줍니다.

image-20220207142147313

이렇게 선형 모델에서 ‘학습’을 하는 과정에 대해 간단하게 살펴보았습니다.


Beyond Neural Networks

위에서 선형 모델에 대해 살펴보았는데, 이제 우리는 여기에 비선형성을 추가할 것입니다.

위의 행렬곱/행렬 덧셈 같은 선형 변환으로는 몇 번을 하든 비선형성을 만들어내지 못합니다. 어떤 벡터에 행렬을 몇 번을 곱하든, 그 결과는 행렬끼리 먼저 곱해진 결과 행렬을 어떤 벡터에 한 번 곱한 것과 같기 때문입니다.

image-20220207142500912

따라서, 우리는 더 많은 함수들, 비선형성이 존재하는 많은 함수들을 근사하기 위해 중간에 activation function(비선형 함수) 층을 추가합니다. 이렇게 함으로써 우리의 뉴럴 네트워크는 훨씬 많은 종류의 함수들을 근사하는 것이 가능하게 됩니다.

image-20220207142733186

많이 사용되는 비선형 함수에는 다음의 함수들이 있습니다.

image-20220207142744211

강의에서는, 이렇게 선형 함수와 비선형 함수의 연속으로 이루어진 뉴럴 네트워크 모델이 거의 모든 함수를 표현할 수 있는 것은 맞지만, 이것이 우리가 만든 모델이 모든 함수를 적절히 표현할 수 있는 것과는 다르다는 것을 전달해주고 있습니다.

즉, 표현을 할 수는 있을테지만 실제로 내 모델이 그것을 표현하도록 만드는 것은 쉽지만은 않다는 것이죠.


Multi-Layer Perceptron

그리고, 이런 뉴럴 네트워크 모형은 깊~~게 쌓은 것을 MLP(Multi-Layer Perceptron)라고 합니다.

image-20220207143053041

이렇게 깊은 신경망은 여러 task를 수행할 수 있으며, 그 목적에 따라 loss function 또한 달라지게 됩니다. 모델에 따라 또는 목적에 따라 ‘왜 그 손실 함수를 사용하느냐’에 대한 얘기는 통계학적인 관점에서 접근할 수 있으며, 그 인사이트는 단순하지만은 않습니다.

여기서는 그 내용에 대해서는 다루지 않고, 대표적인 task마다 가장 일반적으로 사용하는 loss function을 소개하면서 포스팅을 마치겠습니다.

image-20220207143416192

MLP 실습

MLP를 간단히 code level에서 보도록 하겠습니다.

  • Define the MLP Model

    class MultiLayerPerceptronClass(nn.Module):
        def __init__(self,name='mlp',xdim=784,hdim=256,ydim=10):
            super(MultiLayerPerceptronClass,self).__init__()
            self.name = name
            self.xdim = xdim
            self.hdim = hdim
            self.ydim = ydim
            # 입력층 - 은닉층 사이 네트워크
            self.lin_1 = nn.Linear( # indim, outdim
                self.xdim, self.hdim
            )
            # 은닉층 - 출력층 사이 네트워크
            self.lin_2 = nn.Linear( # indim, outdim
                self.hdim, self.ydim
            )
            self.init_param() # initialize parameters
            # 가중치 초기화
        def init_param(self):
            nn.init.kaiming_normal_(self.lin_1.weight)
            nn.init.zeros_(self.lin_1.bias)
            nn.init.kaiming_normal_(self.lin_2.weight)
            nn.init.zeros_(self.lin_2.bias)
    		# 순전파(입력 -> 출력 계산)
        def forward(self,x):
            net = x
            net = self.lin_1(net) # 입력층 -> 은닉층 선형 변환
            net = F.relu(net)     # 비선형 변환
            net = self.lin_2(net) # 은닉층 -> 출력층 선형 변환
            return net # logit
      
    M = MultiLayerPerceptronClass(name='mlp',xdim=784,hdim=256,ydim=10).to(device)
    loss = nn.CrossEntropyLoss() # 손실 함수 정의
    optm = optim.Adam(M.parameters(),lr=1e-3) # 옵티마이저 정의
    
  • Train Model

    M.init_param() # initialize parameters
    M.train() # train mode
    EPOCHS = 10
    # Epoch: 전체 데이터를 한 번 도는 것 
    for epoch in range(EPOCHS): 
        loss_val_sum = 0
        for batch_in,batch_out in train_iter:
            ### Forward path
            # 1. 입력 -> 출력 계산
            y_pred = M.forward(batch_in.view(-1, 28*28).to(device)) # reshape input data
            # 2. 손실값 계산
            loss_out = loss(y_pred,batch_out.to(device))
            ### Update
            # 3. reset gradient -> 그래디언트 초기화
            optm.zero_grad()
            # 4. backpropagate -> 손실 함수 그래디언트 계산
            loss_out.backward()
            # 5. optimizer update -> 각 가중치에 대해 업데이트
            optm.step()
              
            loss_val_sum += loss_out
        loss_val_avg = loss_val_sum/len(train_iter)
        ...
    



참고 자료


Leave a comment