提交 e8fe4ad0 authored 作者: jiakai's avatar jiakai

Maybe I did something wrong, or the padding in GpuCorrMM is wrong

上级 95d9c1a5
import copy
import os
import logging
_logger = logging.getLogger(__name__)
import theano
from theano import Apply
......@@ -504,39 +506,61 @@ gpu_ger_inplace = GpuGer(inplace=True)
class BaseGpuCorrMM(GpuOp):
"""Base class for `GpuCorrMM`, `GpuCorrMM_gradWeights` and
`GpuCorrMM_gradInputs`. Cannot be used directly."""
`GpuCorrMM_gradInputs`. Cannot be used directly.
def __init__(self, border_mode="valid",
subsample=(1, 1),
pad=(0, 0)):
if border_mode != "valid":
raise ValueError("border_mode must be 'valid'")
:param border_mode: one of 'valid', 'full', 'half'; additionally, the
padding size could be directly specified by an integer or a pair of
integers
:param subsample: perform subsampling of the output (default: (1, 1))
:param pad: *deprecated*, now you should always use border_mode
"""
def __init__(self, border_mode="valid", subsample=(1, 1), pad=(0, 0)):
if pad != (0, 0):
_logger.warning(
'do not use pad for BaseGpuCorrMM; please set padding in'
'border_mode, see the docstring for more details')
if border_mode != "valid":
raise ValueError("border_mode must be 'valid'")
border_mode = pad
if isinstance(border_mode, int):
border_mode = (border_mode, border_mode)
if isinstance(border_mode, tuple):
pad_h, pad_w = map(int, border_mode)
border_mode = (pad_h, pad_w)
if not ((isinstance(border_mode, tuple) and min(border_mode) >= 0) or
border_mode in ('valid', 'full', 'half')):
raise ValueError(
'invalid border_mode {}, which must be either '
'"valid", "full", "half", an integer or a pair of'
' integers'.format(border_mode))
self.border_mode = border_mode
if len(subsample) != 2:
raise ValueError("subsample must have two elements")
self.subsample = subsample
if (pad not in ("half", "full")) and (len(pad) != 2):
raise ValueError("pad must be 'half', 'full', or have two elements")
self.pad = pad
@property
def pad(self):
if self.border_mode != 'valid':
return self.border_mode
return (0, 0)
def __eq__(self, other):
return type(self) == type(other) \
and self.border_mode == other.border_mode \
and self.subsample == other.subsample \
and self.pad == other.pad
and self.subsample == other.subsample
def __hash__(self):
return hash(type(self)) \
^ hash(self.border_mode) \
^ hash(self.subsample) \
^ hash(self.pad)
^ hash(self.subsample)
def __str__(self):
return '%s{%s, %s, pad=%r}' % (
return '%s{%s, %s}' % (
self.__class__.__name__,
self.border_mode,
str(self.subsample),
self.pad)
str(self.subsample))
def flops(self, inp, outp):
""" Useful with the hack in profilemode to print the MFlops"""
......@@ -558,7 +582,7 @@ class BaseGpuCorrMM(GpuOp):
def c_code_cache_version(self):
# raise this whenever modifying any of the support_code_files
return (0, 23)
return (0, 24)
def c_support_code_apply(self, node, nodename):
# REMEMBER TO RAISE c_code_cache_version when changing any of
......@@ -591,27 +615,28 @@ class BaseGpuCorrMM(GpuOp):
:param sub: Dictionary of substitutions useable to help generating the
C code.
:param height: If self.subsample[0] != 1, a variable giving the height
of the filters for direction="backprop weights" or the height of the
input images for direction="backprop inputs".
If self.pad == 'half', a variable giving the height of the filters
for direction="backprop weights".
Ignored otherwise.
of the filters for direction="backprop weights" or the height of
the input images for direction="backprop inputs".
If self.border_mode == 'half', a variable giving the height of the
filters for direction="backprop weights". Ignored otherwise.
:param width: If self.subsample[1] != 1, a variable giving the width
of the filters for direction="backprop weights" or the width of the
input images for direction="backprop inputs".
If self.pad == 'half', a variable giving the width of the filters
for direction="backprop weights".
Ignored otherwise.
If self.border_mode == 'half', a variable giving the width of the
filters for direction="backprop weights". Ignored otherwise.
"""
if self.border_mode != "valid":
raise ValueError("mode must be 'valid'")
dH, dW = self.subsample
if self.pad == "half":
if self.border_mode == "half":
padH = padW = -1
elif self.pad == "full":
elif self.border_mode == "full":
padH = padW = -2
elif isinstance(self.border_mode, tuple):
padH, padW = self.border_mode
else:
padH, padW = self.pad
assert self.border_mode == "valid"
padH = padW = 0
if direction == "forward":
direction = 0
out = top
......@@ -841,10 +866,10 @@ class GpuCorrMM(BaseGpuCorrMM):
bottom, weights = inp
top, = grads
top = gpu_contiguous(top)
d_bottom = GpuCorrMM_gradInputs(self.border_mode, self.subsample, self.pad)(
weights, top, bottom.shape[-2:])
d_weights = GpuCorrMM_gradWeights(self.border_mode, self.subsample, self.pad)(
bottom, top, weights.shape[-2:])
d_bottom = GpuCorrMM_gradInputs(self.border_mode, self.subsample)(
weights, top, bottom.shape[-2:])
d_weights = GpuCorrMM_gradWeights(self.border_mode, self.subsample)(
bottom, top, weights.shape[-2:])
return d_bottom, d_weights
......
......@@ -122,9 +122,7 @@ class GpuDnnConvDesc(GpuOp):
"""This Op builds a convolution descriptor for use in the other
convolution operations.
:param border_mode: 'valid' or 'full'
:param subsample: The subsample, tuple like (dx, dy)
:param conv_mode: 'conv' or 'cross'
see the doc of :func:`dnn_conv` for a description of the parameters
"""
__props__ = ('border_mode', 'subsample', 'conv_mode')
......
......@@ -586,7 +586,7 @@ def test_gemm_valid():
extra_shapes += get_shapes2(scales_kern=(2, 2), kern_stride=(2, 2))
for t in _test_valid(cuda.blas.BaseGpuCorrMM,
mode=theano_mode.including("conv_gemm"),
mode=theano_mode.excluding("cudnn"),
extra_shapes=extra_shapes):
yield t
......@@ -695,7 +695,7 @@ def test_full():
def test_gemm_full():
for t in _test_full(cuda.blas.BaseGpuCorrMM,
mode=theano_mode.including("conv_gemm")):
mode=theano_mode.excluding("cudnn")):
yield t
......@@ -747,7 +747,7 @@ def test_subsample():
def test_gemm_subsample():
for t in _test_subsample(cuda.blas.BaseGpuCorrMM,
theano_mode.including("conv_gemm")):
theano_mode.excluding("cudnn")):
yield t
......@@ -837,7 +837,8 @@ class TestConvWithPadding(object):
note that in order to make the yield work, we can not subclass from
unittest.TestCase
"""
conv_ops = []
conv_ops = [lambda i, k, border_mode:
theano.sandbox.cuda.blas.GpuCorrMM(border_mode=border_mode)(i, k)]
@classmethod
def setup_class(cls):
......@@ -855,7 +856,7 @@ class TestConvWithPadding(object):
assert_raises(ValueError, i, img, kern,
border_mode='not border')
def _run_onecase(self, img_shape, kern_shape, padding):
def _run_onecase(self, img_shape, kern_shape, padding, op):
npy_img = numpy.random.rand(*img_shape).astype('float32')
npy_kern = numpy.random.rand(*kern_shape).astype('float32')
img = theano._asarray(npy_img, dtype='float32')
......@@ -863,11 +864,10 @@ class TestConvWithPadding(object):
border_mode = padding
cpuval = py_conv(npy_img, npy_kern, border_mode, (1, 1))
X = tensor.ftensor4()
for op in self.conv_ops:
Y = op(X, kern, border_mode=border_mode)
func = theano.function([X], Y)
gpuval = func(img)
assert_allclose(cpuval, gpuval, rtol=1e-5, atol=1e-5)
Y = op(X, kern, border_mode=border_mode)
func = theano.function([X], Y, mode=theano_mode)
gpuval = numpy.asarray(func(img))
assert_allclose(cpuval, gpuval, rtol=1e-5, atol=1e-5)
def test_numeric_value(self):
params = [
......@@ -877,7 +877,8 @@ class TestConvWithPadding(object):
((5, 10, 9, 6), (12, 10, 9, 4), 'valid')
]
for img_shape, kern_shape, padding in params:
yield (self._run_onecase, img_shape, kern_shape, padding)
for op in self.conv_ops:
yield self._run_onecase, img_shape, kern_shape, padding, op
def gemm_directly(bs, ch, nf, rImg1, rImg2, rFlt1, rFlt2, subsx, subsy,
......@@ -938,8 +939,7 @@ def test_gemm_directly():
def gemm_op(mode, subsample):
pad = 'full' if mode == 'full' else (0, 0)
return theano.sandbox.cuda.blas.GpuCorrMM('valid', subsample, pad)
return theano.sandbox.cuda.blas.GpuCorrMM(mode, subsample)
def dnn_op(mode, subsample):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论