This repository has been archived by the owner on Nov 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ClassCaps.py
100 lines (84 loc) · 3.24 KB
/
ClassCaps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import math
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from EMRouting import EMRouting
class ClassCaps(nn.Module):
def __init__(self, B=32, C=32, K=3, P=4, stride=2, iters=3,
coor_add=False, w_shared=False,cuda= True):
super(ClassCaps, self).__init__()
# TODO: lambda scheduler
self.B = B
self.C = C
self.K = K
self.P = P
self.psize = P*P
self.stride = stride
self.iters = iters
self.coor_add = coor_add
self.w_shared = w_shared
# constant
self.eps = 1e-8
self._lambda = 1e-03
# params
# Note that \beta_u and \beta_a are per capsule type,
# which are stated at https://openreview.net/forum?id=HJWLfGWRb¬eId=rJUY2VdbM
self.beta_u = nn.Parameter(torch.zeros(C))
self.beta_a = nn.Parameter(torch.zeros(C))
# Note that the total number of trainable parameters between
# two convolutional capsule layer types is 4*4*k*k
# and for the whole layer is 4*4*k*k*B*C,
# which are stated at https://openreview.net/forum?id=HJWLfGWRb¬eId=r17t2UIgf
self.weights = nn.Parameter(torch.randn(1, K*K*B, C, P, P))
self.cuda = cuda
self.EM = EMRouting(self.cuda)
def transform_view(self, x, w, C, P, w_shared=False):
b, B, psize = x.shape
assert psize == P*P
x = x.view(b, B, 1, P, P)
if w_shared:
hw = int(B / w.size(1))
w = w.repeat(1, hw, 1, 1, 1)
w = w.repeat(b, 1, 1, 1, 1)
x = x.repeat(1, 1, C, 1, 1)
v = torch.matmul(x, w)
v = v.view(b, B, C, P*P)
return v
def add_coord(self, v, b, h, w, B, C, psize):
assert h == w
v = v.view(b, h, w, B, C, psize)
coor = 1. * torch.arange(h) / h
if self.cuda:
coor_h = torch.cuda.FloatTensor(
1, h, 1, 1, 1, self.psize).fill_(0.)
coor_w = torch.cuda.FloatTensor(
1, 1, w, 1, 1, self.psize).fill_(0.)
else:
coor_h = torch.FloatTensor(1, h, 1, 1, 1, self.psize).fill_(0.)
coor_w = torch.FloatTensor(1, 1, w, 1, 1, self.psize).fill_(0.)
coor_h[0, :, 0, 0, 0, 0] = coor
coor_w[0, 0, :, 0, 0, 1] = coor
v = v + coor_h + coor_w
v = v.view(b, h*w*B, C, psize)
return v
def forward(self, x):
b, h, w, c = x.shape
if self.w_shared:
assert c == self.B*(self.psize+1)
assert 1 == self.K
assert 1 == self.stride
p_in = x[:, :, :, :self.B*self.psize].contiguous()
p_in = p_in.view(b, h*w*self.B, self.psize)
a_in = x[:, :, :, self.B*self.psize:].contiguous()
a_in = a_in.view(b, h*w*self.B, 1)
# transform view
v = self.transform_view(
p_in, self.weights, self.C, self.P, self.w_shared)
# coor_add
if self.coor_add:
v = self.add_coord(v, b, h, w, self.B, self.C, self.psize)
# em_routing
_, out = self.EM.caps_em_routing(
v, a_in, self.C, self.eps, self.beta_a, self.beta_u, self._lambda, self.iters)
return out