智算服务器SGM7-40,适配主流LLM,单卡可运行70B的大语言模型
SOM1684,搭载算能BM1684,支持16路高清视频分析
Core-1684-JD4,搭载算能BM1684,支持16路高清视频分析
SBC-6841,搭载算能BM1684,支持16路高清视频分析
iCore-1684XQ,搭载算能BM1684X,支持32路高清视频分析
Core-1684XJD4,搭载算能BM1684X,支持32路高清视频分析
Shaolin PI SLKY01,搭载算能BM1684,支持16路高清视频分析
QY-AIM16T-M,搭载算能BM1684,支持16路高清视频分析
QY-AIM16T-M-G,搭载算能BM1684,支持16路高清视频分析
QY-AIM16T-W,搭载算能BM1684,支持16路高清视频分析
AIV02T,PCIE板卡,1684*2,半高半长
IVP03X,搭载算能BM1684X,支持32路高清视频分析
IVP03A,微服务器 被动散热,12GB内存
Coeus-3550T,搭载算能BM1684,支持16路高清视频分析
EC-1684JD4,搭载算能BM1684,支持16路高清视频分析
CSA1-N8S1684,算力集群服务器,BM1684*8,1U
DZFT-ZDFX,ARM+DSP智能封条分析,搭载算能BM1684X
ZNFX-32,搭载算能BM1684,支持16路高清视频分析
ZNFX-8,ARM+DSP架构,隔爆兼本安分析装置符合煤安要求,搭载BM1684X
EC-A1684JD4,微服务器主动散热,16GB内存,32GB eMMC
EC-A1684JD4 FD,搭载算能BM1684,支持16路高清视频分析,16GB内存,32GB eMMC
EC-A1684XJD4 FD,搭载算能BM1684X,支持32路高清视频分析
ECE-S01,搭载算能BM1684,支持16路高清视频分析
IOEHM-AIRC01,微服务器,主动散热,搭载算能BM1684,支持16路高清视频分析
IOEHM-VCAE01,搭载算能BM1684,支持16路高清视频分析
CSA1-N8S1684X,算力集群服务器,BM1684X*8,1U
QY-S1U-16,1U版本BM1684盒子
QY-S1U-192,算力集群服务器,BM1684*12,1U
QY-S1X-384,算力集群服务器,BM1684X*12,1U
视频实时压缩转码上云和监测异常事件,增强道路运行安全事件的发现和处置能力
为交通拥堵、行车安全、车辆违法和道路污染治理问题赋能
以国产化算力支撑海量视频的结构化解析,服务警务应用实战
以数据为中心打造“智能、协同、高效、创新”的步态识别大数据分析系统
为用户快速构建融合人、车、通行等多维数据的业务能力
对生产全过程、全方位实时感知与精细化监管,推进应急监测智能化,赋能风险识别预警
为粮仓、棉仓等大型仓储园区的办公、质检、磅房、库区等区域提供了违规行为和异常事件的安全监控方案
全量场景感知预警,赋能烟草生产作业过程数智化
为白酒生产企业细化风险监测因素,建立智能感知与预警感知体系,提高企业安全生产管理水平
以云边协同的新型算力基础设施赋能各类数字城市场景,为数字经济发展提供源动力
以自动化训练推理一体化平台为基础,助力算力/算法整合应用快速、高效工程化落地
typedef struct {
int left_rows, left_cols, right_cols; //左矩阵行,左矩阵列,右矩阵列
unsigned long long output_addr; //输出矩阵地址
unsigned long long left_addr; //左矩阵地址
unsigned long long right_addr; //右矩阵地址
} __attribute__((packed)) param_t;
param_t params[] = {
{.left_rows = 2, .left_cols = 100352, .right_cols = 2048 }, // 0
{.left_rows = 2, .left_cols = 1280, .right_cols = 1000 }, // 1
{.left_rows = 2, .left_cols = 25088, .right_cols = 4096 }, // 2
{.left_rows = 4, .left_cols = 1024, .right_cols = 25088}, // 3
{.left_rows = 32, .left_cols = 2048, .right_cols = 36 }, // 4
{.left_rows = 64, .left_cols = 9216, .right_cols = 4096 }, // 5
{.left_rows = 79, .left_cols = 256, .right_cols = 4090 }, // 6
{.left_rows = 200, .left_cols = 4096, .right_cols = 324 }, // 7
{.left_rows = 256, .left_cols = 768, .right_cols = 3072 }, // 8
{.left_rows = 256, .left_cols = 3072, .right_cols = 768 }, // 9
{.left_rows = 300, .left_cols = 2048, .right_cols = 80 }, // 10
{.left_rows = 1024, .left_cols = 1024, .right_cols = 1024 }, // 11
{.left_rows = 2048, .left_cols = 4, .right_cols = 1024 }, // 12
{.left_rows = 12544, .left_cols = 2, .right_cols = 1024 }, // 13
{.left_rows = 100352, .left_cols = 1024, .right_cols = 1 }, // 14
};
关于矩阵在local memory中的存储方式,与tensor的存储方式稍有不同,详见算丰文档。在编程时需要注意的是合理分配每个TPU上的数据大小,来尽可能多的利用TPU的算力。
如果左矩阵、右矩阵以及结果矩阵能够同时存放到local memory中,那么所作的事情就比较清晰了:搬入左右矩阵->计算结果->搬出结果矩阵。伪代码如下:
local_addr_t left_addr, right_addr, output_addr;
param_t* param;
matrix_S2L(left_addr, param->left_addr);
matrix_S2L(local_right_addr, param->lright_addr);
okk_bdc_matmul(output_addr, left_addr, right_addr);
matrix_L2S(param->output_addr, output_addr);
所给测试用例中的大部分用例都无法直接存入local memory中,因此,需要利用分块矩阵乘法,对矩阵进行切分。
这里提供三种切分的思路。
如图,当左矩阵较大,而右矩阵较小时,可以考虑按左矩阵的行来进行切分,例如测试用例中的用例14。这样的情况下,可以固定右矩阵,循环搬入左矩阵的待计算部分以及搬出部分输出矩阵。
local_addr_t left_addr, right_addr, output_addr;
param_t* param;
matrix_S2L(right_addr, param->right_addr);
for(int i;i<blocks;i++)
{
matrix_S2L(left_addr, param->left_addr + left_skip_bytes);
okk_bdc_matmul(output_addr, left_addr, right_addr);
matrix_L2S(param->output_addr + output_skip_bytes, output_addr);
}
其中需要注意左矩阵的最后一块,因为左矩阵的行数并不能总是被块数整除,因此最后一个块的大小和之前块的大小会有不同。
同样的,当右矩阵较大,而左矩阵较小时,可以考虑按右矩阵的列进行切分,例如测试用例中的用例4。我们可以固定左矩阵不动,循环搬入右矩阵进行计算,并搬出输出矩阵。
local_addr_t left_addr, right_addr, output_addr;
param_t* param;
matrix_S2L(left_addr, param->left_addr);
for(int i;i<blocks;i++)
{
matrix_S2L(right_addr, param->right_addr + right_skip_bytes, right_cols_in_memory); //right_cols_in_memory控制搬运时内存每行有多少列,这样在搬运一部分的时候会跳过该行而不是只跳过已搬运的元素
okk_bdc_matmul(output_addr, left_addr, right_addr);
matrix_L2S(param->output_addr + output_skip_bytes, output_addr, right_cols_in_memory);
}
这里需要注意的是,矩阵在内存中是按行存储,因此在按左矩阵切分时,可以简单搬运数行,但是在按右矩阵列进行切分时,会有不连续的问题,因此需要在搬入矩阵时,设置在内存中矩阵的列数,以此来仅选取当前块的数据。
此外,还有一种情况,如测试用例中的用例0,由于左矩阵的列以及右矩阵的行都比较大,导致单一矩阵都无法存入TPU,因此需要对左矩阵的列进行切分。对不同部分的运算结果进行累加,并搬运最终的输出矩阵。
local_addr_t left_addr, right_addr, output_addr;
param_t* param;
okk_bdc_set_C(output_addr, 0.0); //将输出矩阵置0,累加初始化
for(int i=0; i<blocks; i++)
{
matrix_S2L(left_addr, param->left_addr + left_skip_bytes);
matrix_S2L(right_addr, param->right_addr + right_skip_bytes);
okk_bdc_matmul(output_addr, left_addr, right_addr, result_add=True); //通过result_add控制是否将结果累加到输出地址上
}
matrix_L2S(para->output_addr, output_addr);
matmul部分没有比较好的特例优化方式,可能主要是控制col_per_NPU这样的参数,来达到尽可能多的利用算力的目的。
通过以上的几张方法,基本能够通过所提供的测试用例。如果遇到更大的矩阵,可以考虑通过行列都切分的方式进行计算。