[blas] Openblas 사용해보기

alirz-pixel·2022년 5월 16일
0

blas

목록 보기
2/2

0. 기초

blas 컴파일하기

gcc openblas_test.c -lopenblas

blas 열거형

이름목록
CBLAS_ORDERmajor가 row 또는 col로 되어있음CblasRowMajor, CblasColMajor
CBLAS_TRANSPOSE전치 행렬CblasNoTrans, CblasTrans, CblasConjTrans, CblasConjNoTrans
CBLAS_UPLO상/하 삼각행렬CblasUpper, CblasLower

1. gemm

1) 함수 원형

void cblas_sgemm(OPENBLAS_CONST enum CBLAS_ORDER Order, OPENBLAS_CONST enum CBLAS_TRANSPOSE TransA, OPENBLAS_CONST enum CBLAS_TRANSPOSE TransB, OPENBLAS_CONST blasint M, OPENBLAS_CONST blasint N, OPENBLAS_CONST blasint K,
		 OPENBLAS_CONST float alpha, OPENBLAS_CONST float *A, OPENBLAS_CONST blasint lda, OPENBLAS_CONST float *B, OPENBLAS_CONST blasint ldb, OPENBLAS_CONST float beta, float *C, OPENBLAS_CONST blasint ldc);

gemmGEneral Matrix-Matrix Multiplication 의 약자로
αAB * βC = C를 구하는 함수이다.


행렬 A를 m × k, 행렬 B를 k × n 라고 할 때, 행렬 AB의 결과인 C는 n × m 이다


인자 목록

Order : rowMajor의 경우 CblasRowMajor, colMajor의 경우, CblasColMajor
TransA : 전치행렬의 경우, CblasTrans, 아닐경우 CblasNoTrans
TransB : TransA와 동일

A, B : 행렬 A, B
C : input과 output으로 받을 행렬 C
(A, B, C 모두 1차원 배열)

M, N, K : 위의 정의와 동일한 값 (즉, 실제 행렬 곱에 사용되는 m, n, k)

alpha : (행렬 A × 행렬 B)에 곱해질 상수
beta : 행렬 C에 곱해질 상수

lda, ldb : 행렬 A 또는 B의 열의 크기
ldc : 행렬 C의 열의 크기

2) gemm 사용해보기

#include <stdlib.h>
#include <stdio.h>
#include <cblas.h>

void print_matrix(float* A, int m, int k) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < k; j++) {
			printf("%f ", A[i * k + j]);
		}
		
		printf("\n");
	}

	printf("\n");
}

int main() {
	int a_m = 2;
	int a_n = 3;

	int b_m = 7;
	int b_n = 3;

	float* A = (float*)malloc(a_m * a_n * sizeof(float));
	float* B = (float*)malloc(b_m * b_n * sizeof(float));
	float* C = (float*)malloc(a_m * b_m * sizeof(float));

	for (int i = 0; i < a_m * a_n; i++) {
		A[i] = i + 1;
	}
	
	for (int i = 0; i < b_m * b_n; i++) {
		B[i] = i + 1;
	}

	print_matrix(A, a_m, a_n);
	print_matrix(B, b_m, b_n);

	cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 2, 7, 3, 1.0f, A, 3, B, 3, 0, C, 7);

	print_matrix(C, a_m, b_m);

	free(A);
	free(B);
	free(C);

	return 0;
}

2. gemv

1) 함수 원형

void cblas_sgemv(const enum CBLAS_ORDER __Order, const enum CBLAS_TRANSPOSE __TransA, const int __M, const int __N,
         const float __alpha, const float *__A, const int __lda, const float *__X, const int __incX, const float __beta, float *__Y, const int __incY);

gemvGEneral Matrix-Vector multiplication의 약자로
αAX * βY = Y를 구하는 함수이다.

인자 목록

Order, TransA : gemm과 동일

A, X : 행렬 A벡터 X
Y : input 과 output으로 받을 벡터 Y

M, N : 행렬 A의 행과 열

alpha : (행렬 A × 벡터 X)에 곱해질 상수
beta : 벡터 Y에 곱해질 상수

ida : 행렬 A의 열의 크기
incX, incY : incX, incY 값 만큼 점프뛰어 해당 행렬을 계산한다.

2) gemv을 통해 mn × n1 구현

#include <stdio.h>
#include <stdlib.h>
#include <cblas.h>

void insert_value(float *matrix, int m, int n) {
	for (int i = 0; i < m * n; i++) {
		matrix[i] = i + 1;
	}
}

void print_value(float* matrix, int m, int n) {
	for (int y = 0; y < m; y++) {
		for (int x = 0; x < n; x++) {
			printf("%f ", matrix[y * n + x]);
		}

		printf("\n");
	}

	printf("\n");
}

int main() {
	int m = 3;
	int n = 2;

	float *A = (float*)malloc(sizeof(float) * m * n);
	float *X = (float*)malloc(sizeof(float) * n * 1);
	float *Y = (float*)malloc(sizeof(float) * m * 1);

	insert_value(A, m, n);
	insert_value(X, n, 1);

	print_value(A, m, n);
	print_value(X, n, 1);

	cblas_sgemv(CblasRowMajor, CblasNoTrans, m, n, 1, A, n, X, 1, 0, Y, 1);

	print_value(Y, m, 1);

	return 0;
}

3) incX 활용해보기

[123456789][12345]\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{bmatrix} \begin{bmatrix} 1 \\ 2 \\ 3 \\ 4 \\ 5 \end{bmatrix}

인자 목록에 적었듯이 incX는 점프해서 계산하기 때문에 위의 행렬과 벡터의 곱incX = 2로 세팅하여 아래처럼 계산이 가능하도록 구현가능하다.

[123456789][135]\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{bmatrix} \begin{bmatrix} 1 \\ 3 \\ 5 \end{bmatrix}

코드

#include <stdio.h>
#include <stdlib.h>
#include <cblas.h>

void insert_value(float *matrix, int m, int n) {
        for (int i = 0; i < m * n; i++) {
                matrix[i] = i + 1;
        }
}

void print_value(float* matrix, int m, int n) {
        for (int y = 0; y < m; y++) {
                for (int x = 0; x < n; x++) {
                        printf("%f ", matrix[y * n + x]);
                }

                printf("\n");
        }

        printf("\n");
}

int main() {
        //  cblas_sgemv(OPENBLAS_CONST enum CBLAS_ORDER order,  OPENBLAS_CONST enum CBLAS_TRANSPOSE trans,  OPENBLAS_CONST blasint m, OPENBLAS_CONST blasint n,
        //       OPENBLAS_CONST float alpha, OPENBLAS_CONST float  *a, OPENBLAS_CONST blasint lda,  OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx,  OPENBLAS_CONST float beta,  float  *y, OPENBLAS_CONST blasint incy);

        // Y = bY + aAX
        int m = 3;
        int n = 3;

        float *A = (float*)malloc(sizeof(float) * m * n);
        float *X = (float*)malloc(sizeof(float) * 5 * 1);
        float *Y = (float*)malloc(sizeof(float) * m * 1);

        insert_value(A, m, n);
        insert_value(X, 5, 1);

        print_value(A, m, n);
        print_value(X, 5, 1);

        cblas_sgemv(CblasRowMajor, CblasNoTrans, m, n, 1, A, n, X, 2, 0, Y, 1);

        print_value(Y, m, 1);

        return 0;
}

3. sdot

1) 함수 원형

float cblas_sdot(const int __N, const float *__X, const int __incX, const float *__Y, const int __incY);

X·Y 즉, 벡터 X벡터 Y의 내적을 구하는 함수이다.

인자 목록

X, Y : 벡터 X, 벡터 Y
N : 벡터 X, Y의 element 개수

incX, incY : incX, incY값 만큼 점프뛰어 내적을 계산한다.

2) sdot 사용해보기

#include <stdio.h>
#include <stdlib.h>
#include <cblas.h>

void insert_value(float *matrix, int m, int n) {
	for (int i = 0; i < m * n; i++) {
		matrix[i] = i + 1;
	}
}

void print_value(float* matrix, int m, int n) {
	for (int y = 0; y < m; y++) {
		for (int x = 0; x < n; x++) {
			printf("%f ", matrix[y * n + x]);
		}

		printf("\n");
	}

	printf("\n");
}

int main() {
	// float cblas_sdot(const int __N, const float *__X, const int __incX, const float *__Y, const int __incY);

	// ans = X · Y;
	int n = 3;

	float *X = (float*)malloc(sizeof(float) * n * 1);
	float *Y = (float*)malloc(sizeof(float) * 5 * 1);

	insert_value(X, n, 1);
	insert_value(Y, 5, 1);

	print_value(X, n, 1);
	print_value(Y, 5, 1);

	float ans = cblas_sdot(n, X, 1, Y, 2);
	printf("%f", ans);

	return 0;
}

4. axpby

1) 함수 원형

void catlas_caxpby(const int __N, const void *__alpha, const void *__X, const int __incX, const void *__beta, void *__Y, const int __incY);

axpbyAlpha, vector X, Plus, Beta, vector Y 의 약자로
αX * βY = Y를 구하는 함수이다.

인자 목록

X, Y : 벡터 X, 벡터 Y
N :벡터 X, Y의 element 개수

alpha, beta = 벡터 X 또는 벡터 Y에 곱해질 상수
incX, incY : incX, incY값 만큼 점프뛰어 계산

2) axpby 사용해보기

#include <stdio.h>
#include <stdlib.h>
#include <cblas.h>

void insert_value(float *matrix, int m, int n) {
	for (int i = 0; i < m * n; i++) {
		matrix[i] = i + 1;
	}
}

void print_value(float* matrix, int m, int n) {
	for (int y = 0; y < m; y++) {
		for (int x = 0; x < n; x++) {
			printf("%f ", matrix[y * n + x]);
		}

		printf("\n");
	}

	printf("\n");
}

int main() {
	// void catlas_caxpby(const int __N, const void *__alpha, const void *__X, const int __incX, const void *__beta, void *__Y, const int __incY);

	// αX * βY = Y
	int n = 3;

	float *X = (float*)malloc(sizeof(float) * n * 1);
	float *Y = (float*)malloc(sizeof(float) * 5 * 1);

	insert_value(X, n, 1);
	insert_value(Y, 5, 1);

	print_value(X, n, 1);
	print_value(Y, 5, 1);

	cblas_saxpby(n, 2, X, 1, 3, Y, 2);
	print_value(Y, 5, 1);

	return 0;
}

0개의 댓글