diff --git a/python/tfdeploy.py b/python/tfdeploy.py index 79ec925ed53fe50fbd03f4caec7d914f7fe08bdb..a489435f2ed31b5abacb250fd170430f87ad53fa 100644 --- a/python/tfdeploy.py +++ b/python/tfdeploy.py @@ -12,7 +12,7 @@ __credits__ = ["Marcel Rieger"] __contact__ = "https://github.com/riga/tfdeploy" __license__ = "MIT" __status__ = "Development" -__version__ = "0.3.0" +__version__ = "0.3.2" __all__ = ["Model", "Tensor", "Operation", "Ensemble", "UnknownOperationException", "OperationMismatchException", @@ -2081,7 +2081,7 @@ def Softmax(a): # NN convolution ops # -def _conv_patches(a, f, strides, padding, padmode="constant"): +def _prepare_patches(a, f, strides, padding, padmode): v = np.array((0,) + (a.ndim - 2) * (1,) + (0,)) w = np.array((0,) + f.shape[:-2] + (0,)) @@ -2097,6 +2097,12 @@ def _conv_patches(a, f, strides, padding, padmode="constant"): / strides).astype(np.int) pad = np.zeros(len(a.shape)) + return out_shape, src + + +def _conv_patches(a, f, strides, padding): + out_shape, src = _prepare_patches(a, f, strides, padding, "constant") + patches = np.empty(tuple(out_shape)[:-1] + f.shape).astype(a.dtype) s = (slice(None),) @@ -2157,6 +2163,24 @@ def Conv3D(a, f, strides, padding): # NN pooling ops # +def _pool_patches(a, k, strides, padding): + f = np.ones(k[1:] + [a.shape[-1]]) + + out_shape, src = _prepare_patches(a, f, strides, padding, "edge") + + patches = np.empty(tuple(out_shape) + f.shape).astype(a.dtype) + + s = (slice(None),) + e = (Ellipsis,) + en = (Ellipsis, np.newaxis) + for coord in np.ndindex(*out_shape[1:]): + pos = np.array(strides[1:]) * coord + patches[s + coord + e] = \ + src[s + tuple(slice(*tpl) for tpl in zip(pos, pos + f.shape[:-1]))][en] * f + + return patches + + @Operation.factory(attrs=("ksize", "strides", "padding", "data_format")) def AvgPool(a, k, strides, padding, data_format): """ @@ -2165,8 +2189,8 @@ def AvgPool(a, k, strides, padding, data_format): if data_format.decode("ascii") == "NCHW": a = np.rollaxis(a, 1, -1), - patches = _conv_patches(a, np.ones(k[1:] + [1]), strides, padding.decode("ascii"), "edge") - pool = np.average(patches, axis=tuple(range(-len(k), -1))) + patches = _pool_patches(a, k, strides, padding.decode("ascii")) + pool = np.average(patches, axis=tuple(range(-len(k), 0))) if data_format.decode("ascii") == "NCHW": pool = np.rollaxis(pool, -1, 1) @@ -2182,8 +2206,8 @@ def MaxPool(a, k, strides, padding, data_format): if data_format.decode("ascii") == "NCHW": a = np.rollaxis(a, 1, -1), - patches = _conv_patches(a, np.ones(k[1:] + [1]), strides, padding.decode("ascii"), "edge") - pool = np.amax(patches, axis=tuple(range(-len(k), -1))) + patches = _pool_patches(a, k, strides, padding.decode("ascii")) + pool = np.amax(patches, axis=tuple(range(-len(k), 0))) if data_format.decode("ascii") == "NCHW": pool = np.rollaxis(pool, -1, 1) @@ -2196,8 +2220,8 @@ def AvgPool3D(a, k, strides, padding): """ Average 3D pooling op. """ - patches = _conv_patches(a, np.ones(k[1:] + [1]), strides, padding.decode("ascii"), "edge") - return np.average(patches, axis=tuple(range(-len(k), -1))), + patches = _pool_patches(a, k, strides, padding.decode("ascii")) + return np.average(patches, axis=tuple(range(-len(k), 0))), @Operation.factory(attrs=("ksize", "strides", "padding")) @@ -2205,5 +2229,5 @@ def MaxPool3D(a, k, strides, padding): """ Maximum 3D pooling op. """ - patches = _conv_patches(a, np.ones(k[1:] + [1]), strides, padding.decode("ascii"), "edge") - return np.amax(patches, axis=tuple(range(-len(k), -1))), + patches = _pool_patches(a, k, strides, padding.decode("ascii")) + return np.amax(patches, axis=tuple(range(-len(k), 0))),