-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Add TopK layer support for pnnx ONNX export path #6558
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
Changes from all 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
9db3d84
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,121 @@ | ||||||
| // Copyright 2025 Tencent | ||||||
| // SPDX-License-Identifier: BSD-3-Clause | ||||||
|
|
||||||
| #include "gather.h" | ||||||
|
|
||||||
| namespace ncnn { | ||||||
|
|
||||||
| Gather::Gather() | ||||||
| { | ||||||
| one_blob_only = false; | ||||||
| support_inplace = false; | ||||||
| } | ||||||
|
|
||||||
| int Gather::load_param(const ParamDict& pd) | ||||||
| { | ||||||
| axis = pd.get(0, 0); | ||||||
|
|
||||||
| return 0; | ||||||
| } | ||||||
|
|
||||||
| int Gather::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& index_blob = bottom_blobs[1]; | ||||||
| const int dims = input_blob.dims; | ||||||
|
|
||||||
| // index_blob should contain int64 or int32 indices | ||||||
| // For simplicity we treat it as float and cast | ||||||
| const int index_size = (int)index_blob.total(); | ||||||
|
|
||||||
| int positive_axis = axis < 0 ? axis + dims : axis; | ||||||
| if (positive_axis < 0 || positive_axis >= dims) | ||||||
| return -1; | ||||||
|
|
||||||
| int shape[4] = {1, 1, 1, 1}; | ||||||
| shape[0] = input_blob.w; | ||||||
| if (dims >= 2) shape[1] = input_blob.h; | ||||||
| if (dims == 3) shape[2] = input_blob.c; | ||||||
| if (dims == 4) shape[2] = input_blob.c; // w*h*c layout | ||||||
|
|
||||||
| const int axis_dim_size = shape[positive_axis]; | ||||||
|
|
||||||
| // Output shape matches index_blob shape | ||||||
| const Mat& out_shape = index_blob; | ||||||
|
|
||||||
| // Allocate output (same dtype as input, shape matches index) | ||||||
| Mat& top_blob = top_blobs[0]; | ||||||
| top_blob.create(out_shape.w, out_shape.h, out_shape.c, input_blob.elemsize, input_blob.elempack, opt.blob_allocator); | ||||||
| if (top_blob.empty()) | ||||||
| return -100; | ||||||
|
|
||||||
| const float* inp = input_blob; | ||||||
| const int* idx = (const int*)index_blob; | ||||||
|
||||||
| const int* idx = (const int*)index_blob; | |
| const float* idx = index_blob; |
Copilot
AI
Apr 16, 2026
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.
This implementation only decomposes output coordinates / computes flat_in for dims up to 3. For 4D inputs (and/or 4D index tensors), coord_out/flat_in are left partially unset and flat_in stays 0, so most outputs will incorrectly read the first element. Add explicit handling for dims==4 (both coordinate decomposition and flat index computation, including cstep/d strides).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // Copyright 2025 Tencent | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| #ifndef LAYER_GATHER_H | ||
| #define LAYER_GATHER_H | ||
|
|
||
| #include "layer.h" | ||
|
|
||
| namespace ncnn { | ||
|
|
||
| class Gather : public Layer | ||
| { | ||
| public: | ||
| Gather(); | ||
|
|
||
| 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; | ||
|
|
||
| public: | ||
| // param_0 = axis (default 0) | ||
| int axis; | ||
| }; | ||
|
|
||
| } // namespace ncnn | ||
|
|
||
| #endif // LAYER_GATHER_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.
top_blob.create(out_shape.w, out_shape.h, out_shape.c, ...)always creates a 3D output, even whenindex_blobis 1D/2D/4D. That changes the output rank and breaks the coordinate decomposition logic below (which depends ontop_blob.dims). Allocatetop_blobusing the correctcreate()overload based onout_shape.dimsso the output shape truly matches the index tensor.