-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat: add TopK, Gather, GatherElements, Expand, Tile, and Mod operators #6669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 33 commits
8bd7d30
b2c445a
01d15cb
13cf18c
e95770e
4b4b87a
c9e856e
4d5b35f
5c11058
226bd88
6c5978b
e16514b
00be7f8
1fe4463
6ea29eb
7befff6
5ba7fbc
e4b4073
49dbc7b
9d31f3b
84e083b
2ea44dd
5674b1c
caa9de3
4e39cb6
ca55f8a
2b5fa16
d8fd80c
d68852d
93bd423
0db1718
5909f77
d5c57c3
065e7cc
d6f4a00
4c2034e
56d79ed
5fdea12
982be1d
912c814
31f1605
8d79ad7
e0c0fed
0f52cf1
c282f6d
e06a8ca
93964ad
a4675cc
53160b4
605b72c
29755a2
93feab3
f2840eb
8d2da47
42c4e70
11d782c
d09b113
3857116
c8d3126
220d3ec
d828e9d
26cee4f
a8d6830
f2575de
906caaf
8374fed
ff9f51e
6bfb603
0d56d02
d9b02c5
17ac7ba
a5878fd
a3a14e4
a2bdae6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| name: topk-linux-test | ||
| on: | ||
| push: | ||
| branches: | ||
| - topk-ci-tests | ||
| - fix-pnnx-onnx-topk-support | ||
| pull_request: | ||
| branches: | ||
| - master | ||
|
|
||
| jobs: | ||
| x64-none: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: build | ||
| run: | | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_BUILD_TYPE=Debug -DNCNN_RUNTIME_CPU=OFF \ | ||
| -DNCNN_SSE2=OFF -DNCNN_AVX=OFF \ | ||
| -DNCNN_OPENMP=OFF -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_TESTS=ON .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test | ||
| run: cd build && ./tests/test_topk | ||
|
|
||
| x64-sse2: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: build | ||
| run: | | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_BUILD_TYPE=Debug -DNCNN_RUNTIME_CPU=OFF \ | ||
| -DNCNN_SSE2=ON -DNCNN_AVX=OFF \ | ||
| -DNCNN_OPENMP=OFF -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_TESTS=ON .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test | ||
| run: cd build && ./tests/test_topk | ||
|
|
||
| x64-avx2: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: build | ||
| run: | | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_BUILD_TYPE=Debug -DNCNN_RUNTIME_CPU=OFF \ | ||
| -DNCNN_SSE2=ON -DNCNN_AVX=ON -DNCNN_F16C=ON -DNCNN_FMA=ON -DNCNN_AVX2=ON \ | ||
| -DNCNN_AVX512=OFF -DNCNN_XOP=OFF -DNCNN_AVXVNNI=OFF \ | ||
| -DNCNN_OPENMP=OFF -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_TESTS=ON .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test | ||
| run: cd build && ./tests/test_topk | ||
|
|
||
| simplestl-simplemath: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: build | ||
| run: | | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/host-c.gcc.toolchain.cmake \ | ||
| -DCMAKE_BUILD_TYPE=Debug \ | ||
| -DNCNN_SIMPLESTL=ON -DNCNN_SIMPLEMATH=ON \ | ||
| -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF \ | ||
| -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_TESTS=ON .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test | ||
| run: cd build && ./tests/test_topk | ||
|
|
||
| linux-x86-gcc: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: install | ||
| run: sudo apt-get update && sudo apt-get install -y gcc-multilib g++-multilib | ||
| - name: build | ||
| run: | | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/host.gcc-m32.toolchain.cmake \ | ||
| -DNCNN_BUILD_TESTS=ON -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test | ||
| run: cd build && ./tests/test_topk | ||
| - name: build-nosse | ||
| run: | | ||
| mkdir build-nosse && cd build-nosse | ||
| cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/host.gcc-m32.toolchain.cmake \ | ||
| -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX=OFF \ | ||
| -DNCNN_BUILD_TESTS=ON -DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF .. | ||
| cmake --build . --target test_topk -j$(nproc) | ||
| - name: test-nosse | ||
| run: cd build-nosse && ./tests/test_topk | ||
|
|
||
| pnnx-onnx-topk: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.12' | ||
| - name: setup-pytorch | ||
| run: | | ||
| pip3 install torch --index-url https://download.pytorch.org/whl/cpu | ||
| pip3 install numpy packaging onnx onnxruntime | ||
| - name: build-pnnx | ||
| run: | | ||
| cd tools/pnnx | ||
| mkdir build && cd build | ||
| cmake -DCMAKE_BUILD_TYPE=Release .. | ||
| cmake --build . --config Release -j$(nproc) | ||
| - name: test-topk | ||
| run: | | ||
| cd tools/pnnx/build | ||
| ctest --output-on-failure -R test_onnx_torch_topk |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| // Copyright 2025 Tencent | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| #include "expand.h" | ||
|
|
||
| namespace ncnn { | ||
|
|
||
| Expand::Expand() | ||
| { | ||
| one_blob_only = false; | ||
| support_inplace = false; | ||
| } | ||
|
|
||
| int Expand::load_param(const ParamDict& pd) | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| int Expand::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const | ||
| { | ||
| if (bottom_blobs.size() < 2) | ||
| return -1; | ||
|
|
||
| const Mat& input_blob = bottom_blobs[0]; | ||
| const Mat& shape_blob = bottom_blobs[1]; | ||
|
|
||
| // shape_blob contains the target shape as int64/int32 values | ||
| const int* target_shape = (const int*)shape_blob; | ||
| int target_dims = (int)shape_blob.total(); | ||
|
|
||
| // Get input dimensions | ||
|
||
| int in_dims = input_blob.dims; | ||
| int in_shape[4] = {1, 1, 1, 1}; | ||
| in_shape[0] = input_blob.w; | ||
| if (in_dims >= 2) in_shape[1] = input_blob.h; | ||
| if (in_dims >= 3) in_shape[2] = input_blob.c; | ||
| // For 4D, we'd need to handle differently but ncnn typically uses 3D blobs | ||
|
|
||
| // Calculate output shape (broadcasting rules) | ||
| int out_shape[4] = {1, 1, 1, 1}; | ||
| int max_dims = std::max(in_dims, target_dims); | ||
|
|
||
| for (int i = 0; i < max_dims; i++) | ||
| { | ||
| int in_idx = i - (max_dims - in_dims); | ||
| int target_idx = i - (max_dims - target_dims); | ||
|
|
||
| int in_dim = (in_idx >= 0 && in_idx < in_dims) ? in_shape[in_idx] : 1; | ||
| int target_dim = (target_idx >= 0 && target_idx < target_dims) ? target_shape[target_idx] : 1; | ||
|
|
||
| // Broadcasting: if in_dim is 1, expand to target_dim; otherwise must match | ||
| out_shape[i] = (in_dim == 1) ? target_dim : in_dim; | ||
| } | ||
|
||
|
|
||
| Mat& top_blob = top_blobs[0]; | ||
|
|
||
| if (max_dims == 1) | ||
| { | ||
| top_blob.create(out_shape[0], input_blob.elemsize, input_blob.elempack, opt.blob_allocator); | ||
| } | ||
| else if (max_dims == 2) | ||
| { | ||
| top_blob.create(out_shape[0], out_shape[1], input_blob.elemsize, input_blob.elempack, opt.blob_allocator); | ||
| } | ||
| else if (max_dims == 3) | ||
| { | ||
| top_blob.create(out_shape[0], out_shape[1], out_shape[2], input_blob.elemsize, input_blob.elempack, opt.blob_allocator); | ||
| } | ||
| else | ||
| { | ||
| return -1; | ||
| } | ||
|
|
||
| if (top_blob.empty()) | ||
| return -100; | ||
|
|
||
| const float* inp = input_blob; | ||
| float* out = top_blob; | ||
|
|
||
| // Fill output by broadcasting input | ||
| int total = (int)top_blob.total(); | ||
|
|
||
| for (int i = 0; i < total; i++) | ||
| { | ||
| // Calculate multi-dimensional coordinates | ||
| int coords[4] = {0, 0, 0, 0}; | ||
| int rem = i; | ||
|
|
||
| if (max_dims == 1) | ||
| { | ||
| coords[0] = rem; | ||
| } | ||
| else if (max_dims == 2) | ||
| { | ||
| coords[0] = rem % top_blob.w; | ||
| coords[1] = rem / top_blob.w; | ||
| } | ||
| else if (max_dims == 3) | ||
| { | ||
| int wh = top_blob.w * top_blob.h; | ||
| coords[0] = (rem % wh) % top_blob.w; | ||
| coords[1] = (rem % wh) / top_blob.w; | ||
| coords[2] = rem / wh; | ||
| } | ||
|
|
||
| // Map to input coordinates (modulo for expanded dimensions) | ||
| int in_coords[4] = {0, 0, 0, 0}; | ||
| for (int d = 0; d < max_dims; d++) | ||
| { | ||
| int in_idx = d - (max_dims - in_dims); | ||
| if (in_idx >= 0 && in_idx < in_dims) | ||
| { | ||
| int dim_size = (d == 0) ? input_blob.w : (d == 1 && in_dims >= 2) ? input_blob.h : input_blob.c; | ||
| in_coords[in_idx] = coords[d] % dim_size; | ||
| } | ||
| } | ||
|
|
||
| // Calculate flat input index | ||
| int in_idx = 0; | ||
| if (in_dims == 1) | ||
| { | ||
| in_idx = in_coords[0]; | ||
| } | ||
| else if (in_dims == 2) | ||
| { | ||
| in_idx = in_coords[0] + in_coords[1] * input_blob.w; | ||
| } | ||
| else if (in_dims == 3) | ||
| { | ||
| size_t cstep = input_blob.cstep; | ||
| in_idx = in_coords[0] + in_coords[1] * input_blob.w + in_coords[2] * (int)cstep; | ||
| } | ||
|
|
||
| out[i] = inp[in_idx]; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| } // namespace ncnn | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // Copyright 2025 Tencent | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| #ifndef LAYER_EXPAND_H | ||
| #define LAYER_EXPAND_H | ||
|
|
||
| #include "layer.h" | ||
|
|
||
| namespace ncnn { | ||
|
|
||
| class Expand : public Layer | ||
| { | ||
| public: | ||
| Expand(); | ||
|
|
||
| virtual int load_param(const ParamDict& pd); | ||
|
|
||
| virtual int forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const; | ||
| }; | ||
|
|
||
| } // namespace ncnn | ||
|
|
||
| #endif // LAYER_EXPAND_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expandlayer implementation was added (src/layer/expand.*) but it is not registered in this CMake layer list. As-is, the layer won't be built/registered, and models lowered to anExpandlayer will fail at runtime (unknown layer type). Addncnn_add_layer(Expand)here (near Tile/TopK for related ops).