Commit 55d55a6a authored by Benjamin Thomas Graham's avatar Benjamin Thomas Graham
Browse files

README

parent 556a8c06
# Code of Conduct # Code of Conduct
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read the [full text](https://code.facebook.com/pages/876921332402685/open-source-code-of-conduct) so that you can understand what actions will and will not be tolerated. Facebook has adopted a Code of Conduct that we expect project participants to adhere to.
Please read the [full text](https://code.fb.com/codeofconduct/)
so that you can understand what actions will and will not be tolerated.
...@@ -143,9 +143,10 @@ To run the examples you may also need to install unrar: ...@@ -143,9 +143,10 @@ To run the examples you may also need to install unrar:
apt-get install unrar apt-get install unrar
``` ```
## License
SparseConvNet is Attribution-NonCommercial 4.0 International licensed, as found in the LICENSE file.
## Links
### Links
1. [ICDAR 2013 Chinese Handwriting Recognition Competition 2013](http://www.nlpr.ia.ac.cn/events/CHRcompetition2013/competition/Home.html) First place in task 3, with test error of 2.61%. Human performance on the test set was 4.81%. [Report](http://www.nlpr.ia.ac.cn/events/CHRcompetition2013/competition/ICDAR%202013%20CHR%20competition.pdf) 1. [ICDAR 2013 Chinese Handwriting Recognition Competition 2013](http://www.nlpr.ia.ac.cn/events/CHRcompetition2013/competition/Home.html) First place in task 3, with test error of 2.61%. Human performance on the test set was 4.81%. [Report](http://www.nlpr.ia.ac.cn/events/CHRcompetition2013/competition/ICDAR%202013%20CHR%20competition.pdf)
2. [Spatially-sparse convolutional neural networks, 2014](http://arxiv.org/abs/1409.6070) SparseConvNets for Chinese handwriting recognition 2. [Spatially-sparse convolutional neural networks, 2014](http://arxiv.org/abs/1409.6070) SparseConvNets for Chinese handwriting recognition
3. [Fractional max-pooling, 2014](http://arxiv.org/abs/1412.6071) A SparseConvNet with fractional max-pooling achieves an error rate of 3.47% for CIFAR-10. 3. [Fractional max-pooling, 2014](http://arxiv.org/abs/1412.6071) A SparseConvNet with fractional max-pooling achieves an error rate of 3.47% for CIFAR-10.
...@@ -156,7 +157,7 @@ apt-get install unrar ...@@ -156,7 +157,7 @@ apt-get install unrar
8. [Workshop on Learning to See from 3D Data, 2017](https://shapenet.cs.stanford.edu/iccv17workshop/) First place in the [semantic segmentation](https://shapenet.cs.stanford.edu/iccv17/) competition. [Report](https://arxiv.org/pdf/1710.06104) 8. [Workshop on Learning to See from 3D Data, 2017](https://shapenet.cs.stanford.edu/iccv17workshop/) First place in the [semantic segmentation](https://shapenet.cs.stanford.edu/iccv17/) competition. [Report](https://arxiv.org/pdf/1710.06104)
9. [3D Semantic Segmentation with Submanifold Sparse Convolutional Networks, 2017](https://arxiv.org/abs/1711.10275) Semantic segmentation for the ShapeNet Core55 and NYU-DepthV2 datasets, CVPR 2018 9. [3D Semantic Segmentation with Submanifold Sparse Convolutional Networks, 2017](https://arxiv.org/abs/1711.10275) Semantic segmentation for the ShapeNet Core55 and NYU-DepthV2 datasets, CVPR 2018
### Citations ## Citations
If you find this code useful in your research then please cite: If you find this code useful in your research then please cite:
......
#!/bin/bash #!/bin/bash
# Copyright 2016-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
rm -rf build/ dist/ sparseconvnet.egg-info rm -rf build/ dist/ sparseconvnet.egg-info
python setup.py install python setup.py install
python examples/hello-world.py
...@@ -69,7 +69,7 @@ input.precomputeMetadata(3) ...@@ -69,7 +69,7 @@ input.precomputeMetadata(3)
model.train() model.train()
if use_cuda: if use_cuda:
input.cuda() input.cuda()
output = model.forward(input) output = model(input)
# Output is 2x32x10x10: our minibatch has 2 samples, the network has 32 output # Output is 2x32x10x10: our minibatch has 2 samples, the network has 32 output
# feature planes, and 10x10 is the spatial size of the output. # feature planes, and 10x10 is the spatial size of the output.
......
// Copyright 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the license found in the
// LICENSE file in the root directory of this source tree.
#include <ATen/ATen.h> #include <ATen/ATen.h>
#include <Metadata/Metadata.h> #include <Metadata/Metadata.h>
......
// Copyright 2016-present, Facebook, Inc.
// All rights reserved.
//
// This source code is licensed under the license found in the
// LICENSE file in the root directory of this source tree.
#include "Metadata/Metadata.h" #include "Metadata/Metadata.h"
double AffineReluTrivialConvolution_updateOutput(at::Tensor input_features, double AffineReluTrivialConvolution_updateOutput(at::Tensor input_features,
......
...@@ -8,13 +8,13 @@ forward_pass_multiplyAdd_count = 0 ...@@ -8,13 +8,13 @@ forward_pass_multiplyAdd_count = 0
forward_pass_hidden_states = 0 forward_pass_hidden_states = 0
from .activations import Tanh, Sigmoid, ReLU, LeakyReLU, ELU, SELU, BatchNormELU from .activations import Tanh, Sigmoid, ReLU, LeakyReLU, ELU, SELU, BatchNormELU
from .averagePooling import AveragePooling from .averagePooling import AveragePooling
from .batchNormalization import BatchNormalization, BatchNormReLU, BatchNormLeakyReLU from .batchNormalization import BatchNormalization, BatchNormReLU, BatchNormLeakyReLU, MeanOnlyBNLeakyReLU
from .classificationTrainValidate import ClassificationTrainValidate from .classificationTrainValidate import ClassificationTrainValidate
from .convolution import Convolution from .convolution import Convolution
from .deconvolution import Deconvolution from .deconvolution import Deconvolution
from .denseToSparse import DenseToSparse from .denseToSparse import DenseToSparse
from .dropout import Dropout, BatchwiseDropout from .dropout import Dropout, BatchwiseDropout
from .fullConvolution import FullConvolution from .fullConvolution import FullConvolution, TransposeConvolution
from .identity import Identity from .identity import Identity
from .inputBatch import InputBatch from .inputBatch import InputBatch
from .ioLayers import InputLayer, OutputLayer, BLInputLayer, BLOutputLayer, InputLayerInput from .ioLayers import InputLayer, OutputLayer, BLInputLayer, BLOutputLayer, InputLayerInput
......
...@@ -34,8 +34,8 @@ class BatchNormalization(Module): ...@@ -34,8 +34,8 @@ class BatchNormalization(Module):
self.momentum = momentum self.momentum = momentum
self.affine = affine self.affine = affine
self.leakiness = leakiness self.leakiness = leakiness
self.register_buffer("runningMean", torch.Tensor(nPlanes).fill_(0)) self.register_buffer("running_mean", torch.Tensor(nPlanes).fill_(0))
self.register_buffer("runningVar", torch.Tensor(nPlanes).fill_(1)) self.register_buffer("running_var", torch.Tensor(nPlanes).fill_(1))
if affine: if affine:
self.weight = Parameter(torch.Tensor(nPlanes).fill_(1)) self.weight = Parameter(torch.Tensor(nPlanes).fill_(1))
self.bias = Parameter(torch.Tensor(nPlanes).fill_(0)) self.bias = Parameter(torch.Tensor(nPlanes).fill_(0))
...@@ -49,8 +49,8 @@ class BatchNormalization(Module): ...@@ -49,8 +49,8 @@ class BatchNormalization(Module):
input.features, input.features,
optionalTensor(self, 'weight'), optionalTensor(self, 'weight'),
optionalTensor(self, 'bias'), optionalTensor(self, 'bias'),
self.runningMean, self.running_mean,
self.runningVar, self.running_var,
self.eps, self.eps,
self.momentum, self.momentum,
self.training, self.training,
...@@ -84,8 +84,11 @@ class BatchNormLeakyReLU(BatchNormalization): ...@@ -84,8 +84,11 @@ class BatchNormLeakyReLU(BatchNormalization):
BatchNormalization.__init__(self, nPlanes, eps, momentum, True, 0.333) BatchNormalization.__init__(self, nPlanes, eps, momentum, True, 0.333)
def __repr__(self): def __repr__(self):
s = 'BatchNormReLU(' + str(self.nPlanes) + ',eps=' + str(self.eps) + \ s = 'BatchLeakyNorm(' + str(self.nPlanes) + ',eps=' + str(self.eps) + \
',momentum=' + str(self.momentum) + ',affine=' + str(self.affine) + ')' ',momentum=' + str(self.momentum) + ',affine=' + str(self.affine)
if self.leakiness > 0:
s = s + ',leakiness=' + str(self.leakiness)
s = s + ')'
return s return s
class BatchNormalizationFunction(Function): class BatchNormalizationFunction(Function):
...@@ -95,25 +98,25 @@ class BatchNormalizationFunction(Function): ...@@ -95,25 +98,25 @@ class BatchNormalizationFunction(Function):
input_features, input_features,
weight, weight,
bias, bias,
runningMean, running_mean,
runningVar, running_var,
eps, eps,
momentum, momentum,
train, train,
leakiness): leakiness):
ctx.nPlanes = runningMean.shape[0] ctx.nPlanes = running_mean.shape[0]
ctx.train = train ctx.train = train
ctx.leakiness = leakiness ctx.leakiness = leakiness
output_features = input_features.new() output_features = input_features.new()
saveMean = input_features.new().resize_(ctx.nPlanes) saveMean = input_features.new().resize_(ctx.nPlanes)
saveInvStd = runningMean.clone().resize_(ctx.nPlanes) saveInvStd = running_mean.clone().resize_(ctx.nPlanes)
sparseconvnet.SCN.BatchNormalization_updateOutput( sparseconvnet.SCN.BatchNormalization_updateOutput(
input_features, input_features,
output_features, output_features,
saveMean, saveMean,
saveInvStd, saveInvStd,
runningMean, running_mean,
runningVar, running_var,
weight, weight,
bias, bias,
eps, eps,
...@@ -124,8 +127,8 @@ class BatchNormalizationFunction(Function): ...@@ -124,8 +127,8 @@ class BatchNormalizationFunction(Function):
output_features, output_features,
weight, weight,
bias, bias,
runningMean, running_mean,
runningVar, running_var,
saveMean, saveMean,
saveInvStd) saveInvStd)
return output_features return output_features
...@@ -136,8 +139,8 @@ class BatchNormalizationFunction(Function): ...@@ -136,8 +139,8 @@ class BatchNormalizationFunction(Function):
output_features,\ output_features,\
weight,\ weight,\
bias,\ bias,\
runningMean,\ running_mean,\
runningVar,\ running_var,\
saveMean,\ saveMean,\
saveInvStd = ctx.saved_tensors saveInvStd = ctx.saved_tensors
assert ctx.train assert ctx.train
...@@ -151,11 +154,58 @@ class BatchNormalizationFunction(Function): ...@@ -151,11 +154,58 @@ class BatchNormalizationFunction(Function):
grad_output.contiguous(), grad_output.contiguous(),
saveMean, saveMean,
saveInvStd, saveInvStd,
runningMean, running_mean,
runningVar, running_var,
weight, weight,
bias, bias,
grad_weight, grad_weight,
grad_bias, grad_bias,
ctx.leakiness) ctx.leakiness)
return grad_input, optionalTensorReturn(grad_weight), optionalTensorReturn(grad_bias), None, None, None, None, None, None return grad_input, optionalTensorReturn(grad_weight), optionalTensorReturn(grad_bias), None, None, None, None, None, None
class MeanOnlyBNLeakyReLU(Module):
"""
Parameters:
nPlanes : number of input planes
momentum : for calculating running average for testing (default 0.9)
leakiness : Apply activation def inplace: 0<=leakiness<=1.
0 for ReLU, values in (0,1) for LeakyReLU, 1 for no activation def.
"""
def __init__(
self,
nPlanes,
affine=True,
leakiness=1,
momentum=0.9):
Module.__init__(self)
self.nPlanes = nPlanes
self.momentum = momentum
self.register_buffer("running_mean", torch.Tensor(nPlanes).fill_(0))
self.affine = affine
if affine:
self.bias = Parameter(torch.Tensor(nPlanes).fill_(0))
self.leakiness = leakiness
def forward(self, input):
assert input.features.nelement() == 0 or input.features.size(1) == self.nPlanes
output = SparseConvNetTensor()
output.metadata = input.metadata
output.spatial_size = input.spatial_size
if self.training:
with torch.no_grad():
m=input.features.mean(0)
self.running_mean=self.running_mean*self.momentum+m*(1-self.momentum)
output.features = input.features - m
else:
output.features = input.features - self.running_mean
if self.affine:
output_features = output_features + self.bias
if self.leakiness != 1:
output.features = torch.nn.functional.leaky_relu(output.features, self.leakiness)
return output
def input_spatial_size(self, out_size):
return out_size
def __repr__(self):
s = 'MeanOnlyBatchNorm(' + str(self.nPlanes) + ',momentum=' + str(self.momentum) + ',leakiness=' + str(self.leakiness) + ')'
return s
...@@ -148,3 +148,5 @@ class FullConvolutionFunction(Function): ...@@ -148,3 +148,5 @@ class FullConvolutionFunction(Function):
grad_weight, grad_weight,
grad_bias) grad_bias)
return grad_input, grad_weight, optionalTensorReturn(grad_bias), None, None, None, None, None, None, None return grad_input, grad_weight, optionalTensorReturn(grad_bias), None, None, None, None, None, None, None
TransposeConvolution=FullConvolution
...@@ -31,3 +31,16 @@ class Sequential(torch.nn.Sequential): ...@@ -31,3 +31,16 @@ class Sequential(torch.nn.Sequential):
else: else:
input = module(input) input = module(input)
return input return input
def rebias(self, input):
for module in self._modules.values():
if isinstance(module, Sequential):
input = module.reweight(input)
elif hasattr(input, 'features') and hasattr(module, 'bias'):
f = module(input).features
f = f - module.bias
module.bias = torch.nn.Parameter(-f.mean(0))
input = module(input)
else:
input = module(input)
return input
import torch # Copyright 2016-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
import torch import torch
from torch.nn.functional import normalize from torch.nn.functional import normalize
from torch.nn.parameter import Parameter from torch.nn.parameter import Parameter
class SpectralNorm(object): class SpectralNorm(object):
def __init__(self, name='weight', n_power_iterations=1, dim=0, eps=1e-12): def __init__(self, name='weight', n_power_iterations=1, dim=0, eps=1e-12, norm=1):
self.name = name self.name = name
self.dim = dim self.dim = dim
self.norm = norm
if n_power_iterations <= 0: if n_power_iterations <= 0:
raise ValueError('Expected n_power_iterations to be positive, but ' raise ValueError('Expected n_power_iterations to be positive, but '
'got n_power_iterations={}'.format(n_power_iterations)) 'got n_power_iterations={}'.format(n_power_iterations))
...@@ -19,7 +22,7 @@ class SpectralNorm(object): ...@@ -19,7 +22,7 @@ class SpectralNorm(object):
def compute_weight(self, module): def compute_weight(self, module):
weight = getattr(module, self.name + '_orig') weight = getattr(module, self.name + '_orig')
u = getattr(module, self.name + '_u') u = getattr(module, self.name + '_u')
weight_mat = weight weight_mat = weight #/ self.norm
if self.dim != 0: if self.dim != 0:
# permute dim to front # permute dim to front
weight_mat = weight_mat.permute(self.dim, weight_mat = weight_mat.permute(self.dim,
...@@ -35,7 +38,7 @@ class SpectralNorm(object): ...@@ -35,7 +38,7 @@ class SpectralNorm(object):
u = normalize(torch.matmul(weight_mat, v), dim=0, eps=self.eps) u = normalize(torch.matmul(weight_mat, v), dim=0, eps=self.eps)
sigma = torch.dot(u, torch.matmul(weight_mat, v)) sigma = torch.dot(u, torch.matmul(weight_mat, v))
weight = weight / sigma weight = weight * (self.norm / sigma)
return weight, u return weight, u
def remove(self, module): def remove(self, module):
...@@ -55,8 +58,8 @@ class SpectralNorm(object): ...@@ -55,8 +58,8 @@ class SpectralNorm(object):
getattr(module, self.name).detach_().requires_grad_(r_g) getattr(module, self.name).detach_().requires_grad_(r_g)
@staticmethod @staticmethod
def apply(module, name, n_power_iterations, dim, eps): def apply(module, name, n_power_iterations, dim, eps, norm):
fn = SpectralNorm(name, n_power_iterations, dim, eps) fn = SpectralNorm(name, n_power_iterations, dim, eps, norm)
weight = module._parameters[name] weight = module._parameters[name]
height = weight.size(dim) height = weight.size(dim)
...@@ -75,11 +78,10 @@ class SpectralNorm(object): ...@@ -75,11 +78,10 @@ class SpectralNorm(object):
module.register_forward_pre_hook(fn) module.register_forward_pre_hook(fn)
return fn return fn
def spectral_norm(module, n_power_iterations=1, eps=1e-12): def spectral_norm(module, n_power_iterations=1, eps=1e-12, norm=1):
""" """
https://github.com/pytorch/pytorch/blob/master/torch/nn/utils/spectral_norm.py https://github.com/pytorch/pytorch/blob/master/torch/nn/utils/spectral_norm.py
""" """
dim=1 dim=module.weight.ndimension()-1
#torch.nn.utils. SpectralNorm.apply(module, 'weight', n_power_iterations, dim, eps, norm)
SpectralNorm.apply(module, 'weight', n_power_iterations, dim, eps)
return module return module
...@@ -69,7 +69,7 @@ def append_tensors(tensors): ...@@ -69,7 +69,7 @@ def append_tensors(tensors):
spatial_size=tensors[0].spatial_size spatial_size=tensors[0].spatial_size
dimension=len(spatial_size) dimension=len(spatial_size)
x=SparseConvNetTensor( x=SparseConvNetTensor(
features=torch.cat([t.features for t in features],0), features=torch.cat([t.features for t in tensors],0),
metadata=Metadata(dimension), metadata=Metadata(dimension),
spatial_size=spatial_size) spatial_size=spatial_size)
for t in tensors: for t in tensors:
...@@ -106,3 +106,10 @@ def compare_sparse(x, y): ...@@ -106,3 +106,10 @@ def compare_sparse(x, y):
if R.numel(): if R.numel():
e += y.features[R].pow(2).sum() e += y.features[R].pow(2).sum()
return e / (cL.numel() + L.numel() + R.numel()) return e / (cL.numel() + L.numel() + R.numel())
def spectral_norm_svd(module):
w=module.weight
if w.ndimension()==3:
w=w.view(-1,w.size(2))
_,s,_=torch.svd(w)
return s[0]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment