华为计算微信公众号
昇腾AI开发者公众号
华为计算微博
华为计算今日头条
测试用例是m*k的全1矩阵和k*n的全0矩阵相乘,最后得到的应该是m*n的全k矩阵,但是测试结果一直是随机数,求助有人可以给一个正确的测试代码吗
// ---- 矩阵尺寸(满足 MMAD 粒度)---- const int M = 16, N = 16, K = 32; // ---- 对齐工具 ---- auto align32 = [](uint32_t &x){ x = (x + 31u) & ~31u; }; auto align512 = [](uint32_t &x){ x = (x + 511u) & ~511u; }; // ---- 申请一小块 UB 只用于回读打印 ---- AscendC::LocalTensor<uint8_t> ub_mem; bool ok_ub = AscendC::PopStackBuffer<uint8_t, AscendC::TPosition::VECCALC>(ub_mem); if (!ok_ub) { AscendC::printf("PopStackBuffer UB failed\n"); return; } uint32_t off_ub = 0; AscendC::LocalTensor<float> C_ub; align32(off_ub); C_ub.SetAddrWithOffset(ub_mem, off_ub); C_ub.SetSize((uint32_t)(M * N * (int)sizeof(float))); off_ub += C_ub.GetSize(); // ---- 在 A2/B2/CO1 位面申请矩阵核缓冲 ---- AscendC::TBuf<AscendC::TPosition::A2> bufA2; AscendC::TBuf<AscendC::TPosition::B2> bufB2; AscendC::TBuf<AscendC::TPosition::CO1> bufCO1; uint32_t sizeA2 = (uint32_t)(M * K * (int)sizeof(half)); align512(sizeA2); uint32_t sizeB2 = (uint32_t)(K * N * (int)sizeof(half)); align512(sizeB2); uint32_t sizeC1 = (uint32_t)(M * N * (int)sizeof(float)); align512(sizeC1); pipe.InitBuffer(bufA2, sizeA2); pipe.InitBuffer(bufB2, sizeB2); pipe.InitBuffer(bufCO1, sizeC1); AscendC::LocalTensor<half> A2 = bufA2.Get<half>(); AscendC::LocalTensor<half> B2 = bufB2.Get<half>(); AscendC::LocalTensor<float> C1 = bufCO1.Get<float>(); A2.SetSize((uint32_t)(M * K * (int)sizeof(half))); B2.SetSize((uint32_t)(K * N * (int)sizeof(half))); C1.SetSize((uint32_t)(M * N * (int)sizeof(float))); // ---- 关键:直接在分形位面“批量填充”常数 ---- // 常数阵在任何布局下等价于逻辑全 1,因此可避开 LoadData2D 的复杂度 AscendC::Duplicate(A2, (half)1.0f, (uint32_t)(M * K)); AscendC::Duplicate(B2, (half)1.0f, (uint32_t)(K * N)); AscendC::Duplicate(C1, 0.0f, (uint32_t)(M * N)); // 累加前清零 // (可选)确保向量填充都已完成 AscendC::PipeBarrier<PIPE_V>(); // ---- 关闭 HF32(void 接口)---- AscendC::SetHF32Mode(false); AscendC::SetHF32TransMode(false); // ---- MMAD:FP16×FP16 -> FP32 ---- AscendC::MmadParams p{}; p.m = (uint32_t)M; p.n = (uint32_t)N; p.k = (uint32_t)K; AscendC::Mmad(C1, A2, B2, p); // 让矩阵核计算落地 AscendC::PipeBarrier<PIPE_V>(); // 若你环境有 PIPE_M,可再加一条 PipeBarrier<PIPE_M>(); // ---- 回 UB 打印 ---- AscendC::DataCopy(C_ub, C1, (uint32_t)(M * N)); AscendC::printf("\n[MMAD ones] expect each elem = %f\n", (float)K); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) AscendC::printf("%f ", C_ub.GetValue(i * N + j)); AscendC::printf("\n"); } float sum0 = 0.0f; for (int t = 0; t < M * N; ++t) sum0 += C_ub.GetValue(t); AscendC::printf("[Sanity sum] %f\n", sum0);
我要发帖子
测试用例是m*k的全1矩阵和k*n的全0矩阵相乘,最后得到的应该是m*n的全k矩阵,但是测试结果一直是随机数,求助有人可以给一个正确的测试代码吗
// ---- 矩阵尺寸(满足 MMAD 粒度)---- const int M = 16, N = 16, K = 32; // ---- 对齐工具 ---- auto align32 = [](uint32_t &x){ x = (x + 31u) & ~31u; }; auto align512 = [](uint32_t &x){ x = (x + 511u) & ~511u; }; // ---- 申请一小块 UB 只用于回读打印 ---- AscendC::LocalTensor<uint8_t> ub_mem; bool ok_ub = AscendC::PopStackBuffer<uint8_t, AscendC::TPosition::VECCALC>(ub_mem); if (!ok_ub) { AscendC::printf("PopStackBuffer UB failed\n"); return; } uint32_t off_ub = 0; AscendC::LocalTensor<float> C_ub; align32(off_ub); C_ub.SetAddrWithOffset(ub_mem, off_ub); C_ub.SetSize((uint32_t)(M * N * (int)sizeof(float))); off_ub += C_ub.GetSize(); // ---- 在 A2/B2/CO1 位面申请矩阵核缓冲 ---- AscendC::TBuf<AscendC::TPosition::A2> bufA2; AscendC::TBuf<AscendC::TPosition::B2> bufB2; AscendC::TBuf<AscendC::TPosition::CO1> bufCO1; uint32_t sizeA2 = (uint32_t)(M * K * (int)sizeof(half)); align512(sizeA2); uint32_t sizeB2 = (uint32_t)(K * N * (int)sizeof(half)); align512(sizeB2); uint32_t sizeC1 = (uint32_t)(M * N * (int)sizeof(float)); align512(sizeC1); pipe.InitBuffer(bufA2, sizeA2); pipe.InitBuffer(bufB2, sizeB2); pipe.InitBuffer(bufCO1, sizeC1); AscendC::LocalTensor<half> A2 = bufA2.Get<half>(); AscendC::LocalTensor<half> B2 = bufB2.Get<half>(); AscendC::LocalTensor<float> C1 = bufCO1.Get<float>(); A2.SetSize((uint32_t)(M * K * (int)sizeof(half))); B2.SetSize((uint32_t)(K * N * (int)sizeof(half))); C1.SetSize((uint32_t)(M * N * (int)sizeof(float))); // ---- 关键:直接在分形位面“批量填充”常数 ---- // 常数阵在任何布局下等价于逻辑全 1,因此可避开 LoadData2D 的复杂度 AscendC::Duplicate(A2, (half)1.0f, (uint32_t)(M * K)); AscendC::Duplicate(B2, (half)1.0f, (uint32_t)(K * N)); AscendC::Duplicate(C1, 0.0f, (uint32_t)(M * N)); // 累加前清零 // (可选)确保向量填充都已完成 AscendC::PipeBarrier<PIPE_V>(); // ---- 关闭 HF32(void 接口)---- AscendC::SetHF32Mode(false); AscendC::SetHF32TransMode(false); // ---- MMAD:FP16×FP16 -> FP32 ---- AscendC::MmadParams p{}; p.m = (uint32_t)M; p.n = (uint32_t)N; p.k = (uint32_t)K; AscendC::Mmad(C1, A2, B2, p); // 让矩阵核计算落地 AscendC::PipeBarrier<PIPE_V>(); // 若你环境有 PIPE_M,可再加一条 PipeBarrier<PIPE_M>(); // ---- 回 UB 打印 ---- AscendC::DataCopy(C_ub, C1, (uint32_t)(M * N)); AscendC::printf("\n[MMAD ones] expect each elem = %f\n", (float)K); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) AscendC::printf("%f ", C_ub.GetValue(i * N + j)); AscendC::printf("\n"); } float sum0 = 0.0f; for (int t = 0; t < M * N; ++t) sum0 += C_ub.GetValue(t); AscendC::printf("[Sanity sum] %f\n", sum0);