提交 0e85602f authored 作者: Nicolas Ballas's avatar Nicolas Ballas

Update interface + doc

上级 f815f1e3
...@@ -2726,12 +2726,10 @@ def local_abstractconv_gemm(node): ...@@ -2726,12 +2726,10 @@ def local_abstractconv_gemm(node):
prod1 = node.op.kshp[0] * node.op.kshp[1] prod1 = node.op.kshp[0] * node.op.kshp[1]
prod2 = ((node.op.imshp[-2] - node.op.kshp[0] + 1) * prod2 = ((node.op.imshp[-2] - node.op.kshp[0] + 1) *
(node.op.imshp[-1] - node.op.kshp[1] + 1)) (node.op.imshp[-1] - node.op.kshp[1] + 1))
if ((node.op.bsize is not None) and if (None not in node.op.imshp[:1]):
(len(node.op.imshp) == 3) and
(node.op.imshp[0] is not None)):
# we also know batchsize and input channels # we also know batchsize and input channels
prod1 *= node.op.bsize prod1 *= node.op.imshp[0]
prod2 *= node.op.imshp[0] prod2 *= node.op.imshp[1]
# compare to decide # compare to decide
if prod1 > prod2: if prod1 > prod2:
# (we need to wrap the result in as_cuda_ndarray_variable, # (we need to wrap the result in as_cuda_ndarray_variable,
...@@ -2784,7 +2782,7 @@ def local_abstractconv_gradinputs_gemm(node): ...@@ -2784,7 +2782,7 @@ def local_abstractconv_gradinputs_gemm(node):
# which ones take precedence over others. # which ones take precedence over others.
abstractconv_groupopt = theano.gof.optdb.LocalGroupDB() abstractconv_groupopt = theano.gof.optdb.LocalGroupDB()
abstractconv_groupopt.__name__ = "gpu_abstractconv_opts" abstractconv_groupopt.__name__ = "gpu_abstractconv_opts"
register_specialize_device()(abstractconv_groupopt, 'gpu', 'fast_compile') register_specialize_device(abstractconv_groupopt, 'gpu', 'fast_compile')
# cuDNN is first, but only registered if cuDNN is available. # cuDNN is first, but only registered if cuDNN is available.
conv_groupopt.register('local_abstractconv_dnn', dnn.local_abstractconv_cudnn, 20, conv_groupopt.register('local_abstractconv_dnn', dnn.local_abstractconv_cudnn, 20,
......
...@@ -8,6 +8,12 @@ import theano.tensor.nnet.abstract_conv2d as conv ...@@ -8,6 +8,12 @@ import theano.tensor.nnet.abstract_conv2d as conv
from theano.sandbox.cuda import float32_shared_constructor as gpu_shared from theano.sandbox.cuda import float32_shared_constructor as gpu_shared
from theano.compile import shared as cpu_shared from theano.compile import shared as cpu_shared
from theano.sandbox.cuda.dnn import dnn_available, dnn_conv, dnn_gradweight, dnn_gradinput from theano.sandbox.cuda.dnn import dnn_available, dnn_conv, dnn_gradweight, dnn_gradinput
from nose.plugins.skip import SkipTest
import theano.sandbox.cuda as cuda
if not cuda.cuda_available:
raise SkipTest('Optional package cuda disabled')
if theano.config.mode == 'FAST_COMPILE': if theano.config.mode == 'FAST_COMPILE':
mode_with_gpu = theano.compile.mode.get_mode('FAST_RUN').including('gpu') mode_with_gpu = theano.compile.mode.get_mode('FAST_RUN').including('gpu')
...@@ -84,7 +90,7 @@ class TestConv2d(unittest.TestCase): ...@@ -84,7 +90,7 @@ class TestConv2d(unittest.TestCase):
utt.assert_allclose(res_ref, res) utt.assert_allclose(res_ref, res)
if verify_grad: if verify_grad:
utt.verify_grad(conv.AbstractConv2d(border_mode="valid", imshp=imshp, kshp=kshp, utt.verify_grad(conv.AbstractConv2d(border_mode="valid", imshp=imshp, kshp=kshp,
bsize=inputs_shape[0], subsample=subsample), subsample=subsample),
[inputs_val, filters_val], [inputs_val, filters_val],
mode=mode) mode=mode)
...@@ -180,7 +186,7 @@ class TestConv2d(unittest.TestCase): ...@@ -180,7 +186,7 @@ class TestConv2d(unittest.TestCase):
def test_dnn_conv(self): def test_dnn_conv(self):
if not dnn_available(): if not dnn_available():
return raise SkipTest(cuda.dnn.dnn_available.msg)
mode = mode_with_gpu mode = mode_with_gpu
# provide_shape is not used by the CuDNN impementation # provide_shape is not used by the CuDNN impementation
provide_shape = False provide_shape = False
...@@ -207,8 +213,10 @@ class TestConv2d(unittest.TestCase): ...@@ -207,8 +213,10 @@ class TestConv2d(unittest.TestCase):
filters_flip=flip) filters_flip=flip)
def test_cormm_conv(self): def test_cormm_conv(self):
mode = mode_with_gpu.excluding('cudnn') if not dnn_available():
raise SkipTest(cuda.dnn.dnn_available.msg)
mode = mode_with_gpu.excluding('cudnn')
for (i, f), s, b, flip, provide_shape in itertools.product( for (i, f), s, b, flip, provide_shape in itertools.product(
zip(self.inputs_shapes, self.filters_shapes), zip(self.inputs_shapes, self.filters_shapes),
self.subsamples, self.subsamples,
...@@ -233,8 +241,10 @@ class TestConv2d(unittest.TestCase): ...@@ -233,8 +241,10 @@ class TestConv2d(unittest.TestCase):
filters_flip=flip) filters_flip=flip)
def test_cpu_conv(self): def test_cpu_conv(self):
mode = mode_without_gpu if not dnn_available():
raise SkipTest(cuda.dnn.dnn_available.msg)
mode = mode_without_gpu
for (i, f), s, b, flip, provide_shape in itertools.product( for (i, f), s, b, flip, provide_shape in itertools.product(
zip(self.inputs_shapes, self.filters_shapes), zip(self.inputs_shapes, self.filters_shapes),
self.subsamples, self.subsamples,
......
...@@ -26,7 +26,6 @@ def conv2d(inputs, ...@@ -26,7 +26,6 @@ def conv2d(inputs,
filters, filters,
inputs_shape=None, inputs_shape=None,
filters_shape=None, filters_shape=None,
batch_size=None,
border_mode='valid', border_mode='valid',
subsample=(1, 1), subsample=(1, 1),
filters_flip=True): filters_flip=True):
...@@ -89,7 +88,6 @@ def conv2d(inputs, ...@@ -89,7 +88,6 @@ def conv2d(inputs,
conv_op = AbstractConv2d(imshp=inputs_shape, conv_op = AbstractConv2d(imshp=inputs_shape,
kshp=filters_shape, kshp=filters_shape,
bsize=batch_size,
border_mode=border_mode, border_mode=border_mode,
subsample=subsample, subsample=subsample,
filters_flip=filters_flip) filters_flip=filters_flip)
...@@ -98,13 +96,53 @@ def conv2d(inputs, ...@@ -98,13 +96,53 @@ def conv2d(inputs,
class BaseAbstractConv2d(Op): class BaseAbstractConv2d(Op):
""" """
Base class for ConvInferace Base class for AbstractConv
Define an abstract convolution op that will be replaced with the appropriate implementation
:type imshp: None, tuple/list of len 4 of int or Constant variable
:param imshp: The shape of the input parameter.
Optional, possibly used to choose an optimal implementation.
You can give ``None`` for any element of the list to specify that this
element is not known at compile time.
imshp is defined w.r.t the forward conv.
:type kshp: None, tuple/list of len 4 of int or Constant variable
:param kshp: The shape of the filters parameter.
Optional, possibly used to choose an optimal implementation.
You can give ``None`` for any element of the list to specify that this
element is not known at compile time.
kshp is defined w.r.t the forward conv.
:type border_mode: str, int or tuple of two int
:param border_mode: Either of the following:
* ``'valid'``: apply filter wherever it completely overlaps with the
input. Generates output of shape: input shape - filter shape + 1
* ``'full'``: apply filter wherever it partly overlaps with the input.
Generates output of shape: input shape + filter shape - 1
* ``'half'``: pad input with a symmetric border of ``filter rows // 2``
rows and ``filter columns // 2`` columns, then perform a valid
convolution. For filters with an odd number of rows and columns, this
leads to the output shape being equal to the input shape.
* ``int``: pad input with a symmetric border of zeros of the given
width, then perform a valid convolution.
* ``(int1, int2)``: pad input with a symmetric border of ``int1`` rows
and ``int2`` columns, then perform a valid convolution.
:type subsample: tuple of len 2
:param subsample: factor by which to subsample the output.
Also called strides elsewhere.
:type filters_flip: bool
:param filters_flip: If ``True``, will flip the filter rows and columns
before sliding them over the input. This operation is normally referred
to as a convolution, and this is the default. If ``False``, the filters
are not flipped and the operation is referred to as a cross-correlation.
""" """
check_broadcast = False check_broadcast = False
__props__ = ('border_mode', 'subsample', 'filters_flip', 'imshp', 'kshp', 'bsize') __props__ = ('border_mode', 'subsample', 'filters_flip', 'imshp', 'kshp')
def __init__(self, def __init__(self,
imshp=None, kshp=None, bsize=None, imshp=None, kshp=None,
border_mode="valid", subsample=(1, 1), border_mode="valid", subsample=(1, 1),
filters_flip = True): filters_flip = True):
if isinstance(border_mode, int): if isinstance(border_mode, int):
...@@ -121,7 +159,6 @@ class BaseAbstractConv2d(Op): ...@@ -121,7 +159,6 @@ class BaseAbstractConv2d(Op):
self.imshp = imshp self.imshp = imshp
self.kshp = kshp self.kshp = kshp
self.bsize = bsize
self.border_mode = border_mode self.border_mode = border_mode
self.filters_flip = filters_flip self.filters_flip = filters_flip
...@@ -146,15 +183,17 @@ class BaseAbstractConv2d(Op): ...@@ -146,15 +183,17 @@ class BaseAbstractConv2d(Op):
class AbstractConv2d(BaseAbstractConv2d): class AbstractConv2d(BaseAbstractConv2d):
"""
Abstract Op for the forward convolution.
"""
def __init__(self, def __init__(self,
imshp=None, imshp=None,
kshp=None, kshp=None,
bsize=None,
border_mode="valid", border_mode="valid",
subsample=(1, 1), subsample=(1, 1),
filters_flip = True): filters_flip = True):
super(AbstractConv2d, self).__init__(imshp, kshp, bsize, super(AbstractConv2d, self).__init__(imshp, kshp,
border_mode, subsample, filters_flip) border_mode, subsample, filters_flip)
def make_node(self, img, kern): def make_node(self, img, kern):
...@@ -176,13 +215,11 @@ class AbstractConv2d(BaseAbstractConv2d): ...@@ -176,13 +215,11 @@ class AbstractConv2d(BaseAbstractConv2d):
bottom, weights = inp bottom, weights = inp
top, = grads top, = grads
d_bottom = AbstractConv2d_gradInputs(self.imshp, self.kshp, d_bottom = AbstractConv2d_gradInputs(self.imshp, self.kshp,
self.bsize,
self.border_mode, self.border_mode,
self.subsample, self.subsample,
self.filters_flip)( self.filters_flip)(
weights, top, bottom.shape[-2:]) weights, top, bottom.shape[-2:])
d_weights = AbstractConv2d_gradWeights(self.imshp, self.kshp, d_weights = AbstractConv2d_gradWeights(self.imshp, self.kshp,
self.bsize,
self.border_mode, self.border_mode,
self.subsample, self.subsample,
self.filters_flip)( self.filters_flip)(
...@@ -201,11 +238,10 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d): ...@@ -201,11 +238,10 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d):
def __init__(self, def __init__(self,
imshp=None, imshp=None,
kshp=None, kshp=None,
bsize=None,
border_mode="valid", border_mode="valid",
subsample=(1, 1), subsample=(1, 1),
filters_flip=True): filters_flip=True):
super(AbstractConv2d_gradWeights, self).__init__(imshp, kshp, bsize, super(AbstractConv2d_gradWeights, self).__init__(imshp, kshp,
border_mode, subsample, filters_flip) border_mode, subsample, filters_flip)
# Update shape/height_width # Update shape/height_width
...@@ -214,10 +250,6 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d): ...@@ -214,10 +250,6 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d):
raise TypeError('img must be 4D tensor') raise TypeError('img must be 4D tensor')
if topgrad.type.ndim != 4: if topgrad.type.ndim != 4:
raise TypeError('topgrad must be 4D tensor') raise TypeError('topgrad must be 4D tensor')
if self.subsample != (1, 1) or self.border_mode == "half":
if shape is None:
raise ValueError('shape must be given if subsample != (1, 1)'
' or border_mode == "half"')
shape = as_tensor_variable(shape) shape = as_tensor_variable(shape)
broadcastable = [topgrad.broadcastable[1], broadcastable = [topgrad.broadcastable[1],
...@@ -233,13 +265,11 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d): ...@@ -233,13 +265,11 @@ class AbstractConv2d_gradWeights(BaseAbstractConv2d):
bottom, top = inp[:2] bottom, top = inp[:2]
weights, = grads weights, = grads
d_bottom = AbstractConv2d_gradInputs(self.imshp, self.kshp, d_bottom = AbstractConv2d_gradInputs(self.imshp, self.kshp,
self.bsize,
self.border_mode, self.border_mode,
self.subsample, self.subsample,
self.filters_flip)(weights, top, bottom.shape[-2:]) self.filters_flip)(weights, top, bottom.shape[-2:])
d_top = AbstractConv2d(self.imshp, d_top = AbstractConv2d(self.imshp,
self.kshp, self.kshp,
self.bsize,
self.border_mode, self.border_mode,
self.subsample, self.subsample,
self.filters_flip)(bottom, weights) self.filters_flip)(bottom, weights)
...@@ -262,11 +292,10 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d): ...@@ -262,11 +292,10 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d):
def __init__(self, def __init__(self,
imshp=None, imshp=None,
kshp=None, kshp=None,
bsize=None,
border_mode="valid", border_mode="valid",
subsample=(1, 1), subsample=(1, 1),
filters_flip=True): filters_flip=True):
super(AbstractConv2d_gradInputs, self).__init__(imshp, kshp, bsize, super(AbstractConv2d_gradInputs, self).__init__(imshp, kshp,
border_mode, subsample, filters_flip) border_mode, subsample, filters_flip)
# Update shape/height_width # Update shape/height_width
...@@ -275,8 +304,6 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d): ...@@ -275,8 +304,6 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d):
raise TypeError('kern must be 4D tensor') raise TypeError('kern must be 4D tensor')
if topgrad.type.ndim != 4: if topgrad.type.ndim != 4:
raise TypeError('topgrad must be 4D tensor') raise TypeError('topgrad must be 4D tensor')
if self.subsample != (1, 1) and shape is None:
raise ValueError('shape must be given if subsample != (1, 1)')
shape = as_tensor_variable(shape) shape = as_tensor_variable(shape)
broadcastable = [topgrad.type.broadcastable[0], broadcastable = [topgrad.type.broadcastable[0],
...@@ -292,10 +319,9 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d): ...@@ -292,10 +319,9 @@ class AbstractConv2d_gradInputs(BaseAbstractConv2d):
weights, top = inp[:2] weights, top = inp[:2]
bottom, = grads bottom, = grads
d_weights = AbstractConv2d_gradWeights(self.imshp, self.kshp, d_weights = AbstractConv2d_gradWeights(self.imshp, self.kshp,
self.bsize,
self.border_mode, self.border_mode,
self.subsample)(bottom, top, weights.shape[-2:]) self.subsample)(bottom, top, weights.shape[-2:])
d_top = AbstractConv2d(self.imshp, self.kshp, self.bsize, d_top = AbstractConv2d(self.imshp, self.kshp,
self.border_mode, self.subsample)(bottom, weights) self.border_mode, self.subsample)(bottom, weights)
d_height_width = (theano.gradient.DisconnectedType()(),) d_height_width = (theano.gradient.DisconnectedType()(),)
return (d_weights, d_top) + d_height_width return (d_weights, d_top) + d_height_width
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论