onnxruntime/onnxruntime/core/mlas/lib/pooling_fp16.cpp
Chen Fu 41ddcd30a1
Fp16 NHWC Max and Average Pooling (#15181)
### Description
Max and average pooling operators for fp16, NHWC 


### Motivation and Context
Continue on the steps for fp16 inference support
2023-03-28 08:22:55 -07:00

355 lines
10 KiB
C++

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License.
Module Name:
pooling_fp16.cpp
Abstract:
This module implements the pooling operation for fp16
tensors in NHWC format.
--*/
#include "mlasi.h"
#include "fp16_common.h"
#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED
template <typename AggregationType>
typename AggregationType::CtxType
PoolCreateContext(size_t KernelSize);
template <typename AggregationType>
MLAS_FLOAT16X8
PoolInit16x8();
template <typename AggregationType>
MLAS_FLOAT16X4
PoolInit16x4();
template <typename AggregationType>
MLAS_FLOAT16X8
PoolAggregate16x8(MLAS_FLOAT16X8 agg, MLAS_FLOAT16X8 element);
template <typename AggregationType>
MLAS_FLOAT16X4
PoolAggregate16x4(MLAS_FLOAT16X4 agg, MLAS_FLOAT16X4 element);
template <typename AggregationType>
MLAS_FLOAT16X8
PoolSummary16x8(MLAS_FLOAT16X8 agg, typename AggregationType::CtxType context);
template <typename AggregationType>
MLAS_FLOAT16X4
PoolSummary16x4(MLAS_FLOAT16X4 agg, typename AggregationType::CtxType context);
struct MaxPoolAggregation {
typedef size_t CtxType; // useless type to satisfy compilers
};
template <>
MLAS_FORCEINLINE
size_t
PoolCreateContext<MaxPoolAggregation>(size_t KernelSize)
{
MLAS_UNREFERENCED_PARAMETER(KernelSize);
return 0;
}
template<>
MLAS_FORCEINLINE
MLAS_FLOAT16X8
PoolInit16x8<MaxPoolAggregation>()
{
// lowest fp16 -65504.0f
return MlasBroadcastFloat16x8(0xfbff);
}
template <>
MLAS_FORCEINLINE
MLAS_FLOAT16X4
PoolInit16x4<MaxPoolAggregation>()
{
// lowest fp16 -65504.0f
return MlasBroadcastFloat16x4(0xfbff);
}
template<>
MLAS_FORCEINLINE
MLAS_FLOAT16X8
PoolAggregate16x8<MaxPoolAggregation>(MLAS_FLOAT16X8 agg, MLAS_FLOAT16X8 element)
{
return MlasMaximumFloat16x8(agg, element);
}
template<>
MLAS_FORCEINLINE
MLAS_FLOAT16X4
PoolAggregate16x4<MaxPoolAggregation>(MLAS_FLOAT16X4 agg, MLAS_FLOAT16X4 element)
{
return MlasMaximumFloat16x4(agg, element);
}
template<>
MLAS_FORCEINLINE
MLAS_FLOAT16X8
PoolSummary16x8<MaxPoolAggregation>(MLAS_FLOAT16X8 agg, size_t size)
{
MLAS_UNREFERENCED_PARAMETER(size);
return agg;
}
template<>
MLAS_FORCEINLINE
MLAS_FLOAT16X4
PoolSummary16x4<MaxPoolAggregation>(MLAS_FLOAT16X4 agg, size_t size)
{
MLAS_UNREFERENCED_PARAMETER(size);
return agg;
}
struct AveragePoolAggregation {
typedef MLAS_FLOAT16X8 CtxType;
};
template<>
MLAS_FLOAT16X8
PoolCreateContext<AveragePoolAggregation>(size_t KernelSize)
{
return MlasBroadcastFloat16x8(MLAS_Float2Half(float(KernelSize)));
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X8
PoolInit16x8<AveragePoolAggregation>()
{
return MlasZeroFloat16x8();
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X4
PoolInit16x4<AveragePoolAggregation>()
{
return MlasZeroFloat16x4();
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X8
PoolAggregate16x8<AveragePoolAggregation>(MLAS_FLOAT16X8 agg, MLAS_FLOAT16X8 element)
{
return MlasAddFloat16x8(agg, element);
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X4
PoolAggregate16x4<AveragePoolAggregation>(MLAS_FLOAT16X4 agg, MLAS_FLOAT16X4 element)
{
return MlasAddFloat16x4(agg, element);
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X8
PoolSummary16x8<AveragePoolAggregation>(MLAS_FLOAT16X8 agg, MLAS_FLOAT16X8 context)
{
return MlasDivFloat16x8(agg, context);
}
template <>
MLAS_FORCEINLINE MLAS_FLOAT16X4
PoolSummary16x4<AveragePoolAggregation>(MLAS_FLOAT16X4 agg, MLAS_FLOAT16X8 context)
{
return MlasDivFloat16x4(agg, MlasToLowHalfFloat16x4(context));
}
template<typename AggregationType>
MLAS_FORCEINLINE
void
MlasPoolFp16HWC(
const _mlas_fp16_* const* Input,
_mlas_fp16_* Output,
size_t Channels,
size_t OutputCount,
size_t KernelSize
)
{
while (OutputCount > 0) {
size_t ChannelOffset = 0;
size_t c = Channels;
while (c >= 32) {
MLAS_FLOAT16X8 MaximumVector0 = PoolInit16x8<AggregationType>();
MLAS_FLOAT16X8 MaximumVector1 = MaximumVector0;
MLAS_FLOAT16X8 MaximumVector2 = MaximumVector0;
MLAS_FLOAT16X8 MaximumVector3 = MaximumVector0;
size_t cnt = 0;
for (size_t k = 0; k < KernelSize; k++) {
if (Input[k] == nullptr) {
continue;
}
MLAS_FLOAT16X8 InputVector0 = MlasLoadFloat16x8(&Input[k][ChannelOffset]);
MLAS_FLOAT16X8 InputVector1 = MlasLoadFloat16x8(&Input[k][ChannelOffset + 8]);
MLAS_FLOAT16X8 InputVector2 = MlasLoadFloat16x8(&Input[k][ChannelOffset + 16]);
MLAS_FLOAT16X8 InputVector3 = MlasLoadFloat16x8(&Input[k][ChannelOffset + 24]);
MaximumVector0 = PoolAggregate16x8<AggregationType>(MaximumVector0, InputVector0);
MaximumVector1 = PoolAggregate16x8<AggregationType>(MaximumVector1, InputVector1);
MaximumVector2 = PoolAggregate16x8<AggregationType>(MaximumVector2, InputVector2);
MaximumVector3 = PoolAggregate16x8<AggregationType>(MaximumVector3, InputVector3);
cnt++;
}
typename AggregationType::CtxType context = PoolCreateContext<AggregationType>(cnt);
MaximumVector0 = PoolSummary16x8<AggregationType>(MaximumVector0, context);
MaximumVector1 = PoolSummary16x8<AggregationType>(MaximumVector1, context);
MaximumVector2 = PoolSummary16x8<AggregationType>(MaximumVector2, context);
MaximumVector3 = PoolSummary16x8<AggregationType>(MaximumVector3, context);
MlasStoreFloat16x8(&Output[0], MaximumVector0);
MlasStoreFloat16x8(&Output[8], MaximumVector1);
MlasStoreFloat16x8(&Output[16], MaximumVector2);
MlasStoreFloat16x8(&Output[24], MaximumVector3);
Output += 32;
ChannelOffset += 32;
c -= 32;
}
if (c >= 16) {
MLAS_FLOAT16X8 MaximumVector0 = PoolInit16x8<AggregationType>();
MLAS_FLOAT16X8 MaximumVector1 = MaximumVector0;
size_t cnt = 0;
for (size_t k = 0; k < KernelSize; k++) {
if (Input[k] == nullptr) {
continue;
}
MLAS_FLOAT16X8 InputVector0 = MlasLoadFloat16x8(&Input[k][ChannelOffset]);
MLAS_FLOAT16X8 InputVector1 = MlasLoadFloat16x8(&Input[k][ChannelOffset + 8]);
MaximumVector0 = PoolAggregate16x8<AggregationType>(MaximumVector0, InputVector0);
MaximumVector1 = PoolAggregate16x8<AggregationType>(MaximumVector1, InputVector1);
cnt++;
}
typename AggregationType::CtxType context = PoolCreateContext<AggregationType>(cnt);
MaximumVector0 = PoolSummary16x8<AggregationType>(MaximumVector0, context);
MaximumVector1 = PoolSummary16x8<AggregationType>(MaximumVector1, context);
MlasStoreFloat16x8(&Output[0], MaximumVector0);
MlasStoreFloat16x8(&Output[8], MaximumVector1);
Output += 16;
ChannelOffset += 16;
c -= 16;
}
if (c >= 8) {
MLAS_FLOAT16X8 MaximumVector0 = PoolInit16x8<AggregationType>();
size_t cnt = 0;
for (size_t k = 0; k < KernelSize; k++) {
if (Input[k] == nullptr) {
continue;
}
MLAS_FLOAT16X8 InputVector0 = MlasLoadFloat16x8(&Input[k][ChannelOffset]);
MaximumVector0 = PoolAggregate16x8<AggregationType>(MaximumVector0, InputVector0);
cnt++;
}
typename AggregationType::CtxType context = PoolCreateContext<AggregationType>(cnt);
MaximumVector0 = PoolSummary16x8<AggregationType>(MaximumVector0, context);
MlasStoreFloat16x8(&Output[0], MaximumVector0);
Output += 8;
ChannelOffset += 8;
c -= 8;
}
if (c >= 4) {
MLAS_FLOAT16X4 MaximumVector0 = PoolInit16x4<AggregationType>();
size_t cnt = 0;
for (size_t k = 0; k < KernelSize; k++) {
if (Input[k] == nullptr) {
continue;
}
MLAS_FLOAT16X4 InputVector0 = MlasLoadFloat16x4(&Input[k][ChannelOffset]);
MaximumVector0 = PoolAggregate16x4<AggregationType>(MaximumVector0, InputVector0);
cnt++;
}
typename AggregationType::CtxType context = PoolCreateContext<AggregationType>(cnt);
MaximumVector0 = PoolSummary16x4<AggregationType>(MaximumVector0, context);
MlasStoreFloat16x4(&Output[0], MaximumVector0);
Output += 4;
ChannelOffset += 4;
c -= 4;
}
if (c > 0) {
// possible over read by 7 bytes
MLAS_FLOAT16X4 MaximumVector0 = PoolInit16x4<AggregationType>();
size_t cnt = 0;
for (size_t k = 0; k < KernelSize; k++) {
if (Input[k] == nullptr) {
continue;
}
MLAS_FLOAT16X4 InputVector0 = MlasLoadFloat16x4(&Input[k][ChannelOffset]);
MaximumVector0 = PoolAggregate16x4<AggregationType>(MaximumVector0, InputVector0);
cnt++;
}
typename AggregationType::CtxType context = PoolCreateContext<AggregationType>(cnt);
MaximumVector0 = PoolSummary16x4<AggregationType>(MaximumVector0, context);
MlasStorePartialFloat16x4(&Output[0], MaximumVector0, c);
Output += c;
}
Input += KernelSize;
OutputCount -= 1;
}
}
void
MLASCALL
MlasNhwcMaxPool(
const MLAS_FP16* const* Input,
MLAS_FP16* Output,
size_t Channels,
size_t OutputCount,
size_t KernelSize
)
{
const _mlas_fp16_* const* input_ptr = reinterpret_cast<const _mlas_fp16_* const*>(Input);
_mlas_fp16_* output_ptr = reinterpret_cast<_mlas_fp16_*>(Output);
MlasPoolFp16HWC<MaxPoolAggregation>(input_ptr, output_ptr, Channels, OutputCount, KernelSize);
}
void
MLASCALL
MlasNhwcAvgPool(
const MLAS_FP16* const* Input,
MLAS_FP16* Output,
size_t Channels,
size_t OutputCount,
size_t KernelSize
)
{
const _mlas_fp16_* const* input_ptr = reinterpret_cast<const _mlas_fp16_* const*>(Input);
_mlas_fp16_* output_ptr = reinterpret_cast<_mlas_fp16_*>(Output);
MlasPoolFp16HWC<AveragePoolAggregation>(input_ptr, output_ptr, Channels, OutputCount, KernelSize);
}
#endif // MLAS_F16VEC_INTRINSICS_SUPPORTED