win10 Clion 免编译使用OpenBLAS线性代数库

近期需要移植项目,所以要在Windows上用BLAS。 网上有相关流程,但总体来看一是比较繁琐,二来有效性不高。本流程根据自身经验总结,希望能有所帮助。

Openblas github官网有介绍如何在Window上编译的方法(How to use OpenBLAS in Microsoft Visual Studio),但是编译很麻烦。网上大多都是使用Microsoft Visual Studio2015编译并使用BLAS库,但是本人还是喜欢轻巧好用的Clion IDE。

下面是经过自己编译好的OpenBLAS库,可以直接下载使用,省去编译的麻烦:
OpenBLAS-0.3.3x64-编译好的库.zip

下载解压后,在Clion配置如下

cmake_minimum_required(VERSION 3.13)
project(MEC)


set(CMAKE_CXX_STANDARD 14)
set(INC_DIR C:\\Users\\YYL\\Desktop\\OpenBLAS-0.3.3x64\\include)
set(LINK_DIR C:\\Users\\YYL\\Desktop\\OpenBLAS-0.3.3x64\\lib)

include_directories(${INC_DIR})
link_directories(${LINK_DIR})



add_executable(MEC  test3.cpp)
target_link_libraries(MEC libopenblas.a)
  • set表示定义变量,指明自己的路径
  • include_directories表示添加头文件搜索路径
  • link_directories表示添加库文件搜索路径
  • target_link_libraries(MEC libopenblas.a)中的MEC是工程名

例1

#include <cblas.h>
#include <iostream>
using namespace std;
int main(){
    const int M = 4;//A的行数,C的行数
    const int N = 2;//B的列数,C的列数
    const int K = 3;//A的列数,B的行数
    const double alpha = 1;
    const double beta = 0;
    const double A[K*M] = { 1,2,3,4,5,6,7,8,9,8,7,6 };
    const double B[K*N] = { 5,4,3,2,1,0 };
    double C[M*N];
    int lda = K;
    int ldb = N;
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, alpha, A, lda, B,ldb, beta, C, N);
    for(int i=0;i<M;i++){
        for(int j=0;j<N;j++){
            cout<<C[i*N+j]<<"\t";
        }
        cout<<endl;
    }
    return 0;
}

输出

14      8
41      26
68      44
67      46

例2

#include <iostream>
#include <vector>
#include <cstdlib>

#include <cblas.h>

// 随机生成20以内的给定尺寸数组
static void RandomFill(std::vector<float>& numbers,size_t size);
// 打印数组元素的函数
static void Print(const std::vector<float>& numbers);
// vector是一维的,输出是个矩阵,那输出的时候就要指定有几行几列
static void Print(const std::vector<float>& numbers, int rows, int cols);
// 寻找数组中最大的那个元素的索引和值
static void TestLevel1();
// 测试Level2里面最常用的函数:向量和矩阵的乘积
static void TestLevel2();
static void TestLevel3();

int main(int argc, const char * argv[]) {
    TestLevel1();
    TestLevel2();
    TestLevel3();
    return 0;
}

void RandomFill(std::vector<float>& numbers, size_t size) {
    // 预分配size的缓冲区,这样性能相对更好一点
    numbers.resize(size);
    for (size_t i = 0; i != size; ++ i) {
        numbers[i] = static_cast<float>(rand() % 20);
    }
}

void Print(const std::vector<float>& numbers) {
    for (float number : numbers) {
        std::cout << number << ' ';
    }
    std::cout << std::endl;
}

void Print (const std:: vector<float>& numbers ,int  rows, int cols) {
    for (int row =0; row != rows; ++ row) {
        for (int col = 0; col != cols; ++ col) {
            // 取出每一列的数字
            std::cout << numbers[row * cols + col] << ' ';
        }
        // 没输出一行之后换一行
        std::cout << std::endl;
    }
}
//Level1:找出数组的最大值和改值所在的Index
static void TestLevel1() {
    const int VECTOR_SIZE = 4;
    std::vector<float> fv1;

    RandomFill(fv1, VECTOR_SIZE);
    Print(fv1);

    /**
     从数组里面找出最大的那个数的索引:cblas_isamax()属于Level1的函数

      VECTOR_SIZE 数组长度
      fv1.data 数组缓冲区指针的首地址,怎么获得fv1内部缓冲区呢,用fv1.data
     third params: 跳跃数量,两个元素之间间隔几个元素,也就是每处理一个元素之后,+1得到下一个元素,如果想跳过一个元素 +2
     */
    size_t maxIndex = cblas_isamax(VECTOR_SIZE, fv1.data(), 1);
    std::cout << maxIndex << std::endl;
    std::cout << fv1[maxIndex] << std::endl;
}
/*
    Prints:
    7 9 13 18
    3
    18
    */

//Level2常用函数:计算向量与矩阵的乘积
/*
 测试Level2里面最常用的函数:向量和矩阵的乘积
 */
static void TestLevel2()
{
    // 假设我们有一个三行二列的矩阵
    const int M = 3;
    const int N = 2;

    /*
     A(M*N),x(N*1), y(M*1)
     我们定义三个矩阵a、x、y
     a:M*N的矩阵:维度为M*N矩阵
     x:N*1的矩阵,实际上是一个向量,维度为N矩阵
     y:M*1的矩阵,实际上是长度为M的向量,维度为M的矩阵
     */
    std::vector<float> a;
    std::vector<float> x;
    std::vector<float> y;

    RandomFill(a, M * N);
    RandomFill(x, N);
    RandomFill(y, M);

    std::cout << "A" << std::endl;
    Print(a, M, N);
    std::cout << "x" << std::endl;
    Print(x);
    std::cout << "y" << std::endl;
    Print(y);

    /*
     我们的目标是想计算这么一个公式:
     y := alpha * A * x + beta * y
     A:是一个矩阵,x是一个向量,所以我希望说去计算一个矩阵和向量的乘积。alpha是一个乘积的缩放,
     beta是对y的缩放,
     相当于把y里面的数字乘以beta,再加上A矩阵和向量的乘积。

     那这边有一个特例,假如我y里面都是0,或这beta是0的情况下,我就可以把公式看成:
    // y := alpha * A * x

     这个函数名称为:cblas_sgemv()
     // s:single 单精度浮点数
     // ge: 是一个乘法
     // m: matrix
     // v: vector
     */

    /**
     参数解释:
     param CblasRowMajor 行主序还是列主序,默认行主序,何为主序:即数组存储元素的方式--按行存储还是按列存储,行主序:00,01,列主序00,10
     param CblasNoTrans 矩阵是否需要转置,不需要转置,如果需要转置的话,运算的时候它会自动做转置
     param M 矩阵的行数
     param N 矩阵的列数
     param 1.0f alpha ,我们设为1
     param a.data a矩阵的缓冲区首地址
     param lda a矩阵的列数
     param x.data x矩阵的缓冲区首地址
     param 1 x里面每次跳跃累加的个数,默认为1
     param 2.0f beta对y的缩放值
     param y.data y矩阵的缓冲区首地址
     param 1 y里面每次跳跃累加的个数,默认为1
     */
    int lda = N;
    cblas_sgemv(CblasRowMajor, CblasNoTrans, M, N, 1.0f, a.data(), lda, x.data(), 1, 2.0f, y.data(), 1);
    std::cout << "result y" << std::endl;
    Print(y);
}
/*
 Prints:
 A
 7 9
 13 18
 10 12
 x
 4 18
 y
 3 9 0
 result y
 196 394 256
*/

//Level3常用函数:计算两个矩阵的乘积
/**
 计算两个矩阵的乘积
 */
static void TestLevel3() {
    // 我们希望计算两个矩阵的乘积,我们就需要定义三个参数M、N、K。
    const int M = 3;
    const int N = 2;
    const int K = 4;

    std::vector<float> a;
    std::vector<float> b;
    std::vector<float> c;

    RandomFill(a, M * K);
    RandomFill(b, K * N);
    RandomFill(c, M * N);

    // 输出A、B、C 三个矩阵
    std::cout << "A" << std::endl;
    Print(a, M, K);

    std::cout << "B" << std::endl;
    Print(b, K, N);

    std::cout << "C" << std::endl;
    Print(c, M, N);

    /*
     我们的目标是计算这么一个公式:

    // C := alpha * A * B + beta * C
    // 如果只想做两个矩阵的乘法,beta设成0就好了,变为如下式子:
    // C := alpha * A * B
      */

    /*
     函数释义:
     sgemm:矩阵间的单精度乘法
     s:single 单精度
     ge:乘法
     m:matix
     */

    /**
     参数释义:
     param CblasRowMajor 行主序还是列主序,默认行主序
     param CblasNoTrans A需不需要转置,不需要
     param CblasNoTrans B需不需要转置,不需要
     param M 系数M
     param N 系数N
     param K 系数K
     param 1.0f alpha 设为1
     param a.data a的缓冲区首地址
     param lda a的列数
     param b.data b的缓冲区首地址
     param ldb b的列数
     param 1.0f beta 设为1
     param c.data c的缓冲区首地址
     param ldc c的列数
     */

    int lda = K;
    int ldb = N;
    int ldc = N;
    cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, 1.0f, a.data(), lda, b.data(), ldb, 1.0f, c.data(), ldc);
    std::cout << "Result C" << std::endl;
    // 三行四列的矩阵 * 四行二列的矩阵 + 三行二列的矩阵,结果为一个三行二列的矩阵
    Print(c, M, N);
}
/*
 Prints:
 A
 7 9 13 18
 10 12 4 18
 3 9 0 5
 B
 12 2
 7 3
 7 9
 0 12
 C
 3 9
 9 17
 0 13
 Result C
 241 383
 241 325
 99 106
 */

输出

1 7 14 0
2
14
A
9 4
18 18
2 4
x
5 5
y
1 7 1
result y
67 194 32
A
11 15 2 7
16 11 4 2
13 12 2 1
B


16 18
15 7
6 11
18 9
C
12 7
19 15
14 3
Result C
551 395
500 442
432 352

猜你喜欢

转载自blog.csdn.net/yyl424525/article/details/102702324
今日推荐