# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # pylint: disable=invalid-name, line-too-long, unused-variable, too-many-locals """Space to batch ND in python""" import numpy as np def space_to_batch_nd_python(data, block_shape, pad_before, pad_after, pad_value=0): """Space to Batch operator in python for NHWC layout. Parameters ---------- data : np.ndarray N-D with shape [batch, spatial_shape, remaining_shapes], where spatial_shape has M dimensions. block_shape : list of ints 1-D array of size [M] where M is number of spatial dims, specifies block size for each spatial dimension. pad_before : list of ints list of shape [M] where M is number of spatial dims, specifies zero-padding size before each spatial dimension. pad_after : list of ints list of shape [M] where M is number of spatial dims, specifies zero-padding size after each spatial dimension. pad_value : float, optional the value used for padding. Defaults to 0. Returns ------- s2b_out : np.ndarray N-D with shape [batch * prod(block_shape), padded_data[1] / block_shape[0], ..., padded_data[M] / block_shape[M-1], remaining_shape] """ M = len(block_shape) in_batch = data.shape[0] block_shape_prod = np.prod(block_shape) # Apply padding to input data input_shape = data.shape # Add the paddings for batch and remaining dims paddings = map(list, zip(pad_before, pad_after)) paddings = [[0, 0]] + list(paddings) + [[0, 0]] * (data.ndim - 1 - M) padded_data = np.pad(data, paddings, mode="constant", constant_values=pad_value) padded_shape = padded_data.shape # Get the reshape shape and transpose axes r_shape = [] trans_axis = [] r_shape.append(in_batch) for i in range(1, M + 1): r_shape.append(int(padded_shape[i] // block_shape[i - 1])) r_shape.append(block_shape[i - 1]) trans_axis.append(len(r_shape) - 1) axis_len = len(trans_axis) trans_axis.append(0) for i in range(axis_len): trans_axis.append(trans_axis[i] - 1) out_shape = [] out_shape.append(int(in_batch * block_shape_prod)) for i in range(1, M + 1): out_shape.append(int(padded_shape[i] // block_shape[i - 1])) for i in range(M + 1, len(input_shape)): r_shape.append(input_shape[i]) trans_axis.append(len(r_shape) - 1) out_shape.append(input_shape[i]) s2b_out = np.reshape(padded_data, newshape=r_shape) s2b_out = np.transpose(s2b_out, axes=trans_axis) s2b_out = np.reshape(s2b_out, newshape=out_shape) return s2b_out