convolution 연산 pytorch, navie for loop로 구현하기

ganadara·2023년 6월 10일
1

DL

목록 보기
4/5

convolution 연산 pytorch로 구현하기

OS

  • window 10
  • colab

Convolution

합성곱 신경망(Convolutional Neural Network, CNN)
성곱층(Convolution layer)와 풀링층(Pooling layer)로 구성되어 있다.

합성곱은 행렬의 합, 곱 연산으로 사용되며 선형함수이다.
딥러닝에서 주로 픽셀 이미지(행렬)의 특징 맵을 만드는 데 사용된다.
입력 데이터에 마법의 도장을 찍어서 유용한 특성만 드러나게 하는 것으로 비유 가능하다.

이미지 위에서 stride 값 만큼 filter(kernel)을 이동시키면서 겹쳐지는 부분의 각 원소의 값을 곱해서 모두 더한 값을 출력으로 하는 연산

인공 신경망은 처음에 가중치 w1~w10과 절편b를 랜덤학 초기화한 다음 에포크를 반복하면서 경사 하강법 알고리즘을 사용하여 손실이 낮아지도록 최적의 가중치와 절편을 찾아간다. 이것이 모델 훈련이다.
한 칸씩 이동하면서 출력을 만드는 것이 합성곱이다.

커널은 입력에 곱하는 가중치이고, 필터는 뉴련 개수를 표현할 때 사용.
tensor : 데이터의 배열
dot product(내적) : 2개의 vector를 같은 index에 해당하는 것끼리 곱해서 더한 것

합성곱 연산

합성곱 계층에서 합성곱 연산을 처리한다. 합성곱 연산은 이미지처리에서 말하는 필터 연산에 해당된다.
합성곱 연산은 입력 데이터에 필터를 적용한다. 입력 ㄷ이

padding

합성곱 연산을 수행하기 전에 입력 데이터 주변을 특정 값으로 채우는 것이다.

pooling

입력 데이터를 압축하여 연산량을 줄이는 작업이다.

implement 구현

torch

input = channel 3
NHWC = (10, 14, 14, 3), kernel=3, stride=2, oc=7
output = torch.nn.conv2d(input)
np.all_close(output, output2) == true

NHWC = ([batch_size, height, width, chnnels])
batch_size = : Total number of training examples present in a single batch. 나눠진 데이터 셋의 size. 한 번에 처리되는 데이터 샘플의 개수
oc = output channel

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)

import torch
import torch.nn as nn

#Conv2d layer 생성(in_channels=3, out_channels=7, kernel_size=(3, 3), stride=(2, 2))
conv = torch.nn.Conv2d(in_channels=3, out_channels=7, kernel_size=3, stride=2)

#input tensor 생성(NCHW) 
input = torch.randn(10, 3, 14, 14)  
print(input.shape)

output = conv(input)
output.shape

출력

torch.Size([10, 3, 14, 14])
torch.Size([10, 7, 6, 6])

naive for loop

input = channel 3
NHWC = (10, 14, 14, 3), kernel=3, stride=2, OC=7
output = myfunction(input)
np.all_close(output, output2) == true

import numpy as np

# input tensor 생성 (NCHW)
input = np.random.randn(10, 3, 14, 14)
batch_size, in_channels, height, width = input.shape

# Conv2d 연산을 수행하기 위한 output tensor 초기화

# Conv2d kernel의 생성
kernel = np.random.randn(7, 3, 3, 3)

# output 크기 구하기
# output_height = (height - kernel_height) // stride + 1
# output_width = (width - kernel_height) // stride + 1
output_height = (height - 3) // 2 + 1
output_width = (width - 3) // 2 + 1
output2 = np.zeros((batch_size, 7, output_height, output_width))

# Conv2d 연산 수행 (naive for loop)
for b in range(batch_size):
    for c_out in range(7):
        for i in range(output_height):
            for j in range(output_width):
                # stride=2에 해당하는 위치에서 Conv2d 연산 수행
                start_i = i * 2
                start_j = j * 2
                con = input[b, :, start_i:start_i + 3, start_j:start_j + 3]
                output2[b, c_out, i, j] = np.sum(con * kernel[c_out])

print(output2.shape)
  • np.random.randn
    random.randn(d0, d1, ..., dn)

출력

torch.Size([10, 7, 6, 6])

torch, navie for loop 결과가 같도록 구현

import torch
import torch.nn as nn
import numpy as np

# torch로 구현
# input tensor 생성(NCHW)
input = torch.randn(10, 3, 14, 14)

# Conv2d 연산 수행
# Conv2d layer 생성(in_channels=3, out_channels=7, kernel_size=(3, 3), stride=(2, 2))
conv = torch.nn.Conv2d(in_channels=3, out_channels=7, kernel_size=3, stride=2)

output = conv(input)
output_shape = output.shape


# naive for loop로 구현
# input tensor 생성 (NCHW)
input2 = np.random.randn(10, 3, 14, 14)
batch_size, in_channels, height, width = input2.shape

# output 크기 구하기
output_height = (height - 3) // 2 + 1
output_width = (width - 3) // 2 + 1

# Conv2d 연산을 수행하기 위한 output tensor 초기화
output2 = np.zeros((batch_size, 7, output_height, output_width))

# Conv2d kernel의 생성
kernel = np.random.randn(7, 3, 3, 3)

# Conv2d 연산 수행 
for b in range(batch_size):
    for c_out in range(7):
        for i in range(output_height):
            for j in range(output_width):
                # stride=2에 해당하는 위치에서 Conv2d 연산 수행
                start_i = i * 2
                start_j = j * 2
                con = input2[b, :, start_i:start_i + 3, start_j:start_j + 3]
                output2[b, c_out, i, j] = np.sum(con * kernel[c_out])

print(output_shape)
print(output2.shape)


# output 결과 같은 지 확인
print(tuple(output_shape) == output2.shape)



출력

torch.Size([10, 7, 6, 6])
(10, 7, 6, 6)
True
  • 참고

CONV2D
How to convert a pre-trained model from NCHW to NHWC format
numpy.random.randn

profile
DL 공부중

1개의 댓글

comment-user-thumbnail
2023년 6월 21일

🐻

답글 달기