์ง๊ธ์ผ๋ก๋ถํฐ ๋ฌด๋ ค 27๋ ์ ํ์ํ ๊ณ ๋์ ์ธ๊ณต์ง๋ฅ.
1998๋ ์ ์ ์๋ ํฉ์ฑ๊ณฑ์ ๊ฒฝ๋ง(CNN)์ ์กฐ์ LeNet-5๋ฅผ ๊ตฌํํด๋ณด์
ํนํ ๋ ผ๋ฌธ ์ ๋ฌธ์ ์ CONV3 ๋ ์ด์ด๊น์ง...!
์์ ์ฐํ๋ฅผ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, LeNet-5๋ ์ธ๊ณต์ง๋ฅ๊ณผ CNN์ด๋ผ๋ ๊ฐ๋
์ด ์ฃผ๋ฅ๋ก์ ์ ํํ๊ธฐ ์ ์ ์ ์๋์ด, ํ๋ CNN ๋ชจ๋ธ๋ค์ ๊ธฐ์ด๋ฅผ ๋ฆ์ ์ด๊ธฐ์ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ด๋ค.
1998๋
์ Yann LeCun์ด ๊ฐ๋ฐํ LeNet-5๋ ์ฃผ๋ก ์๊ธ์จ ์ซ์ ์ธ์์ ์ํด ์ค๊ณ๋์์ผ๋ฉฐ, ์ดํ ์ปดํจํฐ ๋น์ ์ ํจ๋ฌ๋ค์์ ๋ฐ๊พธ๋ ๋ฐ ํฐ ์ญํ ์ ํ๋ค.
๋น์ ๋ถ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ๋์ด ์ง์ ๋ฐ์ดํฐ์์ ํน์ง์ ์ถ์ถํด ํ์ตํ๋ ๊ฒ์ด ์ฃผ๋ฅ์์ผ๋, LeNet-5๋ ๊ฐ์ค์น๋ฅผ ๊ฐ๋ ํํฐ ์์ฒด๋ฅผ ํ์ต์์ผ ์ด๋ฅผ ์๋ํํด ํ์ ์ ์ธ ์ ๊ทผ์ ์๋ํ์๋ค.
LeNet-5์ ๊ณ์ธต ๊ตฌ์กฐ๋ ํ๋์ ๋ชจ๋ธ์ ๋นํด ๋งค์ฐ ๋จ์ํ๋ค. ๋ฐ๋ผ์ ๋๋ฅผ ํฌํจํ ๋ง์ CNN ์ด์ฌ์๋ค์ด ์ฒ์์ผ๋ก ์ ํ๊ฒ ๋๋ ์ ๋๋ก๋ CNN ๋ชจ๋ธ์ด๋ค.
์์ฆ CNN๊ณผ ๋ค๋ฅด๊ฒ ๊ทผ๋ณธ ๋์น๋ ๊ตฌ์กฐ.
์ด ๊ตฌ์กฐ๋ง์ผ๋ก๋ 0~9์ ์๊ธ์จ๋ฅผ 99% ์ด์์ ์ ํ๋๋ก ์์ธกํ ์ ์๋ค.
๊ทธ๋ฌ๋ LeNet-5๋ฅผ ์กฐ๊ธ๋ง ๊น๊ฒ ์ฐพ์๋ณด๊ณ ๊ณต๋ถํ๊ฒ ๋๋ฉด, ์์ํ ๋ ์ด์ด ํ๋๊ฐ ์ฐ๋ฆฌ์ ์ดํด๋ฅผ ๋ฐฉํดํ๋ค.
CONV3 ๊ณ์ธต์ LeNet-5์ ๊ตฌ์กฐ์์ ๊ฐ์ฅ ๋
ํนํ ๋ถ๋ถ์ด๊ณ ํ๋ CNN์์๋ ๊ฑฐ์ ์ฐพ์๋ณผ ์ ์๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ณ ์๋ค.
์ผ๋ฐ์ ์ธ ํฉ์ฑ๊ณฑ ๊ณ์ธต์ ๋ค์๊ณผ ๊ฐ๋ค.
๊ทธ๋ฆผ์์ ๋ณผ ์ ์๋ฏ, 1์ฑ๋์ ์ธํ์ด 6๊ฐ์ ์ปค๋์ ๊ฐ๊ฐ ์ฐ์ฐ๋์ด ์๋ก์ด 6๊ฐ์ ์์ํ์ ๋ง๋ค์ด๋ธ๋ค.
์ด๋, ๊ฐ ํํฐ๋ ๋ชจ๋ ๋์ผํ ์ธํ์ ์ ๋ถ ๋ฐ์๋ค์ด๊ณ , ํฉ์ฑ๊ณฑ ์ฐ์ฐ์ ์ํํ๊ฒ ๋๋ค.
๋ฐ๋ผ์ ๊ณ์ธต์ ์ ์ฒด์ ์ธ ๋์นญ ์ฐ๊ฒฐ์ ์ ์งํ๊ฒ ๋๋ค.
๊ทธ๋ฌ๋, LeNet-5์ Conv3 ๊ณ์ธต์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ ์ฌ์ด์ ๋น๋์นญ ์ฐ๊ฒฐ ๋ฐฉ์์ ์ฑํํ๊ณ ์๋ค.
์ด ์ฐ๊ฒฐ ๋ฐฉ์์ ํ๋ CNN์์ ์ผ๋ฐ์ ์ธ ์์ ์ฐ๊ฒฐ ๋ฐฉ์์ด ์๋, ๋ค์ํ ํํฐ ์ฐ๊ฒฐ์ ํตํด ์๋ก ๋ค๋ฅธ ์กฐํฉ์ ์
๋ ฅ์ ํ์ตํ๊ฒ ํ๋๋ก ๊ณ ์๋ ๊ฒ์ด๋ค.
CONV3 ๊ณ์ธต์ 6๊ฐ์ ์
๋ ฅ์ 16๊ฐ์ ์ถ๋ ฅ์ผ๋ก ๋น๋์นญ์ ์ผ๋ก ์ฐ๊ฒฐํ์ฌ ํํฐ๊ฐ ๋ค๋ฅธ ์ ๋ณด๋ฅผ ์ถ์ถํ๊ฒ๋ ์ค๊ณ๋์ด์๋ค.
์๋ ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์ ์ ์๋ฏ, 0๋ฒ ์ธํ์ ๋๋ฒ์งธ, ์ธ๋ฒ์งธ ํํฐ์ ์ธํ์ผ๋ก ์ฌ์ฉ๋์ง ์๋๋ค.
๋
ผ๋ฌธ์์ ์ ์ํ ๊ท์น์ ๋ค์์ ํ์ ๊ฐ๋ค.
์์๋ก 0๋ฒ ํํฐ๋ ์ค์ง 0, 1, 2๋ฒ์ ์ธํ๋ง์ ์ทจ๊ธํ๋ฉฐ, ๋ฐ๋ผ์ ํํฐ์ ์ฑ๋๋ 3์ด ๋ ๊ฒ์ด๋ค.
14๋ฒ ํํฐ๋ 0, 2, 3, 5๋ฒ์ ์ธํ๋ง์ ๋ฐ์๋ค์ด๊ณ ํํฐ์ ์ฑ๋๋ 4๊ฐ ๋ ๊ฒ์ด๋ค.
14๊ฐ์ ์ฑ๋์ ๋ค์ํ ๊น์ด๋ฅผ ๊ฐ์ง๋ง, ๊ฒฐ๊ตญ ๋ชจ๋ ํํฐ์ ๊ฒฐ๊ณผ๋ฌผ์ ๋์ผํ ํฌ๊ธฐ๊ฐ ๋๋ค.
๋ฐ๋ผ์ ์ด๋ค์ ๋ฌด์ฌํ ๋ค์ ๋ ์ด์ด๋ก ์ ํด์ง ์ ์๋ค.
์ด๋ก ์์ฒด๋ ์ฒ์ฒํ ๋ฐ๋ผ๊ฐ๋ฉด ์ดํดํ๊ธฐ ์ฝ๋ค.
๊ทธ๋ฌ๋ ํธ๊ธฐ๋กญ๊ฒ LeNet-5 ๊ตฌํ์ ๋์ ํ๋ ๋ง์ ์ด๋ค์ด ๋๊ฐํจ์ ๋๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ด ๋ถ๋ถ์ ๋ฌด์ํ๊ฑฐ๋ ํฌ๊ธฐํ๊ณ ์ผ๋ฐ์ ์ธ ํฉ์ฑ๊ณฑ ๋ ์ด์ด์ ๋์ผํ๊ฒ ๋ค์๊ณผ ๊ฐ์ด ํ์น๊ณ ๋์ด๊ฐ๋ค.
self.conv3 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5, stride=1)
๊ทธ๋ฌ๋ ๋ ผ๋ฌธ ์์์๋ ํด๋น ๋ ์ด์ด๋ฅผ ์ค๋ช ํ๋๋ฐ ๋ง์ ์๊ฐ์ ํ ์ ํ๊ณ ์๋๋งํผ, ์ด๋ฅผ ๊ผญ ๊ตฌํํด๋ณด๊ณ ์ถ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
์ด๋ฅผ ์ง์ ๊ตฌํํ๊ธฐ์ ์์, ํด๋น ๋ ์ด์ด๋ฅผ ๋
ผ๋ฌธ๊ณผ ์๋ฒฝํ ๋์ผํ ์ฝ๋๊ฐ ์ธํฐ๋ท ์์ ์กด์ฌํ๋์ง ์ฐพ์๋ณด์๋ค.
๋ธ๋ก๊ทธ๋ ์ฐพ์ง ๋ชปํ๊ณ , tensorflow๋ก ๊ตฌํํ ํ ๋ํ์์ ๋ถ์ ์์์ ์ฐพ๊ฒ ๋์๋ค.
์ ์ผํ๊ฒ ์ฐพ์ ์ ๋๋ก ๊ตฌํํ LeNet-5 ์ค๋ช ์์
์์ฌ์ด ๊ฒ์ ์๋๊ฐ ์กฐ๊ธ์ ๋ณํ์ฌ ํ์ต์ฉ์ผ๋ก ์ฃผ๋ก pytourch๋ฅผ ํ์ฉํ๋ค๋ ๊ฒ์ด์๋ค. ๊ทธ๋ ์ง๋ง, ๊ตฌํ์ ํํธ๋ฅผ ์ป์ ์ ์์๋ค.
๋ค์์ pytourch๋ก ๊ตฌํํ ์ ๋๋ก๋ Conv3 ๋ ์ด์ด์ด๋ค.
# Conv3 layer์ Rules ์ ์
CONV3_RULES = [
[0, 1, 2], [1, 2, 3], [2, 3, 4],
[3, 4, 5], [0, 4, 5] , [0, 1, 5],
[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5],
[0, 3, 4, 5], [0, 1, 4, 5], [0, 1, 2, 5],
[0, 1, 3, 4], [1, 2, 4, 5], [0, 2, 3, 5],
[0, 1, 2, 3, 4, 5],
]
# Conv3 Layer ๊ตฌํ
class ReNet5Conv3(nn.Module):
def __init__(self):
super(ReNet5Conv3, self).__init__()
self.conv_layers = nn.ModuleList(
[
nn.Conv2d(
in_channels=len(rules), out_channels=1, kernel_size=5, stride=1
)
for rules in CONV3_RULES
]
)
def forward(self, x):
conv3_results = []
for i, rule in enumerate(CONV3_RULES):
selected_inputs = torch.cat(
[x[:, idx : idx + 1, :, :] for idx in rule], dim=1
)
conv3_results.append(self.conv_layers[i](selected_inputs))
return torch.cat(conv3_results, dim=1)
ํด๋น ๋ชจ๋์ ํฌํจํ์ฌ ์ ์ฒด LeNet-5๋ฅผ ์ ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
(LeNet-5์ ๋
ผ๋ฌธ์ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, pooling layer์๋ ํ์ต ๊ฐ๋ฅํ ํ๋ผ๋ฏธํฐ๊ฐ ์๋ค.)
# ํ์ต ๊ฐ๋ฅํ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๋ SubSampling Layer ๊ตฌํ
class LearnableSubsampling2d(nn.Module):
def __init__(self, kernel_size, stride=None, num_channels=1):
super(LearnableSubsampling2d, self).__init__()
self.kernel_size = kernel_size
self.stride = stride if stride is not None else kernel_size
self.weights = nn.Parameter(torch.ones(1, num_channels, 1, 1))
self.bias = nn.Parameter(torch.zeros(1, num_channels, 1, 1))
def forward(self, x):
x = F.avg_pool2d(x, self.kernel_size, self.stride)
x = x * self.weights + self.bias
return x
# LeNet-5 ๋
ผ๋ฌธ๊ณผ ์ต๋ํ ์ ์ฌํ๊ฒ ๊ตฌํ
class RealLeNet5(nn.Module):
def __init__(self, num_classes):
super(RealLeNet5, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, stride=1)
self.pool2 = LearnableSubsampling2d(kernel_size=2, stride=2, num_channels=6)
self.conv3 = ReNet5Conv3()
self.pool4 = LearnableSubsampling2d(kernel_size=2, stride=2, num_channels=16)
self.conv5 = nn.Conv2d(
in_channels=16, out_channels=120, kernel_size=5, stride=1
)
self.fc6 = nn.Linear(120, 84)
self.fc7 = nn.Linear(84, num_classes)
def forward(self, x):
x = F.tanh(self.conv1(x))
x = self.pool2(x)
x = F.tanh(self.conv3(x))
x = self.pool4(x)
x = F.tanh(self.conv5(x))
x = x.view(x.size(0), -1)
x = F.tanh(self.fc6(x))
logits = self.fc7(x)
return logits
torchinfo.summary(RealLeNet5(NUM_CLASSES), input_size=(1, 1, 32, 32))
![]() | ![]() |
---|
Conv3์ ์กด์ฌ ์์์ ๋ํด ๊ณ ๋ฏผํด ๋ณผ ๊ธฐํ๊ฐ ์์๊ณ , ๋น์ ์ฐ๊ตฌ์ค ๊ต์๋๊ณผ ๋ ผ์ํ ํ ์ ๋๋ฆ๋๋ก ๊ฒฐ๋ก ์ ์ ๋ฆฌํด ๋ณด์๋ค.
์ด๋ ๊ฒ ๋น๋์นญ ์ฐ๊ฒฐ ๋ฐฉ์์ ํตํด LeNet-5๋ ์ ์ฒด ๋คํธ์ํฌ์ ๋์นญ์ฑ์ ๊นจ๊ณ , ๋ ๋ค์ํ ํน์ง์ ํ์ตํ ์ ์๋๋ก ์ ๋ํ๊ณ ์๋ค. ํ๋ CNN์์๋ ์ด์ ๊ฐ์ ๊ธฐ๋ฒ์ ์ ์ฐพ์๋ณผ ์ ์์ง๋ง, ๋๋กญ์์(dropout)๊ณผ ๊ฐ์ ์ ๊ทํ ๊ธฐ๋ฒ์ด ์ด๋ฌํ ํน์ฑ๊ณผ ๋งฅ์ ๊ฐ์ดํ๋ค๊ณ ๋ณผ ์ ์๋ค. ๊ทธ๋ฌ๋ ๋น์์๋ ๋๋กญ์์๊ณผ ๊ฐ์ ์ ๊ทํ ๊ธฐ๋ฒ์ด ์กด์ฌํ์ง ์์๋ค(์ด๋ AlexNet์์ ์ ์๋จ). ๋ฐ๋ผ์, LeNet-5๋ ์ด๋ฐ ๋น๋์นญ ์ฐ๊ฒฐ ๋ฐฉ์์ผ๋ก ๋ด๋ฐ์ ๋ค์์ฑ์ ์ ์งํ๋ ค ํ ๊ฒ์ผ๋ก ์๊ฐ๋๋ค.
LeNet-5์ ์ฐ๊ตฌ์ง๋ค์ด ๋น์์ ์ด๋ฐ ๋น๋์นญ ๊ตฌ์กฐ๋ฅผ ์ผ๋ง๋ ์ธ๋ฐํ๊ฒ ์ค๊ณํ๋์ง๋ฅผ ์์ผ ๋๋ ์ ์์๊ณ , ๋๋กญ์์์ด ์์ง๋ ๋๋ฆฌ ์ฌ์ฉ๋๋ค๋ ์ ์์ ์์น์ ๊นจ๋ ๋จ์ํ ์์ด๋์ด์ ๊ฐ๋ ฅํจ์ ๋ค์ ํ ๋ฒ ์ค๊ฐํ๋ค.
์ค ์ ์ตํ ๋ด์ฉ ์ ๋ณด์์ต๋๋ค!
๋ฏผํค๋ ์ ๋ฆฌ ์ค๋ ฅ์ด ์ฅ๋ ์๋์ ๋ฐ์
์ ์ ๋จธ์ ๋ฌ๋ ์์ ๋ ๋ค์๋ ๋ด์ฉ๋ค์ด ์ธ๋ป ๋ ์ค๋ฅด๋ค์! ํฌ๋ฏธํ๊ฒ ์ธ๋ป...