Skip to content

使用vulkan进行推理时结果不正确 #5909

Open
@XingRay

Description

error log | 日志或报错信息 | ログ

context | 编译/运行环境 | バックグラウンド

windows11

how to reproduce | 复现步骤 | 再現方法

使用cpu进行推理时, 结果是正常的, 但是使用gpu推理时,返回的结果是错误的, 我将运行时的所有的blob输出, 结果发现经过第一个卷积层后输出就不一样了

more | 其他 | その他

主要代码如下:

    bool useGpu = true;
    bool useDebugParam = true;

    SetConsoleOutputCP(CP_UTF8);
    LOG_I("开始 face detection test...");

    // 文件路径配置
    std::string param_path;
    if (useDebugParam) {
        param_path = R"(D:\tmp\ncnn_pytorch\face_detector.ncnn_debug.param)";
    } else {
        param_path = R"(D:\tmp\ncnn_pytorch\face_detector.ncnn.param)";
    }
    std::string bin_path = R"(D:\tmp\ncnn_pytorch\face_detector.ncnn.bin)";

    std::string original_img_path = R"(D:\tmp\image\o\face_image_1080_1920.png)";
    std::string padded_image_save_path = R"(D:\tmp\image\face_detector_ncnn_padded.png)"; // 你可以修改为所需路径

    std::string output_img_path = R"(D:\tmp\image\face_detector_ncnn.png)";
    std::string original_with_detection_output_img_path = R"(D:\tmp\image\face_detector_ncnn_with_original.png)";

    // 加载图像
    cv::Mat originalImg = cv::imread(original_img_path, cv::IMREAD_UNCHANGED);
    if (originalImg.empty()) {
        LOG_E("图片未找到: %s", original_img_path.c_str());
        return -1;
    }

    // 转换通道:如果图像有 4 通道,转换为 RGB;否则从 BGR 转换为 RGB
    if (originalImg.channels() == 4) {
        LOG_D("COLOR_BGRA2RGB");
        cv::cvtColor(originalImg, originalImg, cv::COLOR_BGRA2RGB);
    } else {
        LOG_D("COLOR_BGR2RGB");
        cv::cvtColor(originalImg, originalImg, cv::COLOR_BGR2RGB);
    }

    // 1. letterbox处理后得到 padded 图像,尺寸为 128x128,格式为 RGB
    PaddingParams padding_params{};
    cv::Mat padded = letterbox_padding(originalImg, cv::Size(128, 128), padding_params);

    ncnn::Mat mat_in;
    cv::Mat padded_float;

    if (useDebugParam) {
        mat_in = ncnn::Mat::from_pixels(padded.data, ncnn::Mat::PIXEL_RGB, padded.cols, padded.rows);
        const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
        mat_in.substract_mean_normalize(0, norm_vals);
        mat_in.dims = 4;
    }else {
        padded.convertTo(padded_float, CV_32FC3, 1.0 / 255.0);
        mat_in = ncnn::Mat(3, 128, 128, 1, padded_float.data);
    }
    print_ncnn_mat_shape(mat_in, "mat_in");

    ncnn::Net net;
    if (useGpu) {
        int gpu_count = ncnn::get_gpu_count();
        LOG_D("gpu_count:%d", gpu_count);
        if (gpu_count <= 0) {
            LOG_E("gpu_count<=0");
            return -1;
        }

        LOG_D("use_vulkan_compute");
        net.opt.use_vulkan_compute = true;

        // set specified vulkan device before loading param and model
        // net.set_vulkan_device(0); // use device-0

        net.opt.use_fp16_packed = false;
        net.opt.use_fp16_storage = false;
        net.opt.use_fp16_arithmetic = false;
        net.opt.use_int8_storage = false;
        net.opt.use_int8_arithmetic = false;
    }

    LOG_I("load_param: %s", param_path.c_str());
    if (net.load_param(param_path.c_str()) != 0) {
        LOG_E("加载 param 文件失败");
        return -1;
    }
    LOG_I("load_model: %s", bin_path.c_str());
    if (net.load_model(bin_path.c_str()) != 0) {
        LOG_E("加载 bin 文件失败");
        return -1;
    }

    ncnn::Extractor ex = net.create_extractor();
    // 设置输入节点名称为 "in0"
    LOG_D("ex.input");
    ex.input("in0", mat_in);

    // 执行推理,提取输出 "out0" 和 "out1"
    LOG_D("ex.extract");
    ncnn::Mat regressors, scores;
    ex.extract("out0", regressors);
    ex.extract("out1", scores);
    print_ncnn_mat_shape(regressors, "regressors");
    print_ncnn_mat_shape(scores, "scores");

    int num_regressors = regressors.w * regressors.h * regressors.c; // 896*16
    int num_scores = scores.w * scores.h * scores.c; // 896

    std::vector<float> reg_vec((float *) regressors.data, (float *) regressors.data + num_regressors);
    std::vector<float> score_vec((float *) scores.data, (float *) scores.data + num_scores);

    // 对 score_vec 执行 clip(-100,100) 并计算 sigmoid
    for (auto &s: score_vec) {
        if (s < -100.0f) s = -100.0f;
        if (s > 100.0f) s = 100.0f;
        s = 1.0f / (1.0f + std::exp(-s));
    }
    // 找到最大分数索引
    int max_index = std::distance(score_vec.begin(), std::max_element(score_vec.begin(), score_vec.end()));
    float max_score = score_vec[max_index];
    LOG_I("最大分数: %.4f, 索引: %d", max_score, max_index);

通过flag useGpu 切换使用cpu/gpu 推理
bool useGpu = true;
通过flag useDebugParam 切换是否使用手动调整过的param
bool useDebugParam = true;

模型是使用pnnx将onnx转换成的ncnn模型,
pnnx输出的模型转换输入:

Input                    in0                      0 1 in0
Permute                  permute_56               1 1 in0 1 0=4

手动调整一下可以传入常规的shape的tensor

Input                    in0                      0 1 in0
Permute                  permute_56               1 1 in0 1 0=6

区别是 permute 参数 type 修改

现在的现象是:
当 useGpu = false 时, useDebugParam 为 true/false 都可以正常输出
当 useGpu = true 时, useDebugParam 为 true/false 都可以输出, 但是数值是错误的

完整的项目见附件
ncnn-test.zip

输出的blob部分如下, 前2个blob, 使用cpu和gpu时完全一致, 第三个blob开始产生区别
blob.zip

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions