๐ CNN๋?
CNN(Convolutional Neural Network)์ ์ด๋ฏธ์ง ์ธ์๊ณผ ๋ถ๋ฅ์ ํนํ๋ ์ธ๊ณต์ ๊ฒฝ๋ง์ผ๋ก, ์ฌ๋์ ์๊ฐ ์ฒ๋ฆฌ ๋ฐฉ์๊ณผ ์ ์ฌํ๊ฒ ๊ตญ์์ ์ธ ์์ญ์ ์ค์ฌ์ผ๋ก ํน์ง(feature)์ ์ถ์ถํ๊ณ ํ์ตํ๋ค. ๊ธฐ์กด์ MLP๋ณด๋ค ์ด๋ฏธ์ง ๊ตฌ์กฐ๋ฅผ ๋ ์ ๋ฐ์ํ๋ฉฐ, ์ปดํจํฐ ๋น์ (CV) ๋ถ์ผ์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ค.
<ํฉ์ฑ๊ณฑ ์ธต - Convolution Layer>
- ์ ๋ ฅ ์ด๋ฏธ์ง์ ํํฐ(์ปค๋)๋ฅผ ์ ์ฉํด ํน์ง ๋งต(Feature Map) ์์ฑ
- ๋ณดํต 3ร3 ํฌ๊ธฐ์ ํํฐ ์ฌ์ฉ (VGGNet ๋ฑ) โ ์์์๋ก ๋ค์ํ feature ์ถ์ถ ๊ฐ๋ฅ
- ํํฐ์ ๋๊ป๋ ์ ๋ ฅ ๋ฐ์ดํฐ(์: RGB โ 3)์ ์๋ ๋ง์ถฐ์ง
- Stride: ํํฐ ์ด๋ ๊ฐ๊ฒฉ, ์์์๋ก ์ ๋ฐํ๊ณ ํด์๋ก ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌ๋จ
- Padding: ์ถ๋ ฅ feature map ํฌ๊ธฐ๋ฅผ ์ ์งํ๋ ค๋ฉด padding=same ์ค์
- ํฉ์ฑ๊ณฑ ์ฐ์ฐ ๋ค์๋ ํ์ฑํ ํจ์(ReLU)๋ฅผ ์ ์ฉํด ๋น์ ํ์ฑ ๋์
<ํ๋ง ์ธต - Pooling Layer>
- MaxPooling: ํ๋ง ์์ญ์ ์ต๋๊ฐ โ ์ฃผ์ ํน์ง๋ง ๊ฐ์กฐ
- AveragePooling: ์์ญ ๋ด ํ๊ท ๊ฐ ์ฌ์ฉ
- GlobalAveragePooling: Flatten ์์ด ์ ์ฒด ํ๊ท ๋ง ๋ฝ์๋ด๋ ๋ฐฉ์ (GoogLeNet)
- ์ฐ์ฐ๋ ๊ฐ์ + ๊ณผ์ ํฉ ๋ฐฉ์ง + ๊ณต๊ฐ ๊ตฌ์กฐ ์์ฝ
<๋ฐ์ง์ธต - Fully Connected Layer>
- Flatten ๋ ์ด์ด๋ก feature map์ 1์ฐจ์ ๋ฒกํฐ๋ก ๋ณํ
- ์ดํ Fully Connected Layer๋ฅผ ๊ฑฐ์ณ ํด๋์ค๋ณ ์ถ๋ ฅ๊ฐ ์์ฑ
- ์ฃผ๋ก softmax๋ฅผ ์ถ๋ ฅ์ธต ํ์ฑํ ํจ์๋ก ์ฌ์ฉํด ํ๋ฅ ๊ฐ ๋์ถ
๐งฎ example flow
- ์: ์ต์ข ์ถ๋ ฅ๊ฐ์ด (0.7, 0)์ด๊ณ ์ ๋ต์ด (1, 0)์ธ ๊ฒฝ์ฐ โ 0.3 ์ค์ฐจ
- ์ด ์ค์ฐจ๋ฅผ ์ญ์ ํ(backpropagation)๋ก ์ ํํ๋ฉฐ ๊ฐ์ค์น ์ ๋ฐ์ดํธ
- ๊ฒฝ์ฌํ๊ฐ๋ฒ(gradient descent) ๋ฑ ์ต์ ํ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ
๐๏ธ CNN ๋ชจ๋ธ๊ณผ ์ธ๊ฐ ์๊ฐ ์ฒ๋ฆฌ์ ์ ์ฌ์ฑ
- ์ธ๊ฐ์ ์๊ฐ ํผ์ง๋ ๋จ์ํ ์๊ฐ ์ ๋ณด โ ๋ณต์กํ ํน์ง ์์ผ๋ก ์ฒ๋ฆฌ
- CNN๋ ์ธต์ด ๊น์ด์ง์๋ก ๋ณต์กํ feature๋ฅผ ์ถ์ถ
- ์ ์ฐจ์ edge โ ๊ณ ์ฐจ์ ํจํด ์ถ์ถ ํ๋ฆ์ด ์๊ฐ ์ ๋ณด ์ฒ๋ฆฌ์ ๋ฎ์
๐ง ๋ํ CNN ๊ตฌ์กฐ๋ค
- AlexNet (2012): CNN์ ์ ๋ช ํ๊ฒ ๋ง๋ ์ต์ด์ ๊ตฌ์กฐ, 8์ธต ๊ตฌ์ฑ
- VGGNet (2014): 3ร3 ํํฐ ๋ฐ๋ณต ์ฌ์ฉ, ๊ตฌ์กฐ ๋จ์ & ํจ๊ณผ์
- GoogLeNet: Inception ๊ตฌ์กฐ + Global Average Pooling ์ฌ์ฉ
- ResNet: Residual Block ์ฌ์ฉ โ ์ธต์ด ๊น์ด์ ธ๋ ์ฑ๋ฅ ์ ์ง
๐ ์ ์ดํ์ต (Transfer Learning)
- ๊ธฐ์กด ์ฌ์ ํ์ต๋ ๋ชจ๋ธ์ ๊ฐ์ค์น๋ฅผ ์ฌ์ฌ์ฉํ์ฌ ์ ์ ๋ฐ์ดํฐ๋ก๋ ํ์ต ๊ฐ๋ฅ
- Feature Extraction: ๊ธฐ์กด ๊ตฌ์กฐ ์ ์ง, ์ถ๋ ฅ์ธต๋ง ์๋ก ํ์ต
- Fine-Tuning: ์ผ๋ถ ์ธต์ ๊ณ ์ , ๋๋จธ์ง๋ ์ฌํ์ต
- ์ ์ ๋ฐ์ดํฐ ์ํฉ์์ ๊ฐ๋ ฅํ ์ฑ๋ฅ ๋ฐํ ๊ฐ๋ฅ
๐จโ๐ป ์ค์ต
๐ก Code : CNN Layer ๊ตฌํ
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# ํฉ์ฑ๊ณฑ ํจ์ ๊ตฌํ
def conv(a, b):
c = np.array(a) * np.array(b)
return np.sum(c)
# MaxPooling ํจ์ ๊ตฌํ(ํ ๊ฐ์ map ๊ณ์ฐ)
def MaxPooling(nimg): # 2d input
nimg = np.array(nimg)
i0, j0 = nimg.shape # i0 = nimg.shape[0], j0 = nimg.shape[1]
i1 = int((i0 + 1) / 2)
j1 = int((j0 + 1) / 2)
output = np.zeros((i1, j1))
if i0 % 2 == 1:
i0 += 1
tmp = np.zeros((1, j0))
nimg = np.concatenate([nimg, tmp], axis=0)
if j0 % 2 == 1:
j0 += 1
tmp = np.zeros((i0, 1))
nimg = np.concatenate([nimg, tmp], axis=1)
for i in range(output.shape[0]):
for j in range(output.shape[1]):
a = np.array(nimg[2*i:2*i+2, 2*j:2*j+2])
output[i, j] = a.max()
return output
# ํฉ์ฑ๊ณฑ ์ถ๋ ฅ ์ธต(reature map) ํจ์ ๊ตฌํ(ํ ๊ฐ์ filter ๊ณ์ฐ)
def featuring(nimg, filters):
feature = np.zeros((nimg.shape[0] - 2, nimg.shape[1] - 2))
for i in range(feature.shape[0]):
for j in range(feature.shape[1]):
a = nimg[i:i+3, j:j+3]
feature[i, j] = conv(a, filters)
return feature
# MaxPooling ์ถ๋ ฅ ์ธต ํจ์ ๊ตฌํ(์ฌ๋ฌ map ๊ณ์ฐ)
def Pooling(nimg):
nimg = np.array(nimg)
pool0 = []
for i in range(len(nimg)):
pool0.append(MaxPooling(nimg[i]))
return pool0
# ๋ฐฐ์ด์ ๊ทธ๋ฆผ์ผ๋ก ๋ณํ
def to_img(nimg):
nimg = np.array(nimg)
nimg = np.uint8(np.round(nimg))
fimg = []
for i in range(len(nimg)):
fimg.append(Image.fromarray(nimg[i]))
return fimg
# feature map ์์ฑ(์ฌ๋ฌ filter ๊ณ์ฐ)
def ConvD(nimg, filters):
nimg = np.array(nimg)
feat0 = []
for i in range(len(filters)):
feat0.append(featuring(nimg, filters[i]))
return feat0
# ReLU ํ์ฑํ ํจ์
def ReLU(fo):
fo = np.array(fo)
fo = (fo > 0) * fo
return fo
# CNN Layer ํจ์ : Conv + ReLU + MaxPooling
def ConvMax(nimg, filters):
nimg = np.array(nimg)
f0 = ConvD(nimg, filters)
f0 = ReLU(f0)
fg = Pooling(f0)
return f0, fg
# ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๊ธฐ : ํฉ์ฑ๊ณฑ ํ์ ์ํ์ MaxPooling ํ์ ์ํ๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ๊ทธ๋ฆฌ๊ธฐ
def draw(f0, fg0, size=(12, 8), k=-1): # size์ k๋ ๊ธฐ๋ณธ๊ฐ ์ค์
plt.figure(figsize=size)
for i in range(len(f0)):
plt.subplot(2, len(f0), i + 1)
plt.gca().set_title('Conv' + str(k) + '-' + str(i))
plt.imshow(f0[i])
for i in range(len(fg0)):
plt.subplot(2, len(fg0), len(f0) + i + 1)
plt.gca().set_title('MaxP' + str(k) + '-' + str(i))
plt.imshow(fg0[i])
if k != -1: # k=-1์ด ์๋๋ฉด ๊ทธ๋ฆผ์ ์ ์ฅ
plt.savefig('conv' + str(k) + '.png')
# 3๊ฐ์ activation map ํฉ์น๊ธฐ : MaxPooling ํ์ ๊ฒฐ๊ณผ map๋ค์ ํ๋์ ๋ฐ์ดํฐ๋ก ํตํฉ
def join(mm):
mm = np.array(mm)
m1 = np.zeros((mm.shape[1], mm.shape[2], mm.shape[0]))
for i in range(mm.shape[1]):
for j in range(mm.shape[2]):
for k in range(mm.shape[0]):
m1[i][j][k] = mm[k][i][j]
return m1
# CNN Layer ๊ณผ์ ์ ๊ณ์ฐํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ์ถ๋ ฅ
def ConvDraw(p0, filters, size=(12, 8), k=-1):
f0, fg0 = ConvMax(p0, filters)
f0_img = to_img(f0)
fg1_img = to_img(fg0)
draw(f0, fg0, size, k)
p1 = join(fg0)
return p1
# ํ
์คํธ ์คํ
nimg31 = np.random.rand(10, 10)
filters = [np.ones((3, 3))] * 3
m0 = ConvDraw(nimg31, filters, (12, 10), 0)
โ Result : CNN Layer ๊ตฌํ
๐ ๋ผ์ฆ๋ฒ ๋ฆฌํ์ด ํ๊ฒฝ ๊ตฌ์ถ
โ ์ค์น ๋ฐ ์ด๋ฏธ์ง ์ค์
sudo apt install rpi-imager
: ๋ผ์ฆ๋ฒ ๋ฆฌํ์ด ์ด๋ฏธ์ง ๋๊ตฌ ์ค์นrpi-imager
: GUI ์คํ ํ OS ์ด๋ฏธ์ง ๋ค์ด๋ก๋ ๋ฐ ์ค์น ๊ฐ๋ฅ
โ๏ธ ์ค์ ์ ๋ณด
- ์ด์์ฒด์ : Raspberry Pi OS (64-bit)
- ์ ์ฅ์: Mass Storage Device - 62.5 GB