最近在用 C 手写模型推理, 其中 gemm 可以说是核心计算, 于是决定以学习为目的自己尝试优化一下.
用 3 个 for 循环可以实现最基本的矩阵乘法, 在我用 simd, blocking, 并行计算这些方法之后, 速度比 naive 版本的快了很多, 但还是会比 openblas 慢不少. 接下来该怎么做有点没头绪了. 我想知道有没有办法能进一步提升? 谢谢
1
nagisaushio 10 小时 5 分钟前
函数签名改成这样试试
void matmul(const float * restrict A, const float * restrict B, float * restrict C, const int M, const int N, const int K) |
2
elfive 9 小时 39 分钟前 via iPhone
如果是 intel 平台,可以考虑使用 Intel Intrinsics Library ,会比 OpenBLAS 快不少。
|
3
elfive 9 小时 34 分钟前 via iPhone
@elfive 另外还有个 intel MKL 库可以用,这个库有办法在 AMD 平台加速,具体方法可以参考这个博客: https://monsoon-cs.moe/2023-06-19-mkl-on-amd/
|
4
AirCrusher 9 小时 24 分钟前
可以看下这个 repo ,循序渐进:
https://github.com/yzhaiustc/Optimizing-DGEMM-on-Intel-CPUs-with-AVX512F |
6
Avafly OP @nagisaushio 这个确实有一些帮助, 不过只能提升一点点大概 0.1GFLOPS 吧, 还是和 openblas, blis 这些有断档的差距. 感觉更多还是算法设计方面的问题, 这部分不知道该怎么做了.
|
7
Avafly OP @AirCrusher 谢谢分享, 这个有点猛汇编都用上了, 我回头看下. 其实后面我看过类似的就是 flame 的教程, 基本上里面的技术都应用到了已经.
|
8
Donaldo 8 小时 50 分钟前
歪个楼,请问你 README 的矩阵图是用什么画的?
|
11
WonderfulRush 7 小时 35 分钟前
可以看看这篇文章 里面讲了 cpu 矩阵乘的优化 https://justine.lol/matmul/
|
12
Avafly OP |
13
toma62299781 6 小时 15 分钟前
你这个刚好就是 MIT 韩松老师开的 MIT 6.5940 Efficient AI 课程的 lab5 哇,可以去参考一下:
课程主页: https://hanlab.mit.edu/courses/2024-fall-65940 lab5: https://drive.google.com/drive/folders/1MhMvxvLsyYrN-4C6eQG8Zj2JeSuyAOf0 |
14
tankeco 6 小时 10 分钟前
我感觉你取 index 就做了不少乘法,不确定编译器能不能帮你优化掉,你自己把 index 改成累加的方式试试
|
15
Avafly OP @toma62299781
感谢分享 |
16
Avafly OP @tankeco
是的, 这点我也觉得要花时间想下怎么减少 index. 其实已经优化过一次 index 了, 现在保留的都是为了分块和区分多线程访问空间的, 后面个人感觉这不是影响速度的最大的因素就没继续花心思了. |
17
dingyaguang117 5 小时 15 分钟前
因为人家复杂度就不是 O(N^3) ...
|
18
foool 5 小时 14 分钟前
对比 openblas 中 cblas_sgemm 也是 4 并行度的吗?
|
19
foool 5 小时 7 分钟前
几个小建议和疑问:
1 先大致理论分析下最大能够达到的 GFLOS 是多少(考虑 CPU 多 port 都可以执行运算); 2 先用单线程跑到最高速率,排除多线程调度或资源竞争导致的劣化; 3 尝试加上预取指令,perf 看看瓶颈在哪里 4 测试多次,取最优值,看你测试了一次,都会有“冷启动”的问题。 5 omp parallel for schedule(static) 是在编译时就确定代码位于哪个线程了吗,会导致 cache 相关问题吗( false sharing ) |
20
dazhangpan 5 小时 0 分钟前
使用 AMX 指令
|
21
Avafly OP @foool #19
非常感谢你的回复. 1. 最大 GFLOPS 这个我没算, 是以 openblas 的为目标优化的 (试过别的库, 有比 openblas 更快的). 2. 3. 很好的建议, 我回头再优化测试看看. 4. 我是脚本跑 100 次取最优值的. 5. 使用 schedule(static)是因为 for 循环中每次计算量近似才用的, 不过我试过去掉这个, 其实性能基本没区别. |
22
Avafly OP @dingyaguang117
你是说它们不是传统的 C=AB, 而是用了 Strassen/Winograd 之类的方法减少了复杂度吗? |