Files
TheRock/rocm-libraries/projects/miopen/test/gtest/activ_common.hpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

521 lines
15 KiB
C++

/*******************************************************************************
*
* MIT License
*
* Copyright (c) 2024 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#pragma once
#include <cmath>
#include <future>
#include <numeric>
#include <stdexcept>
#include <thread>
#include <miopen/miopen.h>
#include "../tensor_holder.hpp"
namespace miopen {
namespace tests {
namespace activ {
template <class T1,
class T2,
std::enable_if_t<(std::is_unsigned_v<T1> && std::is_unsigned_v<T2>), bool> = false>
auto Ceil(T1 val, T2 div)
{
assert(div != 0);
return (val + div - 1) / div;
}
namespace activ_func {
/// \note static_cast in below functions is needed to speed up execution time for CPU non-native
/// data types
class ActivationPASTHRU
{
public:
template <class T, class Tparam>
static T Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)alpha;
(void)beta;
(void)gamma;
return x;
}
template <class T, class Tparam>
static T Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)alpha;
(void)beta;
(void)gamma;
(void)x;
(void)y;
return dy;
}
};
class ActivationLOGISTIC
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)alpha;
(void)beta;
(void)gamma;
return 1 / (1 + std::exp(-x));
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)alpha;
(void)beta;
(void)gamma;
(void)x;
return static_cast<Tparam>(dy) * y * (static_cast<Tparam>(1) - y);
}
};
class ActivationTANH
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)gamma;
return beta * std::tanh(alpha * x);
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)gamma;
(void)x;
return dy * alpha * (beta - static_cast<Tparam>(y) * y / beta);
}
};
class ActivationRELU
{
public:
template <class T, class Tparam>
static T Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)alpha;
(void)beta;
(void)gamma;
return (x > static_cast<Tparam>(0)) ? x : static_cast<T>(0);
}
template <class T, class Tparam>
static T Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)alpha;
(void)beta;
(void)gamma;
(void)y;
return (x > static_cast<Tparam>(0)) ? dy : static_cast<T>(0);
}
};
class ActivationSOFTRELU
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)alpha;
(void)beta;
(void)gamma;
return std::log1p(std::exp(x));
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)alpha;
(void)beta;
(void)gamma;
(void)y;
const Tparam threshold = 50.0;
const Tparam expval = std::exp(std::min(static_cast<Tparam>(x), threshold));
return dy * expval / (expval + 1);
}
};
class ActivationABS
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)alpha;
(void)beta;
(void)gamma;
return std::abs(x);
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)alpha;
(void)beta;
(void)gamma;
(void)y;
return dy * static_cast<Tparam>((x > static_cast<Tparam>(0)) ? 1 : -1);
}
};
class ActivationPOWER
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
const auto v = alpha + beta * x;
return v <= std::numeric_limits<decltype(v)>::epsilon() ? 0 : std::pow(v, gamma);
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)gamma;
(void)dy;
const auto v = alpha + beta * x;
return v <= std::numeric_limits<decltype(v)>::epsilon() ? 0 : gamma * beta * y / v;
}
};
class ActivationCLIPPEDRELU
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)beta;
(void)gamma;
return std::clamp(static_cast<Tparam>(x), static_cast<Tparam>(0), alpha);
}
template <class T, class Tparam>
static T Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)beta;
(void)gamma;
(void)y;
Tparam x_native = x;
return (x_native > 0 && x_native <= alpha) ? dy : static_cast<T>(0);
}
};
class ActivationLEAKYRELU
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)beta;
(void)gamma;
Tparam x_native = x;
return (x_native > 0) ? x_native : x_native * alpha;
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)beta;
(void)gamma;
(void)y;
return dy * ((x > static_cast<Tparam>(0)) ? 1 : alpha);
}
};
class ActivationELU
{
public:
template <class T, class Tparam>
static Tparam Forward(Tparam alpha, Tparam beta, Tparam gamma, T x)
{
(void)beta;
(void)gamma;
Tparam x_native = x;
return (x_native > 0) ? x_native : alpha * std::expm1(x_native);
}
template <class T, class Tparam>
static Tparam Backward(Tparam alpha, Tparam beta, Tparam gamma, T dy, T x, T y)
{
(void)beta;
(void)gamma;
return dy * ((x > static_cast<Tparam>(0)) ? 1 : y + alpha);
}
};
} // namespace activ_func
enum class Direction
{
Forward,
Backward
};
template <class T>
class ActivationParamDataType;
template <>
class ActivationParamDataType<double>
{
public:
using Type = double; // "Type" must be a native CPU type!
};
template <>
class ActivationParamDataType<float>
{
public:
using Type = float; // "Type" must be a native CPU type!
};
template <>
class ActivationParamDataType<half_float::half>
{
public:
using Type = float; // "Type" must be a native CPU type!
};
template <>
class ActivationParamDataType<bfloat16>
{
public:
using Type = float; // "Type" must be a native CPU type!
};
std::size_t CpuActivationGetNumThreads(std::size_t num_jobs)
{
const unsigned max_num_hw_threads = std::thread::hardware_concurrency();
return std::min(num_jobs, static_cast<std::size_t>(max_num_hw_threads));
}
template <class A, class Tparam, class T>
void DoCpuActivationForwardPacked(std::size_t offset,
std::size_t end,
Tparam alpha,
Tparam beta,
Tparam gamma,
const tensor<T>& x,
tensor<T>& y)
{
for(std::size_t i = offset; i < end; i++)
y.data[i] = A::Forward(alpha, beta, gamma, x.data[i]);
}
template <class A, class Tparam, class T>
void DoCpuActivationBackwardPacked(std::size_t offset,
std::size_t end,
Tparam alpha,
Tparam beta,
Tparam gamma,
const tensor<T>& y,
const tensor<T>& dy,
const tensor<T>& x,
tensor<T>& dx)
{
for(std::size_t i = offset; i < end; i++)
dx.data[i] = A::Backward(alpha, beta, gamma, dy.data[i], x.data[i], y.data[i]);
}
template <Direction direction, class A, class... Ts>
void DoCpuActivationPacked(std::size_t offset, std::size_t end, Ts&&... xs)
{
if constexpr(direction == Direction::Forward)
DoCpuActivationForwardPacked<A>(offset, end, xs...);
else
DoCpuActivationBackwardPacked<A>(offset, end, xs...);
}
template <Direction direction, class A, class... Ts>
void CpuActivationPackedSingleThread(std::size_t num_items, Ts&&... xs)
{
DoCpuActivationPacked<direction, A>(0, num_items, xs...);
}
template <Direction direction, class A, class... Ts>
void CpuActivationPackedMultiThread(std::size_t num_items, Ts&&... xs)
{
const std::size_t max_num_items_per_job = 16 * 1024 * 1024;
const std::size_t num_jobs = Ceil(num_items, max_num_items_per_job);
const auto num_threads = CpuActivationGetNumThreads(num_jobs);
if(num_threads == 1)
{
CpuActivationPackedSingleThread<direction, A>(num_items, xs...);
return;
}
auto func = [&](std::size_t thread_num) {
const auto offset = num_items * thread_num / num_threads;
const auto end = num_items * (thread_num + 1) / num_threads;
DoCpuActivationPacked<direction, A>(offset, end, xs...);
};
std::vector<std::future<void>> threads;
threads.reserve(num_threads - 1);
for(std::size_t i = 0; i < num_threads - 1; ++i)
threads.push_back(std::async(std::launch::async, func, i));
func(num_threads - 1);
for(auto& thread : threads)
thread.wait();
}
template <Direction direction, class A, class... Ts>
void CpuActivationPacked(std::size_t num_items, Ts&&... xs)
{
CpuActivationPackedMultiThread<direction, A>(num_items, xs...);
}
template <Direction direction, class A, class... Ts>
[[noreturn]] void CpuActivationNonPacked(std::size_t /*num_items*/, Ts&&... /*xs*/)
{
throw std::runtime_error("CpuActivationNonPacked is not implemented yet");
}
template <Direction direction, bool is_packed, class A, class... Ts>
void CpuActivation(std::size_t num_items, Ts&&... xs)
{
if constexpr(is_packed)
CpuActivationPacked<direction, A>(num_items, xs...);
else
CpuActivationNonPacked<direction, A>(num_items, xs...);
}
template <Direction direction, bool is_packed, class... Ts>
void CpuActivation(miopenActivationMode_t m, std::size_t num_items, Ts&&... xs)
{
switch(m)
{
case miopenActivationPASTHRU:
CpuActivation<direction, is_packed, activ_func::ActivationPASTHRU>(num_items, xs...);
break;
case miopenActivationLOGISTIC:
CpuActivation<direction, is_packed, activ_func::ActivationLOGISTIC>(num_items, xs...);
break;
case miopenActivationTANH:
CpuActivation<direction, is_packed, activ_func::ActivationTANH>(num_items, xs...);
break;
case miopenActivationRELU:
CpuActivation<direction, is_packed, activ_func::ActivationRELU>(num_items, xs...);
break;
case miopenActivationSOFTRELU:
CpuActivation<direction, is_packed, activ_func::ActivationSOFTRELU>(num_items, xs...);
break;
case miopenActivationABS:
CpuActivation<direction, is_packed, activ_func::ActivationABS>(num_items, xs...);
break;
case miopenActivationPOWER:
CpuActivation<direction, is_packed, activ_func::ActivationPOWER>(num_items, xs...);
break;
case miopenActivationCLIPPEDRELU:
CpuActivation<direction, is_packed, activ_func::ActivationCLIPPEDRELU>(num_items, xs...);
break;
case miopenActivationLEAKYRELU:
CpuActivation<direction, is_packed, activ_func::ActivationLEAKYRELU>(num_items, xs...);
break;
case miopenActivationELU:
CpuActivation<direction, is_packed, activ_func::ActivationELU>(num_items, xs...);
break;
case miopenActivationCLAMP: throw std::runtime_error("Unknown activation mode");
}
}
template <class T>
void CpuActivationForward(miopenActivationMode_t m,
double alpha,
double beta,
double gamma,
const tensor<T>& x,
tensor<T>& y)
{
using Tparam = typename ActivationParamDataType<T>::Type;
if(x.desc.GetElementSize() != y.desc.GetElementSize())
throw std::runtime_error("x.desc.GetElementSize() != y.desc.GetElementSize()");
Tparam p_alpha = alpha;
Tparam p_beta = beta;
Tparam p_gamma = gamma;
if(x.desc.IsPacked() && y.desc.IsPacked())
{
const auto num_items = x.data.size();
CpuActivation<Direction::Forward, true>(m, num_items, p_alpha, p_beta, p_gamma, x, y);
}
else
{
CpuActivation<Direction::Forward, false>(m, 0, p_alpha, p_beta, p_gamma, x, y);
}
}
template <class T>
void CpuActivationBackward(miopenActivationMode_t m,
double alpha,
double beta,
double gamma,
const tensor<T>& y,
const tensor<T>& dy,
const tensor<T>& x,
tensor<T>& dx)
{
using Tparam = typename ActivationParamDataType<T>::Type;
if(x.desc.GetElementSize() != y.desc.GetElementSize())
throw std::runtime_error("x.desc.GetElementSize() != y.desc.GetElementSize()");
if(dx.desc.GetElementSize() != dy.desc.GetElementSize())
throw std::runtime_error("dx.desc.GetElementSize() != dy.desc.GetElementSize()");
if(x.desc.GetElementSize() != dx.desc.GetElementSize())
throw std::runtime_error("x.desc.GetElementSize() != dx.desc.GetElementSize()");
Tparam p_alpha = alpha;
Tparam p_beta = beta;
Tparam p_gamma = gamma;
if(y.desc.IsPacked() && dy.desc.IsPacked() && x.desc.IsPacked() && dx.desc.IsPacked())
{
const auto num_items = dy.data.size();
CpuActivation<Direction::Backward, true>(
m, num_items, p_alpha, p_beta, p_gamma, y, dy, x, dx);
}
else
{
CpuActivation<Direction::Backward, false>(m, 0, p_alpha, p_beta, p_gamma, y, dy, x, dx);
}
}
} // namespace activ
} // namespace tests
} // namespace miopen