Commit d77687a6 authored by Benjamin Graham's avatar Benjamin Graham Committed by Benjamin Thomas Graham
Browse files

Rename ValidConvolutions to SubmanifoldConvolutions, update for PyTorch 0.4 Tensor/Variable merge

parent 297e04c0
......@@ -6,12 +6,13 @@
import sparseconvnet
import torch.nn.functional as F
from torch.autograd import Function, Variable
from torch.autograd import Function
from torch.nn import Module, Parameter
from .utils import *
from .sparseConvNetTensor import SparseConvNetTensor
from .batchNormalization import BatchNormalization
class Sigmoid(Module):
def forward(self, input):
output = SparseConvNetTensor()
......@@ -20,6 +21,7 @@ class Sigmoid(Module):
output.spatial_size = input.spatial_size
return output
class Tanh(Module):
def forward(self, input):
output = SparseConvNetTensor()
......@@ -28,6 +30,7 @@ class Tanh(Module):
output.spatial_size = input.spatial_size
return output
class ReLU(Module):
def forward(self, input):
output = SparseConvNetTensor()
......@@ -36,6 +39,7 @@ class ReLU(Module):
output.spatial_size = input.spatial_size
return output
class ELU(Module):
def forward(self, input):
output = SparseConvNetTensor()
......
......@@ -4,11 +4,12 @@
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
from torch.autograd import Function, Variable
from torch.autograd import Function
from torch.nn import Module
from .utils import *
from .sparseConvNetTensor import SparseConvNetTensor
class AveragePoolingFunction(Function):
@staticmethod
def forward(
......@@ -21,15 +22,11 @@ class AveragePoolingFunction(Function):
pool_size,
pool_stride,
nFeaturesToDrop):
ctx.input_features=input_features
ctx.input_metadata=input_metadata
ctx.input_spatial_size = input_spatial_size
ctx.output_spatial_size = output_spatial_size
ctx.input_metadata = input_metadata
ctx.dimension = dimension
ctx.pool_size = pool_size
ctx.pool_stride = pool_stride
ctx.nFeaturesToDrop = nFeaturesToDrop
output_features = input_features.new()
dim_typed_fn(dimension, input_features, 'AveragePooling_updateOutput')(
input_spatial_size,
output_spatial_size,
......@@ -40,23 +37,36 @@ class AveragePoolingFunction(Function):
output_features,
nFeaturesToDrop,
torch.cuda.IntTensor() if input_features.is_cuda else nullptr)
ctx.save_for_backward(input_features,
output_features,
input_spatial_size,
output_spatial_size,
pool_size,
pool_stride)
return output_features
@staticmethod
def backward(ctx, grad_output):
grad_input=Variable(grad_output.data.new())
input_features,\
output_features,\
input_spatial_size,\
output_spatial_size,\
pool_size,\
pool_stride = ctx.saved_tensors
grad_input = grad_output.new()
dim_typed_fn(
ctx.dimension, ctx.input_features, 'AveragePooling_updateGradInput')(
ctx.input_spatial_size,
ctx.output_spatial_size,
ctx.pool_size,
ctx.pool_stride,
ctx.dimension, input_features, 'AveragePooling_updateGradInput')(
input_spatial_size,
output_spatial_size,
pool_size,
pool_stride,
ctx.input_metadata.ffi,
ctx.input_features,
grad_input.data,
grad_output.data.contiguous(),
input_features,
grad_input,
grad_output.contiguous(),
ctx.nFeaturesToDrop,
torch.cuda.IntTensor() if ctx.input_features.is_cuda else nullptr)
torch.cuda.IntTensor() if input_features.is_cuda else nullptr)
return grad_input, None, None, None, None, None, None, None
......@@ -67,29 +77,39 @@ class AveragePooling(Module):
self.pool_size = toLongTensor(dimension, pool_size)
self.pool_stride = toLongTensor(dimension, pool_stride)
self.nFeaturesToDrop = nFeaturesToDrop
def forward(self, input):
output = SparseConvNetTensor()
output.metadata = input.metadata
output.spatial_size = (
input.spatial_size - self.pool_size) / self.pool_stride + 1
assert ((output.spatial_size-1)*self.pool_stride+self.pool_size==input.spatial_size).all()
output.features = AveragePoolingFunction().apply(
input.features, input.metadata, input.spatial_size,
output.spatial_size, self.dimension,self.pool_size,self.pool_stride,
assert ((output.spatial_size - 1) * self.pool_stride +
self.pool_size == input.spatial_size).all()
output.features = AveragePoolingFunction.apply(
input.features,
input.metadata,
input.spatial_size,
output.spatial_size,
self.dimension,
self.pool_size,
self.pool_stride,
self.nFeaturesToDrop)
return output
def input_spatial_size(self, out_size):
return (out_size - 1) * self.pool_stride + self.pool_size
def __repr__(self):
s = 'AveragePooling'
if self.pool_size.max() == self.pool_size.min() and\
self.pool_stride.max() == self.pool_stride.min():
s = s + str(self.pool_size[0]) + '/' + str(self.pool_stride[0])
s = s + str(self.pool_size[0].item()) + \
'/' + str(self.pool_stride[0].item())
else:
s = s + '(' + str(self.pool_size[0])
s = s + '(' + str(self.pool_size[0].item())
for i in self.pool_size[1:]:
s = s + ',' + str(i)
s = s + ')/(' + str(self.pool_stride[0])
s = s + ')/(' + str(self.pool_stride[0].item())
for i in self.pool_stride[1:]:
s = s + ',' + str(i)
s = s + ')'
......
......@@ -15,11 +15,12 @@ leakiness : Apply activation def inplace: 0<=leakiness<=1.
0 for ReLU, values in (0,1) for LeakyReLU, 1 for no activation def.
"""
from torch.autograd import Function, Variable
from torch.autograd import Function
from torch.nn import Module, Parameter
from .utils import *
from .sparseConvNetTensor import SparseConvNetTensor
class BatchNormalizationFunction(Function):
@staticmethod
def forward(
......@@ -33,60 +34,72 @@ class BatchNormalizationFunction(Function):
momentum,
train,
leakiness):
ctx.nPlanes=runningMean.shape[0]
ctx.input_features=input_features
ctx.weight=weight
ctx.bias=bias
ctx.runningMean=runningMean
ctx.runningVar=runningVar
ctx.train=train
ctx.leakiness=leakiness
ctx.output_features = input_features.new()
ctx.saveMean = input_features.new().resize_(ctx.nPlanes)
ctx.saveInvStd = runningMean.clone().resize_(ctx.nPlanes)
ctx.nPlanes = runningMean.shape[0]
ctx.train = train
ctx.leakiness = leakiness
output_features = input_features.new()
saveMean = input_features.new().resize_(ctx.nPlanes)
saveInvStd = runningMean.clone().resize_(ctx.nPlanes)
typed_fn(input_features, 'BatchNormalization_updateOutput')(
input_features,
ctx.output_features,
ctx.saveMean,
ctx.saveInvStd,
ctx.runningMean,
ctx.runningVar,
ctx.weight if ctx.weight is not None else nullptr,
ctx.bias if ctx.bias is not None else nullptr,
output_features,
saveMean,
saveInvStd,
runningMean,
runningVar,
weight if weight is not None else nullptr,
bias if bias is not None else nullptr,
eps,
momentum,
ctx.train,
ctx.leakiness)
return ctx.output_features
ctx.save_for_backward(input_features,
output_features,
weight,
bias,
runningMean,
runningVar,
saveMean,
saveInvStd)
return output_features
@staticmethod
def backward(ctx, grad_output):
input_features,\
output_features,\
weight,\
bias,\
runningMean,\
runningVar,\
saveMean,\
saveInvStd = ctx.saved_tensors
assert ctx.train
grad_input=Variable(grad_output.data.new())
if ctx.weight is None:
grad_weight=None
grad_input = grad_output.new()
if weight is None:
grad_weight = None
else:
grad_weight=Variable(ctx.input_features.new().resize_(ctx.nPlanes).zero_())
if ctx.bias is None:
grad_bias=None
grad_weight = input_features.new().resize_(ctx.nPlanes).zero_()
if bias is None:
grad_bias = None
else:
grad_bias=Variable(ctx.input_features.new().resize_(ctx.nPlanes).zero_())
typed_fn(ctx.input_features, 'BatchNormalization_backward')(
ctx.input_features,
grad_input.data,
ctx.output_features,
grad_output.data.contiguous(),
ctx.saveMean,
ctx.saveInvStd,
ctx.runningMean,
ctx.runningVar,
ctx.weight if ctx.weight is not None else nullptr,
ctx.bias if ctx.bias is not None else nullptr,
grad_bias = input_features.new().resize_(ctx.nPlanes).zero_()
typed_fn(input_features, 'BatchNormalization_backward')(
input_features,
grad_input,
output_features,
grad_output.contiguous(),
saveMean,
saveInvStd,
runningMean,
runningVar,
weight if weight is not None else nullptr,
bias if bias is not None else nullptr,
grad_weight.data if grad_weight is not None else nullptr,
grad_bias.data if grad_bias is not None else nullptr,
ctx.leakiness)
return grad_input, grad_weight, grad_bias, None, None, None, None, None, None
class BatchNormalization(Module):
def __init__(
self,
......@@ -109,12 +122,13 @@ class BatchNormalization(Module):
else:
self.weight = None
self.bias = None
def forward(self, input):
assert input.features.ndimension()==0 or input.features.size(1) == self.nPlanes
assert input.features.ndimension() == 0 or input.features.size(1) == self.nPlanes
output = SparseConvNetTensor()
output.metadata = input.metadata
output.spatial_size = input.spatial_size
output.features = BatchNormalizationFunction().apply(
output.features = BatchNormalizationFunction.apply(
input.features,
self.weight,
self.bias,
......@@ -125,8 +139,10 @@ class BatchNormalization(Module):
self.training,
self.leakiness)
return output
def input_spatial_size(self, out_size):
return out_size
def __repr__(self):
s = 'BatchNorm(' + str(self.nPlanes) + ',eps=' + str(self.eps) + \
',momentum=' + str(self.momentum) + ',affine=' + str(self.affine)
......@@ -135,17 +151,21 @@ class BatchNormalization(Module):
s = s + ')'
return s
class BatchNormReLU(BatchNormalization):
def __init__(self, nPlanes, eps=1e-4, momentum=0.9):
BatchNormalization.__init__(self, nPlanes, eps, momentum, True, 0)
def __repr__(self):
s = 'BatchNormReLU(' + str(self.nPlanes) + ',eps=' + str(self.eps) + \
',momentum=' + str(self.momentum) + ',affine=' + str(self.affine) + ')'
return s
class BatchNormLeakyReLU(BatchNormalization):
def __init__(self, nPlanes, eps=1e-4, momentum=0.9):
BatchNormalization.__init__(self, nPlanes, eps, momentum, True, 0.333)
def __repr__(self):
s = 'BatchNormReLU(' + str(self.nPlanes) + ',eps=' + str(self.eps) + \
',momentum=' + str(self.momentum) + ',affine=' + str(self.affine) + ')'
......
This diff is collapsed.
This diff is collapsed.
......@@ -12,12 +12,13 @@ Parameters:
dimension : of the input field
"""
from torch.autograd import Function, Variable
from torch.autograd import Function
from torch.nn import Module
from .utils import *
from .metadata import Metadata
from .sparseConvNetTensor import SparseConvNetTensor
class DenseToSparseFunction(Function):
@staticmethod
def forward(
......@@ -26,32 +27,36 @@ class DenseToSparseFunction(Function):
output_metadata,
output_spatial_size,
dimension):
ctx.dimension=dimension
a=input
aa=a.permute(*([0,]+list(range(2,2+dimension))+[1,])).clone()
ctx.aas=aa.size()
nz=aa.abs().sum(dimension+1).view(aa.size()[0:-1])
s=torch.LongTensor(nz.stride()).view(1,dimension+1)
nz=nz.nonzero()
s=s.type_as(nz)
aa=aa.view(-1,a.size(1))
ctx.aas2=aa.size()
ctx.r=(nz*s.expand_as(nz)).sum(1).view(-1)
ctx.output_features=aa.index_select(0,ctx.r)
ctx.dimension = dimension
aa = input.permute(
*([0, ] + list(range(2, 2 + dimension)) + [1, ])).clone()
aas = aa.size()
nz = aa.abs().sum(dimension + 1).view(aa.size()[0:-1])
s = torch.LongTensor(nz.stride()).view(1, dimension + 1)
nz = nz.nonzero()
s = s.type_as(nz)
aa = aa.view(-1, input.size(1))
aas2 = aa.size()
r = (nz * s.expand_as(nz)).sum(1).view(-1)
output_features = aa.index_select(0, ctx.r)
dim_fn(dimension, 'createMetadataForDenseToSparse')(
output_metadata.ffi,
output_spatial_size,
nz.cpu(),
input.size(0))
return ctx.output_features
ctx.save_for_backwards(output_features, aas, aas2, r)
return output_features
@staticmethod
def backward(ctx, grad_output):
grad_input=Variable(grad_output.data.new().resize_(ctx.aas2).zero_().index_copy_(0,ctx.r,grad_output.data))
grad_input=grad_input.view(ctx.aas).permute(*([0,ctx.dimension+1]+list(range(1,ctx.dimension+1))))
output_features, aas, aas2, r = ctx.saved_tensors
grad_input = grad_output.new().resize_(
aas2).zero_().index_copy_(0, r, grad_output.data)
grad_input = grad_input.view(aas).permute(
*([0, ctx.dimension + 1] + list(range(1, ctx.dimension + 1))))
return grad_input, None, None, None
class DenseToSparse(Module):
def __init__(self, dimension):
Module.__init__(self)
......@@ -60,8 +65,8 @@ class DenseToSparse(Module):
def forward(self, input):
output = SparseConvNetTensor()
output.metadata = Metadata(self.dimension)
output.spatial_size=torch.LongTensor(list(input.size()[2:]))
output.features=DenseToSparseFunction().apply(
output.spatial_size = torch.LongTensor(list(input.size()[2:]))
output.features = DenseToSparseFunction.apply(
input,
output.metadata,
output.spatial_size,
......
This diff is collapsed.
......@@ -6,8 +6,10 @@
from torch.nn import Module
class Identity(Module):
def forward(self, input):
return input
def input_spatial_size(self, out_size):
return out_size
......@@ -9,6 +9,7 @@ from .metadata import Metadata
from .utils import toLongTensor, dim_fn
from .sparseConvNetTensor import SparseConvNetTensor
class InputBatch(SparseConvNetTensor):
def __init__(self, dimension, spatial_size):
self.dimension = dimension
......@@ -51,7 +52,7 @@ class InputBatch(SparseConvNetTensor):
to add point (1,2,3) to sample 7, and (4,5,6) to sample 9 (0-indexed).
"""
l = locations.narrow(1,0,self.dimension)
l = locations[:, :self.dimension]
assert l.min() >= 0 and (self.spatial_size.expand_as(l) - l).min() > 0
dim_fn(self.dimension, 'setInputSpatialLocations')(
self.metadata.ffi, self.features, locations, vectors, overwrite)
......
This diff is collapsed.
......@@ -25,7 +25,7 @@ from .networkInNetwork import NetworkInNetwork
from .reLU import ReLU
from .sequential import Sequential
from .sparseToDense import SparseToDense
from .validConvolution import ValidConvolution
from .submanifoldConvolution import SubmanifoldConvolution
from .networkArchitectures import *
from .classificationTrainValidate import ClassificationTrainValidate
from .misc import *
......@@ -25,7 +25,10 @@ class AveragePooling(SparseModule):
self.output.metadata = input.metadata
self.output.spatial_size =\
(input.spatial_size - self.pool_size) / self.pool_stride + 1
dim_typed_fn(self.dimension, input.features, 'AveragePooling_updateOutput')(
dim_typed_fn(
self.dimension,
input.features,
'AveragePooling_updateOutput')(
input.spatial_size,
self.output.spatial_size,
self.pool_size,
......
This diff is collapsed.
This diff is collapsed.
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