def infer_shape(self, fgraph, node, in_shapes): shape_a = in_shapes[0] n = node.inputs[1] axis = node.inputs[2] if len(shape_a) == 1: return [(n, )] elif isinstance(axis, TensorConstant): out_shape = (list(shape_a[0:axis.data.item()]) + [n] + list(shape_a[axis.data + 1:])) else: l = len(shape_a) shape_a = stack(shape_a) out_shape = concatenate((shape_a[0:axis], [n], shape_a[axis + 1:])) n_splits = [1] * l out_shape = split(out_shape, n_splits, l) out_shape = [a[0] for a in out_shape] return [out_shape]
def neibs2images(neibs, neib_shape, original_shape, mode="valid"): """ Function :func:`neibs2images <aesara.sandbox.neighbours.neibs2images>` performs the inverse operation of :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>`. It inputs the output of :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>` and reconstructs its input. Parameters ---------- neibs : 2d tensor Like the one obtained by :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>`. neib_shape `neib_shape` that was used in :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>`. original_shape Original shape of the 4d tensor given to :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>` Returns ------- object Reconstructs the input of :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>`, a 4d tensor of shape `original_shape`. Notes ----- Currently, the function doesn't support tensors created with `neib_step` different from default value. This means that it may be impossible to compute the gradient of a variable gained by :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>` w.r.t. its inputs in this case, because it uses :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>` for gradient computation. Examples -------- Example, which uses a tensor gained in example for :func:`images2neibs <aesara.sandbox.neighbours.neibs2images>`: .. code-block:: python im_new = neibs2images(neibs, (5, 5), im_val.shape) # Aesara function definition inv_window = aesara.function([neibs], im_new) # Function application im_new_val = inv_window(neibs_val) .. note:: The code will output the initial image array. """ neibs = as_tensor_variable(neibs) neib_shape = as_tensor_variable(neib_shape) original_shape = as_tensor_variable(original_shape) new_neib_shape = stack( [original_shape[-1] // neib_shape[1], neib_shape[1]]) output_2d = images2neibs(neibs.dimshuffle("x", "x", 0, 1), new_neib_shape, mode=mode) if mode == "ignore_borders": # We use set_subtensor to accept original_shape we can't infer # the shape and still raise error when it don't have the right # shape. valid_shape = original_shape valid_shape = set_subtensor( valid_shape[2], (valid_shape[2] // neib_shape[0]) * neib_shape[0]) valid_shape = set_subtensor( valid_shape[3], (valid_shape[3] // neib_shape[1]) * neib_shape[1]) output_4d = output_2d.reshape(valid_shape, ndim=4) # padding the borders with zeros for d in (2, 3): pad_shape = list(output_4d.shape) pad_shape[d] = original_shape[d] - valid_shape[d] output_4d = concatenate([output_4d, zeros(pad_shape)], axis=d) elif mode == "valid": # TODO: we do not implement all mode with this code. # Add a check for the good cases. output_4d = output_2d.reshape(original_shape, ndim=4) else: raise NotImplementedError(f"neibs2images do not support mode={mode}") return output_4d