์๋ ํ์ธ์. ์ค๋์ Xception ๋ฆฌ๋ทฐ ์ธ๋ฒ ์งธ ์๊ฐ์ ๋๋ค.
1. The Xception architecture
in particular the VGG-16 architecture , which is schematically similar to our proposed architecture
in a few respects.
ํนํ VGG-16๊ณ์ธต์ ๋ช ๊ฐ์ง ์ธก๋ฉด์์ Xception ๊ณ์ธต๊ณผ ๊ฐ๋ต์ ์ผ๋ก ์ ์ฌํฉ๋๋ค.
The Inception architecture family of convolutional neural networks, which first demonstrated the
advantages of factoring convolutions into multiple branches operating successively on channels and then on
space.
Inception ๋ชจ๋์ด ์ฌ๋ฌ๊ฐ์ง ๋ฐฉํฅ์ผ๋ก ์ฑ๋๊ณผ ๊ณต๊ฐ์์ ์๋ํ๋ ์ฅ์ ์ ์๊ฐํ๊ณ ์๋ค๋ ๋ด์ฉ์
๋๋ค.
Depthwise separable convolutions, which our proposed architecture is entirely based upon. ~~
์ ์ชฝ์์ ์ด์ผ๊ธฐํ Depthwise Separable Convolution์ ์ฐ์ฐ๋ ๊ฐ์๋ก ์ธํ ์๋ ์ฆ๊ฐ์ ์ฅ์ ์ ์๊ฐํ๊ณ
์์ต๋๋ค.
Residual connections, introduced by He et al. in [4], which our proposed architecture uses extensively.
Resnet์์ ์ฌ์ฉํ๋ Residual Connections
https://openaccess.thecvf.com/content_cvpr_2016/papers/He_Deep_Residual_Learning_CVPR_2016_paper.pdf
Residual Connections๋ฅผ ์ง๊ณ ๋์ด๊ฐ์๋ฉด, Resnet์ ๋ฐฐ๊ฒฝ์ ํ๋ ๋ ์ด์ด๊ฐ ์ฆ๊ฐํจ์ ๋ฐ๋ผ ํ์ต์ด ๋ ์๋์ด์ผ ํ์ง๋ง, ์คํ๋ ค ํ์ต์ ๋ชปํ๋ ํ์์ด ๋ฐ์ํฉ๋๋ค. ์ด ํ์์ด vanishing/exploding gradients (๊ธฐ์ธ๊ธฐ ์์ค) ๋ฌธ์ ์ ๋๋ค. Batch Normalization์ผ๋ก ์ด๋์ ๋ ํด๊ฒฐํ ์ ์์ง๋ง, ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๊ทธ๋์ ๊ณ ์๋ ๋ฐฉ๋ฒ์ด Residual Connection(mapping) ์ ๋๋ค. ์ด์ ์ ๊ฐ์ ๋ํด์ค์ผ๋ก ๊ธฐ์ธ๊ธฐ ์์ค์ ๋ฐฉ์งํ๋ ๊ฒ์ ๋๋ค. ๊ฐ๋จํ ๋ฐฉ๋ฒ์ด์ง๋ง ํจ๊ณผ๋ ๊ต์ฅํ ์ข์ต๋๋ค.
dataset์ FastEval14K๋ฅผ ์ฌ์ฉํ์์ต๋๋ค. (299x299x3)
2. implemention
2-1 depthwise separable convolution
def depthwise_separable_conv(input_dim, output_dim):
depthwise_convolution = nn.Conv2d(input_dim, input_dim, kernel_size=3, padding=1, groups=input_dim, bias=False)
pointwise_convolution = nn.Conv2d(input_dim, output_dim, kernel_size=1, bias=False)
model = nn.Sequential(
depthwise_convolution,
pointwise_convolution
)
return model
2-2 Entry flow
class entry_flow(nn.Module):
def __init__(self):
super(entry_flow, self).__init__()
self.conv2d_init_1 = nn.Conv2d(in_channels = 3,
out_channels = 32,
kernel_size = 3,
stride = 2,
)
self.conv2d_init_2 = nn.Conv2d(in_channels = 32,
out_channels = 64,
kernel_size = 3,
stride = 1,
)
self.layer_1 = nn.Sequential(
depthwise_separable_conv(input_dim = 64, output_dim = 128),
nn.ReLU(),
depthwise_separable_conv(input_dim = 128, output_dim = 128),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.conv2d_1 = nn.Conv2d(in_channels = 64,
out_channels = 128,
kernel_size = 1,
stride = 2
)
self.layer_2 = nn.Sequential(
depthwise_separable_conv(input_dim = 128, output_dim = 256),
nn.ReLU(),
depthwise_separable_conv(input_dim = 256, output_dim = 256),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.conv2d_2 = nn.Conv2d(in_channels = 128,
out_channels = 256,
kernel_size = 1,
stride = 2
)
self.layer_3 = nn.Sequential(
depthwise_separable_conv(input_dim = 256, output_dim = 728),
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 728),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.conv2d_3 = nn.Conv2d(in_channels = 256,
out_channels = 728,
kernel_size = 1,
stride = 2
)
self.relu = nn.ReLU()
def forward(self, x):
x = self.conv2d_init_1(x)
x = self.relu(x)
x = self.conv2d_init_2(x)
x = self.relu(x)
output1_1 = self.layer_1(x)
output1_2 = self.conv2d_1(x)
output1_3 = output1_1 + output1_2
output2_1 = self.layer_2(output1_3)
output2_2 = self.conv2d_2(output1_3)
output2_3 = output2_1 + output2_2
output3_1 = self.layer_3(output2_3)
output3_2 = self.conv2d_3(output2_3)
output3_3 = output3_1 + output3_2
y = output3_3
return y
2-2 Middle flow
class middle_flow(nn.Module):
def __init__(self):
super(middle_flow, self).__init__()
self.module_list = nn.ModuleList()
layers = nn.Sequential(
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 728),
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 728),
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 728)
)
for i in range(7):
self.module_list.append(layers)
def forward(self, x):
for layer in self.module_list:
x_temp = layer(x)
x = x + x_temp
return x
2-3 Exit flow
class exit_flow(nn.Module):
def __init__(self, growth_rate=32):
super(exit_flow, self).__init__()
self.separable_network = nn.Sequential(
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 728),
nn.ReLU(),
depthwise_separable_conv(input_dim = 728, output_dim = 1024),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.conv2d_1 = nn.Conv2d(in_channels = 728,
out_channels = 1024,
kernel_size = 1,
stride = 2
)
self.separable_conv_1 = depthwise_separable_conv(input_dim = 1024, output_dim = 1536)
self.separable_conv_2 = depthwise_separable_conv(input_dim = 1536, output_dim = 2048)
self.relu = nn.ReLU()
self.avgpooling = nn.AdaptiveAvgPool2d((1))
self.fc_layer = nn.Linear(2048, 10)
def forward(self, x):
output1_1 = self.separable_network(x)
output1_2 = self.conv2d_1(x)
output1_3 = output1_1 + output1_2
y = self.separable_conv_1(output1_3)
y = self.relu(y)
y = self.separable_conv_2(y)
y = self.relu(y)
y = self.avgpooling(y)
y = y.view(-1, 2048)
y= self.fc_layer(y)
return y
2-4 Xception
class Xception(nn.Module):
def __init__(self):
super(Xception, self).__init__()
self.entry_flow = entry_flow()
self.middle_flow = middle_flow()
self.exit_flow = exit_flow()
def forward(self, x):
x = self.entry_flow(x)
x = self.middle_flow(x)
x = self.exit_flow(x)
return x
3. Experiment result
4. Conclusions
Depthwise Separable Convolution์ด Inception ๋ชจ๋๊ณผ ์ ์ฌํ์ง๋ง, Standard Convolution ๋งํผ ์ฌ์ฉํ๊ธฐ ์ฝ๊ณ , ๋์ ์ฑ๋ฅ๊ณผ ์ฐ์ฐ๋ ๊ฐ์์ ์ฅ์ ๋๋ฌธ์ CNN์ ์ค๊ณ์ ๊ธฐ์ด๊ฐ ๋ ๊ฒ์ผ๋ก ๊ธฐ๋๊ฐ ๋ฉ๋๋ค. Xception ๋ ผ๋ฌธ ๋ฆฌ๋ทฐ๋ฅผ ๋ง์น๋๋ก ํ๊ฒ ์ต๋๋ค. ์ฒซ ๋ ผ๋ฌธ ๋ฆฌ๋ทฐ์ธ์ง๋ผ ๋งํ๊ณ ์ ํ๋ ๋ด์ฉ์ ๋ช ํํ๊ฒ ์ค๋ช ํ์ง ๋ชปํ์์ต๋๋ค. ํน์๋ผ๋ ๋ณด์๋ค๊ฐ ์๋ชป๋ ๋ถ๋ถ์ด๋ ์ถ๊ฐํด์ผํ ๋ถ๋ถ์ด ๋ณด์ด์๋ฉด ํผ๋๋ฐฑ ์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.