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
380 lines
15 KiB
C++
380 lines
15 KiB
C++
/*******************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017 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.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifndef MIO_CONV_BATCHNORM_ACTIV_HOST_H_
|
|
#define MIO_CONV_BATCHNORM_ACTIV_HOST_H_
|
|
|
|
#include "mloNeuronHost.hpp"
|
|
|
|
#include <miopen/convolution.hpp>
|
|
#include <miopen/miopen.h>
|
|
#include <miopen/tensor.hpp>
|
|
#include <miopen/tensor_extra.hpp>
|
|
|
|
#include <cmath>
|
|
#include <iomanip>
|
|
|
|
template <typename Tgpu, typename Tref>
|
|
int miopenBNSpatialFwdInferHost(miopenTensorDescriptor_t& inputTensor,
|
|
const Tref* in_ptr,
|
|
Tref* out_ptr,
|
|
const Tgpu* scale_ptr,
|
|
const Tgpu* bias_ptr,
|
|
double epsilon,
|
|
const Tgpu* estimatedMean,
|
|
const Tgpu* estimatedVariance)
|
|
{
|
|
int nIn, cIn, hIn, wIn;
|
|
miopenGet4dTensorDescriptorLengths(inputTensor, &nIn, &cIn, &hIn, &wIn);
|
|
const auto tensorLayout = miopen::deref(inputTensor).GetLayoutEnum().value();
|
|
|
|
int n_batchs = nIn;
|
|
int channels = cIn;
|
|
int height = hIn;
|
|
int width = wIn;
|
|
|
|
unsigned int index;
|
|
unsigned int adjIndex;
|
|
unsigned int in_nstride = channels * height * width;
|
|
unsigned int in_cstride = height * width;
|
|
|
|
double elemStd = 0.;
|
|
int ret = 0;
|
|
|
|
double variance = 0.;
|
|
double mean = 0.;
|
|
double inhat = 0.;
|
|
for(int cidx = 0; cidx < channels; cidx++)
|
|
{ // via channel
|
|
mean = estimatedMean[cidx];
|
|
variance = estimatedVariance[cidx];
|
|
double invertVar = 1.0 / sqrt(variance + epsilon);
|
|
// process the batch per channel
|
|
for(int row = 0; row < height; row++)
|
|
{ // via rows
|
|
for(int column = 0; column < width; column++)
|
|
{ // via columns
|
|
adjIndex = (tensorLayout == miopenTensorNCHW)
|
|
? in_cstride * cidx + width * row + column
|
|
: width * channels * row + channels * column + cidx;
|
|
for(int bidx = 0; bidx < n_batchs; bidx++)
|
|
{ // via mini_batch
|
|
index = in_nstride * bidx + adjIndex;
|
|
elemStd = in_ptr[index] - mean;
|
|
inhat = elemStd * invertVar;
|
|
out_ptr[index] = scale_ptr[cidx] * inhat + bias_ptr[cidx];
|
|
} // end for (n)
|
|
}
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
template <typename Tgpu, typename Tref>
|
|
int miopenBNPerActivFwdInferHost(miopenTensorDescriptor_t& inputTensor,
|
|
const Tref* in_ptr,
|
|
Tref* out_ptr,
|
|
const Tgpu* scale_ptr,
|
|
const Tgpu* bias_ptr,
|
|
double epsilon,
|
|
const Tgpu* estimatedMean,
|
|
const Tgpu* estimatedVariance)
|
|
{ // use running mean and variance
|
|
|
|
int nIn, cIn, hIn, wIn;
|
|
miopenGet4dTensorDescriptorLengths(inputTensor, &nIn, &cIn, &hIn, &wIn);
|
|
const auto tensorLayout = miopen::deref(inputTensor).GetLayoutEnum().value();
|
|
|
|
int n_batchs = nIn;
|
|
int channels = cIn;
|
|
int height = hIn;
|
|
int width = wIn;
|
|
|
|
// C*H*W is also stored as in_nstride, H*W is in_cstride, W is in_hstride.
|
|
unsigned int index;
|
|
unsigned int adjIndex;
|
|
unsigned int in_nstride = channels * height * width;
|
|
unsigned int in_cstride = height * width;
|
|
|
|
double elemStd = 0.;
|
|
|
|
int ret = 0;
|
|
|
|
double mean = 0.;
|
|
double variance = 0.;
|
|
for(int cidx = 0; cidx < channels; cidx++)
|
|
{ // via channel
|
|
// process the batch per channel
|
|
for(int row = 0; row < height; row++)
|
|
{ // via rows
|
|
for(int column = 0; column < width; column++)
|
|
{ // via columns
|
|
adjIndex = (tensorLayout == miopenTensorNCHW)
|
|
? in_cstride * cidx + width * row + column
|
|
: width * channels * row + channels * column + cidx;
|
|
mean = estimatedMean[adjIndex];
|
|
variance = estimatedVariance[adjIndex];
|
|
double elemInvVar = 1.0 / double(sqrt(variance + epsilon));
|
|
for(int bidx = 0; bidx < n_batchs; bidx++)
|
|
{ // via mini_batch
|
|
index = in_nstride * bidx + adjIndex;
|
|
// per (x-dims) channel load a block of data into LDS
|
|
elemStd = in_ptr[index] - mean; // (x_i - mean)
|
|
double inhat = elemStd * elemInvVar;
|
|
// #5 Gamma and Beta adjust
|
|
// y_i = gamma*x_hat + beta
|
|
out_ptr[index] = (scale_ptr[adjIndex] * inhat) + bias_ptr[adjIndex];
|
|
} // end for(n_batchs)
|
|
} // for (column)
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
template <typename Tgpu /* the data type used in GPU computations (usually half) */,
|
|
typename Tref /* the data type used in CPU checkings (usually double) */>
|
|
void miopenActivationFwdHost(int neuron_type,
|
|
Tref gamma,
|
|
Tref beta,
|
|
Tref alpha,
|
|
size_t size,
|
|
const Tref* bot_ptr,
|
|
Tref* c_res)
|
|
{
|
|
|
|
/* std::vector<Tref> data(size, 0.);
|
|
|
|
for(size_t k = 0; k < size; k++)
|
|
data.at(k) = bot_ptr[k];
|
|
*/
|
|
std::function<Tref(Tref)> f;
|
|
|
|
switch(neuron_type)
|
|
{
|
|
case MIOPEN_NEURON_PASTHRU: // x
|
|
f = [=](Tref x) { return x; };
|
|
break;
|
|
case MIOPEN_NEURON_LOGISTIC: // 1 / (1 + e^-x) //Sigmoid
|
|
f = [=](Tref x) { return 1. / (1. + std::exp(Tref(-x))); };
|
|
break;
|
|
case MIOPEN_NEURON_TANH: // beta * tanh(alpha * x)
|
|
f = [=](Tref x) { return beta * std::tanh(alpha * x); };
|
|
break;
|
|
case MIOPEN_NEURON_RELU: // max(0, x)
|
|
f = [=](Tref x) { return (x > 0.) ? x : 0.; };
|
|
break;
|
|
case MIOPEN_NEURON_SOFTRELU: // log(1 + e^x) // bonomial normal log likelihood
|
|
f = [=](Tref x) {
|
|
return (x > 0.) ? (x + std::log1p(std::exp(-x))) : (std::log1p(std::exp(x)));
|
|
};
|
|
break;
|
|
case MIOPEN_NEURON_ABS: // abs(x)
|
|
f = [=](Tref x) { return std::abs(x); };
|
|
break;
|
|
case MIOPEN_NEURON_POWER: // (alpha + beta * x) ^ gamma
|
|
f = [=](Tref x) {
|
|
Tref v = alpha + beta * x;
|
|
return v <= std::numeric_limits<Tref>::epsilon() ? 0. : pow(v, gamma);
|
|
};
|
|
break;
|
|
case MIOPEN_NEURON_CLIPPED_RELU: // min(alpha, max(0, x))
|
|
f = [=](Tref x) { return std::min(alpha, std::max(Tref(0.), x)); };
|
|
break;
|
|
case MIOPEN_NEURON_LEAKY_RELU: // alpha * x | x<=0; x | x>0
|
|
f = [=](Tref x) { return (x > 0) ? x : x * alpha; };
|
|
break;
|
|
case MIOPEN_NEURON_ELU: // alpah * (exp(x)-1) | x<=0; x | x>0
|
|
f = [=](Tref x) { return (x > 0) ? x : alpha * std::expm1(x); };
|
|
break;
|
|
case MIOPEN_NEURON_CLAMP: // max(alpha, min(beta, x)))
|
|
f = [=](Tref x) { return std::max(alpha, std::min(beta, x)); };
|
|
break;
|
|
default: printf("ERROR: unknown neuron type: %d\n", neuron_type); break;
|
|
}
|
|
|
|
for(size_t i = 0; i < size; i++)
|
|
c_res[i] = f(static_cast<Tref>(bot_ptr[i])); // f(data.at(i));
|
|
}
|
|
|
|
template <typename Tgpu /* the data type used in GPU computations (usually half) */,
|
|
typename Tref /* the data type used in CPU checkings (usually double) */>
|
|
int miopenInferVerify(size_t size, const Tref* c_res, const Tgpu* top_ptr, Tref allowedEps)
|
|
{
|
|
int match = 1;
|
|
for(size_t i = 0; i < size && match; i++)
|
|
{
|
|
Tref c_val = c_res[i];
|
|
Tref g_val = static_cast<Tref>(top_ptr[i]);
|
|
double err = std::abs(c_val - g_val);
|
|
double err_rel = calculate_relative_error(c_val, g_val);
|
|
// if(err > 1e-6) printf("i: %d, cval: %f, gval: %f\n", i, c_val, g_val );
|
|
if((err > allowedEps && err_rel > allowedEps) || std::isnan(c_val) || std::isnan(g_val) ||
|
|
!std::isfinite(c_val) || !std::isfinite(g_val))
|
|
{
|
|
std::cout << "Difference in neuron layer: " << err << " too large at " << i
|
|
<< " c_v = " << c_val << " vs g_val = " << g_val
|
|
<< " tolerance = " << allowedEps << std::endl;
|
|
match = 0;
|
|
}
|
|
}
|
|
|
|
return (match);
|
|
}
|
|
|
|
template <typename Tgpu, typename Tref>
|
|
int ConvForwardCPU(const std::vector<Tref>& in,
|
|
std::vector<Tref>& outhost,
|
|
const std::vector<Tgpu>& wei,
|
|
const std::vector<Tgpu>& b,
|
|
const int bias,
|
|
miopenConvolutionDescriptor_t& convDesc,
|
|
miopenTensorDescriptor_t& inputTensor,
|
|
miopenTensorDescriptor_t& weightTensor,
|
|
miopenTensorDescriptor_t& outputTensor)
|
|
{
|
|
|
|
int in_n, in_c, in_h, in_w;
|
|
int in_nstride, in_cstride, in_hstride, in_wstride;
|
|
miopenDataType_t dt;
|
|
miopenGet4dTensorDescriptor(inputTensor,
|
|
&dt,
|
|
&in_n,
|
|
&in_c,
|
|
&in_h,
|
|
&in_w,
|
|
&in_nstride,
|
|
&in_cstride,
|
|
&in_hstride,
|
|
&in_wstride);
|
|
|
|
int wei_n, wei_c, wei_h, wei_w;
|
|
int wei_nstride, wei_cstride, wei_hstride, wei_wstride;
|
|
|
|
miopenGet4dTensorDescriptor(weightTensor,
|
|
&dt,
|
|
&wei_n,
|
|
&wei_c,
|
|
&wei_h,
|
|
&wei_w,
|
|
&wei_nstride,
|
|
&wei_cstride,
|
|
&wei_hstride,
|
|
&wei_wstride);
|
|
|
|
int out_n, out_c, out_h, out_w;
|
|
int out_nstride, out_cstride, out_hstride, out_wstride;
|
|
miopenGet4dTensorDescriptor(outputTensor,
|
|
&dt,
|
|
&out_n,
|
|
&out_c,
|
|
&out_h,
|
|
&out_w,
|
|
&out_nstride,
|
|
&out_cstride,
|
|
&out_hstride,
|
|
&out_wstride);
|
|
|
|
int stride_h, stride_w, pad_h, pad_w, dilation_h, dilation_w;
|
|
miopenConvolutionMode_t mode;
|
|
miopenPaddingMode_t pmode = miopen::deref(convDesc).paddingMode;
|
|
miopenGetConvolutionDescriptor(
|
|
convDesc, &mode, &pad_h, &pad_w, &stride_h, &stride_w, &dilation_h, &dilation_w);
|
|
|
|
if(pmode == miopenPaddingSame)
|
|
{
|
|
pad_h = (in_h % stride_h == 0) ? (std::max((wei_h - stride_h), 0))
|
|
: (std::max((wei_h - (in_h % stride_h)), 0));
|
|
pad_w = (in_w % stride_w == 0) ? (std::max((wei_w - stride_w), 0))
|
|
: (std::max((wei_w - (in_w % stride_w)), 0));
|
|
pad_h /= 2;
|
|
pad_w /= 2;
|
|
}
|
|
else if(pmode == miopenPaddingValid)
|
|
{
|
|
pad_h = 0;
|
|
pad_w = 0;
|
|
}
|
|
|
|
if(out_h <= 0 || out_w <= 0)
|
|
throw std::runtime_error("Invalid Test Case: Check Output Dimension.");
|
|
|
|
miopenGet4dTensorDescriptor(weightTensor,
|
|
&dt,
|
|
&wei_n,
|
|
&wei_c,
|
|
&wei_h,
|
|
&wei_w,
|
|
&wei_nstride,
|
|
&wei_cstride,
|
|
&wei_hstride,
|
|
&wei_wstride);
|
|
|
|
for(int o = 0; o < out_n; o++)
|
|
{ // mini-batch size
|
|
for(int w = 0; w < out_c; w++)
|
|
{ // out_channels (num filters)
|
|
for(int i = 0; i < out_h; i++)
|
|
{ // output_height (from getforwardoutputdim())
|
|
int in_off_h = i * stride_h;
|
|
for(int j = 0; j < out_w; j++)
|
|
{ // output_width (from getforwardoutputdim())
|
|
Tgpu acc = static_cast<Tgpu>(0.);
|
|
int in_off_w = j * stride_w;
|
|
for(int k = 0; k < in_c; k++)
|
|
{ // in_channels (RGB)
|
|
for(int x = 0; x < wei_h; x++)
|
|
{
|
|
int in_x = in_off_h - pad_h + x * dilation_h;
|
|
if(in_x >= 0 && in_x < in_h)
|
|
{
|
|
for(int y = 0; y < wei_w; y++)
|
|
{
|
|
int in_y = in_off_w - pad_w + y * dilation_w;
|
|
if(in_y >= 0 && in_y < in_w)
|
|
{
|
|
acc += static_cast<Tgpu>(in.at(o * in_nstride +
|
|
k * in_cstride +
|
|
in_x * in_w + in_y)) *
|
|
static_cast<Tgpu>(wei.at(w * wei_nstride +
|
|
k * wei_cstride +
|
|
x * wei_hstride + y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
acc = bias != 0 ? acc + static_cast<Tgpu>(b[w]) : acc;
|
|
outhost[o * out_nstride + w * out_cstride + i * out_hstride + j] = acc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|