├── pub
└── DCL.png
├── LICENSE
├── README.md
└── Dynamic_Convolutional_Layer.py
/pub/DCL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhaoJ9014/Dynamic-Conditional-Networks.PyTorch/HEAD/pub/DCL.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Jian Zhao
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Dynamic Conditional Networks for Few Shot Learning
2 |
3 |
4 | - Pytorch implementation of the algorithm in our ECCV 2018 [Paper](https://www.researchgate.net/publication/326584672_Dynamic_Conditional_Networks_for_Few-Shot_Learning).
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## Getting Started
13 | Clone the repo:
14 |
15 | ```
16 | git clone https://github.com/ZhaoJ9014/Dynamic-Conditional-Networks-for-Few-Shot-Learning.pytorch.git
17 | ```
18 |
19 | ### Requirements
20 |
21 | Tested under python3.
22 |
23 | - python packages
24 | - pytorch>=0.3.1
25 | - Anaconda3
26 | - An NVIDAI GPU and CUDA 8.0 or higher. Some operations only have gpu implementation.
27 | - **NOTICE**: different versions of Pytorch package have different memory usages.
28 |
29 |
30 | ## Citation
31 | - Please consult and consider citing the following paper:
32 |
33 | @inproceedings{zhao2018dynamic,
34 | title={Dynamic Conditional Networks for Few-Shot Learning},
35 | author={Zhao, Fang and Zhao, Jian and Yan, Shuicheng and Feng, Jiashi},
36 | booktitle={ECCV},
37 | pages={19--35},
38 | year={2018}
39 | }
40 |
--------------------------------------------------------------------------------
/Dynamic_Convolutional_Layer.py:
--------------------------------------------------------------------------------
1 | import math
2 | import torch
3 | import torch.nn as nn
4 | from torch.nn.parameter import Parameter
5 | import torch.nn.functional as F
6 | from torch.nn.modules.utils import _single, _pair, _triple
7 |
8 | # dynamic conditional conv layer (it is fc layer when the kernel size is 1x1 and the input is cx1x1)
9 | class ConvBasis2d(nn.Module):
10 | def __init__(self, idfcn, in_channels, out_channels, kernel_size, stride=1,
11 | padding=0, dilation=1, transposed=False, output_padding=_pair(0), groups=1, bias=True):
12 | super(ConvBasis2d, self).__init__()
13 | if in_channels % groups != 0:
14 | raise ValueError('in_channels must be divisible by groups')
15 | if out_channels % groups != 0:
16 | raise ValueError('out_channels must be divisible by groups')
17 | self.idfcn = idfcn # the dimension of coditional input
18 | self.in_channels = in_channels
19 | self.out_channels = out_channels
20 | self.kernel_size = _pair(kernel_size)
21 | self.stride = _pair(stride)
22 | self.padding = _pair(padding)
23 | self.dilation = _pair(dilation)
24 | self.transposed = transposed
25 | self.output_padding = output_padding
26 | self.groups = groups
27 | self.weight_basis = Parameter(torch.Tensor(idfcn*out_channels, in_channels // groups, *self.kernel_size))
28 | if bias:
29 | self.bias = Parameter(torch.Tensor(out_channels))
30 | else:
31 | self.register_parameter('bias', None)
32 | self.reset_parameters()
33 |
34 | def reset_parameters(self):
35 | n = self.in_channels
36 | for k in self.kernel_size:
37 | n *= k
38 | stdv = 1. / math.sqrt(n)
39 | self.weight_basis.data.uniform_(-stdv, stdv)
40 | if self.bias is not None:
41 | self.bias.data.uniform_(-stdv, stdv)
42 |
43 | def __repr__(self):
44 | s = ('{name}({in_channels}, {out_channels}, kernel_size={kernel_size}'
45 | ', stride={stride}')
46 | if self.padding != (0,) * len(self.padding):
47 | s += ', padding={padding}'
48 | if self.dilation != (1,) * len(self.dilation):
49 | s += ', dilation={dilation}'
50 | if self.output_padding != (0,) * len(self.output_padding):
51 | s += ', output_padding={output_padding}'
52 | if self.groups != 1:
53 | s += ', groups={groups}'
54 | if self.bias is None:
55 | s += ', bias=False'
56 | s += ')'
57 | return s.format(name=self.__class__.__name__, **self.__dict__)
58 |
59 | def forward(self, input, idw):
60 | # idw: conditional input
61 | output = F.conv2d(input, self.weight_basis, self.bias, self.stride, self.padding, self.dilation, self.groups)
62 | output = output.view(output.size(0), self.idfcn, self.out_channels, output.size(2), output.size(3)) * \
63 | idw.view(-1, self.idfcn, 1, 1, 1).expand(output.size(0), self.idfcn, self.out_channels, output.size(2), output.size(3))
64 | output = output.sum(1).view(output.size(0), output.size(2), output.size(3), output.size(4))
65 | return output
66 |
67 |
68 | # an example using dynamic conditional layer
69 | class condition_idfcn_basis_comb_resnet(nn.Module):
70 | def __init__(self, resnet, fcn):
71 | super(condition_idfcn_basis_comb_resnet, self).__init__()
72 | self.resnet = resnet
73 | self.id_fc = nn.Linear(459558, fcn)
74 | self.id_tanh = nn.Tanh()
75 | self.conv_basis = ConvBasis2d(fcn, resnet.fc.in_features, 512, kernel_size=3, padding=1, bias=False)
76 | self.relu = nn.ReLU(inplace=True)
77 | self.fc_output = nn.Linear(512, 5)
78 |
79 | def forward(self, x1, x2):
80 | x1 = self.resnet.conv1(x1)
81 | x1 = self.resnet.bn1(x1)
82 | x1 = self.resnet.relu(x1)
83 | x1 = self.resnet.maxpool(x1)
84 |
85 | x1 = self.resnet.layer1(x1)
86 | x1 = self.resnet.layer2(x1)
87 | x1 = self.resnet.layer3(x1)
88 | x1 = self.resnet.layer4(x1)
89 |
90 | x2 = self.id_fc(x2)
91 | x2 = self.id_tanh(x2)
92 | x3 = self.conv_basis(x1, x2)
93 |
94 | x3 = self.relu(x3)
95 | x3 = self.resnet.avgpool(x3)
96 | x3 = x3.view(x3.size(0), -1)
97 | x3 = self.fc_output(x3)
98 |
99 | return x3
100 |
--------------------------------------------------------------------------------