HungNP
New single commit message
cb80c28
'''
Reference:
https://github.com/hshustc/CVPR19_Incremental_Learning/blob/master/cifar100-class-incremental/modified_linear.py
'''
import math
import torch
from torch import nn
from torch.nn import functional as F
class SimpleLinear(nn.Module):
'''
Reference:
https://github.com/pytorch/pytorch/blob/master/torch/nn/modules/linear.py
'''
def __init__(self, in_features, out_features, bias=True):
super(SimpleLinear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
if bias:
self.bias = nn.Parameter(torch.Tensor(out_features))
else:
self.register_parameter('bias', None)
self.reset_parameters()
def reset_parameters(self):
nn.init.kaiming_uniform_(self.weight, nonlinearity='linear')
nn.init.constant_(self.bias, 0)
def forward(self, input):
return {'logits': F.linear(input, self.weight, self.bias)}
class CosineLinear(nn.Module):
def __init__(self, in_features, out_features, nb_proxy=1, to_reduce=False, sigma=True):
super(CosineLinear, self).__init__()
self.in_features = in_features
self.out_features = out_features * nb_proxy
self.nb_proxy = nb_proxy
self.to_reduce = to_reduce
self.weight = nn.Parameter(torch.Tensor(self.out_features, in_features))
if sigma:
self.sigma = nn.Parameter(torch.Tensor(1))
else:
self.register_parameter('sigma', None)
self.reset_parameters()
def reset_parameters(self):
stdv = 1. / math.sqrt(self.weight.size(1))
self.weight.data.uniform_(-stdv, stdv)
if self.sigma is not None:
self.sigma.data.fill_(1)
def forward(self, input):
out = F.linear(F.normalize(input, p=2, dim=1), F.normalize(self.weight, p=2, dim=1))
if self.to_reduce:
# Reduce_proxy
out = reduce_proxies(out, self.nb_proxy)
if self.sigma is not None:
out = self.sigma * out
return {'logits': out}
class SplitCosineLinear(nn.Module):
def __init__(self, in_features, out_features1, out_features2, nb_proxy=1, sigma=True):
super(SplitCosineLinear, self).__init__()
self.in_features = in_features
self.out_features = (out_features1 + out_features2) * nb_proxy
self.nb_proxy = nb_proxy
self.fc1 = CosineLinear(in_features, out_features1, nb_proxy, False, False)
self.fc2 = CosineLinear(in_features, out_features2, nb_proxy, False, False)
if sigma:
self.sigma = nn.Parameter(torch.Tensor(1))
self.sigma.data.fill_(1)
else:
self.register_parameter('sigma', None)
def forward(self, x):
out1 = self.fc1(x)
out2 = self.fc2(x)
out = torch.cat((out1['logits'], out2['logits']), dim=1) # concatenate along the channel
# Reduce_proxy
out = reduce_proxies(out, self.nb_proxy)
if self.sigma is not None:
out = self.sigma * out
return {
'old_scores': reduce_proxies(out1['logits'], self.nb_proxy),
'new_scores': reduce_proxies(out2['logits'], self.nb_proxy),
'logits': out
}
def reduce_proxies(out, nb_proxy):
if nb_proxy == 1:
return out
bs = out.shape[0]
nb_classes = out.shape[1] / nb_proxy
assert nb_classes.is_integer(), 'Shape error'
nb_classes = int(nb_classes)
simi_per_class = out.view(bs, nb_classes, nb_proxy)
attentions = F.softmax(simi_per_class, dim=-1)
return (attentions * simi_per_class).sum(-1)
'''
class CosineLinear(nn.Module):
def __init__(self, in_features, out_features, sigma=True):
super(CosineLinear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
if sigma:
self.sigma = nn.Parameter(torch.Tensor(1))
else:
self.register_parameter('sigma', None)
self.reset_parameters()
def reset_parameters(self):
stdv = 1. / math.sqrt(self.weight.size(1))
self.weight.data.uniform_(-stdv, stdv)
if self.sigma is not None:
self.sigma.data.fill_(1)
def forward(self, input):
out = F.linear(F.normalize(input, p=2, dim=1), F.normalize(self.weight, p=2, dim=1))
if self.sigma is not None:
out = self.sigma * out
return {'logits': out}
class SplitCosineLinear(nn.Module):
def __init__(self, in_features, out_features1, out_features2, sigma=True):
super(SplitCosineLinear, self).__init__()
self.in_features = in_features
self.out_features = out_features1 + out_features2
self.fc1 = CosineLinear(in_features, out_features1, False)
self.fc2 = CosineLinear(in_features, out_features2, False)
if sigma:
self.sigma = nn.Parameter(torch.Tensor(1))
self.sigma.data.fill_(1)
else:
self.register_parameter('sigma', None)
def forward(self, x):
out1 = self.fc1(x)
out2 = self.fc2(x)
out = torch.cat((out1['logits'], out2['logits']), dim=1) # concatenate along the channel
if self.sigma is not None:
out = self.sigma * out
return {
'old_scores': out1['logits'],
'new_scores': out2['logits'],
'logits': out
}
'''