Files
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

694 lines
29 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 MLO_POOLINGHOST_H_
#define MLO_POOLINGHOST_H_
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#endif
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <limits>
#include <type_traits>
#include "calcerr.hpp"
#include <miopen/bfloat16.hpp>
#if 0
template<typename _T>
double CalcErr( _T c_val, _T g_val)
{
double err = 0;
if (sizeof(_T) == 4)
{
int * c_uval = (int *)&c_val;
int * g_uval = (int *)&g_val;
err = (double)std::abs(*c_uval - *g_uval);
}
else if (sizeof(_T) == 8)
{
int64_t * c_uval = (int64_t *)&c_val;
int64_t * g_uval = (int64_t *)&g_val;
err = (double)std::abs(*c_uval - *g_uval);
}
// double delta = abs(c_val - g_val);
// double nextafter_delta = nextafterf(min(abs(c_val), abs(g_val)), (_T)INFINITY) - min(abs(c_val), abs(g_val));
// err = delta / nextafter_delta;
return err;
}
#endif
////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////
#ifndef MLO_POOLING_OP_MAX
#define MLO_POOLING_OP_MAX 0
#define MLO_POOLING_OP_AVE 1
#define MLO_POOLING_OP_STC 2
#define MLO_POOLING_OP_AVE_INCLUSIVE 3
#endif
// Non-zero value N skips each Nth computation, thus leading to validation failure.
// For FP16, 100 works well.
#define MLO_POOLING_EMULATE_VALIDATION_FAILURE 0
constexpr int N = 0;
constexpr int C = 1;
constexpr int D = 2;
constexpr int H = 3;
constexpr int W = 4;
struct pooling_math_stats
{
double max_error = 0.0;
int max_num_flops_per_res = 0;
};
struct TensorDimsStrides
{
int n_batchs;
int n_outputs;
int depth;
int height;
int width;
int n_stride;
int c_stride;
int d_stride;
int h_stride;
int w_stride;
TensorDimsStrides() {}
TensorDimsStrides(int spatial_dim, const miopen::TensorDescriptor& desc)
{
std::tie(n_batchs, n_outputs, depth, height, width) =
miopen::GetNCDHW(spatial_dim, desc.GetLengths());
std::tie(n_stride, c_stride, d_stride, h_stride, w_stride) =
miopen::GetNCDHW(spatial_dim, desc.GetStrides());
}
};
struct PoolingConfig
{
int method;
int pad_d;
int stride_d;
int size_d;
int pad_h;
int stride_h;
int size_h;
int pad_w;
int stride_w;
int size_w;
PoolingConfig() {}
PoolingConfig(const int method_,
const int pad_d_,
const int stride_d_,
const int size_d_,
const int pad_h_,
const int stride_h_,
const int size_h_,
const int pad_w_,
const int stride_w_,
const int size_w_)
{
method = method_;
pad_d = pad_d_;
stride_d = stride_d_;
size_d = size_d_;
pad_h = pad_h_;
stride_h = stride_h_;
size_h = size_h_;
pad_w = pad_w_;
stride_w = stride_w_;
size_w = size_w_;
}
};
template <bool is_mt = false, typename Tgpu_, typename Tcheck_, typename Index, typename Tmatch_>
void fwd_pooling_compute_verify(const TensorDimsStrides& bot_dims_strides,
const TensorDimsStrides& top_dims_strides,
const PoolingConfig& poolConf,
Tmatch_& match,
const Tgpu_* bot_ptr,
const Tgpu_* top_ptr,
const size_t b,
const size_t o,
const std::array<int, 5>& mask_strides,
const bool do_backward,
const int index_position,
const Tcheck_ MAX_VAL,
const Tgpu_ G_MAX_VAL,
size_t* mask_ptr,
Index* mask_gpu,
const Tcheck_ allowedEps,
pooling_math_stats& stats,
std::optional<std::reference_wrapper<std::mutex>> stats_mutex)
{
if constexpr(is_mt) // checks when running with multiple threads
{
static_assert(std::is_same<Tmatch_, std::atomic_bool>::value == true,
"'match' has to be std::atomic_bool when running in multi-threaded mode");
if(!stats_mutex.has_value())
{
MIOPEN_THROW(
"'std::mutex' is needed as last parameter when running in multi-threaded mode");
}
}
Tcheck_ res_init = (poolConf.method == MLO_POOLING_OP_MAX) ? -MAX_VAL : static_cast<Tcheck_>(0);
Tcheck_ res = static_cast<Tcheck_>(0);
size_t bot_idx_off = b * bot_dims_strides.n_stride + o * bot_dims_strides.c_stride;
size_t top_idx_off = b * top_dims_strides.n_stride + o * top_dims_strides.c_stride;
size_t mask_gpu_idx_off = b * mask_strides[N] + o * mask_strides[C];
size_t total_pool_size = poolConf.size_w * poolConf.size_h * poolConf.size_d;
double max_err = 0.0;
int max_num_flops_per_res = 0;
for(int k = 0; k < top_dims_strides.depth; k++)
{
for(int j = 0; j < top_dims_strides.height; j++)
{
for(int i = 0; i < top_dims_strides.width; i++)
{
// c-emulator
res = res_init;
int num_flops_per_res = 0;
int dstart = k * poolConf.stride_d - poolConf.pad_d;
int hstart = j * poolConf.stride_h - poolConf.pad_h;
int wstart = i * poolConf.stride_w - poolConf.pad_w;
int dend = std::min(dstart + poolConf.size_d, bot_dims_strides.depth);
int hend = std::min(hstart + poolConf.size_h, bot_dims_strides.height);
int wend = std::min(wstart + poolConf.size_w, bot_dims_strides.width);
dstart = std::max(dstart, 0);
hstart = std::max(hstart, 0);
wstart = std::max(wstart, 0);
int pool_size = (poolConf.method == MLO_POOLING_OP_AVE)
? ((dend - dstart) * (hend - hstart) * (wend - wstart))
: total_pool_size;
pool_size = (pool_size == 0) ? 1 : pool_size;
size_t res_index = 0;
size_t res_index_gpu = 0;
bool found = false;
for(int d = dstart; d < dend; ++d)
{
for(int h = hstart; h < hend; ++h)
{
for(int w = wstart; w < wend; ++w)
{
size_t bot_index = bot_idx_off + d * bot_dims_strides.d_stride +
h * bot_dims_strides.h_stride +
w * bot_dims_strides.w_stride;
if(poolConf.method == MLO_POOLING_OP_MAX)
{
if(static_cast<Tcheck_>(bot_ptr[bot_index]) > res)
{
res = static_cast<Tcheck_>(bot_ptr[bot_index]);
res_index = bot_index;
res_index_gpu =
index_position == 1
? (d * bot_dims_strides.height *
bot_dims_strides.width +
h * bot_dims_strides.width + w)
: ((d - k * poolConf.stride_d + poolConf.pad_d) *
poolConf.size_w * poolConf.size_h) +
((h - j * poolConf.stride_h + poolConf.pad_h) *
poolConf.size_w) +
(w - i * poolConf.stride_w + poolConf.pad_w);
found = true;
}
}
else if(poolConf.method == MLO_POOLING_OP_AVE ||
poolConf.method == MLO_POOLING_OP_AVE_INCLUSIVE)
{
#if MLO_POOLING_EMULATE_VALIDATION_FAILURE
if(num_flops_per_res % MLO_POOLING_EMULATE_VALIDATION_FAILURE != 0)
#endif
res += static_cast<Tcheck_>(bot_ptr[bot_index]);
++num_flops_per_res;
}
else
{
std::cout << "ERROR: unknown operator : layer: pooling."
<< std::endl;
match = false;
return;
}
}
}
}
// special index value is used to mark top points which has no associated
// bottom
// points
if(!found)
{
res_index = std::numeric_limits<size_t>::max();
res_index_gpu = std::numeric_limits<uint8_t>::max();
}
size_t top_index = top_idx_off + k * top_dims_strides.d_stride +
j * top_dims_strides.h_stride + i * top_dims_strides.w_stride;
size_t mask_gpu_index = mask_gpu_idx_off + k * mask_strides[D] +
j * mask_strides[H] + i * mask_strides[W];
if(poolConf.method == MLO_POOLING_OP_MAX)
{
// the case with the odd input, the even kernel size and 2*pad == kernel
// size
mask_ptr[top_index] = res_index;
if(do_backward)
{
size_t mg = mask_gpu[mask_gpu_index];
if(mg != res_index_gpu)
{
std::cout << "Mask mismatch, gpu " << mg << " cpu " << res_index_gpu
<< "(" << res_index << ")" << std::endl;
match = false;
}
}
}
if(poolConf.method == MLO_POOLING_OP_AVE ||
poolConf.method == MLO_POOLING_OP_AVE_INCLUSIVE)
{
res /= pool_size;
++num_flops_per_res;
}
Tcheck_ c_val = (res == -MAX_VAL) ? 0 : res;
Tgpu_ gg_val = (top_ptr[top_index]);
gg_val = (gg_val == (-G_MAX_VAL)) ? static_cast<Tgpu_>(0) : gg_val;
Tcheck_ g_val(gg_val);
double err = std::abs(c_val - g_val);
if(err > allowedEps || std::isnan(c_val) || std::isnan(g_val) ||
!std::isfinite(c_val) || !std::isfinite(g_val))
{
std::cout << "Difference " << err << " too large (> " << allowedEps << ") at {"
<< b << ',' << o << ',' << j << ',' << i << "}, cpu_val = " << c_val
<< " vs gpu_val = " << g_val << std::endl;
std::cout << "Number of flops used: " << num_flops_per_res
<< ", pool_size: " << pool_size << std::endl;
match = false;
}
if constexpr(is_mt)
{
max_err = err > max_err ? err : max_err;
max_num_flops_per_res = num_flops_per_res > max_num_flops_per_res
? num_flops_per_res
: max_num_flops_per_res;
}
else
{
if(err > stats.max_error)
stats.max_error = err;
if(num_flops_per_res > stats.max_num_flops_per_res)
stats.max_num_flops_per_res = num_flops_per_res;
}
}
}
}
if constexpr(is_mt)
{
const std::lock_guard<std::mutex> lock(stats_mutex.value());
if(max_err > stats.max_error)
{
stats.max_error = max_err;
}
if(max_num_flops_per_res > stats.max_num_flops_per_res)
{
stats.max_num_flops_per_res = max_num_flops_per_res;
}
}
};
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
typename Tcheck_ /* the data type used in CPU checkings (usually double) */,
typename Index>
bool mloPoolingForwardRunHostAndVerify(PoolingConfig poolConf,
const miopenTensorDescriptor_t& bot_,
const miopenTensorDescriptor_t& top_,
const Tgpu_* bot_ptr,
const Tgpu_* top_ptr,
bool do_backward,
size_t* mask_ptr,
Index* mask_gpu,
Tcheck_ allowedEps,
pooling_math_stats& stats,
int index_position = 1)
{
const miopen::TensorDescriptor& bot = miopen::deref(bot_);
const miopen::TensorDescriptor& top = miopen::deref(top_);
const auto spatial_dim = bot.GetLengths().size() - 2;
TensorDimsStrides bot_dims_strides(spatial_dim, bot);
TensorDimsStrides top_dims_strides(spatial_dim, top);
// Mask data is always NCDHW
std::array<int, 5> mask_strides;
mask_strides[W] = 1;
mask_strides[H] = mask_strides[W] * top_dims_strides.width;
mask_strides[D] = mask_strides[H] * top_dims_strides.height;
mask_strides[C] = mask_strides[D] * top_dims_strides.depth;
mask_strides[N] = mask_strides[C] * bot_dims_strides.n_outputs;
bool match = true;
Tcheck_ MAX_VAL(3.402823466e+38);
Tgpu_ G_MAX_VAL = std::numeric_limits<Tgpu_>::max();
for(int b = 0; b < bot_dims_strides.n_batchs && match; b++)
{
for(int o = 0; o < bot_dims_strides.n_outputs && match; o++)
{
fwd_pooling_compute_verify(bot_dims_strides,
top_dims_strides,
poolConf,
match,
bot_ptr,
top_ptr,
b,
o,
mask_strides,
do_backward,
index_position,
MAX_VAL,
G_MAX_VAL,
mask_ptr,
mask_gpu,
allowedEps,
stats,
std::nullopt); // for mutex used in mt implementation
}
}
return (match);
}
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
typename Tcheck_ /* the data type used in CPU checkings (usually double) */,
typename Index>
bool mloPoolingForwardRunHostAndVerify_mt(PoolingConfig poolConf,
const miopenTensorDescriptor_t& bot_,
const miopenTensorDescriptor_t& top_,
const Tgpu_* bot_ptr,
const Tgpu_* top_ptr,
bool do_backward,
size_t* mask_ptr,
Index* mask_gpu,
Tcheck_ allowedEps,
pooling_math_stats& stats,
int index_position = 1)
{
const miopen::TensorDescriptor& bot = miopen::deref(bot_);
const miopen::TensorDescriptor& top = miopen::deref(top_);
const auto spatial_dim = bot.GetLengths().size() - 2;
TensorDimsStrides bot_dims_strides(spatial_dim, bot);
TensorDimsStrides top_dims_strides(spatial_dim, top);
// Mask data is always NCDHW
std::array<int, 5> mask_strides;
mask_strides[W] = 1;
mask_strides[H] = mask_strides[W] * top_dims_strides.width;
mask_strides[D] = mask_strides[H] * top_dims_strides.height;
mask_strides[C] = mask_strides[D] * top_dims_strides.depth;
mask_strides[N] = mask_strides[C] * bot_dims_strides.n_outputs;
std::atomic_bool match = true;
Tcheck_ MAX_VAL(3.402823466e+38);
Tgpu_ G_MAX_VAL = std::numeric_limits<Tgpu_>::max();
std::mutex stats_mutex;
miopen::par_ford(bot_dims_strides.n_batchs, bot_dims_strides.n_outputs)([&](int b, int o) {
fwd_pooling_compute_verify<true>(bot_dims_strides,
top_dims_strides,
poolConf,
match,
bot_ptr,
top_ptr,
b,
o,
mask_strides,
do_backward,
index_position,
MAX_VAL,
G_MAX_VAL,
mask_ptr,
mask_gpu,
allowedEps,
stats,
stats_mutex);
});
return (match);
}
template <bool is_mt = false, typename Tgpu_, typename Tcheck_>
void bwd_pooling_compute(const TensorDimsStrides& bot_dims_strides,
const TensorDimsStrides& top_dims_strides,
const PoolingConfig& poolConf,
Tcheck_* bot_df_v_ptr, // the code assumes that bot_df_v_ptr was zeroed
const Tgpu_* top_df_ptr,
size_t b,
size_t o,
const size_t* mask_ptr,
std::vector<int>& num_flops)
{
int bot_df_v_off = b * bot_dims_strides.n_stride + o * bot_dims_strides.c_stride;
int top_df_off = b * top_dims_strides.n_stride + o * top_dims_strides.c_stride;
if(poolConf.method == MLO_POOLING_OP_MAX)
{
for(int k = 0; k < top_dims_strides.depth; k++)
{
for(int j = 0; j < top_dims_strides.height; j++)
{
for(int i = 0; i < top_dims_strides.width; i++)
{
size_t top_idx = top_df_off + k * top_dims_strides.d_stride +
j * top_dims_strides.h_stride + i * top_dims_strides.w_stride;
size_t bot_idx = mask_ptr[top_idx];
// skip top points that don't have associated bottom points
if(bot_idx == std::numeric_limits<size_t>::max())
continue;
if constexpr(is_mt)
{
std::atomic_ref<Tcheck_>(bot_df_v_ptr[bot_idx])
.fetch_add(static_cast<Tcheck_>(top_df_ptr[top_idx]));
std::atomic_ref<int>(num_flops[bot_idx])++;
}
else
{
bot_df_v_ptr[bot_idx] += static_cast<Tcheck_>(top_df_ptr[top_idx]);
++num_flops[bot_idx];
}
}
}
}
}
else if(poolConf.method == MLO_POOLING_OP_AVE ||
poolConf.method == MLO_POOLING_OP_AVE_INCLUSIVE)
{
for(int k = 0; k < bot_dims_strides.depth; k++)
{
for(int j = 0; j < bot_dims_strides.height; j++)
{
for(int i = 0; i < bot_dims_strides.width; i++)
{
// c-emulator
const auto bot_idx = bot_df_v_off + k * bot_dims_strides.d_stride +
j * bot_dims_strides.h_stride +
i * bot_dims_strides.w_stride;
bot_df_v_ptr[bot_idx] = static_cast<Tcheck_>(0);
num_flops[bot_idx] = 0;
int d = k + poolConf.pad_d;
int h = j + poolConf.pad_h;
int w = i + poolConf.pad_w;
int pdstart =
(d < poolConf.size_d) ? 0 : (d - poolConf.size_d) / poolConf.stride_d + 1;
int pdend = std::min(d / poolConf.stride_d + 1, top_dims_strides.depth);
int phstart =
(h < poolConf.size_h) ? 0 : (h - poolConf.size_h) / poolConf.stride_h + 1;
int phend = std::min(h / poolConf.stride_h + 1, top_dims_strides.height);
int pwstart =
(w < poolConf.size_w) ? 0 : (w - poolConf.size_w) / poolConf.stride_w + 1;
int pwend = std::min(w / poolConf.stride_w + 1, top_dims_strides.width);
Tcheck_ gradient = static_cast<Tcheck_>(0);
int gradient_n_flops = 0;
for(int pd = pdstart; pd < pdend; ++pd)
{
for(int ph = phstart; ph < phend; ++ph)
{
for(int pw = pwstart; pw < pwend; ++pw)
{
// figure out the pooling size
int dstart = pd * poolConf.stride_d - poolConf.pad_d;
int hstart = ph * poolConf.stride_h - poolConf.pad_h;
int wstart = pw * poolConf.stride_w - poolConf.pad_w;
int dend =
std::min(dstart + poolConf.size_d, bot_dims_strides.depth);
int hend =
std::min(hstart + poolConf.size_h, bot_dims_strides.height);
int wend =
std::min(wstart + poolConf.size_w, bot_dims_strides.width);
dstart = std::max(dstart, 0);
hstart = std::max(hstart, 0);
wstart = std::max(wstart, 0);
int pool_size;
if(poolConf.method == MLO_POOLING_OP_AVE)
pool_size =
((dend - dstart) * (hend - hstart) * (wend - wstart) == 0)
? 1
: (dend - dstart) * (hend - hstart) * (wend - wstart);
else
pool_size =
(poolConf.size_w * poolConf.size_h * poolConf.size_d == 0)
? 1
: poolConf.size_w * poolConf.size_h * poolConf.size_d;
const auto top_idx = top_df_off + pd * top_dims_strides.d_stride +
ph * top_dims_strides.h_stride +
pw * top_dims_strides.w_stride;
gradient += static_cast<Tcheck_>(top_df_ptr[top_idx]) /
static_cast<Tcheck_>(pool_size);
gradient_n_flops += 2; // pool_size is computed using
// integer ops, do not count those.
}
}
}
bot_df_v_ptr[bot_idx] = gradient;
num_flops[bot_idx] = gradient_n_flops;
}
}
}
}
else
{
std::cout << "ERROR: unknown operator : layer: pooling back-propagation." << std::endl;
return;
}
}
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
typename Tcheck_ /* the data type used in CPU checkings (usually double) */>
void mloPoolingBackwardRunHost(
PoolingConfig poolConf,
const miopenTensorDescriptor_t& bot_df_,
const miopenTensorDescriptor_t& top_df_,
Tcheck_* bot_df_v_ptr, // the code assumes that bot_df_v_ptr was zeroed
const Tgpu_* top_df_ptr,
const size_t* mask_ptr,
pooling_math_stats& stats)
{
const miopen::TensorDescriptor& bot_df = miopen::deref(bot_df_);
const miopen::TensorDescriptor& top_df = miopen::deref(top_df_);
const auto spatial_dim = bot_df.GetLengths().size() - 2;
TensorDimsStrides bot_dims_strides(spatial_dim, bot_df);
TensorDimsStrides top_dims_strides(spatial_dim, top_df);
std::vector<int> num_flops(bot_df.GetElementSize(), 0);
for(int b = 0; b < bot_dims_strides.n_batchs; b++)
{
for(int o = 0; o < bot_dims_strides.n_outputs; o++)
{
bwd_pooling_compute(bot_dims_strides,
top_dims_strides,
poolConf,
bot_df_v_ptr,
top_df_ptr,
b,
o,
mask_ptr,
num_flops);
}
}
stats.max_num_flops_per_res = *(std::max_element(num_flops.begin(), num_flops.end()));
}
template <typename Tgpu_ /* the data type used in GPU computations (usually half) */,
typename Tcheck_ /* the data type used in CPU checkings (usually double) */>
void mloPoolingBackwardRunHost_mt(
PoolingConfig poolConf,
const miopenTensorDescriptor_t& bot_df_,
const miopenTensorDescriptor_t& top_df_,
Tcheck_* bot_df_v_ptr, // the code assumes that bot_df_v_ptr was zeroed
const Tgpu_* top_df_ptr,
const size_t* mask_ptr,
pooling_math_stats& stats)
{
const miopen::TensorDescriptor& bot_df = miopen::deref(bot_df_);
const miopen::TensorDescriptor& top_df = miopen::deref(top_df_);
const auto spatial_dim = bot_df.GetLengths().size() - 2;
TensorDimsStrides bot_dims_strides(spatial_dim, bot_df);
TensorDimsStrides top_dims_strides(spatial_dim, top_df);
std::vector<int> num_flops(bot_df.GetElementSize(), 0);
miopen::par_ford(bot_dims_strides.n_batchs, bot_dims_strides.n_outputs)([&](int b, int o) {
bwd_pooling_compute<true>(bot_dims_strides,
top_dims_strides,
poolConf,
bot_df_v_ptr,
top_df_ptr,
b,
o,
mask_ptr,
num_flops);
});
stats.max_num_flops_per_res = *(std::max_element(num_flops.begin(), num_flops.end()));
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif