diff --git a/docs/developer-guide/operators.md b/docs/developer-guide/operators.md index 43044b6ff..4860bc4e9 100644 --- a/docs/developer-guide/operators.md +++ b/docs/developer-guide/operators.md @@ -865,8 +865,7 @@ y = wrap_packing(x) # Padding ``` -if pads != -233/-234 y = pad(x, pads) -else y = pad(x0, pads param from x1) +y = pad(x, pads) ``` | param id | name | type | default | description | diff --git a/python/src/main.cpp b/python/src/main.cpp index fa33908e2..c42445f99 100644 --- a/python/src/main.cpp +++ b/python/src/main.cpp @@ -214,12 +214,14 @@ PYBIND11_MODULE(ncnn, m) mat = new Mat(shape[0].cast(), shape[1].cast(), elemsize, elempack, allocator); break; case 3: - mat = new Mat(shape[0].cast(), shape[1].cast(), shape[2].cast(), - elemsize, elempack, allocator); + mat = new Mat(shape[0].cast(), shape[1].cast(), shape[2].cast(), elemsize, elempack, allocator); + break; + case 4: + mat = new Mat(shape[0].cast(), shape[1].cast(), shape[2].cast(), shape[3].cast(), elemsize, elempack, allocator); break; default: std::stringstream ss; - ss << "shape must be 1, 2 or 3 dims, not " << shape.size(); + ss << "shape must be 1, 2, 3 or 4 dims, not " << shape.size(); pybind11::pybind11_fail(ss.str()); } return mat; @@ -235,15 +237,18 @@ PYBIND11_MODULE(ncnn, m) .def(py::init(), py::arg("w"), py::arg("h"), py::arg("c"), py::kw_only(), py::arg("elemsize") = 4, py::arg("elempack") = 1, py::arg("allocator") = nullptr) + .def(py::init(), + py::arg("w"), py::arg("h"), py::arg("d"), py::arg("c"), py::kw_only(), + py::arg("elemsize") = 4, py::arg("elempack") = 1, py::arg("allocator") = nullptr) .def(py::init(), py::arg("m")) .def(py::init([](py::buffer const b) { py::buffer_info info = b.request(); - if (info.ndim > 3) + if (info.ndim > 4) { std::stringstream ss; - ss << "convert numpy.ndarray to ncnn.Mat only dims <=3 support now, but given " << info.ndim; + ss << "convert numpy.ndarray to ncnn.Mat only dims <=4 support now, but given " << info.ndim; pybind11::pybind11_fail(ss.str()); } @@ -283,6 +288,15 @@ PYBIND11_MODULE(ncnn, m) // so we set the cstep as numpy's cstep v->cstep = (int)info.shape[2] * (int)info.shape[1]; } + else if (info.ndim == 4) + { + v = new Mat((int)info.shape[3], (int)info.shape[2], (int)info.shape[1], (int)info.shape[0], info.ptr, elemsize); + + // in ncnn, buffer to construct ncnn::Mat need align to ncnn::alignSize + // with (w * h * d elemsize, 16) / elemsize, but the buffer from numpy not + // so we set the cstep as numpy's cstep + v->cstep = (int)info.shape[3] * (int)info.shape[2] * (int)info.shape[1]; + } return v; }), py::arg("array")) @@ -323,6 +337,17 @@ PYBIND11_MODULE(ncnn, m) strides.push_back(m.w * m.elemsize); strides.push_back(m.elemsize); } + else if (m.dims == 4) + { + shape.push_back(m.c); + shape.push_back(m.d); + shape.push_back(m.h); + shape.push_back(m.w); + strides.push_back(m.cstep * m.elemsize); + strides.push_back(m.w * m.h * m.elemsize); + strides.push_back(m.w * m.elemsize); + strides.push_back(m.elemsize); + } return py::buffer_info( m.data, /* Pointer to buffer */ m.elemsize, /* Size of one scalar */ @@ -347,9 +372,11 @@ PYBIND11_MODULE(ncnn, m) return mat.reshape(shape[0].cast(), shape[1].cast(), allocator); case 3: return mat.reshape(shape[0].cast(), shape[1].cast(), shape[2].cast(), allocator); + case 4: + return mat.reshape(shape[0].cast(), shape[1].cast(), shape[2].cast(), shape[3].cast(), allocator); default: std::stringstream ss; - ss << "shape must be 1, 2 or 3 dims, not " << shape.size(); + ss << "shape must be 1, 2, 3 or 4 dims, not " << shape.size(); pybind11::pybind11_fail(ss.str()); } return Mat(); @@ -361,6 +388,8 @@ PYBIND11_MODULE(ncnn, m) py::arg("w"), py::arg("h"), py::kw_only(), py::arg("allocator") = nullptr) .def("reshape", (Mat(Mat::*)(int, int, int, Allocator*) const) & Mat::reshape, py::arg("w"), py::arg("h"), py::arg("c"), py::kw_only(), py::arg("allocator") = nullptr) + .def("reshape", (Mat(Mat::*)(int, int, int, int, Allocator*) const) & Mat::reshape, + py::arg("w"), py::arg("h"), py::arg("d"), py::arg("c"), py::kw_only(), py::arg("allocator") = nullptr) .def( "create", @@ -372,11 +401,12 @@ PYBIND11_MODULE(ncnn, m) case 2: return mat.create(shape[0].cast(), shape[1].cast(), elemsize, elempack, allocator); case 3: - return mat.create(shape[0].cast(), shape[1].cast(), shape[2].cast(), - elemsize, elempack, allocator); + return mat.create(shape[0].cast(), shape[1].cast(), shape[2].cast(), elemsize, elempack, allocator); + case 4: + return mat.create(shape[0].cast(), shape[1].cast(), shape[2].cast(), shape[3].cast(), elemsize, elempack, allocator); default: std::stringstream ss; - ss << "shape must be 1, 2 or 3 dims, not " << shape.size(); + ss << "shape must be 1, 2, 3 or 4 dims, not " << shape.size(); pybind11::pybind11_fail(ss.str()); } return; @@ -393,6 +423,9 @@ PYBIND11_MODULE(ncnn, m) .def("create", (void (Mat::*)(int, int, int, size_t, int, Allocator*)) & Mat::create, py::arg("w"), py::arg("h"), py::arg("c"), py::kw_only(), py::arg("elemsize") = 4, py::arg("elempack") = 1, py::arg("allocator") = nullptr) + .def("create", (void (Mat::*)(int, int, int, int, size_t, int, Allocator*)) & Mat::create, + py::arg("w"), py::arg("h"), py::arg("d"), py::arg("c"), py::kw_only(), + py::arg("elemsize") = 4, py::arg("elempack") = 1, py::arg("allocator") = nullptr) .def("create_like", (void (Mat::*)(const Mat&, Allocator*)) & Mat::create_like, py::arg("m"), py::arg("allocator") = nullptr) .def("addref", &Mat::addref) @@ -403,6 +436,8 @@ PYBIND11_MODULE(ncnn, m) .def("shape", &Mat::shape) .def("channel", (Mat(Mat::*)(int)) & Mat::channel, py::arg("c")) //.def("channel", (const Mat (Mat::*)(int) const) & Mat::channel, py::arg("c")) + .def("depth", (Mat(Mat::*)(int)) & Mat::depth, py::arg("z")) + //.def("depth", (const Mat (Mat::*)(int) const) & Mat::depth, py::arg("z")) .def( "row", [](Mat& m, int y) { @@ -431,6 +466,8 @@ PYBIND11_MODULE(ncnn, m) py::arg("y")) .def("channel_range", (Mat(Mat::*)(int, int)) & Mat::channel_range, py::arg("c"), py::arg("channels")) //.def("channel_range", (const Mat (Mat::*)(int, int) const) & Mat::channel_range, py::arg("c"), py::arg("channels")) + .def("depth_range", (Mat(Mat::*)(int, int)) & Mat::depth_range, py::arg("z"), py::arg("depths")) + //.def("depth_range", (const Mat (Mat::*)(int, int) const) & Mat::depth_range, py::arg("z"), py::arg("depths")) .def("row_range", (Mat(Mat::*)(int, int)) & Mat::row_range, py::arg("y"), py::arg("rows")) //.def("row_range", (const Mat (Mat::*)(int, int) const) & Mat::row_range, py::arg("y"), py::arg("rows")) .def("range", (Mat(Mat::*)(int, int)) & Mat::range, py::arg("x"), py::arg("n")) @@ -508,11 +545,12 @@ PYBIND11_MODULE(ncnn, m) .def_readwrite("dims", &Mat::dims) .def_readwrite("w", &Mat::w) .def_readwrite("h", &Mat::h) + .def_readwrite("d", &Mat::d) .def_readwrite("c", &Mat::c) .def_readwrite("cstep", &Mat::cstep) .def("__repr__", [](const Mat& m) { std::stringstream ss; - ss << "(m.data) << " allocator=0x" << static_cast(m.allocator) << ">\n"; @@ -720,6 +758,119 @@ PYBIND11_MODULE(ncnn, m) } // for k ss << "]\n"; } + else if (m.dims == 4) + { + bool dot_printed_c = false; + ss << "["; + for (int k = 0; k < m.c; k++) + { + bool dot_printed_d = false; + if (k < max_count / 2 || k >= m.c - max_count / 2) + { + Mat channel = m.channel(k); + if (k > 0) + { + ss << " "; + } + ss << "["; + for (int z = 0; z < channel.d; z++) + { + bool dot_printed_h = false; + if (z < max_count / 2 || z >= channel.d - max_count / 2) + { + if (z > 0) + { + ss << " "; + } + ss << "["; + for (int j = 0; j < channel.h; j++) + { + bool dot_printed_w = false; + if (j < max_count / 2 || j >= channel.h - max_count / 2) + { + if (j > 0) + { + ss << " "; + } + ss << "["; + if (m.elemsize == 1) + { + const int8_t* row = channel.depth(z).row(j); + for (int i = 0; i < channel.w; i++) + { + if (i < max_count / 2 || i >= channel.w - max_count / 2) + { + if (i > 0) + { + ss << ", "; + } + ss << static_cast(row[i]); + } + else if (!dot_printed_w) + { + dot_printed_w = true; + ss << ", ..."; + } + } + } + if (m.elemsize == 4) + { + const float* row = channel.depth(z).row(j); + for (int i = 0; i < m.w; i++) + { + if (i < max_count / 2 || i >= m.w - max_count / 2) + { + if (i > 0) + { + ss << ", "; + } + ss << row[i]; + } + else if (!dot_printed_w) + { + dot_printed_w = true; + ss << ", ..."; + } + } + } + ss << "]"; + if (j < channel.h - 1) + { + ss << "\n"; + } + } + else if (!dot_printed_h) + { + dot_printed_h = true; + ss << " ...\n"; + } + } // for j + ss << "]"; + if (z < channel.d - 1) + { + ss << "\n"; + } + } + else if (!dot_printed_d) + { + dot_printed_d = true; + ss << " ...\n"; + } + } // for z + ss << "]"; + if (k < m.c - 1) + { + ss << "\n\n"; + } + } + else if (!dot_printed_c) + { + dot_printed_c = true; + ss << " ...\n"; + } + } // for k + ss << "]\n"; + } return ss.str(); }); @@ -932,6 +1083,21 @@ PYBIND11_MODULE(ncnn, m) py::arg("top"), py::arg("bottom"), py::arg("left"), py::arg("right"), py::arg("type"), py::arg("v"), py::arg("opt") = Option()); + m.def("copy_make_border_3d", ©_make_border_3d, + py::arg("src"), py::arg("dst"), + py::arg("top"), py::arg("bottom"), py::arg("left"), py::arg("right"), py::arg("front"), py::arg("behind"), + py::arg("type"), py::arg("v"), py::arg("opt") = Option()); + m.def( + "copy_make_border_3d", + [](const Mat& src, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt) { + Mat dst; + copy_make_border_3d(src, dst, top, bottom, left, right, front, behind, type, v, opt); + return dst; + }, + py::arg("src"), + py::arg("top"), py::arg("bottom"), py::arg("left"), py::arg("right"), py::arg("front"), py::arg("behind"), + py::arg("type"), py::arg("v"), py::arg("opt") = Option()); + m.def("copy_cut_border", ©_cut_border, py::arg("src"), py::arg("dst"), py::arg("top"), py::arg("bottom"), py::arg("left"), py::arg("right"), diff --git a/python/tests/test_mat.py b/python/tests/test_mat.py index adc566dd5..605d59c39 100644 --- a/python/tests/test_mat.py +++ b/python/tests/test_mat.py @@ -151,6 +151,64 @@ def test_mat_dims3(): ) +def test_mat_dims4(): + mat = ncnn.Mat(1, 2, 3, 4) + assert mat.dims == 4 and mat.w == 1 and mat.h == 2 and mat.d == 3 and mat.c == 4 + mat = ncnn.Mat(4, 5, 6, 7, elemsize=4) + assert ( + mat.dims == 4 and mat.w == 4 and mat.h == 5 and mat.d == 6 and mat.c == 7 and mat.elemsize == 4 + ) + mat = ncnn.Mat(7, 8, 9, 10, elemsize=4, elempack=1) + assert ( + mat.dims == 4 + and mat.w == 7 + and mat.h == 8 + and mat.d == 9 + and mat.c == 10 + and mat.elemsize == 4 + and mat.elempack == 1 + ) + mat = ncnn.Mat(10, 11, 12, 13, elemsize=4, elempack=1, allocator=None) + assert ( + mat.dims == 4 + and mat.w == 10 + and mat.h == 11 + and mat.d == 12 + and mat.c == 13 + and mat.elemsize == 4 + and mat.elempack == 1 + and mat.allocator == None + ) + + mat = ncnn.Mat((1, 2, 3, 4)) + assert mat.dims == 4 and mat.w == 1 and mat.h == 2 and mat.d == 3 and mat.c == 4 + mat = ncnn.Mat((4, 5, 6, 7), elemsize=4) + assert ( + mat.dims == 4 and mat.w == 4 and mat.h == 5 and mat.d == 6 and mat.c == 7 and mat.elemsize == 4 + ) + mat = ncnn.Mat((7, 8, 9, 10), elemsize=4, elempack=1) + assert ( + mat.dims == 4 + and mat.w == 7 + and mat.h == 8 + and mat.d == 9 + and mat.c == 10 + and mat.elemsize == 4 + and mat.elempack == 1 + ) + mat = ncnn.Mat((10, 11, 12, 13), elemsize=4, elempack=1, allocator=None) + assert ( + mat.dims == 4 + and mat.w == 10 + and mat.h == 11 + and mat.d == 12 + and mat.c == 13 + and mat.elemsize == 4 + and mat.elempack == 1 + and mat.allocator == None + ) + + def test_numpy(): mat = ncnn.Mat(1) array = np.array(mat) @@ -168,6 +226,15 @@ def test_numpy(): and mat.h == array.shape[1] and mat.c == array.shape[0] ) + mat = ncnn.Mat(7, 8, 9, 10) + array = np.array(mat) + assert ( + mat.dims == array.ndim + and mat.w == array.shape[3] + and mat.h == array.shape[2] + and mat.d == array.shape[1] + and mat.c == array.shape[0] + ) mat = ncnn.Mat(1, elemsize=1) array = np.array(mat) @@ -205,6 +272,12 @@ def test_numpy(): mat = np.random.rand(12, 11, 3).astype(np.float32) array = np.array(mat) assert (mat == array).all() + mat = np.random.randint(0, 256, size=(12, 11, 7, 3)).astype(np.uint8) + array = np.array(mat) + assert (mat == array).all() + mat = np.random.rand(12, 11, 7, 3).astype(np.float32) + array = np.array(mat) + assert (mat == array).all() def test_fill(): @@ -232,6 +305,16 @@ def test_clone(): and mat1.c == mat2.c ) + mat1 = ncnn.Mat(7, 8, 9, 10) + mat2 = mat1.clone() + assert ( + mat1.dims == mat2.dims + and mat1.w == mat2.w + and mat1.h == mat2.h + and mat1.d == mat2.d + and mat1.c == mat2.c + ) + mat1 = ncnn.Mat((1,)) mat2 = mat1.clone() assert mat1.dims == mat2.dims and mat1.w == mat2.w @@ -249,6 +332,16 @@ def test_clone(): and mat1.c == mat2.c ) + mat1 = ncnn.Mat((7, 8, 9, 10)) + mat2 = mat1.clone() + assert ( + mat1.dims == mat2.dims + and mat1.w == mat2.w + and mat1.h == mat2.h + and mat1.d == mat2.d + and mat1.c == mat2.c + ) + def test_clone_from(): mat2 = ncnn.Mat() @@ -270,6 +363,16 @@ def test_clone_from(): and mat1.c == mat2.c ) + mat1 = ncnn.Mat(7, 8, 9, 10) + mat2.clone_from(mat1) + assert ( + mat1.dims == mat2.dims + and mat1.w == mat2.w + and mat1.h == mat2.h + and mat1.d == mat2.d + and mat1.c == mat2.c + ) + mat1 = ncnn.Mat((1,)) mat2.clone_from(mat1) assert mat1.dims == mat2.dims and mat1.w == mat2.w @@ -287,6 +390,16 @@ def test_clone_from(): and mat1.c == mat2.c ) + mat1 = ncnn.Mat((7, 8, 9, 10)) + mat2.clone_from(mat1) + assert ( + mat1.dims == mat2.dims + and mat1.w == mat2.w + and mat1.h == mat2.h + and mat1.d == mat2.d + and mat1.c == mat2.c + ) + def test_reshape(): mat1 = ncnn.Mat() @@ -296,12 +409,16 @@ def test_reshape(): assert mat2.dims == 0 mat2 = mat1.reshape(1, 1, 1) assert mat2.dims == 0 + mat2 = mat1.reshape(1, 1, 1, 1) + assert mat2.dims == 0 mat1 = ncnn.Mat(1) mat2 = mat1.reshape(1, 1) assert mat2.dims == 2 and mat2.w == 1 and mat2.h == 1 mat2 = mat1.reshape(1, 1, 1) assert mat2.dims == 3 and mat2.w == 1 and mat2.h == 1 and mat2.c == 1 + mat2 = mat1.reshape(1, 1, 1, 1) + assert mat2.dims == 4 and mat2.w == 1 and mat2.h == 1 and mat2.d == 1 and mat2.c == 1 mat1 = ncnn.Mat(1, 2) mat2 = mat1.reshape(2) @@ -310,6 +427,8 @@ def test_reshape(): assert mat2.dims == 2 and mat2.w == 2 and mat2.h == 1 mat2 = mat1.reshape(2, 1, 1) assert mat2.dims == 3 and mat2.w == 2 and mat2.h == 1 and mat2.c == 1 + mat2 = mat1.reshape(2, 1, 1, 1) + assert mat2.dims == 4 and mat2.w == 2 and mat2.h == 1 and mat2.d == 1 and mat2.c == 1 mat1 = ncnn.Mat(1, 2, 3) mat2 = mat1.reshape(6) @@ -318,12 +437,16 @@ def test_reshape(): assert mat2.dims == 2 and mat2.w == 2 and mat2.h == 3 mat2 = mat1.reshape(2, 3, 1) assert mat2.dims == 3 and mat2.w == 2 and mat2.h == 3 and mat2.c == 1 + mat2 = mat1.reshape(2, 1, 3, 1) + assert mat2.dims == 4 and mat2.w == 2 and mat2.h == 1 and mat2.d == 3 and mat2.c == 1 mat1 = ncnn.Mat((1,)) mat2 = mat1.reshape((1, 1)) assert mat2.dims == 2 and mat2.w == 1 and mat2.h == 1 mat2 = mat1.reshape((1, 1, 1)) assert mat2.dims == 3 and mat2.w == 1 and mat2.h == 1 and mat2.c == 1 + mat2 = mat1.reshape((1, 1, 1, 1)) + assert mat2.dims == 4 and mat2.w == 1 and mat2.h == 1 and mat2.d == 1 and mat2.c == 1 mat1 = ncnn.Mat((1, 2)) mat2 = mat1.reshape((2,)) @@ -332,6 +455,8 @@ def test_reshape(): assert mat2.dims == 2 and mat2.w == 2 and mat2.h == 1 mat2 = mat1.reshape((2, 1, 1)) assert mat2.dims == 3 and mat2.w == 2 and mat2.h == 1 and mat2.c == 1 + mat2 = mat1.reshape((2, 1, 1, 1)) + assert mat2.dims == 4 and mat2.w == 2 and mat2.h == 1 and mat2.d == 1 and mat2.c == 1 mat1 = ncnn.Mat((1, 2, 3)) mat2 = mat1.reshape((6,)) @@ -340,9 +465,12 @@ def test_reshape(): assert mat2.dims == 2 and mat2.w == 2 and mat2.h == 3 and mat2.c == 1 mat2 = mat1.reshape((2, 3, 1)) assert mat2.dims == 3 and mat2.w == 2 and mat2.h == 3 and mat2.c == 1 + mat2 = mat1.reshape((2, 1, 3, 1)) + assert mat2.dims == 4 and mat2.w == 2 and mat2.h == 1 and mat2.d == 3 and mat2.c == 1 + with pytest.raises(RuntimeError) as execinfo: - mat1.reshape((1, 1, 1, 1)) - assert "shape must be 1, 2 or 3 dims, not 4" in str(execinfo.value) + mat1.reshape((1, 1, 1, 1, 1)) + assert "shape must be 1, 2, 3 or 4 dims, not 5" in str(execinfo.value) def test_create(): @@ -353,6 +481,8 @@ def test_create(): assert mat.dims == 2 and mat.w == 2 and mat.h == 3 mat.create(4, 5, 6) assert mat.dims == 3 and mat.w == 4 and mat.h == 5 and mat.c == 6 + mat.create(7, 8, 9, 10) + assert mat.dims == 4 and mat.w == 7 and mat.h == 8 and mat.d == 9 and mat.c == 10 mat.create((1,)) assert mat.dims == 1 and mat.w == 1 @@ -360,7 +490,8 @@ def test_create(): assert mat.dims == 2 and mat.w == 2 and mat.h == 3 mat.create((4, 5, 6)) assert mat.dims == 3 and mat.w == 4 and mat.h == 5 and mat.c == 6 - mat.create((7, 8, 9), elemsize=4) + mat.create((7, 8, 9, 10)) + assert mat.dims == 4 and mat.w == 7 and mat.h == 8 and mat.d == 9 and mat.c == 10 def test_create_like(): @@ -380,6 +511,15 @@ def test_create_like(): and mat1.h == mat2.h and mat1.c == mat2.c ) + mat1 = ncnn.Mat(7, 8, 9, 10) + mat2.create_like(mat1) + assert ( + mat1.dims == mat2.dims + and mat1.w == mat2.w + and mat1.h == mat2.h + and mat1.d == mat2.d + and mat1.c == mat2.c + ) def test_addref_release(): @@ -408,6 +548,8 @@ def test_total(): assert mat.total() == 2 * 3 mat = ncnn.Mat(4, 5, 6) assert mat.total() == 4 * 5 * 6 + mat = ncnn.Mat(7, 8, 9, 10) + assert mat.total() == 7 * 8 * 9 * 10 def test_elembits(): @@ -429,6 +571,22 @@ def test_shape(): mat = ncnn.Mat(4, 5, 6) shape = mat.shape() assert shape.dims == 3 and shape.w == 4 and shape.h == 5 and shape.c == 6 + mat = ncnn.Mat(7, 8, 9, 10) + shape = mat.shape() + assert shape.dims == 4 and shape.w == 7 and shape.h == 8 and shape.d == 9 and shape.c == 10 + + +def test_channel_depth_row(): + mat = ncnn.Mat(2, 3, 4, 5) + mat.fill(6.0) + channel = mat.channel(1) + assert channel.dims == 3 and channel.w == 2 and channel.h == 3 and channel.c == 4 + + depth = channel.depth(1) + assert depth.dims == 2 and depth.w == 2 and depth.h == 3 + + row = depth.row(1) + assert len(row) == 2 and np.abs(row[0] - 6.0) < sys.float_info.min def test_channel_row(): @@ -452,6 +610,17 @@ def test_channel_range(): ) +def test_depth_range(): + mat = ncnn.Mat(1, 2, 3, 4) + depth_range = mat.channel(1).depth_range(1, 2) + assert ( + depth_range.dims == 3 + and depth_range.w == 1 + and depth_range.h == 2 + and depth_range.c == 2 + ) + + def test_row_range(): mat = ncnn.Mat(1, 2) row_range = mat.row_range(0, 2) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 75ac4e56d..f2c3f6e2c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -146,6 +146,9 @@ ncnn_add_layer(GELU) ncnn_add_layer(Convolution1D) ncnn_add_layer(Pooling1D) ncnn_add_layer(ConvolutionDepthWise1D) +ncnn_add_layer(Convolution3D) +ncnn_add_layer(ConvolutionDepthWise3D) +ncnn_add_layer(Pooling3D) if(NCNN_VULKAN) ncnn_add_shader(${CMAKE_CURRENT_SOURCE_DIR}/convert_ycbcr.comp) diff --git a/src/command.cpp b/src/command.cpp index fedf7db9d..91a22dd48 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -401,7 +401,7 @@ void VkCompute::record_upload(const Mat& src, VkMat& dst, const Option& opt) int elemcount = 0; if (dims == 1) elemcount = src_fp16.elempack * src_fp16.w; if (dims == 2) elemcount = src_fp16.elempack * src_fp16.h; - if (dims == 3) elemcount = src_fp16.elempack * src_fp16.c; + if (dims == 3 || dims == 4) elemcount = src_fp16.elempack * src_fp16.c; int dst_elempack = 1; if (opt.use_shader_pack8) @@ -457,7 +457,7 @@ void VkCompute::record_upload(const Mat& src, VkImageMat& dst, const Option& opt int elemcount = 0; if (dims == 1) elemcount = src_fp16.elempack * src_fp16.w; if (dims == 2) elemcount = src_fp16.elempack * src_fp16.h; - if (dims == 3) elemcount = src_fp16.elempack * src_fp16.c; + if (dims == 3 || dims == 4) elemcount = src_fp16.elempack * src_fp16.c; int dst_elempack = 1; if (opt.use_shader_pack8) @@ -498,7 +498,7 @@ void VkCompute::record_download(const VkMat& src, Mat& dst, const Option& opt) int elemcount = 0; if (dims == 1) elemcount = src.elempack * src.w; if (dims == 2) elemcount = src.elempack * src.h; - if (dims == 3) elemcount = src.elempack * src.c; + if (dims == 3 || dims == 4) elemcount = src.elempack * src.c; int dst_elempack = 1; if (opt.use_packing_layout) @@ -592,6 +592,8 @@ void VkCompute::record_download(const VkMat& src, Mat& dst, const Option& opt) dst.create(dst_fp16.w, dst_fp16.h, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); if (dims == 3) dst.create(dst_fp16.w, dst_fp16.h, dst_fp16.c, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); + if (dims == 4) + dst.create(dst_fp16.w, dst_fp16.h, dst_fp16.d, dst_fp16.c, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); d->download_post_mats.push_back(dst); @@ -623,7 +625,7 @@ void VkCompute::record_download(const VkImageMat& src, Mat& dst, const Option& o int elemcount = 0; if (dims == 1) elemcount = src.elempack * src.w; if (dims == 2) elemcount = src.elempack * src.h; - if (dims == 3) elemcount = src.elempack * src.c; + if (dims == 3 || dims == 4) elemcount = src.elempack * src.c; int dst_elempack = 1; if (opt.use_packing_layout) @@ -737,6 +739,8 @@ void VkCompute::record_download(const VkImageMat& src, Mat& dst, const Option& o dst.create(dst_fp16.w, dst_fp16.h, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); if (dims == 3) dst.create(dst_fp16.w, dst_fp16.h, dst_fp16.c, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); + if (dims == 4) + dst.create(dst_fp16.w, dst_fp16.h, dst_fp16.d, dst_fp16.c, (size_t)(dst_fp16.elempack * 4u), dst_fp16.elempack, opt.blob_allocator); d->download_post_mats.push_back(dst); @@ -768,7 +772,7 @@ void VkCompute::record_buffer_to_image(const VkMat& src, VkImageMat& dst, const int elemcount = 0; if (dims == 1) elemcount = src.elempack * src.w; if (dims == 2) elemcount = src.elempack * src.h; - if (dims == 3) elemcount = src.elempack * src.c; + if (dims == 3 || dims == 4) elemcount = src.elempack * src.c; int dst_elempack = 1; if (opt.use_shader_pack8) @@ -805,7 +809,7 @@ void VkCompute::record_image_to_buffer(const VkImageMat& src, VkMat& dst, const int elemcount = 0; if (dims == 1) elemcount = src.elempack * src.w; if (dims == 2) elemcount = src.elempack * src.h; - if (dims == 3) elemcount = src.elempack * src.c; + if (dims == 3 || dims == 4) elemcount = src.elempack * src.c; int dst_elempack = 1; if (opt.use_shader_pack8) @@ -1501,14 +1505,14 @@ void VkCompute::record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkMat& dispatcher) { - Mat dispatcher_mat(dispatcher.w, dispatcher.h, dispatcher.c, (void*)0); + Mat dispatcher_mat(dispatcher.w, dispatcher.h, dispatcher.d, dispatcher.c, (void*)0); record_pipeline(pipeline, buffer_bindings, image_bindings, constants, dispatcher_mat); } void VkCompute::record_pipeline(const Pipeline* pipeline, const std::vector& buffer_bindings, const std::vector& image_bindings, const std::vector& constants, const VkImageMat& dispatcher) { - Mat dispatcher_mat(dispatcher.w, dispatcher.h, dispatcher.c, (void*)0); + Mat dispatcher_mat(dispatcher.w, dispatcher.h, dispatcher.d, dispatcher.c, (void*)0); record_pipeline(pipeline, buffer_bindings, image_bindings, constants, dispatcher_mat); } @@ -1808,7 +1812,7 @@ void VkCompute::record_pipeline(const Pipeline* pipeline, const std::vectorlocal_size_x() - 1) / pipeline->local_size_x(); - uint32_t group_count_y = (dispatcher.h + pipeline->local_size_y() - 1) / pipeline->local_size_y(); + uint32_t group_count_y = (dispatcher.h * (dispatcher.d ? dispatcher.d : 1) + pipeline->local_size_y() - 1) / pipeline->local_size_y(); uint32_t group_count_z = (dispatcher.c + pipeline->local_size_z() - 1) / pipeline->local_size_z(); if (vkdev->info.support_VK_KHR_push_descriptor()) diff --git a/src/layer/arm/cast_arm.cpp b/src/layer/arm/cast_arm.cpp index 8f3d90368..439b9cba3 100644 --- a/src/layer/arm/cast_arm.cpp +++ b/src/layer/arm/cast_arm.cpp @@ -44,6 +44,7 @@ int Cast_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -96,10 +97,14 @@ int Cast_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_allocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_allocator); + } if (top_blob.empty()) return -100; - int size = w * h * elempack; + int size = w * h * d * elempack; #if (__ARM_FP & 2) if (type_from == 1 && type_to == 2) diff --git a/src/layer/arm/convolution_3x3_int8.h b/src/layer/arm/convolution_3x3_int8.h index 54e43b771..efe42fdb6 100644 --- a/src/layer/arm/convolution_3x3_int8.h +++ b/src/layer/arm/convolution_3x3_int8.h @@ -18,7 +18,7 @@ static void conv3x3s1_winograd23_transform_kernel_int8_neon(const Mat& kernel, std::vector& kernel_tm2, int inch, int outch, const Option& opt) { - Mat kernel_tm(4 * 4, inch, outch, 2ul); + Mat kernel_tm(4 * 4, inch, outch, (size_t)2u); // G const short ktm[4][3] = { @@ -65,7 +65,7 @@ static void conv3x3s1_winograd23_transform_kernel_int8_neon(const Mat& kernel, s for (int r = 0; r < 4; r++) { - Mat kernel_tm_test(4 * 8, inch, outch / 8 + (outch % 8) / 4 + outch % 4, 2u); + Mat kernel_tm_test(4 * 8, inch, outch / 8 + (outch % 8) / 4 + outch % 4, (size_t)2u); int p = 0; for (; p + 7 < outch; p += 8) @@ -1061,7 +1061,7 @@ static void conv3x3s1_winograd23_int8_neon(const Mat& bottom_blob, Mat& top_blob static void conv3x3s1_winograd43_transform_kernel_int8_neon(const Mat& kernel, std::vector& kernel_tm2, int inch, int outch, const Option& opt) { - Mat kernel_tm(6 * 6, inch, outch, 2ul); + Mat kernel_tm(6 * 6, inch, outch, (size_t)2u); // G // const float ktm[6][3] = { @@ -1118,7 +1118,7 @@ static void conv3x3s1_winograd43_transform_kernel_int8_neon(const Mat& kernel, s for (int r = 0; r < 9; r++) { - Mat kernel_tm_test(4 * 8, inch, outch / 8 + (outch % 8) / 4 + outch % 4, 2u); + Mat kernel_tm_test(4 * 8, inch, outch / 8 + (outch % 8) / 4 + outch % 4, (size_t)2u); int p = 0; for (; p + 7 < outch; p += 8) diff --git a/src/layer/arm/convolution_3x3_pack8to1_int8.h b/src/layer/arm/convolution_3x3_pack8to1_int8.h index 46572be3a..4e9647ab3 100644 --- a/src/layer/arm/convolution_3x3_pack8to1_int8.h +++ b/src/layer/arm/convolution_3x3_pack8to1_int8.h @@ -15,7 +15,7 @@ static void conv3x3s1_winograd42_transform_kernel_pack8to1_int8_neon(const Mat& kernel, Mat& kernel_tm_pack8to1, int inch, int outch, const Option& opt) { // winograd42 transform kernel - Mat kernel_tm(6 * 6, inch, outch, 2u); + Mat kernel_tm(6 * 6, inch, outch, (size_t)2u); const short ktm[6][3] = { {6, 0, 0}, diff --git a/src/layer/arm/convolution_3x3_pack8to4_int8.h b/src/layer/arm/convolution_3x3_pack8to4_int8.h index b8f83d4e6..7005ec416 100644 --- a/src/layer/arm/convolution_3x3_pack8to4_int8.h +++ b/src/layer/arm/convolution_3x3_pack8to4_int8.h @@ -15,7 +15,7 @@ static void conv3x3s1_winograd42_transform_kernel_pack8to4_int8_neon(const Mat& kernel, Mat& kernel_tm_pack8, int inch, int outch, const Option& opt) { // winograd42 transform kernel - Mat kernel_tm(6 * 6, inch, outch, 2u); + Mat kernel_tm(6 * 6, inch, outch, (size_t)2u); const short ktm[6][3] = { {6, 0, 0}, diff --git a/src/layer/arm/convolution_sgemm_int8.h b/src/layer/arm/convolution_sgemm_int8.h index 173423915..9f130f76e 100644 --- a/src/layer/arm/convolution_sgemm_int8.h +++ b/src/layer/arm/convolution_sgemm_int8.h @@ -3287,20 +3287,20 @@ static void convolution_im2col_sgemm_transform_kernel_int8_neon(const Mat& _kern if (outch >= 4) { if (inch >= 8) - kernel_tm.create(32 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch / 4 + outch % 4, 1u); + kernel_tm.create(32 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch / 4 + outch % 4, (size_t)1u); else if (inch >= 4) - kernel_tm.create(16 * maxk, inch / 4 + inch % 4, outch / 4 + outch % 4, 1u); + kernel_tm.create(16 * maxk, inch / 4 + inch % 4, outch / 4 + outch % 4, (size_t)1u); else - kernel_tm.create(4 * maxk, inch, outch / 4 + outch % 4, 1u); + kernel_tm.create(4 * maxk, inch, outch / 4 + outch % 4, (size_t)1u); } else { if (inch >= 8) - kernel_tm.create(8 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch, 1u); + kernel_tm.create(8 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch, (size_t)1u); else if (inch >= 4) - kernel_tm.create(4 * maxk, inch / 4 + inch % 4, outch, 1u); + kernel_tm.create(4 * maxk, inch / 4 + inch % 4, outch, (size_t)1u); else - kernel_tm.create(1 * maxk, inch, outch, 1u); + kernel_tm.create(1 * maxk, inch, outch, (size_t)1u); } int q = 0; diff --git a/src/layer/arm/convolution_sgemm_pack1to4_int8.h b/src/layer/arm/convolution_sgemm_pack1to4_int8.h index 0d459f18c..cd1cc8dd1 100644 --- a/src/layer/arm/convolution_sgemm_pack1to4_int8.h +++ b/src/layer/arm/convolution_sgemm_pack1to4_int8.h @@ -2432,11 +2432,11 @@ static void convolution_im2col_sgemm_transform_kernel_pack1to4_int8_neon(const M // dst = 4a-4b-2-maxk-inch/8a-outch/4b (arm82) Mat kernel = _kernel.reshape(maxk, inch, outch); if (inch >= 8) - kernel_tm.create(32 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch / 4, 1u); + kernel_tm.create(32 * maxk, inch / 8 + (inch % 8) / 4 + inch % 4, outch / 4, (size_t)1u); if (inch >= 4) - kernel_tm.create(16 * maxk, inch / 4 + inch % 4, outch / 4, 1u); + kernel_tm.create(16 * maxk, inch / 4 + inch % 4, outch / 4, (size_t)1u); else - kernel_tm.create(4 * maxk, inch, outch / 4, 1u); + kernel_tm.create(4 * maxk, inch, outch / 4, (size_t)1u); for (int q = 0; q + 3 < outch; q += 4) { diff --git a/src/layer/arm/convolution_sgemm_pack4_bf16s.h b/src/layer/arm/convolution_sgemm_pack4_bf16s.h index f6e0447c6..f9c495872 100644 --- a/src/layer/arm/convolution_sgemm_pack4_bf16s.h +++ b/src/layer/arm/convolution_sgemm_pack4_bf16s.h @@ -1732,9 +1732,9 @@ static void convolution_im2col_sgemm_transform_kernel_pack4_bf16s_neon(const Mat // dst = 4b-4a-maxk-inch/4a-outch/4b Mat kernel = _kernel.reshape(maxk, inch, outch); #if __aarch64__ - kernel_tm.create(32 * maxk, inch / 4, outch / 8 + (outch % 8) / 4, 2u); + kernel_tm.create(32 * maxk, inch / 4, outch / 8 + (outch % 8) / 4, (size_t)2u); #else - kernel_tm.create(16 * maxk, inch / 4, outch / 4, 2u); + kernel_tm.create(16 * maxk, inch / 4, outch / 4, (size_t)2u); #endif int q = 0; diff --git a/src/layer/arm/convolution_sgemm_pack8_fp16s.h b/src/layer/arm/convolution_sgemm_pack8_fp16s.h index 930b6170c..75b465368 100644 --- a/src/layer/arm/convolution_sgemm_pack8_fp16s.h +++ b/src/layer/arm/convolution_sgemm_pack8_fp16s.h @@ -716,7 +716,7 @@ static void convolution_im2col_sgemm_transform_kernel_pack8_fp16sa_neon(const Ma // src = maxk-inch-outch // dst = 8b-8a-maxk-inch/8a-outch/8b Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(64 * maxk, inch / 8, outch / 8, 2u); + kernel_tm.create(64 * maxk, inch / 8, outch / 8, (size_t)2u); for (int q = 0; q + 7 < outch; q += 8) { diff --git a/src/layer/arm/convolution_sgemm_pack8to1_int8.h b/src/layer/arm/convolution_sgemm_pack8to1_int8.h index 0dc188211..9869db24d 100644 --- a/src/layer/arm/convolution_sgemm_pack8to1_int8.h +++ b/src/layer/arm/convolution_sgemm_pack8to1_int8.h @@ -1639,9 +1639,9 @@ static void convolution_im2col_sgemm_transform_kernel_pack8to1_int8_neon(const M // dst = 4a-4b-2-maxk-inch/8a-outch/4b (arm82) Mat kernel = _kernel.reshape(maxk, inch, outch); if (outch >= 4) - kernel_tm.create(32 * maxk, inch / 8, outch / 4 + outch % 4, 1u); + kernel_tm.create(32 * maxk, inch / 8, outch / 4 + outch % 4, (size_t)1u); else - kernel_tm.create(8 * maxk, inch / 8, outch, 1u); + kernel_tm.create(8 * maxk, inch / 8, outch, (size_t)1u); int q = 0; for (; q + 3 < outch; q += 4) diff --git a/src/layer/arm/convolution_sgemm_pack8to4_int8.h b/src/layer/arm/convolution_sgemm_pack8to4_int8.h index 6efa56fa3..7f614326b 100644 --- a/src/layer/arm/convolution_sgemm_pack8to4_int8.h +++ b/src/layer/arm/convolution_sgemm_pack8to4_int8.h @@ -1112,7 +1112,7 @@ static void convolution_im2col_sgemm_transform_kernel_pack8to4_int8_neon(const M // dst = 8a-4b-maxk-inch/8a-outch/4b // dst = 4a-4b-2-maxk-inch/8a-outch/4b (arm82) Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(32 * maxk, inch / 8, outch / 4, 1u); + kernel_tm.create(32 * maxk, inch / 8, outch / 4, (size_t)1u); for (int q = 0; q + 3 < outch; q += 4) { diff --git a/src/layer/arm/packing_arm.cpp b/src/layer/arm/packing_arm.cpp index 7f2bc7ebf..2a724fd39 100644 --- a/src/layer/arm/packing_arm.cpp +++ b/src/layer/arm/packing_arm.cpp @@ -75,6 +75,7 @@ int Packing_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -91,7 +92,7 @@ int Packing_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -202,13 +203,16 @@ int Packing_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -330,6 +334,7 @@ int Packing_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -346,7 +351,7 @@ int Packing_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -841,13 +846,16 @@ int Packing_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -1349,6 +1357,7 @@ int Packing_arm::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -1365,7 +1374,7 @@ int Packing_arm::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -1459,13 +1468,16 @@ int Packing_arm::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; diff --git a/src/layer/arm/padding_arm.cpp b/src/layer/arm/padding_arm.cpp index 8f61d07a9..293ae31f4 100644 --- a/src/layer/arm/padding_arm.cpp +++ b/src/layer/arm/padding_arm.cpp @@ -94,6 +94,7 @@ int Padding_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -179,6 +180,49 @@ int Padding_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + float32x4_t pad_value = per_channel_pad_data_size ? vld1q_f32((const float*)per_channel_pad_data + q * 4) : vdupq_n_f32(value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack4_neon(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack4_neon(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack4_neon(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __ARM_NEON @@ -198,6 +242,7 @@ int Padding_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons { int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -285,6 +330,49 @@ int Padding_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + float16x8_t pad_value = per_channel_pad_data_size ? vld1q_f16((const __fp16*)per_channel_pad_data_fp16 + q * 8) : vdupq_n_f16((__fp16)value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack8_fp16s_neon(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack8_fp16s_neon(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack8_fp16s_neon(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif @@ -400,6 +488,69 @@ int Padding_arm::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, cons return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // clang-format off + // *INDENT-OFF* + uint16x4_t pad_value; +#if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC + if (opt.use_fp16_storage) + { + pad_value = per_channel_pad_data_size ? vreinterpret_u16_f16(vld1_f16((const __fp16*)per_channel_pad_data_fp16 + q * 4)) : vreinterpret_u16_f16(vdup_n_f16((__fp16)value)); + } + else +#endif +#if NCNN_BF16 + if (opt.use_bf16_storage) + { + pad_value = per_channel_pad_data_size ? vld1_u16((const unsigned short*)per_channel_pad_data_bf16 + q * 4) : vdup_n_u16(value_bf16); + } + else +#endif + { + } + // *INDENT-ON* + // clang-format on + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack4_bf16_fp16s_neon(m, borderm, top, bottom, left, right, vcombine_u16(pad_value, pad_value)); + if (type == 1) + padding_replicate_pack4_bf16_fp16s_neon(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack4_bf16_fp16s_neon(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __ARM_NEON @@ -419,6 +570,7 @@ int Padding_arm::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio { int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -507,6 +659,51 @@ int Padding_arm::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // TODO perchannel + // int8x8_t pad_value = per_channel_pad_data_size ? vld1_s8(per_channel_pad_data + q * 8) : vdup_n_s8((signed char)value); + int8x8_t pad_value = vdup_n_s8((signed char)value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack8_int8_neon(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack8_int8_neon(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack8_int8_neon(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __ARM_NEON diff --git a/src/layer/cast.cpp b/src/layer/cast.cpp index 676a1b76a..49b7e3e56 100644 --- a/src/layer/cast.cpp +++ b/src/layer/cast.cpp @@ -58,6 +58,7 @@ int Cast::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -97,10 +98,14 @@ int Cast::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_allocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_allocator); + } if (top_blob.empty()) return -100; - int size = w * h * elempack; + int size = w * h * d * elempack; if (type_from == 1 && type_to == 2) { diff --git a/src/layer/convolution1d.cpp b/src/layer/convolution1d.cpp index 49bc015cc..62c048f11 100644 --- a/src/layer/convolution1d.cpp +++ b/src/layer/convolution1d.cpp @@ -14,8 +14,6 @@ #include "convolution1d.h" -#include "layer_type.h" - #include "fused_activation.h" namespace ncnn { diff --git a/src/layer/convolution3d.cpp b/src/layer/convolution3d.cpp new file mode 100644 index 000000000..9db45df4c --- /dev/null +++ b/src/layer/convolution3d.cpp @@ -0,0 +1,217 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "convolution3d.h" + +#include "fused_activation.h" + +namespace ncnn { + +Convolution3D::Convolution3D() +{ + one_blob_only = true; + support_inplace = false; +} + +int Convolution3D::load_param(const ParamDict& pd) +{ + num_output = pd.get(0, 0); + kernel_w = pd.get(1, 0); + kernel_h = pd.get(11, kernel_w); + kernel_d = pd.get(21, kernel_w); + dilation_w = pd.get(2, 1); + dilation_h = pd.get(12, dilation_w); + dilation_d = pd.get(22, dilation_w); + stride_w = pd.get(3, 1); + stride_h = pd.get(13, stride_w); + stride_d = pd.get(23, stride_w); + pad_left = pd.get(4, 0); + pad_right = pd.get(15, pad_left); + pad_top = pd.get(14, pad_left); + pad_bottom = pd.get(16, pad_top); + pad_front = pd.get(24, pad_left); + pad_behind = pd.get(17, pad_front); + pad_value = pd.get(18, 0.f); + bias_term = pd.get(5, 0); + weight_data_size = pd.get(6, 0); + activation_type = pd.get(9, 0); + activation_params = pd.get(10, Mat()); + + return 0; +} + +int Convolution3D::load_model(const ModelBin& mb) +{ + weight_data = mb.load(weight_data_size, 0); + if (weight_data.empty()) + return -100; + + if (bias_term) + { + bias_data = mb.load(num_output, 1); + if (bias_data.empty()) + return -100; + } + + return 0; +} + +int Convolution3D::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + int channels = bottom_blob.c; + size_t elemsize = bottom_blob.elemsize; + + const int kernel_extend_w = dilation_w * (kernel_w - 1) + 1; + const int kernel_extend_h = dilation_h * (kernel_h - 1) + 1; + const int kernel_extend_d = dilation_d * (kernel_d - 1) + 1; + + Mat bottom_blob_bordered; + Option opt_pad = opt; + opt_pad.use_packing_layout = false; + make_padding(bottom_blob, bottom_blob_bordered, opt_pad); + if (bottom_blob_bordered.empty()) + return -100; + + w = bottom_blob_bordered.w; + h = bottom_blob_bordered.h; + d = bottom_blob_bordered.d; + + int outw = (w - kernel_extend_w) / stride_w + 1; + int outh = (h - kernel_extend_h) / stride_h + 1; + int outd = (d - kernel_extend_d) / stride_d + 1; + + const int maxk = kernel_w * kernel_h * kernel_d; + + // kernel offsets + std::vector _space_ofs(maxk); + int* space_ofs = &_space_ofs[0]; + { + int p1 = 0; + int p2 = 0; + int gap0 = w * dilation_h - kernel_w * dilation_w; + int gap1 = h * w * dilation_d - w * kernel_h * dilation_h; + for (int z = 0; z < kernel_d; z++) + { + for (int i = 0; i < kernel_h; i++) + { + for (int j = 0; j < kernel_w; j++) + { + space_ofs[p1] = p2; + p1++; + p2 += dilation_w; + } + p2 += gap0; + } + p2 += gap1; + } + } + + top_blob.create(outw, outh, outd, num_output, elemsize, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + #pragma omp parallel for num_threads(opt.num_threads) + for (int p = 0; p < num_output; p++) + { + float* outptr = top_blob.channel(p); + + for (int z = 0; z < outd; z++) + { + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + float sum = 0.f; + + if (bias_term) + sum = bias_data[p]; + + const float* kptr = (const float*)weight_data + maxk * channels * p; + + for (int q = 0; q < channels; q++) + { + const Mat m = bottom_blob_bordered.channel(q); + const float* sptr = m.depth(z * stride_d).row(i * stride_h) + j * stride_w; + + for (int l = 0; l < maxk; l++) + { + float val = sptr[space_ofs[l]]; + + float wt = kptr[l]; + sum += val * wt; + } + + kptr += maxk; + } + + outptr[j] = activation_ss(sum, activation_type, activation_params); + } + + outptr += outw; + } + } + } + + return 0; +} + +void Convolution3D::make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + + const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1; + const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1; + const int kernel_extent_d = dilation_d * (kernel_d - 1) + 1; + + bottom_blob_bordered = bottom_blob; + if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0 || pad_front > 0 || pad_behind > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, pad_top, pad_bottom, pad_left, pad_right, pad_front, pad_behind, BORDER_CONSTANT, pad_value, opt_b); + } + else if (pad_left == -233 && pad_right == -233 && pad_top == -233 && pad_bottom == -233 && pad_front == -233 && pad_behind == -233) + { + // tensorflow padding=SAME or onnx padding=SAME_UPPER + int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_extent_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } + else if (pad_left == -234 && pad_right == -234 && pad_top == -234 && pad_bottom == -234 && pad_front == -234 && pad_behind == -234) + { + // onnx padding=SAME_LOWER + int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_extent_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad - hpad / 2, hpad / 2, wpad - wpad / 2, wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } +} + +} // namespace ncnn diff --git a/src/layer/convolution3d.h b/src/layer/convolution3d.h new file mode 100644 index 000000000..aee377420 --- /dev/null +++ b/src/layer/convolution3d.h @@ -0,0 +1,68 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#ifndef LAYER_CONVOLUTION3D_H +#define LAYER_CONVOLUTION3D_H + +#include "layer.h" + +namespace ncnn { + +class Convolution3D : public Layer +{ +public: + Convolution3D(); + + virtual int load_param(const ParamDict& pd); + + virtual int load_model(const ModelBin& mb); + + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + +protected: + void make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const; + +public: + // param + int num_output; + int kernel_w; + int kernel_h; + int kernel_d; + int dilation_w; + int dilation_h; + int dilation_d; + int stride_w; + int stride_h; + int stride_d; + int pad_left; // -233=SAME_UPPER -234=SAME_LOWER + int pad_right; + int pad_top; + int pad_bottom; + int pad_front; + int pad_behind; + float pad_value; + int bias_term; + + int weight_data_size; + + int activation_type; + Mat activation_params; + + Mat weight_data; + Mat bias_data; +}; + +} // namespace ncnn + +#endif //LAYER_CONVOLUTION3D_H diff --git a/src/layer/convolutiondepthwise3d.cpp b/src/layer/convolutiondepthwise3d.cpp new file mode 100644 index 000000000..7c062b0e5 --- /dev/null +++ b/src/layer/convolutiondepthwise3d.cpp @@ -0,0 +1,271 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "convolutiondepthwise3d.h" + +#include "fused_activation.h" + +namespace ncnn { + +ConvolutionDepthWise3D::ConvolutionDepthWise3D() +{ + one_blob_only = true; + support_inplace = false; +} + +int ConvolutionDepthWise3D::load_param(const ParamDict& pd) +{ + num_output = pd.get(0, 0); + kernel_w = pd.get(1, 0); + kernel_h = pd.get(11, kernel_w); + kernel_d = pd.get(21, kernel_w); + dilation_w = pd.get(2, 1); + dilation_h = pd.get(12, dilation_w); + dilation_d = pd.get(22, dilation_w); + stride_w = pd.get(3, 1); + stride_h = pd.get(13, stride_w); + stride_d = pd.get(23, stride_w); + pad_left = pd.get(4, 0); + pad_right = pd.get(15, pad_left); + pad_top = pd.get(14, pad_left); + pad_bottom = pd.get(16, pad_top); + pad_front = pd.get(24, pad_left); + pad_behind = pd.get(17, pad_front); + pad_value = pd.get(18, 0.f); + bias_term = pd.get(5, 0); + weight_data_size = pd.get(6, 0); + group = pd.get(7, 1); + activation_type = pd.get(9, 0); + activation_params = pd.get(10, Mat()); + + return 0; +} + +int ConvolutionDepthWise3D::load_model(const ModelBin& mb) +{ + weight_data = mb.load(weight_data_size, 0); + if (weight_data.empty()) + return -100; + + if (bias_term) + { + bias_data = mb.load(num_output, 1); + if (bias_data.empty()) + return -100; + } + + return 0; +} + +int ConvolutionDepthWise3D::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + int channels = bottom_blob.c; + size_t elemsize = bottom_blob.elemsize; + + const int kernel_extend_w = dilation_w * (kernel_w - 1) + 1; + const int kernel_extend_h = dilation_h * (kernel_h - 1) + 1; + const int kernel_extend_d = dilation_d * (kernel_d - 1) + 1; + + Mat bottom_blob_bordered; + Option opt_pad = opt; + opt_pad.use_packing_layout = false; + make_padding(bottom_blob, bottom_blob_bordered, opt_pad); + if (bottom_blob_bordered.empty()) + return -100; + + w = bottom_blob_bordered.w; + h = bottom_blob_bordered.h; + d = bottom_blob_bordered.d; + + int outw = (w - kernel_extend_w) / stride_w + 1; + int outh = (h - kernel_extend_h) / stride_h + 1; + int outd = (d - kernel_extend_d) / stride_d + 1; + + const int maxk = kernel_w * kernel_h * kernel_d; + + // kernel offsets + std::vector _space_ofs(maxk); + int* space_ofs = &_space_ofs[0]; + { + int p1 = 0; + int p2 = 0; + int gap0 = w * dilation_h - kernel_w * dilation_w; + int gap1 = h * w * dilation_d - w * kernel_h * dilation_h; + for (int z = 0; z < kernel_d; z++) + { + for (int i = 0; i < kernel_h; i++) + { + for (int j = 0; j < kernel_w; j++) + { + space_ofs[p1] = p2; + p1++; + p2 += dilation_w; + } + p2 += gap0; + } + p2 += gap1; + } + } + + top_blob.create(outw, outh, outd, num_output, elemsize, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + // depth-wise + if (channels == group && group == num_output) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int g = 0; g < group; g++) + { + float* outptr = top_blob.channel(g); + const float* kptr = (const float*)weight_data + maxk * g; + const Mat m = bottom_blob_bordered.channel(g); + + for (int z = 0; z < outd; z++) + { + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + float sum = 0.f; + + if (bias_term) + sum = bias_data[g]; + + const float* sptr = m.depth(z * stride_d).row(i * stride_h) + j * stride_w; + + for (int k = 0; k < maxk; k++) + { + float val = sptr[space_ofs[k]]; + float w = kptr[k]; + sum += val * w; + } + + outptr[j] = activation_ss(sum, activation_type, activation_params); + } + + outptr += outw; + } + } + } + } + else + { + // group convolution + const int channels_g = channels / group; + const int num_output_g = num_output / group; + +#ifdef _WIN32 + #pragma omp parallel for num_threads(opt.num_threads) +#else // _WIN32 + #pragma omp parallel for collapse(2) num_threads(opt.num_threads) +#endif // _WIN32 + for (int g = 0; g < group; g++) + { + for (int p = 0; p < num_output_g; p++) + { + float* outptr = top_blob.channel(g * num_output_g + p); + const float* weight_data_ptr = (const float*)weight_data + maxk * channels_g * num_output_g * g; + + for (int z = 0; z < outd; z++) + { + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + float sum = 0.f; + + if (bias_term) + sum = bias_data[num_output_g * g + p]; + + const float* kptr = weight_data_ptr + maxk * channels_g * p; + + for (int q = 0; q < channels_g; q++) + { + const Mat m = bottom_blob_bordered.channel(channels_g * g + q); + const float* sptr = m.depth(z * stride_d).row(i * stride_h) + j * stride_w; + + for (int l = 0; l < maxk; l++) + { + float val = sptr[space_ofs[l]]; + + float wt = kptr[l]; + sum += val * wt; + } + + kptr += maxk; + } + + outptr[j] = activation_ss(sum, activation_type, activation_params); + } + + outptr += outw; + } + } + } + } + } + + return 0; +} + +void ConvolutionDepthWise3D::make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + + const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1; + const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1; + const int kernel_extent_d = dilation_d * (kernel_d - 1) + 1; + + bottom_blob_bordered = bottom_blob; + if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0 || pad_front > 0 || pad_behind > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, pad_top, pad_bottom, pad_left, pad_right, pad_front, pad_behind, BORDER_CONSTANT, pad_value, opt_b); + } + else if (pad_left == -233 && pad_right == -233 && pad_top == -233 && pad_bottom == -233 && pad_front == -233 && pad_behind == -233) + { + // tensorflow padding=SAME or onnx padding=SAME_UPPER + int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_extent_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } + else if (pad_left == -234 && pad_right == -234 && pad_top == -234 && pad_bottom == -234 && pad_front == -234 && pad_behind == -234) + { + // onnx padding=SAME_LOWER + int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_extent_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad - hpad / 2, hpad / 2, wpad - wpad / 2, wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } +} + +} // namespace ncnn diff --git a/src/layer/convolutiondepthwise3d.h b/src/layer/convolutiondepthwise3d.h new file mode 100644 index 000000000..e8aa1db0c --- /dev/null +++ b/src/layer/convolutiondepthwise3d.h @@ -0,0 +1,69 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#ifndef LAYER_CONVOLUTIONDEPTHWISE3D_H +#define LAYER_CONVOLUTIONDEPTHWISE3D_H + +#include "layer.h" + +namespace ncnn { + +class ConvolutionDepthWise3D : public Layer +{ +public: + ConvolutionDepthWise3D(); + + virtual int load_param(const ParamDict& pd); + + virtual int load_model(const ModelBin& mb); + + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + +protected: + void make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const; + +public: + // param + int num_output; + int kernel_w; + int kernel_h; + int kernel_d; + int dilation_w; + int dilation_h; + int dilation_d; + int stride_w; + int stride_h; + int stride_d; + int pad_left; // -233=SAME_UPPER -234=SAME_LOWER + int pad_right; + int pad_top; + int pad_bottom; + int pad_front; + int pad_behind; + float pad_value; + int bias_term; + + int weight_data_size; + int group; + + int activation_type; + Mat activation_params; + + Mat weight_data; + Mat bias_data; +}; + +} // namespace ncnn + +#endif //LAYER_CONVOLUTIONDEPTHWISE3D_H diff --git a/src/layer/input.cpp b/src/layer/input.cpp index 4732c88db..f417c88b9 100644 --- a/src/layer/input.cpp +++ b/src/layer/input.cpp @@ -31,7 +31,7 @@ int Input::load_param(const ParamDict& pd) w = pd.get(0, 0); h = pd.get(1, 0); c = pd.get(2, 0); - + d = pd.get(3, 0); return 0; } diff --git a/src/layer/input.h b/src/layer/input.h index bd7f31cc8..e8f1c2a96 100644 --- a/src/layer/input.h +++ b/src/layer/input.h @@ -37,6 +37,7 @@ public: int w; int h; int c; + int d; }; } // namespace ncnn diff --git a/src/layer/mips/convolution_sgemm_pack4to1.h b/src/layer/mips/convolution_sgemm_pack4to1.h index 7761c28d4..2ceef6c06 100644 --- a/src/layer/mips/convolution_sgemm_pack4to1.h +++ b/src/layer/mips/convolution_sgemm_pack4to1.h @@ -567,7 +567,7 @@ static void convolution_im2col_sgemm_transform_kernel_pack4to1_msa(const Mat& _k // src = maxk-inch-outch // dst = pb-pa-maxk-inch/pa-outch/pb Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(4 * 4 * maxk, inch / 4, outch / 4 + outch % 4, 4u); + kernel_tm.create(4 * 4 * maxk, inch / 4, outch / 4 + outch % 4); int q = 0; for (; q + 3 < outch; q += 4) diff --git a/src/layer/mips/packing_mips.cpp b/src/layer/mips/packing_mips.cpp index c420d5628..efef2efa1 100644 --- a/src/layer/mips/packing_mips.cpp +++ b/src/layer/mips/packing_mips.cpp @@ -62,6 +62,7 @@ int Packing_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& o int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -78,7 +79,7 @@ int Packing_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& o top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -216,13 +217,16 @@ int Packing_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& o return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -367,6 +371,7 @@ int Packing_mips::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opti int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -383,7 +388,7 @@ int Packing_mips::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opti top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -477,13 +482,16 @@ int Packing_mips::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opti return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; diff --git a/src/layer/mips/padding_mips.cpp b/src/layer/mips/padding_mips.cpp index 785bbc469..ee2a10e7d 100644 --- a/src/layer/mips/padding_mips.cpp +++ b/src/layer/mips/padding_mips.cpp @@ -49,6 +49,7 @@ int Padding_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& o int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -134,6 +135,49 @@ int Padding_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& o return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + v4f32 pad_value = per_channel_pad_data_size ? (v4f32)__msa_ld_w((const float*)per_channel_pad_data + q * 4, 0) : __msa_fill_w_f32(value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack4_msa(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack4_msa(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack4_msa(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __mips_msa @@ -168,6 +212,7 @@ int Padding_mips::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opti { int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -257,6 +302,52 @@ int Padding_mips::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opti return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // TODO perchannel + // int64_t pad_value = per_channel_pad_data_size ? vld1_s8(per_channel_pad_data + q * 8) : vdup_n_s8((signed char)value); + int64_t v8 = (int64_t)value; + int64_t pad_value = v8 | (v8 << 8) | (v8 << 16) | (v8 << 24) | (v8 << 32) | (v8 << 40) | (v8 << 48) | (v8 << 56); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack8_int8_msa(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack8_int8_msa(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack8_int8_msa(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __mips_msa diff --git a/src/layer/packing.cpp b/src/layer/packing.cpp index e855d583f..8e989fef7 100644 --- a/src/layer/packing.cpp +++ b/src/layer/packing.cpp @@ -48,6 +48,7 @@ int Packing::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -65,7 +66,7 @@ int Packing::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -178,6 +179,53 @@ int Packing::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c return 0; } + if (dims == 4) + { + int outc = (channels * elempack + out_elempack - 1) / out_elempack; + size_t out_elemsize = elemsize / elempack * out_elempack; + size_t lane_size = out_elemsize / out_elempack; + + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < outc; q++) + { + Mat out = top_blob.channel(q); + + for (int z = 0; z < d; z++) + { + for (int i = 0; i < h; i++) + { + unsigned char* outptr = (unsigned char*)out + (size_t)(z * h + i) * w * out_elemsize; + + for (int j = 0; j < w; j++) + { + unsigned char* out_elem_ptr = outptr + j * out_elemsize; + + for (int k = 0; k < out_elempack; k++) + { + int srcq = (q * out_elempack + k) / elempack; + if (srcq >= channels) + break; + + int srck = (q * out_elempack + k) % elempack; + + const Mat m = bottom_blob.channel(srcq); + const unsigned char* ptr = (const unsigned char*)m + (size_t)(z * h + i) * w * elemsize; + const unsigned char* elem_ptr = ptr + j * elemsize; + + memcpy(out_elem_ptr + k * lane_size, elem_ptr + srck * lane_size, lane_size); + } + } + } + } + } + + return 0; + } + return 0; } diff --git a/src/layer/padding.cpp b/src/layer/padding.cpp index 6cb9af34c..5e46bb8e8 100644 --- a/src/layer/padding.cpp +++ b/src/layer/padding.cpp @@ -34,15 +34,6 @@ int Padding::load_param(const ParamDict& pd) front = pd.get(7, 0); behind = pd.get(8, 0); - if (top == -233 && bottom == -233 && left == -233 && right == -233) - { - one_blob_only = false; - } - if (top == -234 && bottom == -234 && left == -234 && right == -234) - { - one_blob_only = false; - } - return 0; } @@ -301,6 +292,7 @@ int Padding::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -341,10 +333,10 @@ int Padding::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c return 0; } - int outc = channels + front + behind; - if (dims == 3) { + int outc = channels + front + behind; + top_blob.create(outw, outh, outc, elemsize, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -395,135 +387,65 @@ int Padding::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c copy_make_border_image(m, borderm, top, left, type, pad_value); } } - return 0; - } - - return 0; -} - -int Padding::forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const -{ - const Mat& bottom_blob = bottom_blobs[0]; - const Mat& reference_blob = bottom_blobs[1]; - - Mat& top_blob = top_blobs[0]; - - int _top; - int _bottom; - int _left; - int _right; - int _front; - int _behind; - { - const int* param_data = reference_blob; - - _top = param_data[0]; - _bottom = param_data[1]; - _left = param_data[2]; - _right = param_data[3]; - _front = param_data[4]; - _behind = param_data[5]; - } - if (_top == 0 && _bottom == 0 && _left == 0 && _right == 0 && _front == 0 && _behind == 0) - { - top_blob = bottom_blob; - return 0; - } - - int w = bottom_blob.w; - int h = bottom_blob.h; - int channels = bottom_blob.c; - int dims = bottom_blob.dims; - size_t elemsize = bottom_blob.elemsize; - - int outw = w + _left + _right; - - if (dims == 1) - { - top_blob.create(outw, elemsize, opt.blob_allocator); - if (top_blob.empty()) - return -100; - - if (elemsize == 1) - copy_make_border_image(bottom_blob, top_blob, 0, _left, type, static_cast(value)); - if (elemsize == 2) - copy_make_border_image(bottom_blob, top_blob, 0, _left, type, support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(value) : float32_to_bfloat16(value)); - if (elemsize == 4) - copy_make_border_image(bottom_blob, top_blob, 0, _left, type, value); return 0; } - int outh = h + _top + _bottom; - - if (dims == 2) + if (dims == 4) { - top_blob.create(outw, outh, elemsize, opt.blob_allocator); - if (top_blob.empty()) - return -100; + int outd = d + front + behind; - if (elemsize == 1) - copy_make_border_image(bottom_blob, top_blob, _top, _left, type, static_cast(value)); - if (elemsize == 2) - copy_make_border_image(bottom_blob, top_blob, _top, _left, type, support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(value) : float32_to_bfloat16(value)); - if (elemsize == 4) - copy_make_border_image(bottom_blob, top_blob, _top, _left, type, value); - - return 0; - } - - int outc = channels + _front + _behind; - - if (dims == 3) - { - top_blob.create(outw, outh, outc, elemsize, opt.blob_allocator); + top_blob.create(outw, outh, outd, channels, elemsize, opt.blob_allocator); if (top_blob.empty()) return -100; #pragma omp parallel for num_threads(opt.num_threads) - for (int q = 0; q < outc; q++) + for (int q = 0; q < channels; q++) { - Mat borderm = top_blob.channel(q); - float pad_value = per_channel_pad_data_size ? per_channel_pad_data[q] : value; - //Channel padding - if (((q < _front) || (q >= (channels + _front))) && type == 0) - { - if (elemsize == 1) - { - borderm.fill(static_cast(pad_value)); - } - if (elemsize == 2) - { - borderm.fill(support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(pad_value) : float32_to_bfloat16(pad_value)); - } - if (elemsize == 4) - { - borderm.fill(pad_value); - } - } - else - { - int q_ = q - _front; - //Clamp channel - if (type == 1) - { - q_ = q_ <= 0 ? 0 : q_; - q_ = q_ >= channels - 1 ? channels - 1 : q_; - } - if (type == 2) - { - q_ = abs(q_); - q_ = (channels - 1) - abs(q_ - (channels - 1)); - } - const Mat m = bottom_blob.channel(q_); - if (elemsize == 1) - copy_make_border_image(m, borderm, top, left, type, static_cast(pad_value)); - if (elemsize == 2) - copy_make_border_image(m, borderm, top, left, type, support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(pad_value) : float32_to_bfloat16(pad_value)); - if (elemsize == 4) - copy_make_border_image(m, borderm, top, left, type, pad_value); + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if (((z < front) || (z >= (d + front))) && type == 0) + { + if (elemsize == 1) + { + borderm.fill(static_cast(pad_value)); + } + if (elemsize == 2) + { + borderm.fill(support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(pad_value) : float32_to_bfloat16(pad_value)); + } + if (elemsize == 4) + { + borderm.fill(pad_value); + } + } + else + { + int z_ = z - front; + + if (type == 1) + { + z_ = z_ <= 0 ? 0 : z_; + z_ = z_ >= d - 1 ? d - 1 : z_; + } + if (type == 2) + { + z_ = abs(z_); + z_ = (d - 1) - abs(z_ - (d - 1)); + } + const Mat m = bottom_blob.channel(q).depth(z_); + if (elemsize == 1) + copy_make_border_image(m, borderm, top, left, type, static_cast(pad_value)); + if (elemsize == 2) + copy_make_border_image(m, borderm, top, left, type, support_fp16_storage && opt.use_fp16_storage ? float32_to_float16(pad_value) : float32_to_bfloat16(pad_value)); + if (elemsize == 4) + copy_make_border_image(m, borderm, top, left, type, pad_value); + } } } diff --git a/src/layer/padding.h b/src/layer/padding.h index b270b2ee9..36c5be140 100644 --- a/src/layer/padding.h +++ b/src/layer/padding.h @@ -30,10 +30,7 @@ public: virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; - virtual int forward(const std::vector& bottom_blobs, std::vector& top_blobs, const Option& opt) const; - public: - // -233 = dynamic offset from reference blob int top; int bottom; int left; diff --git a/src/layer/pooling3d.cpp b/src/layer/pooling3d.cpp new file mode 100644 index 000000000..509490669 --- /dev/null +++ b/src/layer/pooling3d.cpp @@ -0,0 +1,480 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pooling3d.h" + +#include + +namespace ncnn { + +Pooling3D::Pooling3D() +{ + one_blob_only = true; + support_inplace = false; +} + +int Pooling3D::load_param(const ParamDict& pd) +{ + pooling_type = pd.get(0, 0); + kernel_w = pd.get(1, 0); + kernel_h = pd.get(11, kernel_w); + kernel_d = pd.get(21, kernel_w); + stride_w = pd.get(2, 1); + stride_h = pd.get(12, stride_w); + stride_d = pd.get(22, stride_w); + pad_left = pd.get(3, 0); + pad_right = pd.get(14, pad_left); + pad_top = pd.get(13, pad_left); + pad_bottom = pd.get(15, pad_top); + pad_front = pd.get(23, pad_top); + pad_behind = pd.get(16, pad_front); + global_pooling = pd.get(4, 0); + pad_mode = pd.get(5, 0); + avgpool_count_include_pad = pd.get(6, 0); + adaptive_pooling = pd.get(7, 0); + out_w = pd.get(8, 0); + out_h = pd.get(18, out_w); + out_d = pd.get(28, out_w); + + return 0; +} + +int Pooling3D::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const +{ + // max value in NxN window + // avg value in NxN window + + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + int channels = bottom_blob.c; + size_t elemsize = bottom_blob.elemsize; + + // NCNN_LOGE("Pooling input %d x %d pad = %d %d %d %d ksize=%d %d stride=%d %d", w, h, pad_left, pad_right, pad_top, pad_bottom, kernel_w, kernel_h, stride_w, stride_h); + if (global_pooling) + { + top_blob.create(channels, elemsize, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + int size = w * h * d; + + if (pooling_type == PoolMethod_MAX) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const float* ptr = bottom_blob.channel(q); + + float max_value = ptr[0]; + for (int i = 0; i < size; i++) + { + max_value = std::max(max_value, ptr[i]); + } + + top_blob[q] = max_value; + } + } + else if (pooling_type == PoolMethod_AVE) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const float* ptr = bottom_blob.channel(q); + + float sum = 0.f; + for (int i = 0; i < size; i++) + { + sum += ptr[i]; + } + + top_blob[q] = sum / size; + } + } + + return 0; + } + + if (adaptive_pooling) + { + top_blob.create(out_w, out_h, out_d, channels, elemsize, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (pooling_type == PoolMethod_MAX) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const float* inptr = bottom_blob.channel(q); + float* outptr = top_blob.channel(q); + + for (int z = 0; z < out_d; z++) + { + // floor div + const int id0 = d * z / out_d; + // ceil div + const int id1 = (d * (z + 1) + out_d - 1) / out_d; + for (int i = 0; i < out_h; i++) + { + // floor div + const int ih0 = h * i / out_h; + // ceil div + const int ih1 = (h * (i + 1) + out_h - 1) / out_h; + for (int j = 0; j < out_w; j++) + { + // floor div + const int iw0 = w * j / out_w; + // ceil div + const int iw1 = (w * (j + 1) + out_w - 1) / out_w; + + float max_value = inptr[id0 * w * h + ih0 * w + iw0]; + + for (int id = id0; id < id1; id++) + { + for (int ih = ih0; ih < ih1; ih++) + { + for (int iw = iw0; iw < iw1; iw++) + { + max_value = std::max(max_value, inptr[id * w * h + ih * w + iw]); + } + } + } + + outptr[j] = max_value; + } + + outptr += out_w; + } + } + } + } + else if (pooling_type == PoolMethod_AVE) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const float* inptr = bottom_blob.channel(q); + float* outptr = top_blob.channel(q); + + for (int z = 0; z < out_d; z++) + { + // floor div + const int id0 = d * z / out_d; + // ceil div + const int id1 = (d * (z + 1) + out_d - 1) / out_d; + int dk = id1 - id0; + for (int i = 0; i < out_h; i++) + { + // floor div + const int ih0 = h * i / out_h; + // ceil div + const int ih1 = (h * (i + 1) + out_h - 1) / out_h; + int hk = ih1 - ih0; + for (int j = 0; j < out_w; j++) + { + // floor div + const int iw0 = w * j / out_w; + // ceil div + const int iw1 = (w * (j + 1) + out_w - 1) / out_w; + int wk = iw1 - iw0; + + float sum = 0; + for (int id = id0; id < id1; id++) + { + for (int ih = ih0; ih < ih1; ih++) + { + for (int iw = iw0; iw < iw1; iw++) + { + sum += inptr[id * w * h + ih * w + iw]; + } + } + } + + outptr[j] = sum / hk / wk / dk; + } + + outptr += out_w; + } + } + } + } + + return 0; + } + + Mat bottom_blob_bordered; + Option opt_pad = opt; + opt_pad.use_packing_layout = false; + make_padding(bottom_blob, bottom_blob_bordered, opt_pad); + if (bottom_blob_bordered.empty()) + return -100; + + w = bottom_blob_bordered.w; + h = bottom_blob_bordered.h; + d = bottom_blob_bordered.d; + + int outw = (w - kernel_w) / stride_w + 1; + int outh = (h - kernel_h) / stride_h + 1; + int outd = (d - kernel_d) / stride_d + 1; + + top_blob.create(outw, outh, outd, channels, elemsize); + if (top_blob.empty()) + return -100; + + const int maxk = kernel_w * kernel_h * kernel_d; + + // kernel offsets + std::vector _space_ofs(maxk); + int* space_ofs = &_space_ofs[0]; + { + int p1 = 0; + int p2 = 0; + int gap0 = w - kernel_w; + int gap1 = h * w - w * kernel_h; + for (int z = 0; z < kernel_d; z++) + { + for (int i = 0; i < kernel_h; i++) + { + for (int j = 0; j < kernel_w; j++) + { + space_ofs[p1] = p2; + p1++; + p2 += 1; + } + p2 += gap0; + } + p2 += gap1; + } + } + + if (pooling_type == PoolMethod_MAX) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const Mat m = bottom_blob_bordered.channel(q); + float* outptr = top_blob.channel(q); + for (int z = 0; z < outd; z++) + { + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + const float* sptr = m.depth(z * stride_d).row(i * stride_h) + j * stride_w; + + float max_value = sptr[0]; + + for (int l = 0; l < maxk; l++) + { + float val = sptr[space_ofs[l]]; + max_value = std::max(max_value, val); + } + + outptr[j] = max_value; + } + + outptr += outw; + } + } + } + } + else if (pooling_type == PoolMethod_AVE) + { + if (avgpool_count_include_pad == 0) + { + int wtailpad = 0; + int htailpad = 0; + int dtailpad = 0; + + if (pad_mode == 0) // full padding + { + wtailpad = bottom_blob_bordered.w - bottom_blob.w - pad_left - pad_right; + htailpad = bottom_blob_bordered.h - bottom_blob.h - pad_top - pad_bottom; + dtailpad = bottom_blob_bordered.d - bottom_blob.d - pad_front - pad_behind; + } + + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const Mat m = bottom_blob_bordered.channel(q); + float* outptr = top_blob.channel(q); + + for (int z = 0; z < outd; z++) + { + int sz0 = z * stride_d; + + for (int i = 0; i < outh; i++) + { + int sy0 = i * stride_h; + + for (int j = 0; j < outw; j++) + { + int sx0 = j * stride_w; + + float sum = 0; + int area = 0; + for (int kd = 0; kd < kernel_d; kd++) + { + int sz = sz0 + kd; + + if (sz < pad_front) + continue; + + if (sz >= d - pad_behind - dtailpad) + break; + + for (int ki = 0; ki < kernel_h; ki++) + { + int sy = sy0 + ki; + + if (sy < pad_top) + continue; + + if (sy >= h - pad_bottom - htailpad) + break; + + for (int kj = 0; kj < kernel_w; kj++) + { + int sx = sx0 + kj; + + if (sx < pad_left) + continue; + + if (sx >= w - pad_right - wtailpad) + break; + + float val = m.depth(sz).row(sy)[sx]; + sum += val; + area += 1; + } + } + } + + outptr[j] = sum / area; + } + + outptr += outw; + } + } + } + } + else // if (avgpool_count_include_pad == 1) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + const Mat m = bottom_blob_bordered.channel(q); + float* outptr = top_blob.channel(q); + + for (int z = 0; z < outd; z++) + { + for (int i = 0; i < outh; i++) + { + for (int j = 0; j < outw; j++) + { + const float* sptr = m.depth(z * stride_d).row(i * stride_h) + j * stride_w; + + float sum = 0; + + for (int l = 0; l < maxk; l++) + { + float val = sptr[space_ofs[l]]; + sum += val; + } + + outptr[j] = sum / maxk; + } + + outptr += outw; + } + } + } + } + } + + return 0; +} + +void Pooling3D::make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int d = bottom_blob.d; + + bottom_blob_bordered = bottom_blob; + + float pad_value = 0.f; + if (pooling_type == PoolMethod_MAX) + { + pad_value = bottom_blob.elemsize == 1 ? -128.f : -FLT_MAX; + } + else if (pooling_type == PoolMethod_AVE) + { + pad_value = 0.f; + } + + int wtailpad = 0; + int htailpad = 0; + int dtailpad = 0; + + if (pad_mode == 0) // full padding + { + int wtail = (w + pad_left + pad_right - kernel_w) % stride_w; + int htail = (h + pad_top + pad_bottom - kernel_h) % stride_h; + int dtail = (d + pad_front + pad_behind - kernel_d) % stride_d; + if (wtail != 0) + wtailpad = stride_w - wtail; + if (htail != 0) + htailpad = stride_h - htail; + if (dtail != 0) + dtailpad = stride_d - dtail; + + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, pad_top, pad_bottom + htailpad, pad_left, pad_right + wtailpad, pad_front, pad_behind + dtailpad, BORDER_CONSTANT, pad_value, opt_b); + } + else if (pad_mode == 1) // valid padding + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, pad_top, pad_bottom, pad_left, pad_right, pad_front, pad_behind, BORDER_CONSTANT, pad_value, opt_b); + } + else if (pad_mode == 2) // tensorflow padding=SAME or onnx padding=SAME_UPPER + { + int wpad = kernel_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } + else if (pad_mode == 3) // onnx padding=SAME_LOWER + { + int wpad = kernel_w + (w - 1) / stride_w * stride_w - w; + int hpad = kernel_h + (h - 1) / stride_h * stride_h - h; + int dpad = kernel_d + (d - 1) / stride_d * stride_d - d; + if (wpad > 0 || hpad > 0 || dpad > 0) + { + Option opt_b = opt; + opt_b.blob_allocator = opt.workspace_allocator; + copy_make_border_3d(bottom_blob, bottom_blob_bordered, hpad - hpad / 2, hpad / 2, wpad - wpad / 2, wpad / 2, dpad / 2, dpad - dpad / 2, BORDER_CONSTANT, pad_value, opt_b); + } + } +} + +} //namespace ncnn diff --git a/src/layer/pooling3d.h b/src/layer/pooling3d.h new file mode 100644 index 000000000..9e8bcf496 --- /dev/null +++ b/src/layer/pooling3d.h @@ -0,0 +1,66 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#ifndef LAYER_POOLING3D_H +#define LAYER_POOLING3D_H + +#include "layer.h" + +namespace ncnn { + +class Pooling3D : public Layer +{ +public: + Pooling3D(); + + virtual int load_param(const ParamDict& pd); + + virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; + + enum PoolMethod + { + PoolMethod_MAX = 0, + PoolMethod_AVE = 1 + }; + +protected: + void make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const; + +public: + // param + int pooling_type; + int kernel_w; + int kernel_h; + int kernel_d; + int stride_w; + int stride_h; + int stride_d; + int pad_left; + int pad_right; + int pad_top; + int pad_bottom; + int pad_front; + int pad_behind; + int global_pooling; + int pad_mode; // 0=full 1=valid 2=SAME_UPPER 3=SAME_LOWER + int avgpool_count_include_pad; + int adaptive_pooling; + int out_w; + int out_h; + int out_d; +}; + +} //namespace ncnn + +#endif // LAYER_POOLING3D_H diff --git a/src/layer/relu.cpp b/src/layer/relu.cpp index dc542ebac..563ca912b 100644 --- a/src/layer/relu.cpp +++ b/src/layer/relu.cpp @@ -33,8 +33,9 @@ int ReLU::forward_inplace(Mat& bottom_top_blob, const Option& opt) const { int w = bottom_top_blob.w; int h = bottom_top_blob.h; + int d = bottom_top_blob.d; int channels = bottom_top_blob.c; - int size = w * h; + int size = w * h * d; if (slope == 0.f) { diff --git a/src/layer/riscv/cast_riscv.cpp b/src/layer/riscv/cast_riscv.cpp index 65421baa0..a2f9a4698 100644 --- a/src/layer/riscv/cast_riscv.cpp +++ b/src/layer/riscv/cast_riscv.cpp @@ -44,6 +44,7 @@ int Cast_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -83,10 +84,14 @@ int Cast_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_allocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_allocator); + } if (top_blob.empty()) return -100; - int size = w * h * elempack; + int size = w * h * d * elempack; #if __riscv_vector && __riscv_zfh if (type_from == 1 && type_to == 2) diff --git a/src/layer/riscv/convolution_sgemm_fp16s.h b/src/layer/riscv/convolution_sgemm_fp16s.h index f8d670999..5cd5ea8a3 100644 --- a/src/layer/riscv/convolution_sgemm_fp16s.h +++ b/src/layer/riscv/convolution_sgemm_fp16s.h @@ -398,7 +398,7 @@ static void convolution_im2col_sgemm_transform_kernel_fp16sa_rvv(const Mat& _ker // dst = 8b-maxk-inch-outch/8b Mat kernel = _kernel.reshape(maxk, inch, outch); #if __riscv_vector - kernel_tm.create(8 * maxk, inch, outch / 8 + (outch % 8) / 4 + outch % 4, 2u); + kernel_tm.create(8 * maxk, inch, outch / 8 + (outch % 8) / 4 + outch % 4, (size_t)2u); int q = 0; for (; q + 7 < outch; q += 8) diff --git a/src/layer/riscv/convolution_sgemm_packnto1.h b/src/layer/riscv/convolution_sgemm_packnto1.h index 1de5f95d4..828bdcb69 100644 --- a/src/layer/riscv/convolution_sgemm_packnto1.h +++ b/src/layer/riscv/convolution_sgemm_packnto1.h @@ -597,7 +597,7 @@ static void convolution_im2col_sgemm_transform_kernel_packnto1_rvv(const Mat& _k // src = maxk-inch-outch // dst = pb-pa-maxk-inch/pa-outch/pb Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(packn * packn * maxk, inch / packn, outch / packn + outch % packn, 4u); + kernel_tm.create(packn * packn * maxk, inch / packn, outch / packn + outch % packn); int q = 0; for (; q + (packn - 1) < outch; q += packn) diff --git a/src/layer/riscv/convolution_sgemm_packnto1_fp16s.h b/src/layer/riscv/convolution_sgemm_packnto1_fp16s.h index 247f71793..b8c297c21 100644 --- a/src/layer/riscv/convolution_sgemm_packnto1_fp16s.h +++ b/src/layer/riscv/convolution_sgemm_packnto1_fp16s.h @@ -597,7 +597,7 @@ static void convolution_im2col_sgemm_transform_kernel_packnto1_fp16sa_rvv(const // src = maxk-inch-outch // dst = pb-pa-maxk-inch/pa-outch/pb Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(packn * packn * maxk, inch / packn, outch / packn + outch % packn, 2u); + kernel_tm.create(packn * packn * maxk, inch / packn, outch / packn + outch % packn, (size_t)2u); int q = 0; for (; q + (packn - 1) < outch; q += packn) diff --git a/src/layer/riscv/packing_riscv.cpp b/src/layer/riscv/packing_riscv.cpp index 79ed9522f..ec1f03a22 100644 --- a/src/layer/riscv/packing_riscv.cpp +++ b/src/layer/riscv/packing_riscv.cpp @@ -82,6 +82,7 @@ int Packing_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -98,7 +99,7 @@ int Packing_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -440,13 +441,16 @@ int Packing_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -800,6 +804,7 @@ int Packing_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, co int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -816,7 +821,7 @@ int Packing_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, co top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -1158,13 +1163,16 @@ int Packing_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, co return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -1514,6 +1522,7 @@ int Packing_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opt int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -1530,7 +1539,7 @@ int Packing_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opt top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -1624,13 +1633,16 @@ int Packing_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opt return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; diff --git a/src/layer/riscv/padding_riscv.cpp b/src/layer/riscv/padding_riscv.cpp index b128f67b2..4bea22fae 100644 --- a/src/layer/riscv/padding_riscv.cpp +++ b/src/layer/riscv/padding_riscv.cpp @@ -100,6 +100,7 @@ int Padding_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -185,6 +186,49 @@ int Padding_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + vfloat32m1_t pad_value = per_channel_pad_data_size ? vle32_v_f32m1((const float*)per_channel_pad_data + q * packn, vl) : vfmv_v_f_f32m1(value, vl); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_packn_float32_rvv(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_packn_float32_rvv(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_packn_float32_rvv(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __riscv_vector @@ -225,6 +269,7 @@ int Padding_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, co int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -331,6 +376,69 @@ int Padding_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, co return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // clang-format off + // *INDENT-OFF* + vuint16m1_t pad_value; +#if __riscv_zfh + if (opt.use_fp16_storage) + { + pad_value = per_channel_pad_data_size ? vreinterpret_v_f16m1_u16m1(vle16_v_f16m1((const __fp16*)per_channel_pad_data_fp16 + q * packn, vl)) : vreinterpret_v_f16m1_u16m1(vfmv_v_f_f16m1((__fp16)value, vl)); + } + else +#endif +#if NCNN_BF16 + if (opt.use_bf16_storage) + { + pad_value = per_channel_pad_data_size ? vle16_v_u16m1((const unsigned short*)per_channel_pad_data_bf16 + q * packn, vl) : vmv_v_x_u16m1(value_bf16, vl); + } + else +#endif + { + } + // *INDENT-ON* + // clang-format on + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_packn_uint16_rvv(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_packn_uint16_rvv(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_packn_uint16_rvv(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __riscv_vector @@ -370,6 +478,7 @@ int Padding_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opt int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -458,6 +567,51 @@ int Padding_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Opt return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // TODO perchannel + // vint8m1_t pad_value = per_channel_pad_data_size ? vle8_v_i8m1(per_channel_pad_data + q * packn) : vmv_v_x_i8m1((signed char)value); + vint8m1_t pad_value = vmv_v_x_i8m1((signed char)value, vl); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_packn_int8_rvv(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_packn_int8_rvv(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_packn_int8_rvv(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __riscv_vector diff --git a/src/layer/vulkan/cast_vulkan.cpp b/src/layer/vulkan/cast_vulkan.cpp index 11c15dd29..2fb42e5a8 100644 --- a/src/layer/vulkan/cast_vulkan.cpp +++ b/src/layer/vulkan/cast_vulkan.cpp @@ -39,12 +39,12 @@ int Cast_vulkan::create_pipeline(const Option& opt) int elempack = 1; if (shape.dims == 1) elempack = opt.use_shader_pack8 && shape.w % 8 == 0 ? 8 : shape.w % 4 == 0 ? 4 : 1; if (shape.dims == 2) elempack = opt.use_shader_pack8 && shape.h % 8 == 0 ? 8 : shape.h % 4 == 0 ? 4 : 1; - if (shape.dims == 3) elempack = opt.use_shader_pack8 && shape.c % 8 == 0 ? 8 : shape.c % 4 == 0 ? 4 : 1; + if (shape.dims == 3 || shape.dims == 4) elempack = opt.use_shader_pack8 && shape.c % 8 == 0 ? 8 : shape.c % 4 == 0 ? 4 : 1; int out_elempack = 1; if (out_shape.dims == 1) out_elempack = opt.use_shader_pack8 && out_shape.w % 8 == 0 ? 8 : out_shape.w % 4 == 0 ? 4 : 1; if (out_shape.dims == 2) out_elempack = opt.use_shader_pack8 && out_shape.h % 8 == 0 ? 8 : out_shape.h % 4 == 0 ? 4 : 1; - if (out_shape.dims == 3) out_elempack = opt.use_shader_pack8 && out_shape.c % 8 == 0 ? 8 : out_shape.c % 4 == 0 ? 4 : 1; + if (out_shape.dims == 3 || out_shape.dims == 4) out_elempack = opt.use_shader_pack8 && out_shape.c % 8 == 0 ? 8 : out_shape.c % 4 == 0 ? 4 : 1; size_t elemsize; size_t out_elemsize; @@ -68,21 +68,23 @@ int Cast_vulkan::create_pipeline(const Option& opt) if (shape.dims == 1) shape_packed = Mat(shape.w / elempack, (void*)0, elemsize, elempack); if (shape.dims == 2) shape_packed = Mat(shape.w, shape.h / elempack, (void*)0, elemsize, elempack); if (shape.dims == 3) shape_packed = Mat(shape.w, shape.h, shape.c / elempack, (void*)0, elemsize, elempack); + if (shape.dims == 4) shape_packed = Mat(shape.w, shape.h, shape.d, shape.c / elempack, (void*)0, elemsize, elempack); Mat out_shape_packed; if (out_shape.dims == 1) out_shape_packed = Mat(out_shape.w / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 2) out_shape_packed = Mat(out_shape.w, out_shape.h / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 3) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); + if (out_shape.dims == 4) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.d, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); std::vector specializations(0 + 10); specializations[0 + 0].i = shape_packed.dims; specializations[0 + 1].i = shape_packed.w; - specializations[0 + 2].i = shape_packed.h; + specializations[0 + 2].i = shape_packed.h * shape_packed.d; specializations[0 + 3].i = shape_packed.c; specializations[0 + 4].i = shape_packed.cstep; specializations[0 + 5].i = out_shape_packed.dims; specializations[0 + 6].i = out_shape_packed.w; - specializations[0 + 7].i = out_shape_packed.h; + specializations[0 + 7].i = out_shape_packed.h * out_shape_packed.d; specializations[0 + 8].i = out_shape_packed.c; specializations[0 + 9].i = out_shape_packed.cstep; @@ -105,6 +107,12 @@ int Cast_vulkan::create_pipeline(const Option& opt) local_size_xyz.h = std::min(4, out_shape_packed.h); local_size_xyz.c = std::min(4, out_shape_packed.c); } + if (out_shape_packed.dims == 4) + { + local_size_xyz.w = std::min(4, out_shape_packed.w); + local_size_xyz.h = std::min(4, out_shape_packed.h * out_shape_packed.d); + local_size_xyz.c = std::min(4, out_shape_packed.c); + } if (type_from == 1 && type_to == 2) { @@ -196,6 +204,7 @@ int Cast_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& c int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -243,6 +252,10 @@ int Cast_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& c { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_vkallocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -253,12 +266,12 @@ int Cast_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& c std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; @@ -294,6 +307,7 @@ int Cast_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, Vk int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -341,6 +355,10 @@ int Cast_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, Vk { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_vkallocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -351,12 +369,12 @@ int Cast_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, Vk std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = 0; //bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = 0; //top_blob.cstep; diff --git a/src/layer/vulkan/packing_vulkan.cpp b/src/layer/vulkan/packing_vulkan.cpp index f66ca8b13..ff2212e1c 100644 --- a/src/layer/vulkan/packing_vulkan.cpp +++ b/src/layer/vulkan/packing_vulkan.cpp @@ -76,6 +76,7 @@ int Packing_vulkan::create_pipeline(const Option& _opt) if (out_shape.dims == 1) out_shape_packed = Mat(out_shape.w / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 2) out_shape_packed = Mat(out_shape.w, out_shape.h / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 3) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); + if (out_shape.dims == 4) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.d, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); // check blob shape if (!vkdev->shape_support_image_storage(out_shape_packed)) @@ -94,7 +95,7 @@ int Packing_vulkan::create_pipeline(const Option& _opt) specializations[2 + 4].i = 0; specializations[2 + 5].i = out_shape_packed.dims; specializations[2 + 6].i = out_shape_packed.w; - specializations[2 + 7].i = out_shape_packed.h; + specializations[2 + 7].i = out_shape_packed.h * out_shape_packed.d; specializations[2 + 8].i = out_shape_packed.c; specializations[2 + 9].i = out_shape_packed.cstep; @@ -117,6 +118,12 @@ int Packing_vulkan::create_pipeline(const Option& _opt) local_size_xyz.h = 4; local_size_xyz.c = 4; } + if (out_shape_packed.dims == 4) + { + local_size_xyz.w = 4; + local_size_xyz.h = 4; + local_size_xyz.c = 4; + } if (out_elempack == 8) { @@ -259,6 +266,7 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -276,7 +284,7 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -353,6 +361,15 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute return -100; } + if (dims == 4) + { + int outc = (channels * elempack + out_elempack - 1) / out_elempack; + + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_vkallocator); + if (top_blob.empty()) + return -100; + } + std::vector buffer_bindings(2); buffer_bindings[0] = bottom_blob; buffer_bindings[1] = top_blob; @@ -366,12 +383,12 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; @@ -428,6 +445,7 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -444,7 +462,7 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -511,6 +529,15 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, return -100; } + if (dims == 4) + { + int outc = (channels * elempack + out_elempack - 1) / out_elempack; + + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_vkallocator); + if (top_blob.empty()) + return -100; + } + std::vector buffer_bindings(2); std::vector image_bindings(2); @@ -520,12 +547,12 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = 0; //bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = 0; //top_blob.cstep; @@ -576,6 +603,7 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkImageMat& top_blob, VkCo int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -646,6 +674,15 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkImageMat& top_blob, VkCo return -100; } + if (dims == 4) + { + int outc = (channels * elempack + out_elempack - 1) / out_elempack; + + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_vkallocator); + if (top_blob.empty()) + return -100; + } + std::vector buffer_bindings(2); buffer_bindings[0] = bottom_blob; @@ -655,12 +692,12 @@ int Packing_vulkan::forward(const VkMat& bottom_blob, VkImageMat& top_blob, VkCo std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = 0; //top_blob.cstep; @@ -711,6 +748,7 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkMat& top_blob, VkCo int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -781,6 +819,15 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkMat& top_blob, VkCo return -100; } + if (dims == 4) + { + int outc = (channels * elempack + out_elempack - 1) / out_elempack; + + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_vkallocator); + if (top_blob.empty()) + return -100; + } + std::vector buffer_bindings(2); buffer_bindings[1] = top_blob; @@ -790,12 +837,12 @@ int Packing_vulkan::forward(const VkImageMat& bottom_blob, VkMat& top_blob, VkCo std::vector constants(10); constants[0].i = bottom_blob.dims; constants[1].i = bottom_blob.w; - constants[2].i = bottom_blob.h; + constants[2].i = bottom_blob.h * bottom_blob.d; constants[3].i = bottom_blob.c; constants[4].i = 0; //bottom_blob.cstep; constants[5].i = top_blob.dims; constants[6].i = top_blob.w; - constants[7].i = top_blob.h; + constants[7].i = top_blob.h * top_blob.d; constants[8].i = top_blob.c; constants[9].i = top_blob.cstep; diff --git a/src/layer/vulkan/padding_vulkan.cpp b/src/layer/vulkan/padding_vulkan.cpp index a75a90823..4f97733c3 100644 --- a/src/layer/vulkan/padding_vulkan.cpp +++ b/src/layer/vulkan/padding_vulkan.cpp @@ -32,6 +32,10 @@ Padding_vulkan::Padding_vulkan() pipeline_padding_pack4to8 = 0; pipeline_padding_pack8to4 = 0; pipeline_padding_pack8to1 = 0; + + pipeline_padding_3d = 0; + pipeline_padding_3d_pack4 = 0; + pipeline_padding_3d_pack8 = 0; } int Padding_vulkan::create_pipeline(const Option& _opt) @@ -43,12 +47,12 @@ int Padding_vulkan::create_pipeline(const Option& _opt) int elempack = 1; if (shape.dims == 1) elempack = opt.use_shader_pack8 && shape.w % 8 == 0 ? 8 : shape.w % 4 == 0 ? 4 : 1; if (shape.dims == 2) elempack = opt.use_shader_pack8 && shape.h % 8 == 0 ? 8 : shape.h % 4 == 0 ? 4 : 1; - if (shape.dims == 3) elempack = opt.use_shader_pack8 && shape.c % 8 == 0 ? 8 : shape.c % 4 == 0 ? 4 : 1; + if (shape.dims == 3 || shape.dims == 4) elempack = opt.use_shader_pack8 && shape.c % 8 == 0 ? 8 : shape.c % 4 == 0 ? 4 : 1; int out_elempack = 1; if (out_shape.dims == 1) out_elempack = opt.use_shader_pack8 && out_shape.w % 8 == 0 ? 8 : out_shape.w % 4 == 0 ? 4 : 1; if (out_shape.dims == 2) out_elempack = opt.use_shader_pack8 && out_shape.h % 8 == 0 ? 8 : out_shape.h % 4 == 0 ? 4 : 1; - if (out_shape.dims == 3) out_elempack = opt.use_shader_pack8 && out_shape.c % 8 == 0 ? 8 : out_shape.c % 4 == 0 ? 4 : 1; + if (out_shape.dims == 3 || out_shape.dims == 4) out_elempack = opt.use_shader_pack8 && out_shape.c % 8 == 0 ? 8 : out_shape.c % 4 == 0 ? 4 : 1; int offset_elempack = 1; if (shape.dims == 1) @@ -65,13 +69,17 @@ int Padding_vulkan::create_pipeline(const Option& _opt) else offset_elempack = opt.use_shader_pack8 && top % 8 == 0 ? 8 : top % 4 == 0 ? 4 : 1; } - else // if (shape.dims == 3) + else if (shape.dims == 3) { if (front == 0) offset_elempack = elempack; else offset_elempack = opt.use_shader_pack8 && front % 8 == 0 ? 8 : front % 4 == 0 ? 4 : 1; } + else // if (shape.dims == 4) + { + offset_elempack = elempack; + } offset_elempack = std::min(offset_elempack, elempack); @@ -97,11 +105,13 @@ int Padding_vulkan::create_pipeline(const Option& _opt) if (shape.dims == 1) shape_packed = Mat(shape.w / elempack, (void*)0, elemsize, elempack); if (shape.dims == 2) shape_packed = Mat(shape.w, shape.h / elempack, (void*)0, elemsize, elempack); if (shape.dims == 3) shape_packed = Mat(shape.w, shape.h, shape.c / elempack, (void*)0, elemsize, elempack); + if (shape.dims == 4) shape_packed = Mat(shape.w, shape.h, shape.d, shape.c / elempack, (void*)0, elemsize, elempack); Mat out_shape_packed; if (out_shape.dims == 1) out_shape_packed = Mat(out_shape.w / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 2) out_shape_packed = Mat(out_shape.w, out_shape.h / out_elempack, (void*)0, out_elemsize, out_elempack); if (out_shape.dims == 3) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); + if (out_shape.dims == 4) out_shape_packed = Mat(out_shape.w, out_shape.h, out_shape.d, out_shape.c / out_elempack, (void*)0, out_elemsize, out_elempack); Mat shape_unpacked = shape_packed; if (one_blob_only && shape.dims != 0 && elempack > offset_elempack) @@ -123,6 +133,7 @@ int Padding_vulkan::create_pipeline(const Option& _opt) if (shape.dims == 1) shape_unpacked = Mat(shape.w / offset_elempack, (void*)0, offset_elemsize, offset_elempack); if (shape.dims == 2) shape_unpacked = Mat(shape.w, shape.h / offset_elempack, (void*)0, offset_elemsize, offset_elempack); if (shape.dims == 3) shape_unpacked = Mat(shape.w, shape.h, shape.c / offset_elempack, (void*)0, offset_elemsize, offset_elempack); + // if (shape.dims == 4) should never reach here } // check blob shape @@ -147,6 +158,23 @@ int Padding_vulkan::create_pipeline(const Option& _opt) specializations[3 + 8].i = out_shape_packed.c; specializations[3 + 9].i = out_shape_packed.cstep; + std::vector specializations_3d(3 + 12); + specializations_3d[0].i = type; + specializations_3d[1].f = value; + specializations_3d[2].i = per_channel_pad_data_size ? 1 : 0; + specializations_3d[3 + 0].i = shape_unpacked.dims; + specializations_3d[3 + 1].i = shape_unpacked.w; + specializations_3d[3 + 2].i = shape_unpacked.h; + specializations_3d[3 + 3].i = shape_unpacked.d; + specializations_3d[3 + 4].i = shape_unpacked.c; + specializations_3d[3 + 5].i = shape_unpacked.cstep; + specializations_3d[3 + 6].i = out_shape_packed.dims; + specializations_3d[3 + 7].i = out_shape_packed.w; + specializations_3d[3 + 8].i = out_shape_packed.h; + specializations_3d[3 + 9].i = out_shape_packed.d; + specializations_3d[3 + 10].i = out_shape_packed.c; + specializations_3d[3 + 11].i = out_shape_packed.cstep; + Mat local_size_xyz; if (out_shape_packed.dims == 1) { @@ -166,6 +194,12 @@ int Padding_vulkan::create_pipeline(const Option& _opt) local_size_xyz.h = std::min(4, out_shape_packed.h); local_size_xyz.c = std::min(4, out_shape_packed.c); } + if (out_shape_packed.dims == 4) + { + local_size_xyz.w = std::min(4, out_shape_packed.w); + local_size_xyz.h = std::min(4, out_shape_packed.h * out_shape_packed.d); + local_size_xyz.c = std::min(4, out_shape_packed.c); + } // pack1 if (out_shape.dims == 0 || (offset_elempack == 1 && out_elempack == 1)) @@ -173,6 +207,10 @@ int Padding_vulkan::create_pipeline(const Option& _opt) pipeline_padding = new Pipeline(vkdev); pipeline_padding->set_optimal_local_size_xyz(local_size_xyz); pipeline_padding->create(LayerShaderType::padding, opt, specializations); + + pipeline_padding_3d = new Pipeline(vkdev); + pipeline_padding_3d->set_optimal_local_size_xyz(local_size_xyz); + pipeline_padding_3d->create(LayerShaderType::padding_3d, opt, specializations_3d); } // pack4 @@ -181,6 +219,10 @@ int Padding_vulkan::create_pipeline(const Option& _opt) pipeline_padding_pack4 = new Pipeline(vkdev); pipeline_padding_pack4->set_optimal_local_size_xyz(local_size_xyz); pipeline_padding_pack4->create(LayerShaderType::padding_pack4, opt, specializations); + + pipeline_padding_3d_pack4 = new Pipeline(vkdev); + pipeline_padding_3d_pack4->set_optimal_local_size_xyz(local_size_xyz); + pipeline_padding_3d_pack4->create(LayerShaderType::padding_3d_pack4, opt, specializations_3d); } // pack1to4 @@ -205,6 +247,10 @@ int Padding_vulkan::create_pipeline(const Option& _opt) pipeline_padding_pack8 = new Pipeline(vkdev); pipeline_padding_pack8->set_optimal_local_size_xyz(local_size_xyz); pipeline_padding_pack8->create(LayerShaderType::padding_pack8, opt, specializations); + + pipeline_padding_3d_pack8 = new Pipeline(vkdev); + pipeline_padding_3d_pack8->set_optimal_local_size_xyz(local_size_xyz); + pipeline_padding_3d_pack8->create(LayerShaderType::padding_3d_pack8, opt, specializations_3d); } // pack1to8 @@ -271,6 +317,15 @@ int Padding_vulkan::destroy_pipeline(const Option& /*opt*/) delete pipeline_padding_pack8to1; pipeline_padding_pack8to1 = 0; + delete pipeline_padding_3d; + pipeline_padding_3d = 0; + + delete pipeline_padding_3d_pack4; + pipeline_padding_3d_pack4 = 0; + + delete pipeline_padding_3d_pack8; + pipeline_padding_3d_pack8 = 0; + return 0; } @@ -301,12 +356,14 @@ int Padding_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute int dims = bottom_blob.dims; int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; size_t elemsize = bottom_blob.elemsize; int elempack = bottom_blob.elempack; int outw = 0; int outh = 0; + int outd = 0; int outc = 0; int offset_elempack; @@ -337,7 +394,7 @@ int Padding_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute out_elempack = opt.use_shader_pack8 && outh % 8 == 0 ? 8 : outh % 4 == 0 ? 4 : 1; offset_elempack = top == 0 ? elempack : opt.use_shader_pack8 && top % 8 == 0 ? 8 : top % 4 == 0 ? 4 : 1; } - else // if (dims == 3) + else if (dims == 3) { if (top == 0 && bottom == 0 && left == 0 && right == 0 && front == 0 && behind == 0) { @@ -351,6 +408,21 @@ int Padding_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute out_elempack = opt.use_shader_pack8 && outc % 8 == 0 ? 8 : outc % 4 == 0 ? 4 : 1; offset_elempack = front == 0 ? elempack : opt.use_shader_pack8 && front % 8 == 0 ? 8 : front % 4 == 0 ? 4 : 1; } + else // if (dims == 4) + { + if (top == 0 && bottom == 0 && left == 0 && right == 0 && front == 0 && behind == 0) + { + top_blob = bottom_blob; + return 0; + } + + outw = w + left + right; + outh = h + top + bottom; + outd = d + front + behind; + outc = channels * elempack; + out_elempack = elempack; + offset_elempack = elempack; + } offset_elempack = std::min(offset_elempack, elempack); @@ -381,10 +453,14 @@ int Padding_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute { top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } - else // if (dims == 3) + else if (dims == 3) { top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } + else // if (dims == 4) + { + top_blob.create(outw, outh, outd, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -393,6 +469,34 @@ int Padding_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute bindings[1] = top_blob; bindings[2] = per_channel_pad_data_gpu; + if (dims == 4) + { + std::vector constants(15); + constants[0].i = bottom_blob_unpacked.dims; + constants[1].i = bottom_blob_unpacked.w; + constants[2].i = bottom_blob_unpacked.h; + constants[3].i = bottom_blob_unpacked.d; + constants[4].i = bottom_blob_unpacked.c; + constants[5].i = bottom_blob_unpacked.cstep; + constants[6].i = top_blob.dims; + constants[7].i = top_blob.w; + constants[8].i = top_blob.h; + constants[9].i = top_blob.d; + constants[10].i = top_blob.c; + constants[11].i = top_blob.cstep; + constants[12].i = left; + constants[13].i = top; + constants[14].i = front; + + const Pipeline* pipeline = out_elempack == 8 ? pipeline_padding_3d_pack8 + : out_elempack == 4 ? pipeline_padding_3d_pack4 + : pipeline_padding_3d; + + cmd.record_pipeline(pipeline, bindings, constants, top_blob); + + return 0; + } + std::vector constants(13); constants[0].i = bottom_blob_unpacked.dims; constants[1].i = bottom_blob_unpacked.w; @@ -477,12 +581,14 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::vector< int dims = bottom_blob.dims; int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; size_t elemsize = bottom_blob.elemsize; int elempack = bottom_blob.elempack; int outw = 0; int outh = 0; + int outd = 0; int outc = 0; int offset_elempack; @@ -513,7 +619,7 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::vector< out_elempack = opt.use_shader_pack8 && outh % 8 == 0 ? 8 : outh % 4 == 0 ? 4 : 1; offset_elempack = _top == 0 ? elempack : opt.use_shader_pack8 && _top % 8 == 0 ? 8 : _top % 4 == 0 ? 4 : 1; } - else // if (dims == 3) + else if (dims == 3) { if (_top == 0 && _bottom == 0 && _left == 0 && _right == 0 && _front == 0 && _behind == 0) { @@ -527,6 +633,21 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::vector< out_elempack = opt.use_shader_pack8 && outc % 8 == 0 ? 8 : outc % 4 == 0 ? 4 : 1; offset_elempack = _front == 0 ? elempack : opt.use_shader_pack8 && _front % 8 == 0 ? 8 : _front % 4 == 0 ? 4 : 1; } + else // if (dims == 4) + { + if (_top == 0 && _bottom == 0 && _left == 0 && _right == 0 && _front == 0 && _behind == 0) + { + top_blob = bottom_blob; + return 0; + } + + outw = w + _left + _right; + outh = h + _top + _bottom; + outd = d + _front + _behind; + outc = channels * elempack; + out_elempack = elempack; + offset_elempack = elempack; + } offset_elempack = std::min(offset_elempack, elempack); @@ -557,10 +678,14 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::vector< { top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } - else // if (dims == 3) + else if (dims == 3) { top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } + else // if (dims == 4) + { + top_blob.create(outw, outh, outd, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -569,6 +694,34 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::vector< bindings[1] = top_blob; bindings[2] = per_channel_pad_data_gpu; + if (dims == 4) + { + std::vector constants(15); + constants[0].i = bottom_blob_unpacked.dims; + constants[1].i = bottom_blob_unpacked.w; + constants[2].i = bottom_blob_unpacked.h; + constants[3].i = bottom_blob_unpacked.d; + constants[4].i = bottom_blob_unpacked.c; + constants[5].i = bottom_blob_unpacked.cstep; + constants[6].i = top_blob.dims; + constants[7].i = top_blob.w; + constants[8].i = top_blob.h; + constants[9].i = top_blob.d; + constants[10].i = top_blob.c; + constants[11].i = top_blob.cstep; + constants[12].i = _left; + constants[13].i = _top; + constants[14].i = _front; + + const Pipeline* pipeline = out_elempack == 8 ? pipeline_padding_3d_pack8 + : out_elempack == 4 ? pipeline_padding_3d_pack4 + : pipeline_padding_3d; + + cmd.record_pipeline(pipeline, bindings, constants, top_blob); + + return 0; + } + std::vector constants(13); constants[0].i = bottom_blob_unpacked.dims; constants[1].i = bottom_blob_unpacked.w; @@ -632,12 +785,14 @@ int Padding_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, int dims = bottom_blob.dims; int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; size_t elemsize = bottom_blob.elemsize; int elempack = bottom_blob.elempack; int outw = 0; int outh = 0; + int outd = 0; int outc = 0; int offset_elempack; @@ -668,7 +823,7 @@ int Padding_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, out_elempack = opt.use_shader_pack8 && outh % 8 == 0 ? 8 : outh % 4 == 0 ? 4 : 1; offset_elempack = top == 0 ? elempack : opt.use_shader_pack8 && top % 8 == 0 ? 8 : top % 4 == 0 ? 4 : 1; } - else // if (dims == 3) + else if (dims == 3) { if (top == 0 && bottom == 0 && left == 0 && right == 0 && front == 0 && behind == 0) { @@ -682,6 +837,21 @@ int Padding_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, out_elempack = opt.use_shader_pack8 && outc % 8 == 0 ? 8 : outc % 4 == 0 ? 4 : 1; offset_elempack = front == 0 ? elempack : opt.use_shader_pack8 && front % 8 == 0 ? 8 : front % 4 == 0 ? 4 : 1; } + else // if (dims == 4) + { + if (top == 0 && bottom == 0 && left == 0 && right == 0 && front == 0 && behind == 0) + { + top_blob = bottom_blob; + return 0; + } + + outw = w + left + right; + outh = h + top + bottom; + outd = d + front + behind; + outc = channels * elempack; + out_elempack = elempack; + offset_elempack = elempack; + } offset_elempack = std::min(offset_elempack, elempack); @@ -712,10 +882,14 @@ int Padding_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, { top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } - else // if (dims == 3) + else if (dims == 3) { top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } + else // if (dims == 4) + { + top_blob.create(outw, outh, outd, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -724,6 +898,34 @@ int Padding_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, bindings[1] = top_blob; bindings[2] = per_channel_pad_data_gpu_image; + if (dims == 4) + { + std::vector constants(15); + constants[0].i = bottom_blob_unpacked.dims; + constants[1].i = bottom_blob_unpacked.w; + constants[2].i = bottom_blob_unpacked.h; + constants[3].i = bottom_blob_unpacked.d; + constants[4].i = bottom_blob_unpacked.c; + constants[5].i = 0; + constants[6].i = top_blob.dims; + constants[7].i = top_blob.w; + constants[8].i = top_blob.h; + constants[9].i = top_blob.d; + constants[10].i = top_blob.c; + constants[11].i = 0; + constants[12].i = left; + constants[13].i = top; + constants[14].i = front; + + const Pipeline* pipeline = out_elempack == 8 ? pipeline_padding_3d_pack8 + : out_elempack == 4 ? pipeline_padding_3d_pack4 + : pipeline_padding_3d; + + cmd.record_pipeline(pipeline, bindings, constants, top_blob); + + return 0; + } + std::vector constants(13); constants[0].i = bottom_blob_unpacked.dims; constants[1].i = bottom_blob_unpacked.w; @@ -809,12 +1011,14 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::ve int dims = bottom_blob.dims; int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; size_t elemsize = bottom_blob.elemsize; int elempack = bottom_blob.elempack; int outw = 0; int outh = 0; + int outd = 0; int outc = 0; int offset_elempack; @@ -845,7 +1049,7 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::ve out_elempack = opt.use_shader_pack8 && outh % 8 == 0 ? 8 : outh % 4 == 0 ? 4 : 1; offset_elempack = _top == 0 ? elempack : opt.use_shader_pack8 && _top % 8 == 0 ? 8 : _top % 4 == 0 ? 4 : 1; } - else // if (dims == 3) + else if (dims == 3) { if (_top == 0 && _bottom == 0 && _left == 0 && _right == 0 && _front == 0 && _behind == 0) { @@ -859,6 +1063,21 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::ve out_elempack = opt.use_shader_pack8 && outc % 8 == 0 ? 8 : outc % 4 == 0 ? 4 : 1; offset_elempack = _front == 0 ? elempack : opt.use_shader_pack8 && _front % 8 == 0 ? 8 : _front % 4 == 0 ? 4 : 1; } + else // if (dims == 4) + { + if (_top == 0 && _bottom == 0 && _left == 0 && _right == 0 && _front == 0 && _behind == 0) + { + top_blob = bottom_blob; + return 0; + } + + outw = w + _left + _right; + outh = h + _top + _bottom; + outd = d + _front + _behind; + outc = channels * elempack; + out_elempack = elempack; + offset_elempack = elempack; + } offset_elempack = std::min(offset_elempack, elempack); @@ -889,10 +1108,14 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::ve { top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } - else // if (dims == 3) + else if (dims == 3) { top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); } + else // if (dims == 4) + { + top_blob.create(outw, outh, outd, outc / out_elempack, out_elemsize, out_elempack, opt.blob_vkallocator); + } if (top_blob.empty()) return -100; @@ -901,6 +1124,34 @@ int Padding_vulkan::forward(const std::vector& bottom_blobs, std::ve bindings[1] = top_blob; bindings[2] = per_channel_pad_data_gpu_image; + if (dims == 4) + { + std::vector constants(15); + constants[0].i = bottom_blob_unpacked.dims; + constants[1].i = bottom_blob_unpacked.w; + constants[2].i = bottom_blob_unpacked.h; + constants[3].i = bottom_blob_unpacked.d; + constants[4].i = bottom_blob_unpacked.c; + constants[5].i = 0; + constants[6].i = top_blob.dims; + constants[7].i = top_blob.w; + constants[8].i = top_blob.h; + constants[9].i = top_blob.d; + constants[10].i = top_blob.c; + constants[11].i = 0; + constants[12].i = _left; + constants[13].i = _top; + constants[14].i = _front; + + const Pipeline* pipeline = out_elempack == 8 ? pipeline_padding_3d_pack8 + : out_elempack == 4 ? pipeline_padding_3d_pack4 + : pipeline_padding_3d; + + cmd.record_pipeline(pipeline, bindings, constants, top_blob); + + return 0; + } + std::vector constants(13); constants[0].i = bottom_blob_unpacked.dims; constants[1].i = bottom_blob_unpacked.w; diff --git a/src/layer/vulkan/padding_vulkan.h b/src/layer/vulkan/padding_vulkan.h index 3f4c41edb..faea7bd92 100644 --- a/src/layer/vulkan/padding_vulkan.h +++ b/src/layer/vulkan/padding_vulkan.h @@ -50,6 +50,10 @@ public: Pipeline* pipeline_padding_pack4to8; Pipeline* pipeline_padding_pack8to4; Pipeline* pipeline_padding_pack8to1; + + Pipeline* pipeline_padding_3d; + Pipeline* pipeline_padding_3d_pack4; + Pipeline* pipeline_padding_3d_pack8; }; } // namespace ncnn diff --git a/src/layer/vulkan/shader/padding_3d.comp b/src/layer/vulkan/shader/padding_3d.comp new file mode 100644 index 000000000..df4debfd6 --- /dev/null +++ b/src/layer/vulkan/shader/padding_3d.comp @@ -0,0 +1,124 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#version 450 + +#if NCNN_fp16_storage +#extension GL_EXT_shader_16bit_storage: require +#endif +#if NCNN_fp16_arithmetic +#extension GL_EXT_shader_explicit_arithmetic_types_float16: require +#endif + +layout (constant_id = 0) const int type = 1; +layout (constant_id = 1) const float value = 0; +layout (constant_id = 2) const int per_channel_pad = 0; + +#define shape_constant_id_offset 3 +layout (constant_id = shape_constant_id_offset + 0) const int dims = 0; +layout (constant_id = shape_constant_id_offset + 1) const int w = 0; +layout (constant_id = shape_constant_id_offset + 2) const int h = 0; +layout (constant_id = shape_constant_id_offset + 3) const int d = 0; +layout (constant_id = shape_constant_id_offset + 4) const int c = 0; +layout (constant_id = shape_constant_id_offset + 5) const int cstep = 0; + +layout (constant_id = shape_constant_id_offset + 6) const int outdims = 0; +layout (constant_id = shape_constant_id_offset + 7) const int outw = 0; +layout (constant_id = shape_constant_id_offset + 8) const int outh = 0; +layout (constant_id = shape_constant_id_offset + 9) const int outd = 0; +layout (constant_id = shape_constant_id_offset + 10) const int outc = 0; +layout (constant_id = shape_constant_id_offset + 11) const int outcstep = 0; + +#if NCNN_image_shader +layout (binding = 0) uniform unfp sampler3D bottom_blob; +layout (binding = 1, imfmtc1) writeonly uniform unfp image3D top_blob; +layout (binding = 2) uniform unfp sampler3D per_channel_pad_blob; +#else +layout (binding = 0) readonly buffer bottom_blob { sfp bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { sfp top_blob_data[]; }; +layout (binding = 2) readonly buffer per_channel_pad_blob { sfp per_channel_pad_blob_data[]; }; +#endif + +layout (push_constant) uniform parameter +{ + int dims; + int w; + int h; + int d; + int c; + int cstep; + + int outdims; + int outw; + int outh; + int outd; + int outc; + int outcstep; + + int left; + int top; + int front; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= psc(outw) || gy >= psc(outh) * psc(outd) || gz >= psc(outc)) + return; + + // if (psc(dims) == 4) + { + const int gi = gz * psc(outcstep) + gy * psc(outw) + gx; + + int x = gx - p.left; + int yh = gy % psc(outh) - p.top; + int yd = gy / psc(outh) - p.front; + int y = yd * psc(h) + yh; + int z = gz; + + if (type == 0) + { + if (x >= 0 && x < psc(w) && yh >= 0 && yh < psc(h) && yd >= 0 && yd < psc(d) && z >= 0 && z < psc(c)) + { +#if NCNN_image_shader + image3d_cp1(top_blob, ivec3(gx, gy, gz), bottom_blob, ivec3(x, y, z)); +#else + int v_offset = z * psc(cstep) + y * psc(w) + x; + buffer_cp1(top_blob_data, gi, bottom_blob_data, v_offset); +#endif + } + else if (per_channel_pad == 1) + { +#if NCNN_image_shader + image3d_cp1(top_blob, ivec3(gx, gy, gz), per_channel_pad_blob, ivec3(gz, 0, 0)); +#else + buffer_cp1(top_blob_data, gi, per_channel_pad_blob_data, gz); +#endif + } + else + { + afp v = afp(value); +#if NCNN_image_shader + image3d_st1(top_blob, ivec3(gx, gy, gz), v); +#else + buffer_st1(top_blob_data, gi, v); +#endif + } + } + // TODO implement type 1 and 2 + } +} diff --git a/src/layer/vulkan/shader/padding_3d_pack4.comp b/src/layer/vulkan/shader/padding_3d_pack4.comp new file mode 100644 index 000000000..1d06ee3fb --- /dev/null +++ b/src/layer/vulkan/shader/padding_3d_pack4.comp @@ -0,0 +1,124 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#version 450 + +#if NCNN_fp16_storage +#extension GL_EXT_shader_16bit_storage: require +#endif +#if NCNN_fp16_arithmetic +#extension GL_EXT_shader_explicit_arithmetic_types_float16: require +#endif + +layout (constant_id = 0) const int type = 1; +layout (constant_id = 1) const float value = 0; +layout (constant_id = 2) const int per_channel_pad = 0; + +#define shape_constant_id_offset 3 +layout (constant_id = shape_constant_id_offset + 0) const int dims = 0; +layout (constant_id = shape_constant_id_offset + 1) const int w = 0; +layout (constant_id = shape_constant_id_offset + 2) const int h = 0; +layout (constant_id = shape_constant_id_offset + 3) const int d = 0; +layout (constant_id = shape_constant_id_offset + 4) const int c = 0; +layout (constant_id = shape_constant_id_offset + 5) const int cstep = 0; + +layout (constant_id = shape_constant_id_offset + 6) const int outdims = 0; +layout (constant_id = shape_constant_id_offset + 7) const int outw = 0; +layout (constant_id = shape_constant_id_offset + 8) const int outh = 0; +layout (constant_id = shape_constant_id_offset + 9) const int outd = 0; +layout (constant_id = shape_constant_id_offset + 10) const int outc = 0; +layout (constant_id = shape_constant_id_offset + 11) const int outcstep = 0; + +#if NCNN_image_shader +layout (binding = 0) uniform unfp sampler3D bottom_blob; +layout (binding = 1, imfmtc4) writeonly uniform unfp image3D top_blob; +layout (binding = 2) uniform unfp sampler3D per_channel_pad_blob; +#else +layout (binding = 0) readonly buffer bottom_blob { sfpvec4 bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { sfpvec4 top_blob_data[]; }; +layout (binding = 2) readonly buffer per_channel_pad_blob { sfpvec4 per_channel_pad_blob_data[]; }; +#endif + +layout (push_constant) uniform parameter +{ + int dims; + int w; + int h; + int d; + int c; + int cstep; + + int outdims; + int outw; + int outh; + int outd; + int outc; + int outcstep; + + int left; + int top; + int front; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= psc(outw) || gy >= psc(outh) * psc(outd) || gz >= psc(outc)) + return; + + // if (psc(dims) == 4) + { + const int gi = gz * psc(outcstep) + gy * psc(outw) + gx; + + int x = gx - p.left; + int yh = gy % psc(outh) - p.top; + int yd = gy / psc(outh) - p.front; + int y = yd * psc(h) + yh; + int z = gz; + + if (type == 0) + { + if (x >= 0 && x < psc(w) && yh >= 0 && yh < psc(h) && yd >= 0 && yd < psc(d) && z >= 0 && z < psc(c)) + { +#if NCNN_image_shader + image3d_cp4(top_blob, ivec3(gx, gy, gz), bottom_blob, ivec3(x, y, z)); +#else + int v_offset = z * psc(cstep) + y * psc(w) + x; + buffer_cp4(top_blob_data, gi, bottom_blob_data, v_offset); +#endif + } + else if (per_channel_pad == 1) + { +#if NCNN_image_shader + image3d_cp4(top_blob, ivec3(gx, gy, gz), per_channel_pad_blob, ivec3(gz, 0, 0)); +#else + buffer_cp4(top_blob_data, gi, per_channel_pad_blob_data, gz); +#endif + } + else + { + afpvec4 v = afpvec4(value); +#if NCNN_image_shader + image3d_st4(top_blob, ivec3(gx, gy, gz), v); +#else + buffer_st4(top_blob_data, gi, v); +#endif + } + } + // TODO implement type 1 and 2 + } +} diff --git a/src/layer/vulkan/shader/padding_3d_pack8.comp b/src/layer/vulkan/shader/padding_3d_pack8.comp new file mode 100644 index 000000000..269d8525a --- /dev/null +++ b/src/layer/vulkan/shader/padding_3d_pack8.comp @@ -0,0 +1,124 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#version 450 + +#if NCNN_fp16_storage +#extension GL_EXT_shader_16bit_storage: require +#endif +#if NCNN_fp16_arithmetic +#extension GL_EXT_shader_explicit_arithmetic_types_float16: require +#endif + +layout (constant_id = 0) const int type = 1; +layout (constant_id = 1) const float value = 0; +layout (constant_id = 2) const int per_channel_pad = 0; + +#define shape_constant_id_offset 3 +layout (constant_id = shape_constant_id_offset + 0) const int dims = 0; +layout (constant_id = shape_constant_id_offset + 1) const int w = 0; +layout (constant_id = shape_constant_id_offset + 2) const int h = 0; +layout (constant_id = shape_constant_id_offset + 3) const int d = 0; +layout (constant_id = shape_constant_id_offset + 4) const int c = 0; +layout (constant_id = shape_constant_id_offset + 5) const int cstep = 0; + +layout (constant_id = shape_constant_id_offset + 6) const int outdims = 0; +layout (constant_id = shape_constant_id_offset + 7) const int outw = 0; +layout (constant_id = shape_constant_id_offset + 8) const int outh = 0; +layout (constant_id = shape_constant_id_offset + 9) const int outd = 0; +layout (constant_id = shape_constant_id_offset + 10) const int outc = 0; +layout (constant_id = shape_constant_id_offset + 11) const int outcstep = 0; + +#if NCNN_image_shader +layout (binding = 0) uniform unfp sampler3D bottom_blob; +layout (binding = 1, imfmtc4) writeonly uniform unfp image3D top_blob; +layout (binding = 2) uniform unfp sampler3D per_channel_pad_blob; +#else +layout (binding = 0) readonly buffer bottom_blob { sfpvec8 bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { sfpvec8 top_blob_data[]; }; +layout (binding = 2) readonly buffer per_channel_pad_blob { sfpvec8 per_channel_pad_blob_data[]; }; +#endif + +layout (push_constant) uniform parameter +{ + int dims; + int w; + int h; + int d; + int c; + int cstep; + + int outdims; + int outw; + int outh; + int outd; + int outc; + int outcstep; + + int left; + int top; + int front; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= psc(outw) || gy >= psc(outh) * psc(outd) || gz >= psc(outc)) + return; + + // if (psc(dims) == 4) + { + const int gi = gz * psc(outcstep) + gy * psc(outw) + gx; + + int x = gx - p.left; + int yh = gy % psc(outh) - p.top; + int yd = gy / psc(outh) - p.front; + int y = yd * psc(h) + yh; + int z = gz; + + if (type == 0) + { + if (x >= 0 && x < psc(w) && yh >= 0 && yh < psc(h) && yd >= 0 && yd < psc(d) && z >= 0 && z < psc(c)) + { +#if NCNN_image_shader + image3d_cp8(top_blob, ivec3(gx, gy, gz), bottom_blob, ivec3(x, y, z)); +#else + int v_offset = z * psc(cstep) + y * psc(w) + x; + buffer_cp8(top_blob_data, gi, bottom_blob_data, v_offset); +#endif + } + else if (per_channel_pad == 1) + { +#if NCNN_image_shader + image3d_cp8(top_blob, ivec3(gx, gy, gz), per_channel_pad_blob, ivec3(gz, 0, 0)); +#else + buffer_cp8(top_blob_data, gi, per_channel_pad_blob_data, gz); +#endif + } + else + { + afpvec8 v = afpvec8(afpvec4(value), afpvec4(value)); +#if NCNN_image_shader + image3d_st8(top_blob, ivec3(gx, gy, gz), v); +#else + buffer_st8(top_blob_data, gi, v); +#endif + } + } + // TODO implement type 1 and 2 + } +} diff --git a/src/layer/x86/cast_x86.cpp b/src/layer/x86/cast_x86.cpp index 5148206f0..5f737d7bb 100644 --- a/src/layer/x86/cast_x86.cpp +++ b/src/layer/x86/cast_x86.cpp @@ -83,6 +83,7 @@ int Cast_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -127,10 +128,14 @@ int Cast_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) { top_blob.create(w, h, channels, out_elemsize, elempack, opt.blob_allocator); } + else if (dims == 4) + { + top_blob.create(w, h, d, channels, out_elemsize, elempack, opt.blob_allocator); + } if (top_blob.empty()) return -100; - int size = w * h * elempack; + int size = w * h * d * elempack; if (type_from == 1 && type_to == 2) { int nn = size >> 3; diff --git a/src/layer/x86/convolution_3x3_int8.h b/src/layer/x86/convolution_3x3_int8.h index c03c12efc..a5c5dfe4e 100644 --- a/src/layer/x86/convolution_3x3_int8.h +++ b/src/layer/x86/convolution_3x3_int8.h @@ -80,7 +80,7 @@ static void conv3x3s1_int8_sse(const Mat& bottom_blob, Mat& top_blob, const Mat& static void conv3x3s1_winograd23_transform_kernel_int8_sse(const Mat& kernel, Mat& kernel_tm, int inch, int outch, const Option& opt) { - kernel_tm.create(4 * 4, inch, outch, 2ul); + kernel_tm.create(4 * 4, inch, outch, (size_t)2u); // G const short ktm[4][3] = { @@ -516,7 +516,7 @@ static void conv3x3s1_winograd23_int8_sse(const Mat& bottom_blob, Mat& top_blob, static void conv3x3s1_winograd43_transform_kernel_int8_sse(const Mat& kernel, Mat& kernel_tm, int inch, int outch, const Option& opt) { - kernel_tm.create(6 * 6, inch, outch, 2ul); + kernel_tm.create(6 * 6, inch, outch, (size_t)2u); // G // const float ktm[6][3] = { diff --git a/src/layer/x86/convolution_sgemm_pack8to4_int8.h b/src/layer/x86/convolution_sgemm_pack8to4_int8.h index 52bb21f10..0d66dc07a 100644 --- a/src/layer/x86/convolution_sgemm_pack8to4_int8.h +++ b/src/layer/x86/convolution_sgemm_pack8to4_int8.h @@ -272,7 +272,7 @@ static void convolution_im2col_sgemm_transform_kernel_pack8to4_int8_sse(const Ma // src = maxk-inch-outch // dst = 8a-4b-maxk-inch/8a-outch/4b Mat kernel = _kernel.reshape(maxk, inch, outch); - kernel_tm.create(32 * maxk, inch / 8, outch / 4, 1u); + kernel_tm.create(32 * maxk, inch / 8, outch / 4, (size_t)1u); for (int q = 0; q + 3 < outch; q += 4) { diff --git a/src/layer/x86/packing_x86.cpp b/src/layer/x86/packing_x86.cpp index 5e1cc247b..3db54c939 100644 --- a/src/layer/x86/packing_x86.cpp +++ b/src/layer/x86/packing_x86.cpp @@ -64,6 +64,7 @@ int Packing_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -80,7 +81,7 @@ int Packing_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -346,13 +347,16 @@ int Packing_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; @@ -628,6 +632,7 @@ int Packing_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; @@ -644,7 +649,7 @@ int Packing_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio top_blob = bottom_blob; return 0; } - if (dims == 3 && channels * elempack % out_elempack != 0) + if ((dims == 3 || dims == 4) && channels * elempack % out_elempack != 0) { top_blob = bottom_blob; return 0; @@ -738,13 +743,16 @@ int Packing_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio return 0; } - if (dims == 3) + if (dims == 3 || dims == 4) { - int size = w * h; + int size = w * h * d; int outc = channels * elempack / out_elempack; size_t out_elemsize = elemsize / elempack * out_elempack; - top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + if (dims == 3) + top_blob.create(w, h, outc, out_elemsize, out_elempack, opt.blob_allocator); + else // if (dims == 4) + top_blob.create(w, h, d, outc, out_elemsize, out_elempack, opt.blob_allocator); if (top_blob.empty()) return -100; diff --git a/src/layer/x86/padding_x86.cpp b/src/layer/x86/padding_x86.cpp index b5b1be9fd..0ebcdfa61 100644 --- a/src/layer/x86/padding_x86.cpp +++ b/src/layer/x86/padding_x86.cpp @@ -53,6 +53,7 @@ int Padding_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -139,6 +140,49 @@ int Padding_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + __m256 pad_value = per_channel_pad_data_size ? _mm256_loadu_ps((const float*)per_channel_pad_data + q * 8) : _mm256_set1_ps(value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack8_avx(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack8_avx(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack8_avx(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __AVX__ @@ -233,6 +277,49 @@ int Padding_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + __m128 pad_value = per_channel_pad_data_size ? _mm_loadu_ps((const float*)per_channel_pad_data + q * 4) : _mm_set1_ps(value); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack4_sse(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack4_sse(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack4_sse(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __SSE2__ @@ -252,6 +339,7 @@ int Padding_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio { int w = bottom_blob.w; int h = bottom_blob.h; + int d = bottom_blob.d; int channels = bottom_blob.c; int dims = bottom_blob.dims; size_t elemsize = bottom_blob.elemsize; @@ -341,6 +429,52 @@ int Padding_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Optio return 0; } } + + if (dims == 4) + { + int outw = w + left + right; + int outh = h + top + bottom; + int outd = d + front + behind; + + top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator); + if (top_blob.empty()) + return -100; + + if (type == 0) + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < channels; q++) + { + // TODO perchannel + // int64_t pad_value = per_channel_pad_data_size ? vld1_s8(per_channel_pad_data + q * 8) : vdup_n_s8((signed char)value); + int64_t v8 = (int64_t)value; + int64_t pad_value = v8 | (v8 << 8) | (v8 << 16) | (v8 << 24) | (v8 << 32) | (v8 << 40) | (v8 << 48) | (v8 << 56); + + for (int z = 0; z < outd; z++) + { + Mat borderm = top_blob.channel(q).depth(z); + + // depth padding + if ((z - front) < 0 || (z - front) >= d) + { + borderm.fill(pad_value); + } + else + { + const Mat m = bottom_blob.channel(q).depth(z - front); + if (type == 0) + padding_constant_pack8_int8_sse(m, borderm, top, bottom, left, right, pad_value); + if (type == 1) + padding_replicate_pack8_int8_sse(m, borderm, top, bottom, left, right); + if (type == 2) + padding_reflect_pack8_int8_sse(m, borderm, top, bottom, left, right); + } + } + } + + return 0; + } + } } #endif // __SSE2__ diff --git a/src/mat.cpp b/src/mat.cpp index 09a2f5f9e..780516c77 100644 --- a/src/mat.cpp +++ b/src/mat.cpp @@ -45,6 +45,8 @@ Mat Mat::clone(Allocator* _allocator) const m.create(w, h, elemsize, elempack, _allocator); else if (dims == 3) m.create(w, h, c, elemsize, elempack, _allocator); + else if (dims == 4) + m.create(w, h, d, c, elemsize, elempack, _allocator); if (total() > 0) { @@ -53,7 +55,7 @@ Mat Mat::clone(Allocator* _allocator) const else { // copy by channel for differnet cstep - size_t size = (size_t)w * h * elemsize; + size_t size = (size_t)w * h * d * elemsize; for (int i = 0; i < c; i++) { memcpy(m.channel(i), channel(i), size); @@ -71,10 +73,10 @@ void Mat::clone_from(const ncnn::Mat& mat, Allocator* allocator) Mat Mat::reshape(int _w, Allocator* _allocator) const { - if (w * h * c != _w) + if (w * h * d * c != _w) return Mat(); - if (dims == 3 && cstep != (size_t)w * h) + if (dims >= 3 && cstep != (size_t)w * h * d) { Mat m; m.create(_w, elemsize, elempack, _allocator); @@ -83,8 +85,8 @@ Mat Mat::reshape(int _w, Allocator* _allocator) const for (int i = 0; i < c; i++) { const void* ptr = (unsigned char*)data + i * cstep * elemsize; - void* mptr = (unsigned char*)m.data + (size_t)i * w * h * elemsize; - memcpy(mptr, ptr, (size_t)w * h * elemsize); + void* mptr = (unsigned char*)m.data + (size_t)i * w * h * d * elemsize; + memcpy(mptr, ptr, (size_t)w * h * d * elemsize); } return m; @@ -95,6 +97,7 @@ Mat Mat::reshape(int _w, Allocator* _allocator) const m.dims = 1; m.w = _w; m.h = 1; + m.d = 1; m.c = 1; m.cstep = _w; @@ -104,10 +107,10 @@ Mat Mat::reshape(int _w, Allocator* _allocator) const Mat Mat::reshape(int _w, int _h, Allocator* _allocator) const { - if (w * h * c != _w * _h) + if (w * h * d * c != _w * _h) return Mat(); - if (dims == 3 && cstep != (size_t)w * h) + if (dims >= 3 && cstep != (size_t)w * h * d) { Mat m; m.create(_w, _h, elemsize, elempack, _allocator); @@ -116,8 +119,8 @@ Mat Mat::reshape(int _w, int _h, Allocator* _allocator) const for (int i = 0; i < c; i++) { const void* ptr = (unsigned char*)data + i * cstep * elemsize; - void* mptr = (unsigned char*)m.data + (size_t)i * w * h * elemsize; - memcpy(mptr, ptr, (size_t)w * h * elemsize); + void* mptr = (unsigned char*)m.data + (size_t)i * w * h * d * elemsize; + memcpy(mptr, ptr, (size_t)w * h * d * elemsize); } return m; @@ -128,6 +131,7 @@ Mat Mat::reshape(int _w, int _h, Allocator* _allocator) const m.dims = 2; m.w = _w; m.h = _h; + m.d = 1; m.c = 1; m.cstep = (size_t)_w * _h; @@ -137,7 +141,7 @@ Mat Mat::reshape(int _w, int _h, Allocator* _allocator) const Mat Mat::reshape(int _w, int _h, int _c, Allocator* _allocator) const { - if (w * h * c != _w * _h * _c) + if (w * h * d * c != _w * _h * _c) return Mat(); if (dims < 3) @@ -170,6 +174,7 @@ Mat Mat::reshape(int _w, int _h, int _c, Allocator* _allocator) const m.dims = 3; m.w = _w; m.h = _h; + m.d = 1; m.c = _c; m.cstep = alignSize((size_t)_w * _h * elemsize, 16) / elemsize; @@ -177,6 +182,49 @@ Mat Mat::reshape(int _w, int _h, int _c, Allocator* _allocator) const return m; } +Mat Mat::reshape(int _w, int _h, int _d, int _c, Allocator* _allocator) const +{ + if (w * h * d * c != _w * _h * _d * _c) + return Mat(); + + if (dims < 3) + { + if ((size_t)_w * _h * _d != alignSize((size_t)_w * _h * _d * elemsize, 16) / elemsize) + { + Mat m; + m.create(_w, _h, _d, _c, elemsize, elempack, _allocator); + + // align channel + for (int i = 0; i < _c; i++) + { + const void* ptr = (unsigned char*)data + (size_t)i * _w * _h * _d * elemsize; + void* mptr = (unsigned char*)m.data + i * m.cstep * m.elemsize; + memcpy(mptr, ptr, (size_t)_w * _h * _d * elemsize); + } + + return m; + } + } + else if (c != _c) + { + // flatten and then align + Mat tmp = reshape(_w * _h * _d * _c, _allocator); + return tmp.reshape(_w, _h, _d, _c, _allocator); + } + + Mat m = *this; + + m.dims = 4; + m.w = _w; + m.h = _h; + m.d = _d; + m.c = _c; + + m.cstep = alignSize((size_t)_w * _h * _d * elemsize, 16) / elemsize; + + return m; +} + void Mat::create(int _w, size_t _elemsize, Allocator* _allocator) { if (dims == 1 && w == _w && elemsize == _elemsize && elempack == 1 && allocator == _allocator) @@ -191,6 +239,7 @@ void Mat::create(int _w, size_t _elemsize, Allocator* _allocator) dims = 1; w = _w; h = 1; + d = 1; c = 1; cstep = w; @@ -221,6 +270,7 @@ void Mat::create(int _w, int _h, size_t _elemsize, Allocator* _allocator) dims = 2; w = _w; h = _h; + d = 1; c = 1; cstep = (size_t)w * h; @@ -251,6 +301,7 @@ void Mat::create(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator dims = 3; w = _w; h = _h; + d = 1; c = _c; cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; @@ -267,6 +318,37 @@ void Mat::create(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator } } +void Mat::create(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == 1 && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = 1; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; + + if (total() > 0) + { + size_t totalsize = alignSize(total() * elemsize, 4); + if (allocator) + data = allocator->fastMalloc(totalsize + (int)sizeof(*refcount)); + else + data = fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((unsigned char*)data) + totalsize); + *refcount = 1; + } +} + void Mat::create(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) { if (dims == 1 && w == _w && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) @@ -281,6 +363,7 @@ void Mat::create(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) dims = 1; w = _w; h = 1; + d = 1; c = 1; cstep = w; @@ -311,6 +394,7 @@ void Mat::create(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _al dims = 2; w = _w; h = _h; + d = 1; c = 1; cstep = (size_t)w * h; @@ -341,6 +425,7 @@ void Mat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, Alloca dims = 3; w = _w; h = _h; + d = 1; c = _c; cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; @@ -357,6 +442,37 @@ void Mat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, Alloca } } +void Mat::create(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = _elempack; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; + + if (total() > 0) + { + size_t totalsize = alignSize(total() * elemsize, 4); + if (allocator) + data = allocator->fastMalloc(totalsize + (int)sizeof(*refcount)); + else + data = fastMalloc(totalsize + (int)sizeof(*refcount)); + refcount = (int*)(((unsigned char*)data) + totalsize); + *refcount = 1; + } +} + void Mat::create_like(const Mat& m, Allocator* _allocator) { int _dims = m.dims; @@ -366,6 +482,8 @@ void Mat::create_like(const Mat& m, Allocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } #if NCNN_VULKAN @@ -378,6 +496,8 @@ void Mat::create_like(const VkMat& m, Allocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } void Mat::create_like(const VkImageMat& im, Allocator* _allocator) @@ -389,6 +509,8 @@ void Mat::create_like(const VkImageMat& im, Allocator* _allocator) create(im.w, im.h, im.elemsize, im.elempack, _allocator); if (_dims == 3) create(im.w, im.h, im.c, im.elemsize, im.elempack, _allocator); + if (_dims == 4) + create(im.w, im.h, im.d, im.c, im.elemsize, im.elempack, _allocator); } #endif // NCNN_VULKAN @@ -407,6 +529,7 @@ void VkMat::create(int _w, size_t _elemsize, VkAllocator* _allocator) dims = 1; w = _w; h = 1; + d = 1; c = 1; cstep = w; @@ -436,6 +559,7 @@ void VkMat::create(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) dims = 2; w = _w; h = _h; + d = 1; c = 1; cstep = w * h; @@ -465,6 +589,7 @@ void VkMat::create(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _alloc dims = 3; w = _w; h = _h; + d = 1; c = _c; cstep = alignSize(w * h * elemsize, 16) / elemsize; @@ -480,6 +605,36 @@ void VkMat::create(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _alloc } } +void VkMat::create(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == 1 && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = 1; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; + + if (total() > 0) + { + size_t totalsize = alignSize(total() * elemsize, 4); + + data = allocator->fastMalloc(totalsize); + + refcount = (int*)((unsigned char*)data + offsetof(VkBufferMemory, refcount)); + *refcount = 1; + } +} + void VkMat::create(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) { if (dims == 1 && w == _w && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) @@ -494,6 +649,7 @@ void VkMat::create(int _w, size_t _elemsize, int _elempack, VkAllocator* _alloca dims = 1; w = _w; h = 1; + d = 1; c = 1; cstep = w; @@ -523,6 +679,7 @@ void VkMat::create(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* dims = 2; w = _w; h = _h; + d = 1; c = 1; cstep = w * h; @@ -552,6 +709,7 @@ void VkMat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAl dims = 3; w = _w; h = _h; + d = 1; c = _c; cstep = alignSize(w * h * elemsize, 16) / elemsize; @@ -567,6 +725,36 @@ void VkMat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAl } } +void VkMat::create(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = _elempack; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; + + if (total() > 0) + { + size_t totalsize = alignSize(total() * elemsize, 4); + + data = allocator->fastMalloc(totalsize); + + refcount = (int*)((unsigned char*)data + offsetof(VkBufferMemory, refcount)); + *refcount = 1; + } +} + void VkMat::create_like(const Mat& m, VkAllocator* _allocator) { int _dims = m.dims; @@ -576,6 +764,8 @@ void VkMat::create_like(const Mat& m, VkAllocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } void VkMat::create_like(const VkMat& m, VkAllocator* _allocator) @@ -587,6 +777,8 @@ void VkMat::create_like(const VkMat& m, VkAllocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } void VkMat::create_like(const VkImageMat& im, VkAllocator* _allocator) @@ -598,6 +790,8 @@ void VkMat::create_like(const VkImageMat& im, VkAllocator* _allocator) create(im.w, im.h, im.elemsize, im.elempack, _allocator); if (_dims == 3) create(im.w, im.h, im.c, im.elemsize, im.elempack, _allocator); + if (_dims == 4) + create(im.w, im.h, im.d, im.c, im.elemsize, im.elempack, _allocator); } void VkImageMat::create(int _w, size_t _elemsize, VkAllocator* _allocator) @@ -614,6 +808,7 @@ void VkImageMat::create(int _w, size_t _elemsize, VkAllocator* _allocator) dims = 1; w = _w; h = 1; + d = 1; c = 1; if (total() > 0) @@ -641,6 +836,7 @@ void VkImageMat::create(int _w, int _h, size_t _elemsize, VkAllocator* _allocato dims = 2; w = _w; h = _h; + d = 1; c = 1; if (total() > 0) @@ -668,6 +864,7 @@ void VkImageMat::create(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _ dims = 3; w = _w; h = _h; + d = 1; c = _c; if (total() > 0) @@ -681,6 +878,35 @@ void VkImageMat::create(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _ } } +void VkImageMat::create(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == 1 && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = 1; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + if (total() > 0) + { + // underlying image is 3d + data = allocator->fastMalloc(w, h * d, c, elemsize, elempack); + if (!data) + return; + + refcount = (int*)((unsigned char*)data + offsetof(VkImageMemory, refcount)); + *refcount = 1; + } +} + void VkImageMat::create(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) { if (dims == 1 && w == _w && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) @@ -695,6 +921,7 @@ void VkImageMat::create(int _w, size_t _elemsize, int _elempack, VkAllocator* _a dims = 1; w = _w; h = 1; + d = 1; c = 1; if (total() > 0) @@ -722,6 +949,7 @@ void VkImageMat::create(int _w, int _h, size_t _elemsize, int _elempack, VkAlloc dims = 2; w = _w; h = _h; + d = 1; c = 1; if (total() > 0) @@ -749,6 +977,7 @@ void VkImageMat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, dims = 3; w = _w; h = _h; + d = 1; c = _c; if (total() > 0) @@ -762,6 +991,35 @@ void VkImageMat::create(int _w, int _h, int _c, size_t _elemsize, int _elempack, } } +void VkImageMat::create(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) +{ + if (dims == 4 && w == _w && h == _h && d == _d && c == _c && elemsize == _elemsize && elempack == _elempack && allocator == _allocator) + return; + + release(); + + elemsize = _elemsize; + elempack = _elempack; + allocator = _allocator; + + dims = 4; + w = _w; + h = _h; + d = _d; + c = _c; + + if (total() > 0) + { + // underlying image is 3d + data = allocator->fastMalloc(w, h * d, c, elemsize, elempack); + if (!data) + return; + + refcount = (int*)((unsigned char*)data + offsetof(VkImageMemory, refcount)); + *refcount = 1; + } +} + void VkImageMat::create_like(const Mat& m, VkAllocator* _allocator) { int _dims = m.dims; @@ -771,6 +1029,8 @@ void VkImageMat::create_like(const Mat& m, VkAllocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } void VkImageMat::create_like(const VkMat& m, VkAllocator* _allocator) @@ -782,6 +1042,8 @@ void VkImageMat::create_like(const VkMat& m, VkAllocator* _allocator) create(m.w, m.h, m.elemsize, m.elempack, _allocator); if (_dims == 3) create(m.w, m.h, m.c, m.elemsize, m.elempack, _allocator); + if (_dims == 4) + create(m.w, m.h, m.d, m.c, m.elemsize, m.elempack, _allocator); } void VkImageMat::create_like(const VkImageMat& im, VkAllocator* _allocator) @@ -793,6 +1055,8 @@ void VkImageMat::create_like(const VkImageMat& im, VkAllocator* _allocator) create(im.w, im.h, im.elemsize, im.elempack, _allocator); if (_dims == 3) create(im.w, im.h, im.c, im.elemsize, im.elempack, _allocator); + if (_dims == 4) + create(im.w, im.h, im.d, im.c, im.elemsize, im.elempack, _allocator); } #endif // NCNN_VULKAN @@ -1085,6 +1349,31 @@ void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, i delete padding; } +void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt) +{ + Layer* padding = create_layer(LayerType::Padding); + + ParamDict pd; + pd.set(0, top); + pd.set(1, bottom); + pd.set(2, left); + pd.set(3, right); + pd.set(4, type); + pd.set(5, v); + pd.set(7, front); + pd.set(8, behind); + + padding->load_param(pd); + + padding->create_pipeline(opt); + + padding->forward(src, dst, opt); + + padding->destroy_pipeline(opt); + + delete padding; +} + void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt) { if (left + right > src.w || top + bottom > src.h) diff --git a/src/mat.h b/src/mat.h index 93443db13..79434128b 100644 --- a/src/mat.h +++ b/src/mat.h @@ -71,12 +71,16 @@ public: Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); // dim Mat(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // cube + Mat(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); // packed vec Mat(int w, size_t elemsize, int elempack, Allocator* allocator = 0); // packed image Mat(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); // packed dim Mat(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // packed cube + Mat(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); // copy Mat(const Mat& m); // external vec @@ -85,12 +89,16 @@ public: Mat(int w, int h, void* data, size_t elemsize = 4u, Allocator* allocator = 0); // external dim Mat(int w, int h, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); + // external cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize = 4u, Allocator* allocator = 0); // external packed vec Mat(int w, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); // external packed image Mat(int w, int h, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); // external packed dim Mat(int w, int h, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); + // external packed cube + Mat(int w, int h, int d, int c, void* data, size_t elemsize, int elempack, Allocator* allocator = 0); // release ~Mat(); // assign @@ -135,18 +143,24 @@ public: Mat reshape(int w, int h, Allocator* allocator = 0) const; // reshape dim Mat reshape(int w, int h, int c, Allocator* allocator = 0) const; + // reshape cube + Mat reshape(int w, int h, int d, int c, Allocator* allocator = 0) const; // allocate vec void create(int w, size_t elemsize = 4u, Allocator* allocator = 0); // allocate image void create(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0); // allocate dim void create(int w, int h, int c, size_t elemsize = 4u, Allocator* allocator = 0); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize = 4u, Allocator* allocator = 0); // allocate packed vec void create(int w, size_t elemsize, int elempack, Allocator* allocator = 0); // allocate packed image void create(int w, int h, size_t elemsize, int elempack, Allocator* allocator = 0); // allocate packed dim void create(int w, int h, int c, size_t elemsize, int elempack, Allocator* allocator = 0); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, Allocator* allocator = 0); // allocate like void create_like(const Mat& m, Allocator* allocator = 0); #if NCNN_VULKAN @@ -172,6 +186,8 @@ public: // data reference Mat channel(int c); const Mat channel(int c) const; + Mat depth(int z); + const Mat depth(int z) const; float* row(int y); const float* row(int y) const; template @@ -182,6 +198,8 @@ public: // range reference Mat channel_range(int c, int channels); const Mat channel_range(int c, int channels) const; + Mat depth_range(int z, int depths); + const Mat depth_range(int z, int depths) const; Mat row_range(int y, int rows); const Mat row_range(int y, int rows) const; Mat range(int x, int n); @@ -298,9 +316,9 @@ public: size_t elemsize; // packed count inside element - // c/1-h-w-1 h/1-w-1 w/1-1 scalar - // c/4-h-w-4 h/4-w-4 w/4-4 sse/neon - // c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 int elempack; // the allocator @@ -311,6 +329,7 @@ public: int w; int h; + int d; int c; size_t cstep; @@ -330,12 +349,16 @@ public: VkMat(int w, int h, size_t elemsize, VkAllocator* allocator); // dim VkMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); // packed vec VkMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); // packed image VkMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); // packed dim VkMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); // copy VkMat(const VkMat& m); // external vec @@ -344,12 +367,16 @@ public: VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); // external dim VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, VkAllocator* allocator); // external packed vec VkMat(int w, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // external packed image VkMat(int w, int h, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // external packed dim VkMat(int w, int h, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkMat(int w, int h, int d, int c, VkBufferMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // release ~VkMat(); // assign @@ -360,12 +387,16 @@ public: void create(int w, int h, size_t elemsize, VkAllocator* allocator); // allocate dim void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); // allocate packed vec void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); // allocate packed image void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); // allocate packed dim void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); // allocate like void create_like(const Mat& m, VkAllocator* allocator); // allocate like @@ -411,9 +442,9 @@ public: size_t elemsize; // packed count inside element - // c/1-h-w-1 h/1-w-1 w/1-1 scalar - // c/4-h-w-4 h/4-w-4 w/4-4 sse/neon - // c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 int elempack; // the allocator @@ -424,6 +455,7 @@ public: int w; int h; + int d; int c; size_t cstep; @@ -440,12 +472,16 @@ public: VkImageMat(int w, int h, size_t elemsize, VkAllocator* allocator); // dim VkImageMat(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); // packed vec VkImageMat(int w, size_t elemsize, int elempack, VkAllocator* allocator); // packed image VkImageMat(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); // packed dim VkImageMat(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // packed cube + VkImageMat(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); // copy VkImageMat(const VkImageMat& m); // external vec @@ -454,12 +490,16 @@ public: VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); // external dim VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); + // external cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, VkAllocator* allocator); // external packed vec VkImageMat(int w, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // external packed image VkImageMat(int w, int h, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // external packed dim VkImageMat(int w, int h, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); + // external packed cube + VkImageMat(int w, int h, int d, int c, VkImageMemory* data, size_t elemsize, int elempack, VkAllocator* allocator); // release ~VkImageMat(); // assign @@ -470,12 +510,16 @@ public: void create(int w, int h, size_t elemsize, VkAllocator* allocator); // allocate dim void create(int w, int h, int c, size_t elemsize, VkAllocator* allocator); + // allocate cube + void create(int w, int h, int d, int c, size_t elemsize, VkAllocator* allocator); // allocate packed vec void create(int w, size_t elemsize, int elempack, VkAllocator* allocator); // allocate packed image void create(int w, int h, size_t elemsize, int elempack, VkAllocator* allocator); // allocate packed dim void create(int w, int h, int c, size_t elemsize, int elempack, VkAllocator* allocator); + // allocate packed cube + void create(int w, int h, int d, int c, size_t elemsize, int elempack, VkAllocator* allocator); // allocate like void create_like(const Mat& m, VkAllocator* allocator); // allocate like @@ -527,9 +571,9 @@ public: size_t elemsize; // packed count inside element - // c/1-h-w-1 h/1-w-1 w/1-1 scalar - // c/4-h-w-4 h/4-w-4 w/4-4 sse/neon - // c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 + // c/1-d-h-w-1 c/1-h-w-1 h/1-w-1 w/1-1 scalar + // c/4-d-h-w-4 c/4-h-w-4 h/4-w-4 w/4-4 sse/neon + // c/8-d-h-w-8 c/8-h-w-8 h/8-w-8 w/8-8 avx/fp16 int elempack; // the allocator @@ -540,6 +584,7 @@ public: int w; int h; + int d; int c; }; @@ -724,6 +769,7 @@ enum BorderType BORDER_TRANSPARENT = -233, }; NCNN_EXPORT void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, const Option& opt = Option()); +NCNN_EXPORT void copy_make_border_3d(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int front, int behind, int type, float v, const Option& opt = Option()); NCNN_EXPORT void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, const Option& opt = Option()); NCNN_EXPORT void resize_nearest(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); NCNN_EXPORT void resize_bilinear(const Mat& src, Mat& dst, int w, int h, const Option& opt = Option()); @@ -740,88 +786,112 @@ NCNN_EXPORT void dequantize_from_int32(const Mat& src, Mat& dst, const Mat& scal NCNN_EXPORT void requantize_from_int32_to_int8(const Mat& src, Mat& dst, const Mat& scale_in_data, const Mat& scale_out_data, const Mat& bias_data, int activation_type, const Mat& activation_params, const Option& opt = Option()); inline Mat::Mat() - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { } inline Mat::Mat(int _w, size_t _elemsize, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _elemsize, _allocator); } inline Mat::Mat(int _w, int _h, size_t _elemsize, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _elemsize, _allocator); } inline Mat::Mat(int _w, int _h, int _c, size_t _elemsize, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _c, _elemsize, _allocator); } +inline Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + inline Mat::Mat(int _w, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _elemsize, _elempack, _allocator); } inline Mat::Mat(int _w, int _h, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _elemsize, _elempack, _allocator); } inline Mat::Mat(int _w, int _h, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _c, _elemsize, _elempack, _allocator); } +inline Mat::Mat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + inline Mat::Mat(const Mat& m) - : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), c(m.c), cstep(m.cstep) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c), cstep(m.cstep) { addref(); } inline Mat::Mat(int _w, void* _data, size_t _elemsize, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { cstep = w; } inline Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { cstep = (size_t)w * h; } inline Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) { cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; } +inline Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + inline Mat::Mat(int _w, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { cstep = w; } inline Mat::Mat(int _w, int _h, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { cstep = (size_t)w * h; } inline Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) { cstep = alignSize((size_t)w * h * elemsize, 16) / elemsize; } +inline Mat::Mat(int _w, int _h, int _d, int _c, void* _data, size_t _elemsize, int _elempack, Allocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize((size_t)w * h * d * elemsize, 16) / elemsize; +} + inline Mat::~Mat() { release(); @@ -1125,6 +1195,7 @@ inline Mat& Mat::operator=(const Mat& m) dims = m.dims; w = m.w; h = m.h; + d = m.d; c = m.c; cstep = m.cstep; @@ -1156,6 +1227,7 @@ inline void Mat::release() dims = 0; w = 0; h = 0; + d = 0; c = 0; cstep = 0; @@ -1186,18 +1258,42 @@ inline Mat Mat::shape() const return Mat(w, h * elempack, (void*)0); if (dims == 3) return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); return Mat(); } inline Mat Mat::channel(int _c) { - return Mat(w, h, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + if (dims == 3) + return Mat(w, h, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + + // if (dims == 4) + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; } inline const Mat Mat::channel(int _c) const { - return Mat(w, h, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + if (dims == 3) + return Mat(w, h, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + + // if (dims == 4) + Mat m(w, h, d, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +inline Mat Mat::depth(int z) +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); +} + +inline const Mat Mat::depth(int z) const +{ + return Mat(w, h, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); } inline float* Mat::row(int y) @@ -1224,12 +1320,34 @@ inline const T* Mat::row(int y) const inline Mat Mat::channel_range(int _c, int channels) { - return Mat(w, h, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + if (dims == 3) + return Mat(w, h, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + + // if (dims == 4) + return Mat(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); } inline const Mat Mat::channel_range(int _c, int channels) const { - return Mat(w, h, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + if (dims == 3) + return Mat(w, h, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); + + // if (dims == 4) + return Mat(w, h, d, channels, (unsigned char*)data + cstep * _c * elemsize, elemsize, elempack, allocator); +} + +inline Mat Mat::depth_range(int z, int depths) +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; +} + +inline const Mat Mat::depth_range(int z, int depths) const +{ + Mat m(w, h, depths, (unsigned char*)data + (size_t)w * h * z * elemsize, elemsize, elempack, allocator); + m.cstep = (size_t)w * h; + return m; } inline Mat Mat::row_range(int y, int rows) @@ -1277,48 +1395,60 @@ inline const float& Mat::operator[](size_t i) const #if NCNN_VULKAN inline VkMat::VkMat() - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { } inline VkMat::VkMat(int _w, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _elemsize, _allocator); } inline VkMat::VkMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _elemsize, _allocator); } inline VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _c, _elemsize, _allocator); } +inline VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + inline VkMat::VkMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _elemsize, _elempack, _allocator); } inline VkMat::VkMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _elemsize, _elempack, _allocator); } inline VkMat::VkMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0), cstep(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) { create(_w, _h, _c, _elemsize, _elempack, _allocator); } +inline VkMat::VkMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0), cstep(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + inline VkMat::VkMat(const VkMat& m) - : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), c(m.c) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) { addref(); @@ -1326,41 +1456,53 @@ inline VkMat::VkMat(const VkMat& m) } inline VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { cstep = w; } inline VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { cstep = w * h; } inline VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) { cstep = alignSize(w * h * elemsize, 16) / elemsize; } +inline VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + inline VkMat::VkMat(int _w, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { cstep = w; } inline VkMat::VkMat(int _w, int _h, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { cstep = w * h; } inline VkMat::VkMat(int _w, int _h, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) { cstep = alignSize(w * h * elemsize, 16) / elemsize; } +inline VkMat::VkMat(int _w, int _h, int _d, int _c, VkBufferMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) +{ + cstep = alignSize(w * h * d * elemsize, 16) / elemsize; +} + inline VkMat::~VkMat() { release(); @@ -1385,6 +1527,7 @@ inline VkMat& VkMat::operator=(const VkMat& m) dims = m.dims; w = m.w; h = m.h; + d = m.d; c = m.c; cstep = m.cstep; @@ -1406,6 +1549,9 @@ inline Mat VkMat::mapped() const if (dims == 3) return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + return Mat(); } @@ -1441,6 +1587,7 @@ inline void VkMat::release() dims = 0; w = 0; h = 0; + d = 0; c = 0; cstep = 0; @@ -1471,6 +1618,8 @@ inline Mat VkMat::shape() const return Mat(w, h * elempack, (void*)0); if (dims == 3) return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); return Mat(); } @@ -1491,79 +1640,101 @@ inline size_t VkMat::buffer_capacity() const } inline VkImageMat::VkImageMat() - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { } inline VkImageMat::VkImageMat(int _w, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _elemsize, _allocator); } inline VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _h, _elemsize, _allocator); } inline VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _h, _c, _elemsize, _allocator); } +inline VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _allocator); +} + inline VkImageMat::VkImageMat(int _w, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _elemsize, _elempack, _allocator); } inline VkImageMat::VkImageMat(int _w, int _h, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _h, _elemsize, _elempack, _allocator); } inline VkImageMat::VkImageMat(int _w, int _h, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), c(0) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) { create(_w, _h, _c, _elemsize, _elempack, _allocator); } +inline VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(0), refcount(0), elemsize(0), elempack(0), allocator(0), dims(0), w(0), h(0), d(0), c(0) +{ + create(_w, _h, _d, _c, _elemsize, _elempack, _allocator); +} + inline VkImageMat::VkImageMat(const VkImageMat& m) - : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), c(m.c) + : data(m.data), refcount(m.refcount), elemsize(m.elemsize), elempack(m.elempack), allocator(m.allocator), dims(m.dims), w(m.w), h(m.h), d(m.d), c(m.c) { addref(); } inline VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { } inline VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { } inline VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +inline VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(1), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) { } inline VkImageMat::VkImageMat(int _w, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(1), w(_w), h(1), d(1), c(1) { } inline VkImageMat::VkImageMat(int _w, int _h, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), c(1) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(2), w(_w), h(_h), d(1), c(1) { } inline VkImageMat::VkImageMat(int _w, int _h, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) - : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), c(_c) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(3), w(_w), h(_h), d(1), c(_c) +{ +} + +inline VkImageMat::VkImageMat(int _w, int _h, int _d, int _c, VkImageMemory* _data, size_t _elemsize, int _elempack, VkAllocator* _allocator) + : data(_data), refcount(0), elemsize(_elemsize), elempack(_elempack), allocator(_allocator), dims(4), w(_w), h(_h), d(_d), c(_c) { } @@ -1591,6 +1762,7 @@ inline VkImageMat& VkImageMat::operator=(const VkImageMat& m) dims = m.dims; w = m.w; h = m.h; + d = m.d; c = m.c; return *this; @@ -1610,6 +1782,9 @@ inline Mat VkImageMat::mapped() const if (dims == 3) return Mat(w, h, c, mapped_ptr(), elemsize, elempack, 0); + if (dims == 4) + return Mat(w, h, d, c, mapped_ptr(), elemsize, elempack, 0); + return Mat(); } @@ -1645,6 +1820,7 @@ inline void VkImageMat::release() dims = 0; w = 0; h = 0; + d = 0; c = 0; refcount = 0; @@ -1657,7 +1833,7 @@ inline bool VkImageMat::empty() const inline size_t VkImageMat::total() const { - return w * h * c; + return w * h * d * c; } inline int VkImageMat::elembits() const @@ -1673,6 +1849,8 @@ inline Mat VkImageMat::shape() const return Mat(w, h * elempack, (void*)0); if (dims == 3) return Mat(w, h, c * elempack, (void*)0); + if (dims == 4) + return Mat(w, h, d, c * elempack, (void*)0); return Mat(); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dfae3649c..16925fce9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -63,8 +63,10 @@ ncnn_add_layer_test(Clip) ncnn_add_layer_test(Concat) ncnn_add_layer_test(Convolution) ncnn_add_layer_test(Convolution1D) +ncnn_add_layer_test(Convolution3D) ncnn_add_layer_test(ConvolutionDepthWise) ncnn_add_layer_test(ConvolutionDepthWise1D) +ncnn_add_layer_test(ConvolutionDepthWise3D) ncnn_add_layer_test(Crop) ncnn_add_layer_test(Deconvolution) ncnn_add_layer_test(DeconvolutionDepthWise) @@ -98,6 +100,7 @@ ncnn_add_layer_test(Permute) ncnn_add_layer_test(PixelShuffle) ncnn_add_layer_test(Pooling) ncnn_add_layer_test(Pooling1D) +ncnn_add_layer_test(Pooling3D) ncnn_add_layer_test(PReLU) ncnn_add_layer_test(PriorBox) ncnn_add_layer_test(Quantize) diff --git a/tests/test_cast.cpp b/tests/test_cast.cpp index e388af51d..b20bad615 100644 --- a/tests/test_cast.cpp +++ b/tests/test_cast.cpp @@ -65,7 +65,7 @@ static int test_cast_cpu(const ncnn::Mat& a, int type_from, int type_to) if (CompareMat(b, c, 0.001) != 0) { - fprintf(stderr, "test_cast_cpu failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_cpu failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -138,7 +138,7 @@ static int test_cast_cpu_packed(const ncnn::Mat& a, int type_from, int type_to) if (CompareMat(b, c, 0.001) != 0) { - fprintf(stderr, "test_cast_cpu_packed failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_cpu_packed failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -254,7 +254,7 @@ static int test_cast_gpu_fp16p(const ncnn::Mat& a, int type_from, int type_to) if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_cast_gpu_fp16p failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_gpu_fp16p failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -372,7 +372,7 @@ static int test_cast_gpu_fp16p_pack8(const ncnn::Mat& a, int type_from, int type if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_cast_gpu_fp16p_pack8 failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_gpu_fp16p_pack8 failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -487,7 +487,7 @@ static int test_cast_gpu_image_fp16p(const ncnn::Mat& a, int type_from, int type if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_cast_gpu_image_fp16p failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_gpu_image_fp16p failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -605,7 +605,7 @@ static int test_cast_gpu_image_fp16p_pack8(const ncnn::Mat& a, int type_from, in if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_cast_gpu_image_fp16p_pack8 failed a.dims=%d a=(%d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.c, type_from, type_to); + fprintf(stderr, "test_cast_gpu_image_fp16p_pack8 failed a.dims=%d a=(%d %d %d %d) type_from=%d type_to=%d\n", a.dims, a.w, a.h, a.d, a.c, type_from, type_to); return -1; } @@ -628,6 +628,19 @@ static int test_cast(const ncnn::Mat& a, int type_from, int type_to) } static int test_cast_0() +{ + return 0 + || test_cast(RandomMat(5, 6, 7, 16), 1, 2) + || test_cast(RandomMat(3, 4, 5, 13), 1, 2) + || test_cast(RandomMat(5, 6, 7, 16), 2, 1) + || test_cast(RandomMat(3, 4, 5, 13), 2, 1) + || test_cast(RandomMat(5, 6, 7, 16), 1, 4) + || test_cast(RandomMat(3, 4, 5, 13), 1, 4) + || test_cast(RandomMat(5, 6, 7, 16), 4, 1) + || test_cast(RandomMat(3, 4, 5, 13), 4, 1); +} + +static int test_cast_1() { return 0 || test_cast(RandomMat(5, 7, 16), 1, 2) @@ -640,7 +653,7 @@ static int test_cast_0() || test_cast(RandomMat(3, 5, 13), 4, 1); } -static int test_cast_1() +static int test_cast_2() { return 0 || test_cast(RandomMat(6, 16), 1, 2) @@ -653,7 +666,7 @@ static int test_cast_1() || test_cast(RandomMat(7, 15), 4, 1); } -static int test_cast_2() +static int test_cast_3() { return 0 || test_cast(RandomMat(128), 1, 2) @@ -673,5 +686,6 @@ int main() return 0 || test_cast_0() || test_cast_1() - || test_cast_2(); + || test_cast_2() + || test_cast_3(); } diff --git a/tests/test_convolution.cpp b/tests/test_convolution.cpp index d02d1695e..cb2b9be41 100644 --- a/tests/test_convolution.cpp +++ b/tests/test_convolution.cpp @@ -233,19 +233,19 @@ static int test_convolution_1() {1, 1, 1, 0}, {1, 1, 2, 0}, {2, 1, 1, 1}, - {2, 1, 2, 1}, + {2, 1, 2, -233}, {3, 1, 1, 1}, {3, 1, 2, 1}, {3, 2, 1, 1}, {4, 1, 1, 2}, - {4, 1, 2, 2}, - {4, 2, 1, 2}, - {5, 1, 1, 2}, + {4, 1, 2, -233}, + {4, 2, 1, -234}, + {5, 1, 1, -234}, {5, 1, 2, 2}, {5, 2, 2, 2}, {7, 1, 1, 3}, {7, 1, 2, 3}, - {7, 2, 1, 3}, + {7, 2, 1, -233}, }; for (int i = 0; i < 16; i++) diff --git a/tests/test_convolution3d.cpp b/tests/test_convolution3d.cpp new file mode 100644 index 000000000..2cd752982 --- /dev/null +++ b/tests/test_convolution3d.cpp @@ -0,0 +1,95 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "layer/convolution3d.h" +#include "testutil.h" + +static int test_convolution3d(int w, int h, int d, int c, int outch, int kernel, int dilation, int stride, int pad, int bias) +{ + ncnn::Mat a = RandomMat(w, h, d, c); + + ncnn::ParamDict pd; + pd.set(0, outch); // num_output + pd.set(1, kernel); // kernel_w + pd.set(2, dilation); // dilation_w + pd.set(3, stride); // stride_w + pd.set(4, pad); // pad_w + pd.set(5, bias); // bias_term + pd.set(6, outch * c * kernel * kernel * kernel); + + int activation_type = RAND() % 6; // 0 1 2 3 4 5 + ncnn::Mat activation_params(2); + activation_params[0] = RandomFloat(-1, 0); // alpha + activation_params[1] = RandomFloat(0, 1); // beta + pd.set(9, activation_type); + pd.set(10, activation_params); + + std::vector weights(bias ? 2 : 1); + weights[0] = RandomMat(outch * c * kernel * kernel * kernel); + if (bias) + weights[1] = RandomMat(outch); + + int ret = test_layer("Convolution3D", pd, weights, a); + if (ret != 0) + { + fprintf(stderr, "test_convolution3d failed w=%d h=%d d=%d c=%d outch=%d kernel=%d dilation=%d stride=%d pad=%d bias=%d act=%d actparams=[%f,%f]\n", w, h, d, c, outch, kernel, dilation, stride, pad, bias, activation_type, activation_params[0], activation_params[1]); + } + + return ret; +} + +static int test_convolution3d_0() +{ + static const int kdsp[7][4] = { + {1, 1, 1, 0}, + {1, 1, 2, 0}, + {2, 1, 1, 1}, + {2, 1, 2, -233}, + {3, 1, 1, 1}, + {3, 1, 2, 1}, + {3, 2, 1, -234}, + }; + + for (int i = 0; i < 7; i++) + { + const int k = kdsp[i][0]; + const int d = kdsp[i][1]; + const int s = kdsp[i][2]; + const int p = kdsp[i][3]; + + int ret = 0 + || test_convolution3d(11, 10, 9, 1, 1, k, d, s, p, 1) + || test_convolution3d(11, 10, 9, 4, 13, k, d, s, p, 0) + || test_convolution3d(11, 10, 9, 13, 4, k, d, s, p, 1) + || test_convolution3d(11, 10, 9, 12, 12, k, d, s, p, 0) + || test_convolution3d(11, 10, 9, 8, 12, k, d, s, p, 1) + || test_convolution3d(11, 10, 9, 8, 13, k, d, s, p, 0) + || test_convolution3d(11, 10, 9, 13, 8, k, d, s, p, 1) + || test_convolution3d(11, 10, 9, 12, 16, k, d, s, p, 0) + || test_convolution3d(11, 10, 9, 15, 15, k, d, s, p, 0) + || test_convolution3d(11, 10, 9, 16, 16, k, d, s, p, 0); + + if (ret != 0) + return -1; + } + + return 0; +} + +int main() +{ + SRAND(7767517); + + return test_convolution3d_0(); +} diff --git a/tests/test_convolutiondepthwise3d.cpp b/tests/test_convolutiondepthwise3d.cpp new file mode 100644 index 000000000..7ecb51447 --- /dev/null +++ b/tests/test_convolutiondepthwise3d.cpp @@ -0,0 +1,98 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "layer/convolutiondepthwise3d.h" +#include "testutil.h" + +static int test_convolutiondepthwise3d(int w, int h, int d, int c, int outch, int kernel, int dilation, int stride, int pad, int bias, int group) +{ + ncnn::Mat a = RandomMat(w, h, d, c); + + ncnn::ParamDict pd; + pd.set(0, outch); // num_output + pd.set(1, kernel); // kernel_w + pd.set(2, dilation); // dilation_w + pd.set(3, stride); // stride_w + pd.set(4, pad); // pad_w + pd.set(5, bias); // bias_term + pd.set(6, outch / group * c / group * kernel * kernel * kernel * group); + pd.set(7, group); + + int activation_type = RAND() % 7; // 0 1 2 3 4 5 6 + ncnn::Mat activation_params(2); + activation_params[0] = (activation_type == 6) ? RandomFloat(0, 1) : RandomFloat(-1, 0); // alpha + activation_params[1] = RandomFloat(0, 1); // beta + pd.set(9, activation_type); + pd.set(10, activation_params); + + std::vector weights(2); + weights[0] = RandomMat(outch / group * c / group * kernel * kernel * kernel * group); + weights[1] = RandomMat(outch); + + int ret = test_layer("ConvolutionDepthWise3D", pd, weights, a); + if (ret != 0) + { + fprintf(stderr, "test_convolutiondepthwise3d failed w=%d h=%d d=%d c=%d outch=%d kernel=%d dilation=%d stride=%d pad=%d bias=%d group=%d act=%d actparams=[%f,%f]\n", w, h, d, c, outch, kernel, dilation, stride, pad, bias, group, activation_type, activation_params[0], activation_params[1]); + } + + return ret; +} + +static int test_convolutiondepthwise3d_0() +{ + static const int kdsp[7][4] = { + {1, 1, 1, 0}, + {1, 1, 2, 0}, + {2, 1, 1, 1}, + {2, 1, 2, -233}, + {3, 1, 1, 1}, + {3, 1, 2, 1}, + {3, 2, 1, -234}, + }; + + for (int i = 0; i < 7; i++) + { + const int k = kdsp[i][0]; + const int d = kdsp[i][1]; + const int s = kdsp[i][2]; + const int p = kdsp[i][3]; + + int ret = 0 + || test_convolutiondepthwise3d(11, 10, 9, 1, 1, k, d, s, p, 1, 1) + || test_convolutiondepthwise3d(11, 10, 9, 2, 2, k, d, s, p, 0, 1) + || test_convolutiondepthwise3d(11, 10, 9, 2, 2, k, d, s, p, 1, 2) + || test_convolutiondepthwise3d(11, 10, 9, 3, 3, k, d, s, p, 0, 3) + || test_convolutiondepthwise3d(11, 10, 9, 4, 2, k, d, s, p, 1, 2) + || test_convolutiondepthwise3d(11, 10, 9, 4, 4, k, d, s, p, 0, 4) + || test_convolutiondepthwise3d(11, 10, 9, 7, 7, k, d, s, p, 1, 7) + || test_convolutiondepthwise3d(11, 10, 9, 8, 8, k, d, s, p, 0, 2) + || test_convolutiondepthwise3d(11, 10, 9, 8, 8, k, d, s, p, 1, 8) + || test_convolutiondepthwise3d(11, 10, 9, 12, 12, k, d, s, p, 0, 4) + || test_convolutiondepthwise3d(11, 10, 9, 15, 15, k, d, s, p, 1, 15) + || test_convolutiondepthwise3d(11, 10, 9, 16, 8, k, d, s, p, 0, 2) + || test_convolutiondepthwise3d(11, 10, 9, 16, 16, k, d, s, p, 1, 16); + + if (ret != 0) + return -1; + } + + return 0; +} + +int main() +{ + SRAND(7767517); + + return test_convolutiondepthwise3d_0(); +} diff --git a/tests/test_mat_pixel.cpp b/tests/test_mat_pixel.cpp index 26f0019b7..d748ed014 100644 --- a/tests/test_mat_pixel.cpp +++ b/tests/test_mat_pixel.cpp @@ -58,7 +58,7 @@ static int test_mat_pixel_gray(int w, int h) for (int i = 0; i < 1; i++) { ncnn::Mat m = ncnn::Mat::from_pixels(a, pixel_type_from[i], w, h); - ncnn::Mat b(w, h, 1u, 1); + ncnn::Mat b(w, h, (size_t)1u, 1); m.to_pixels(b, pixel_type_to[i]); if (memcmp(a, b, w * h * 1) != 0) @@ -82,7 +82,7 @@ static int test_mat_pixel_rgb(int w, int h) for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels(a, pixel_type_from[i], w, h); - ncnn::Mat b(w, h, 3u, 3); + ncnn::Mat b(w, h, (size_t)3u, 3); m.to_pixels(b, pixel_type_to[i]); if (memcmp(a, b, w * h * 3) != 0) @@ -106,7 +106,7 @@ static int test_mat_pixel_bgr(int w, int h) for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels(a, pixel_type_from[i], w, h); - ncnn::Mat b(w, h, 3u, 3); + ncnn::Mat b(w, h, (size_t)3u, 3); m.to_pixels(b, pixel_type_to[i]); if (memcmp(a, b, w * h * 3) != 0) @@ -129,7 +129,7 @@ static int test_mat_pixel_rgba(int w, int h) for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels(a, pixel_type_from[i], w, h); - ncnn::Mat b(w, h, 4u, 4); + ncnn::Mat b(w, h, (size_t)4u, 4); m.to_pixels(b, pixel_type_to[i]); if (memcmp(a, b, w * h * 4) != 0) @@ -152,7 +152,7 @@ static int test_mat_pixel_bgra(int w, int h) for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels(a, pixel_type_from[i], w, h); - ncnn::Mat b(w, h, 4u, 4); + ncnn::Mat b(w, h, (size_t)4u, 4); m.to_pixels(b, pixel_type_to[i]); if (memcmp(a, b, w * h * 4) != 0) @@ -179,7 +179,7 @@ static int test_mat_pixel_roi_gray(int w, int h, int roix, int roiy, int roiw, i for (int i = 0; i < 1; i++) { ncnn::Mat m = ncnn::Mat::from_pixels_roi(a, pixel_type_from[i], w, h, roix, roiy, roiw, roih); - ncnn::Mat b(roiw, roih, 1u, 1); + ncnn::Mat b(roiw, roih, (size_t)1u, 1); m.to_pixels(b, pixel_type_to[i]); ncnn::Mat b2; @@ -211,7 +211,7 @@ static int test_mat_pixel_roi_rgb(int w, int h, int roix, int roiy, int roiw, in for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels_roi(a, pixel_type_from[i], w, h, roix, roiy, roiw, roih); - ncnn::Mat b(roiw, roih, 3u, 3); + ncnn::Mat b(roiw, roih, (size_t)3u, 3); m.to_pixels(b, pixel_type_to[i]); ncnn::Mat b2; @@ -243,7 +243,7 @@ static int test_mat_pixel_roi_bgr(int w, int h, int roix, int roiy, int roiw, in for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels_roi(a, pixel_type_from[i], w, h, roix, roiy, roiw, roih); - ncnn::Mat b(roiw, roih, 3u, 3); + ncnn::Mat b(roiw, roih, (size_t)3u, 3); m.to_pixels(b, pixel_type_to[i]); ncnn::Mat b2; @@ -274,7 +274,7 @@ static int test_mat_pixel_roi_rgba(int w, int h, int roix, int roiy, int roiw, i for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels_roi(a, pixel_type_from[i], w, h, roix, roiy, roiw, roih); - ncnn::Mat b(roiw, roih, 4u, 4); + ncnn::Mat b(roiw, roih, (size_t)4u, 4); m.to_pixels(b, pixel_type_to[i]); ncnn::Mat b2; @@ -305,7 +305,7 @@ static int test_mat_pixel_roi_bgra(int w, int h, int roix, int roiy, int roiw, i for (int i = 0; i < 2; i++) { ncnn::Mat m = ncnn::Mat::from_pixels_roi(a, pixel_type_from[i], w, h, roix, roiy, roiw, roih); - ncnn::Mat b(roiw, roih, 4u, 4); + ncnn::Mat b(roiw, roih, (size_t)4u, 4); m.to_pixels(b, pixel_type_to[i]); ncnn::Mat b2; @@ -340,10 +340,10 @@ static int test_mat_pixel_yuv420sp2rgb(int w, int h) p += 2; } - ncnn::Mat rgb(w, h, 3u, 3); + ncnn::Mat rgb(w, h, (size_t)3u, 3); yuv420sp2rgb(nv21, w, h, rgb); - ncnn::Mat rgb2(w, h, 3u, 3); + ncnn::Mat rgb2(w, h, (size_t)3u, 3); yuv420sp2rgb_nv12(nv12, w, h, rgb2); if (memcmp(rgb, rgb2, w * h * 3) != 0) diff --git a/tests/test_mat_pixel_affine.cpp b/tests/test_mat_pixel_affine.cpp index 2158a9c28..817b0f57a 100644 --- a/tests/test_mat_pixel_affine.cpp +++ b/tests/test_mat_pixel_affine.cpp @@ -456,7 +456,7 @@ static int test_mat_pixel_affine_0() static int test_mat_pixel_affine_yuv420sp(int w, int h) { - ncnn::Mat a0(w, h * 3 / 2, 1u, 1); + ncnn::Mat a0(w, h * 3 / 2, (size_t)1u, 1); ncnn::Mat a0_y = RandomMat(w, h, 1); ncnn::Mat a0_uv = RandomMat(w / 2, h / 2, 2); @@ -468,21 +468,21 @@ static int test_mat_pixel_affine_yuv420sp(int w, int h) ncnn::get_rotation_matrix(-70.f, 0.3f, w / 2, h / 2, tm); ncnn::invert_affine_transform(tm, tm_inv); - ncnn::Mat a1(w / 2, (h / 2) * 3 / 2, 1u, 1); + ncnn::Mat a1(w / 2, (h / 2) * 3 / 2, (size_t)1u, 1); ncnn::Mat a2 = a0.clone(); ncnn::warpaffine_bilinear_yuv420sp(a0, w, h, a1, w / 2, h / 2, tm, 0); ncnn::warpaffine_bilinear_yuv420sp(a1, w / 2, h / 2, a2, w, h, tm_inv, -233); // Y - if (CompareNearlyEqual(ncnn::Mat(w, h, (unsigned char*)a0, 1u, 1), ncnn::Mat(w, h, (unsigned char*)a2, 1u, 1)) != 0) + if (CompareNearlyEqual(ncnn::Mat(w, h, (unsigned char*)a0, (size_t)1u, 1), ncnn::Mat(w, h, (unsigned char*)a2, (size_t)1u, 1)) != 0) { fprintf(stderr, "test_mat_pixel_affine_yuv420sp Y failed w=%d h=%d\n", w, h); return -1; } // UV - if (CompareNearlyEqual(ncnn::Mat(w / 2, h / 2, (unsigned char*)a0 + w * h, 2u, 2), ncnn::Mat(w / 2, h / 2, (unsigned char*)a2 + w * h, 2u, 2)) != 0) + if (CompareNearlyEqual(ncnn::Mat(w / 2, h / 2, (unsigned char*)a0 + w * h, (size_t)2u, 2), ncnn::Mat(w / 2, h / 2, (unsigned char*)a2 + w * h, (size_t)2u, 2)) != 0) { fprintf(stderr, "test_mat_pixel_affine_yuv420sp UV failed w=%d h=%d\n", w, h); return -1; diff --git a/tests/test_mat_pixel_drawing.cpp b/tests/test_mat_pixel_drawing.cpp index a1dee6aab..2f68927d6 100644 --- a/tests/test_mat_pixel_drawing.cpp +++ b/tests/test_mat_pixel_drawing.cpp @@ -39,8 +39,8 @@ static int RandomInt2(int a, int b) static int test_mat_pixel_drawing_c1(int w, int h) { - ncnn::Mat a(w, h, 1u, 1); - ncnn::Mat b(h, w, 1u, 1); + ncnn::Mat a(w, h, (size_t)1u, 1); + ncnn::Mat b(h, w, (size_t)1u, 1); int _color = 0; unsigned char* color = (unsigned char*)&_color; @@ -108,7 +108,7 @@ static int test_mat_pixel_drawing_c1(int w, int h) ncnn::draw_line_c1(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1); // transpose b - ncnn::Mat c(w, h, 1u, 1); + ncnn::Mat c(w, h, (size_t)1u, 1); ncnn::kanna_rotate_c1(b, h, w, c, w, h, 5); // draw text @@ -153,8 +153,8 @@ static int test_mat_pixel_drawing_c1(int w, int h) static int test_mat_pixel_drawing_c2(int w, int h) { - ncnn::Mat a(w, h, 2u, 2); - ncnn::Mat b(h, w, 2u, 2); + ncnn::Mat a(w, h, (size_t)2u, 2); + ncnn::Mat b(h, w, (size_t)2u, 2); int _color = 0; unsigned char* color = (unsigned char*)&_color; @@ -233,7 +233,7 @@ static int test_mat_pixel_drawing_c2(int w, int h) ncnn::draw_line_c2(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1); // transpose b - ncnn::Mat c(w, h, 2u, 2); + ncnn::Mat c(w, h, (size_t)2u, 2); ncnn::kanna_rotate_c2(b, h, w, c, w, h, 5); // draw text @@ -280,8 +280,8 @@ static int test_mat_pixel_drawing_c2(int w, int h) static int test_mat_pixel_drawing_c3(int w, int h) { - ncnn::Mat a(w, h, 3u, 3); - ncnn::Mat b(h, w, 3u, 3); + ncnn::Mat a(w, h, (size_t)3u, 3); + ncnn::Mat b(h, w, (size_t)3u, 3); int _color = 0; unsigned char* color = (unsigned char*)&_color; @@ -371,7 +371,7 @@ static int test_mat_pixel_drawing_c3(int w, int h) ncnn::draw_line_c3(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1); // transpose b - ncnn::Mat c(w, h, 3u, 3); + ncnn::Mat c(w, h, (size_t)3u, 3); ncnn::kanna_rotate_c3(b, h, w, c, w, h, 5); // draw text @@ -420,8 +420,8 @@ static int test_mat_pixel_drawing_c3(int w, int h) static int test_mat_pixel_drawing_c4(int w, int h) { - ncnn::Mat a(w, h, 4u, 4); - ncnn::Mat b(h, w, 4u, 4); + ncnn::Mat a(w, h, (size_t)4u, 4); + ncnn::Mat b(h, w, (size_t)4u, 4); int _color = 0; unsigned char* color = (unsigned char*)&_color; @@ -522,7 +522,7 @@ static int test_mat_pixel_drawing_c4(int w, int h) ncnn::draw_line_c4(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1); // transpose b - ncnn::Mat c(w, h, 4u, 4); + ncnn::Mat c(w, h, (size_t)4u, 4); ncnn::kanna_rotate_c4(b, h, w, c, w, h, 5); // draw text @@ -592,8 +592,8 @@ static int test_mat_pixel_drawing_0() static int test_mat_pixel_drawing_yuv420sp(int w, int h) { - ncnn::Mat a(w, h * 3 / 2, 1u, 1); - ncnn::Mat b(h, w * 3 / 2, 1u, 1); + ncnn::Mat a(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat b(h, w * 3 / 2, (size_t)1u, 1); int _color = 0; unsigned char* color = (unsigned char*)&_color; @@ -683,7 +683,7 @@ static int test_mat_pixel_drawing_yuv420sp(int w, int h) ncnn::draw_line_yuv420sp(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 2); // transpose b - ncnn::Mat c(w, h * 3 / 2, 1u, 1); + ncnn::Mat c(w, h * 3 / 2, (size_t)1u, 1); ncnn::kanna_rotate_yuv420sp(b, h, w, c, w, h, 5); // draw text diff --git a/tests/test_mat_pixel_rotate.cpp b/tests/test_mat_pixel_rotate.cpp index bd0b25fa0..b0ec78d34 100644 --- a/tests/test_mat_pixel_rotate.cpp +++ b/tests/test_mat_pixel_rotate.cpp @@ -38,14 +38,14 @@ static int test_mat_pixel_rotate_c1(int w, int h) { ncnn::Mat a0 = RandomMat(w, h, 1); - ncnn::Mat a1(w, h, 1u, 1); - ncnn::Mat a2(w, h, 1u, 1); - ncnn::Mat a3(w, h, 1u, 1); - ncnn::Mat a4(w, h, 1u, 1); - ncnn::Mat a5(h, w, 1u, 1); - ncnn::Mat a6(w, h, 1u, 1); - ncnn::Mat a7(h, w, 1u, 1); - ncnn::Mat a8(w, h, 1u, 1); + ncnn::Mat a1(w, h, (size_t)1u, 1); + ncnn::Mat a2(w, h, (size_t)1u, 1); + ncnn::Mat a3(w, h, (size_t)1u, 1); + ncnn::Mat a4(w, h, (size_t)1u, 1); + ncnn::Mat a5(h, w, (size_t)1u, 1); + ncnn::Mat a6(w, h, (size_t)1u, 1); + ncnn::Mat a7(h, w, (size_t)1u, 1); + ncnn::Mat a8(w, h, (size_t)1u, 1); ncnn::kanna_rotate_c1(a0, w, h, a1, w, h, 1); ncnn::kanna_rotate_c1(a1, w, h, a2, w, h, 2); @@ -69,14 +69,14 @@ static int test_mat_pixel_rotate_c2(int w, int h) { ncnn::Mat a0 = RandomMat(w, h, 2); - ncnn::Mat a1(w, h, 2u, 2); - ncnn::Mat a2(w, h, 2u, 2); - ncnn::Mat a3(w, h, 2u, 2); - ncnn::Mat a4(w, h, 2u, 2); - ncnn::Mat a5(h, w, 2u, 2); - ncnn::Mat a6(w, h, 2u, 2); - ncnn::Mat a7(h, w, 2u, 2); - ncnn::Mat a8(w, h, 2u, 2); + ncnn::Mat a1(w, h, (size_t)2u, 2); + ncnn::Mat a2(w, h, (size_t)2u, 2); + ncnn::Mat a3(w, h, (size_t)2u, 2); + ncnn::Mat a4(w, h, (size_t)2u, 2); + ncnn::Mat a5(h, w, (size_t)2u, 2); + ncnn::Mat a6(w, h, (size_t)2u, 2); + ncnn::Mat a7(h, w, (size_t)2u, 2); + ncnn::Mat a8(w, h, (size_t)2u, 2); ncnn::kanna_rotate_c2(a0, w, h, a1, w, h, 1); ncnn::kanna_rotate_c2(a1, w, h, a2, w, h, 2); @@ -100,14 +100,14 @@ static int test_mat_pixel_rotate_c3(int w, int h) { ncnn::Mat a0 = RandomMat(w, h, 3); - ncnn::Mat a1(w, h, 3u, 3); - ncnn::Mat a2(w, h, 3u, 3); - ncnn::Mat a3(w, h, 3u, 3); - ncnn::Mat a4(w, h, 3u, 3); - ncnn::Mat a5(h, w, 3u, 3); - ncnn::Mat a6(w, h, 3u, 3); - ncnn::Mat a7(h, w, 3u, 3); - ncnn::Mat a8(w, h, 3u, 3); + ncnn::Mat a1(w, h, (size_t)3u, 3); + ncnn::Mat a2(w, h, (size_t)3u, 3); + ncnn::Mat a3(w, h, (size_t)3u, 3); + ncnn::Mat a4(w, h, (size_t)3u, 3); + ncnn::Mat a5(h, w, (size_t)3u, 3); + ncnn::Mat a6(w, h, (size_t)3u, 3); + ncnn::Mat a7(h, w, (size_t)3u, 3); + ncnn::Mat a8(w, h, (size_t)3u, 3); ncnn::kanna_rotate_c3(a0, w, h, a1, w, h, 1); ncnn::kanna_rotate_c3(a1, w, h, a2, w, h, 2); @@ -131,14 +131,14 @@ static int test_mat_pixel_rotate_c4(int w, int h) { ncnn::Mat a0 = RandomMat(w, h, 4); - ncnn::Mat a1(w, h, 4u, 4); - ncnn::Mat a2(w, h, 4u, 4); - ncnn::Mat a3(w, h, 4u, 4); - ncnn::Mat a4(w, h, 4u, 4); - ncnn::Mat a5(h, w, 4u, 4); - ncnn::Mat a6(w, h, 4u, 4); - ncnn::Mat a7(h, w, 4u, 4); - ncnn::Mat a8(w, h, 4u, 4); + ncnn::Mat a1(w, h, (size_t)4u, 4); + ncnn::Mat a2(w, h, (size_t)4u, 4); + ncnn::Mat a3(w, h, (size_t)4u, 4); + ncnn::Mat a4(w, h, (size_t)4u, 4); + ncnn::Mat a5(h, w, (size_t)4u, 4); + ncnn::Mat a6(w, h, (size_t)4u, 4); + ncnn::Mat a7(h, w, (size_t)4u, 4); + ncnn::Mat a8(w, h, (size_t)4u, 4); ncnn::kanna_rotate_c4(a0, w, h, a1, w, h, 1); ncnn::kanna_rotate_c4(a1, w, h, a2, w, h, 2); @@ -179,14 +179,14 @@ static int test_mat_pixel_rotate_yuv420sp(int w, int h) { ncnn::Mat a0 = RandomMat(w, h * 3 / 2, 1); - ncnn::Mat a1(w, h * 3 / 2, 1u, 1); - ncnn::Mat a2(w, h * 3 / 2, 1u, 1); - ncnn::Mat a3(w, h * 3 / 2, 1u, 1); - ncnn::Mat a4(w, h * 3 / 2, 1u, 1); - ncnn::Mat a5(h, w * 3 / 2, 1u, 1); - ncnn::Mat a6(w, h * 3 / 2, 1u, 1); - ncnn::Mat a7(h, w * 3 / 2, 1u, 1); - ncnn::Mat a8(w, h * 3 / 2, 1u, 1); + ncnn::Mat a1(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat a2(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat a3(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat a4(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat a5(h, w * 3 / 2, (size_t)1u, 1); + ncnn::Mat a6(w, h * 3 / 2, (size_t)1u, 1); + ncnn::Mat a7(h, w * 3 / 2, (size_t)1u, 1); + ncnn::Mat a8(w, h * 3 / 2, (size_t)1u, 1); ncnn::kanna_rotate_yuv420sp(a0, w, h, a1, w, h, 1); ncnn::kanna_rotate_yuv420sp(a1, w, h, a2, w, h, 2); diff --git a/tests/test_packing.cpp b/tests/test_packing.cpp index 1f65943a2..c4ee6877d 100644 --- a/tests/test_packing.cpp +++ b/tests/test_packing.cpp @@ -55,7 +55,7 @@ static int test_packing_cpu_fp32(const ncnn::Mat& a, int in_elempack, int out_el if (CompareMat(b, c, 0.001) != 0) { - fprintf(stderr, "test_packing_cpu_fp32 failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_cpu_fp32 failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -114,7 +114,7 @@ static int test_packing_cpu_fp16(const ncnn::Mat& a, int in_elempack, int out_el if (CompareMat(b, c32, 0.001) != 0) { - fprintf(stderr, "test_packing_cpu_fp16 failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_cpu_fp16 failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -150,6 +150,7 @@ static int test_packing_cpu_int8(const ncnn::Mat& a, int in_elempack, int out_el if (a.dims == 1) a8 = RandomS8Mat(a.w); if (a.dims == 2) a8 = RandomS8Mat(a.w, a.h); if (a.dims == 3) a8 = RandomS8Mat(a.w, a.h, a.c); + if (a.dims == 4) a8 = RandomS8Mat(a.w, a.h, a.d, a.c); ncnn::Mat ap; ncnn::convert_packing(a8, ap, in_elempack); @@ -172,7 +173,7 @@ static int test_packing_cpu_int8(const ncnn::Mat& a, int in_elempack, int out_el if (CompareMat(b32, c32, 0.001) != 0) { - fprintf(stderr, "test_packing_cpu_int8 failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_cpu_int8 failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -270,7 +271,7 @@ static int test_packing_gpu_buffer(const ncnn::Mat& a, int in_elempack, int out_ if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_packing_gpu_buffer failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_gpu_buffer failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -357,7 +358,7 @@ static int test_packing_gpu_image(const ncnn::Mat& a, int in_elempack, int out_e if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_packing_gpu_image failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_gpu_image failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -444,7 +445,7 @@ static int test_packing_gpu_buffer2image(const ncnn::Mat& a, int in_elempack, in if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_packing_gpu_buffer2image failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_gpu_buffer2image failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -531,7 +532,7 @@ static int test_packing_gpu_image2buffer(const ncnn::Mat& a, int in_elempack, in if (CompareMat(b, d, 0.001) != 0) { - fprintf(stderr, "test_packing_gpu_image2buffer failed a.dims=%d a=(%d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.c, in_elempack, out_elempack); + fprintf(stderr, "test_packing_gpu_image2buffer failed a.dims=%d a=(%d %d %d %d) in_elempack=%d out_elempack=%d\n", a.dims, a.w, a.h, a.d, a.c, in_elempack, out_elempack); return -1; } @@ -540,6 +541,71 @@ static int test_packing_gpu_image2buffer(const ncnn::Mat& a, int in_elempack, in #endif static int test_packing_0() +{ + ncnn::Mat a = RandomMat(9, 7, 10, 16); + ncnn::Mat b = RandomMat(9, 7, 10, 3); + + return 0 + || test_packing_cpu(a, 1, 1) + || test_packing_cpu(a, 4, 4) + || test_packing_cpu(a, 4, 8) + || test_packing_cpu(a, 1, 4) + || test_packing_cpu(a, 4, 1) + || test_packing_cpu(a, 1, 8) + || test_packing_cpu(a, 8, 1) + || test_packing_cpu(a, 4, 8) + || test_packing_cpu(a, 8, 4) + || test_packing_cpu(b, 1, 1) + || test_packing_cpu(b, 4, 4) + || test_packing_cpu(b, 4, 8) + || test_packing_cpu(b, 1, 4) + || test_packing_cpu(b, 4, 1) + || test_packing_cpu(b, 1, 8) + || test_packing_cpu(b, 8, 1) + || test_packing_cpu(b, 4, 8) + || test_packing_cpu(b, 8, 4) +#if NCNN_VULKAN + || test_packing_gpu_buffer(a, 1, 1) + || test_packing_gpu_buffer(a, 4, 4) + || test_packing_gpu_buffer(a, 8, 8) + || test_packing_gpu_buffer(a, 1, 4) + || test_packing_gpu_buffer(a, 4, 1) + || test_packing_gpu_buffer(a, 1, 8) + || test_packing_gpu_buffer(a, 8, 1) + || test_packing_gpu_buffer(a, 4, 8) + || test_packing_gpu_buffer(a, 8, 4) + || test_packing_gpu_image(a, 1, 1) + || test_packing_gpu_image(a, 4, 4) + || test_packing_gpu_image(a, 8, 8) + || test_packing_gpu_image(a, 1, 4) + || test_packing_gpu_image(a, 4, 1) + || test_packing_gpu_image(a, 1, 8) + || test_packing_gpu_image(a, 8, 1) + || test_packing_gpu_image(a, 4, 8) + || test_packing_gpu_image(a, 8, 4) + || test_packing_gpu_buffer2image(a, 1, 1) + || test_packing_gpu_buffer2image(a, 4, 4) + || test_packing_gpu_buffer2image(a, 8, 8) + || test_packing_gpu_buffer2image(a, 1, 4) + || test_packing_gpu_buffer2image(a, 4, 1) + || test_packing_gpu_buffer2image(a, 1, 8) + || test_packing_gpu_buffer2image(a, 8, 1) + || test_packing_gpu_buffer2image(a, 4, 8) + || test_packing_gpu_buffer2image(a, 8, 4) + || test_packing_gpu_image2buffer(a, 1, 1) + || test_packing_gpu_image2buffer(a, 4, 4) + || test_packing_gpu_image2buffer(a, 8, 8) + || test_packing_gpu_image2buffer(a, 1, 4) + || test_packing_gpu_image2buffer(a, 4, 1) + || test_packing_gpu_image2buffer(a, 1, 8) + || test_packing_gpu_image2buffer(a, 8, 1) + || test_packing_gpu_image2buffer(a, 4, 8) + || test_packing_gpu_image2buffer(a, 8, 4) +#endif // NCNN_VULKAN + ; +} + +static int test_packing_1() { ncnn::Mat a = RandomMat(9, 10, 16); ncnn::Mat b = RandomMat(9, 10, 3); @@ -604,7 +670,7 @@ static int test_packing_0() ; } -static int test_packing_1() +static int test_packing_2() { ncnn::Mat a = RandomMat(19, 16); @@ -659,7 +725,7 @@ static int test_packing_1() ; } -static int test_packing_2() +static int test_packing_3() { ncnn::Mat a = RandomMat(80); @@ -721,5 +787,6 @@ int main() return 0 || test_packing_0() || test_packing_1() - || test_packing_2(); + || test_packing_2() + || test_packing_3(); } diff --git a/tests/test_padding.cpp b/tests/test_padding.cpp index f69de7c60..251070a79 100644 --- a/tests/test_padding.cpp +++ b/tests/test_padding.cpp @@ -35,13 +35,49 @@ static int test_padding(const ncnn::Mat& a, int top, int bottom, int left, int r int ret = test_layer("Padding", pd, weights, a); if (ret != 0) { - fprintf(stderr, "test_padding failed a.dims=%d a=(%d %d %d) top=%d bottom=%d left=%d right=%d front=%d behind=%d type=%d value=%f per_channel_pad_data_size=%d\n", a.dims, a.w, a.h, a.c, top, bottom, left, right, front, behind, type, value, per_channel_pad_data_size); + fprintf(stderr, "test_padding failed a.dims=%d a=(%d %d %d %d) top=%d bottom=%d left=%d right=%d front=%d behind=%d type=%d value=%f per_channel_pad_data_size=%d\n", a.dims, a.w, a.h, a.d, a.c, top, bottom, left, right, front, behind, type, value, per_channel_pad_data_size); } return ret; } static int test_padding_0() +{ + ncnn::Mat a = RandomMat(9, 10, 11, 96); + ncnn::Mat b = RandomMat(10, 12, 13, 44); + ncnn::Mat c = RandomMat(8, 7, 9, 13); + + return 0 + || test_padding(a, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + || test_padding(b, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + || test_padding(c, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + + || test_padding(a, 2, 2, 2, 2, 2, 2, 0, 1.f, 0) + || test_padding(b, 2, 2, 2, 2, 2, 2, 0, 2.f, 0) + || test_padding(c, 2, 2, 2, 2, 2, 2, 0, -3.f, 0) + + || test_padding(a, 2, 1, 2, 1, 2, 1, 0, 0.f, a.c) + || test_padding(b, 2, 1, 2, 1, 2, 1, 0, 0.f, b.c) + || test_padding(c, 2, 1, 2, 1, 2, 1, 0, 0.f, c.c) + + || test_padding(a, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + || test_padding(b, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + || test_padding(c, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + + || test_padding(a, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + || test_padding(b, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + || test_padding(c, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + + || test_padding(a, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + || test_padding(b, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + || test_padding(c, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + + || test_padding(a, 1, 1, 1, 1, 1, 1, 0, -1.f, 0) + || test_padding(b, 1, 1, 1, 1, 1, 1, 0, -2.f, 0) + || test_padding(c, 1, 1, 1, 1, 1, 1, 0, 3.f, 0); +} + +static int test_padding_1() { ncnn::Mat a = RandomMat(9, 11, 96); ncnn::Mat b = RandomMat(10, 13, 44); @@ -101,7 +137,7 @@ static int test_padding_0() || test_padding(c, 4, 2, 1, 3, 3, 5, 2, 0.f, 0); } -static int test_padding_1() +static int test_padding_2() { ncnn::Mat a = RandomMat(15, 96); ncnn::Mat b = RandomMat(19, 44); @@ -149,7 +185,7 @@ static int test_padding_1() || test_padding(c, 2, 6, 1, 0, 0, 0, 2, 0.f, 0); } -static int test_padding_2() +static int test_padding_3() { ncnn::Mat a = RandomMat(128); ncnn::Mat b = RandomMat(124); @@ -209,13 +245,49 @@ static int test_padding_int8(const ncnn::Mat& a, int top, int bottom, int left, int ret = test_layer("Padding", pd, weights, a, 0.001, 0, flag); if (ret != 0) { - fprintf(stderr, "test_padding_int8 failed a.dims=%d a=(%d %d %d) top=%d bottom=%d left=%d right=%d front=%d behind=%d type=%d value=%f per_channel_pad_data_size=%d\n", a.dims, a.w, a.h, a.c, top, bottom, left, right, front, behind, type, value, per_channel_pad_data_size); + fprintf(stderr, "test_padding_int8 failed a.dims=%d a=(%d %d %d %d) top=%d bottom=%d left=%d right=%d front=%d behind=%d type=%d value=%f per_channel_pad_data_size=%d\n", a.dims, a.w, a.h, a.d, a.c, top, bottom, left, right, front, behind, type, value, per_channel_pad_data_size); } return ret; } -static int test_padding_3() +static int test_padding_4() +{ + ncnn::Mat a = RandomS8Mat(9, 10, 11, 96); + ncnn::Mat b = RandomS8Mat(10, 12, 13, 44); + ncnn::Mat c = RandomS8Mat(8, 7, 9, 13); + + return 0 + || test_padding_int8(a, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + || test_padding_int8(b, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + || test_padding_int8(c, 0, 0, 0, 0, 0, 0, 0, 0.f, 0) + + || test_padding_int8(a, 2, 2, 2, 2, 1, 1, 0, 1.f, 0) + || test_padding_int8(b, 2, 2, 2, 2, 1, 1, 0, 2.f, 0) + || test_padding_int8(c, 2, 2, 2, 2, 1, 1, 0, -3.f, 0) + + || test_padding_int8(a, 2, 1, 2, 1, 2, 1, 0, 0.f, a.c) + || test_padding_int8(b, 2, 1, 2, 1, 2, 1, 0, 0.f, b.c) + || test_padding_int8(c, 2, 1, 2, 1, 2, 1, 0, 0.f, c.c) + + || test_padding_int8(a, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + || test_padding_int8(b, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + || test_padding_int8(c, 0, 1, 0, 1, 0, 1, 0, 0.f, 0) + + || test_padding_int8(a, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + || test_padding_int8(b, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + || test_padding_int8(c, 1, 2, 3, 4, 5, 6, 0, 0.f, 0) + + || test_padding_int8(a, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + || test_padding_int8(b, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + || test_padding_int8(c, 2, 3, 2, 3, 2, 3, 0, 0.f, 0) + + || test_padding_int8(a, 1, 1, 1, 1, 1, 1, 0, -1.f, 0) + || test_padding_int8(b, 1, 1, 1, 1, 1, 1, 0, -2.f, 0) + || test_padding_int8(c, 1, 1, 1, 1, 1, 1, 0, 3.f, 0); +} + +static int test_padding_5() { ncnn::Mat a = RandomS8Mat(9, 11, 96); ncnn::Mat b = RandomS8Mat(10, 13, 44); @@ -275,7 +347,7 @@ static int test_padding_3() || test_padding_int8(c, 4, 2, 1, 3, 3, 5, 2, 0.f, 0); } -static int test_padding_4() +static int test_padding_6() { ncnn::Mat a = RandomS8Mat(15, 96); ncnn::Mat b = RandomS8Mat(19, 44); @@ -323,7 +395,7 @@ static int test_padding_4() || test_padding_int8(c, 2, 6, 1, 0, 0, 0, 2, 0.f, 0); } -static int test_padding_5() +static int test_padding_7() { ncnn::Mat a = RandomS8Mat(128); ncnn::Mat b = RandomS8Mat(124); @@ -368,5 +440,7 @@ int main() || test_padding_2() || test_padding_3() || test_padding_4() - || test_padding_5(); + || test_padding_5() + || test_padding_6() + || test_padding_7(); } diff --git a/tests/test_pooling3d.cpp b/tests/test_pooling3d.cpp new file mode 100644 index 000000000..870fd79a9 --- /dev/null +++ b/tests/test_pooling3d.cpp @@ -0,0 +1,263 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "layer/pooling3d.h" +#include "testutil.h" + +static int test_pooling3d(int w, int h, int d, int c, int pooling_type, int kernel, int stride, int pad, int global_pooling, int pad_mode, int avgpool_count_include_pad, int adaptive_pooling, int out_w) +{ + ncnn::Mat a = RandomMat(w, h, d, c); + + ncnn::ParamDict pd; + pd.set(0, pooling_type); // pooling_type + pd.set(1, kernel); // kernel_w + pd.set(2, stride); // stride_w + pd.set(3, pad); // pad_w + pd.set(4, global_pooling); // global_pooling + pd.set(5, pad_mode); // pad_mode + pd.set(6, avgpool_count_include_pad); // avgpool_count_include_pad + pd.set(7, adaptive_pooling); // adaptive_pooling + pd.set(8, out_w); // out_w + + std::vector weights(0); + + int ret = test_layer("Pooling3D", pd, weights, a); + if (ret != 0) + { + fprintf(stderr, "test_pooling3d failed w=%d h=%d d=%d c=%d pooling_type=%d kernel=%d stride=%d pad=%d global_pooling=%d pad_mode=%d avgpool_count_include_pad=%d adaptive_pooling=%d out_w=%d\n", w, h, d, c, pooling_type, kernel, stride, pad, global_pooling, pad_mode, avgpool_count_include_pad, adaptive_pooling, out_w); + } + + return ret; +} + +static int test_pooling3d_0() +{ + static const int ksp[11][3] = { + {2, 1, 0}, + {2, 2, 0}, + {3, 1, 0}, + {3, 2, 1}, + {4, 1, 0}, + {4, 2, 1}, + {5, 1, 0}, + {5, 2, 2}, + {7, 1, 0}, + {7, 2, 1}, + {7, 3, 2}, + }; + + for (int i = 0; i < 11; i++) + { + int ret = 0 + || test_pooling3d(9, 8, 7, 1, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 0, 0, 0) + || test_pooling3d(9, 8, 7, 2, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 0, 0, 0) + || test_pooling3d(9, 8, 7, 3, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 2, 0, 0, 0) + || test_pooling3d(9, 8, 7, 4, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 3, 0, 0, 0) + || test_pooling3d(9, 8, 7, 7, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 0, 0, 0) + || test_pooling3d(9, 8, 7, 8, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 0, 0, 0) + || test_pooling3d(9, 8, 7, 15, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 2, 0, 0, 0) + || test_pooling3d(9, 8, 7, 16, 0, ksp[i][0], ksp[i][1], ksp[i][2], 0, 3, 0, 0, 0); + + if (ret != 0) + return -1; + } + + return 0; +} + +static int test_pooling3d_1() +{ + static const int ksp[11][3] = { + {2, 1, 0}, + {2, 2, 0}, + {3, 1, 0}, + {3, 2, 1}, + {4, 1, 0}, + {4, 2, 1}, + {5, 1, 0}, + {5, 2, 2}, + {7, 1, 0}, + {7, 2, 1}, + {7, 3, 2}, + }; + + for (int i = 0; i < 11; i++) + { + int ret = 0 + || test_pooling3d(9, 8, 7, 1, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 0, 0, 0) + || test_pooling3d(9, 8, 7, 2, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 0, 0, 0) + || test_pooling3d(9, 8, 7, 3, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 1, 0, 0) + || test_pooling3d(9, 8, 7, 4, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 0, 0, 0) + || test_pooling3d(9, 8, 7, 7, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 0, 0, 0) + || test_pooling3d(9, 8, 7, 8, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 1, 0, 0) + || test_pooling3d(9, 8, 7, 12, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 2, 1, 0, 0) + || test_pooling3d(9, 8, 7, 15, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 0, 0, 0, 0) + || test_pooling3d(9, 8, 7, 16, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 1, 0, 0, 0) + || test_pooling3d(9, 8, 7, 64, 1, ksp[i][0], ksp[i][1], ksp[i][2], 0, 3, 1, 0, 0); + + if (ret != 0) + return -1; + } + + return 0; +} + +static int test_pooling3d_2() +{ + return 0 + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(3, 3, 6, 3, 0, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(6, 3, 3, 3, 1, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(7, 7, 8, 8, 1, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 1, 0, 0, 0, 0) + || test_pooling3d(48, 48, 48, 4, 0, 2, 2, 0, 0, 0, 0, 0, 0) + || test_pooling3d(48, 48, 48, 15, 0, 2, 2, 1, 0, 0, 0, 0, 0); +} + +// adaptive avg pool +static int test_pooling3d_3() +{ + return 0 + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(2, 2, 5, 1, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(5, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(3, 4, 6, 3, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 7) + || test_pooling3d(4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 8) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(6, 5, 4, 4, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 7) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 8) + || test_pooling3d(8, 7, 7, 8, 1, 1, 1, 0, 0, 0, 0, 1, 9) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 1) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 3) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 5) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 7) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 9) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 11) + || test_pooling3d(11, 12, 13, 16, 1, 1, 1, 0, 0, 0, 1, 0, 13) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 2) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 4) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 6) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 8) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 10) + || test_pooling3d(13, 12, 11, 16, 1, 1, 1, 0, 0, 0, 1, 0, 12); +} + +// adaptive max pool +static int test_pooling3d_4() +{ + return 0 + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(2, 2, 5, 1, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(5, 2, 2, 1, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(3, 4, 6, 3, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 7) + || test_pooling3d(4, 4, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 8) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(6, 5, 4, 4, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 1) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 2) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 3) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 4) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 5) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 6) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 7) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 8) + || test_pooling3d(8, 7, 7, 8, 0, 1, 1, 0, 0, 0, 0, 1, 9) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 1) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 3) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 5) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 7) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 9) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 11) + || test_pooling3d(11, 12, 13, 16, 0, 1, 1, 0, 0, 0, 1, 0, 13) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 2) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 4) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 6) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 8) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 10) + || test_pooling3d(13, 12, 11, 16, 0, 1, 1, 0, 0, 0, 1, 0, 12); +} + +int main() +{ + SRAND(7767517); + + return 0 + || test_pooling3d_0() + || test_pooling3d_1() + || test_pooling3d_2() + || test_pooling3d_3() + || test_pooling3d_4(); +} diff --git a/tests/testutil.h b/tests/testutil.h index 1ca42b7c8..27393e2b6 100644 --- a/tests/testutil.h +++ b/tests/testutil.h @@ -124,6 +124,13 @@ static ncnn::Mat RandomMat(int w, int h, int c) return m; } +static ncnn::Mat RandomMat(int w, int h, int d, int c) +{ + ncnn::Mat m(w, h, d, c); + Randomize(m); + return m; +} + static ncnn::Mat RandomIntMat(int w) { ncnn::Mat m(w); @@ -145,6 +152,13 @@ static ncnn::Mat RandomIntMat(int w, int h, int c) return m; } +static ncnn::Mat RandomIntMat(int w, int h, int d, int c) +{ + ncnn::Mat m(w, h, d, c); + RandomizeInt(m); + return m; +} + static ncnn::Mat RandomS8Mat(int w) { ncnn::Mat m(w, (size_t)1u); @@ -166,6 +180,13 @@ static ncnn::Mat RandomS8Mat(int w, int h, int c) return m; } +static ncnn::Mat RandomS8Mat(int w, int h, int d, int c) +{ + ncnn::Mat m(w, h, d, c, (size_t)1u); + RandomizeS8(m); + return m; +} + static ncnn::Mat scales_mat(const ncnn::Mat& mat, int m, int k, int ldx) { ncnn::Mat weight_scales(m); @@ -215,6 +236,7 @@ static int Compare(const ncnn::Mat& a, const ncnn::Mat& b, float epsilon = 0.001 CHECK_MEMBER(dims) CHECK_MEMBER(w) CHECK_MEMBER(h) + CHECK_MEMBER(d) CHECK_MEMBER(c) CHECK_MEMBER(elemsize) CHECK_MEMBER(elempack) @@ -225,16 +247,21 @@ static int Compare(const ncnn::Mat& a, const ncnn::Mat& b, float epsilon = 0.001 { const ncnn::Mat ma = a.channel(q); const ncnn::Mat mb = b.channel(q); - for (int i = 0; i < a.h; i++) + for (int z = 0; z < a.d; z++) { - const float* pa = ma.row(i); - const float* pb = mb.row(i); - for (int j = 0; j < a.w; j++) + const ncnn::Mat da = a.depth(z); + const ncnn::Mat db = b.depth(z); + for (int i = 0; i < a.h; i++) { - if (!NearlyEqual(pa[j], pb[j], epsilon)) + const float* pa = da.row(i); + const float* pb = db.row(i); + for (int j = 0; j < a.w; j++) { - fprintf(stderr, "value not match at c:%d h:%d w:%d expect %f but got %f\n", q, i, j, pa[j], pb[j]); - return -1; + if (!NearlyEqual(pa[j], pb[j], epsilon)) + { + fprintf(stderr, "value not match at c:%d d:%d h:%d w:%d expect %f but got %f\n", q, z, i, j, pa[j], pb[j]); + return -1; + } } } } diff --git a/tools/pnnx/README.md b/tools/pnnx/README.md index 1d45702f8..19491c6bd 100644 --- a/tools/pnnx/README.md +++ b/tools/pnnx/README.md @@ -414,16 +414,16 @@ TORCH_LIBRARY(upfirdn2d_op, m) { | torch.nn | Is Supported | Export to ncnn | |---------------------------|----|---| -|nn.AdaptiveAvgPool1d | :heavy_check_mark: | +|nn.AdaptiveAvgPool1d | :heavy_check_mark: | :heavy_check_mark: | |nn.AdaptiveAvgPool2d | :heavy_check_mark: | :heavy_check_mark: | -|nn.AdaptiveAvgPool3d | :heavy_check_mark: | -|nn.AdaptiveMaxPool1d | :heavy_check_mark: | +|nn.AdaptiveAvgPool3d | :heavy_check_mark: | :heavy_check_mark: | +|nn.AdaptiveMaxPool1d | :heavy_check_mark: | :heavy_check_mark: | |nn.AdaptiveMaxPool2d | :heavy_check_mark: | :heavy_check_mark: | -|nn.AdaptiveMaxPool3d | :heavy_check_mark: | +|nn.AdaptiveMaxPool3d | :heavy_check_mark: | :heavy_check_mark: | |nn.AlphaDropout | | -|nn.AvgPool1d | :heavy_check_mark: | +|nn.AvgPool1d | :heavy_check_mark: | :heavy_check_mark:* | |nn.AvgPool2d | :heavy_check_mark: | :heavy_check_mark:* | -|nn.AvgPool3d | :heavy_check_mark: | +|nn.AvgPool3d | :heavy_check_mark: | :heavy_check_mark:* | |nn.BatchNorm1d | :heavy_check_mark: | :heavy_check_mark: | |nn.BatchNorm2d | :heavy_check_mark: | :heavy_check_mark: | |nn.BatchNorm3d | :heavy_check_mark: | @@ -432,10 +432,10 @@ TORCH_LIBRARY(upfirdn2d_op, m) { |nn.ChannelShuffle | :heavy_check_mark: | :heavy_check_mark: | |nn.ConstantPad1d | :heavy_check_mark: | :heavy_check_mark: | |nn.ConstantPad2d | :heavy_check_mark: | :heavy_check_mark: | -|nn.ConstantPad3d | :heavy_check_mark: | +|nn.ConstantPad3d | :heavy_check_mark: | :heavy_check_mark: | |nn.Conv1d | :heavy_check_mark: | :heavy_check_mark: | |nn.Conv2d | :heavy_check_mark: | :heavy_check_mark: | -|nn.Conv3d | :heavy_check_mark: | +|nn.Conv3d | :heavy_check_mark: | :heavy_check_mark: | |nn.ConvTranspose1d | :heavy_check_mark: | |nn.ConvTranspose2d | :heavy_check_mark: | :heavy_check_mark: | |nn.ConvTranspose3d | :heavy_check_mark: | @@ -482,9 +482,9 @@ TORCH_LIBRARY(upfirdn2d_op, m) { |nn.LPPool2d | :heavy_check_mark: | |nn.LSTM | :heavy_check_mark: | :heavy_check_mark: | |nn.LSTMCell | | -|nn.MaxPool1d | :heavy_check_mark: | +|nn.MaxPool1d | :heavy_check_mark: | :heavy_check_mark: | |nn.MaxPool2d | :heavy_check_mark: | :heavy_check_mark: | -|nn.MaxPool3d | :heavy_check_mark: | +|nn.MaxPool3d | :heavy_check_mark: | :heavy_check_mark: | |nn.MaxUnpool1d | | |nn.MaxUnpool2d | | |nn.MaxUnpool3d | | @@ -533,17 +533,17 @@ TORCH_LIBRARY(upfirdn2d_op, m) { | torch.nn.functional | Is Supported | Export to ncnn | |---------------------------|----|----| -|F.adaptive_avg_pool1d | :heavy_check_mark: | +|F.adaptive_avg_pool1d | :heavy_check_mark: | :heavy_check_mark: | |F.adaptive_avg_pool2d | :heavy_check_mark: | :heavy_check_mark: | -|F.adaptive_avg_pool3d | :heavy_check_mark: | -|F.adaptive_max_pool1d | :heavy_check_mark: | +|F.adaptive_avg_pool3d | :heavy_check_mark: | :heavy_check_mark: | +|F.adaptive_max_pool1d | :heavy_check_mark: | :heavy_check_mark: | |F.adaptive_max_pool2d | :heavy_check_mark: | :heavy_check_mark: | -|F.adaptive_max_pool3d | :heavy_check_mark: | -|F.affine_grid | :heavy_check_mark: | +|F.adaptive_max_pool3d | :heavy_check_mark: | :heavy_check_mark: | +|F.affine_grid | :heavy_check_mark: | :heavy_check_mark: | |F.alpha_dropout | | -|F.avg_pool1d | :heavy_check_mark: | -|F.avg_pool2d | :heavy_check_mark: | -|F.avg_pool3d | :heavy_check_mark: | +|F.avg_pool1d | :heavy_check_mark: | :heavy_check_mark:* | +|F.avg_pool2d | :heavy_check_mark: | :heavy_check_mark:* | +|F.avg_pool3d | :heavy_check_mark: | :heavy_check_mark:* | |F.batch_norm | :heavy_check_mark: | :heavy_check_mark: | |F.bilinear | | |F.celu | :heavy_check_mark: | @@ -586,9 +586,9 @@ TORCH_LIBRARY(upfirdn2d_op, m) { |F.log_softmax | :heavy_check_mark: | |F.lp_pool1d | :heavy_check_mark: | |F.lp_pool2d | :heavy_check_mark: | -|F.max_pool1d | :heavy_check_mark: | -|F.max_pool2d | :heavy_check_mark: | -|F.max_pool3d | :heavy_check_mark: | +|F.max_pool1d | :heavy_check_mark: | :heavy_check_mark: | +|F.max_pool2d | :heavy_check_mark: | :heavy_check_mark: | +|F.max_pool3d | :heavy_check_mark: | :heavy_check_mark: | |F.max_unpool1d | | |F.max_unpool2d | | |F.max_unpool3d | | diff --git a/tools/pnnx/src/CMakeLists.txt b/tools/pnnx/src/CMakeLists.txt index 61e565515..175f4df6d 100644 --- a/tools/pnnx/src/CMakeLists.txt +++ b/tools/pnnx/src/CMakeLists.txt @@ -195,6 +195,7 @@ set(pnnx_pass_level4_SRCS ) set(pnnx_pass_level5_SRCS + pass_level5/eliminate_maxpool_indices.cpp pass_level5/eliminate_slice.cpp pass_level5/eliminate_view_reshape.cpp pass_level5/eval_expression.cpp @@ -230,8 +231,15 @@ set(pnnx_pass_ncnn_SRCS pass_ncnn/fuse_deconvolutiondepthwise_activation.cpp pass_ncnn/fuse_innerproduct_activation.cpp + pass_ncnn/F_adaptive_avg_pool1d.cpp pass_ncnn/F_adaptive_avg_pool2d.cpp + pass_ncnn/F_adaptive_avg_pool3d.cpp + pass_ncnn/F_adaptive_max_pool1d.cpp pass_ncnn/F_adaptive_max_pool2d.cpp + pass_ncnn/F_adaptive_max_pool3d.cpp + pass_ncnn/F_avg_pool1d.cpp + pass_ncnn/F_avg_pool2d.cpp + pass_ncnn/F_avg_pool3d.cpp pass_ncnn/F_batch_norm.cpp pass_ncnn/F_conv2d.cpp pass_ncnn/F_elu.cpp @@ -246,6 +254,9 @@ set(pnnx_pass_ncnn_SRCS pass_ncnn/F_leaky_relu.cpp pass_ncnn/F_linear.cpp pass_ncnn/F_local_response_norm.cpp + pass_ncnn/F_max_pool1d.cpp + pass_ncnn/F_max_pool2d.cpp + pass_ncnn/F_max_pool3d.cpp pass_ncnn/F_mish.cpp pass_ncnn/F_normalize.cpp pass_ncnn/F_pad.cpp @@ -262,16 +273,24 @@ set(pnnx_pass_ncnn_SRCS pass_ncnn/F_upsample_bilinear.cpp pass_ncnn/F_upsample_nearest.cpp pass_ncnn/F_upsample.cpp + pass_ncnn/nn_AdaptiveAvgPool1d.cpp pass_ncnn/nn_AdaptiveAvgPool2d.cpp + pass_ncnn/nn_AdaptiveAvgPool3d.cpp + pass_ncnn/nn_AdaptiveMaxPool1d.cpp pass_ncnn/nn_AdaptiveMaxPool2d.cpp + pass_ncnn/nn_AdaptiveMaxPool3d.cpp + pass_ncnn/nn_AvgPool1d.cpp pass_ncnn/nn_AvgPool2d.cpp + pass_ncnn/nn_AvgPool3d.cpp pass_ncnn/nn_BatchNorm1d.cpp pass_ncnn/nn_BatchNorm2d.cpp pass_ncnn/nn_ChannelShuffle.cpp pass_ncnn/nn_ConstantPad1d.cpp pass_ncnn/nn_ConstantPad2d.cpp + pass_ncnn/nn_ConstantPad3d.cpp pass_ncnn/nn_Conv1d.cpp pass_ncnn/nn_Conv2d.cpp + pass_ncnn/nn_Conv3d.cpp pass_ncnn/nn_ConvTranspose2d.cpp pass_ncnn/nn_Dropout.cpp pass_ncnn/nn_ELU.cpp @@ -288,7 +307,9 @@ set(pnnx_pass_ncnn_SRCS pass_ncnn/nn_Linear.cpp pass_ncnn/nn_LocalResponseNorm.cpp pass_ncnn/nn_LSTM.cpp + pass_ncnn/nn_MaxPool1d.cpp pass_ncnn/nn_MaxPool2d.cpp + pass_ncnn/nn_MaxPool3d.cpp pass_ncnn/nn_Mish.cpp pass_ncnn/nn_MultiheadAttention.cpp pass_ncnn/nn_PixelShuffle.cpp diff --git a/tools/pnnx/src/pass_level1/nn_AdaptiveMaxPool1d.cpp b/tools/pnnx/src/pass_level1/nn_AdaptiveMaxPool1d.cpp index 59f838cbe..aaf7a224b 100644 --- a/tools/pnnx/src/pass_level1/nn_AdaptiveMaxPool1d.cpp +++ b/tools/pnnx/src/pass_level1/nn_AdaptiveMaxPool1d.cpp @@ -33,8 +33,6 @@ public: void write(Operator* op, const std::shared_ptr& graph) const { - graph->dump(); - const torch::jit::Node* adaptive_max_pool1d = find_node_by_kind(graph, "aten::adaptive_max_pool1d"); op->params["output_size"] = adaptive_max_pool1d->namedInput("output_size"); diff --git a/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.cpp b/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.cpp new file mode 100644 index 000000000..a677fef3a --- /dev/null +++ b/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.cpp @@ -0,0 +1,70 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "eliminate_maxpool_indices.h" + +#include +#include "pass_level2.h" + +namespace pnnx { + +void eliminate_maxpool_indices(Graph& graph) +{ + while (1) + { + bool matched = false; + + for (size_t i = 0; i < graph.ops.size(); i++) + { + Operator* op = graph.ops[i]; + + if (op->type != "F.adaptive_max_pool1d" && op->type != "F.adaptive_max_pool2d" && op->type != "F.adaptive_max_pool3d" + && op->type != "F.max_pool1d" && op->type != "F.max_pool2d" && op->type != "F.max_pool3d" + && op->type != "nn.AdaptiveMaxPool1d" && op->type != "nn.AdaptiveMaxPool2d" && op->type != "nn.AdaptiveMaxPool3d" + && op->type != "nn.MaxPool1d" && op->type != "nn.MaxPool2d" && op->type != "nn.MaxPool3d") + continue; + + if (op->outputs.size() != 2) + continue; + + if (op->params.find("return_indices") == op->params.end()) + continue; + + if (op->params.at("return_indices").b == false) + continue; + + Operand* op_indices = op->outputs[1]; + + if (!op_indices->consumers.empty()) + continue; + + matched = true; + + op->params["return_indices"] = false; + op->outputs.resize(1); + + op_indices->producer = 0; + + graph.operands.erase(std::find(graph.operands.begin(), graph.operands.end(), op_indices)); + delete op_indices; + + break; + } + + if (!matched) + break; + } +} + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.h b/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.h new file mode 100644 index 000000000..deecf3169 --- /dev/null +++ b/tools/pnnx/src/pass_level5/eliminate_maxpool_indices.h @@ -0,0 +1,21 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "ir.h" + +namespace pnnx { + +void eliminate_maxpool_indices(Graph& graph); + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn.cpp b/tools/pnnx/src/pass_ncnn.cpp index 2dffc2c2e..f19fb1dd0 100644 --- a/tools/pnnx/src/pass_ncnn.cpp +++ b/tools/pnnx/src/pass_ncnn.cpp @@ -37,6 +37,7 @@ #include "pass_level4/dead_code_elimination.h" #include "pass_level4/canonicalize.h" +#include "pass_level5/eliminate_maxpool_indices.h" #include "pass_level5/unroll_rnn_op.h" namespace pnnx { @@ -63,6 +64,8 @@ void pass_ncnn(Graph& g) { unroll_rnn_op(g); + eliminate_maxpool_indices(g); + ncnn::expand_expression(g); ncnn::chain_multi_output(g); diff --git a/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool1d.cpp b/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool1d.cpp new file mode 100644 index 000000000..e975151da --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool1d.cpp @@ -0,0 +1,88 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_adaptive_avg_pool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_avg_pool1d op_0 1 1 input out output_size=(1) +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "gap1d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 1; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_avg_pool1d, 20) + +class F_adaptive_avg_pool1d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_avg_pool1d op_0 1 1 input out output_size=%output_size +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "aap1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 1; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_avg_pool1d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool3d.cpp b/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool3d.cpp new file mode 100644 index 000000000..469ebdc58 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_adaptive_avg_pool3d.cpp @@ -0,0 +1,90 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_adaptive_avg_pool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_avg_pool3d op_0 1 1 input out output_size=(1,1,1) +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "gap3d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 1; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_avg_pool3d, 20) + +class F_adaptive_avg_pool3d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_avg_pool3d op_0 1 1 input out output_size=%output_size +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "aap3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 1; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[2]; + op->params["18"] = captured_params.at("output_size").ai[1]; + op->params["28"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_avg_pool3d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool1d.cpp b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool1d.cpp new file mode 100644 index 000000000..816794794 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool1d.cpp @@ -0,0 +1,88 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_adaptive_max_pool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_max_pool1d op_0 1 1 input out output_size=(1) return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "gmp1d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 0; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_max_pool1d, 20) + +class F_adaptive_max_pool1d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_max_pool1d op_0 1 1 input out output_size=%output_size return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "amp1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_max_pool1d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool2d.cpp b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool2d.cpp index d514ed673..ae5ec51f1 100644 --- a/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool2d.cpp +++ b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool2d.cpp @@ -26,7 +26,7 @@ public: return R"PNNXIR(7767517 3 2 pnnx.Input input 0 1 input -F.adaptive_max_pool2d op_0 1 1 input out output_size=(1,1) +F.adaptive_max_pool2d op_0 1 1 input out output_size=(1,1) return_indices=False pnnx.Output output 1 0 out )PNNXIR"; } @@ -58,7 +58,7 @@ public: return R"PNNXIR(7767517 3 2 pnnx.Input input 0 1 input -F.adaptive_max_pool2d op_0 1 1 input out output_size=%output_size +F.adaptive_max_pool2d op_0 1 1 input out output_size=%output_size return_indices=False pnnx.Output output 1 0 out )PNNXIR"; } diff --git a/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool3d.cpp b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool3d.cpp new file mode 100644 index 000000000..c465ac5e9 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_adaptive_max_pool3d.cpp @@ -0,0 +1,90 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_adaptive_max_pool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_max_pool3d op_0 1 1 input out output_size=(1,1,1) return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "gmp3d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 0; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_max_pool3d, 20) + +class F_adaptive_max_pool3d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.adaptive_max_pool3d op_0 1 1 input out output_size=%output_size return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "amp3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[2]; + op->params["18"] = captured_params.at("output_size").ai[1]; + op->params["28"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_adaptive_max_pool3d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_avg_pool1d.cpp b/tools/pnnx/src/pass_ncnn/F_avg_pool1d.cpp new file mode 100644 index 000000000..691b762d1 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_avg_pool1d.cpp @@ -0,0 +1,69 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_avg_pool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.avg_pool1d op_0 1 1 input out kernel_size=%kernel_size stride=%stride padding=%padding ceil_mode=%ceil_mode count_include_pad=%count_include_pad +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "avgpool1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 1; + op->params["1"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + op->params["6"] = captured_params.at("count_include_pad").b ? 1 : 0; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_avg_pool1d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_avg_pool2d.cpp b/tools/pnnx/src/pass_ncnn/F_avg_pool2d.cpp new file mode 100644 index 000000000..8403831f8 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_avg_pool2d.cpp @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_avg_pool2d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.avg_pool2d op_0 1 1 input out kernel_size=%kernel_size stride=%stride padding=%padding ceil_mode=%ceil_mode count_include_pad=%count_include_pad divisor_override=%divisor_override +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling"; + } + + const char* name_str() const + { + return "avgpool2d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + if (captured_params.at("divisor_override").type != 0) + { + fprintf(stderr, "unsupported avgpool2d divisor_override\n"); + return; + } + + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 1; + op->params["1"] = captured_params.at("kernel_size").ai[1]; + op->params["11"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[1]; + op->params["12"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[1]; + op->params["13"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + op->params["6"] = captured_params.at("count_include_pad").b ? 1 : 0; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_avg_pool2d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_avg_pool3d.cpp b/tools/pnnx/src/pass_ncnn/F_avg_pool3d.cpp new file mode 100644 index 000000000..ec5d4123a --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_avg_pool3d.cpp @@ -0,0 +1,81 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_avg_pool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.avg_pool3d op_0 1 1 input out kernel_size=%kernel_size stride=%stride padding=%padding ceil_mode=%ceil_mode count_include_pad=%count_include_pad divisor_override=%divisor_override +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "avgpool3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + if (captured_params.at("divisor_override").type != 0) + { + fprintf(stderr, "unsupported avgpool3d divisor_override\n"); + return; + } + + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 1; + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[2]; + op->params["12"] = stride[1]; + op->params["22"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[2]; + op->params["13"] = captured_params.at("padding").ai[1]; + op->params["23"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + op->params["6"] = captured_params.at("count_include_pad").b ? 1 : 0; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_avg_pool3d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_max_pool1d.cpp b/tools/pnnx/src/pass_ncnn/F_max_pool1d.cpp new file mode 100644 index 000000000..1d9ca98e0 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_max_pool1d.cpp @@ -0,0 +1,68 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_max_pool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.max_pool1d op_0 1 1 input out kernel_size=%kernel_size stride=%stride dilation=(1) padding=%padding ceil_mode=%ceil_mode return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "maxpool1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 0; + op->params["1"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_max_pool1d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_max_pool2d.cpp b/tools/pnnx/src/pass_ncnn/F_max_pool2d.cpp new file mode 100644 index 000000000..ba5a52f4f --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_max_pool2d.cpp @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_max_pool2d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.max_pool2d op_0 1 1 input out kernel_size=%kernel_size stride=%stride dilation=(1,1) padding=%padding ceil_mode=%ceil_mode return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling"; + } + + const char* name_str() const + { + return "maxpool2d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 0; + op->params["1"] = captured_params.at("kernel_size").ai[1]; + op->params["11"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[1]; + op->params["12"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[1]; + op->params["13"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_max_pool2d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/F_max_pool3d.cpp b/tools/pnnx/src/pass_ncnn/F_max_pool3d.cpp new file mode 100644 index 000000000..5476907fa --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/F_max_pool3d.cpp @@ -0,0 +1,74 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class F_max_pool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +F.max_pool3d op_0 1 1 input out kernel_size=%kernel_size stride=%stride dilation=(1,1,1) padding=%padding ceil_mode=%ceil_mode return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "maxpool3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + std::vector stride; + if (captured_params.at("stride").type == 0) + { + stride = captured_params.at("kernel_size").ai; + } + else + { + stride = captured_params.at("stride").ai; + } + + op->params["0"] = 0; + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = stride[2]; + op->params["12"] = stride[1]; + op->params["22"] = stride[0]; + op->params["3"] = captured_params.at("padding").ai[2]; + op->params["13"] = captured_params.at("padding").ai[1]; + op->params["23"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(F_max_pool3d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool1d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool1d.cpp new file mode 100644 index 000000000..2ee31d471 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool1d.cpp @@ -0,0 +1,88 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AdaptiveAvgPool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveAvgPool1d op_0 1 1 input out output_size=1 +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "gap"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 1; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool1d, 20) + +class nn_AdaptiveAvgPool1d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveAvgPool1d op_0 1 1 input out output_size=%output_size +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "aap"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 1; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool1d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool2d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool2d.cpp index 869f6020d..ae76bdbe2 100644 --- a/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool2d.cpp +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool2d.cpp @@ -82,7 +82,7 @@ pnnx.Output output 1 0 out } }; -REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool2d_n, 20) +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool2d_n, 21) } // namespace ncnn diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool3d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool3d.cpp new file mode 100644 index 000000000..17f873dbd --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveAvgPool3d.cpp @@ -0,0 +1,90 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AdaptiveAvgPool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveAvgPool3d op_0 1 1 input out output_size=(1,1,1) +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "gap3d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 1; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool3d, 20) + +class nn_AdaptiveAvgPool3d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveAvgPool3d op_0 1 1 input out output_size=%output_size +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "aap3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 1; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[2]; + op->params["18"] = captured_params.at("output_size").ai[1]; + op->params["28"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveAvgPool3d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool1d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool1d.cpp new file mode 100644 index 000000000..790103ad7 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool1d.cpp @@ -0,0 +1,88 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AdaptiveMaxPool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveMaxPool1d op_0 1 1 input out output_size=(1) return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "gmp1d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 0; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool1d, 20) + +class nn_AdaptiveMaxPool1d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveMaxPool1d op_0 1 1 input out output_size=%output_size return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "amp1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool1d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool2d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool2d.cpp index 33ba4df01..3dbb4e39b 100644 --- a/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool2d.cpp +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool2d.cpp @@ -26,7 +26,7 @@ public: return R"PNNXIR(7767517 3 2 pnnx.Input input 0 1 input -nn.AdaptiveMaxPool2d op_0 1 1 input out output_size=(1,1) +nn.AdaptiveMaxPool2d op_0 1 1 input out output_size=(1,1) return_indices=False pnnx.Output output 1 0 out )PNNXIR"; } @@ -58,7 +58,7 @@ public: return R"PNNXIR(7767517 3 2 pnnx.Input input 0 1 input -nn.AdaptiveMaxPool2d op_0 1 1 input out output_size=%output_size +nn.AdaptiveMaxPool2d op_0 1 1 input out output_size=%output_size return_indices=False pnnx.Output output 1 0 out )PNNXIR"; } @@ -82,7 +82,7 @@ pnnx.Output output 1 0 out } }; -REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool2d_n, 20) +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool2d_n, 21) } // namespace ncnn diff --git a/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool3d.cpp b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool3d.cpp new file mode 100644 index 000000000..3df76fb0e --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AdaptiveMaxPool3d.cpp @@ -0,0 +1,90 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AdaptiveMaxPool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveMaxPool3d op_0 1 1 input out output_size=(1,1,1) return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "gmp3d"; + } + + void write(Operator* op, const std::map& /*captured_params*/) const + { + op->params["0"] = 0; + op->params["4"] = 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool3d, 20) + +class nn_AdaptiveMaxPool3d_n : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AdaptiveMaxPool3d op_0 1 1 input out output_size=%output_size return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "amp3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["7"] = 1; + op->params["8"] = captured_params.at("output_size").ai[2]; + op->params["18"] = captured_params.at("output_size").ai[1]; + op->params["28"] = captured_params.at("output_size").ai[0]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AdaptiveMaxPool3d_n, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AvgPool1d.cpp b/tools/pnnx/src/pass_ncnn/nn_AvgPool1d.cpp new file mode 100644 index 000000000..20e0a9474 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AvgPool1d.cpp @@ -0,0 +1,59 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AvgPool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AvgPool1d op_0 1 1 input out kernel_size=%kernel_size stride=%stride padding=%padding ceil_mode=%ceil_mode count_include_pad=%count_include_pad +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "avgpool1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 1; + op->params["1"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("stride").ai[0]; + op->params["3"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + op->params["6"] = captured_params.at("count_include_pad").b ? 1 : 0; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AvgPool1d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_AvgPool3d.cpp b/tools/pnnx/src/pass_ncnn/nn_AvgPool3d.cpp new file mode 100644 index 000000000..65783a28e --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_AvgPool3d.cpp @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_AvgPool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.AvgPool3d op_0 1 1 input out kernel_size=%kernel_size stride=%stride padding=%padding ceil_mode=%ceil_mode count_include_pad=%count_include_pad divisor_override=%divisor_override +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "avgpool3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + if (captured_params.at("divisor_override").type != 0) + { + fprintf(stderr, "unsupported avgpool3d divisor_override\n"); + return; + } + + op->params["0"] = 1; + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("stride").ai[2]; + op->params["12"] = captured_params.at("stride").ai[1]; + op->params["22"] = captured_params.at("stride").ai[0]; + op->params["3"] = captured_params.at("padding").ai[2]; + op->params["13"] = captured_params.at("padding").ai[1]; + op->params["23"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + op->params["6"] = captured_params.at("count_include_pad").b ? 1 : 0; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_AvgPool3d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_ConstantPad3d.cpp b/tools/pnnx/src/pass_ncnn/nn_ConstantPad3d.cpp new file mode 100644 index 000000000..748f42922 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_ConstantPad3d.cpp @@ -0,0 +1,68 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_ConstantPad3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.ConstantPad3d op_0 1 1 input out padding=%padding value=%value +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Padding"; + } + + const char* name_str() const + { + return "constpad3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + float pad_value = 0.f; + if (captured_params.at("value").type == 2) + pad_value = captured_params.at("value").i; + if (captured_params.at("value").type == 3) + pad_value = captured_params.at("value").f; + + op->params["0"] = captured_params.at("padding").ai[2]; + op->params["1"] = captured_params.at("padding").ai[3]; + op->params["2"] = captured_params.at("padding").ai[0]; + op->params["3"] = captured_params.at("padding").ai[1]; + op->params["4"] = 0; + op->params["5"] = pad_value; + op->params["6"] = 0; // per_channel_pad_data_size + op->params["7"] = captured_params.at("padding").ai[4]; + op->params["8"] = captured_params.at("padding").ai[5]; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_ConstantPad3d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_Conv3d.cpp b/tools/pnnx/src/pass_ncnn/nn_Conv3d.cpp new file mode 100644 index 000000000..e20f24b28 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_Conv3d.cpp @@ -0,0 +1,145 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_Conv3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.Conv3d op_0 1 1 input out in_channels=%in_channels out_channels=%out_channels kernel_size=%kernel_size stride=%stride padding=%padding dilation=%dilation groups=1 bias=%bias @weight @bias +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Convolution3D"; + } + + const char* name_str() const + { + return "conv3d"; + } + + void write(Operator* op, const std::map& captured_params, const std::map& captured_attrs) const + { + op->params["0"] = captured_params.at("out_channels"); + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("dilation").ai[2]; + op->params["12"] = captured_params.at("dilation").ai[1]; + op->params["22"] = captured_params.at("dilation").ai[0]; + op->params["3"] = captured_params.at("stride").ai[2]; + op->params["13"] = captured_params.at("stride").ai[1]; + op->params["23"] = captured_params.at("stride").ai[0]; + if (captured_params.at("padding").type == 4) + { + if (captured_params.at("padding").s == "same") + op->params["4"] = -233; + else if (captured_params.at("padding").s == "valid") + op->params["4"] = 0; + } + else + { + op->params["4"] = captured_params.at("padding").ai[2]; + op->params["14"] = captured_params.at("padding").ai[1]; + op->params["24"] = captured_params.at("padding").ai[0]; + } + op->params["5"] = captured_params.at("bias").b ? 1 : 0; + op->params["6"] = (int)(captured_attrs.at("op_0.weight").data.size() / sizeof(float)); + + op->attrs["0"] = Attribute(); + op->attrs["0"].data = {0, 0, 0, 0}; + op->attrs["1"] = captured_attrs.at("op_0.weight"); + if (captured_params.at("bias").b) + op->attrs["2"] = captured_attrs.at("op_0.bias"); + } +}; + +class nn_Conv3d_1 : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.Conv3d op_0 1 1 input out in_channels=%in_channels out_channels=%out_channels kernel_size=%kernel_size stride=%stride padding=%padding dilation=%dilation groups=%groups bias=%bias @weight @bias +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "ConvolutionDepthWise3D"; + } + + const char* name_str() const + { + return "convdw3d"; + } + + void write(Operator* op, const std::map& captured_params, const std::map& captured_attrs) const + { + op->params["0"] = captured_params.at("out_channels"); + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("dilation").ai[2]; + op->params["12"] = captured_params.at("dilation").ai[1]; + op->params["22"] = captured_params.at("dilation").ai[0]; + op->params["3"] = captured_params.at("stride").ai[2]; + op->params["13"] = captured_params.at("stride").ai[1]; + op->params["23"] = captured_params.at("stride").ai[0]; + if (captured_params.at("padding").type == 4) + { + if (captured_params.at("padding").s == "same") + op->params["4"] = -233; + else if (captured_params.at("padding").s == "valid") + op->params["4"] = 0; + } + else + { + op->params["4"] = captured_params.at("padding").ai[2]; + op->params["14"] = captured_params.at("padding").ai[1]; + op->params["24"] = captured_params.at("padding").ai[0]; + } + op->params["5"] = captured_params.at("bias").b ? 1 : 0; + op->params["6"] = (int)(captured_attrs.at("op_0.weight").data.size() / sizeof(float)); + op->params["7"] = captured_params.at("groups"); + + op->attrs["0"] = Attribute(); + op->attrs["0"].data = {0, 0, 0, 0}; + op->attrs["1"] = captured_attrs.at("op_0.weight"); + if (captured_params.at("bias").b) + op->attrs["2"] = captured_attrs.at("op_0.bias"); + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_Conv3d, 20) +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_Conv3d_1, 21) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_MaxPool1d.cpp b/tools/pnnx/src/pass_ncnn/nn_MaxPool1d.cpp new file mode 100644 index 000000000..aeec9b176 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_MaxPool1d.cpp @@ -0,0 +1,58 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_MaxPool1d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.MaxPool1d op_0 1 1 input out kernel_size=%kernel_size stride=%stride dilation=(1) padding=%padding ceil_mode=%ceil_mode return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling1D"; + } + + const char* name_str() const + { + return "maxpool1d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["1"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("stride").ai[0]; + op->params["3"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_MaxPool1d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/src/pass_ncnn/nn_MaxPool3d.cpp b/tools/pnnx/src/pass_ncnn/nn_MaxPool3d.cpp new file mode 100644 index 000000000..dd67939a8 --- /dev/null +++ b/tools/pnnx/src/pass_ncnn/nn_MaxPool3d.cpp @@ -0,0 +1,64 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#include "pass_ncnn.h" + +namespace pnnx { + +namespace ncnn { + +class nn_MaxPool3d : public GraphRewriterPass +{ +public: + const char* match_pattern_graph() const + { + return R"PNNXIR(7767517 +3 2 +pnnx.Input input 0 1 input +nn.MaxPool3d op_0 1 1 input out kernel_size=%kernel_size stride=%stride dilation=(1,1,1) padding=%padding ceil_mode=%ceil_mode return_indices=False +pnnx.Output output 1 0 out +)PNNXIR"; + } + + const char* type_str() const + { + return "Pooling3D"; + } + + const char* name_str() const + { + return "maxpool3d"; + } + + void write(Operator* op, const std::map& captured_params) const + { + op->params["0"] = 0; + op->params["1"] = captured_params.at("kernel_size").ai[2]; + op->params["11"] = captured_params.at("kernel_size").ai[1]; + op->params["21"] = captured_params.at("kernel_size").ai[0]; + op->params["2"] = captured_params.at("stride").ai[2]; + op->params["12"] = captured_params.at("stride").ai[1]; + op->params["22"] = captured_params.at("stride").ai[0]; + op->params["3"] = captured_params.at("padding").ai[2]; + op->params["13"] = captured_params.at("padding").ai[1]; + op->params["23"] = captured_params.at("padding").ai[0]; + op->params["5"] = captured_params.at("ceil_mode").b ? 0 : 1; + } +}; + +REGISTER_GLOBAL_PNNX_NCNN_GRAPH_REWRITER_PASS(nn_MaxPool3d, 20) + +} // namespace ncnn + +} // namespace pnnx diff --git a/tools/pnnx/tests/ncnn/CMakeLists.txt b/tools/pnnx/tests/ncnn/CMakeLists.txt index 85a45dcfc..b254b8d61 100644 --- a/tools/pnnx/tests/ncnn/CMakeLists.txt +++ b/tools/pnnx/tests/ncnn/CMakeLists.txt @@ -5,6 +5,15 @@ macro(pnnx_ncnn_add_test name) add_test(NAME test_ncnn_${name} COMMAND ${CMAKE_COMMAND} -DPYTHON_EXECUTABLE=${Python3_EXECUTABLE} -DPYTHON_SCRIPT=${CMAKE_CURRENT_SOURCE_DIR}/test_${name}.py -P ${CMAKE_CURRENT_SOURCE_DIR}/../run_test.cmake) endmacro() +pnnx_ncnn_add_test(F_adaptive_avg_pool1d) +pnnx_ncnn_add_test(F_adaptive_avg_pool2d) +pnnx_ncnn_add_test(F_adaptive_avg_pool3d) +pnnx_ncnn_add_test(F_adaptive_max_pool1d) +pnnx_ncnn_add_test(F_adaptive_max_pool2d) +pnnx_ncnn_add_test(F_adaptive_max_pool3d) +pnnx_ncnn_add_test(F_avg_pool1d) +pnnx_ncnn_add_test(F_avg_pool2d) +pnnx_ncnn_add_test(F_avg_pool3d) pnnx_ncnn_add_test(F_elu) pnnx_ncnn_add_test(F_gelu) pnnx_ncnn_add_test(F_hardsigmoid) @@ -13,6 +22,9 @@ pnnx_ncnn_add_test(F_hardtanh) pnnx_ncnn_add_test(F_interpolate) pnnx_ncnn_add_test(F_leaky_relu) pnnx_ncnn_add_test(F_local_response_norm) +pnnx_ncnn_add_test(F_max_pool1d) +pnnx_ncnn_add_test(F_max_pool2d) +pnnx_ncnn_add_test(F_max_pool3d) pnnx_ncnn_add_test(F_normalize) pnnx_ncnn_add_test(F_pad) pnnx_ncnn_add_test(F_pixel_shuffle) @@ -27,15 +39,24 @@ pnnx_ncnn_add_test(F_upsample_bilinear) pnnx_ncnn_add_test(F_upsample_nearest) pnnx_ncnn_add_test(F_upsample) +pnnx_ncnn_add_test(nn_AdaptiveAvgPool1d) pnnx_ncnn_add_test(nn_AdaptiveAvgPool2d) +pnnx_ncnn_add_test(nn_AdaptiveAvgPool3d) +pnnx_ncnn_add_test(nn_AdaptiveMaxPool1d) +pnnx_ncnn_add_test(nn_AdaptiveMaxPool2d) +pnnx_ncnn_add_test(nn_AdaptiveMaxPool3d) +pnnx_ncnn_add_test(nn_AvgPool1d) pnnx_ncnn_add_test(nn_AvgPool2d) +pnnx_ncnn_add_test(nn_AvgPool3d) pnnx_ncnn_add_test(nn_BatchNorm1d) pnnx_ncnn_add_test(nn_BatchNorm2d) pnnx_ncnn_add_test(nn_ChannelShuffle) pnnx_ncnn_add_test(nn_ConstantPad1d) pnnx_ncnn_add_test(nn_ConstantPad2d) +pnnx_ncnn_add_test(nn_ConstantPad3d) pnnx_ncnn_add_test(nn_Conv1d) pnnx_ncnn_add_test(nn_Conv2d) +pnnx_ncnn_add_test(nn_Conv3d) pnnx_ncnn_add_test(nn_ConvTranspose2d) pnnx_ncnn_add_test(nn_ELU) pnnx_ncnn_add_test(nn_GELU) @@ -50,7 +71,9 @@ pnnx_ncnn_add_test(nn_LeakyReLU) pnnx_ncnn_add_test(nn_Linear) pnnx_ncnn_add_test(nn_LocalResponseNorm) pnnx_ncnn_add_test(nn_LSTM) +pnnx_ncnn_add_test(nn_MaxPool1d) pnnx_ncnn_add_test(nn_MaxPool2d) +pnnx_ncnn_add_test(nn_MaxPool3d) pnnx_ncnn_add_test(nn_MultiheadAttention) pnnx_ncnn_add_test(nn_PixelShuffle) pnnx_ncnn_add_test(nn_PixelUnshuffle) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool1d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool1d.py new file mode 100644 index 000000000..62cc45086 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool1d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_avg_pool1d(x, output_size=7) + x = F.adaptive_avg_pool1d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_avg_pool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_avg_pool1d.pt inputshape=[1,12,24]") + + # ncnn inference + import test_F_adaptive_avg_pool1d_ncnn + b = test_F_adaptive_avg_pool1d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool2d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool2d.py new file mode 100644 index 000000000..8b035a45b --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool2d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_avg_pool2d(x, output_size=(7,6)) + x = F.adaptive_avg_pool2d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_avg_pool2d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_avg_pool2d.pt inputshape=[1,12,24,64]") + + # ncnn inference + import test_F_adaptive_avg_pool2d_ncnn + b = test_F_adaptive_avg_pool2d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool3d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool3d.py new file mode 100644 index 000000000..f4ad1c0dc --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_avg_pool3d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_avg_pool3d(x, output_size=(7,6,5)) + x = F.adaptive_avg_pool3d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24, 33, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_avg_pool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_avg_pool3d.pt inputshape=[1,12,24,33,64]") + + # ncnn inference + import test_F_adaptive_avg_pool3d_ncnn + b = test_F_adaptive_avg_pool3d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool1d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool1d.py new file mode 100644 index 000000000..dfef51ac6 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool1d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_max_pool1d(x, output_size=7) + x = F.adaptive_max_pool1d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_max_pool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_max_pool1d.pt inputshape=[1,12,24]") + + # ncnn inference + import test_F_adaptive_max_pool1d_ncnn + b = test_F_adaptive_max_pool1d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool2d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool2d.py new file mode 100644 index 000000000..479f68ef0 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool2d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_max_pool2d(x, output_size=(7,6)) + x = F.adaptive_max_pool2d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_max_pool2d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_max_pool2d.pt inputshape=[1,12,24,64]") + + # ncnn inference + import test_F_adaptive_max_pool2d_ncnn + b = test_F_adaptive_max_pool2d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool3d.py b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool3d.py new file mode 100644 index 000000000..f84d8b674 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_adaptive_max_pool3d.py @@ -0,0 +1,57 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.adaptive_max_pool3d(x, output_size=(7,6,5)) + x = F.adaptive_max_pool3d(x, output_size=1) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 24, 33, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_adaptive_max_pool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_adaptive_max_pool3d.pt inputshape=[1,12,24,33,64]") + + # ncnn inference + import test_F_adaptive_max_pool3d_ncnn + b = test_F_adaptive_max_pool3d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_avg_pool1d.py b/tools/pnnx/tests/ncnn/test_F_avg_pool1d.py new file mode 100644 index 000000000..fedaf6aba --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_avg_pool1d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.avg_pool1d(x, kernel_size=3) + x = F.avg_pool1d(x, kernel_size=4, stride=2, padding=2) + x = F.avg_pool1d(x, kernel_size=3, stride=1, padding=(0), ceil_mode=False, count_include_pad=True) + x = F.avg_pool1d(x, kernel_size=5, stride=2, padding=(2), ceil_mode=True, count_include_pad=False) + x = F.avg_pool1d(x, kernel_size=3, stride=2, padding=1, ceil_mode=False, count_include_pad=True) + x = F.avg_pool1d(x, kernel_size=2, stride=1, padding=0, ceil_mode=True, count_include_pad=True) + x = F.avg_pool1d(x, kernel_size=4, stride=1, padding=2, ceil_mode=False, count_include_pad=False) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_avg_pool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_avg_pool1d.pt inputshape=[1,12,128]") + + # ncnn inference + import test_F_avg_pool1d_ncnn + b = test_F_avg_pool1d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_avg_pool2d.py b/tools/pnnx/tests/ncnn/test_F_avg_pool2d.py new file mode 100644 index 000000000..837777323 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_avg_pool2d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.avg_pool2d(x, kernel_size=3) + x = F.avg_pool2d(x, kernel_size=4, stride=2, padding=2) + x = F.avg_pool2d(x, kernel_size=(1,3), stride=1, padding=(0,1), ceil_mode=False, count_include_pad=True) + x = F.avg_pool2d(x, kernel_size=(4,5), stride=(1,2), padding=(1,2), ceil_mode=True, count_include_pad=False) + x = F.avg_pool2d(x, kernel_size=(5,3), stride=(2,1), padding=1, ceil_mode=False, count_include_pad=True) + x = F.avg_pool2d(x, kernel_size=2, stride=1, padding=0, ceil_mode=True, count_include_pad=True) + #x = F.avg_pool2d(x, kernel_size=(5,4), stride=1, padding=2, ceil_mode=False, count_include_pad=False, divisor_override=18) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 128, 127) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_avg_pool2d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_avg_pool2d.pt inputshape=[1,12,128,127]") + + # ncnn inference + import test_F_avg_pool2d_ncnn + b = test_F_avg_pool2d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_avg_pool3d.py b/tools/pnnx/tests/ncnn/test_F_avg_pool3d.py new file mode 100644 index 000000000..50e775d87 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_avg_pool3d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.avg_pool3d(x, kernel_size=3) + x = F.avg_pool3d(x, kernel_size=4, stride=2, padding=2) + x = F.avg_pool3d(x, kernel_size=(1,2,3), stride=1, padding=(0,1,1), ceil_mode=False, count_include_pad=True) + x = F.avg_pool3d(x, kernel_size=(3,4,5), stride=(1,2,2), padding=(1,1,2), ceil_mode=True, count_include_pad=False) + x = F.avg_pool3d(x, kernel_size=(5,4,3), stride=(2,1,1), padding=1, ceil_mode=False, count_include_pad=True) + x = F.avg_pool3d(x, kernel_size=2, stride=1, padding=0, ceil_mode=True, count_include_pad=True) + #x = F.avg_pool3d(x, kernel_size=(5,4,4), stride=1, padding=2, ceil_mode=False, count_include_pad=False, divisor_override=77) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 96, 128, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_avg_pool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_avg_pool3d.pt inputshape=[1,12,96,128,128]") + + # ncnn inference + import test_F_avg_pool3d_ncnn + b = test_F_avg_pool3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_max_pool1d.py b/tools/pnnx/tests/ncnn/test_F_max_pool1d.py new file mode 100644 index 000000000..ee0948d48 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_max_pool1d.py @@ -0,0 +1,62 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.max_pool1d(x, kernel_size=3) + x = F.max_pool1d(x, kernel_size=4, stride=2, padding=2, dilation=1) + x = F.max_pool1d(x, kernel_size=3, stride=1, padding=1, dilation=1, return_indices=False, ceil_mode=False) + x = F.max_pool1d(x, kernel_size=5, stride=2, padding=2, dilation=1, return_indices=False, ceil_mode=True) + x = F.max_pool1d(x, kernel_size=3, stride=1, padding=1, dilation=1, return_indices=False, ceil_mode=False) + x = F.max_pool1d(x, kernel_size=2, stride=1, padding=0, dilation=1, return_indices=False, ceil_mode=True) + return x + #x, indices1 = F.max_pool1d(x, kernel_size=2, padding=1, dilation=1, return_indices=True, ceil_mode=False) + #x, indices2 = F.max_pool1d(x, kernel_size=5, stride=1, padding=2, dilation=1, return_indices=True, ceil_mode=True) + #return x, indices1, indices2 + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_max_pool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_max_pool1d.pt inputshape=[1,12,128]") + + # ncnn inference + import test_F_max_pool1d_ncnn + b = test_F_max_pool1d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_max_pool2d.py b/tools/pnnx/tests/ncnn/test_F_max_pool2d.py new file mode 100644 index 000000000..ff4413ef2 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_max_pool2d.py @@ -0,0 +1,62 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.max_pool2d(x, kernel_size=3) + x = F.max_pool2d(x, kernel_size=4, stride=2, padding=2, dilation=1) + x = F.max_pool2d(x, kernel_size=(1,3), stride=1, padding=(0,1), dilation=1, return_indices=False, ceil_mode=False) + x = F.max_pool2d(x, kernel_size=(4,5), stride=(1,2), padding=(1,2), dilation=1, return_indices=False, ceil_mode=True) + x = F.max_pool2d(x, kernel_size=(2,3), stride=1, padding=1, dilation=(1,1), return_indices=False, ceil_mode=False) + x = F.max_pool2d(x, kernel_size=2, stride=1, padding=0, dilation=1, return_indices=False, ceil_mode=True) + return x + #x, indices1 = F.max_pool2d(x, kernel_size=2, padding=1, dilation=1, return_indices=True, ceil_mode=False) + #x, indices2 = F.max_pool2d(x, kernel_size=(5,4), stride=1, padding=2, dilation=1, return_indices=True, ceil_mode=False) + #return x, indices1, indices2 + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 128, 127) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_max_pool2d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_max_pool2d.pt inputshape=[1,12,128,127]") + + # ncnn inference + import test_F_max_pool2d_ncnn + b = test_F_max_pool2d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_F_max_pool3d.py b/tools/pnnx/tests/ncnn/test_F_max_pool3d.py new file mode 100644 index 000000000..ab0c35eb2 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_F_max_pool3d.py @@ -0,0 +1,61 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + def forward(self, x): + x = F.max_pool3d(x, kernel_size=3) + x = F.max_pool3d(x, kernel_size=4, stride=2, padding=2, dilation=1) + x = F.max_pool3d(x, kernel_size=(1,2,3), stride=1, padding=(0,0,1), dilation=1, return_indices=False, ceil_mode=False) + x = F.max_pool3d(x, kernel_size=(3,4,5), stride=(1,2,2), padding=(1,2,2), dilation=1, return_indices=False, ceil_mode=True) + x = F.max_pool3d(x, kernel_size=(2,3,3), stride=1, padding=1, dilation=(1,1,1), return_indices=False, ceil_mode=False) + x = F.max_pool3d(x, kernel_size=2, stride=1, padding=0, dilation=1, return_indices=False, ceil_mode=True) + return x + #x, indices = F.max_pool3d(x, kernel_size=(5,4,4), stride=1, padding=2, dilation=1, return_indices=True, ceil_mode=False) + #return x, indices + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 96, 128, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_F_max_pool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_F_max_pool3d.pt inputshape=[1,12,96,128,128]") + + # ncnn inference + import test_F_max_pool3d_ncnn + b = test_F_max_pool3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool1d.py b/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool1d.py new file mode 100644 index 000000000..cef5e0528 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool1d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AdaptiveAvgPool1d(output_size=(7)) + self.pool_1 = nn.AdaptiveAvgPool1d(output_size=1) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 128, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AdaptiveAvgPool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AdaptiveAvgPool1d.pt inputshape=[1,128,13]") + + # ncnn inference + import test_nn_AdaptiveAvgPool1d_ncnn + b = test_nn_AdaptiveAvgPool1d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool3d.py b/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool3d.py new file mode 100644 index 000000000..f8c8720ee --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AdaptiveAvgPool3d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AdaptiveAvgPool3d(output_size=(7,6,5)) + self.pool_1 = nn.AdaptiveAvgPool3d(output_size=1) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 128, 13, 13, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AdaptiveAvgPool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AdaptiveAvgPool3d.pt inputshape=[1,128,13,13,13]") + + # ncnn inference + import test_nn_AdaptiveAvgPool3d_ncnn + b = test_nn_AdaptiveAvgPool3d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool1d.py b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool1d.py new file mode 100644 index 000000000..1f927a3e8 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool1d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AdaptiveMaxPool1d(output_size=(7)) + self.pool_1 = nn.AdaptiveMaxPool1d(output_size=1) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 128, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AdaptiveMaxPool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AdaptiveMaxPool1d.pt inputshape=[1,128,13]") + + # ncnn inference + import test_nn_AdaptiveMaxPool1d_ncnn + b = test_nn_AdaptiveMaxPool1d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool2d.py b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool2d.py new file mode 100644 index 000000000..bfb6df26d --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool2d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AdaptiveMaxPool2d(output_size=(7,6)) + self.pool_1 = nn.AdaptiveMaxPool2d(output_size=1) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 128, 13, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AdaptiveMaxPool2d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AdaptiveMaxPool2d.pt inputshape=[1,128,13,13]") + + # ncnn inference + import test_nn_AdaptiveMaxPool2d_ncnn + b = test_nn_AdaptiveMaxPool2d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool3d.py b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool3d.py new file mode 100644 index 000000000..7744dc2b8 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AdaptiveMaxPool3d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AdaptiveMaxPool3d(output_size=(7,6,5)) + self.pool_1 = nn.AdaptiveMaxPool3d(output_size=1) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 128, 13, 13, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AdaptiveMaxPool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AdaptiveMaxPool3d.pt inputshape=[1,128,13,13,13]") + + # ncnn inference + import test_nn_AdaptiveMaxPool3d_ncnn + b = test_nn_AdaptiveMaxPool3d_ncnn.test_inference() + + b = b.reshape_as(a) + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AvgPool1d.py b/tools/pnnx/tests/ncnn/test_nn_AvgPool1d.py new file mode 100644 index 000000000..357c8b67b --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AvgPool1d.py @@ -0,0 +1,68 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AvgPool1d(kernel_size=3) + self.pool_1 = nn.AvgPool1d(kernel_size=4, stride=2, padding=2) + self.pool_2 = nn.AvgPool1d(kernel_size=3, stride=1, padding=(0), ceil_mode=False, count_include_pad=True) + self.pool_3 = nn.AvgPool1d(kernel_size=5, stride=2, padding=(2), ceil_mode=True, count_include_pad=False) + self.pool_4 = nn.AvgPool1d(kernel_size=3, stride=2, padding=1, ceil_mode=False, count_include_pad=True) + self.pool_5 = nn.AvgPool1d(kernel_size=2, stride=1, padding=0, ceil_mode=True, count_include_pad=True) + self.pool_6 = nn.AvgPool1d(kernel_size=4, stride=1, padding=2, ceil_mode=False, count_include_pad=False) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + x = self.pool_2(x) + x = self.pool_3(x) + x = self.pool_4(x) + x = self.pool_5(x) + x = self.pool_6(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AvgPool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AvgPool1d.pt inputshape=[1,12,128]") + + # ncnn inference + import test_nn_AvgPool1d_ncnn + b = test_nn_AvgPool1d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_AvgPool3d.py b/tools/pnnx/tests/ncnn/test_nn_AvgPool3d.py new file mode 100644 index 000000000..207101215 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_AvgPool3d.py @@ -0,0 +1,66 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.AvgPool3d(kernel_size=3) + self.pool_1 = nn.AvgPool3d(kernel_size=4, stride=2, padding=2) + self.pool_2 = nn.AvgPool3d(kernel_size=(1,2,3), stride=1, padding=(0,1,1), ceil_mode=False, count_include_pad=True) + self.pool_3 = nn.AvgPool3d(kernel_size=(3,4,5), stride=(1,2,2), padding=(1,1,2), ceil_mode=True, count_include_pad=False) + self.pool_4 = nn.AvgPool3d(kernel_size=(5,4,3), stride=(2,1,1), padding=1, ceil_mode=False, count_include_pad=True) + self.pool_5 = nn.AvgPool3d(kernel_size=2, stride=1, padding=0, ceil_mode=True, count_include_pad=True) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + x = self.pool_2(x) + x = self.pool_3(x) + x = self.pool_4(x) + x = self.pool_5(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 96, 128, 128) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_AvgPool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_AvgPool3d.pt inputshape=[1,12,96,128,128]") + + # ncnn inference + import test_nn_AvgPool3d_ncnn + b = test_nn_AvgPool3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_ConstantPad3d.py b/tools/pnnx/tests/ncnn/test_nn_ConstantPad3d.py new file mode 100644 index 000000000..ca6faa77e --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_ConstantPad3d.py @@ -0,0 +1,60 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pad_0 = nn.ConstantPad3d(2, 0.3) + self.pad_1 = nn.ConstantPad3d(padding=(1,2,3,4,5,6), value=0) + self.pad_2 = nn.ConstantPad3d(padding=(1,0,2,0,0,3), value=1.1) + + def forward(self, x): + x = self.pad_0(x) + x = self.pad_1(x) + x = self.pad_2(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 13, 13, 13) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_ConstantPad3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_ConstantPad3d.pt inputshape=[1,12,13,13,13]") + + # ncnn inference + import test_nn_ConstantPad3d_ncnn + b = test_nn_ConstantPad3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_Conv3d.py b/tools/pnnx/tests/ncnn/test_nn_Conv3d.py new file mode 100644 index 000000000..3032d3d50 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_Conv3d.py @@ -0,0 +1,75 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.conv_0 = nn.Conv3d(in_channels=12, out_channels=16, kernel_size=3) + self.conv_1 = nn.Conv3d(in_channels=16, out_channels=20, kernel_size=(2,3,4), stride=(2,2,1), padding=2, dilation=1) + self.conv_2 = nn.Conv3d(in_channels=20, out_channels=24, kernel_size=(1,2,3), stride=1, padding=(2,4,1), dilation=1, groups=1, bias=False) + if torch.__version__ < '1.9': + self.conv_3 = nn.Conv3d(in_channels=24, out_channels=28, kernel_size=(5,4,3), stride=1, padding=0, dilation=1, groups=4, bias=True) + self.conv_4 = nn.Conv3d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding=1, dilation=(1,2,2), groups=2, bias=False, padding_mode='zeros') + else: + self.conv_3 = nn.Conv3d(in_channels=24, out_channels=28, kernel_size=(5,4,3), stride=1, padding='valid', dilation=1, groups=4, bias=True) + self.conv_4 = nn.Conv3d(in_channels=28, out_channels=32, kernel_size=3, stride=1, padding='same', dilation=(1,2,2), groups=2, bias=False, padding_mode='zeros') + #self.conv_5 = nn.Conv3d(in_channels=32, out_channels=32, kernel_size=2, stride=2, padding=3, dilation=1, groups=32, bias=True, padding_mode='reflect') + #self.conv_6 = nn.Conv3d(in_channels=32, out_channels=28, kernel_size=2, stride=1, padding=2, dilation=1, groups=1, bias=False, padding_mode='replicate') + #self.conv_7 = nn.Conv3d(in_channels=28, out_channels=24, kernel_size=3, stride=2, padding=(5,6), dilation=2, groups=1, bias=True, padding_mode='circular') + + def forward(self, x): + x = self.conv_0(x) + x = self.conv_1(x) + x = self.conv_2(x) + x = self.conv_3(x) + x = self.conv_4(x) + #x = self.conv_5(x) + #x = self.conv_6(x) + #x = self.conv_7(x) + + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 48, 48, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_Conv3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_Conv3d.pt inputshape=[1,12,48,48,64]") + + # ncnn inference + import test_nn_Conv3d_ncnn + b = test_nn_Conv3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_MaxPool1d.py b/tools/pnnx/tests/ncnn/test_nn_MaxPool1d.py new file mode 100644 index 000000000..36a141fb5 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_MaxPool1d.py @@ -0,0 +1,68 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.MaxPool1d(kernel_size=3) + self.pool_1 = nn.MaxPool1d(kernel_size=4, stride=2, padding=2, dilation=1) + self.pool_2 = nn.MaxPool1d(kernel_size=3, stride=1, padding=1, dilation=1, return_indices=False, ceil_mode=False) + self.pool_3 = nn.MaxPool1d(kernel_size=5, stride=2, padding=2, dilation=1, return_indices=False, ceil_mode=True) + self.pool_4 = nn.MaxPool1d(kernel_size=3, stride=1, padding=1, dilation=1, return_indices=False, ceil_mode=False) + self.pool_5 = nn.MaxPool1d(kernel_size=2, stride=1, padding=0, dilation=1, return_indices=False, ceil_mode=True) + self.pool_6 = nn.MaxPool1d(kernel_size=5, stride=1, padding=2, dilation=1, return_indices=False, ceil_mode=False) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + x = self.pool_2(x) + x = self.pool_3(x) + x = self.pool_4(x) + x = self.pool_5(x) + x = self.pool_6(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_MaxPool1d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_MaxPool1d.pt inputshape=[1,12,64]") + + # ncnn inference + import test_nn_MaxPool1d_ncnn + b = test_nn_MaxPool1d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1) diff --git a/tools/pnnx/tests/ncnn/test_nn_MaxPool3d.py b/tools/pnnx/tests/ncnn/test_nn_MaxPool3d.py new file mode 100644 index 000000000..271604eb6 --- /dev/null +++ b/tools/pnnx/tests/ncnn/test_nn_MaxPool3d.py @@ -0,0 +1,68 @@ +# Tencent is pleased to support the open source community by making ncnn available. +# +# Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Model(nn.Module): + def __init__(self): + super(Model, self).__init__() + + self.pool_0 = nn.MaxPool3d(kernel_size=3) + self.pool_1 = nn.MaxPool3d(kernel_size=4, stride=2, padding=2, dilation=1) + self.pool_2 = nn.MaxPool3d(kernel_size=(1,2,3), stride=1, padding=(0,0,1), dilation=1, return_indices=False, ceil_mode=False) + self.pool_3 = nn.MaxPool3d(kernel_size=(3,4,5), stride=(1,2,2), padding=(1,2,2), dilation=1, return_indices=False, ceil_mode=True) + self.pool_4 = nn.MaxPool3d(kernel_size=(2,3,3), stride=1, padding=1, dilation=(1,1,1), return_indices=False, ceil_mode=False) + self.pool_5 = nn.MaxPool3d(kernel_size=2, stride=1, padding=0, dilation=1, return_indices=False, ceil_mode=True) + self.pool_6 = nn.MaxPool3d(kernel_size=(5,4,4), stride=1, padding=2, dilation=1, return_indices=False, ceil_mode=False) + + def forward(self, x): + x = self.pool_0(x) + x = self.pool_1(x) + x = self.pool_2(x) + x = self.pool_3(x) + x = self.pool_4(x) + x = self.pool_5(x) + x = self.pool_6(x) + return x + +def test(): + net = Model() + net.eval() + + torch.manual_seed(0) + x = torch.rand(1, 12, 64, 64, 64) + + a = net(x) + + # export torchscript + mod = torch.jit.trace(net, x) + mod.save("test_nn_MaxPool3d.pt") + + # torchscript to pnnx + import os + os.system("../../src/pnnx test_nn_MaxPool3d.pt inputshape=[1,12,64,64,64]") + + # ncnn inference + import test_nn_MaxPool3d_ncnn + b = test_nn_MaxPool3d_ncnn.test_inference() + + return torch.allclose(a, b, 1e-4, 1e-4) + +if __name__ == "__main__": + if test(): + exit(0) + else: + exit(1)