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

932 lines
35 KiB
C++

/*******************************************************************************
*
* MIT License
*
* Copyright (c) 2019 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 GUARD_MIOPEN_TEST_POOLING_COMMON_HPP
#define GUARD_MIOPEN_TEST_POOLING_COMMON_HPP
#include "test.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <limits>
#include <memory>
#include <miopen/logger.hpp>
#include <miopen/miopen.h>
#include <miopen/pooling.hpp>
#include <miopen/stringutils.hpp>
#include <miopen/tensor.hpp>
#include <miopen/tensor_layout.hpp>
#include <utility>
// #include "network_data.hpp"
#include "driver.hpp"
#include "get_handle.hpp"
#include "tensor_holder.hpp"
#include "verify.hpp"
#include "cpu_conv.hpp"
#include "workspace.hpp"
#define TEST_PADDING_MODE 0
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
static int num_uint16_case = 0;
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
static int num_uint32_case = 0;
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
static int num_uint32_case_imgidx = 0;
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
static int num_uint64_case = 0;
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
static int num_uint64_case_imgidx = 0;
static inline void print(const miopen::PoolingDescriptor& filter)
{
std::cout << "Pooling: ";
if(filter.GetMode() == miopenPoolingAverage)
std::cout << "Average";
else if(filter.GetMode() == miopenPoolingAverageInclusive)
std::cout << "AverageInclusive";
else
std::cout << "Max";
std::cout << std::endl;
std::cout << "Lengths: ";
miopen::LogRange(std::cout, filter.GetLengths(), ", ") << std::endl;
std::cout << "Pads: ";
miopen::LogRange(std::cout, filter.GetPads(), ", ") << std::endl;
std::cout << "Strides: ";
miopen::LogRange(std::cout, filter.GetStrides(), ", ") << std::endl;
}
template <class T>
tensor<T> get_output_tensor(const miopen::PoolingDescriptor& filter, const tensor<T>& input)
{
return tensor<T>{filter.GetForwardOutputTensor(input.desc)};
}
template <class T>
struct pooling_operators
{
miopen::PoolingDescriptor filter;
pooling_operators(miopen::PoolingDescriptor f) : filter(f) {}
double start() const
{
if(filter.GetMode() == miopenPoolingMax)
return std::numeric_limits<T>::lowest();
else
return 0.0;
}
double operator()(double x, double y) const
{
if(filter.GetMode() == miopenPoolingMax)
{
double m = std::max(x, y);
return (m);
}
else
{
return x + y;
}
}
double final(double x, double y)
{
if(filter.GetMode() == miopenPoolingMax)
return (x);
else
return x / y;
}
};
template <int SptDim>
struct verify_forward_pooling
{
template <class T, class Index>
tensor<T>
cpu(const tensor<T>& input, const miopen::PoolingDescriptor& filter, std::vector<Index>&) const
{
auto out = get_output_tensor(filter, input);
const auto in_strides = input.desc.GetStrides();
const std::size_t in_n_stride = in_strides[0];
const std::size_t in_c_stride = in_strides[1];
std::array<std::size_t, SptDim> in_spatial_strides{};
std::copy_n(in_strides.begin() + 2, SptDim, in_spatial_strides.begin());
const auto out_strides = out.desc.GetStrides();
const std::size_t out_n_stride = out_strides[0];
const std::size_t out_c_stride = out_strides[1];
std::array<std::size_t, SptDim> out_spatial_strides{};
std::copy_n(out_strides.begin() + 2, SptDim, out_spatial_strides.begin());
const T* input_ptr = input.data.data();
T* out_ptr = out.data.data();
std::array<int, SptDim> in_dim{};
std::copy_n(input.desc.GetLengths().begin() + 2, SptDim, in_dim.begin());
std::array<int, SptDim> strides{};
std::copy_n(filter.GetStrides().begin(), SptDim, strides.begin());
std::array<int, SptDim> pads{};
std::copy_n(filter.GetPads().begin(), SptDim, pads.begin());
std::array<int, SptDim> kers{};
std::copy_n(filter.GetLengths().begin(), SptDim, kers.begin());
auto op = pooling_operators<T>{filter};
int b_n = out.desc.GetLengths()[0];
int k_n = out.desc.GetLengths()[1];
std::array<int, SptDim> out_spatial_len{};
std::copy_n(out.desc.GetLengths().begin() + 2, SptDim, out_spatial_len.begin());
auto par_ford_out =
miopen::unpacker(miopen::prepender(miopen::par_ford, b_n, k_n))(out_spatial_len);
par_ford_out([&](int o, int w, auto... out_spatial_id_pack) {
auto out_spatial_id = make_array(out_spatial_id_pack...);
std::array<int, SptDim> start_idx{};
std::array<int, SptDim> win_sz{};
for(int i = 0; i < SptDim; ++i)
{
start_idx[i] = out_spatial_id[i] * strides[i] - pads[i];
int end_idx = start_idx[i] + kers[i];
end_idx = std::min(end_idx, in_dim[i]);
start_idx[i] = std::max(start_idx[i], 0);
win_sz[i] = std::max(end_idx - start_idx[i], 0);
}
int pool_size =
filter.GetMode() == miopenPoolingAverageInclusive
? std::accumulate(kers.begin(), kers.end(), 1, std::multiplies<int>())
: std::accumulate(win_sz.begin(), win_sz.end(), 1, std::multiplies<int>());
pool_size = std::max(pool_size, 1); // Avoid division by zero when window is in padding
double acc = op.start();
miopen::unpacker(miopen::ford)(win_sz)([&](auto... in_spatial_id_pack) {
auto in_spatial_id = make_array(in_spatial_id_pack...);
std::array<std::size_t, SptDim + 2> idx{};
idx[0] = o;
idx[1] = w;
bool in_cmp_idx = true;
for(int i = 0; i < SptDim; ++i)
{
idx[i + 2] = start_idx[i] + in_spatial_id[i];
in_cmp_idx &= (in_dim[i] > idx[i + 2]);
}
if(in_cmp_idx)
{
// Compute input linear index
std::size_t in_linear_idx = o * in_n_stride + w * in_c_stride;
for(int i = 0; i < SptDim; ++i)
{
in_linear_idx += idx[i + 2] * in_spatial_strides[i];
}
acc = op(acc, input_ptr[in_linear_idx]);
}
});
// Compute output linear index
std::size_t out_linear_idx = o * out_n_stride + w * out_c_stride;
for(int i = 0; i < SptDim; ++i)
{
out_linear_idx += out_spatial_id[i] * out_spatial_strides[i];
}
out_ptr[out_linear_idx] = T(op.final(acc, pool_size));
});
return out;
}
template <class T, class Index>
tensor<T> gpu(const tensor<T>& input,
const miopen::PoolingDescriptor& filter,
std::vector<Index>& indices) const
{
auto&& handle = get_handle();
auto out = get_output_tensor(filter, input);
indices.resize(out.data.size(), 0);
auto in_dev = handle.Write(input.data);
auto out_dev = handle.Create<T>(out.data.size());
Workspace wspace{};
wspace.Write(indices);
float alpha = 1, beta = 0;
filter.Forward(handle,
&alpha,
input.desc,
in_dev.get(),
&beta,
out.desc,
out_dev.get(),
true,
wspace.ptr(),
wspace.size());
indices = wspace.Read<std::vector<Index>>();
out.data = handle.Read<T>(out_dev, out.data.size());
return out;
}
template <class T, class Index>
void fail(float,
const tensor<T>& input,
const miopen::PoolingDescriptor& filter,
const std::vector<Index>&) const
{
std::cout << "Forward ";
print(filter);
std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
std::cout << "Output tensor: " << filter.GetForwardOutputTensor(input.desc).ToString()
<< std::endl;
}
};
template <int SptDim>
struct verify_backward_pooling
{
template <class T, class Index>
tensor<T> cpu(const tensor<T>& input,
const tensor<T>& dout,
const tensor<T>& out,
const miopen::PoolingDescriptor& filter,
const std::vector<Index>& indices,
bool use_global_index,
bool verify_index) const
{
auto dinput = input;
std::vector<double> din_vec(input.desc.GetElementSpace(), 0.0);
CHECK(dout.desc == out.desc);
const auto in_strides = input.desc.GetStrides();
const std::size_t in_n_stride = in_strides[0];
const std::size_t in_c_stride = in_strides[1];
std::array<std::size_t, SptDim> in_spatial_strides{};
std::copy_n(in_strides.begin() + 2, SptDim, in_spatial_strides.begin());
const auto out_strides = dout.desc.GetStrides();
const std::size_t out_n_stride = out_strides[0];
const std::size_t out_c_stride = out_strides[1];
std::array<std::size_t, SptDim> out_spatial_strides{};
std::copy_n(out_strides.begin() + 2, SptDim, out_spatial_strides.begin());
const T* input_ptr = input.data.data();
const T* dout_ptr = dout.data.data();
const T* out_ptr = out.data.data();
std::array<int, SptDim + 2> in_dim{};
std::copy_n(input.desc.GetLengths().begin(), SptDim + 2, in_dim.begin());
std::array<int, SptDim + 2> in_str{};
std::copy_n(input.desc.GetStrides().begin(), SptDim + 2, in_str.begin());
std::array<int, SptDim> strides{};
std::copy_n(filter.GetStrides().begin(), SptDim, strides.begin());
std::array<int, SptDim> pads{};
std::copy_n(filter.GetPads().begin(), SptDim, pads.begin());
std::array<int, SptDim> kers{};
std::copy_n(filter.GetLengths().begin(), SptDim, kers.begin());
auto ford_ker = miopen::unpacker(miopen::ford)(kers);
int out_n = out.desc.GetLengths()[0];
int out_c = out.desc.GetLengths()[1];
std::array<int, SptDim> out_spatial_len{};
std::copy_n(out.desc.GetLengths().begin() + 2, SptDim, out_spatial_len.begin());
auto ford_out = miopen::unpacker(miopen::ford)(out_spatial_len);
miopen::par_ford(out_n, out_c)([&](int o, int w) {
if(filter.GetMode() == miopenPoolingMax)
{
ford_out([&](auto... out_spatial_id_pack) {
auto mx_idx = indices.at(dout.desc.GetIndex(o, w, out_spatial_id_pack...));
std::array<std::size_t, SptDim + 2> idx{};
bool in_cmp_idx = true;
if(use_global_index)
{
auto total_spatial = std::accumulate(
in_dim.begin() + 2, in_dim.end(), 1ULL, std::multiplies<std::size_t>());
in_cmp_idx = (mx_idx < total_spatial);
auto out_spatial_id = make_array(out_spatial_id_pack...);
for(int i = 0; i < SptDim && in_cmp_idx; i++)
{
int win_start = out_spatial_id[i] * strides[i] - pads[i];
int win_end = win_start + kers[i] - 1;
if(win_end < 0 || win_start >= in_dim[i + 2])
{
in_cmp_idx = false;
}
}
for(int i = 0; i < SptDim; i++)
{
std::size_t mx_idx_dim = mx_idx;
mx_idx_dim /= std::accumulate(in_dim.begin() + i + 3,
in_dim.end(),
1ULL,
std::multiplies<std::size_t>());
mx_idx_dim %= in_dim[i + 2];
idx[i + 2] = mx_idx_dim;
}
}
else
{
auto out_spatial_id = make_array(out_spatial_id_pack...);
for(int i = 0; i < SptDim; i++)
{
int mx_idx_dim = mx_idx;
mx_idx_dim /= std::accumulate(
kers.begin() + i + 1, kers.end(), 1, std::multiplies<int>());
mx_idx_dim %= kers[i];
mx_idx_dim += (out_spatial_id[i] * strides[i] - pads[i]);
in_cmp_idx &= (in_dim[i + 2] > mx_idx_dim && mx_idx_dim >= 0);
idx[i + 2] = std::size_t(mx_idx_dim);
}
}
if(in_cmp_idx)
{
idx[0] = o;
idx[1] = w;
if(verify_index)
{
// Compute input and output linear indices for verification
std::size_t in_verify_idx = o * in_n_stride + w * in_c_stride;
auto out_spatial_id_verify = make_array(out_spatial_id_pack...);
std::size_t out_verify_idx = o * out_n_stride + w * out_c_stride;
for(int i = 0; i < SptDim; ++i)
{
in_verify_idx += idx[i + 2] * in_spatial_strides[i];
out_verify_idx += out_spatial_id_verify[i] * out_spatial_strides[i];
}
CHECK(miopen::float_equal(input_ptr[in_verify_idx],
out_ptr[out_verify_idx]));
}
std::size_t din_idx = 0;
for(int i = 0; i < SptDim + 2; i++)
{
din_idx += idx[i] * in_str[i];
}
// Compute dout linear index
auto out_spatial_id = make_array(out_spatial_id_pack...);
std::size_t dout_linear_idx = o * out_n_stride + w * out_c_stride;
for(int i = 0; i < SptDim; ++i)
{
dout_linear_idx += out_spatial_id[i] * out_spatial_strides[i];
}
din_vec.at(din_idx) += dout_ptr[dout_linear_idx];
}
});
}
else
{
ford_out([&](auto... out_spatial_id_pack) {
auto out_spatial_id = make_array(out_spatial_id_pack...);
std::array<int, SptDim> start_idx{};
std::array<int, SptDim> win_sz{};
for(int i = 0; i < SptDim; ++i)
{
start_idx[i] = out_spatial_id[i] * strides[i] - pads[i];
int end_idx = start_idx[i] + kers[i];
end_idx = std::min(end_idx, in_dim[i + 2]);
win_sz[i] = end_idx - std::max(start_idx[i], 0);
win_sz[i] = std::max(win_sz[i], 0);
}
int pool_size =
filter.GetMode() == miopenPoolingAverageInclusive
? std::accumulate(kers.begin(), kers.end(), 1, std::multiplies<int>())
: std::accumulate(
win_sz.begin(), win_sz.end(), 1, std::multiplies<int>());
pool_size = std::max(pool_size, 1); // Avoid division by zero
ford_ker([&](auto... ker_id_pack) {
auto ker_id = make_array(ker_id_pack...);
bool in_cmp_idx = true;
std::array<int, SptDim + 2> in_idx{};
in_idx[0] = o;
in_idx[1] = w;
for(int i = 0; i < SptDim; ++i)
{
in_idx[i + 2] = start_idx[i] + ker_id[i];
in_cmp_idx &= (in_dim[i + 2] > in_idx[i + 2] && in_idx[i + 2] >= 0);
}
if(in_cmp_idx)
{
std::size_t din_idx = 0;
for(int i = 0; i < SptDim + 2; i++)
{
din_idx += in_idx[i] * in_str[i];
}
// Compute dout linear index
std::size_t dout_linear_idx = o * out_n_stride + w * out_c_stride;
for(int i = 0; i < SptDim; ++i)
{
dout_linear_idx += out_spatial_id[i] * out_spatial_strides[i];
}
din_vec.at(din_idx) +=
static_cast<double>(dout_ptr[dout_linear_idx]) / pool_size;
}
});
});
}
});
miopen::unpacker(miopen::ford)(in_dim)([&](auto... in_id_pack) {
auto in_id = make_array(in_id_pack...);
std::size_t din_idx = 0;
for(int i = 0; i < SptDim + 2; i++)
{
din_idx += in_id[i] * in_str[i];
}
dinput(in_id_pack...) = din_vec.at(din_idx);
});
return dinput;
}
template <class T, class Index>
tensor<T> gpu(const tensor<T>& input,
const tensor<T>& dout,
const tensor<T>& out,
const miopen::PoolingDescriptor& filter,
const std::vector<Index>& indices,
bool,
bool) const
{
auto&& handle = get_handle();
auto dinput = input;
auto in_dev = handle.Write(input.data);
auto dout_dev = handle.Write(dout.data);
auto out_dev = handle.Write(out.data);
auto din_dev = handle.Create<T>(dinput.data.size());
Workspace wspace{};
wspace.Write(indices);
float alpha = 1, beta = 0;
filter.Backward(handle,
&alpha,
// y
out.desc,
out_dev.get(),
// dy
dout.desc,
dout_dev.get(),
// x
input.desc,
in_dev.get(),
&beta,
// dx
dinput.desc,
din_dev.get(),
wspace.ptr());
dinput.data = handle.Read<T>(din_dev, dinput.data.size());
return dinput;
}
template <class T, class Index>
void fail(float,
const tensor<T>& input,
const tensor<T>&,
const tensor<T>& out,
const miopen::PoolingDescriptor& filter,
const std::vector<Index>&,
bool,
bool) const
{
std::cout << "Backward ";
print(filter);
std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
std::cout << "Output tensor: " << out.desc.ToString() << std::endl;
}
};
template <class T>
struct pooling_driver : test_driver
{
miopen::PoolingDescriptor filter;
std::vector<int> in_shape;
std::vector<int> lens;
std::vector<int> pads;
std::vector<int> strides;
std::string index_type;
std::string mode;
#if TEST_PADDING_MODE == 1
std::string pmode;
#endif
int verify_indices{};
int wsidx{};
std::string in_layout;
std::unordered_map<std::string, miopenIndexType_t> index_type_lookup = {
{miopen::ToUpper("miopenIndexUint8"), miopenIndexUint8},
{miopen::ToUpper("miopenIndexUint16"), miopenIndexUint16},
{miopen::ToUpper("miopenIndexUint32"), miopenIndexUint32},
{miopen::ToUpper("miopenIndexUint64"), miopenIndexUint64},
};
std::unordered_map<std::string, miopenPoolingMode_t> mode_lookup = {
{"MAX", miopenPoolingMax},
{"MIOPENPOOLINGMAX", miopenPoolingMax},
{"AVERAGE", miopenPoolingAverage},
{"MIOPENPOOLINGAVERAGE", miopenPoolingAverage},
{"AVERAGEINCLUSIVE", miopenPoolingAverageInclusive},
{"MIOPENPOOLINGAVERAGEINCLUSIVE", miopenPoolingAverageInclusive},
};
#if TEST_PADDING_MODE == 1
std::unordered_map<std::string, miopenPaddingMode_t> pmode_lookup = {
{"DEFAULT", miopenPaddingDefault},
{"SAME", miopenPaddingSame},
{"VALID", miopenPaddingValid},
};
#endif
pooling_driver()
{
add(index_type,
"index_type",
generate_multi_data<const char*>( //
{{"miopenIndexUint8",
"miopenIndexUint16",
"miopenIndexUint32",
"miopenIndexUint64"}, //
{"miopenIndexUint8", "miopenIndexUint32"}, //
{"miopenIndexUint32"}} //
));
add(mode,
"mode",
generate_data(
{"miopenPoolingMax", "miopenPoolingAverage", "miopenPoolingAverageInclusive"}));
#if TEST_PADDING_MODE == 1
add(pmode, "pmode", generate_data({"default", "same", "valid"}));
#endif
add(verify_indices, "verify_indices", generate_data({1}));
add(in_layout, "in_layout", generate_data({"NCHW"}));
}
template <class Index, int SptDim>
void run_impl()
{
std::vector<Index> indices{};
auto input = tensor<T>{in_shape};
// Set up tensor descriptor with correct layout BEFORE generating data
if(in_layout != "NCHW" && in_layout != "NCDHW")
{
const std::vector<std::size_t> dim_lens = input.desc.GetLengths();
std::vector<std::size_t> dim_strides;
miopen::tensor_layout_to_strides(
dim_lens,
miopen::tensor_layout_get_default(input.desc.GetNumDims()),
in_layout,
dim_strides);
input.desc = miopen::TensorDescriptor(miopen_type<T>{}, dim_lens, dim_strides);
}
input.generate(tensor_elem_gen_integer{
(miopen_type<T>{} == miopenHalf || miopen_type<T>{} == miopenBFloat16) ? 5 : 17});
auto out = verify(verify_forward_pooling<SptDim>{}, input, filter, indices);
auto dout = out.first;
dout.generate(tensor_elem_gen_integer{2503});
verify(verify_backward_pooling<SptDim>{},
input,
dout,
out.first,
filter,
indices,
wsidx != 0,
static_cast<bool>(this->verify_indices));
}
void run()
{
auto idx_typ = index_type_lookup.at(miopen::ToUpper(index_type));
auto idx_sz = sizeof(uint8_t);
int spt_dim = in_shape.size() - 2;
const bool skip_many_configs_with_non_int8_index =
(dataset_id == 0) && full_set; // Otherwise the default dataset takes too much time.
const bool wide_dataset = (dataset_id == 2) && full_set;
filter = miopen::PoolingDescriptor{mode_lookup.at(miopen::ToUpper(mode)),
#if TEST_PADDING_MODE == 1
pmode_lookup.at(miopen::ToUpper(pmode)),
#else
miopenPaddingDefault,
#endif
lens,
strides,
pads};
filter.SetIndexType(idx_typ);
filter.SetWorkspaceIndexMode(miopenPoolingWorkspaceIndexMode_t(wsidx));
if(wsidx == 0 && spt_dim == 3 && filter.GetMode() == miopenPoolingMax && full_set)
{
show_command();
std::cout << "Warning: Config skipped. Workspace index mask mode is not implemented "
"yet in 3D max pooling solvers."
<< std::endl;
return;
}
if(wsidx == 0 && spt_dim == 2 && filter.GetMode() == miopenPoolingMax && wide_dataset)
{
show_command();
std::cout << "Warning: Config skipped. Workspace index mask mode is not implemented "
"yet in 2D max backward solvers that support wide pooling window."
<< std::endl;
return;
}
if(wsidx == 0 &&
(filter.GetMode() == miopenPoolingAverage ||
filter.GetMode() == miopenPoolingAverageInclusive) &&
full_set)
{
show_command();
std::cout << "Warning: Config skipped. Workspace index modes are irrelevant for "
"Average pooling. "
"In order to optimize performance of full tests, we "
"skip average pooling configs when (wsidx == 0). "
"Please make sure that dataset includes counterparts with (wsidx == 1)."
<< std::endl;
return;
}
switch(idx_typ)
{
/// The "index is too small" limitation is an approximation
/// of the real limitation, and therefore applied only when
/// the "full test" is ran. See:
/// \ref max_pooling_index_max_restriction
case miopenIndexUint8: {
if((spt_dim == 3 || (spt_dim == 2 && wsidx == 1)) && full_set &&
filter.GetMode() == miopenPoolingMax)
{
show_command();
std::cout << "Warning: Config skipped: uint8 index is too small "
"(spt_dim == 3 || (spt_dim == 2 && wsidx == 1)) "
"&& filter.GetMode() == miopenPoolingMax"
<< std::endl;
return;
}
break;
}
case miopenIndexUint16: {
if((spt_dim == 3 || (spt_dim == 2 && wsidx == 1)) && full_set &&
filter.GetMode() == miopenPoolingMax)
{
show_command();
std::cout << "Warning: Config skipped: uint16 index is too small "
"(spt_dim == 3 || (spt_dim == 2 && wsidx == 1)) "
"&& filter.GetMode() == miopenPoolingMax"
<< std::endl;
return;
}
if(skip_many_configs_with_non_int8_index)
{
// test_pooling_test --all only test 5 uint16 cases
if(num_uint16_case > 5)
{
show_command();
std::cout << "Warning: Config skipped for the default dataset to speed "
"up testing (num_uint16_case > 5)"
<< std::endl;
return;
}
++num_uint16_case;
}
idx_sz = sizeof(uint16_t);
break;
}
case miopenIndexUint32: {
if(skip_many_configs_with_non_int8_index)
{
// test_pooling_test --all only test 5 uint32 cases
if(wsidx == 0)
{
if(num_uint32_case > 5)
{
show_command();
std::cout << "Warning: Config skipped for the default dataset to speed up "
"testing (wsidx == 0 && num_uint32_case > 5)"
<< std::endl;
return;
}
++num_uint32_case;
}
else
{
if(num_uint32_case_imgidx > 5)
{
show_command();
std::cout << "Warning: Config skipped for the default dataset to speed up "
"testing (wsidx != 0 && num_uint32_case_imgidx > 5)"
<< std::endl;
return;
}
++num_uint32_case_imgidx;
}
}
idx_sz = sizeof(uint32_t);
break;
}
case miopenIndexUint64: {
if(skip_many_configs_with_non_int8_index)
{
if(wsidx == 0)
{
if(num_uint64_case > 5)
{
show_command();
std::cout << "Warning: Config skipped for the default dataset to speed up "
"testing (wsidx == 0) && (num_uint64_case > 5)"
<< std::endl;
return;
}
++num_uint64_case;
}
else
{
if(num_uint64_case_imgidx > 5 && spt_dim == 2)
{
show_command();
std::cout << "Warning: Config skipped to speed up testing of the "
"default dataset (wsidx != 0) && (num_uint64_case_imgidx > 5 "
"&& spt_dim == 2)"
<< std::endl;
return;
}
++num_uint64_case_imgidx;
}
}
idx_sz = sizeof(uint64_t);
break;
}
}
auto input_desc = miopen::TensorDescriptor(this->type, in_shape);
if(spt_dim != 2 && spt_dim != 3)
{
show_command();
std::cout << "Warning: Config skipped becuse it is not supported " //
"(spt_dim != 2 && spt_dim != 3)"
<< std::endl;
return;
}
for(int i = 0; i < spt_dim; i++)
{
if(lens[i] > (input_desc.GetLengths()[i + 2] + static_cast<uint64_t>(2) * pads[i]))
{
show_command();
std::cout << "Warning: Config skipped becuse it is invalid "
"(lens[i] > (input_desc.GetLengths()[i + 2] + 2 * pads[i]))"
<< std::endl;
return;
}
}
if(full_set)
{
auto output_desc = filter.GetForwardOutputTensor(input_desc);
size_t total_mem =
3 * input_desc.GetNumBytes() + output_desc.GetNumBytes() +
idx_sz * output_desc.GetElementSize(); // estimate based on backward pass
size_t device_mem = get_handle().GetGlobalMemorySize();
if(total_mem >= device_mem)
{
show_command();
std::cout << "Config skipped because it requires " << total_mem
<< " Bytes to write all necessary tensors to GPU. GPU has " << device_mem
<< " Bytes of memory." << std::endl;
return;
}
}
std::vector<int> in_dim(input_desc.GetLengths().begin() + 2, input_desc.GetLengths().end());
std::vector<int> out_dim(spt_dim);
std::vector<int> ker_dim(filter.GetLengths().begin(), filter.GetLengths().end());
#if TEST_PADDING_MODE == 1
if(filter.pmode == miopenPaddingSame)
{
if(std::any_of(filter.GetStrides().begin(), filter.GetStrides().end(), [](int i) {
return i == 0;
}))
return;
for(int i = 0; i < spt_dim; i++)
{
filter.pads[i] =
((in_dim[i] % filter.GetStrides()[i] == 0)
? (std::max((ker_dim[i] - filter.GetStrides()[i]), 0))
: (std::max((ker_dim[i] - (in_dim[i] % filter.GetStrides()[i])), 0))) /
2;
out_dim[i] = std::ceil(static_cast<double>(in_dim[i]) / filter.strides[i]);
}
if(std::any_of(out_dim.begin(), out_dim.end(), [](int i) { return i <= 0; }))
return;
}
else if(filter.pmode == miopenPaddingValid)
{
if(std::any_of(filter.GetStrides().begin(), filter.GetStrides().end(), [](int i) {
return i == 0;
}))
return;
for(int i = 0; i < spt_dim; i++)
{
filter.pads[i] = 0;
out_dim[i] = std::ceil(static_cast<double>(in_dim[i] - filter.lens[i] + 1) /
filter.strides[i]);
}
if(std::any_of(out_dim.begin(), out_dim.end(), [](int i) { return i <= 0; }))
return;
}
#endif
switch(filter.GetIndexType())
{
case miopenIndexUint8: {
if(spt_dim == 3)
{
run_impl<uint8_t, 3>();
}
else
{
run_impl<uint8_t, 2>();
}
break;
}
case miopenIndexUint16: {
if(spt_dim == 3)
{
run_impl<uint16_t, 3>();
}
else
{
run_impl<uint16_t, 2>();
}
break;
}
case miopenIndexUint32: {
if(spt_dim == 3)
{
run_impl<uint32_t, 3>();
}
else
{
run_impl<uint32_t, 2>();
}
break;
}
case miopenIndexUint64: {
if(spt_dim == 3)
{
run_impl<uint64_t, 3>();
}
else
{
run_impl<uint64_t, 2>();
}
break;
}
}
}
};
#endif