“东方杯”英特尔oneAPI黑客松参赛经验总结

目录

问题简介

oneMKL介绍

问题简单分析

代码实现

生成随机数据

分配内存用于输出结果

生成指定大小的随机单精度实数数组

使用 oneMKL API 进行两维实数到复数的FFT计算(示例)

两维实数到复数的FFT实现(参考代码)

允许适当的精度误差下验证两个数组是否完全相等

完整代码

结果展示

结语


问题简介

  1. 调用 oneMKL 相应 API 函数, 产生 2048 * 2048 个 随机单精度实数();
  2. 根据 1 产生的随机数据作为输入,实现两维 Real to complex FFT 参考代码;
  3. 根据 1 产生的随机数据作为输入, 调用 oneMKL API 计算两维 Real to complex FFT;
  4. 结果正确性验证,对 2 和 3 计算的两维 FFT 输出数据进行全数据比对(允许适当精度误差), 输出 “结果正确”或“结果不正确”信息;
  5. 平均性能数据比对(比如运行 1000 次),输出 FFT 参考代码平均运行时间和 oneMKL FFT 平均运行时间。

oneMKL介绍

        oneMKL是英特尔发布的数学内核库,提供了高性能的线性代数、FFT和随机数生成等数学函数。该库支持常见的CPU架构和操作系统,包括Windows、Linux和macOS等,能够充分利用Intel CPU的优势,提供了高效且灵活的API接口,方便用户进行编程。同时,oneMKL还提供了Python和MATLAB等语言的接口,为用户提供了更便捷的编程方式。总之,oneMKL是一个高效、灵活且易于使用的数学库,为科学计算和工程计算应用提供了强大的支持。

问题简单分析

  1. 调用oneMKL相应API函数产生随机数: 使用oneMKL库中的随机数生成函数,例如vdRngUniform,来生成指定行列数的随机单精度实数数组。
  2.  实现两维Real-to-Complex FFT参考代码: 首先,将输入数据按行进行一维FFT计算。然后,对每一列的一维FFT结果进行进一步的一维FFT计算,得到最终的二维FFT结果。
  3. 调用oneMKL API计算两维Real-to-Complex FFT结果正确性验证: 使用oneMKL库中的FFT函数,如cufftPlanMany和cufftExecC2R,根据生成的随机数据计算两维Real-to-Complex FFT的结果。
  4. 对两维FFT输出数据进行全数据比对: 将参考代码得到的二维FFT结果与oneMKL计算的二维FFT结果进行逐个元素比较。可以使用适当的误差范围来容忍小的数值误差。
  5. 平均性能数据比对: 分别运行1000次参考代码和oneMKL FFT计算,并记录每次运行的时间。计算平均运行时间并进行比较,即可得到平均性能数据比对结果

代码实现

  • 生成随机数据

     float* inputData = new float[dataSize];
     generateRandomData(inputData, dataSize);

  • 分配内存用于输出结果

    MKL_Complex8* refOutput = new MKL_Complex8[dataSize];
    MKL_Complex8* mklOutput = new MKL_Complex8[dataSize];

  • 生成指定大小的随机单精度实数数组

    void generateRandomData(float* data, int size) {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<float> dis(-1.0f, 1.0f);
    
        for (int i = 0; i < size; i++) {
            data[i] = dis(gen);
        }
    }
  • 使用 oneMKL API 进行两维实数到复数的FFT计算(示例)

    void mklFFT(float* input, MKL_Complex8* output, int size) {
        MKL_LONG status;
    
        DFTI_DESCRIPTOR_HANDLE handle;
        status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 2, size, size);
        if (status != 0) {
            std::cout << "创建oneMKL FFT描述符失败。" << std::endl;
            return;
        }
    
        status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
        if (status != 0) {
            std::cout << "设置oneMKL FFT的位置失败。" << std::endl;
            DftiFreeDescriptor(&handle);
            return;
        }
    
        status = DftiCommitDescriptor(handle);
        if (status != 0) {
            std::cout << "提交oneMKL FFT描述符失败。" << std::endl;
            DftiFreeDescriptor(&handle);
            return;
        }
    
        status = DftiComputeForward(handle, input, output);
        if (status != 0) {
            std::cout << "计算oneMKL FFT失败。" << std::endl;
        }
    
        DftiFreeDescriptor(&handle);
    }
  • 两维实数到复数的FFT实现(参考代码)

    void referenceFFT(float* input, MKL_Complex8* output, int size) {
        DFTI_DESCRIPTOR_HANDLE handle;
        MKL_LONG status;
    
        status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 2, size, size);
        if (status != 0) {
            std::cout << "创建参考FFT描述符失败。" << std::endl;
            return;
        }
    
        status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
        if (status != 0) {
            std::cout << "设置参考FFT的位置失败。" << std::endl;
            DftiFreeDescriptor(&handle);
            return;
        }
    
        status = DftiCommitDescriptor(handle);
        if (status != 0) {
            std::cout << "提交参考FFT描述符失败。" << std::endl;
            DftiFreeDescriptor(&handle);
            return;
        }
    
        status = DftiComputeForward(handle, input, output);
        if (status != 0) {
            std::cout << "计算参考FFT失败。" << std::endl;
        }
    
        DftiFreeDescriptor(&handle);
    }
  • 允许适当的精度误差下验证两个数组是否完全相等

    bool verifyResult(MKL_Complex8* refOutput, MKL_Complex8* mklOutput, int size) {
        float epsilon = 1e-6f; // 允许的精度误差
    
        for (int i = 0; i < size; i++) {
            float diffReal = std::abs(refOutput[i].real - mklOutput[i].real);
            float diffImag = std::abs(refOutput[i].imag - mklOutput[i].imag);
    
            if (diffReal > epsilon || diffImag > epsilon) {
                return false;
            }
        }
    
        return true;
    }

完整代码

#include <iostream>
#include <random>
#include <chrono>
#include <cmath>
#include <mkl.h>

// 生成指定大小的随机单精度实数数组
void generateRandomData(float* data, int size) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> dis(-1.0f, 1.0f);

    for (int i = 0; i < size; i++) {
        data[i] = dis(gen);
    }
}

// 参考代码:两维实数到复数的FFT实现
void referenceFFT(float* input, MKL_Complex8* output, int size) {
    DFTI_DESCRIPTOR_HANDLE handle;
    MKL_LONG status;

    status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 2, size, size);
    if (status != 0) {
        std::cout << "创建参考FFT描述符失败。" << std::endl;
        return;
    }

    status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
    if (status != 0) {
        std::cout << "设置参考FFT的位置失败。" << std::endl;
        DftiFreeDescriptor(&handle);
        return;
    }

    status = DftiCommitDescriptor(handle);
    if (status != 0) {
        std::cout << "提交参考FFT描述符失败。" << std::endl;
        DftiFreeDescriptor(&handle);
        return;
    }

    status = DftiComputeForward(handle, input, output);
    if (status != 0) {
        std::cout << "计算参考FFT失败。" << std::endl;
    }

    DftiFreeDescriptor(&handle);
}

// 使用 oneMKL API 进行两维实数到复数的FFT计算
void mklFFT(float* input, MKL_Complex8* output, int size) {
    MKL_LONG status;

    DFTI_DESCRIPTOR_HANDLE handle;
    status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 2, size, size);
    if (status != 0) {
        std::cout << "创建oneMKL FFT描述符失败。" << std::endl;
        return;
    }

    status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
    if (status != 0) {
        std::cout << "设置oneMKL FFT的位置失败。" << std::endl;
        DftiFreeDescriptor(&handle);
        return;
    }

    status = DftiCommitDescriptor(handle);
    if (status != 0) {
        std::cout << "提交oneMKL FFT描述符失败。" << std::endl;
        DftiFreeDescriptor(&handle);
        return;
    }

    status = DftiComputeForward(handle, input, output);
    if (status != 0) {
        std::cout << "计算oneMKL FFT失败。" << std::endl;
    }

    DftiFreeDescriptor(&handle);
}

// 验证两个数组是否完全相等(允许适当的精度误差)
bool verifyResult(MKL_Complex8* refOutput, MKL_Complex8* mklOutput, int size) {
    float epsilon = 1e-6f; // 允许的精度误差

    for (int i = 0; i < size; i++) {
        float diffReal = std::abs(refOutput[i].real - mklOutput[i].real);
        float diffImag = std::abs(refOutput[i].imag - mklOutput[i].imag);

        if (diffReal > epsilon || diffImag > epsilon) {
            return false;
        }
    }

    return true;
}

int main() {
    int size = 2048;
    int dataSize = size * size;
    int numRuns = 1000; // 运行次数

    // 生成随机数据
    float* inputData = new float[dataSize];
    generateRandomData(inputData, dataSize);

    // 分配内存用于输出结果
    MKL_Complex8* refOutput = new MKL_Complex8[dataSize];
    MKL_Complex8* mklOutput = new MKL_Complex8[dataSize];

    // 参考代码实现两维实数到复数的FFT
    auto startRef = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < numRuns; i++) {
        referenceFFT(inputData, refOutput, size);
    }
    auto endRef = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> refDuration = (endRef - startRef) / numRuns;

    // 使用 oneMKL API 进行两维实数到复数的FFT计算
    auto startMkl = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < numRuns; i++) {
        mklFFT(inputData, mklOutput, size);
    }
    auto endMkl = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> mklDuration = (endMkl - startMkl) / numRuns;

    // 验证结果正确性
    bool resultCorrect = verifyResult(refOutput, mklOutput, dataSize);

    // 输出结果
    if (resultCorrect) {
        std::cout << "结果正确" << std::endl;
    }
    else {
        std::cout << "结果不正确" << std::endl;
    }

    std::cout << "参考代码平均运行时间: " << refDuration.count() << " 秒" << std::endl;
    std::cout << "oneMKL 平均运行时间: " << mklDuration.count() << " 秒" << std::endl;

    // 释放内存
    delete[] inputData;
    delete[] refOutput;
    delete[] mklOutput;

    getchar();

    return 0;
}

结果展示

结语

        本次是我第一次使用oneAPI数学内核库(oneMKL)接口,该比赛内容主要是调用oneMKL相关接口实现2D、FFT变换等,难度不高但要花一定的时间去查阅示例代码与环境配置。虽然只是简单的FFT并没有特别深入了解,但已经初步体会到oneMKL对英特尔处理器架构的能够充分利用的特性。综上所述,oneMKL是一款功能强大、易于使用、性能卓越的数学库,对于需要进行计算密集型任务的用户来说是一款值得推荐的工具。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值