반응형

안녕하세요. 오늘은 Deep Learning 분야에서 CNN의 BottleNeck구조에 대해 알아보겠습니다. 

 

대표적으로 ResNet에서 BottleNeck을 사용했습니다. 

 

ResNet에서 왼쪽은 BottleNeck 구조를 사용하지 않았고, 오른쪽은 BottleNeck 구조를 사용했습니다.

 

BottleNeck을 설명하기 전, Convolution의 Parameters을 계산할 줄 알아야 합니다. 이 부분은 다른 글에서 자세히 설명하겠습니다.

 

Convolution Parameters = Kernel Size x Kernel Size x Input Channel x Output Channel

 

BottleNeck의 핵심은 1x1 Convolution입니다. ( Pointwise Convolution 이라고도 합니다. 이는 Depthwise Separable Convolution에서도 똑같은 원리로 이용되기 때문에 잘 알아두면 좋습니다.)

1x1 Convolution의 Parameters는 1 x 1 x Input Channel x Output Channel입니다.

대게 1x1 Convolution은 연산량이 작기 때문에 Feature Map(Output Channel)을 줄이거나 키울 때 사용됩니다.

 

 

BottleNeck 구조

 

 

1. Input Channel = 256인 320x320  Input Image가 있다고 가정합니다. 

B=Batch SIze 

 

 

 

2. Channel Compression ( 채널 압축 )

Input Channel 256 -> Output Channel 64

256을 64로 채널을 강제로 축소한 이유는 오로지 연산량을 줄이기 위함입니다. 

 

1x1 Convolution에는 Spatial(공간적인) 특징을 가지고 있지 않습니다. Convolution 연산이 공간적인 특징을 추출하기 위해선 Kernel이 최소 2 이상 되어야 합니다. 

 

 

 

 

 

3. 특징 추출

 

Input Channel 64 -> Output Channel 64 

 

3x3 Convolution은 특성을 추출하는 역할을 합니다.

3x3 Convolution 연산은 = 3 x 3 x Input Channel x Output Channel 입니다. ( 3 x 3 x 64 x 64 )

 

3x3 Convolution은 1x1 Convolution 보다 9배 연산량이 많기 때문에, 1x1 Convolution에서 채널을 줄인 후에 

3x3 Convolution에서 특성을 추출합니다. 

 

 

 

 

4. Channel Increase( 채널 증가 )

Input Channel 64 -> Output Channel 256

 

CNN은 Feature Map의 특성이 많으면 많을수록 학습이 잘 되기 때문에, 1x1 Convolution으로 강제적으로 채널을 증가시켜줍니다. 

 

BottleNeck의 구조는 1x1 Convolution으로 장난을 치면서 연산량을 최소화하는 것입니다. 

 

하지만 강제로 채널을 줄이고 늘리는 것은 정보 손실을 일으킵니다. 

정보 손실은 모델의 정확성을 떨어뜨립니다. 

 

연산량과 정보손실은 서로 tradeoff 관계이기 때문에 서로의 합의점을 찾는 것이 중요합니다. 

ResNet이 제시한 두 구조를 Pytorch로 구현해 Parameter를 확인하겠습니다. 

 

Standard는 Channel 수가 적을지라도, 3x3 Convolution을 두 번 통과했고, 

BottleNeck은 1x1, 3x3, 1x1 순으로 Convolution을 통과하고, Channel 수는 4배 정도 많지만, Parameter가 세 배 정도 적습니다. 

 

그리고 형성된 것이 도로의 병목 현상과 비슷하다 하여 BottleNeck 구조라고 불립니다.

병목 현상

 

 

cf) Pytorch Code

# standard
class Standard(nn.Module):
    def __init__(self, in_dim=256, mid_dim=64, out_dim=64):
        super(BuildingBlock, self).__init__()
        self.building_block = nn.Sequential(
            nn.Conv2d(in_channels=in_dim, out_channels=mid_dim, kernel_size=3, padding=1, bias=False),
            nn.ReLU(),
            nn.Conv2d(in_channels=mid_dim, out_channels=out_dim, kernel_size=3, padding=1, bias=False),
        )
        self.relu = nn.ReLU()

    def forward(self, x):
        fx = self.building_block(x)  # F(x)
        out = fx + x  # F(x) + x
        out = self.relu(out)
        return out
# BottleNeck
class BottleNeck(nn.Module):
    def __init__(self, in_dim=256, mid_dim=64, out_dim=256):
        super(BottleNeck, self).__init__()
        self.bottleneck = nn.Sequential(
            nn.Conv2d(in_channels=in_dim, out_channels=mid_dim, kernel_size=1, bias=False),
            nn.ReLU(),
            nn.Conv2d(in_channels=mid_dim, out_channels=mid_dim, kernel_size=3, padding=1, bias=False),
            nn.ReLU(),
            nn.Conv2d(in_channels=mid_dim, out_channels=in_dim, kernel_size=1, bias=False),
        )

        self.relu = nn.ReLU()

    def forward(self, x):
        fx = self.bottleneck(x)  # F(x)
        out = fx + x  # F(x) + x
        out = self.relu(out)
        return out
728x90
반응형
반응형

안녕하세요. 저번 Depthwise Separable Convolution 기법에 대해 글을 올렸습니다.

 

오늘은 이 기법을 사용한 Xception 논문에 대해 리뷰하도록 하겠습니다. 

 

https://openaccess.thecvf.com/content_cvpr_2017/html/Chollet_Xception_Deep_Learning_CVPR_2017_paper.html

 

CVPR 2017 Open Access Repository

Francois Chollet; Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2017, pp. 1251-1258 We present an interpretation of Inception modules in convolutional neural networks as being an intermediate step in-between regular

openaccess.thecvf.com

 

우선, Xception을 리뷰하기 전 Inception에 대해 간단히 짚고 넘어가겠습니다. 

 

Inception 모듈로 2014년도에 가장 높은 성적을 거둔 GoogleLeNet 을 만들었습니다.

 

 

 

 

 

1. Inception Module

 

 

Inception Module

 

인셉션 모듈은 이전 단계의 활성화 지도에 다양한 필터 크기(Kernel_Size)로 합성곱 연산을 적용하는 방식입니다.

 

쉽게 표현하면, 강아지 사진에서 귀, 코, 눈 등의 특징을 다른 방향으로 보는 것입니다. 

 

다른 방향에서 보기 때문에, 같은 강아지 사진에서 다른 특성들을 추출할 수 있습니다.

 

인셉션은 적은 파라미터로 다양한 특징값을  추출하는데 의미가 있습니다.

 

class InceptionModule(nn.Module):
    def __init__(self, n_channels=10):
        super(InceptionModule, self).__init__()
        # Sequential : 연산을 차례로 수행

        self.conv2d_3k = nn.Conv2d(in_channels=n_channels,
                                   out_channels=n_channels,
                                   kernel_size=3,
                                   padding=1)

        self.conv2d_1k = nn.Conv2d(in_channels=n_channels,
                                   out_channels=n_channels,
                                   kernel_size=1)

        self.avgpool2d = nn.AvgPool2d(kernel_size=1)

    def forward(self, x):
        y1 = self.conv2d_1k(x)

        y2_1 = self.conv2d_1k(x)
        y2_2 = self.conv2d_3k(y2_1)

        y3_1 = self.avgpool2d(x)
        y3_2 = self.conv2d_3k(y3_1)

        y4_1 = self.conv2d_1k(x)
        y4_2 = self.conv2d_3k(y4_1)
        y4_3 = self.conv2d_3k(y4_2)

        out = torch.cat([y1, y2_2, y3_2, y4_3], dim=1)

        return out

 

 

2. 단순한 Inception Module

A Simplified Inception Module

 

저번 글에 나온 Depthwise Separable Convolution의 핵심 개념인 spartial correlation(3x3 convolution)cross channel correlation(1x1 convolution)이 등장합니다. 

 

여기 Standard Convolution과 차별 점은 서로가 매핑(mapping)되지 않고 독립적으로 수행하는 것입니다.

 

Figure1의 복잡함을 최대한 Simple하게 가는데 의미가 있습니다.

 

class SimplyInceptionModule(nn.Module):
    def __init__(self, n_channels=10):
        super(SimplyInceptionModule, self).__init__()
        # Sequential : 연산을 차례로 수행

        self.conv2d_3k = nn.Conv2d(in_channels=n_channels,
                                   out_channels=n_channels,
                                   kernel_size=3,
                                   padding=1)

        self.conv2d_1k = nn.Conv2d(in_channels=n_channels,
                                   out_channels=n_channels,
                                   kernel_size=1)

    def forward(self, x):
        y1_1 = self.conv2d_1k(x)
        y1_2 = self.conv2d_3k(y1_1)

        y2_1 = self.conv2d_1k(x)
        y2_2 = self.conv2d_3k(y2_1)

        y3_1 = self.conv2d_1k(x)
        y3_2 = self.conv2d_3k(y3_1)

        out = torch.cat([y1_2, y2_2, y3_2], dim=1)

        return out

 

 

3. 더 단순한 Inception module

A strictly equivalent reformulation of the simplified Inception module

 

Figure2에서 1x1 Convolution을 Input마다 독립적으로 수행했다면,

 

Figure3에서는 1x1 Convolution을 input 한 번만을 수행합니다. 

 

1x1 Convolution 수행한 output을 (그룹으로) 분리하여 3x3 Convolution을 수행합니다. 

 

Figure2를 변형하여 더 Simple하게!

 

SimplyInceptionModule3 = nn.Sequential(
    nn.Conv2d(in_channels=9,
              out_channels=9,
              kernel_size=1,
              bias=False),
              
    nn.ReLU(),

    nn.Conv2d(in_channels=9,
              out_channels=9,
              kernel_size=3,
              groups=3,
              bias=False),
    
    nn.ReLU()

)

 

 

 

 

이 논문에서 중요한 부분이라고 생각되는 부분입니다. 

 

 This observation naturally raises the question: 
 
 이 관찰은 당연히 문제를 제기합니다.
 
 what is the effect of the number of segments in the partition (and their size)?
 
 파티션의 세그먼트 수 (및 크기)는 어떤 영향을 미칩니까?
 

 

 

 

 

4. Extreme version of Inception module

Figure3에서 Output Channels를 최대로 그룹을 지어 분리하여 수행하면 어떨까?

 

An Extreme version of Inception module

 

위 논문의 질문의 가설로,  파티션의 세그먼트를 최대 단위로 수행한다면 어떻게 되는가?

 

ExtremeInception = nn.Sequential(
    nn.Conv2d(in_channels=9,
              out_channels=9,
              kernel_size=1,
              bias=False),
              
    nn.ReLU(),

    nn.Conv2d(in_channels=9,
              out_channels=9,
              kernel_size=3,
              groups=9,
              bias=False),
    
    nn.ReLU()

)

 

 

We remark that this extreme version of an Inception module is almost identical to a depthwise 
separable convolution, an operation that has been used in neural network design as early as 
2014 and has become more popular since its inclusion in the TensorFlow framework in 2016.


An extreme version of Inception module은 2014 년 초 신경망 설계에 사용되었으며 2016 년 TensorFlow 프레임 워크에 
포함 된 이후 더 널리 사용되는 Depthwise Separable Convolution과 거의 동일합니다.

 

depthwise separable convolution 와 비슷한 형태의 모듈이 생성됩니다.

 

depthwise separable convolution가 궁금하시면

 

https://coding-yoon.tistory.com/77

 

[딥러닝] Depthwise Separable Covolution with Pytorch( feat. Convolution parameters VS Depthwise Separable Covolution paramet

안녕하세요. Google Coral에서 학습된 모델을 통해 추론을 할 수 있는 Coral Board & USB Accelator 가 있습니다. 저는 Coral Board를 사용하지 않고, 라즈베리파이4에 USB Accelator를 연결하여 사용할 생각입니..

coding-yoon.tistory.com

 

Xception을 한 번에 작성할려고 했지만 생각보다 쓸 것이 많아 2편 정도로 연장될 것 같습니다. 

 

첫 논문 리뷰인데 부족한 부분이 많습니다. 피드백 주시면 감사하겠습니다.

 

 

728x90
반응형
반응형
글의 가독성을 위해 아래 링크에 정리해둠.

https://blog.naver.com/younjung1996/223413266165

 

[딥러닝] Depth-wise Separable Convolution

Depth-wise Separable Convolution은 합성곱 신경망(CNN:Convolution Neural Network)의 효율성과...

blog.naver.com

안녕하세요. 

 

Google Coral에서 학습된 모델을 통해 추론을 할 수 있는 Coral Board & USB Accelator 가 있습니다. 

 

저는 Coral Board를 사용하지 않고, 라즈베리파이4에 USB Accelator를 연결하여 사용할 생각입니다. 

 

딥러닝을 위해 나온 제품이라 할지라도 아직 부족한 부분이 많습니다.

 

이런 고성능 환경이 아닌 곳에서도 학습하고, 추론할 수 있는 모바일 넷(Mobile Net)이 개발되었습니다. 

 

그 중 Mobile Net의 Architecture에서 Depthwise Separable Convolution에 대해 이야기하겠습니다. 

 

Depthwise separable Convoltion은 Parameter를 줄임으로, 연산량을 줄이고, 속도를 높이는 기법입니다. 

 

 

 

 

 

https://hichoe95.tistory.com/48

 

Different types of Convolutions (Grouped convolution, depthwise convolution, pointwise convolution, depthwise separable convolut

오늘 정리해 볼 것들은 앞으로 정리할 논문들을 위해 미리 알아두면 좋은 convolution입니다. 각 convolution들에 대한 간단한 특징과 param수, 연산량 등에대해서 알아봅시다 ㅎㅎ 들어가기에 앞서 몇��

hichoe95.tistory.com

 

Depthwise Separable Convolution = Depthwise Convolution + Pointwise Convolution

 

아마 Depthwise Separable Convolution을 공부하실 때 위 그림을 가장 많이 보셨을겁니다.

 

 

 

Depthwise Convolution으로 채널간 Spartial Correlations을 고려하여 ~ 각각 독립적으로 패턴을 파악하고 ~ 

Pointwise Convolution으로 Cross Channel Correlations로 채널을 조절할 수 있는 ~ 블라블라

 

위 블로그 분께서 굉장히 정리를 잘해주셨습니다.

 

그럼 저의 글의 목적은 무엇이냐.

 

Standard Convolution과 Depthwise Separable Covolution를 pytorch로 구현하여 정말로 파라미터 수와 연산량이 줄어드는지 결과값을 눈으로 확인하는 것입니다.

 

 

1. Standard Convolution

Convolution = K * K * C * M

 

k : Kernel ( 3으로 가정)

c : intput_dimension (channel ) (100으로 가정)

m : output_dimension (activation map) (1000으로 가정)

 

standard_convolution = nn.Conv2d(in_channels=100, out_channels=1000, kernel_size=3, bias=False)
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 1000, 15, 15]         900,000
================================================================
Total params: 900,000
Trainable params: 900,000
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 1.72
Params size (MB): 3.43
Estimated Total Size (MB): 5.26
----------------------------------------------------------------

 

 

2. Depth-wise Convolution

Depthwise Convolutuon = K * K * C

 

k : Kernel ( 3으로 가정)

c : intput_dimension (channel ) (100으로 가정)

m : output_dimension (activation map) (1000으로 가정)

 

depthwise_convolution = nn.Conv2d(in_channels=100, out_channels=1000, kernel_size=3, groups=100,bias=False)
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1          [-1, 100, 15, 15]             900
================================================================
Total params: 900
Trainable params: 900
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 0.17
Params size (MB): 0.00
Estimated Total Size (MB): 0.29
----------------------------------------------------------------

 

 

3. Point-wise Convolution ( 1 x 1 Convolution )

Pointwise Convolutuon = C * M

 

k : Kernel ( 3으로 가정)

c : intput_dimension (channel ) (100으로 가정)

m : output_dimension (activation map) (1000으로 가정)

 

pointwise_convolution = nn.Conv2d(in_channels=100, out_channels=1000, kernel_size=1, bias=False)
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 1000, 17, 17]         100,000
================================================================
Total params: 100,000
Trainable params: 100,000
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 2.20
Params size (MB): 0.38
Estimated Total Size (MB): 2.70
----------------------------------------------------------------

 

 

4. Depthwise Separable Convolution 

Depthwise Separable Convolution = K * K * C + C * M = C( K * K + M )

 

k : Kernel ( 3으로 가정)

c : intput_dimension (channel ) (100으로 가정)

m : output_dimension (activation map) (1000으로 가정)

 

depthwise_separable_convolution = nn.Sequential(
    nn.Conv2d(in_channels=100,
              out_channels=100,
              kernel_size=3,
              groups=100,
              bias=False),

    nn.Conv2d(in_channels=100,
              out_channels=1000,
              kernel_size=1,
              bias=False)
)
----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1          [-1, 100, 15, 15]             900
            Conv2d-2         [-1, 1000, 15, 15]         100,000
================================================================
Total params: 100,900
Trainable params: 100,900
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 1.89
Params size (MB): 0.38
Estimated Total Size (MB): 2.38
----------------------------------------------------------------

Depthwise Separable Convolution = Depthwise Convolution + Pointwise Convolution ( 100900 = 100000 + 900 ) 

 

Standard Convolution Parameters = 900,000

Depthwise Separable Convolution Parameters = 100,900

 

=> 약 K(Kernel Size) 제곱의 차이

 

5. Kernel Size가 값이 굉장히 크다면... ( kerenl size == 7 )

 

Standard Convolution 

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 1000, 11, 11]       4,900,000
================================================================
Total params: 4,900,000
Trainable params: 4,900,000
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 0.92
Params size (MB): 18.69
Estimated Total Size (MB): 19.73
----------------------------------------------------------------

 

Depthwise separable Convolution 

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1          [-1, 100, 11, 11]           4,900
            Conv2d-2         [-1, 1000, 11, 11]         100,000
================================================================
Total params: 104,900
Trainable params: 104,900
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.11
Forward/backward pass size (MB): 1.02
Params size (MB): 0.40
Estimated Total Size (MB): 1.53
----------------------------------------------------------------

 

Kernel의 사이즈가 커질수록, 엄청난 파라미터 수의 감소를 보여주며, 곱셈을 덧셈으로 대체하기 때문에 연산이 굉장히 빨라집니다.

 

이러한 특징덕에 의해, Depthwise separable Convolution를 통한 Inception, Xception, mobile net 등 여러 논문에서 많이 등장합니다. 

 

728x90
반응형
반응형

오늘은 Pytorch를 통해 RNN을 알아보겠습니다. 

 

https://www.youtube.com/watch?v=bPRfnlG6dtU&t=2674s

RNN의 기본구조를 모르시면 위 링크를 보시는걸 추천드립니다.

 

Pytorch document에 RNN을 확인하겠습니다.

https://pytorch.org/docs/stable/nn.html

 

RNN with Pytorch

 

RNN with Book

 

 

1. RNN (default)

 

RNN의 입력은 [sequence, batch_size, input_size] 으로 이루어집니다.

 

import torch
import torch.nn as nn


input = torch.randn(4, 7, 5)
print(input.size())
# 결과 
# torch.Size([4, 7, 5])

sequence = 4차원,

batch_size = 7차원,

input_size = 5차원 인 임의의 input 데이터를 생성했습니다.

 

2. nn.RNN

 

RNN의 기본 인자 값으로 input_size=5, hidden_size=4, num_layer=3 값을 받습니다. 

rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3)
print(rnn_layer)

# 결과
# RNN(5, 4, num_layers=3, batch_first=True)

input_size는 Input의 input_size의 값을 받으므로, 5로 적어주시면 됩니다.

 

hidden_size는 nn.RNN을 걸치면 나오는 Output으로 볼 수 있으며, 위 그림의 주황색 박스입니다. 

 

hidden_size = 4 이므로 output 또한 4차원으로 만들어집니다. 

 

num_layer는 층으로 보시면 편할 것 같습니다. num_layer = 3 이므로 3개의 층이 생성됩니다. 

 

(output, hidden) = rnn_layer(input)

print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))

# 결과 
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 7, 4])

 

 

RNN Structure

RNN을 검색해보셨다면 위 그림은 정말 많이 보셨을거라고 생각합니다. 

 

처음에 RNN을 공부할 때 위 그림이 무슨 말인고 하고 별로 신경쓰지 않았지만, 상당히 중요한 그림입니다. 

 

nn.RNN의 함수를 사용하면 위 코딩처럼 output, hidden의 값을 뱉어냅니다. 

 

2개의 값을 뱉어낸 이유는 그림을 쉽게 이해할 수 있습니다. 

RNN return output, hidden

A 박스에 input X0의 값이 들어가면, output은 h0 의 값을 반환하고 hidden은 다음 Sequnece의 A박스에 값이 들어가므로 output과 hidden의 값을 반환합니다. 

 

Output size : torch.Size[4, 7, 4])

Hidden size : torch.Size[3, 7, 4])

 

값의 size를 찍어보면 이상한 형태로 사이즈가 반환됩니다. 

 

output : [sequence, batch_size, hidden_size] 

hidden : [num_layer, batch_size, hidden_size] 

 

값의 반환은 위처럼 규칙을 따라 모양이 변형됩니다. 

 

batch_size = 7

sequence = 4

input_size = 5

hidden_size =4

num_layer = 3

 

위에서 사용하는 인자들을 보면서 하나씩 봐보면 값이 일치합니다. 

 

조금 더 자세히 보도록 하겠습니다.

 

output[-1], hidden[-1]

output[-1]이란.

output : [sequence, batch_size, hidden_size]  에서 Sequence의 가장 끝을 의미합니다. (보라색 상자)

hidden[-1]이란.

hidden : [num_layer, batch_size, hidden_size]  에서 num_layer의 가장 끝을 의미합니다. (회색 상자)

 

결국 output[-1]과 hidden[-1]이 hT(k)를 지칭하므로, 둘은 같은 값을 의미합니다 한 번 찍어보겠습니다.

print(output[-1])
print(hidden[-1])

# 결과
tensor([[ 0.8153, -0.1394,  0.3829,  0.0173],
        [ 0.8094,  0.2289,  0.4830, -0.2243],
        [ 0.7936, -0.0426,  0.3890, -0.0643],
        [ 0.7714,  0.3094,  0.4685, -0.2558],
        [ 0.8282,  0.1141,  0.4310, -0.1885],
        [ 0.8027, -0.0607,  0.3745, -0.0249],
        [ 0.8292, -0.1473,  0.4938,  0.0935]], grad_fn=<SelectBackward>)

tensor([[ 0.8153, -0.1394,  0.3829,  0.0173],
        [ 0.8094,  0.2289,  0.4830, -0.2243],
        [ 0.7936, -0.0426,  0.3890, -0.0643],
        [ 0.7714,  0.3094,  0.4685, -0.2558],
        [ 0.8282,  0.1141,  0.4310, -0.1885],
        [ 0.8027, -0.0607,  0.3745, -0.0249],
        [ 0.8292, -0.1473,  0.4938,  0.0935]], grad_fn=<SelectBackward>)

 실제로도 들어있는 값들이 같음을 알 수 있습니다. 

 

 

2. batch_first=True ( default는 False이다. )

 

pytorch는 모델에 데이터를 넣을 때는 batch_size를 가장 먼저 앞에 나옵니다. 

 

하지만 RNN이나 LSTM 같은 경우는 batch_size가 아닌 sequence가 가장 먼저 나옵니다.

 

input : [sequence, batch_size, input_size]

 

model에서 나오는 output 또한 sequence가 가장 먼저 나옵니다.

 

output : [sequence, batch_size, hidden_size]

 

이렇게 sequence가 가장 앞에서 사용되면 가끔 데이터 차원이 헷갈립니다. 

 

그럴 때 사용하는 것이 batch_first=True 입니다. default는 False입니다.

 

batch_first를 True로 설정하면 batch_size가 제일 먼자 앞으로 이동합니다. 

 

input : [batch_size, sequence, input_size]

   

output : [batch_size, sequence, hidden_size]

 

hidden은 그대로입니다.

 

사용하는 방법은 간단합니다. 

 

import torch
import torch.nn as nn


input = torch.randn(4, 7, 5)
print(input.size())

rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3, batch_first=True)
print(rnn_layer)

# 결과 
# RNN(5, 4, num_layers=3, batch_first=True)

 

batch_first를 True하게 되어 batch_size가 가장 앞으로 가게 됩니다. 

 

그렇다면 인자들에 전달된 값 또한 변합니다.

 

batch_size = 4

sequence = 7

input_size = 5

hidden_size =4

num_layer = 3

 

으로 변경됩니다.

 

print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))

#output : [batch_size, sequence, hidden_size]
#hidden : [num_layer, batch_size, hidden_size] 
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 4, 4])

모양이 달라졌지만 사이즈 이외에는 크게 바뀌는 것은 없습니다. 

 

indexing 하는 방법을 sequnece, num_layer를 똑같이 적용시켜주면 됩니다.

 

print(output[:, -1, :])
print()
print(hidden[-1])

#결과
tensor([[-0.2105,  0.4423,  0.8115, -0.2838],
        [-0.4891,  0.1518,  0.8839, -0.3675],
        [-0.5495,  0.3221,  0.8500, -0.4782],
        [-0.5822,  0.3100,  0.7938, -0.4242]], grad_fn=<SliceBackward>)

tensor([[-0.2105,  0.4423,  0.8115, -0.2838],
        [-0.4891,  0.1518,  0.8839, -0.3675],
        [-0.5495,  0.3221,  0.8500, -0.4782],
        [-0.5822,  0.3100,  0.7938, -0.4242]], grad_fn=<SelectBackward>)

 

 

728x90
반응형
반응형

선형 회귀를 Pytorch로 구현하겠습니다.

 

이 글을 보시기 전에 아래 링크를 보시는 것을 추천드립니다.

 

https://coding-yoon.tistory.com/50?category=825914

 

[딥러닝] 선형 회귀(Linear Regression)

지도 학습에는 대표적으로 세가지가 있습니다. 1. 선형 회귀 ( Linear Regression ) : 3월 : 60점, 6월 : 70점, 9월 : 80점이라면, 12월은 몇 점일까? 2. 이진 분류 ( Binary Classification ) : [0, 1], [True, F..

coding-yoon.tistory.com

최대한 선형 회귀식처럼 보기 쉽게끔 코딩하였습니다.

 

아래 코딩과 비교하면서 봐보세요.

 

# 선형 회귀
import torch
import torch.nn as nn  # 선형회귀를 불러오기 위한 라이브러리
import torch.optim as optim  # 경사하강법를 불러오기 위한 라이브러리
import torch.nn.init as init  # 텐서의 초기값을 구하기 위한 라이브러리

data = 1000  # 몇 개의 데이터를 만들 것인가...
epoch = 500  # 몇 번을 거쳐 돌릴 것인가... ( = 데이터 전체를 학습에 한 번 사용하는 주기 )
W = 4  # weight ( = 기울기 )
b = 5  # bias  ( = 절편 )

x = init.uniform_(torch.Tensor(data, 1), -10, 10)  # Input data
y = W * x + b  # Output data

model = nn.Linear(1, 1)  # 선형회귀 모델 ( Input 특성의 수, 결과로 나오는 특성의 수 )
cost_function = nn.MSELoss()  # MSE : 제곱의 평균 ( = Mean of squares )

# optim : 최적화 함수 ( = optimizer)
# SGD : 경사하강법 ( = stochastic gradient descent )
# model.parameters() : model 의 parameter(w, b) 를 전달
# lr : 학습률 ( = learning rate )
optimizer = optim.SGD(model.parameters(), lr=0.01)

for i in range(epoch):
    optimizer.zero_grad()  # 처음엔 gradient 값이 없기 때문에 0으로 초기화
    H_x = model(x)  # hypothesis
    loss = cost_function(H_x, y)  # cost(=loss) 구하기

    loss.backward()  # W, b에 대한 기울기 계산
    optimizer.step()  # optimizer 호출, 경사하강법을 사용하여 업테이트

    # 10번 씩 수행하면 cost 출력
    if i % 10 == 0:
        print("Cost(=loss) :", loss.item())

result = list(model.parameters())
print("W :", result[0].item())
print("b :", result[1].item())

 

# 결과
Cost(=loss) : 814.8699340820312
Cost(=loss) : 12.195707321166992
Cost(=loss) : 8.143980026245117
Cost(=loss) : 5.438344955444336
Cost(=loss) : 3.6315879821777344
Cost(=loss) : 2.4250807762145996
Cost(=loss) : 1.6194065809249878
Cost(=loss) : 1.081398606300354
Cost(=loss) : 0.7221314907073975
Cost(=loss) : 0.4822206497192383
Cost(=loss) : 0.3220142424106598
Cost(=loss) : 0.21503257751464844
Cost(=loss) : 0.14359332621097565
Cost(=loss) : 0.09588787704706192
Cost(=loss) : 0.06403134018182755
Cost(=loss) : 0.042758237570524216
Cost(=loss) : 0.02855268307030201
Cost(=loss) : 0.01906675659120083
Cost(=loss) : 0.012732233852148056
Cost(=loss) : 0.008502312004566193
Cost(=loss) : 0.005677602719515562
Cost(=loss) : 0.003791437717154622
Cost(=loss) : 0.0025317480321973562
Cost(=loss) : 0.001690658857114613
Cost(=loss) : 0.001128957374021411
Cost(=loss) : 0.0007538488134741783
Cost(=loss) : 0.0005033717607147992
Cost(=loss) : 0.0003361686831340194
Cost(=loss) : 0.00022449734387919307
Cost(=loss) : 0.0001499166974099353
Cost(=loss) : 0.00010010885307565331
Cost(=loss) : 6.684719119220972e-05
Cost(=loss) : 4.463006553123705e-05
Cost(=loss) : 2.9802462449879386e-05
Cost(=loss) : 1.990168311749585e-05
Cost(=loss) : 1.3289816706674173e-05
Cost(=loss) : 8.872347279975656e-06
Cost(=loss) : 5.9264275478199124e-06
Cost(=loss) : 3.959625701099867e-06
Cost(=loss) : 2.6436666757945204e-06
Cost(=loss) : 1.766238597156189e-06
Cost(=loss) : 1.1812345519501832e-06
Cost(=loss) : 7.882306931605854e-07
Cost(=loss) : 5.261869091555127e-07
Cost(=loss) : 3.516942399528489e-07
Cost(=loss) : 2.3484382438709872e-07
Cost(=loss) : 1.5710433842741622e-07
Cost(=loss) : 1.0491751822883089e-07
Cost(=loss) : 6.964684473587113e-08
Cost(=loss) : 4.667232644806063e-08
W : 3.9999990463256836
b : 4.999824047088623

Process finished with exit code 0

 

아래 결과를 자세히 보시면 중간까지는 cost의 값이 굉장히 작다가 후반부에 cost의 값이 증가하는 것을 확인할 수 있습니다. 

 

모델링을 할 때 유의사항 중 epoch를 무조건 많이 준다하여, 학습이 잘되는 것이 아닙니다.

 

데이터 처리, 모델링, epoch 등을 모두 적절하게 적용하여야 합니다.

728x90
반응형

+ Recent posts