blob: 117d49da560ad2ee9912185cee1168de2571cd22 [file] [log] [blame]
// Copyright (c) 2023-2024, ARM Limited.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "generate_dot_product.h"
#include "half.hpp"
namespace
{
//---------------------------------------------------------------------------//
// MatMul //
//---------------------------------------------------------------------------//
template <typename DataType>
void generateMatMulA(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const uint32_t T = cfg.shape[0] * cfg.shape[1] * cfg.shape[2];
const uint32_t C = cfg.shape[2];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(t % C)); // k = c
}
}
template <typename DataType>
void generateMatMulB(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const uint32_t T = cfg.shape[0] * cfg.shape[1] * cfg.shape[2];
const uint32_t C = cfg.shape[1];
const uint32_t W = cfg.shape[2];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator((t / W) % C)); // k = c
}
}
bool generateMatMul(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
if (cfg.shape.size() != 3)
{
WARNING("[Generator][DP][MatMul] Tensor shape expected 3 dimensions.");
return false;
}
if (cfg.inputPos > 1 || cfg.inputPos < 0)
{
WARNING("[Generator][DP][MatMul] Invalid input tensor slot position to operator.");
return false;
}
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
(cfg.inputPos == 0) ? generateMatMulA(cfg, generator, outData, size)
: generateMatMulB(cfg, generator, outData, size);
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
(cfg.inputPos == 0) ? generateMatMulA(cfg, generator, outData, size)
: generateMatMulB(cfg, generator, outData, size);
break;
}
default:
WARNING("[Generator][DP][MatMul] Only supports FP32 or FP16.");
return false;
}
return true;
}
//---------------------------------------------------------------------------//
// Conv2D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateConv2DInput(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.dotProductInfo.kernel.size() != 2 || cfg.dotProductInfo.kernel[0] <= 0 || cfg.dotProductInfo.kernel[1] <= 0)
{
WARNING("[Generator][DP][Conv2D][Input] Missing or incorrect kernel size information.");
return false;
}
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][Conv2D][Input] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IH = cfg.shape[1];
const uint32_t IW = cfg.shape[2];
const uint32_t IC = cfg.shape[3];
const uint32_t KH = cfg.dotProductInfo.kernel[0];
const uint32_t KW = cfg.dotProductInfo.kernel[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t ix = (t / IC) % IW;
uint32_t iy = ((t / IC) / IW) % IH;
uint32_t k = ((iy % KH) * KW + (ix % KW)) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateConv2DWeight(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][Conv2D][Weight] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t KH = cfg.shape[1];
const uint32_t KW = cfg.shape[2];
const uint32_t IC = cfg.shape[3];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t kx = (t / IC) % KW;
uint32_t ky = ((t / IC) / KW) % KH;
uint32_t k = (ky * KW + kx) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateConv2DBias(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 1)
{
WARNING("[Generator][DP][Conv2D][Bias] Tensor shape expected 1 dimension.");
return false;
}
const uint32_t T = cfg.shape[0];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(2));
}
return true;
}
bool generateConv2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateConv2DInput(cfg, generator, outData, size);
case 1:
return generateConv2DWeight(cfg, generator, outData, size);
case 2:
return generateConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][Conv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
switch (cfg.inputPos)
{
case 0:
return generateConv2DInput(cfg, generator, outData, size);
case 1:
return generateConv2DWeight(cfg, generator, outData, size);
case 2:
return generateConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][Conv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][Conv2D] Only supports FP32 or FP16.");
return false;
}
}
//---------------------------------------------------------------------------//
// Reduce Sum //
//---------------------------------------------------------------------------//
template <typename DataType>
void generateReduceSumData(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t axis = cfg.dotProductInfo.axis;
for (int64_t t = 0; t < T; ++t)
{
uint64_t k = t;
for (uint32_t d = cfg.shape.size() - 1; d > axis; --d)
{
k = k / cfg.shape[d];
}
k = k % cfg.shape[axis];
data[t] = static_cast<DataType>(generator(static_cast<int32_t>(k)));
}
}
bool generateReduceSum(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
if (cfg.inputPos != 0)
{
WARNING("[Generator][DP][ReduceSum] Invalid input tensor slot position to operator.");
return false;
}
if (cfg.dotProductInfo.axis < 0 || static_cast<size_t>(cfg.dotProductInfo.axis) >= cfg.shape.size())
{
WARNING("[Generator][DP][ReduceSum] Invalid axis %d.", cfg.dotProductInfo.axis);
return false;
}
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
generateReduceSumData(cfg, generator, outData, size);
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
generateReduceSumData(cfg, generator, outData, size);
break;
}
default:
WARNING("[Generator][DP][ReduceSum] Only supports FP32 or FP16.");
return false;
}
return true;
}
//---------------------------------------------------------------------------//
// Fully Connected //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateFullyConnectedInput(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 2)
{
WARNING("[Generator][DP][FullyConnected][Input] Tensor shape expected 2 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IC = cfg.shape[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t k = t % IC;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateFullyConnectedWeight(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 2)
{
WARNING("[Generator][DP][FullyConnected][Weight] Tensor shape expected 2 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IC = cfg.shape[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t k = t % IC;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateFullyConnectedBias(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 1)
{
WARNING("[Generator][DP][FullyConnected][Bias] Tensor shape expected 1 dimension.");
return false;
}
const uint32_t T = cfg.shape[0];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(2));
}
return true;
}
bool generateFullyConnected(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateFullyConnectedInput(cfg, generator, outData, size);
case 1:
return generateFullyConnectedWeight(cfg, generator, outData, size);
case 2:
return generateFullyConnectedBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][FullyConnected] Invalid input tensor slot position to operator.");
return false;
}
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
switch (cfg.inputPos)
{
case 0:
return generateFullyConnectedInput(cfg, generator, outData, size);
case 1:
return generateFullyConnectedWeight(cfg, generator, outData, size);
case 2:
return generateFullyConnectedBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][FullyConnected] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][FullyConnected] Only supports FP32 or FP16.");
return false;
}
}
//---------------------------------------------------------------------------//
// Avg Pool 2D //
//---------------------------------------------------------------------------//
template <typename DataType>
void generateAvgPool2DData(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IH = cfg.shape[1];
const uint32_t IW = cfg.shape[2];
const uint32_t C = cfg.shape[3];
const uint32_t KY = cfg.dotProductInfo.kernel[0];
const uint32_t KX = cfg.dotProductInfo.kernel[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t c = t % C;
uint32_t ix = (t / C) % IW;
uint32_t iy = ((t / C) / IW) % IH;
uint32_t k = ((iy % KY) * KX + (ix % KX)) * C + c;
data[t] = static_cast<DataType>(generator(k));
}
}
bool generateAvgPool2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
if (cfg.inputPos != 0)
{
WARNING("[Generator][DP][AvgPool2D] Invalid input tensor slot position to operator.");
return false;
}
if (cfg.dotProductInfo.kernel.size() != 2 || cfg.dotProductInfo.kernel[0] <= 0 || cfg.dotProductInfo.kernel[1] <= 0)
{
WARNING("[Generator][DP][AvgPool2D] Missing or incorrect kernel size information.");
return false;
}
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][AvgPool2D] Tensor shape expected 4 dimensions.");
return false;
}
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
generateAvgPool2DData(cfg, generator, outData, size);
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
generateAvgPool2DData(cfg, generator, outData, size);
break;
}
default:
WARNING("[Generator][DP][AvgPool2D] Only supports FP32 or FP16.");
return false;
}
return true;
}
//---------------------------------------------------------------------------//
// Depthwise Conv2D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateDepthwiseConv2DInput(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.dotProductInfo.kernel.size() != 2 || cfg.dotProductInfo.kernel[0] <= 0 || cfg.dotProductInfo.kernel[1] <= 0)
{
WARNING("[Generator][DP][DWConv2D][Input] Missing or incorrect kernel size information.");
return false;
}
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][DWConv2D][Input] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IH = cfg.shape[1];
const uint32_t IW = cfg.shape[2];
const uint32_t C = cfg.shape[3];
const uint32_t KH = cfg.dotProductInfo.kernel[0];
const uint32_t KW = cfg.dotProductInfo.kernel[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ix = (t / C) % IW;
uint32_t iy = ((t / C) / IW) % IH;
uint32_t k = ((iy % KH) * KW + (ix % KW));
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateDepthwiseConv2DWeight(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][DWConv2D][Weight] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t KH = cfg.shape[0];
const uint32_t KW = cfg.shape[1];
const uint32_t C = cfg.shape[2];
const uint32_t M = cfg.shape[3];
for (int64_t t = 0; t < T; ++t)
{
uint32_t kx = ((t / M) / C) % KW;
uint32_t ky = (((t / M) / C) / KW) % KH;
uint32_t k = (ky * KW + kx);
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateDepthwiseConv2DBias(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 1)
{
WARNING("[Generator][DP][DWConv2D][Bias] Tensor shape expected 1 dimension.");
return false;
}
const uint32_t T = cfg.shape[0];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(2));
}
return true;
}
bool generateDepthwiseConv2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateDepthwiseConv2DInput(cfg, generator, outData, size);
case 1:
return generateDepthwiseConv2DWeight(cfg, generator, outData, size);
case 2:
return generateDepthwiseConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][DWConv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
switch (cfg.inputPos)
{
case 0:
return generateDepthwiseConv2DInput(cfg, generator, outData, size);
case 1:
return generateDepthwiseConv2DWeight(cfg, generator, outData, size);
case 2:
return generateDepthwiseConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][DWConv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][DWConv2D] Only supports FP32 or FP16.");
return false;
}
}
//---------------------------------------------------------------------------//
// Transpose Conv2D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateTransposeConv2DInput(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.dotProductInfo.kernel.size() != 2 || cfg.dotProductInfo.kernel[0] <= 0 || cfg.dotProductInfo.kernel[1] <= 0)
{
WARNING("[Generator][DP][TConv2D][Input] Missing or incorrect kernel size information.");
return false;
}
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][TConv2D][Input] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t IH = cfg.shape[1];
const uint32_t IW = cfg.shape[2];
const uint32_t IC = cfg.shape[3];
const uint32_t KH = cfg.dotProductInfo.kernel[0];
const uint32_t KW = cfg.dotProductInfo.kernel[1];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t ix = (t / IC) % IW;
uint32_t iy = ((t / IC) / IW) % IH;
uint32_t k = ((iy % KH) * KW + (ix % KW)) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateTransposeConv2DWeight(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 4)
{
WARNING("[Generator][DP][TConv2D][Weight] Tensor shape expected 4 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t KH = cfg.shape[1];
const uint32_t KW = cfg.shape[2];
const uint32_t IC = cfg.shape[3];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t kx = (t / IC) % KW;
uint32_t ky = ((t / IC) / KW) % KH;
uint32_t k = (ky * KW + kx) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateTransposeConv2DBias(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 1)
{
WARNING("[Generator][DP][TConv2D][Bias] Tensor shape expected 1 dimension.");
return false;
}
const uint32_t T = cfg.shape[0];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(2));
}
return true;
}
bool generateTransposeConv2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateTransposeConv2DInput(cfg, generator, outData, size);
case 1:
return generateTransposeConv2DWeight(cfg, generator, outData, size);
case 2:
return generateTransposeConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][TConv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
switch (cfg.inputPos)
{
case 0:
return generateTransposeConv2DInput(cfg, generator, outData, size);
case 1:
return generateTransposeConv2DWeight(cfg, generator, outData, size);
case 2:
return generateTransposeConv2DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][TConv2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][TConv2D] Only supports FP32 or FP16.");
return false;
}
}
//---------------------------------------------------------------------------//
// Conv3D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateConv3DInput(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.dotProductInfo.kernel.size() != 3 || cfg.dotProductInfo.kernel[0] <= 0 ||
cfg.dotProductInfo.kernel[1] <= 0 || cfg.dotProductInfo.kernel[2] <= 0)
{
WARNING("[Generator][DP][Conv3D][Input] Missing or incorrect kernel size information.");
return false;
}
if (cfg.shape.size() != 5)
{
WARNING("[Generator][DP][Conv3D][Input] Tensor shape expected 5 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t ID = cfg.shape[1];
const uint32_t IH = cfg.shape[2];
const uint32_t IW = cfg.shape[3];
const uint32_t IC = cfg.shape[4];
const uint32_t KD = cfg.dotProductInfo.kernel[0];
const uint32_t KH = cfg.dotProductInfo.kernel[1];
const uint32_t KW = cfg.dotProductInfo.kernel[2];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t ix = (t / IC) % IW;
uint32_t iy = ((t / IC) / IW) % IH;
uint32_t id = (((t / IC) / IW) / IH) % ID;
uint32_t k = (((id % KD) * KH + (iy % KH)) * KW + (ix % KW)) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateConv3DWeight(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 5)
{
WARNING("[Generator][DP][Conv3D][Weight] Tensor shape expected 5 dimensions.");
return false;
}
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t KD = cfg.shape[0];
const uint32_t KH = cfg.shape[1];
const uint32_t KW = cfg.shape[2];
const uint32_t IC = cfg.shape[3];
for (int64_t t = 0; t < T; ++t)
{
uint32_t ic = t % IC;
uint32_t kx = (t / IC) % KW;
uint32_t ky = ((t / IC) / KW) % KH;
uint32_t kd = (((t / IC) / KW) / KH) % KD;
uint32_t k = ((kd * KH + ky) * KW + kx) * IC + ic;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateConv3DBias(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
if (cfg.shape.size() != 1)
{
WARNING("[Generator][DP][Conv3D][Bias] Tensor shape expected 1 dimension.");
return false;
}
const uint32_t T = cfg.shape[0];
for (uint32_t t = 0; t < T; ++t)
{
data[t] = static_cast<DataType>(generator(2));
}
return true;
}
bool generateConv3D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateConv3DInput(cfg, generator, outData, size);
case 1:
return generateConv3DWeight(cfg, generator, outData, size);
case 2:
return generateConv3DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][Conv3D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
case DType::DType_FP16: {
half_float::half* outData = reinterpret_cast<half_float::half*>(data);
switch (cfg.inputPos)
{
case 0:
return generateConv3DInput(cfg, generator, outData, size);
case 1:
return generateConv3DWeight(cfg, generator, outData, size);
case 2:
return generateConv3DBias(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][Conv3D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][Conv3D] Only supports FP32 or FP16.");
return false;
}
}
//---------------------------------------------------------------------------//
// FFT2D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateFFT2DReal(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t H = cfg.shape[1];
const uint32_t W = cfg.shape[2];
for (int64_t t = 0; t < T; ++t)
{
uint32_t x = t % W;
uint32_t y = (t / W) % H;
uint32_t k = y * W + x;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
template <typename DataType>
bool generateFFT2DImag(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t H = cfg.shape[1];
const uint32_t W = cfg.shape[2];
// The index expression of ((1*N+n)*H+y)*W+x in the spec equates to
// using the values after those used for the Real tensor, but we need
// to iterate through all those values to get to the Imaginary data
for (int64_t n = 0; n < 2; ++n)
{
for (int64_t t = 0; t < T; ++t)
{
uint32_t x = t % W;
uint32_t y = (t / W) % H;
uint32_t k = y * W + x;
data[t] = static_cast<DataType>(generator(k));
}
}
return true;
}
bool generateFFT2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
if (cfg.shape.size() != 3)
{
WARNING("[Generator][DP][FFT2D] Tensor shape expected 3 dimensions.");
return false;
}
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateFFT2DReal(cfg, generator, outData, size);
case 1:
return generateFFT2DImag(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][FFT2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][FFT2D] Only supports FP32.");
return false;
}
return true;
}
//---------------------------------------------------------------------------//
// RFFT2D //
//---------------------------------------------------------------------------//
template <typename DataType>
bool generateRFFT2DReal(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
DataType* data,
size_t size)
{
const int64_t T = TosaReference::numElementsFromShape(cfg.shape);
const uint32_t H = cfg.shape[1];
const uint32_t W = cfg.shape[2];
for (int64_t t = 0; t < T; ++t)
{
uint32_t x = t % W;
uint32_t y = (t / W) % H;
uint32_t k = y * W + x;
data[t] = static_cast<DataType>(generator(k));
}
return true;
}
bool generateRFFT2D(const TosaReference::GenerateConfig& cfg,
TosaReference::IDotProductGenerator& generator,
void* data,
size_t size)
{
if (cfg.shape.size() != 3)
{
WARNING("[Generator][DP][RFFT2D] Tensor shape expected 3 dimensions.");
return false;
}
switch (cfg.dataType)
{
case DType::DType_FP32: {
float* outData = reinterpret_cast<float*>(data);
switch (cfg.inputPos)
{
case 0:
return generateRFFT2DReal(cfg, generator, outData, size);
default:
WARNING("[Generator][DP][RFFT2D] Invalid input tensor slot position to operator.");
return false;
}
break;
}
default:
WARNING("[Generator][DP][RFFT2D] Only supports FP32.");
return false;
}
return true;
}
} // namespace
namespace TosaReference
{
bool generateDotProduct(const GenerateConfig& cfg, void* data, size_t size)
{
auto generator = pickDotProductGenerator(cfg);
if (!generator)
{
WARNING("[Generator][DP] Requested generator could not be created!");
return false;
}
if (cfg.dotProductInfo.ks <= 0)
{
WARNING("[Generator][DP] Invalid test set kernel size %d.", cfg.dotProductInfo.ks);
return false;
}
// Select which generator to use
switch (cfg.opType)
{
case tosa::Op_MATMUL:
return generateMatMul(cfg, *generator, data, size);
case tosa::Op_CONV2D:
return generateConv2D(cfg, *generator, data, size);
case tosa::Op_REDUCE_SUM:
return generateReduceSum(cfg, *generator, data, size);
case tosa::Op_FULLY_CONNECTED:
return generateFullyConnected(cfg, *generator, data, size);
case tosa::Op_AVG_POOL2D:
return generateAvgPool2D(cfg, *generator, data, size);
case tosa::Op_DEPTHWISE_CONV2D:
return generateDepthwiseConv2D(cfg, *generator, data, size);
case tosa::Op_TRANSPOSE_CONV2D:
return generateTransposeConv2D(cfg, *generator, data, size);
case tosa::Op_CONV3D:
return generateConv3D(cfg, *generator, data, size);
case tosa::Op_FFT2D:
return generateFFT2D(cfg, *generator, data, size);
case tosa::Op_RFFT2D:
return generateRFFT2D(cfg, *generator, data, size);
default:
WARNING("[Generator][DP] Unsupported operator.");
return false;
}
return false;
}
} // namespace TosaReference