안녕하세요
유튜브 채널명 텐초로 활동하고 있는 이종민 입니다.
이번에 제가 지금껏 공부해왔던 딥러닝 지식을 담은
《Must Have 텐초의 파이토치 딥러닝 특강》을 출간하게 되어 저자용 책으로 나눔 이벤트를 진행합니다🎉

딥러닝을 공부하는데 있어서 가장 중요한 기초를 다지는 예제와
초보 탈출을 위한 심화 예제까지 최대한 한권으로 딥러닝 공부를 끝마칠 수 있게 담아보았습니다.
파이토치를 이용해 직접 신경망을 설계해볼 수도 있고,
학습이 완료된 가중치를 공유하고 있으니 시간을 최대한 아껴서 공부하실 수 있습니다.

📕 교보 : https://bit.ly/3cxAktt
📕 예스24 : https://bit.ly/3oDdDGY
📕 알라딘 : https://bit.ly/3b5tCdT

본 책에 기대하는 점을 댓글로 남겨주시면 3명을 뽑아 보내드립니다.
자세한 내용은 아래를 사항을 참고해 주세요!

⭐️ 이벤트 개요
☑️ 참여 마감 : 2022년 8월 02일(화) 오후 9시
☑️ 당첨자 발표 : 2022년 8월 03일(수) 오전 11시
☑️ 참여 방법 : 본 책에 기대하는 점을 댓글로 남겨주세요
☑️ 당첨자 수 : 총 3분
☑️ 선물 : 《Must Have 텐초의 파이토치 딥러닝 특강》 종이책📕
☑️ 증정 방법 : 댓글에 연락처를 남겨주세요. 당첨자에게는 따로 연락을 드립니다.

---

고맙습니다.


WRITTEN BY
텐초
딥러닝 관련 논문들과 코드를 완벽분석 합니다

,

보통 음성혹은 주가 같은 시계열 데이터를 처리하기 위해 RNN계열의 알고리즘을 사용했습니다.
RNN계열의 특징은 네트워크의 가중치를 반복적으로 사용해서 시간순서를 모델링하는 것입니다.
그러나 여기서 문제가 생기게 됩니다.
RNN은 가중치를 반복적으로 호출하기 때문에 뒷부분의 결과를 내기 위해서는 반드시의 앞의 결과가 나올때까지 대기해야 합니다.
또한 매 층 마다 같은 타임 스텝을 이용해야 하기 때문에 시야가 고정적이라는 단점도 갖고 있습니다.
물론 dilated RNN같은 모델이 제안되었지만 여전히 stacked RNN구조에서 dilation을 다양하게 섞을 수는 없었습니다.
TCN(Temporal Convolutional Metwork)은 이런 RNN의 단점을 해결하고자 등장한 모델로
dialted convolution을 이용해 시계열 정보를 처리하는 모델입니다.

TCN

우선 TCN의 구조를 살펴봅시다

TCM의 구조, 층이 깊어질수록 dilation이 커진다

위 그림에서 시간은 왼쪽에서 오른쪽으로 흐르고 층은 아래에서 위로 쌓이게 됩니다.
층이 깊어질수록 dilation이 점점 커지는 것을 확인할 수 있습니다.
층이 깊어질수록 dilation을 크게하는 이유는 입력층에 가까울 수록 local information이 중요하고
층이 깊어짐에 따라 점점 temporal imformation, 즉 순서정보를 학습하기 위함입니다.

TCM을 여러층 쌓아 만든 TCNN 모델이 음성처리에 사용되는 예시

위에서 보여드린 예시는 TCM을 음성처리에 이용하는 모델입니다.
인코더와 디코더는 음성의 특징을 추출 및 복원하는 네트워크입니다. 가운데 TCM이 여러층 쌓아져 있으며
순서정보는 이 단계에서 학습됩니다.
처음 등장한 TCM은 동영상을 처리하기 위해 등장했기 때문에 TCM의 활용도는 task에 맞게 설정하시면 됩니다.

코드 구현(Pytorch)

TCM의 구조

앞서 말씀드린 TCNN에서 사용되는 TCM의 구조입니다.
마찬가지로 task에 따라 얼마든지 변형이 가능합니다.

import torch
import torch.nn as nn


class TCM(nn.Module):
    def __init__(self, in_channels, out_channels, dilation=5, kernel_size=3):
        super(TCM, self).__init__()

        self.c1 = nn.Conv1d(in_channels, out_channels, kernel_size=1)
        self.c2 = nn.Conv1d(out_channels, out_channels, kernel_size=kernel_size, dilation=dilation, padding=dilation)
        self.c3 = nn.Conv1d(out_channels, in_channels, kernel_size=1)

        self.bn1 = nn.BatchNorm1d(num_features=out_channels)
        self.bn2 = nn.BatchNorm1d(num_features=out_channels)

        self.prelu1 = nn.PReLU()
        self.prelu2 = nn.PReLU()

    def forward(self, x):
        x_ = x
        x = self.c1(x)
        x = self.prelu1(x)
        x = self.bn1(x)
        x = self.c2(x)
        x = self.prelu2(x)
        x = self.bn2(x)
        x = self.c3(x)

        x = x + x_

        return x


model = TCM(in_channels=64, out_channels=128)
input_tensor = torch.zeros(1, 64, 100)
print(model(input_tensor).shape)

 


WRITTEN BY
텐초
딥러닝 관련 논문들과 코드를 완벽분석 합니다

,

유행 다지나고 올리는 ViT 분석글입니다.
아직도 ViT를 모르는 사람이 있을까 싶지만
앞으로 나올 거의 대부분의 논문들이 ViT를 레퍼런스로 삼고 있기 때문에
이 기회에 완벽하게 분석해볼까 합니다.

영상으로 보고싶은 분들은
https://www.youtube.com/watch?v=QkwNdgXcfkg&t
위 영상을 봐주세요

바쁜신 분들을 위한 세줄 요약

  1. 이미지를 16X16으로 잘라 트랜스포머에 넣는다
  2. 좋은 성능을 내기 위해서는 무지막지한 양의 데이터로 사전학습이 필요
  3. CNN보다 훨씬 넓은 시야를 갖기 때문에 앞으로 컴퓨터 비전에서 막대한 영향을 미친다

ViT 개요

ViT는 "AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE"
라는 논문에서 처음 소개된 모델입니다.
제목에서 알 수 있듯, 이미지를 16X16 으로 나눠 트랜스포머에 입력하는 모델입니다.
트랜스포머는 원래 자연어처리에서 자주 사용되는 모델이었는데
순서 정보가 없는 이미지에서는 잘 사용되지 않는 모델이었습니다.
사실 트랜스포머의 인코더만 보면 입력 시퀀스를 전부 이용하기 때문에 순서가 존재하지 않는다고 볼 수도 있습니다.
굳이 구글이 연구하지 않았더라도 누군가는 알아챘을 겁니다.
그만큼 트랜스포머가 잘 설계된 모델이라는 얘기겠지요.

서론

어텐션 메커니즘이 등장한 이래로 자연어 처리 분야는 트랜스포머가 완전히 장악했으나,
컴퓨터 비전에서는 그렇지 못했습니다.
셀프 어텐션을 적용하려는 시도는 여럿 있었으나, 어느 것도 빛을 보진 못했죠.
Stand-Alone Self-Attention in Vision Models라는 논문에서는
컨볼루션을 어텐션으로 완전하게 대체한 모델을 선보였는데
GPU등의 하드웨어 가속을 받을 수 있는 모델의 설계에는 실패했습니다.
그만큼 어텐션을 컴퓨터 비전에 적용하기는 어려웠습니다.

ViT는 이전의 시도와는 별개로 비전에서 쓰이던 "커널"이라는 개념을 아예 제거했습니다.
앞서 말씀드린 시도들은 컨볼루션 대신 어텐션만 썼을 뿐이지 큰 틀에서는
CNN과 큰 다를바가 없었습니다.
ViT는 이미지를 16X16개의 패치로 나누어 각각의 패치를 토큰으로 이용해
트랜스포머의 입력으로 사용하는 색다른 접근을 사용했습니다.
하지만 어텐션은 본래 자연어 처리를 위해 등장한 알고리즘입니다.
텍스트 데이터는 이미지보다 훨씬 쉽게 많이 얻을 수 있기 때문에
비전에서도 자연어처리때와 같이 학습이 잘 되리라는 보장은 없었습니다.
예상대로 ViT는 CNN에 비해 inductive bias를 얻기 어려웠습니다.
ImageNet데이터셋을 이용해 학습해본 결과 우수한 CNN모델에 비해
성능이 떨어졌지만, JFT-300M 데이터셋 같이 3억 장의 이미지를 이용해
학습한 뒤, ImageNet에 대해 fine tuning하면 CNN보다 좋은 성능을 얻을 수 있었습니다.

모델 분석

우선 전체적인 모델 구조를 살펴보겠습니다.
각 파트의 상세설명은 뒤에 작성하겠습니다.

먼저 왼쪽 하단의 녹색으로 표시된 부분이 이미지를 패치로 나누는 부분입니다.
이 과정에서 2차원 이미지를 1차원의 벡터로 변경해줍니다.
변경된 벡터를 트랜스포머의 쿼리로 이용하며 이미지 패치와 동일한 의미로 사용하고 있으니
혼동하지 않도록 주의해 주세요.
트랜스포머의 입력으로 사용하기 위해 이미지의 일정 부분을 1차원으로 flatten 시키는 과정입니다.
그다음은 linear projection과정을 거치게 됩니다.
이 부분은 단순히 트랜스포머의 hidden dim, 즉 D차원으로 사상시키는 부분입니다.
LSTM에서도 워드임베딩을 이용해 BOW 등을 통해 얻은 벡터를 dense표현으로 바꾸고 linear projection을 통해
LSTM의 hidden dim으로 차원을 변경했었는데 그와 동일한 작업이라고 보시면 됩니다.
그 위에 파란색으로 표시된 부분은 각 패치에 positional embedding을 추가하는 부분입니다.
트랜스포머는 인코더의 모든 출력을 한번에 계산하기 때문에 데이터에 시계열 정보가 포함되어있지 않습니다.
최근에는 이런 임베딩 방법이 큰 효과가 없다는 연구들이 등장하고 있지만
ViT에서는 이미지 패치에 임베딩을 추가해 패치들의 위치정보를 더해주고 있습니다.
가장 왼쪽의 임베딩은 클래스 임베딩이라고 불리는 벡터인데
이미지 분류를 위해 사용되는 녀석입니다.
이렇게 이미지를 패치로 나누고 임베딩에 성공했으면 트랜스포머 인코더로 넣어주고
트랜스포머의 출력을 분류층에 넣어서 클래스분류를 해주면 ViT 완성입니다.

Fixed size patch

ViT의 가장 핵심적인 부분이라고 할 수도 있는 부분입니다.
그림에서는 3X3으로 나와있지만 실제로는 16X16으로 나눴다는 사실을 잊지 마세요.
우선 입력 이미지 $\textbf{x}$를 정의해야 합니다.
이미지는 너비, 높이, 채널 세 가지 정보를 포함하고 있기 때문에 원문에서
$$\textbf{x}\in\mathbb{R}^{H\times W\times C}$$
와 같이 표현하고 있습니다.
다음으로 이미지 패치 $\textbf{x}_p$ 를 정의해야 합니다.
이미지 패치는 1차원으로 펼쳐진 이미지의 일부분인데, 이때 패치의 가로와 세로를 $P$라고 하면
$\textbf{x}_p$는 다음과 같이 정의됩니다.
$$\textbf{x}_p\in\mathbb{R}^{N\times (P^2\cdot C)}$$
이때 N개의 패치가 생기는데, N은 $N=HW/P^2$로 패치 크기에 의해 결정됩니다.
즉 위 과정을 통해 N개의 $P^2\cdot C$차원의 벡터가 생긴다고 볼 수 있습니다.
마지막으로 패치들을 D차원으로 사상하면 Linear projection과정까지 온 것입니다.

Positional embedding & Class embedding

Positional embedding은 흔하게 쓰는 1차원 sinusoidal 임베딩을 사용했습니다.
임베딩 별 효과를 보기 위해 임베딩을 빼서 학습하고, 1차원 임베딩, 2차원 임베딩, 상대 거리 임베딩의 결과를 비교했는데 임베딩은 넣기만 한다면 방법론 간의 유의미한 차이는 없었다고 합니다.

Appendix D4에 나온 표를 보면 임베딩을 넣지 않으면 정확도가 0.61 정도로, 나머지는 0.64 정도가 나옵니다.
임베딩 방법 별로 결과의 차이가 있지만 크게 차이는 나지 않는 것을 볼 수 있습니다.

Sinusoial 임베딩은 sin함수와 cos함수를 이용한 임베딩 방법입니다.
위치를 임베딩 하기 위해서는 몇 가지 조건이 존재합니다.

  1. 위치별로 절대 값이 겹쳐서는 안 됨
  2. 임베딩의 길이가 일정해야 함
  3. 임베딩 값의 범위가 일정해야 함
  4. 같은 값을 넣으면 언제나 동일한 값이 나와야 함

이제 D차원의 입력 벡터의 절반에는 sin의 주기를 이용해 임베딩 값을 넣어주고
나머지 절반에는 cos의 주기를 이용해 임베딩 값을 넣어주면 됩니다.
주기를 바꿔주는 것으로 표현하고자 하는 위치의 개수가 늘어나더라도 유연하게 대처가 되는 방법이기 때문에 자주 등장합니다. 여기서는 크게 중요하게 다루지 않기 때문에 상세한 설명은 생략하겠습니다.

클래스 분류를 위해 BERT에서 cls토큰을 이용하듯, ViT 역시 cls 토큰을 추가했습니다.
단순히 D차원의 파라미터를 이미지 패치와 합쳐주고(concat), 임베딩 값을 더해주면 트랜스포머 인코더에 넣어줄 입력 텐서의 완성입니다.

1번 식이 입력 벡터를 만드는 과정을 나타낸 수식입니다.
$\textbf{x}_p$는 이미지 패치, $\textbf{E}$는 linear projection의 가중치라고 보시면 됩니다.
Linear projection이 완료된 이미지 패치에 위치 임베딩을 더해 $z_0$를 만들고 트랜스포머 인코더에 넣어줍니다.
위 수식의 LN은 Layer Norm, MSA는 Multi head self attention, MLP는 Mulit layer percrptron층을 나타냅니다.
MLP층의 활성화는 GELU 활성화를 사용했다고 합니다.

Transformer Encoder

ViT의 트랜스포머 인코더는 이미지 패치를 쿼리로 MSA를 계산합니다.
MSA는 Multi Head Self-attention의 약어로 하나의 어텐션 층이 여러 의미를 학습할 수 있도록 하는 알고리즘입니다.

입력으로 들어온 텐서를 fc층을 통해 쿼리(그림 상 Q), 키(K), 밸류(V)를 생성합니다. 만약 여기서, Q, K, V 세 텐서를 이용해 어텐션을 계산하면 하나의 어텐션 층에서 하나의 관계만을 획득할 수 있습니다.
현재의 입력을 통째로 사용했기 때문입니다.
하지만 여기서 만약 QKV를 그대로 사용하지 않고 4개로 나누어 각각의 어텐션을 구하면 어떻게 될까요?
그렇게 된다면 하나의 어텐션 층에서 4개의 관계를 획득할 수 있습니다.
MSA는 이런 원리를 통해 하나의 층에서 여러 관계를 학습할 수 있도록 설계된 알고리즘입니다.
여기서 QKV를 몇개로 나누는가에 따라 헤드 개수 H가 결정되며, 하나의 헤드는 분리된 벡터를 말합니다.
마지막 fc층에서는 모든 값에 대해 가중치가 부여되기 때문에 독립된 N개의 관계를 추출해도 마지막에 가서 정보를 합칠 수 있습니다.

실험 결과

ViT의 실험 결과, 사전 학습에 사용한 데이터셋 별 통계(왼쪽)와 사용한 이미지 개수 별 통계(오른쪽)

ViT는 CNN보다 inductive bias의 형성이 어렵습니다. 따라서 큰 이미지 데이터셋을 이용해 사전학습이 필요합니다.
위 그림에서 보이는 ViT-B, ViT-L, ViT-H는 각각 ViT-Base, Vit-Large, ViT-Huge의 약자로 뒤로 갈 수록 파라미터의 수가 많습니다.
뒤에 붙는 숫자는 패치의 크기를 의미합니다. 패치크기가 줄어들 수록 이미지를 좀더 세세하게 보게 됩니다.
왼쪽의 그림을 보면 그냥 ImageNet을 이용해 학습하면 ResNet(회색으로 칠해진 영역)의 결과를 뛰어넘을 수 없습니다.
하지만 데이터셋의 크기가 점점 커짐에 따라 ResNet의 성능을 뛰어넘기 시작합니다.
최종적으로는 ViT-H/14가 가장 좋은 성능을 내는데, 이는 곧

  1. 파라미터의 수를 늘리고
  2. 데이터셋의 양을 늘린 다음
  3. 패치크기를 줄여 이미지의 세세한 특징을 추출하면

좋은 성능을 낼 수 있다고 생각하면 됩니다.
오른쪽 그림은 사전 학습에 사용한 이미지의 개수를 비교분석한 그림입니다.
사전 학습에 더 많은 이미지를 사용할 수록, ViT계열 모델들이 ResNet계열 모델보다 성능이 나아짐을 볼 수 있습니다.

마무리

앞으로 수많은 모델들이 ViT를 사용할 것이라고 생각합니다.
DETR같은 모델은 ViT를 특징 추출기로 사용하고 있고, ViT의 발전형인 Swin-ViT도 제안되었습니다.
앞으로는 ViT가 레퍼런스 돼있는 논문을 읽을때 헤매지 않도록 이번 글에서는 ViT의 특징에 대해 적어보았습니다.


WRITTEN BY
텐초
딥러닝 관련 논문들과 코드를 완벽분석 합니다

,