Skip to content
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

Upgrade ncnn cause output dimension wrong #4875

Closed
ZiyueWangUoB opened this issue Jul 25, 2023 · 5 comments
Closed

Upgrade ncnn cause output dimension wrong #4875

ZiyueWangUoB opened this issue Jul 25, 2023 · 5 comments

Comments

@ZiyueWangUoB
Copy link

After upgrading NCNN from 20220729 to 20230517, the output from my model is incorrect

Here's the code for running the model:

import ncnn
import torch
import numpy as np
import cv2

def test_inference(arr):
    out = []
    print(np.shape(arr))

    with ncnn.Net() as net:
         net.load_param("ncnn/255.param")
         net.load_model("ncnn/255.bin")

         with net.create_extractor() as ex:
            ex.input("input_1:0", ncnn.Mat(arr).clone())

            _, out0 = ex.extract("transfer_Dense")
            out.append(torch.from_numpy(np.array(out0)).unsqueeze(0))

    if len(out) == 1:
        return out[0]
    else:
        return tuple(out)

img = cv2.imread("ncnn/1.jpg")
img = cv2.resize(img,(300,300),cv2.INTER_NEAREST)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
arr = np.transpose(img,(2,0,1)).astype(np.float32)
#arr = np.expand_dims(arr,axis=0)
#print(np.shape(arr))

print(np.shape(test_inference(arr)))

With the older version the output shape is 1,1,256, the newer version the shape is 1,8,256

@nihui
Copy link
Member

nihui commented Jul 25, 2023

please provide a minimal model, pytorch module code or torchscript, for reproducing your issue

@ZiyueWangUoB
Copy link
Author

Here is the model:

链接:https://pan.baidu.com/s/14vmHbVxTtuXeuovSEp933g
提取码:ab69
--来自百度网盘超级会员V3的分享

Also I've found on the same versions using C++, the result is different but the shape is the same.

@ZiyueWangUoB
Copy link
Author

After analyzing the model more, I've found that the input shape into the gemm layer is the same between NCNN versions. However, the output shape if the gemm layer is different, with previous versions having the output (256,1,1,1) and the newer version with (256,4,1,1).

Here is the C++ 14 code if anyone wants to try:

#include <iostream>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <deque>
#include <set>
#include <numeric>
#include <chrono>
#include <fstream>
#include <algorithm>

#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"

#include "net.h"

using namespace std;

const int MODEL_IN_WIDTH = 300;
const int MODEL_IN_HEIGHT = 300;
const int MODEL_IN_CHANNELS = 3;

cv::Mat loadImage(const char* img_path) {
    cv::Mat orig_img = imread(img_path, cv::IMREAD_COLOR);
    if (!orig_img.data) {
        printf("cv::imread %s fail!\n", img_path);
    }

    cv::Mat resizedImageBGR, resizedImageRGB, resizedImage, preprocessedImage;
    cv::resize(orig_img, resizedImageBGR,
        cv::Size(300, 300),
        0, 0, cv::InterpolationFlags::INTER_NEAREST);

    cv::cvtColor(resizedImageBGR, resizedImageRGB,
        cv::ColorConversionCodes::COLOR_BGR2RGB);

    //cout << resizedImageRGB << endl;

    resizedImageRGB.convertTo(resizedImage, CV_32F, 1.);

    cv::Mat channels[3];
    cv::split(resizedImage, channels);
    cv::merge(channels, 3, resizedImage);
    //cout << resizedImage << endl;

    return resizedImage;
}

int runImage(cv::Mat img, vector<float>& resultFeature, ncnn::Net* netp) {
    int ret;
    resultFeature.resize(1024);
    if (netp == NULL) {
        throw std::runtime_error("netp is null, somehow");
    }

    ncnn::Mat in_pack3(300, 300, 1, (void*)img.data, (size_t)4u * 3, 3);
    ncnn::Mat in;
    ncnn::convert_packing(in_pack3, in, 1);

    ncnn::Mat out;
    ncnn::Extractor ex = netp->create_extractor();
    //ex.set_num_threads(4);

    ex.input("input_1:0", in);
    ex.extract("StatefulPartitionedCall/functional_1/transfer_Dense/MatMul_Gemm__35:0", out);

    ncnn::Mat out_flat = out.reshape(out.w * out.h * out.c);

    for (size_t i = 0; i < 1024; ++i) {
        //resultFeature.push_back(out_flat[i]);
        resultFeature[i] = out_flat[i];
    }

    ex.clear();

    return 1;

}

int main()
{
    std::cout << "Hello World!\n";
    ncnn::Net net;
    net.load_param("mo/255.param");
    net.load_model("mo/255.bin");
    net.opt.use_vulkan_compute = 0;
    //net.opt.use_fp16_arithmetic = 0;
    //net.opt.use_fp16_packed = 0;
    //net.opt.use_fp16_storage = 0;

    ncnn::Net* netp = &net;


    string imgPath = "0.8156_20220525231119452_1-1_香瓜.jpg";
    cv::Mat img = loadImage(imgPath.c_str());

    vector<float> resVec;

    int ret = runImage(img, resVec, netp);

    for (int i = 0; i < 256; ++i) {
        cout << resVec[i] << " " << resVec[256 + i] << " " << resVec[512 + i] << " " << resVec[768 + i] << endl;
    }


}

@w8501
Copy link
Contributor

w8501 commented Jul 28, 2023

After analyzing the model more, I've found that the input shape into the gemm layer is the same between NCNN versions. However, the output shape if the gemm layer is different, with previous versions having the output (256,1,1,1) and the newer version with (256,4,1,1).

Here is the C++ 14 code if anyone wants to try:

#include <iostream>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <deque>
#include <set>
#include <numeric>
#include <chrono>
#include <fstream>
#include <algorithm>

#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"

#include "net.h"

using namespace std;

const int MODEL_IN_WIDTH = 300;
const int MODEL_IN_HEIGHT = 300;
const int MODEL_IN_CHANNELS = 3;

cv::Mat loadImage(const char* img_path) {
    cv::Mat orig_img = imread(img_path, cv::IMREAD_COLOR);
    if (!orig_img.data) {
        printf("cv::imread %s fail!\n", img_path);
    }

    cv::Mat resizedImageBGR, resizedImageRGB, resizedImage, preprocessedImage;
    cv::resize(orig_img, resizedImageBGR,
        cv::Size(300, 300),
        0, 0, cv::InterpolationFlags::INTER_NEAREST);

    cv::cvtColor(resizedImageBGR, resizedImageRGB,
        cv::ColorConversionCodes::COLOR_BGR2RGB);

    //cout << resizedImageRGB << endl;

    resizedImageRGB.convertTo(resizedImage, CV_32F, 1.);

    cv::Mat channels[3];
    cv::split(resizedImage, channels);
    cv::merge(channels, 3, resizedImage);
    //cout << resizedImage << endl;

    return resizedImage;
}

int runImage(cv::Mat img, vector<float>& resultFeature, ncnn::Net* netp) {
    int ret;
    resultFeature.resize(1024);
    if (netp == NULL) {
        throw std::runtime_error("netp is null, somehow");
    }

    ncnn::Mat in_pack3(300, 300, 1, (void*)img.data, (size_t)4u * 3, 3);
    ncnn::Mat in;
    ncnn::convert_packing(in_pack3, in, 1);

    ncnn::Mat out;
    ncnn::Extractor ex = netp->create_extractor();
    //ex.set_num_threads(4);

    ex.input("input_1:0", in);
    ex.extract("StatefulPartitionedCall/functional_1/transfer_Dense/MatMul_Gemm__35:0", out);

    ncnn::Mat out_flat = out.reshape(out.w * out.h * out.c);

    for (size_t i = 0; i < 1024; ++i) {
        //resultFeature.push_back(out_flat[i]);
        resultFeature[i] = out_flat[i];
    }

    ex.clear();

    return 1;

}

int main()
{
    std::cout << "Hello World!\n";
    ncnn::Net net;
    net.load_param("mo/255.param");
    net.load_model("mo/255.bin");
    net.opt.use_vulkan_compute = 0;
    //net.opt.use_fp16_arithmetic = 0;
    //net.opt.use_fp16_packed = 0;
    //net.opt.use_fp16_storage = 0;

    ncnn::Net* netp = &net;


    string imgPath = "0.8156_20220525231119452_1-1_香瓜.jpg";
    cv::Mat img = loadImage(imgPath.c_str());

    vector<float> resVec;

    int ret = runImage(img, resVec, netp);

    for (int i = 0; i < 256; ++i) {
        cout << resVec[i] << " " << resVec[256 + i] << " " << resVec[512 + i] << " " << resVec[768 + i] << endl;
    }


}

Thank you for providing the code and model for testing. The bug has been identified and I am currently submitting the pull request

@ZiyueWangUoB
Copy link
Author

Thank you, it's working now as of PR #4890

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants