def numpy_max_pool_2d_stride(input, ds, ignore_border=False, st=None, mode="max"): """Helper function, implementing max_pool_2d in pure numpy this function provides st input to indicate the stide size for the pooling regions. if not indicated, st == sd.""" if len(input.shape) < 2: raise NotImplementedError("input should have at least 2 dim," " shape is %s" % str(input.shape)) if st is None: st = ds xi = 0 yi = 0 img_rows = input.shape[-2] img_cols = input.shape[-1] out_r = 0 out_c = 0 if img_rows - ds[0] >= 0: out_r = (img_rows - ds[0]) // st[0] + 1 if img_cols - ds[1] >= 0: out_c = (img_cols - ds[1]) // st[1] + 1 if not ignore_border: if out_r > 0: if img_rows - ((out_r - 1) * st[0] + ds[0]) > 0: rr = img_rows - out_r * st[0] if rr > 0: out_r += 1 else: if img_rows > 0: out_r += 1 if out_c > 0: if img_cols - ((out_c - 1) * st[1] + ds[1]) > 0: cr = img_cols - out_c * st[1] if cr > 0: out_c += 1 else: if img_cols > 0: out_c += 1 out_shp = list(input.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) func = numpy.max if mode == "sum": func = numpy.sum elif mode != "max": func = numpy.average output_val = numpy.zeros(out_shp) for k in numpy.ndindex(*input.shape[:-2]): for i in range(output_val.shape[-2]): ii_st = i * st[0] ii_end = builtins.min(ii_st + ds[0], img_rows) for j in range(output_val.shape[-1]): jj_st = j * st[1] jj_end = builtins.min(jj_st + ds[1], img_cols) patch = input[k][ii_st:ii_end, jj_st:jj_end] output_val[k][i, j] = func(patch) return output_val
def perform(self, node, inp, out): x, maxout, ggx = inp z, = out if len(x.shape) != 4: raise NotImplementedError( 'DownsampleFactorMaxGradGrad requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st) 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, self.st), dtype=x.dtype) ggz = z[0] # number of pooling output rows pr = ggz.shape[-2] # number of pooling output cols pc = ggz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st img_rows = x.shape[-2] img_cols = x.shape[-1] for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == x[n, k, row_ind, col_ind]): ggz[n, k, r, c] = ggx[n, k, row_ind, col_ind]
def numpy_max_pool_nd_stride_pad(input, ws, ignore_border=True, stride=None, pad=None, mode="max"): assert ignore_border nd = len(ws) if pad is None: pad = (0, ) * nd if stride is None: stride = (0, ) * nd assert len(pad) == len(ws) == len(stride) assert all(ws[i] > pad[i] for i in range(nd)) def pad_img(x): # initialize padded input y = np.zeros( x.shape[0:-nd] + tuple(x.shape[-nd + i] + pad[i] * 2 for i in range(nd)), dtype=x.dtype, ) # place the unpadded input in the center block = (slice(None), ) * (len(x.shape) - nd) + tuple( slice(pad[i], x.shape[-nd + i] + pad[i]) for i in range(nd)) y[block] = x return y pad_img_shp = list(input.shape[:-nd]) out_shp = list(input.shape[:-nd]) for i in range(nd): padded_size = input.shape[-nd + i] + 2 * pad[i] pad_img_shp.append(padded_size) out_shp.append((padded_size - ws[i]) // stride[i] + 1) output_val = np.zeros(out_shp) padded_input = pad_img(input) func = np.max if mode == "sum": func = np.sum elif mode != "max": func = np.average inc_pad = mode == "average_inc_pad" for l in np.ndindex(*input.shape[:-nd]): for r in np.ndindex(*output_val.shape[-nd:]): region = [] for i in range(nd): r_stride = r[i] * stride[i] r_end = builtins.min(r_stride + ws[i], pad_img_shp[-nd + i]) if not inc_pad: r_stride = builtins.max(r_stride, pad[i]) r_end = builtins.min(r_end, input.shape[-nd + i] + pad[i]) region.append(slice(r_stride, r_end)) patch = padded_input[l][region] output_val[l][r] = func(patch) return output_val
def perform(self, node, inp, out): x, = inp z, = out if len(x.shape) != 4: raise NotImplementedError( 'Pool requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding) if not self.ignore_border: assert z_shape[2] > 0 assert z_shape[3] > 0 if (z[0] is None) or (z[0].shape != z_shape): z[0] = numpy.empty(z_shape, dtype=x.dtype) zz = z[0] # number of pooling output rows pr = zz.shape[-2] # number of pooling output cols pc = zz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w inc_pad = self.mode == 'average_inc_pad' # pad the image if self.padding != (0, 0): y = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x func = numpy.max if self.mode == 'sum': func = numpy.sum elif self.mode != 'max': func = numpy.average for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ds0, img_rows) if not inc_pad: row_st = builtins.max(row_st, self.padding[0]) row_end = builtins.min(row_end, x.shape[-2] + pad_h) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ds1, img_cols) if not inc_pad: col_st = builtins.max(col_st, self.padding[1]) col_end = builtins.min(col_end, x.shape[-1] + pad_w) zz[n, k, r, c] = func(y[ n, k, row_st:row_end, col_st:col_end])
def check_unpool_and_switches(input, output, maxpool_output, ds, ignore_border, st, padding, index_type, index_scope): row_downsample, col_downsample = ds row_stride, col_stride = st output_row = output.shape[-2] output_col = output.shape[-1] input_channels = input.shape[-3] assert input.shape[0] == output.shape[0], 'Image Number Size Incorrect, {6} != {7} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, input.shape[0], output.shape[0]) assert input.shape[1] == output.shape[1], 'Image Channel Size Incorrect, {6} != {7} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, input.shape[1], output.shape[1]) #assert maxpool_output.shape[2]*st[0] + ds[0]-1 == output.shape[2], 'Image Column Size Incorrect, {6} != {7} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, maxpool_output.shape[2]*st[0] + ds[0]-1, output.shape[2]) #assert maxpool_output.shape[3]*st[1] + ds[1]-1 == output.shape[3], 'Image Row Size Incorrect, {6} != {7} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, maxpool_output.shape[3]*st[1] + ds[1]-1, output.shape[3]) if(st[0] >= ds[0] and st[1] >= ds[1]): for n in range(maxpool_output.shape[0]): for k in range(input_channels): for r in range(maxpool_output.shape[2]): row_start = r * st[0] row_end = builtins.min(row_start + row_downsample, output_row) for c in range(maxpool_output.shape[3]): col_start = c * st[1] col_end = builtins.min(col_start + col_downsample, output_col) max_val = np.max(output[n, k, row_start:row_end, col_start:col_end]) expected_max_val = maxpool_output[n, k, r, c] assert max_val == expected_max_val, '(max: {8}, maxpool: {9}, input: {10}, output: {11}) Invalid Max Value in Output Patch {6}, {7} Incorrect, {8} != {9} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, max_val, expected_max_val, input[n, k, row_start, col_start], output[n, k, row_start, col_start]) nz_count = np.count_nonzero(output[n, k, row_start:row_end, col_start:col_end]) if(expected_max_val != 0): assert nz_count == 1, 'Number of Nonzero Values in Output Patch {6}, {7} Incorrect, {8} != 1 (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, nz_count) else: assert nz_count == 0, 'Number of Nonzero Values in Output Patch {6}, {7} Incorrect, {8} != 0 (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, nz_count) else: for n in range(output.shape[0]): for k in range(output.shape[1]): for r in range(output.shape[2]): for c in range(output.shape[3]): val = output[n, k, r, c] if(val != 0): expected_max_matched = False for i in range(max((r-ds[0]+1)//st[0], 0), min(r//st[0]+1, maxpool_output.shape[2])): for j in range(max((c-ds[1]+1)//st[1], 0), min(c//st[1]+1, maxpool_output.shape[3])): if(not expected_max_matched): expected_max_matched = (maxpool_output[n, k, i, j] == val) assert expected_max_matched, 'Nonzero Values {6}, {7} Not Equal to Local Maxs, {8} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, val) assert val == input[n, k, r, c], 'Nonzero Values {6}, {7} Not Same as Input Image, {8} != {9} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, val, input[n, k, r, c]) else: if(r < input.shape[2] and c < input.shape[3] and r//st[0] < maxpool_output.shape[2] and c//st[1] < maxpool_output.shape[3]): expected_max_val = maxpool_output[n, k, r//st[0], c//st[1]] assert input[n, k, r, c] <= expected_max_val, 'Zeroed Value {6}, {7} Greater than Max, {8} > {9} (ds={0}, ignore_border={1}, st={2}, padding={3}, index_type={4}, index_scope={5})'.format(ds, ignore_border, st, padding, index_type, index_scope, r, c, input[n, k, r, c], expected_max_val)
def numpy_max_pool_nd_stride_padding(input, ds, ignore_border=True, st=None, padding=None, mode='max'): assert ignore_border nd = len(ds) if padding is None: padding = (0, ) * nd if st is None: st = (0, ) * nd assert len(padding) == len(ds) == len(st) assert all(ds[i] > padding[i] for i in range(nd)) def pad_img(x): # initialize padded input y = numpy.zeros(x.shape[0:-nd] + tuple(x.shape[-nd + i] + padding[i] * 2 for i in range(nd)), dtype=x.dtype) # place the unpadded input in the center block = ((slice(None), ) * (len(x.shape) - nd) + tuple( slice(padding[i], x.shape[-nd + i] + padding[i]) for i in range(nd))) y[block] = x return y pad_img_shp = list(input.shape[:-nd]) out_shp = list(input.shape[:-nd]) for i in range(nd): padded_size = input.shape[-nd + i] + 2 * padding[i] pad_img_shp.append(padded_size) out_shp.append((padded_size - ds[i]) // st[i] + 1) output_val = numpy.zeros(out_shp) padded_input = pad_img(input) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average inc_pad = mode == 'average_inc_pad' for l in numpy.ndindex(*input.shape[:-nd]): for r in numpy.ndindex(*output_val.shape[-nd:]): region = [] for i in range(nd): r_st = r[i] * st[i] r_end = builtins.min(r_st + ds[i], pad_img_shp[-nd + i]) if not inc_pad: r_st = builtins.max(r_st, padding[i]) r_end = builtins.min(r_end, input.shape[-nd + i] + padding[i]) region.append(slice(r_st, r_end)) patch = padded_input[l][region] output_val[l][r] = func(patch) return output_val
def perform(self, node, inp, out): if self.mode == 'average_exc_pad' and self.padding != (0, 0): raise NotImplementedError() x, gz = inp gx_stg, = out z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding) if (gx_stg[0] is None) or (gx_stg[0].shape != z_shape): gx_stg[0] = numpy.empty(z_shape, dtype=x.dtype) zz = gx_stg[0] # number of pooling output rows pr = zz.shape[-2] # number of pooling output cols pc = zz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w inc_pad = self.mode == 'average_inc_pad' sum_mode = self.mode == 'sum' # pad the image if self.padding != (0, 0): y = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x gx = numpy.zeros_like(y) for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): if sum_mode or inc_pad: row_st = r * st0 else: row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): if sum_mode or inc_pad: col_st = c * st1 else: col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) if sum_mode: val = gz[n, k, r, c] else: val = gz[n, k, r, c] / ((row_end - row_st) * (col_end - col_st)) gx[n, k, row_st:row_end, col_st:col_end] += val # unpad the image gx = gx[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] gx_stg[0] = gx
def numpy_max_pool_2d_stride_padding(x, ds, ignore_border=True, st=None, padding=(0, 0), mode='max'): assert ignore_border pad_h = padding[0] pad_w = padding[1] h = x.shape[-2] w = x.shape[-1] assert ds[0] > pad_h assert ds[1] > pad_w def pad_img(x): y = numpy.zeros((x.shape[0], x.shape[1], x.shape[2] + pad_h * 2, x.shape[3] + pad_w * 2), dtype=x.dtype) y[:, :, pad_h:(x.shape[2] + pad_h), pad_w:(x.shape[3] + pad_w)] = x return y img_rows = h + 2 * pad_h img_cols = w + 2 * pad_w out_r = (img_rows - ds[0]) // st[0] + 1 out_c = (img_cols - ds[1]) // st[1] + 1 out_shp = list(x.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) ds0, ds1 = ds st0, st1 = st output_val = numpy.zeros(out_shp) y = pad_img(x) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average inc_pad = mode == 'average_inc_pad' for k in numpy.ndindex(*x.shape[:-2]): for i in range(output_val.shape[-2]): ii_st = i * st[0] ii_end = builtins.min(ii_st + ds[0], img_rows) if not inc_pad: ii_st = builtins.max(ii_st, pad_h) ii_end = builtins.min(ii_end, h + pad_h) for j in range(output_val.shape[-1]): jj_st = j * st[1] jj_end = builtins.min(jj_st + ds[1], img_cols) if not inc_pad: jj_st = builtins.max(jj_st, pad_w) jj_end = builtins.min(jj_end, w + pad_w) patch = y[k][ii_st:ii_end, jj_st:jj_end] output_val[k][i, j] = func(patch) return output_val
def perform(self, node, inp, out): x, = inp z, ind = out ind = numpy.zeros_like(x) if len(x.shape) != 4: raise NotImplementedError('Pool requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding) if (z[0] is None) or (z[0].shape != z_shape): z[0] = numpy.empty(z_shape, dtype=x.dtype) zz = z[0] # number of pooling output rows pr = zz.shape[-2] # number of pooling output cols pc = zz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w inc_pad = 0 # pad the image if self.padding != (0, 0): y = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ds0, img_rows) if not inc_pad: row_st = builtins.max(row_st, self.padding[0]) row_end = builtins.min(row_end, x.shape[-2] + pad_h) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ds1, img_cols) if not inc_pad: col_st = builtins.max(col_st, self.padding[1]) col_end = builtins.min(col_end, x.shape[-1] + pad_w) cur_max = y[n, k, row_st, col_st] max_r, max_c = row_st, col_st for rr in xrange(row_st, row_end): for cc in xrange(col_st, col_end): if y[n, k, rr, cc] > cur_max: cur_max = y[n, k, rr, cc] max_r, max_c = rr, cc zz[n, k, r, c] = cur_max ind[n, k, max_r, max_c] = 1
def numpy_max_pool_2d_stride_padding( x, ds, ignore_border=True, st=None, padding=(0, 0), mode='max'): assert ignore_border pad_h = padding[0] pad_w = padding[1] h = x.shape[-2] w = x.shape[-1] assert ds[0] > pad_h assert ds[1] > pad_w def pad_img(x): y = numpy.zeros( (x.shape[0], x.shape[1], x.shape[2] + pad_h * 2, x.shape[3] + pad_w * 2), dtype=x.dtype) y[:, :, pad_h:(x.shape[2] + pad_h), pad_w:(x.shape[3] + pad_w)] = x return y img_rows = h + 2 * pad_h img_cols = w + 2 * pad_w out_r = (img_rows - ds[0]) // st[0] + 1 out_c = (img_cols - ds[1]) // st[1] + 1 out_shp = list(x.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) ds0, ds1 = ds st0, st1 = st output_val = numpy.zeros(out_shp) y = pad_img(x) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average inc_pad = mode == 'average_inc_pad' for k in numpy.ndindex(*x.shape[:-2]): for i in range(output_val.shape[-2]): ii_st = i * st[0] ii_end = builtins.min(ii_st + ds[0], img_rows) if not inc_pad: ii_st = builtins.max(ii_st, pad_h) ii_end = builtins.min(ii_end, h + pad_h) for j in range(output_val.shape[-1]): jj_st = j * st[1] jj_end = builtins.min(jj_st + ds[1], img_cols) if not inc_pad: jj_st = builtins.max(jj_st, pad_w) jj_end = builtins.min(jj_end, w + pad_w) patch = y[k][ii_st:ii_end, jj_st:jj_end] output_val[k][i, j] = func(patch) return output_val
def numpy_max_pool_nd_stride_padding( input, ds, ignore_border=True, st=None, padding=None, mode='max'): assert ignore_border nd = len(ds) if padding is None: padding = (0,) * nd if st is None: st = (0,) * nd assert len(padding) == len(ds) == len(st) assert all(ds[i] > padding[i] for i in range(nd)) def pad_img(x): # initialize padded input y = numpy.zeros( x.shape[0:-nd] + tuple(x.shape[-nd + i] + padding[i] * 2 for i in range(nd)), dtype=x.dtype) # place the unpadded input in the center block = ((slice(None),) * (len(x.shape) - nd) + tuple(slice(padding[i], x.shape[-nd + i] + padding[i]) for i in range(nd))) y[block] = x return y pad_img_shp = list(input.shape[:-nd]) out_shp = list(input.shape[:-nd]) for i in range(nd): padded_size = input.shape[-nd + i] + 2 * padding[i] pad_img_shp.append(padded_size) out_shp.append((padded_size - ds[i]) // st[i] + 1) output_val = numpy.zeros(out_shp) padded_input = pad_img(input) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average inc_pad = mode == 'average_inc_pad' for l in numpy.ndindex(*input.shape[:-nd]): for r in numpy.ndindex(*output_val.shape[-nd:]): region = [] for i in range(nd): r_st = r[i] * st[i] r_end = builtins.min(r_st + ds[i], pad_img_shp[-nd + i]) if not inc_pad: r_st = builtins.max(r_st, padding[i]) r_end = builtins.min(r_end, input.shape[-nd + i] + padding[i]) region.append(slice(r_st, r_end)) patch = padded_input[l][region] output_val[l][r] = func(patch) return output_val
def perform(self, node, inp, out): if self.mode != 'max': raise theano.gof.utils.MethodNotDefined() x, maxout, ggx = inp z, = out if len(x.shape) != 4: raise NotImplementedError( 'DownsampleFactorMaxGradGrad requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding) if (z[0] is None) or (z[0].shape != z_shape): z[0] = numpy.zeros(z_shape, dtype=x.dtype) ggz = z[0] # grad wrt maxout_grad has the same shape as maxout # number of pooling output rows pr = ggz.shape[-2] # number of pooling output cols pc = ggz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pd0, pd1 = self.padding img_rows = x.shape[-2] + 2 * pd0 img_cols = x.shape[-1] + 2 * pd1 # pad the image and its gradients if self.padding != (0, 0): y_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) + x.min() - 1 y_padded[:, :, pd0:(img_rows - pd0), pd1:(img_cols - pd1)] = x ggx_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) ggx_padded[:, :, pd0:(img_rows - pd0), pd1:(img_cols - pd1)] = ggx else: y_padded = x ggx_padded = ggx for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y_padded[n, k, row_ind, col_ind]): ggz[n, k, r, c] = ggx_padded[n, k, row_ind, col_ind]
def perform(self, node, inp, out): if self.mode != 'max': raise theano.gof.utils.MethodNotDefined() x, maxout, ggx = inp z, = out if len(x.shape) != 4: raise NotImplementedError( 'DownsampleFactorMaxGradGrad requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding) if (z[0] is None) or (z[0].shape != z_shape): z[0] = numpy.zeros(z_shape, dtype=x.dtype) ggz = z[0] # grad wrt maxout_grad has the same shape as maxout # number of pooling output rows pr = ggz.shape[-2] # number of pooling output cols pc = ggz.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pd0, pd1 = self.padding img_rows = x.shape[-2] + 2 * pd0 img_cols = x.shape[-1] + 2 * pd1 # pad the image and its gradients if self.padding != (0, 0): y_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) + x.min() - 1 y_padded[:, :, pd0:(img_rows-pd0), pd1:(img_cols-pd1)] = x ggx_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) ggx_padded[:, :, pd0:(img_rows-pd0), pd1:(img_cols-pd1)] = ggx else: y_padded = x ggx_padded = ggx for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y_padded[n, k, row_ind, col_ind]): ggz[n, k, r, c] = ggx_padded[n, k, row_ind, col_ind]
def perform(self, node, inp, out): print("Careful I am using python to compute maxpool gradients") assert self.mode == 'max' x, maxout, gz = inp gx_stg, = out # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w # pad the image if self.padding != (0, 0): y = np.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x gx = np.zeros_like(y) for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) break_flag = False for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y[n, k, row_ind, col_ind]): gx[n, k, row_ind, col_ind] += gz[n, k, r, c] # addition here break_flag = True break if break_flag: break # unpad the image gx = gx[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] gx_stg[0] = gx
def min(xs, y_from_x=lambda x: x): ''' >>> range(10) | min() 0 >>> range(10) | min(lambda x: -x) -9 ''' return __builtins__.min(y_from_x(x) for x in xs)
def perform(self, node, inp, out): x, maxout, ggx, ws, stride, pad = inp z, = out assert ws.shape == stride.shape == pad.shape == (2,) if len(x.shape) != 4: raise NotImplementedError( 'DownsampleFactorMaxGradGrad requires 4D input for now') if (z[0] is None) or (z[0].shape != maxout.shape): z[0] = numpy.zeros(maxout.shape, dtype=x.dtype) ggz = z[0] # grad wrt maxout_grad has the same shape as maxout # number of pooling output rows pr = ggz.shape[-2] # number of pooling output cols pc = ggz.shape[-1] ws0, ws1 = ws st0, st1 = stride pd0, pd1 = pad img_rows = x.shape[-2] + 2 * pd0 img_cols = x.shape[-1] + 2 * pd1 # pad the image and its gradients if pd0 != 0 and pd1 != 0: y_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) + x.min() - 1 y_padded[:, :, pd0:(img_rows - pd0), pd1:(img_cols - pd1)] = x ggx_padded = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) ggx_padded[:, :, pd0:(img_rows - pd0), pd1:(img_cols - pd1)] = ggx else: y_padded = x ggx_padded = ggx for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = r * st0 row_end = builtins.min(row_st + ws0, img_rows) for c in xrange(pc): col_st = c * st1 col_end = builtins.min(col_st + ws1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y_padded[n, k, row_ind, col_ind]): ggz[n, k, r, c] = ggx_padded[n, k, row_ind, col_ind]
def perform(self, node, inp, out): assert self.mode == 'max' x, maxout, gz, ws, stride, pad = inp gx_stg, = out assert ws.shape == stride.shape == pad.shape == (2,) # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ws0, ws1 = ws st0, st1 = stride pad_h = pad[0] pad_w = pad[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w # pad the image if (pad_h, pad_w) != (0, 0): y = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x gx = numpy.zeros_like(y) for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = builtins.max(r * st0, pad_h) row_end = builtins.min(row_st + ws0, img_rows) for c in xrange(pc): col_st = builtins.max(c * st1, pad_w) col_end = builtins.min(col_st + ws1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y[n, k, row_ind, col_ind]): gx[n, k, row_ind, col_ind] += gz[n, k, r, c] # unpad the image gx = gx[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] gx_stg[0] = gx
def perform(self, node, inp, out): assert self.mode == 'max' x, maxout, gz = inp gx_stg, = out # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w # pad the image if self.padding != (0, 0): y = numpy.zeros((x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x gx = numpy.zeros_like(y) for n in range(x.shape[0]): for k in range(x.shape[1]): for r in range(pr): row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in range(pc): col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) for row_ind in range(row_st, row_end): for col_ind in range(col_st, col_end): if (maxout[n, k, r, c] == y[n, k, row_ind, col_ind]): gx[n, k, row_ind, col_ind] += gz[n, k, r, c] # unpad the image gx = gx[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] gx_stg[0] = gx
def perform(self, node, inp, out): assert self.mode == "max" x, maxout, gz = inp gx_stg, = out # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w # pad the image if self.padding != (0, 0): y = numpy.zeros((x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h : (img_rows - pad_h), pad_w : (img_cols - pad_w)] = x else: y = x gx = numpy.zeros_like(y) for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if maxout[n, k, r, c] == y[n, k, row_ind, col_ind]: gx[n, k, row_ind, col_ind] += gz[n, k, r, c] # unpad the image gx = gx[:, :, pad_h : (img_rows - pad_h), pad_w : (img_cols - pad_w)] gx_stg[0] = gx
def numpy_max_pool_nd_stride(input, ws, ignore_border=False, stride=None, mode="max"): """Helper function, implementing pooling in pure numpy this function provides stride input to indicate the stide size for the pooling regions. if not indicated, stride == ws.""" nd = len(ws) if stride is None: stride = ws assert len(stride) == len(ws) out_shp = list(input.shape[:-nd]) for i in range(nd): out = 0 if input.shape[-nd + i] - ws[i] >= 0: out = (input.shape[-nd + i] - ws[i]) // stride[i] + 1 if not ignore_border: if out > 0: if input.shape[-nd + i] - ( (out - 1) * stride[i] + ws[i]) > 0: if input.shape[-nd + i] - out * stride[i] > 0: out += 1 else: if input.shape[-nd + i] > 0: out += 1 out_shp.append(out) func = np.max if mode == "sum": func = np.sum elif mode != "max": func = np.average output_val = np.zeros(out_shp) for l in np.ndindex(*input.shape[:-nd]): for r in np.ndindex(*output_val.shape[-nd:]): region = [] for i in range(nd): r_stride = r[i] * stride[i] r_end = builtins.min(r_stride + ws[i], input.shape[-nd + i]) region.append(slice(r_stride, r_end)) patch = input[l][region] output_val[l][r] = func(patch) return output_val
def numpy_max_pool_nd_stride(input, ds, ignore_border=False, st=None, mode='max'): '''Helper function, implementing pooling in pure numpy this function provides st input to indicate the stide size for the pooling regions. if not indicated, st == sd.''' nd = len(ds) if st is None: st = ds assert len(st) == len(ds) out_shp = list(input.shape[:-nd]) for i in range(nd): out = 0 if input.shape[-nd + i] - ds[i] >= 0: out = (input.shape[-nd + i] - ds[i]) // st[i] + 1 if not ignore_border: if out > 0: if input.shape[-nd + i] - ((out - 1) * st[i] + ds[i]) > 0: if input.shape[-nd + i] - out * st[i] > 0: out += 1 else: if input.shape[-nd + i] > 0: out += 1 out_shp.append(out) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average output_val = numpy.zeros(out_shp) for l in numpy.ndindex(*input.shape[:-nd]): for r in numpy.ndindex(*output_val.shape[-nd:]): region = [] for i in range(nd): r_st = r[i] * st[i] r_end = builtins.min(r_st + ds[i], input.shape[-nd + i]) region.append(slice(r_st, r_end)) patch = input[l][region] output_val[l][r] = func(patch) return output_val
def numpy_max_pool_2d_stride(input, ws, ignore_border=False, stride=None, mode="max"): """Helper function, implementing pool_2d in pure numpy this function provides stride input to indicate the stide size for the pooling regions. if not indicated, stride == ws.""" if len(input.shape) < 2: raise NotImplementedError("input should have at least 2 dim," " shape is %s" % str(input.shape)) if stride is None: stride = ws img_rows = input.shape[-2] img_cols = input.shape[-1] out_r = 0 out_c = 0 if img_rows - ws[0] >= 0: out_r = (img_rows - ws[0]) // stride[0] + 1 if img_cols - ws[1] >= 0: out_c = (img_cols - ws[1]) // stride[1] + 1 if not ignore_border: if out_r > 0: if img_rows - ((out_r - 1) * stride[0] + ws[0]) > 0: rr = img_rows - out_r * stride[0] if rr > 0: out_r += 1 else: if img_rows > 0: out_r += 1 if out_c > 0: if img_cols - ((out_c - 1) * stride[1] + ws[1]) > 0: cr = img_cols - out_c * stride[1] if cr > 0: out_c += 1 else: if img_cols > 0: out_c += 1 out_shp = list(input.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) func = np.max if mode == "sum": func = np.sum elif mode != "max": func = np.average output_val = np.zeros(out_shp) for k in np.ndindex(*input.shape[:-2]): for i in range(output_val.shape[-2]): ii_stride = i * stride[0] ii_end = builtins.min(ii_stride + ws[0], img_rows) for j in range(output_val.shape[-1]): jj_stride = j * stride[1] jj_end = builtins.min(jj_stride + ws[1], img_cols) patch = input[k][ii_stride:ii_end, jj_stride:jj_end] output_val[k][i, j] = func(patch) return output_val
def numpy_max_pool_2d_stride(input, ds, ignore_border=False, st=None, mode='max'): '''Helper function, implementing pool_2d in pure numpy this function provides st input to indicate the stide size for the pooling regions. if not indicated, st == sd.''' if len(input.shape) < 2: raise NotImplementedError('input should have at least 2 dim,' ' shape is %s' % str(input.shape)) if st is None: st = ds img_rows = input.shape[-2] img_cols = input.shape[-1] out_r = 0 out_c = 0 if img_rows - ds[0] >= 0: out_r = (img_rows - ds[0]) // st[0] + 1 if img_cols - ds[1] >= 0: out_c = (img_cols - ds[1]) // st[1] + 1 if not ignore_border: if out_r > 0: if img_rows - ((out_r - 1) * st[0] + ds[0]) > 0: rr = img_rows - out_r * st[0] if rr > 0: out_r += 1 else: if img_rows > 0: out_r += 1 if out_c > 0: if img_cols - ((out_c - 1) * st[1] + ds[1]) > 0: cr = img_cols - out_c * st[1] if cr > 0: out_c += 1 else: if img_cols > 0: out_c += 1 out_shp = list(input.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average output_val = numpy.zeros(out_shp) for k in numpy.ndindex(*input.shape[:-2]): for i in range(output_val.shape[-2]): ii_st = i * st[0] ii_end = builtins.min(ii_st + ds[0], img_rows) for j in range(output_val.shape[-1]): jj_st = j * st[1] jj_end = builtins.min(jj_st + ds[1], img_cols) patch = input[k][ii_st:ii_end, jj_st:jj_end] output_val[k][i, j] = func(patch) return output_val
def perform(self, node, inp, out): x, = inp z, = out if len(x.shape) != 4: raise NotImplementedError( 'Pool requires 4D input for now') z_shape = self.out_shape(x.shape, self.ds, self.ignore_border, self.st, self.padding, self.index_type) if (z[0] is None) or (z[0].shape != z_shape): z[0] = np.empty(z_shape, dtype=x.dtype) zz = z[0] # number of pooling output rows output_row = zz.shape[-2] # number of pooling output cols output_col = zz.shape[-1] row_downsample, col_downsample = self.ds row_stride, col_stride = self.st pad_height = self.padding[0] pad_width = self.padding[1] input_row = x.shape[-2] + 2 * pad_height input_col = x.shape[-1] + 2 * pad_width input_channels = x.shape[-3] is_global_scope = self.index_scope == 'global' if is_global_scope: scoped_size = (input_row, input_col) else: scoped_size = self.ds # pad the image if self.padding != (0, 0): y = np.zeros( (x.shape[0], x.shape[1], input_row, input_col), dtype=x.dtype) y[:, :, pad_height:(input_row - pad_height), pad_width:(input_col - pad_width)] = x else: y = x for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(output_row): row_start = r * row_stride row_end = builtins.min(row_start + row_downsample, input_row) for c in xrange(output_col): col_start = c * col_stride col_end = builtins.min(col_start + col_downsample, input_col) zz[n, k, r, c] = np.max(x[n, k, row_start:row_end, col_start:col_end]) max_idx = np.argmax(x[n, k, row_start:row_end, col_start:col_end]) local_size = (row_end-row_start, col_end-col_start) max_row, max_col = np.unravel_index(max_idx, local_size) if is_global_scope: max_row += row_start max_col += col_start if self.index_type_int == 0: max_idx = np.ravel_multi_index([max_row, max_col], scoped_size) zz[n, k+input_channels, r, c] = max_idx elif self.index_type_int == 2: zz[n, k+input_channels, r, c] = max_row zz[n, k+2*input_channels, r, c] = max_col
def perform(self, node, inp, out): if self.mode not in ('max', 'sum') and self.padding != (0, 0): raise NotImplementedError() x, maxout, gz = inp gx_stg, = out # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w inc_pad = self.mode == 'average_inc_pad' sum_mode = self.mode == 'sum' # pad the image if self.padding != (0, 0): y = numpy.zeros((x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] = x else: y = x gx = numpy.zeros_like(y) if self.mode == 'max': for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y[n, k, row_ind, col_ind]): gx[n, k, row_ind, col_ind] += gz[n, k, r, c] else: for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): if sum_mode or inc_pad: row_st = r * st0 else: row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): if sum_mode or inc_pad: col_st = c * st1 else: col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) if sum_mode: val = gz[n, k, r, c] else: val = gz[n, k, r, c] / ((row_end - row_st) * (col_end - col_st)) gx[n, k, row_st:row_end, col_st:col_end] += val # unpad the image gx = gx[:, :, pad_h:(img_rows - pad_h), pad_w:(img_cols - pad_w)] gx_stg[0] = gx
def diag(x): input_shape = get_shape(x) x = backend_ops_diag(x) if isinstance(input_shape, (tuple, list)): add_shape(x, (builtins.min(input_shape), )) return x
def perform(self, node, inp, out): if self.mode not in ('max', 'sum') and self.padding != (0, 0): raise NotImplementedError() x, maxout, gz = inp gx_stg, = out # number of pooling output rows pr = maxout.shape[-2] # number of pooling output cols pc = maxout.shape[-1] ds0, ds1 = self.ds st0, st1 = self.st pad_h = self.padding[0] pad_w = self.padding[1] img_rows = x.shape[-2] + 2 * pad_h img_cols = x.shape[-1] + 2 * pad_w inc_pad = self.mode == 'average_inc_pad' sum_mode = self.mode == 'sum' # pad the image if self.padding != (0, 0): y = numpy.zeros( (x.shape[0], x.shape[1], img_rows, img_cols), dtype=x.dtype) y[:, :, pad_h:(img_rows-pad_h), pad_w:(img_cols-pad_w)] = x else: y = x gx = numpy.zeros_like(y) if self.mode == 'max': for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) for row_ind in xrange(row_st, row_end): for col_ind in xrange(col_st, col_end): if (maxout[n, k, r, c] == y[n, k, row_ind, col_ind]): gx[n, k, row_ind, col_ind] += gz[n, k, r, c] else: for n in xrange(x.shape[0]): for k in xrange(x.shape[1]): for r in xrange(pr): if sum_mode or inc_pad: row_st = r * st0 else: row_st = builtins.max(r * st0, self.padding[0]) row_end = builtins.min(row_st + ds0, img_rows) for c in xrange(pc): if sum_mode or inc_pad: col_st = c * st1 else: col_st = builtins.max(c * st1, self.padding[1]) col_end = builtins.min(col_st + ds1, img_cols) if sum_mode: val = gz[n, k, r, c] else: val = gz[n, k, r, c] / ((row_end - row_st) * (col_end - col_st)) gx[n, k, row_st:row_end, col_st:col_end] += val # unpad the image gx = gx[:, :, pad_h:(img_rows-pad_h), pad_w:(img_cols-pad_w)] gx_stg[0] = gx
def numpy_pool_2d_stride_padding( x, ds, ignore_border=True, st=None, padding=(0, 0), mode='max'): assert (ignore_border is False) in_h = x.shape[-2] in_w = x.shape[-1] kernel_h = ds[0] kernel_w = ds[1] stride_h = st[0] stride_w = st[1] pad_h = padding[0] pad_w = padding[1] assert ds[0] > pad_h assert ds[1] > pad_w def pad_img(x): y = numpy.zeros( (x.shape[0], x.shape[1], x.shape[2] + pad_h * 2, x.shape[3] + pad_w * 2), dtype=x.dtype) y[:, :, pad_h:(x.shape[2] + pad_h), pad_w:(x.shape[3] + pad_w)] = x return y h = in_h + 2 * pad_h w = in_w + 2 * pad_w out_h = int(math.ceil((float)(h - kernel_h) / stride_h)) + 1 out_w = int(math.ceil((float)(w - kernel_w) / stride_w)) + 1 out_shp = list(x.shape[:-2]) out_shp.extend([out_h, out_w]) output_val = numpy.zeros(out_shp) y = pad_img(x) func = numpy.max if mode == 'sum': func = numpy.sum elif mode != 'max': func = numpy.average inc_pad = mode == 'average_inc_pad' for k in numpy.ndindex(*x.shape[:-2]): for i in range(output_val.shape[-2]): ii_st = i * st[0] if ii_st > h: print ('ii_st > h!!!') continue ii_end = builtins.min(ii_st + ds[0], h) if not inc_pad: ii_st = builtins.max(ii_st, pad_h) ii_end = builtins.min(ii_end, in_h + pad_h) for j in range(output_val.shape[-1]): jj_st = j * st[1] if jj_st > w: print ('jj_st > w!!!') continue jj_end = builtins.min(jj_st + ds[1], w) if not inc_pad: jj_st = builtins.max(jj_st, pad_w) jj_end = builtins.min(jj_end, in_w + pad_w) patch = y[k][ii_st:ii_end, jj_st:jj_end] output_val[k][i, j] = func(patch) return output_val
def numpy_max_pool_2d_stride_pad(x, ws, ignore_border=True, stride=None, pad=(0, 0), mode="max"): assert ignore_border pad_h = pad[0] pad_w = pad[1] h = x.shape[-2] w = x.shape[-1] assert ws[0] > pad_h assert ws[1] > pad_w def pad_img(x): y = np.zeros( ( x.shape[0], x.shape[1], x.shape[2] + pad_h * 2, x.shape[3] + pad_w * 2, ), dtype=x.dtype, ) y[:, :, pad_h:(x.shape[2] + pad_h), pad_w:(x.shape[3] + pad_w)] = x return y img_rows = h + 2 * pad_h img_cols = w + 2 * pad_w out_r = (img_rows - ws[0]) // stride[0] + 1 out_c = (img_cols - ws[1]) // stride[1] + 1 out_shp = list(x.shape[:-2]) out_shp.append(out_r) out_shp.append(out_c) ws0, ws1 = ws stride0, stride1 = stride output_val = np.zeros(out_shp) y = pad_img(x) func = np.max if mode == "sum": func = np.sum elif mode != "max": func = np.average inc_pad = mode == "average_inc_pad" for k in np.ndindex(*x.shape[:-2]): for i in range(output_val.shape[-2]): ii_stride = i * stride[0] ii_end = builtins.min(ii_stride + ws[0], img_rows) if not inc_pad: ii_stride = builtins.max(ii_stride, pad_h) ii_end = builtins.min(ii_end, h + pad_h) for j in range(output_val.shape[-1]): jj_stride = j * stride[1] jj_end = builtins.min(jj_stride + ws[1], img_cols) if not inc_pad: jj_stride = builtins.max(jj_stride, pad_w) jj_end = builtins.min(jj_end, w + pad_w) patch = y[k][ii_stride:ii_end, jj_stride:jj_end] output_val[k][i, j] = func(patch) return output_val