Files
2026-07-13 13:33:03 +08:00

161 lines
4.7 KiB
C++

#ifdef MNN_KLEIDIAI_ENABLED
#include <functional>
#include <numeric>
#include <random>
#include "MNNTestSuite.h"
#include "backend/cpu/kleidiai/KleidiAIDenseConvolution.hpp"
using namespace MNN;
namespace utils {
enum class FillType { RANDOM, ZERO };
class RandomEngine {
public:
static std::mt19937& get() {
static std::random_device device;
static std::mt19937 gen(device());
return gen;
}
};
template <typename T>
struct RandomGenerator;
template <>
struct RandomGenerator<float> {
static float generate() {
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
return dist(RandomEngine::get());
}
};
template <>
struct RandomGenerator<int> {
static int generate() {
std::uniform_int_distribution<int> dist(0, 100);
return dist(RandomEngine::get());
}
};
} // namespace utils
class LhsPackingTest : public MNNTestCase {
public:
virtual bool run(int precision) {
return testIndirectionTable1() && testIndirectionTable2() && testWeightConversion();
}
private:
bool testIndirectionTable(const ConvParams& params, int batchSize, int inputHeight, int inputWidth) {
auto outputSize = params.getOutputSize(inputHeight, inputWidth);
int outputHeight = outputSize.height;
int outputWidth = outputSize.width;
std::vector<int> inputShape = {batchSize, inputHeight, inputWidth, params.inputChannel};
std::vector<float> input(std::accumulate(inputShape.begin(), inputShape.end(), 1, std::multiplies<int>()));
std::vector<float> padValues(params.inputChannel);
int blockSize = 32;
auto table = IndirectionTable<float>(inputShape, params, input.data(), padValues.data(), blockSize);
bool succ = true;
// Check the first row
for (int col = 0; col < blockSize; col++) {
int oh = col / outputWidth;
int ow = col % outputWidth;
int ih = oh * params.strideHeight - params.padTop;
int iw = ow * params.strideWidth - params.padLeft;
if (ih < 0 || ih >= inputHeight) {
succ &= (table.data[col] == padValues.data());
} else if (iw < 0 || iw >= inputWidth) {
succ &= (table.data[col] == padValues.data());
} else {
int offset = (ih * inputWidth + iw) * params.inputChannel;
succ &= (table.data[col] == input.data() + offset);
}
}
return succ;
}
bool testIndirectionTable1() {
ConvParams params{
.inputChannel = 3,
.outputChannel = 5,
.kernelHeight = 3,
.kernelWidth = 2,
.strideHeight = 2,
.strideWidth = 1,
.padTop = 1,
.padBottom = 3,
.padLeft = 2,
.padRight = 1,
.dilatedHeight = 1,
.dilatedWidth = 2,
};
int batchSize = 4;
int inputHeight = 7;
int inputWidth = 5;
return testIndirectionTable(params, batchSize, inputHeight, inputWidth);
}
bool testIndirectionTable2() {
ConvParams params{
.inputChannel = 256,
.outputChannel = 256,
.kernelHeight = 3,
.kernelWidth = 3,
.strideHeight = 1,
.strideWidth = 1,
.padTop = 1,
.padBottom = 1,
.padLeft = 1,
.padRight = 1,
.dilatedHeight = 1,
.dilatedWidth = 1,
};
int batchSize = 1;
int inputHeight = 24;
int inputWidth = 24;
return testIndirectionTable(params, batchSize, inputHeight, inputWidth);
}
bool testWeightConversion() {
std::vector<int> shape = {4, 5, 6, 7};
int size = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<int>());
std::vector<float> weightSrc(size);
std::vector<float> weightDst(size);
for (int i = 0; i < size; i++) {
weightSrc[i] = i;
}
ConvertOIHWToHWIO(weightDst.data(), weightSrc.data(), shape);
bool succ = true;
for (int oc = 0; oc < 4; oc++) {
for (int ic = 0; ic < 5; ic++) {
for (int h = 0; h < 6; h++) {
for (int w = 0; w < 7; w++) {
int oo = (h * 7 + w) * 5 * 4 + ic * 4 + oc;
int io = oc * 5 * 6 * 7 + ic * 6 * 7 + h * 7 + w;
succ &= (weightSrc[io] == weightDst[oo]);
}
}
}
}
return true;
}
};
MNNTestSuiteRegister(LhsPackingTest, "imatmul/lhs");
#endif