cblas_sgemm和cublasSgemm参数详解

2023-11-09

机器学习最核心的底层运算肯定是矩阵乘法无疑了,为了让矩阵乘法执行更快,大家也是绞尽脑汁。从算法层面,stranssen算法将矩阵乘法复杂度由 O ( n 3 ) O(n^3) O(n3)降到 O ( n 2.81 ) O(n^{2.81}) O(n2.81),最新的算法好像已经降到 O ( n 2.37 ) O(n^{2.37}) O(n2.37)左右了(Coppersmith–Winograd algorithm),但这只是理论复杂度,只有在矩阵超大的情况下才能体现出优势。从并行角度,我们可以从很多层面对矩阵乘法进行加速:1. 指令集并行,现在的CPU都会有很多并行指令可以一次完成多个乘法运算,Intel下有mmx指令集,arm下有neon指令集;2. 多核并行,除了指令集并行,我们还可以将矩阵分块,放在不同的核上进行数据层面的并行;3. GPU加速,利用GPU上的众核完成并行;4. 多机并行,针对超大矩阵或者众多矩阵乘法还可以采用多机并行。

在实际中,我们往往会采用指令集并行和GPU对矩阵乘法进行加速。用指令集优化矩阵乘法难度比较大,非专业人士不建议采用,而且幸运的是我们现在有很多开源矩阵运算库,性能大概率超过手写的矩阵乘法。CPU下的矩阵运算库有openblas和mkl等,GPU下有cublas,它们都是对fortran blas接口的实现。在上述加速库的基础上,我们可以再对矩阵进行分割实现多核或者多机的并行。在目前情况下,要实现快速的矩阵乘法,最便捷快速的方法就是用好openblas和cublas。openblas下的矩阵乘法函数为:cblas_sgemm,cublas中为cubalsSgemm。两个函数的参数基本一致,不过一个是行主序一个是列主序(cblas下一般用行主序,虽然它支持列主序),导致传递参数的时候差别很大。本博客希望能给大家一个详细明白的解释。

矩阵乘法原理

在线性代数中我们都学习过矩阵乘法,简单描述就是A矩阵的一行乘以B矩阵的一列,如图1所示。如果A矩阵大小为m*k,B矩阵为k*n,则生成的C矩阵大小为m*n,形象地描述就是中间的维度被吃掉了。A矩阵的一行固定之后乘以B的所有列填充C矩阵的一行。这看似简单的矩阵乘法有很多奥妙在里面。
图1 矩阵乘法C=A*B
在实际中,为了避免cache缺失,B矩阵往往会事先做转置,之前B矩阵按列访问元素,转置之后就和A矩阵一样按行访问,如图2所示,这个操作带来的速度提升是很明显的。
在这里插入图片描述
在示意图中,矩阵都是二维形式展示的,但是在内存中它们实际上是以一维数组形式存在的(暂时不考虑padding问题)。A矩阵大小为m*k,在内存中A矩阵的存在形式不过是一个m*k的一维数组而已。针对这块空间我们有很多解释:它既可以表示一个一维数组,也可以表示以能整除m*k的整数为宽的二维数组(也即矩阵)。但是具体宽度是多少选择很多,至少宽度既可以是m也可以是k,所以我们需要知道矩阵的宽度。似乎指定m、n和k之后矩阵的长和宽就定了,绝大多数情况下确实如此,不过也有例外。如图3,比如要进行计算的矩阵是一个大矩阵的一部分,此时为了正确访问矩阵的一行,我们需要跳过的元素就不是k了,而是原始大矩阵的宽度K。这也是库函数中lda、ldb和ldc存在的原因,它表示leading dimension,在行主序中为访问矩阵的一行需要跨过的列元素个数,在列主序中为访问矩阵的一列需要跨过的行元素个数。
在这里插入图片描述
在行主序下,矩阵乘法是A的一行乘以B的一列,为了保证正确性在列主序下就变成了B的一列乘以A的一行。B矩阵的一列固定之后乘以A的所有行填充C的一列,如图4。这样我们就可以和行主序下计算的结果一致。所以在列主序下,A*B变成了B*A。
在这里插入图片描述

cblas_sgemm参数详解

函数原型如下:

void cblas_sgemm(
const enum CBLAS_ORDER Order, 
const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, 
const int M,
const int N,
const int K,
const float alpha, 
const float  *A,
const int lda, 
const float  *B, 
const int ldb,
const float beta,
float  *C, 
const int ldc);
  • 参数Order:表示计算在行主序下(CblasRowMajor)还是列主序下(CblasColMajor)完成,相信大家更熟悉行主序,所以CPU下我们就填CblasRowMajor;
  • 参数TransA:表示第一个矩阵A是否做了转置,转置就填CblasTrans,否则就填CblasNoTrans,在行主序下第一个矩阵往往不做转置,所以一般填CblasNoTrans;
  • 参数TransB:表示第二个矩阵B是否做了转置,在行主序下为了避免cache缺失,第二个矩阵通常会做转置;
  • 参数M:表示 A或C的行数。如果A转置,则表示转置后的列数(A的大小为M*K,则为M,转置之后为K*M,也为M);
  • 参数N:表示 B或C的列数。如果B转置,则表示转置后的行数(B的大小为K*N,则为N,转置之后为N*K,也为N);
  • 参数K:表示 A的列数或B的行数(A的列数=B的行数),即为被吃掉的维度;
  • 参数alpha和beta:计算公式C = alpha*op( A )*op( B ) + beta*C中的两个参数值;
  • 参数lda:表示矩阵A的leading dimension,在行主序下,A转置表示A的行否则为A的列,值均为K,和参数M相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldb:表示矩阵B的leading dimension,在行主序下,B转置表示B的列否则为B的行,值均为K,和参数N相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldc:表示矩阵C的leading dimension,在行主序下始终为N,表示C的列。

上面特别容易出错的几个参数是M、N、K和lda、ldb、ldc,在填这几个参数的时候要相当小心。

cublasSgemm参数详解

函数原型如下:

cublasStatus_t cublasSgemm (
cublasHandle_t handle, 
cublasOperation_t transA,
cublasOperation_t transB, 
int M,
int N,
int K,
const float *alpha,  
const float *A, 
int lda,
const float *B,
int ldb, 
const float *beta,  
float *C,
int ldc);
  • 参数handle:cublas的句柄,通过cublasCreate创建;
  • 参数transA:矩阵B是否转置,转置填CUBLAS_OP_T,否则填CUBLAS_OP_N;
  • 参数transB:矩阵A是否转置;
  • 参数M:表示矩阵B的列数,若转置则为B的行数(B大小为K*N,则为N,转置之后为N*K,也为N);
  • 参数N:表示矩阵A的行数,若转置则为A的列数(A大小为M*K,则为M,转置之后为K*M,也为M);
  • 参数K:表示 B的行数或A的列数(A的列数=B的行数),即为被吃掉的维度;
  • 参数alpha和beta:计算公式C = alpha*op( A )*op( B ) + beta*C中的两个参数的引用
  • 参数lda:表示矩阵B的leading dimension,在列主序下,B转置表示B的列否则为B的行,值均为K,和参数M相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldb:表示矩阵A的leading dimension,在列主序下,A转置表示A的行否则为A的列,值均为K,和参数N相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldc:表示矩阵C的leading dimension,在列主序下始终为N,表示C的列(此处和行主序一样,本人略微不解)。

在填入cublasSgemm的参数时,首先要记得交换矩阵A和B,然后根据列主序的要求填入相关参数。在cuda samples/0_Simple中有一个cublas调用示例matrixMulCUBLAS,大家可以参考里面的调用来进一步学习cublasSgemm。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cblas_sgemm和cublasSgemm参数详解 的相关文章

  • 树06--二叉树中和为某一值的路径

    树06 二叉树中和为某一值的路径 jz24 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 输入一颗二叉树的根节点和一个整数 按字典序打印出二叉树中结点值的和为输入整数的所有路径 路径定义为从树的根结点开始往下一直到叶结点所经
  • 将二叉树转为有序的双向链表

    一 题目要求 输入一棵二叉排序树 现在要将该二叉排序树转换成一个有序的双向链表 而且在转换的过程中 不能创建任何新的结点 只能调整树中的结点指针的指向来实现 include
  • Sort List

    Sort a linked list in O n log n time using constant space complexity 题目要求用 O n log n 的时间复杂度和常数的空间复杂度来进行链表排序 O nlogn 的排序算
  • 链表和线性表的优缺点

    链表和线性表的优缺点 作为我们最先接触的两个数据结构 链表和线性表的优缺点都较为明显 并且二者互相补足 文章目录 链表和线性表的优缺点 线性表 线性表的组成 线性表的缺点 线性表的优点 链表 链表的组成 链表的优点 链表的缺点 总结 线性表
  • 常用的十种算法--马踏棋盘算法

    1 马踏棋盘算法介绍 马踏棋盘算法也被称为骑士周游问题 将马随机放在国际象棋的 8 8 棋盘 Board 0 7 0 7 的某个方格中 马按走棋规则 马走日字 进行移动 要求每个方格只进入一次 走遍棋盘上全部 64 个方格 2 马踏棋盘算法
  • 数据结构之图的两种遍历实现(C语言版)

    上一期文章分享完了图的两种遍历方式 也是两种很重要的算法 DFS和BFS 这两种算法的应用和重要性我就不多说了 内行的人懂的都懂 今天这文章重要就是来上机实现这两种算法 又由于这两种算法都可以由邻接矩阵和邻接表来表示 博主分享的代码都是上机
  • 算法系列15天速成——第八天 线性表【下】

    一 线性表的简单回顾 上一篇跟大家聊过 线性表 顺序存储 通过实验 大家也知道 如果我每次向 顺序表的头部插入元素 都会引起痉挛 效率比较低下 第二点我们用顺序存储时 容 易受到长度的限制 反之就会造成空间资源的浪费 二 链表 对于顺序表存
  • 数据结构与算法书籍推荐

    学习数据结构与算法 还是很有必要看几本相关的书籍 但根据不同基础的人 合适看的书也不一样 因此 针对不同层次 不同语言的人 推荐几本市面上口碑不错的书 1 入门级 针对刚入门的同学 建议不要急着去看那些经典书 像 算法导论 算法 这些比较经
  • 以太坊系列之十五: 以太坊数据库

    以太坊数据库中都存了什么 以太坊使用的数据库是一个NOSQL数据库 是谷歌提供的开源数据leveldb 这里尝试通过分析以太坊数据库存储了什么来分析以太坊可能为我们提供哪些关于区块链的API 存储内容 NOSQL是一个key value数据
  • UE4命令行使用,解释

    命令行在外部 从命令行运行编辑项目 1 导航到您的 LauncherInstall VersionNumber Engine Binaries Win64 目录中 2 右键单击上 UE4Editor exe 的可执行文件 并选择创建快捷方式
  • Linux 内核中的 Device Mapper 机制

    Linux 内核中的 Device Mapper 机制 尹 洋 在读博士生 尹洋 中科院计算所国家高性能计算机工程技术研究中心的在读博士生 主要从事服务部署和存储资源管理以及Linux块设备一级的开发和研究工作 简介 本文结合具体代码对 L
  • 时间复杂度+常见复杂度解释

    前言 算法的效率 虽然计算机能快速的完成运算处理 但实际上 它也需要根据输入数据的大小和算法效率来消耗一定的处理器资源 要想编写出能高效运行的程序 我们就需要考虑到算法的效率 算法的效率主要由以下两个复杂度来评估 时间复杂度 评估执行程序所
  • 二叉树结构的建立与遍历

    实验项目 1 编写建立二叉树的二叉链表存储结构 左右链表示 的程序 并以适当的形式显示和保存二叉树 2 完成二叉树的7种遍历操作 3 给定一个二叉树 编写算法完成下列应用 1 判断其是否为完全二叉树 2 求二叉树中任意两个结点的公共祖先 输
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 基数排序代码实现

    详情请看排序总结 传送门 https blog csdn net m0 52711790 article details 121914543 基数排序的知识点我就不贴出来 相信都能搜到对应概念解释 下面就直接上代码 代码解释其实也很清晰了
  • 无法导入 numpy:错误:/usr/lib/liblapack.so.3:未定义符号:gotoblas

    当我尝试导入 numpy 时 出现以下错误 usr local lib python2 7 dist packages numpy linalg init py in
  • Leetcode1094. 拼车

    Every day a Leetcode 题目来源 1094 拼车 解法1 差分数组 对于本题 设 a i 表示车行驶到位置 i 时车上的人数 我们需要判断是否所有 a i 都不超过 capacity trips i 相当于把 a 中下标从
  • 数组实现循环队列(增设队列大小size)

    目录 一 前言 1 如何实现循环 2 如何判断队列为空 3 如何判断队列为满 二 循环队列的结构定义 三 循环队列的创建及其初始化 四 入队 五 出队 六 取队头元素 七 取队尾元素 八 循环队列判空 九 循环队列判满 十 循环队列销毁 一
  • gem5 系统调用模拟 OpenBLAS cblas_dgemm 失败并显示“致命:系统调用 mbind (#237) 未实现”

    我正在开发一个程序 我需要在 SE 模式下模拟使用 gem5 调用 OpenBLAS 函数的程序 我的代码 C语言 如下 include
  • 在 Windows 上使用 OpenBLAS 安装 numpy 的教程

    拜托 我这里确实需要一盏灯 我想使用良好的 BLAS LAPACK 库安装 numpy在 Windows 上 但绝对没有页面足够好地解释该过程 看来 OpenBLAS 是一个又好又快的选择 目标是将 theano 与 keras 一起使用

随机推荐

  • 调用高德逆地理接口_地理编码与逆地理编码

    本章主要介绍如何将地址描述信息和地理坐标做相互转化 主要包括以内容 正向地理编码 逆向地理编码 地理编码服务 地理编码包含正向地理编码和逆向地理编码两种 正向地理编码 将地址描述信息转换成地理坐标 经纬度 对应为AMap Geocoder的
  • 242. Valid Anagram

    class Solution public bool isAnagram string s string t 使用sort排序 sort s begin s end sort t begin t end if s t return true
  • restful api 与 GraphQL 分析比较

    背景 REST作为一种现代网络应用非常流行的软件架构风格 自从Roy Fielding博士在2000年他的博士论文中提出来到现在已经有了20年的历史 它的简单易用性 可扩展性 伸缩性受到广大Web开发者的喜爱 REST 的 API 配合JS
  • 说一说PCIe5.0的速率和带宽

    最近 有一个并不肤浅的同事问了我一个问题 U 2的带宽是多少 为什么有人说U 2最大是32GB s 首先 从PCIe5 0 CEM规范里我们查到 对于一条lane来说 PCIe5 0 的Basic bandwidth为32 0 GT s 这
  • Thread协议介绍

    Thread 由三星 Nest ARM Big Ass Fans 飞思卡尔和Silicon Labs公司联合推出 是一种基于IP的无线网络协议 用来连接家里的智能产品 比较常用的网络协议有 WiFi 蓝牙 ZigBee Z Wave 不过都
  • 钱包应用

    使用LightWallet和Hooked Web3 Provider创建钱包服务 1 运行geth实例挖矿并启动HTTP RPC服务器 允许来自任何域名客户端请求 解锁账户0 geth dev rpc rpccorsdomain rpcad
  • fvf采用另外一种方式渲染

    if FAILED hr getActiveD3D9Device gt SetVertexDeclaration d3ddecl gt getD3DVertexDeclaration getGlobalInstanceVertexBuffe
  • qt输出到控制台

    include
  • Node.js开发——解决Cesium视角切换的异常

    最近在利用Cesium做开发时 版本是v25 发现一个bug 在它的SandCastle中的任何一个例子 如果用的是Chrome浏览器 在2D视图和2 5D视图之间多次切换 会报一个错 换成firefox浏览器就没问题 An error o
  • 区块链之Solidity类型

    Solidity语言 IDE https remix ethereum org 合约文件结构 版本申明 import 合约 状态变量 函数 结构类型 事件 函数修改器 代码注释 结构举例 表示从0 4 0版本到0 5 0版本 pragma
  • Qt 编程点滴4

    编译win32 中的 dll工程配置方法 以skypebackend为例 因为工程中的代码全是标准C 的代码 所以编译方式跟Qt有点不一样 Project properties Project settings页中的 This is a c
  • 解决java.net.SocketException: Invalid argument or cannot assign requested address

    今天发现facebook app读取facebook上的api时发生以下错误 java net SocketException Invalid argument or cannot assign requested address 解法 l
  • helm下

    讲师 李振良 官方网站 http www ctnrs com 第三章 Helm应用包管理器 下 说明 强烈建议学习课堂视频 更多细节都在里面 本文档为内部学员资料 请不要随意转发 3 6 Chart模板 Helm最核心的就是模板 即模板化的
  • xci转nsp工具_再谈xci、nsz、nsp

    每次群里有人问到进相册的homebrew为什么装不了补丁 或者说刚拉进去的文件为什么读取不到 老白之前推荐的aw 适用大气层 后期有改版aw适用TX tinleaf 适用于TX aw和tinleaf可以直接安装xci nsp nsz 安装n
  • 【爬虫】selenium+webdrive抓取淘宝商品评价

    爬虫 selenium webdrive抓取淘宝商品评价 爬虫小白入门 声明 本人只是处于突如其来的兴趣学习一点点 水平实在不高 但在这个过程中也或多或少地解决了一些问题 所以对同为小白的朋友们或许有用 但还请大神们不要笑我 动手前必备的知
  • DispatcherServlet工作原理简介说明

    转自 DispatcherServlet工作原理简介说明 下文笔者将讲述DispatcherServlet的工作流程 如下所示 当DispatcherServlet接到请求时 他先回查找适当的处理程序来处理请求 DispatcherServ
  • C语言中signal函数简介及使用

    signal h是C标准函数库中的信号处理部分 定义了程序执行时如何处理不同的信号 信号用作进程间通信 报告异常行为 如除零 用户的一些按键组合 如同时按下Ctrl与C键 产生信号SIGINT C 中的对应头文件是csignal C语言标准
  • Jenkins Android项目编译配置(完整版)

    Jenkins编译项目配置 环境要求 Jenkins准备 安装 启动 初始化 全局配置 全局工具 Global Tool Configuration 凭据 项目示例 General 源码管理 构建触发器 构建环境 构建 构建后操作 需要的插
  • C++ 函数覆盖

    C 函数覆盖 在派生类和基类中都定义了相同的函数 如果使用派生类的对象调用这个函数 派生类的函数就会被执行 这在 C 中称为函数覆盖 派生类中的函数覆盖基类中的函数 示例 1 C 函数覆盖 include
  • cblas_sgemm和cublasSgemm参数详解

    机器学习最核心的底层运算肯定是矩阵乘法无疑了 为了让矩阵乘法执行更快 大家也是绞尽脑汁 从算法层面 stranssen算法将矩阵乘法复杂度由 O n 3 O n 3 O n3 降