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