@@ -1592,6 +1592,57 @@ def sliding_window_transpose( | |||||
return output | return output | ||||
def pad( | |||||
src: Tensor, | |||||
pad_witdth: Tuple[Tuple[int, int], ...], | |||||
mode: str = "CONSTANT", | |||||
constant_value: float = 0.0, | |||||
) -> Tensor: | |||||
""" | |||||
pad | |||||
""" | |||||
p_offsets = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |||||
assert mode in [ | |||||
"constant", | |||||
"CONSTANT", | |||||
"edge", | |||||
"EDGE", | |||||
"replicate", | |||||
"REPLICATE", | |||||
"reflect", | |||||
"REFLECT", | |||||
] | |||||
if mode.lower() == "edge": | |||||
mode = "replicate" | |||||
for i in range(0, len(pad_witdth)): | |||||
p_offsets[i * 2] = pad_witdth[i][0] | |||||
p_offsets[i * 2 + 1] = pad_witdth[i][1] | |||||
op = builtin.Padding( | |||||
front_offset_dim0=p_offsets[0], | |||||
front_offset_dim1=p_offsets[2], | |||||
front_offset_dim2=p_offsets[4], | |||||
front_offset_dim3=p_offsets[6], | |||||
front_offset_dim4=p_offsets[8], | |||||
front_offset_dim5=p_offsets[10], | |||||
front_offset_dim6=p_offsets[12], | |||||
back_offset_dim0=p_offsets[1], | |||||
back_offset_dim1=p_offsets[3], | |||||
back_offset_dim2=p_offsets[5], | |||||
back_offset_dim3=p_offsets[7], | |||||
back_offset_dim4=p_offsets[9], | |||||
back_offset_dim5=p_offsets[11], | |||||
back_offset_dim6=p_offsets[13], | |||||
padding_val=constant_value, | |||||
padding_mode=mode.upper(), | |||||
) | |||||
(output,) = apply(op, src) | |||||
return output | |||||
interpolate = deprecated_func("1.3", "megengine.functional.vision", "interpolate", True) | interpolate = deprecated_func("1.3", "megengine.functional.vision", "interpolate", True) | ||||
roi_pooling = deprecated_func("1.3", "megengine.functional.vision", "roi_pooling", True) | roi_pooling = deprecated_func("1.3", "megengine.functional.vision", "roi_pooling", True) | ||||
roi_align = deprecated_func("1.3", "megengine.functional.vision", "roi_align", True) | roi_align = deprecated_func("1.3", "megengine.functional.vision", "roi_align", True) | ||||
@@ -31,6 +31,7 @@ from .identity import Identity | |||||
from .linear import Linear | from .linear import Linear | ||||
from .module import Module | from .module import Module | ||||
from .normalization import GroupNorm, InstanceNorm, LayerNorm | from .normalization import GroupNorm, InstanceNorm, LayerNorm | ||||
from .padding import Pad | |||||
from .pooling import AvgPool2d, MaxPool2d | from .pooling import AvgPool2d, MaxPool2d | ||||
from .quant_dequant import DequantStub, QuantStub | from .quant_dequant import DequantStub, QuantStub | ||||
from .sequential import Sequential | from .sequential import Sequential | ||||
@@ -0,0 +1,22 @@ | |||||
from typing import Tuple | |||||
from ..functional import nn | |||||
from .module import Module | |||||
class Pad(Module): | |||||
def __init__( | |||||
self, | |||||
pad_witdth: Tuple[Tuple[int, int], ...], | |||||
mode: str = "CONSTANT", | |||||
constant_val: float = 0.0, | |||||
): | |||||
super().__init__() | |||||
self.pad_width = pad_witdth | |||||
self.mode = mode | |||||
self.pad_val = constant_val | |||||
def forward(self, src): | |||||
return nn.pad( | |||||
src, pad_witdth=self.pad_width, mode=self.mode, constant_value=self.pad_val | |||||
) |
@@ -1062,3 +1062,22 @@ def test_sliding_window_transpose(): | |||||
dilation=(dh, dw), | dilation=(dh, dw), | ||||
) | ) | ||||
np.testing.assert_equal(gt_out, out.numpy()) | np.testing.assert_equal(gt_out, out.numpy()) | ||||
def test_pad(): | |||||
src = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float32) | |||||
dst = np.pad(src, ((2, 2), (2, 2)), "constant") | |||||
res = F.nn.pad(tensor(src), ((2, 2), (2, 2)), "CONSTANT") | |||||
np.testing.assert_allclose(res, dst, atol=1e-5) | |||||
dst = np.pad(src, ((2, 2), (2, 2)), "constant", constant_values=3) | |||||
res = F.nn.pad(tensor(src), ((2, 2), (2, 2)), "CONSTANT", constant_value=3) | |||||
np.testing.assert_allclose(res, dst, atol=1e-5) | |||||
dst = np.pad(src, ((2, 2), (2, 2)), "edge") | |||||
res = F.nn.pad(tensor(src), ((2, 2), (2, 2)), "EDGE") | |||||
np.testing.assert_allclose(res, dst, atol=1e-5) | |||||
dst = np.pad(src, ((2, 2), (2, 2)), "reflect") | |||||
res = F.nn.pad(tensor(src), ((2, 2), (2, 2)), "REFLECT") | |||||
np.testing.assert_allclose(res, dst, atol=1e-5) |
@@ -660,4 +660,12 @@ OP_TRAIT_REG(Cumsum, Cumsum).apply_on_var_node(apply_on_var_node).fallback(); | |||||
} // namespace cumsum | } // namespace cumsum | ||||
} // namespace | } // namespace | ||||
namespace padding { | |||||
auto apply_on_var_node(const OpDef& def, const VarNodeArray& inputs) { | |||||
auto&& op = static_cast<const Padding&>(def); | |||||
mgb_assert(inputs.size() == 1); | |||||
return opr::Padding::make(inputs[0], op.param()); | |||||
} | |||||
OP_TRAIT_REG(Padding, Padding).apply_on_var_node(apply_on_var_node).fallback(); | |||||
} // namespace padding | |||||
} // namespace mgb::imperative | } // namespace mgb::imperative |
@@ -389,4 +389,6 @@ def Split: MgbHashableOp<"Split", [EmptyParam]> { | |||||
); | ); | ||||
} | } | ||||
def Padding: MgbHashableOp<"Padding", [PaddingParam]>; | |||||
#endif // MGB_OPS | #endif // MGB_OPS |