提交 f81b97d1 authored 作者: Frédéric Bastien's avatar Frédéric Bastien

Merge pull request #1564 from Snarfza/downsampleGradGrad

Added second derivative to max downsampling function
......@@ -310,6 +310,11 @@ class DownsampleFactorMaxGrad(Op):
def infer_shape(self, node, in_shapes):
return [in_shapes[0]]
def grad(self, inp, grads):
x, maxout, gz = inp
ggx, = grads
return [theano.tensor.zeros_like(x),theano.tensor.zeros_like(maxout),DownsampleFactorMaxGradGrad(self.ds, ignore_border=self.ignore_border)(x, maxout, ggx)]
def c_code(self, node, name, inp, out, sub):
x, z, gz = inp
gx, = out
......@@ -404,3 +409,98 @@ class DownsampleFactorMaxGrad(Op):
def c_code_cache_version(self):
return (0,1)
class DownsampleFactorMaxGradGrad(Op):
@staticmethod
def out_shape(imgshape, ds, ignore_border=False):
"""Return the shape of the output from this op, for input of given shape and flags.
:param imgshape: the shape of a tensor of images. The last two elements are interpreted
as the number of rows, and the number of cols.
:type imgshape: tuple, list, or similar of integer or
scalar Theano variable.
:param ds: downsample factor over rows and columns
:type ds: list or tuple of two ints
:param ignore_border: if ds doesn't divide imgshape, do we include an extra row/col of
partial downsampling (False) or ignore it (True).
:type ignore_border: bool
:rtype: list
:returns: the shape of the output from this op, for input of given shape. This will
have the same length as imgshape, but with last two elements reduced as per the
downsampling & ignore_border flags.
"""
if len(imgshape) < 2:
raise TypeError('imgshape must have at least two elements (rows, cols)')
r, c = imgshape[-2:]
rval = list(imgshape[:-2]) + [ r // ds[0], c // ds[1] ]
if not ignore_border:
if isinstance(r, theano.Variable):
rval[-2] = tensor.switch(r % ds[0], rval[-2] + 1, rval[-2])
elif r % ds[0]:
rval[-2] += 1
if isinstance(c, theano.Variable):
rval[-1] = tensor.switch(c % ds[1], rval[-1] + 1, rval[-1])
elif c % ds[1]:
rval[-1] += 1
return rval
def __init__(self, ds, ignore_border):
self.ds = tuple(ds)
self.ignore_border = ignore_border
def __eq__(self, other):
return type(self) == type(other) and self.ds == other.ds and self.ignore_border == other.ignore_border
def __hash__(self):
return hash(type(self)) ^ hash(self.ds) ^ hash(self.ignore_border)
def __str__(self):
return '%s{%s,%s}' % (self.__class__.__name__, self.ds, self.ignore_border)
def make_node(self, x, maxout, gz):
# make_node should only be called by the grad function of DownsampleFactorMax,
# so these asserts should not fail.
assert isinstance(x, Variable) and x.ndim==4
assert isinstance(maxout, Variable) and maxout.ndim==4
assert isinstance(gz, Variable) and gz.ndim==4
return Apply(self, [x, maxout, gz], [x.type()])
def perform(self, node, inp, out):
x, maxout, ggx = inp
z, = out
if len(x.shape)!=4:
raise NotImplementedError('DownsampleFactorMax requires 4D input for now')
z_shape = self.out_shape(x.shape, self.ds, self.ignore_border)
if (z[0] is None) or (z[0].shape != z_shape):
z[0] = numpy.zeros(self.out_shape(x.shape, self.ds, self.ignore_border))
z[0] = theano._asarray(z[0], dtype=x.dtype)
ggz=z[0]
ds0, ds1 = self.ds
if self.ignore_border:
x_usable2 = (x.shape[2] / ds0 * ds0)
else: x_usable2 = x.shape[2]
if self.ignore_border:
x_usable3 = (x.shape[3] / ds1 * ds1)
else: x_usable3 = x.shape[3]
for n in xrange(x.shape[0]):
for k in xrange(x.shape[1]):
for i in xrange(x_usable2):
zi = i / ds0
for j in xrange(x_usable3):
zj = j / ds1
if (maxout[n,k,zi,zj] == x[n,k,i,j]):
ggz[n,k,zi,zj] = ggx[n,k,i,j]
def infer_shape(self, node, in_shapes):
return [in_shapes[0]]
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论