├── 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 | --------------------------------------------------------------------------------