Browse Source

crop axes starts ends expression (#5976)

* skip dynamic tensor index

* handle clone oom
tags/20250428
nihui GitHub 1 year ago
parent
commit
39c055d7f2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
24 changed files with 2493 additions and 302 deletions
  1. +4
    -0
      docs/developer-guide/operators.md
  2. +50
    -56
      src/layer/arm/crop_arm.cpp
  3. +190
    -22
      src/layer/crop.cpp
  4. +6
    -0
      src/layer/crop.h
  5. +48
    -33
      src/layer/loongarch/crop_loongarch.cpp
  6. +48
    -33
      src/layer/mips/crop_mips.cpp
  7. +48
    -33
      src/layer/riscv/crop_riscv.cpp
  8. +71
    -6
      src/layer/vulkan/crop_vulkan.cpp
  9. +57
    -80
      src/layer/x86/crop_x86.cpp
  10. +1
    -1
      src/paramdict.cpp
  11. +12
    -12
      tests/test_crop.cpp
  12. +121
    -0
      tests/test_crop_3.cpp
  13. +194
    -0
      tests/test_crop_oom.cpp
  14. +7
    -23
      tests/test_reshape_1.cpp
  15. +10
    -1
      tools/modelwriter.h
  16. +1
    -0
      tools/pnnx/src/CMakeLists.txt
  17. +22
    -0
      tools/pnnx/src/pass_level2/Tensor_size.cpp
  18. +2
    -0
      tools/pnnx/src/pass_ncnn.cpp
  19. +21
    -2
      tools/pnnx/src/pass_ncnn/convert_Tensor_select.cpp
  20. +1412
    -0
      tools/pnnx/src/pass_ncnn/convert_slice_expression.cpp
  21. +25
    -0
      tools/pnnx/src/pass_ncnn/convert_slice_expression.h
  22. +30
    -0
      tools/pnnx/src/pass_ncnn/solve_batch_index.cpp
  23. +1
    -0
      tools/pnnx/tests/ncnn/CMakeLists.txt
  24. +112
    -0
      tools/pnnx/tests/ncnn/test_ncnn_slice_expr.py

+ 4
- 0
docs/developer-guide/operators.md View File

@@ -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


+ 50
- 56
src/layer/arm/crop_arm.cpp View File

@@ -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);
}



+ 190
- 22
src/layer/crop.cpp View File

@@ -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

+ 6
- 0
src/layer/crop.h View File

@@ -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


+ 48
- 33
src/layer/loongarch/crop_loongarch.cpp View File

@@ -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);
}



+ 48
- 33
src/layer/mips/crop_mips.cpp View File

@@ -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);
}



+ 48
- 33
src/layer/riscv/crop_riscv.cpp View File

@@ -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);
}



+ 71
- 6
src/layer/vulkan/crop_vulkan.cpp View File

@@ -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);
}


+ 57
- 80
src/layer/x86/crop_x86.cpp View File

@@ -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);
}



+ 1
- 1
src/paramdict.cpp View File

@@ -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
{


+ 12
- 12
tests/test_crop.cpp View File

@@ -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);



+ 121
- 0
tests/test_crop_3.cpp View File

@@ -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();
}

+ 194
- 0
tests/test_crop_oom.cpp View File

@@ -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();
}

+ 7
- 23
tests/test_reshape_1.cpp View File

@@ -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()


+ 10
- 1
tools/modelwriter.h View File

@@ -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")


+ 1
- 0
tools/pnnx/src/CMakeLists.txt View File

@@ -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


+ 22
- 0
tools/pnnx/src/pass_level2/Tensor_size.cpp View File

@@ -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

+ 2
- 0
tools/pnnx/src/pass_ncnn.cpp View File

@@ -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);


+ 21
- 2
tools/pnnx/src/pass_ncnn/convert_Tensor_select.cpp View File

@@ -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};


+ 1412
- 0
tools/pnnx/src/pass_ncnn/convert_slice_expression.cpp
File diff suppressed because it is too large
View File


+ 25
- 0
tools/pnnx/src/pass_ncnn/convert_slice_expression.h View File

@@ -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

+ 30
- 0
tools/pnnx/src/pass_ncnn/solve_batch_index.cpp View File

@@ -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)


+ 1
- 0
tools/pnnx/tests/ncnn/CMakeLists.txt View File

@@ -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)


+ 112
- 0
tools/pnnx/tests/ncnn/test_ncnn_slice_expr.py View File

@@ -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)

Loading…
Cancel
Save