* skip dynamic tensor index * handle clone oomtags/20250428
| @@ -493,6 +493,9 @@ y = crop(x) | |||
| | 9 | starts | array | [ ] | | | |||
| | 10 | ends | array | [ ] | | | |||
| | 11 | axes | array | [ ] | | | |||
| | 19 | starts_expr | str | "" | | | |||
| | 20 | ends_expr | str | "" | | | |||
| | 21 | axes_expr | str | "" | | | |||
| # CumulativeSum | |||
| @@ -1699,6 +1702,7 @@ y = reshape(x) | |||
| | 1 | h | int | -233 | | | |||
| | 11 | d | int | -233 | | | |||
| | 2 | c | int | -233 | | | |||
| | 6 | shape_expr | str | "" | | | |||
| Reshape flag: | |||
| - 0 = copy from bottom | |||
| @@ -143,12 +143,21 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| int elempack = bottom_blob.elempack; | |||
| #if __ARM_NEON | |||
| if (elempack == 8) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 8) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -218,7 +227,7 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -260,7 +269,7 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -291,10 +300,6 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (elempack == 4) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -364,7 +369,7 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -406,7 +411,7 @@ int Crop_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -468,19 +473,28 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| Mat& top_blob = top_blobs[0]; | |||
| #if __ARM_NEON | |||
| if (elempack == 8) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 8) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -550,7 +564,7 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -592,7 +606,7 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -623,17 +637,6 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (elempack == 4) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -703,7 +706,7 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -745,7 +748,7 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -775,32 +778,23 @@ int Crop_arm::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| } | |||
| #endif // __ARM_NEON | |||
| Mat bottom_blob_unpacked = bottom_blob; | |||
| if (elempack != 1) | |||
| std::vector<Mat> bottom_blobs_unpacked(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| Mat bottom_blob_unpacked = bottom_blobs[i]; | |||
| if (elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| Mat reference_blob_unpacked = reference_blob; | |||
| if (ref_elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blobs[i], bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| convert_packing(reference_blob, reference_blob_unpacked, 1, opt_pack1); | |||
| if (reference_blob_unpacked.empty()) | |||
| return -100; | |||
| bottom_blobs_unpacked[i] = bottom_blob_unpacked; | |||
| } | |||
| std::vector<Mat> bottom_blobs_unpacked(2); | |||
| bottom_blobs_unpacked[0] = bottom_blob_unpacked; | |||
| bottom_blobs_unpacked[1] = reference_blob_unpacked; | |||
| return Crop::forward(bottom_blobs_unpacked, top_blobs, opt); | |||
| } | |||
| @@ -14,6 +14,8 @@ | |||
| #include "crop.h" | |||
| #include "expression.h" | |||
| namespace ncnn { | |||
| Crop::Crop() | |||
| @@ -41,13 +43,34 @@ int Crop::load_param(const ParamDict& pd) | |||
| ends = pd.get(10, Mat()); | |||
| axes = pd.get(11, Mat()); | |||
| starts_expr = pd.get(19, ""); | |||
| ends_expr = pd.get(20, ""); | |||
| axes_expr = pd.get(21, ""); | |||
| // NCNN_LOGE("%s %s %s", starts_expr.c_str(), ends_expr.c_str(), axes_expr.c_str()); | |||
| bool numpy_style_slice = !starts.empty() && !ends.empty(); | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| numpy_style_slice = true; | |||
| if (outw == 0 && outh == 0 && outd == 0 && outc == 0 && woffset2 == 0 && hoffset2 == 0 && doffset2 == 0 && coffset2 == 0 && !numpy_style_slice) | |||
| { | |||
| one_blob_only = false; | |||
| } | |||
| // count reference blobs | |||
| if (!starts_expr.empty() || !ends_expr.empty() || !axes_expr.empty()) | |||
| { | |||
| const int starts_blob_count = count_expression_blobs(starts_expr); | |||
| const int ends_blob_count = count_expression_blobs(ends_expr); | |||
| const int axes_blob_count = count_expression_blobs(axes_expr); | |||
| // NCNN_LOGE("%d %d %d", starts_blob_count, ends_blob_count, axes_blob_count); | |||
| if (starts_blob_count > 1 || ends_blob_count > 1 || axes_blob_count > 1) | |||
| one_blob_only = false; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -89,7 +112,17 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw = -1, _outh = -1, _outd = -1, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blobs(1); | |||
| bottom_blobs[0] = bottom_blob; | |||
| eval_crop_expr(bottom_blobs, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (dims == 1) | |||
| { | |||
| @@ -109,8 +142,6 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| copy_cut_border_image<unsigned short>(bottom_blob, top_blob, 0, _woffset); | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(bottom_blob, top_blob, 0, _woffset); | |||
| return 0; | |||
| } | |||
| if (dims == 2) | |||
| @@ -131,8 +162,6 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| copy_cut_border_image<unsigned short>(bottom_blob, top_blob, _hoffset, _woffset); | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(bottom_blob, top_blob, _hoffset, _woffset); | |||
| return 0; | |||
| } | |||
| if (dims == 3) | |||
| @@ -147,7 +176,7 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| @@ -171,8 +200,6 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(m, borderm, _hoffset, _woffset); | |||
| } | |||
| return 0; | |||
| } | |||
| if (dims == 4) | |||
| @@ -187,7 +214,7 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| @@ -214,8 +241,6 @@ int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) cons | |||
| copy_cut_border_image<float>(m, borderm, _hoffset, _woffset); | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| return 0; | |||
| @@ -237,7 +262,12 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| int _woffset, _hoffset, _doffset, _coffset = -1; | |||
| int _outw = -1, _outh = -1, _outd = -1, _outc; | |||
| if (woffset == -233) | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| eval_crop_expr(bottom_blobs, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| @@ -264,8 +294,6 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| copy_cut_border_image<unsigned short>(bottom_blob, top_blob, 0, _woffset); | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(bottom_blob, top_blob, 0, _woffset); | |||
| return 0; | |||
| } | |||
| if (dims == 2) | |||
| @@ -286,8 +314,6 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| copy_cut_border_image<unsigned short>(bottom_blob, top_blob, _hoffset, _woffset); | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(bottom_blob, top_blob, _hoffset, _woffset); | |||
| return 0; | |||
| } | |||
| if (dims == 3) | |||
| @@ -302,7 +328,7 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| @@ -326,8 +352,6 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| if (elemsize == 4) | |||
| copy_cut_border_image<float>(m, borderm, _hoffset, _woffset); | |||
| } | |||
| return 0; | |||
| } | |||
| if (dims == 4) | |||
| @@ -342,7 +366,7 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| @@ -369,8 +393,6 @@ int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_bl | |||
| copy_cut_border_image<float>(m, borderm, _hoffset, _woffset); | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| return 0; | |||
| @@ -649,4 +671,150 @@ void Crop::resolve_crop_roi(const Mat& bottom_blob, const int* param_data, int& | |||
| } | |||
| } | |||
| int Crop::eval_crop_expr(const std::vector<Mat>& bottom_blobs, int& _woffset, int& _hoffset, int& _doffset, int& _coffset, int& _outw, int& _outh, int& _outd, int& _outc) const | |||
| { | |||
| std::vector<int> _starts; | |||
| std::vector<int> _ends; | |||
| std::vector<int> _axes; | |||
| int er = eval_list_expression(starts_expr, bottom_blobs, _starts); | |||
| if (er != 0) | |||
| return -1; | |||
| er = eval_list_expression(ends_expr, bottom_blobs, _ends); | |||
| if (er != 0) | |||
| return -1; | |||
| er = eval_list_expression(axes_expr, bottom_blobs, _axes); | |||
| if (er != 0) | |||
| return -1; | |||
| // NCNN_LOGE("%d %d %d", _starts[0], _ends[0], _axes[0]); | |||
| const Mat& bottom_blob = bottom_blobs[0]; | |||
| const int w = bottom_blob.w; | |||
| const int h = bottom_blob.h; | |||
| const int d = bottom_blob.d; | |||
| const int channels = bottom_blob.c; | |||
| const int dims = bottom_blob.dims; | |||
| _woffset = 0; | |||
| _hoffset = 0; | |||
| _doffset = 0; | |||
| _coffset = 0; | |||
| _outw = w; | |||
| _outh = h; | |||
| _outd = d; | |||
| _outc = channels; | |||
| const int* starts_ptr = _starts.data(); | |||
| const int* ends_ptr = _ends.data(); | |||
| const int* axes_ptr = _axes.data(); | |||
| int _axes4[4] = {0, 1, 2, 3}; | |||
| int num_axis = (int)_axes.size(); | |||
| if (num_axis == 0) | |||
| { | |||
| num_axis = dims; | |||
| } | |||
| else | |||
| { | |||
| for (int i = 0; i < num_axis; i++) | |||
| { | |||
| int axis = axes_ptr[i]; | |||
| if (axis < 0) | |||
| axis = dims + axis; | |||
| _axes4[i] = axis; | |||
| } | |||
| } | |||
| for (int i = 0; i < num_axis; i++) | |||
| { | |||
| int axis = _axes4[i]; | |||
| int start = starts_ptr[i]; | |||
| int end = ends_ptr[i]; | |||
| if (dims == 1) // axis == 0 | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = w; | |||
| _woffset = start >= 0 ? start : w + start; | |||
| _outw = std::min(w, end > 0 ? end : w + end) - _woffset; | |||
| } | |||
| if (dims == 2) | |||
| { | |||
| if (axis == 0) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = h; | |||
| _hoffset = start >= 0 ? start : h + start; | |||
| _outh = std::min(h, end > 0 ? end : h + end) - _hoffset; | |||
| } | |||
| if (axis == 1) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = w; | |||
| _woffset = start >= 0 ? start : w + start; | |||
| _outw = std::min(w, end > 0 ? end : w + end) - _woffset; | |||
| } | |||
| } | |||
| if (dims == 3) | |||
| { | |||
| if (axis == 0) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = channels; | |||
| _coffset = start >= 0 ? start : channels + start; | |||
| _outc = std::min(channels, end > 0 ? end : channels + end) - _coffset; | |||
| } | |||
| if (axis == 1) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = h; | |||
| _hoffset = start >= 0 ? start : h + start; | |||
| _outh = std::min(h, end > 0 ? end : h + end) - _hoffset; | |||
| } | |||
| if (axis == 2) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = w; | |||
| _woffset = start >= 0 ? start : w + start; | |||
| _outw = std::min(w, end > 0 ? end : w + end) - _woffset; | |||
| } | |||
| } | |||
| if (dims == 4) | |||
| { | |||
| if (axis == 0) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = channels; | |||
| _coffset = start >= 0 ? start : channels + start; | |||
| _outc = std::min(channels, end > 0 ? end : channels + end) - _coffset; | |||
| } | |||
| if (axis == 1) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = d; | |||
| _doffset = start >= 0 ? start : d + start; | |||
| _outd = std::min(d, end > 0 ? end : d + end) - _doffset; | |||
| } | |||
| if (axis == 2) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = h; | |||
| _hoffset = start >= 0 ? start : h + start; | |||
| _outh = std::min(h, end > 0 ? end : h + end) - _hoffset; | |||
| } | |||
| if (axis == 3) | |||
| { | |||
| if (start == -233) start = 0; | |||
| if (end == -233) end = w; | |||
| _woffset = start >= 0 ? start : w + start; | |||
| _outw = std::min(w, end > 0 ? end : w + end) - _woffset; | |||
| } | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| } // namespace ncnn | |||
| @@ -34,6 +34,7 @@ protected: | |||
| void resolve_crop_roi(const Mat& bottom_blob, int& woffset, int& hoffset, int& doffset, int& coffset, int& outw, int& outh, int& outd, int& outc) const; | |||
| void resolve_crop_roi(const Mat& bottom_blob, const Mat& reference_blob, int& woffset, int& hoffset, int& doffset, int& coffset, int& outw, int& outh, int& outd, int& outc) const; | |||
| void resolve_crop_roi(const Mat& bottom_blob, const int* param_data, int& woffset, int& hoffset, int& doffset, int& coffset, int& outw, int& outh, int& outd, int& outc) const; | |||
| int eval_crop_expr(const std::vector<Mat>& bottom_blobs, int& woffset, int& hoffset, int& doffset, int& coffset, int& outw, int& outh, int& outd, int& outc) const; | |||
| public: | |||
| // -233 = dynamic offset from reference blob | |||
| @@ -60,6 +61,11 @@ public: | |||
| Mat starts; | |||
| Mat ends; | |||
| Mat axes; | |||
| // see docs/developer-guide/expression.md | |||
| std::string starts_expr; | |||
| std::string ends_expr; | |||
| std::string axes_expr; | |||
| }; | |||
| } // namespace ncnn | |||
| @@ -64,12 +64,21 @@ int Crop_loongarch::forward(const Mat& bottom_blob, Mat& top_blob, const Option& | |||
| int elempack = bottom_blob.elempack; | |||
| #if __loongarch_sx | |||
| if (elempack == 4) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 4) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -133,7 +142,7 @@ int Crop_loongarch::forward(const Mat& bottom_blob, Mat& top_blob, const Option& | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -172,7 +181,7 @@ int Crop_loongarch::forward(const Mat& bottom_blob, Mat& top_blob, const Option& | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -206,6 +215,8 @@ int Crop_loongarch::forward(const Mat& bottom_blob, Mat& top_blob, const Option& | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| return Crop::forward(bottom_blob_unpacked, top_blob, opt); | |||
| @@ -229,19 +240,28 @@ int Crop_loongarch::forward(const std::vector<Mat>& bottom_blobs, std::vector<Ma | |||
| Mat& top_blob = top_blobs[0]; | |||
| #if __loongarch_sx | |||
| if (elempack == 4) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 4) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -305,7 +325,7 @@ int Crop_loongarch::forward(const std::vector<Mat>& bottom_blobs, std::vector<Ma | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -344,7 +364,7 @@ int Crop_loongarch::forward(const std::vector<Mat>& bottom_blobs, std::vector<Ma | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -371,28 +391,23 @@ int Crop_loongarch::forward(const std::vector<Mat>& bottom_blobs, std::vector<Ma | |||
| } | |||
| #endif // __loongarch_sx | |||
| Mat bottom_blob_unpacked = bottom_blob; | |||
| if (elempack != 1) | |||
| std::vector<Mat> bottom_blobs_unpacked(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| } | |||
| Mat bottom_blob_unpacked = bottom_blobs[i]; | |||
| if (elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| Mat reference_blob_unpacked = reference_blob; | |||
| if (ref_elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blobs[i], bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| convert_packing(reference_blob, reference_blob_unpacked, 1, opt_pack1); | |||
| bottom_blobs_unpacked[i] = bottom_blob_unpacked; | |||
| } | |||
| std::vector<Mat> bottom_blobs_unpacked(2); | |||
| bottom_blobs_unpacked[0] = bottom_blob_unpacked; | |||
| bottom_blobs_unpacked[1] = reference_blob_unpacked; | |||
| return Crop::forward(bottom_blobs_unpacked, top_blobs, opt); | |||
| } | |||
| @@ -64,12 +64,21 @@ int Crop_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| int elempack = bottom_blob.elempack; | |||
| #if __mips_msa | |||
| if (elempack == 4) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 4) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -133,7 +142,7 @@ int Crop_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -172,7 +181,7 @@ int Crop_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -206,6 +215,8 @@ int Crop_mips::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| return Crop::forward(bottom_blob_unpacked, top_blob, opt); | |||
| @@ -229,19 +240,28 @@ int Crop_mips::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& t | |||
| Mat& top_blob = top_blobs[0]; | |||
| #if __mips_msa | |||
| if (elempack == 4) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == 4) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -305,7 +325,7 @@ int Crop_mips::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& t | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -344,7 +364,7 @@ int Crop_mips::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& t | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -371,28 +391,23 @@ int Crop_mips::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& t | |||
| } | |||
| #endif // __mips_msa | |||
| Mat bottom_blob_unpacked = bottom_blob; | |||
| if (elempack != 1) | |||
| std::vector<Mat> bottom_blobs_unpacked(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| } | |||
| Mat bottom_blob_unpacked = bottom_blobs[i]; | |||
| if (elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| Mat reference_blob_unpacked = reference_blob; | |||
| if (ref_elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blobs[i], bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| convert_packing(reference_blob, reference_blob_unpacked, 1, opt_pack1); | |||
| bottom_blobs_unpacked[i] = bottom_blob_unpacked; | |||
| } | |||
| std::vector<Mat> bottom_blobs_unpacked(2); | |||
| bottom_blobs_unpacked[0] = bottom_blob_unpacked; | |||
| bottom_blobs_unpacked[1] = reference_blob_unpacked; | |||
| return Crop::forward(bottom_blobs_unpacked, top_blobs, opt); | |||
| } | |||
| @@ -113,12 +113,21 @@ int Crop_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt | |||
| int elempack = bottom_blob.elempack; | |||
| #if __riscv_vector | |||
| if (elempack == packn) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == packn) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % packn == 0 ? packn : 1; | |||
| @@ -188,7 +197,7 @@ int Crop_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -230,7 +239,7 @@ int Crop_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -267,6 +276,8 @@ int Crop_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| return Crop::forward(bottom_blob_unpacked, top_blob, opt); | |||
| @@ -296,19 +307,28 @@ int Crop_riscv::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& | |||
| Mat& top_blob = top_blobs[0]; | |||
| #if __riscv_vector | |||
| if (elempack == packn) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (elempack == packn) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % packn == 0 ? packn : 1; | |||
| @@ -378,7 +398,7 @@ int Crop_riscv::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -420,7 +440,7 @@ int Crop_riscv::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -450,28 +470,23 @@ int Crop_riscv::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& | |||
| } | |||
| #endif // __riscv_vector | |||
| Mat bottom_blob_unpacked = bottom_blob; | |||
| if (elempack != 1) | |||
| std::vector<Mat> bottom_blobs_unpacked(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| } | |||
| Mat bottom_blob_unpacked = bottom_blobs[i]; | |||
| if (elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| Mat reference_blob_unpacked = reference_blob; | |||
| if (ref_elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blobs[i], bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| convert_packing(reference_blob, reference_blob_unpacked, 1, opt_pack1); | |||
| bottom_blobs_unpacked[i] = bottom_blob_unpacked; | |||
| } | |||
| std::vector<Mat> bottom_blobs_unpacked(2); | |||
| bottom_blobs_unpacked[0] = bottom_blob_unpacked; | |||
| bottom_blobs_unpacked[1] = reference_blob_unpacked; | |||
| return Crop::forward(bottom_blobs_unpacked, top_blobs, opt); | |||
| } | |||
| @@ -52,7 +52,36 @@ int Crop_vulkan::create_pipeline(const Option& opt) | |||
| int offset_elempack = 1; | |||
| bool numpy_style_slice = !starts.empty() && !ends.empty(); | |||
| if (numpy_style_slice) | |||
| if (!starts_expr.empty() && !ends_expr.empty() && !bottom_shapes.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset = -1; | |||
| int _outw = -1, _outh = -1, _outd = -1, _outc; | |||
| eval_crop_expr(bottom_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (shape.dims == 1) | |||
| { | |||
| if (_woffset == 0) | |||
| offset_elempack = elempack; | |||
| else | |||
| offset_elempack = opt.use_shader_pack8 && _woffset % 8 == 0 ? 8 : _woffset % 4 == 0 ? 4 : 1; | |||
| } | |||
| else if (shape.dims == 2) | |||
| { | |||
| if (_hoffset == 0) | |||
| offset_elempack = elempack; | |||
| else | |||
| offset_elempack = opt.use_shader_pack8 && _hoffset % 8 == 0 ? 8 : _hoffset % 4 == 0 ? 4 : 1; | |||
| } | |||
| else // if (shape.dims == 3 || shape.dims == 4) | |||
| { | |||
| if (_coffset == 0) | |||
| offset_elempack = elempack; | |||
| else | |||
| offset_elempack = opt.use_shader_pack8 && _coffset % 8 == 0 ? 8 : _coffset % 4 == 0 ? 4 : 1; | |||
| } | |||
| } | |||
| else if (numpy_style_slice) | |||
| { | |||
| offset_elempack = elempack; | |||
| @@ -156,7 +185,7 @@ int Crop_vulkan::create_pipeline(const Option& opt) | |||
| 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 == out_elempack && elempack > offset_elempack) | |||
| if ((one_blob_only || (!starts_expr.empty() && !ends_expr.empty())) && shape.dims != 0 && elempack == out_elempack && elempack > offset_elempack) | |||
| { | |||
| size_t offset_elemsize; | |||
| if (opt.use_fp16_storage) | |||
| @@ -334,7 +363,16 @@ int Crop_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& c | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| int offset_elempack; | |||
| int out_elempack; | |||
| @@ -513,7 +551,16 @@ int Crop_vulkan::forward(const std::vector<VkMat>& bottom_blobs, std::vector<VkM | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob.mapped(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| @@ -695,7 +742,16 @@ int Crop_vulkan::forward(const VkImageMat& bottom_blob, VkImageMat& top_blob, Vk | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| int offset_elempack; | |||
| int out_elempack; | |||
| @@ -874,7 +930,16 @@ int Crop_vulkan::forward(const std::vector<VkImageMat>& bottom_blobs, std::vecto | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob.mapped(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| @@ -116,14 +116,23 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| int elempack = bottom_blob.elempack; | |||
| #if __SSE2__ | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| std::vector<Mat> bottom_blob_shapes(1); | |||
| bottom_blob_shapes[0] = bottom_blob.shape(); | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| #if __AVX__ | |||
| #if __AVX512F__ | |||
| if (elempack == 16) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 16 == 0 ? 16 : _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -187,7 +196,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -225,7 +234,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -253,10 +262,6 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (elempack == 8) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -320,7 +325,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -358,7 +363,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -386,10 +391,6 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (elempack == 4) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -453,7 +454,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -492,7 +493,7 @@ int Crop_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -546,26 +547,33 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| size_t elemsize = bottom_blob.elemsize; | |||
| int elempack = bottom_blob.elempack; | |||
| int ref_elempack = reference_blob.elempack; | |||
| Mat& top_blob = top_blobs[0]; | |||
| #if __SSE2__ | |||
| #if __AVX__ | |||
| #if __AVX512F__ | |||
| if (elempack == 16) | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (!starts_expr.empty() && !ends_expr.empty()) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| std::vector<Mat> bottom_blob_shapes(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| bottom_blob_shapes[i] = bottom_blobs[i].shape(); | |||
| } | |||
| eval_crop_expr(bottom_blob_shapes, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| #if __AVX__ | |||
| #if __AVX512F__ | |||
| if (elempack == 16) | |||
| { | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 16 == 0 ? 16 : _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -629,7 +637,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -667,7 +675,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -695,17 +703,6 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (elempack == 8) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 8 == 0 ? 8 : _outw % 4 == 0 ? 4 : 1; | |||
| @@ -769,7 +766,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -807,7 +804,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -835,17 +832,6 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (elempack == 4) | |||
| { | |||
| int _woffset, _hoffset, _doffset, _coffset; | |||
| int _outw, _outh, _outd, _outc; | |||
| if (woffset == -233) | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| else | |||
| { | |||
| resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc); | |||
| } | |||
| if (dims == 1) | |||
| { | |||
| int out_elempack = _outw % 4 == 0 ? 4 : 1; | |||
| @@ -909,7 +895,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -948,7 +934,7 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| if (_outw == w && _outh == h && _outd == d) | |||
| { | |||
| top_blob = bottom_blob_sliced.clone(); | |||
| top_blob = bottom_blob_sliced.clone(opt.blob_allocator); | |||
| if (top_blob.empty()) | |||
| return -100; | |||
| } | |||
| @@ -975,32 +961,23 @@ int Crop_x86::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& to | |||
| } | |||
| #endif // __SSE2__ | |||
| Mat bottom_blob_unpacked = bottom_blob; | |||
| if (elempack != 1) | |||
| std::vector<Mat> bottom_blobs_unpacked(bottom_blobs.size()); | |||
| for (size_t i = 0; i < bottom_blobs.size(); i++) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| Mat bottom_blob_unpacked = bottom_blobs[i]; | |||
| if (elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| Mat reference_blob_unpacked = reference_blob; | |||
| if (ref_elempack != 1) | |||
| { | |||
| Option opt_pack1 = opt; | |||
| opt_pack1.blob_allocator = opt.workspace_allocator; | |||
| convert_packing(bottom_blobs[i], bottom_blob_unpacked, 1, opt_pack1); | |||
| if (bottom_blob_unpacked.empty()) | |||
| return -100; | |||
| } | |||
| convert_packing(reference_blob, reference_blob_unpacked, 1, opt_pack1); | |||
| if (reference_blob_unpacked.empty()) | |||
| return -100; | |||
| bottom_blobs_unpacked[i] = bottom_blob_unpacked; | |||
| } | |||
| std::vector<Mat> bottom_blobs_unpacked(2); | |||
| bottom_blobs_unpacked[0] = bottom_blob_unpacked; | |||
| bottom_blobs_unpacked[1] = reference_blob_unpacked; | |||
| return Crop::forward(bottom_blobs_unpacked, top_blobs, opt); | |||
| } | |||
| @@ -358,7 +358,7 @@ int ParamDict::load_param(const DataReader& dr) | |||
| vstr2[241] = '\0'; // max 255 = 15 + 240 | |||
| if (vstr[0] == '\"') | |||
| { | |||
| nscan = dr.scan("%255[^\"]\"", vstr2); | |||
| nscan = dr.scan("%255[^\"\n]\"", vstr2); | |||
| } | |||
| else | |||
| { | |||
| @@ -17,18 +17,18 @@ | |||
| static int test_crop(const ncnn::Mat& a, int woffset, int hoffset, int doffset, int coffset, int outw, int outh, int outd, int outc, int woffset2, int hoffset2, int doffset2, int coffset2) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(0, woffset); // woffset | |||
| pd.set(1, hoffset); // hoffset | |||
| pd.set(13, doffset); // doffset | |||
| pd.set(2, coffset); // coffset | |||
| pd.set(3, outw); // outw | |||
| pd.set(4, outh); // outh | |||
| pd.set(14, outd); // outd | |||
| pd.set(5, outc); // outc | |||
| pd.set(6, woffset2); // woffset2 | |||
| pd.set(7, hoffset2); // hoffset2 | |||
| pd.set(15, doffset2); // doffset2 | |||
| pd.set(8, coffset2); // coffset2 | |||
| pd.set(0, woffset); | |||
| pd.set(1, hoffset); | |||
| pd.set(13, doffset); | |||
| pd.set(2, coffset); | |||
| pd.set(3, outw); | |||
| pd.set(4, outh); | |||
| pd.set(14, outd); | |||
| pd.set(5, outc); | |||
| pd.set(6, woffset2); | |||
| pd.set(7, hoffset2); | |||
| pd.set(15, doffset2); | |||
| pd.set(8, coffset2); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| @@ -0,0 +1,121 @@ | |||
| // Tencent is pleased to support the open source community by making ncnn available. | |||
| // | |||
| // Copyright (C) 2025 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 "testutil.h" | |||
| static int test_crop(const ncnn::Mat& a, const char* starts_expr, const char* ends_expr, const char* axes_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(19, std::string(starts_expr)); | |||
| pd.set(20, std::string(ends_expr)); | |||
| pd.set(21, std::string(axes_expr)); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer("Crop", pd, weights, a); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_crop failed a.dims=%d a=(%d %d %d %d) starts_expr=%s ends_expr=%s axes_expr=%s\n", a.dims, a.w, a.h, a.d, a.c, starts_expr, ends_expr, axes_expr); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_crop(const std::vector<ncnn::Mat>& as, const char* starts_expr, const char* ends_expr, const char* axes_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(19, std::string(starts_expr)); | |||
| pd.set(20, std::string(ends_expr)); | |||
| pd.set(21, std::string(axes_expr)); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer("Crop", pd, weights, as, 1); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_crop failed a.dims=%d a=(%d %d %d %d) starts_expr=%s ends_expr=%s axes_expr=%s\n", as[0].dims, as[0].w, as[0].h, as[0].d, as[0].c, starts_expr, ends_expr, axes_expr); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_crop_0() | |||
| { | |||
| ncnn::Mat a = RandomMat(13, 12, 25, 48); | |||
| ncnn::Mat b = RandomMat(13, 12, 48); | |||
| ncnn::Mat c = RandomMat(13, 48); | |||
| ncnn::Mat d = RandomMat(128); | |||
| return 0 | |||
| || test_crop(a, "2", "-2", "0") | |||
| || test_crop(b, "2", "-2", "0") | |||
| || test_crop(c, "2", "-2", "0") | |||
| || test_crop(d, "2", "-2", "0") | |||
| || test_crop(a, "16", "32", "-4") | |||
| || test_crop(b, "16", "32", "-3") | |||
| || test_crop(c, "16", "32", "-2") | |||
| || test_crop(d, "16", "32", "-1") | |||
| || test_crop(a, "16,//(0d,4),2,3", "32,-1,-2,-3", "0,1,2,3") | |||
| || test_crop(b, "16,//(0h,4),2", "32,-1,-(0w,2)", "0,1,2") | |||
| || test_crop(c, "16,//(0w,4)", "32,-2", "0,1") | |||
| || test_crop(a, "10", "11", "1") | |||
| || test_crop(b, "1,1", "-(0c,15),-(0w,5)", "0,2") | |||
| || test_crop(a, "-(0w,3),0h//2,floor(*(0c,0.3))", "-1,0h,ceil(*(0c,0.9))", "3,2,0") | |||
| || test_crop(b, "-(0w,3),0h//2,floor(*(0c,0.3))", "-1,0h,ceil(*(0c,0.9))", "2,1,0") | |||
| || test_crop(c, "-(0w,3),floor(*(0h,0.3))", "-1,ceil(*(0h,0.9))", "1,0") | |||
| || test_crop(d, "floor(*(0w,0.3))", "ceil(*(0w,0.9))", "0"); | |||
| } | |||
| static int test_crop_1() | |||
| { | |||
| std::vector<ncnn::Mat> as(2); | |||
| as[0] = RandomMat(14, 15, 13, 48); | |||
| as[1] = RandomMat(8, 5, 3, 4); | |||
| std::vector<ncnn::Mat> bs(2); | |||
| bs[0] = RandomMat(14, 15, 48); | |||
| bs[1] = RandomMat(28, 45, 16); | |||
| std::vector<ncnn::Mat> cs(2); | |||
| cs[0] = RandomMat(24, 48); | |||
| cs[1] = RandomMat(28, 6); | |||
| std::vector<ncnn::Mat> ds(3); | |||
| ds[0] = RandomMat(128); | |||
| ds[1] = RandomMat(16); | |||
| ds[2] = RandomMat(64); | |||
| return 0 | |||
| || test_crop(as, "*(1c,4)", "*(1c,8)", "-4") | |||
| || test_crop(bs, "1c", "-(0c,1c)", "-3") | |||
| || test_crop(cs, "+(1h,10)", "-(1h,22)", "-2") | |||
| || test_crop(ds, "1w", "2w", "-1") | |||
| || test_crop(as, "16,//(min(0w,1d),4),2,3", "32,-1,-2,-3", "0,1,2,3") | |||
| || test_crop(bs, "16,//(min(0w,1h),4),2", "32,-1,-(0w,2)", "0,1,2") | |||
| || test_crop(cs, "16,//(min(0w,1w),4)", "32,-2", "0,1") | |||
| || test_crop(bs, "1,//(1w,7)", "+(1c,1),-(0w,2)", "0,2") | |||
| || test_crop(as, "-(1w,4)", "neg(1h,3)", "0") | |||
| || test_crop(bs, "-(1w,20)", "-2", "0") | |||
| || test_crop(bs, "//(1h,15)", "neg(//(1w,7))", "2") | |||
| || test_crop(bs, "//(100,0h),round(fmod(100,0c))", "-233,min(1c,0c)", "1,0"); | |||
| } | |||
| int main() | |||
| { | |||
| SRAND(776757); | |||
| return 0 | |||
| || test_crop_0() | |||
| || test_crop_1(); | |||
| } | |||
| @@ -0,0 +1,194 @@ | |||
| // Tencent is pleased to support the open source community by making ncnn available. | |||
| // | |||
| // Copyright (C) 2025 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 "testutil.h" | |||
| static int test_crop_oom(const ncnn::Mat& a, int woffset, int hoffset, int doffset, int coffset, int outw, int outh, int outd, int outc, int woffset2, int hoffset2, int doffset2, int coffset2) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(0, woffset); | |||
| pd.set(1, hoffset); | |||
| pd.set(13, doffset); | |||
| pd.set(2, coffset); | |||
| pd.set(3, outw); | |||
| pd.set(4, outh); | |||
| pd.set(14, outd); | |||
| pd.set(5, outc); | |||
| pd.set(6, woffset2); | |||
| pd.set(7, hoffset2); | |||
| pd.set(15, doffset2); | |||
| pd.set(8, coffset2); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer_oom("Crop", pd, weights, a); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_crop_oom failed a.dims=%d a=(%d %d %d %d) woffset=%d hoffset=%d doffset=%d coffset=%d outw=%d outh=%d outd=%d outc=%d woffset2=%d hoffset2=%d doffset2=%d coffset2=%d\n", a.dims, a.w, a.h, a.d, a.c, woffset, hoffset, doffset, coffset, outw, outh, outd, outc, woffset2, hoffset2, doffset2, coffset2); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_crop_oom(const ncnn::Mat& a, const char* starts_expr, const char* ends_expr, const char* axes_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(19, std::string(starts_expr)); | |||
| pd.set(20, std::string(ends_expr)); | |||
| pd.set(21, std::string(axes_expr)); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer_oom("Crop", pd, weights, a); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_crop_oom failed a.dims=%d a=(%d %d %d %d) starts_expr=%s ends_expr=%s axes_expr=%s\n", a.dims, a.w, a.h, a.d, a.c, starts_expr, ends_expr, axes_expr); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_crop_oom(const std::vector<ncnn::Mat>& as, const char* starts_expr, const char* ends_expr, const char* axes_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(19, std::string(starts_expr)); | |||
| pd.set(20, std::string(ends_expr)); | |||
| pd.set(21, std::string(axes_expr)); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer_oom("Crop", pd, weights, as, 1); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_crop_oom failed a.dims=%d a=(%d %d %d %d) starts_expr=%s ends_expr=%s axes_expr=%s\n", as[0].dims, as[0].w, as[0].h, as[0].d, as[0].c, starts_expr, ends_expr, axes_expr); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_crop_0() | |||
| { | |||
| ncnn::Mat a = RandomMat(13, 12, 25, 48); | |||
| ncnn::Mat b = RandomMat(13, 12, 48); | |||
| ncnn::Mat c = RandomMat(13, 48); | |||
| ncnn::Mat d = RandomMat(128); | |||
| return 0 | |||
| || test_crop_oom(a, 1, 1, 1, 1, -233, -233, -233, -233, 1, 1, 1, 1) | |||
| || test_crop_oom(b, 1, 1, 0, 1, -233, -233, 0, -233, 1, 1, 0, 1) | |||
| || test_crop_oom(c, 1, 1, 0, 0, -233, -233, 0, 0, 1, 1, 0, 0) | |||
| || test_crop_oom(d, 1, 0, 0, 0, -233, 0, 0, 0, 1, 0, 0, 0) | |||
| || test_crop_oom(a, 2, 2, 2, 2, 6, 6, 6, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(b, 2, 2, 0, 2, 6, 6, 0, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(c, 2, 2, 0, 0, 6, 16, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(d, 2, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(a, 3, 3, 3, 16, 3, 4, 5, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(b, 3, 3, 0, 16, 3, 4, 0, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(c, 3, 16, 0, 0, 3, 16, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(d, 16, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0); | |||
| } | |||
| static int test_crop_1() | |||
| { | |||
| ncnn::Mat a = RandomMat(13, 12, 25, 47); | |||
| ncnn::Mat b = RandomMat(13, 12, 47); | |||
| ncnn::Mat c = RandomMat(13, 47); | |||
| ncnn::Mat d = RandomMat(129); | |||
| return 0 | |||
| || test_crop_oom(a, 1, 1, 1, 1, -233, -233, -233, -233, 1, 1, 1, 1) | |||
| || test_crop_oom(b, 1, 1, 0, 1, -233, -233, 0, -233, 1, 1, 0, 1) | |||
| || test_crop_oom(c, 1, 1, 0, 0, -233, -233, 0, 0, 1, 1, 0, 0) | |||
| || test_crop_oom(d, 1, 0, 0, 0, -233, 0, 0, 0, 1, 0, 0, 0) | |||
| || test_crop_oom(a, 2, 2, 2, 2, 6, 6, 6, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(b, 2, 2, 0, 2, 6, 6, 0, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(c, 2, 2, 0, 0, 6, 16, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(d, 2, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(a, 3, 3, 3, 16, 6, 6, 6, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(b, 3, 3, 0, 16, 6, 6, 0, 16, 0, 0, 0, 0) | |||
| || test_crop_oom(c, 3, 16, 0, 0, 6, 16, 0, 0, 0, 0, 0, 0) | |||
| || test_crop_oom(d, 16, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0); | |||
| } | |||
| static int test_crop_2() | |||
| { | |||
| ncnn::Mat a = RandomMat(13, 12, 25, 48); | |||
| ncnn::Mat b = RandomMat(13, 12, 48); | |||
| ncnn::Mat c = RandomMat(13, 48); | |||
| ncnn::Mat d = RandomMat(128); | |||
| return 0 | |||
| || test_crop_oom(a, "2", "-2", "0") | |||
| || test_crop_oom(b, "2", "-2", "0") | |||
| || test_crop_oom(c, "2", "-2", "0") | |||
| || test_crop_oom(d, "2", "-2", "0") | |||
| || test_crop_oom(a, "16", "32", "-4") | |||
| || test_crop_oom(b, "16", "32", "-3") | |||
| || test_crop_oom(c, "16", "32", "-2") | |||
| || test_crop_oom(d, "16", "32", "-1") | |||
| || test_crop_oom(a, "16,//(0d,4),2,1", "32,-1,-2,-3", "0,1,2,3") | |||
| || test_crop_oom(b, "16,//(0h,4),2", "32,-1,-(0w,2)", "0,1,2") | |||
| || test_crop_oom(c, "16,//(0w,4)", "32,-2", "0,1") | |||
| || test_crop_oom(a, "10", "11", "1") | |||
| || test_crop_oom(b, "1,1", "-(0c,15),-(0w,5)", "0,2") | |||
| || test_crop_oom(a, "-(0w,3),0h//2,floor(*(0c,0.3))", "-1,0h,ceil(*(0c,0.9))", "3,2,0") | |||
| || test_crop_oom(b, "-(0w,3),0h//2,floor(*(0c,0.3))", "-1,0h,ceil(*(0c,0.9))", "2,1,0") | |||
| || test_crop_oom(c, "-(0w,3),floor(*(0h,0.3))", "-1,ceil(*(0h,0.9))", "1,0") | |||
| || test_crop_oom(d, "floor(*(0w,0.3))", "ceil(*(0w,0.9))", "0"); | |||
| } | |||
| static int test_crop_3() | |||
| { | |||
| std::vector<ncnn::Mat> as(2); | |||
| as[0] = RandomMat(14, 15, 13, 48); | |||
| as[1] = RandomMat(8, 5, 3, 4); | |||
| std::vector<ncnn::Mat> bs(2); | |||
| bs[0] = RandomMat(14, 15, 48); | |||
| bs[1] = RandomMat(28, 45, 16); | |||
| std::vector<ncnn::Mat> cs(2); | |||
| cs[0] = RandomMat(24, 48); | |||
| cs[1] = RandomMat(28, 6); | |||
| std::vector<ncnn::Mat> ds(3); | |||
| ds[0] = RandomMat(128); | |||
| ds[1] = RandomMat(16); | |||
| ds[2] = RandomMat(64); | |||
| return 0 | |||
| || test_crop_oom(as, "*(1c,4)", "*(1c,8)", "-4") | |||
| || test_crop_oom(bs, "1c", "-(0c,1c)", "-3") | |||
| || test_crop_oom(cs, "+(1h,10)", "-(1h,22)", "-2") | |||
| || test_crop_oom(ds, "1w", "2w", "-1") | |||
| || test_crop_oom(as, "16,//(min(0w,1d),4),2,3", "32,-1,-2,-3", "0,1,2,3") | |||
| || test_crop_oom(bs, "16,//(min(0w,1h),4),2", "32,-1,-(0w,2)", "0,1,2") | |||
| || test_crop_oom(cs, "16,//(min(0w,1w),4)", "32,-2", "0,1") | |||
| || test_crop_oom(bs, "1,//(1w,7)", "+(1c,1),-(0w,2)", "0,2") | |||
| || test_crop_oom(as, "-(1w,4)", "neg(1h,3)", "0") | |||
| || test_crop_oom(bs, "-(1w,20)", "-2", "0") | |||
| || test_crop_oom(bs, "//(1h,15)", "neg(//(1w,7))", "2") | |||
| || test_crop_oom(bs, "//(100,0h),round(fmod(100,0c))", "-233,min(1c,0c)", "1,0"); | |||
| } | |||
| int main() | |||
| { | |||
| SRAND(776757); | |||
| return 0 | |||
| || test_crop_0() | |||
| || test_crop_1() | |||
| || test_crop_2() | |||
| || test_crop_3(); | |||
| } | |||
| @@ -30,7 +30,7 @@ static int test_reshape(const ncnn::Mat& a, const char* shape_expr) | |||
| return ret; | |||
| } | |||
| static int test_reshape_refs(const std::vector<ncnn::Mat>& as, const char* shape_expr) | |||
| static int test_reshape(const std::vector<ncnn::Mat>& as, const char* shape_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(6, std::string(shape_expr)); | |||
| @@ -40,23 +40,7 @@ static int test_reshape_refs(const std::vector<ncnn::Mat>& as, const char* shape | |||
| int ret = test_layer("Reshape", pd, weights, as, 1); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_reshape_refs failed a.dims=%d a=(%d %d %d %d) shape_expr=%s\n", as[0].dims, as[0].w, as[0].h, as[0].d, as[0].c, shape_expr); | |||
| } | |||
| return ret; | |||
| } | |||
| static int test_reshape_refs(const ncnn::Mat& a, const char* shape_expr) | |||
| { | |||
| ncnn::ParamDict pd; | |||
| pd.set(6, std::string(shape_expr)); | |||
| std::vector<ncnn::Mat> weights(0); | |||
| int ret = test_layer("Reshape", pd, weights, a); | |||
| if (ret != 0) | |||
| { | |||
| fprintf(stderr, "test_reshape_refs failed a.dims=%d a=(%d %d %d %d) shape_expr=%s\n", a.dims, a.w, a.h, a.d, a.c, shape_expr); | |||
| fprintf(stderr, "test_reshape failed a.dims=%d a=(%d %d %d %d) shape_expr=%s\n", as[0].dims, as[0].w, as[0].h, as[0].d, as[0].c, shape_expr); | |||
| } | |||
| return ret; | |||
| @@ -82,8 +66,8 @@ static int test_reshape_1() | |||
| as[1] = RandomMat(28, 45, 48); | |||
| return 0 | |||
| || test_reshape_refs(as, "*(1w,0.5),/(1h,3),-(1c,32)") | |||
| || test_reshape_refs(as, "*(0w,0h),-(-(1c,0c),16)"); | |||
| || test_reshape(as, "*(1w,0.5),/(1h,3),-(1c,32)") | |||
| || test_reshape(as, "*(0w,0h),-(-(1c,0c),16)"); | |||
| } | |||
| static int test_reshape_2() | |||
| @@ -91,9 +75,9 @@ static int test_reshape_2() | |||
| ncnn::Mat a = RandomMat(14, 15, 16); | |||
| return 0 | |||
| || test_reshape_refs(a, "*(0w,0.5),/(0h,3),-1") | |||
| || test_reshape_refs(a, "-1") | |||
| || test_reshape_refs(a, "*(0w,0h),0c"); | |||
| || test_reshape(a, "*(0w,0.5),/(0h,3),-1") | |||
| || test_reshape(a, "-1") | |||
| || test_reshape(a, "*(0w,0h),0c"); | |||
| } | |||
| int main() | |||
| @@ -1235,6 +1235,15 @@ int ModelWriter::save(const char* parampath, const char* binpath) | |||
| { | |||
| if (!op->axes.empty()) fprintf_param_int_array(11, op->axes, pp); | |||
| } | |||
| { | |||
| if (op->starts_expr != op_default->starts_expr) fprintf(pp, " 19=\"%s\"", op->starts_expr.c_str()); | |||
| } | |||
| { | |||
| if (op->ends_expr != op_default->ends_expr) fprintf(pp, " 20=\"%s\"", op->ends_expr.c_str()); | |||
| } | |||
| { | |||
| if (op->axes_expr != op_default->axes_expr) fprintf(pp, " 21=\"%s\"", op->axes_expr.c_str()); | |||
| } | |||
| } | |||
| else if (layer->type == "CumulativeSum") | |||
| { | |||
| @@ -2345,7 +2354,7 @@ int ModelWriter::save(const char* parampath, const char* binpath) | |||
| fprintf_param_value(" 11=%d", d) | |||
| fprintf_param_value(" 2=%d", c) | |||
| { | |||
| if (op->shape_expr != op_default->shape_expr) fprintf(pp, " 6=%s", op->shape_expr.c_str()); | |||
| if (op->shape_expr != op_default->shape_expr) fprintf(pp, " 6=\"%s\"", op->shape_expr.c_str()); | |||
| } | |||
| } | |||
| else if (layer->type == "RMSNorm") | |||
| @@ -403,6 +403,7 @@ set(pnnx_pass_ncnn_SRCS | |||
| pass_ncnn/convert_half_to_float.cpp | |||
| pass_ncnn/convert_input.cpp | |||
| pass_ncnn/convert_reshape_expression.cpp | |||
| pass_ncnn/convert_slice_expression.cpp | |||
| pass_ncnn/convert_torch_cat.cpp | |||
| pass_ncnn/convert_torch_chunk.cpp | |||
| pass_ncnn/convert_torch_einsum.cpp | |||
| @@ -54,4 +54,26 @@ pnnx.Output output 1 0 out | |||
| REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_size, 10) | |||
| REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_size_dynamic, 11) | |||
| class Tensor_size_onnx : public GraphRewriterPass | |||
| { | |||
| public: | |||
| const char* match_pattern_graph() const | |||
| { | |||
| return R"PNNXIR(7767517 | |||
| 4 3 | |||
| pnnx.Input input 0 1 input | |||
| aten::size op_0 1 1 input shape | |||
| Gather op_1 1 1 shape out axis=0 indices=%dim | |||
| pnnx.Output output 1 0 out | |||
| )PNNXIR"; | |||
| } | |||
| const char* type_str() const | |||
| { | |||
| return "Tensor.size"; | |||
| } | |||
| }; | |||
| REGISTER_GLOBAL_PNNX_GRAPH_REWRITER_PASS(Tensor_size_onnx, 10) | |||
| } // namespace pnnx | |||
| @@ -20,6 +20,7 @@ | |||
| #include "pass_ncnn/convert_half_to_float.h" | |||
| #include "pass_ncnn/convert_input.h" | |||
| #include "pass_ncnn/convert_reshape_expression.h" | |||
| #include "pass_ncnn/convert_slice_expression.h" | |||
| #include "pass_ncnn/convert_torch_cat.h" | |||
| #include "pass_ncnn/convert_torch_chunk.h" | |||
| #include "pass_ncnn/convert_torch_einsum.h" | |||
| @@ -110,6 +111,7 @@ void pass_ncnn(Graph& g, const std::vector<std::string>& module_operators) | |||
| ncnn::convert_torch_einsum(g); | |||
| ncnn::convert_reshape_expression(g); | |||
| ncnn::convert_slice_expression(g); | |||
| ncnn::convert_Tensor_select(g); | |||
| ncnn::convert_Tensor_slice(g); | |||
| @@ -54,8 +54,27 @@ void convert_Tensor_select(Graph& graph) | |||
| if (axis > batch_index) | |||
| axis -= 1; | |||
| int dim = op->params.at("dim").i; | |||
| int index = op->params.at("index").i; | |||
| int dim; | |||
| int index; | |||
| if (op->has_param("dim")) | |||
| { | |||
| dim = op->params.at("dim").i; | |||
| } | |||
| else | |||
| { | |||
| fprintf(stderr, "select with dynamic dim is not supported\n"); | |||
| continue; | |||
| } | |||
| if (op->has_param("index")) | |||
| { | |||
| index = op->params.at("index").i; | |||
| } | |||
| else | |||
| { | |||
| fprintf(stderr, "select with dynamic index is not supported\n"); | |||
| continue; | |||
| } | |||
| op->params["9"] = std::vector<int> {index}; | |||
| op->params["10"] = std::vector<int> {index + 1}; | |||
| @@ -0,0 +1,25 @@ | |||
| // Tencent is pleased to support the open source community by making ncnn available. | |||
| // | |||
| // Copyright (C) 2025 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 { | |||
| void convert_slice_expression(Graph& graph); | |||
| } // namespace ncnn | |||
| } // namespace pnnx | |||
| @@ -225,6 +225,21 @@ static void solve_batch_index_forward(Operand* operand) | |||
| // give up reshape across batch index | |||
| } | |||
| } | |||
| else if (op->type == "Tensor.slice" || op->type == "Tensor.select") | |||
| { | |||
| Operand* r = op->outputs[0]; | |||
| if (r->params.find("__batch_index") == r->params.end()) | |||
| { | |||
| r->params["__batch_index"] = batch_index; | |||
| solve_batch_index_forward(r); | |||
| solve_batch_index_backward(r); | |||
| } | |||
| } | |||
| else if (op->type == "pnnx.SliceIndexes") | |||
| { | |||
| // pass | |||
| } | |||
| else | |||
| { | |||
| for (Operand* r : op->outputs) | |||
| @@ -325,6 +340,21 @@ static void solve_batch_index_backward(Operand* operand) | |||
| // give up reshape across batch index | |||
| } | |||
| } | |||
| else if (op->type == "Tensor.slice" || op->type == "Tensor.select") | |||
| { | |||
| Operand* r = op->inputs[0]; | |||
| if (r->params.find("__batch_index") == r->params.end()) | |||
| { | |||
| r->params["__batch_index"] = batch_index; | |||
| solve_batch_index_backward(r); | |||
| solve_batch_index_forward(r); | |||
| } | |||
| } | |||
| else if (op->type == "pnnx.SliceIndexes") | |||
| { | |||
| // pass | |||
| } | |||
| else | |||
| { | |||
| for (Operand* r : op->inputs) | |||
| @@ -218,6 +218,7 @@ pnnx_ncnn_add_test(ncnn_fuse_binaryop_eltwise) | |||
| pnnx_ncnn_add_test(ncnn_fuse_pad_conv) | |||
| pnnx_ncnn_add_test(ncnn_numpy_binaryop_broadcast) | |||
| pnnx_ncnn_add_test(ncnn_reshape_expr) | |||
| pnnx_ncnn_add_test(ncnn_slice_expr) | |||
| if(TorchVision_FOUND) | |||
| pnnx_ncnn_add_test(torchvision_DeformConv2d) | |||
| @@ -0,0 +1,112 @@ | |||
| # Tencent is pleased to support the open source community by making ncnn available. | |||
| # | |||
| # Copyright (C) 2025 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 | |||
| from packaging import version | |||
| class Model(nn.Module): | |||
| def __init__(self): | |||
| super(Model, self).__init__() | |||
| self.conv0 = nn.Conv2d(in_channels=3, out_channels=15, kernel_size=1) | |||
| def forward(self, x, y, z): | |||
| out0 = x[x.size(0)//128:x.size(0)-3] | |||
| out0 = out0.clone() * 2 | |||
| out1 = y[...,y.size(0)//8] | |||
| out1 = out1.clone() * 3.3 | |||
| z = self.conv0(z) | |||
| out2 = z[:,x.size(0)//64-y.size(1)//128,z.size(3)-3:-z.size(2)//7,z.size(2)//3] | |||
| out2 = out2.clone() * 1.5 | |||
| out3 = z[...,x.size(0)//128:-z.size(2)//10,z.size(3)//8:-z.size(3)//8] | |||
| out3 = out3.clone() * -10 | |||
| return out0, out1, out2, out3 | |||
| def test(): | |||
| net = Model().half().float() | |||
| net.eval() | |||
| torch.manual_seed(0) | |||
| x0 = torch.rand(128) | |||
| y0 = torch.rand(64, 16) | |||
| z0 = torch.rand(1, 3, 39, 16) | |||
| x1 = torch.rand(256) | |||
| y1 = torch.rand(32, 128) | |||
| z1 = torch.rand(1, 3, 15, 33) | |||
| a0 = net(x0, y0, z0) | |||
| a1 = net(x1, y1, z1) | |||
| # export torchscript | |||
| if version.parse(torch.__version__) < version.parse('2.0'): | |||
| mod = torch.jit.trace(net, (x0, y0, z0)) | |||
| else: | |||
| mod = torch.jit.trace(net, (x0, y0, z0), _store_inputs=False) | |||
| mod.save("test_ncnn_slice_expr.pt") | |||
| # torchscript to pnnx | |||
| import os | |||
| os.system("../../src/pnnx test_ncnn_slice_expr.pt inputshape=[128],[64,16],[1,3,39,16] inputshape2=[256],[32,128],[1,3,15,33]") | |||
| # ncnn inference | |||
| import numpy as np | |||
| import ncnn | |||
| b0 = [] | |||
| b1 = [] | |||
| with ncnn.Net() as net: | |||
| net.load_param("test_ncnn_slice_expr.ncnn.param") | |||
| net.load_model("test_ncnn_slice_expr.ncnn.bin") | |||
| with net.create_extractor() as ex: | |||
| ex.input("in0", ncnn.Mat(x0.numpy()).clone()) | |||
| ex.input("in1", ncnn.Mat(y0.numpy()).clone()) | |||
| ex.input("in2", ncnn.Mat(z0.squeeze(0).numpy()).clone()) | |||
| _, out0 = ex.extract("out0") | |||
| _, out1 = ex.extract("out1") | |||
| b0.append(torch.from_numpy(np.array(out0))) | |||
| b0.append(torch.from_numpy(np.array(out1)).unsqueeze(0)) | |||
| with net.create_extractor() as ex: | |||
| ex.input("in0", ncnn.Mat(x1.numpy()).clone()) | |||
| ex.input("in1", ncnn.Mat(y1.numpy()).clone()) | |||
| ex.input("in2", ncnn.Mat(z1.squeeze(0).numpy()).clone()) | |||
| _, out0 = ex.extract("out0") | |||
| _, out1 = ex.extract("out1") | |||
| b1.append(torch.from_numpy(np.array(out0))) | |||
| b1.append(torch.from_numpy(np.array(out1)).unsqueeze(0)) | |||
| for aa, bb in zip(a0, b0): | |||
| if not torch.allclose(aa, bb, 1e-4, 1e-4): | |||
| return False | |||
| for aa, bb in zip(a1, b1): | |||
| if not torch.allclose(aa, bb, 1e-4, 1e-4): | |||
| return False | |||
| return True | |||
| if __name__ == "__main__": | |||
| if test(): | |||
| exit(0) | |||
| else: | |||
| exit(1) | |||