Open chullhwan-song opened 4 years ago
pytorch > 밑에 이외에 여기도 참고 링크 이게 논문과 더..충실한데..조금씩 조끔씩 다르다.
class SKConv(nn.Module):
def __init__(self, features, WH, M, G, r, stride=1 ,L=32):
""" Constructor
Args:
features: input channel dimensionality.
WH: input spatial dimensionality, used for GAP kernel size.
M: the number of branchs.
G: num of convolution groups.
r: the radio for compute d, the length of z.
stride: stride, default 1.
L: the minimum dim of the vector z in paper, default 32.
"""
super(SKConv, self).__init__()
d = max(int(features/r), L)
self.M = M
self.features = features
self.convs = nn.ModuleList([])
for i in range(M):
self.convs.append(nn.Sequential(
nn.Conv2d(features, features, kernel_size=3+i*2, stride=stride, padding=1+i, groups=G),
nn.BatchNorm2d(features),
nn.ReLU(inplace=False)
))
# self.gap = nn.AvgPool2d(int(WH/stride))
self.fc = nn.Linear(features, d)
self.fcs = nn.ModuleList([])
for i in range(M):
self.fcs.append(
nn.Linear(d, features)
)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
for i, conv in enumerate(self.convs):
fea = conv(x).unsqueeze_(dim=1)
if i == 0:
feas = fea
else:
feas = torch.cat([feas, fea], dim=1)
fea_U = torch.sum(feas, dim=1)
# fea_s = self.gap(fea_U).squeeze_()
fea_s = fea_U.mean(-1).mean(-1)
fea_z = self.fc(fea_s)
for i, fc in enumerate(self.fcs):
vector = fc(fea_z).unsqueeze_(dim=1)
if i == 0:
attention_vectors = vector
else:
attention_vectors = torch.cat([attention_vectors, vector], dim=1)
attention_vectors = self.softmax(attention_vectors)
attention_vectors = attention_vectors.unsqueeze(-1).unsqueeze(-1)
fea_v = (feas * attention_vectors).sum(dim=1)
return fea_v
import tensorflow as tf
import tflearn
import tensorflow.contrib.slim as slim
def SKConv(input, M, r, L=32, stride=1, is_training=True): input_feature = input.get_shape().as_list()[3] d = max(int(input_feature / r), L) net = input with slim.arg_scope([slim.conv2d, slim.fully_connected], activation_fn=tf.nn.relu): for i in range(M): net = slim.conv2d(net, input_feature, [3+i2, 3+i2], rate=1+i, stride=stride) net = slim.batch_norm(net, decay=0.9, center=True, scale=True, epsilon=1e-5, updates_collections=tf.GraphKeys.UPDATE_OPS, is_training=is_training) net = tf.nn.relu(net) if i == 0: fea_U = net else: fea_U = tf.add(fea_U, net) gap = tflearn.global_avg_pool(fea_U) fc = slim.fully_connected(gap, d, activationfn=None) fcs = fc for in range(M): fcs = slim.fully_connected(fcs, input_feature, activationfn=None) if == 0: att_vec = fcs else: att_vec = tf.add(att_vec, fcs) att_vec = tf.expand_dims(att_vec, axis=1) att_vec = tf.expand_dims(att_vec, axis=1) att_vec_softmax = tf.nn.softmax(att_vec) fea_v = tf.multiply(fea_U, att_vec_softmax) return fea_v
### Network Architecture
![image](https://user-images.githubusercontent.com/40360823/67671723-d89dd880-f9b9-11e9-9e41-f3a0d8507dc1.png)
## Experiments
### ImageNet Classification
![image](https://user-images.githubusercontent.com/40360823/67672732-e7858a80-f9bb-11e9-8048-221216641ee3.png)
![image](https://user-images.githubusercontent.com/40360823/67672772-fec47800-f9bb-11e9-9c2a-bf88cbd08ad6.png)
## 결론/리뷰
* 개인적으로는 **Selective Kernel** (SK)이라는 근사한(?) 이름을 붙였지만, 또한 이름만 보고서는 dynamic하게 kernel 크기를 그때그대 붙여서 사용하는 형태(이런게 가능할까라고..첨에 생각하기도..)라고 착각하기싶기도하다.
* 결론적으로 제생각에는 multi-kernel SENET이라는게 더 가까운 개념이라고 느꼈다.
https://arxiv.org/abs/1903.06586