mirror of
https://github.com/ROCm/composable_kernel.git
synced 2026-05-14 02:02:46 +00:00
[CK] Integrate GPU reference into ckProfiler for convolutions (#3379)
Refactor and integrate CK GPU references into ckProfiler.
- All convolution layouts and groupings supported for all three directions
- Unit tests verifying GPU and CPU reference is the same
- Support added to profiler (do_verification = 2 enables GPU reference)
- One profiler-based test per direction changed to GPU reference to demonstrate usag
Closes AICK-427
[ROCm/composable_kernel commit: bb8445dca8]
This commit is contained in:
@@ -131,6 +131,9 @@ template <ck::index_t NDimSpatial,
|
||||
typename WeiElementOp,
|
||||
typename OutElementOp,
|
||||
typename DeviceConvNDFwdInstance,
|
||||
typename InLayout,
|
||||
typename WeiLayout,
|
||||
typename OutLayout,
|
||||
typename ComputeDataType = OutDataType>
|
||||
bool run_grouped_conv_fwd(int do_verification,
|
||||
int init_method,
|
||||
@@ -283,31 +286,25 @@ bool run_grouped_conv_fwd(int do_verification,
|
||||
DeviceMem out_device_ref_buf(sizeof(OutDataType) * out_device.mDesc.GetElementSpaceSize());
|
||||
out_device_ref_buf.SetZero();
|
||||
|
||||
// Extract dimensions using helper function
|
||||
ck::ref::ConvDims dims = ck::utils::conv::extract_conv_dims(conv_param, NDimSpatial);
|
||||
|
||||
// Launch GPU reference kernel
|
||||
constexpr ck::index_t block_size = 256;
|
||||
const ck::long_index_t output_length = dims.N * dims.Do * dims.Ho * dims.Wo * dims.K;
|
||||
const ck::index_t grid_size = (output_length + block_size - 1) / block_size;
|
||||
|
||||
auto gpu_ref_kernel = ck::ref::naive_conv_fwd_ndhwc_kzyxc_ndhwk<InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
ComputeDataType,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>;
|
||||
|
||||
gpu_ref_kernel<<<dim3(grid_size), dim3(block_size), 0, nullptr>>>(
|
||||
// Call GPU reference with ConvParam directly, using the correct layout types
|
||||
ck::ref::naive_conv_fwd<InLayout,
|
||||
WeiLayout,
|
||||
OutLayout,
|
||||
InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>(
|
||||
reinterpret_cast<const InDataType*>(in_device_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<const WeiDataType*>(wei_device_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<OutDataType*>(out_device_ref_buf.GetDeviceBuffer()),
|
||||
dims);
|
||||
conv_param);
|
||||
|
||||
HIP_CHECK_ERROR(hipDeviceSynchronize());
|
||||
|
||||
std::cout << "GPU reference kernel completed successfully, copying results..." << std::endl;
|
||||
std::cout << "GPU reference function completed successfully, copying results..."
|
||||
<< std::endl;
|
||||
|
||||
// Copy GPU reference result to host
|
||||
out_device_ref_buf.FromDevice(out_host.mData.data());
|
||||
|
||||
@@ -12,7 +12,7 @@ bool run_convnd_fwd_example(int argc, char* argv[])
|
||||
{
|
||||
print_helper_msg();
|
||||
|
||||
int do_verification = 1; // 0=no, 1=CPU, 2=GPU
|
||||
int do_verification = 2; // 0=no, 1=CPU, 2=GPU
|
||||
int init_method = 1;
|
||||
bool time_kernel = false;
|
||||
|
||||
@@ -71,6 +71,9 @@ bool run_convnd_fwd_example(int argc, char* argv[])
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceGroupedConvNDFwdInstance<ndim_spatial_value, InLayout, WeiLayout, OutLayout>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout,
|
||||
ComputeDataType>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#include "ck/library/utility/convolution_host_tensor_descriptor_helper.hpp"
|
||||
#include "ck/library/reference_tensor_operation/cpu/reference_conv_bwd_data.hpp"
|
||||
#include "ck/library/reference_tensor_operation/gpu/naive_conv_bwd_data_gpu.hpp"
|
||||
#include "ck_tile/host/hip_check_error.hpp"
|
||||
#include "ck/library/utility/algorithm.hpp"
|
||||
#include "ck/host_utility/hip_check_error.hpp"
|
||||
|
||||
using ::ck::DeviceMem;
|
||||
using ::ck::HostTensorDescriptor;
|
||||
@@ -81,7 +82,10 @@ template <ck::index_t NDimSpatial,
|
||||
typename InElementOp,
|
||||
typename WeiElementOp,
|
||||
typename OutElementOp,
|
||||
typename DeviceConvNdBwdDataInstance>
|
||||
typename DeviceConvNdBwdDataInstance,
|
||||
typename InLayout,
|
||||
typename WeiLayout,
|
||||
typename OutLayout>
|
||||
int run_conv_bwd_data(int do_verification,
|
||||
int init_method,
|
||||
bool time_kernel,
|
||||
@@ -225,50 +229,52 @@ int run_conv_bwd_data(int do_verification,
|
||||
}
|
||||
else if(do_verification == 2)
|
||||
{
|
||||
// GPU verification
|
||||
// GPU verification using naive GPU reference
|
||||
std::cout << "Running GPU verification..." << std::endl;
|
||||
|
||||
// Allocate and ZERO GPU memory for reference input
|
||||
DeviceMem in_device_ref_buf(sizeof(InDataType) * in_device.mDesc.GetElementSpaceSize());
|
||||
in_device_ref_buf.SetZero();
|
||||
|
||||
// Extract dimensions using helper function
|
||||
ck::ref::ConvDims dims = ck::utils::conv::extract_conv_dims(conv_param, NDimSpatial);
|
||||
|
||||
constexpr ck::index_t block_size = 256;
|
||||
const ck::long_index_t input_length = dims.N * dims.Di * dims.Hi * dims.Wi * dims.C;
|
||||
const ck::index_t grid_size = (input_length + block_size - 1) / block_size;
|
||||
|
||||
auto gpu_ref_kernel = ck::ref::naive_conv_bwd_data_ndhwc_kzyxc_ndhwk<InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
float,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>;
|
||||
|
||||
gpu_ref_kernel<<<dim3(grid_size), dim3(block_size), 0, nullptr>>>(
|
||||
// Call GPU reference with ConvParam directly, using the correct layout types
|
||||
ck::ref::naive_conv_bwd_data<InLayout,
|
||||
WeiLayout,
|
||||
OutLayout,
|
||||
InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>(
|
||||
reinterpret_cast<InDataType*>(in_device_ref_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<const WeiDataType*>(wei_device_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<const OutDataType*>(out_device_buf.GetDeviceBuffer()),
|
||||
dims);
|
||||
conv_param,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
|
||||
HIP_CHECK_ERROR(hipDeviceSynchronize());
|
||||
|
||||
std::cout << "GPU reference kernel completed, copying results..." << std::endl;
|
||||
std::cout << "GPU reference function completed successfully, copying results..."
|
||||
<< std::endl;
|
||||
|
||||
// Copy GPU reference result
|
||||
// Copy GPU reference result to host
|
||||
Tensor<InDataType> in_gpu_ref(in_host.mDesc);
|
||||
in_device_ref_buf.FromDevice(in_gpu_ref.mData.data());
|
||||
|
||||
// Copy optimized kernel result
|
||||
// Copy GPU kernel result to host
|
||||
in_device_buf.FromDevice(in_device.mData.data());
|
||||
|
||||
std::cout << "Comparing GPU kernel output vs GPU reference..." << std::endl;
|
||||
|
||||
// Compare: Optimized kernel result vs GPU reference result
|
||||
bool pass = ck::utils::check_err(in_device,
|
||||
in_gpu_ref,
|
||||
"Error: Incorrect results!",
|
||||
get_rtol<InDataType, float>(),
|
||||
get_atol<InDataType, float>());
|
||||
|
||||
std::cout << "GPU verification result is:" << (pass ? "correct" : "fail") << std::endl;
|
||||
|
||||
return pass ? 0 : 1;
|
||||
|
||||
@@ -92,16 +92,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<1>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<1>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
else if(conv_param.num_dim_spatial_ == 2)
|
||||
{
|
||||
@@ -128,16 +131,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<2>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<2>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
else if(conv_param.num_dim_spatial_ == 3)
|
||||
{
|
||||
@@ -164,16 +170,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<3>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<3>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -119,16 +119,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<1>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<1>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
else if(conv_param.num_dim_spatial_ == 2)
|
||||
{
|
||||
@@ -155,16 +158,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<2>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<2>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
else if(conv_param.num_dim_spatial_ == 3)
|
||||
{
|
||||
@@ -191,16 +197,19 @@ int main(int argc, char* argv[])
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp,
|
||||
DeviceConvNdBwdDataInstance<3>>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
DeviceConvNdBwdDataInstance<3>,
|
||||
InLayout,
|
||||
WeiLayout,
|
||||
OutLayout>(do_verification,
|
||||
init_method,
|
||||
time_kernel,
|
||||
conv_param,
|
||||
in_g_n_c_wis_desc,
|
||||
wei_g_k_c_xs_desc,
|
||||
out_g_n_k_wos_desc,
|
||||
in_element_op,
|
||||
wei_element_op,
|
||||
out_element_op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -149,55 +149,53 @@ bool run_grouped_conv_bwd_weight(const ExecutionConfig& config,
|
||||
}
|
||||
else if(config.do_verification == 2)
|
||||
{
|
||||
// GPU verification (only supports G=1, standard convolution)
|
||||
if(conv_param.G_ != 1)
|
||||
{
|
||||
std::cout << "GPU verification only supports G=1 (standard convolution)" << std::endl;
|
||||
std::cout << "Current G=" << conv_param.G_ << " not supported." << std::endl;
|
||||
std::cout << "Use do_verification=1 for CPU verification with grouped convolution."
|
||||
<< std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cout << "Running GPU verification (G=1)..." << std::endl;
|
||||
// GPU verification using naive GPU reference
|
||||
std::cout << "Running GPU verification..." << std::endl;
|
||||
|
||||
// Allocate and ZERO GPU memory for reference weights
|
||||
DeviceMem wei_device_ref_buf(sizeof(WeiDataType) *
|
||||
wei_device_result.mDesc.GetElementSpaceSize());
|
||||
wei_device_ref_buf.SetZero();
|
||||
|
||||
// Extract dimensions using helper function (G=1, standard convolution)
|
||||
ck::ref::ConvDims dims = ck::utils::conv::extract_conv_dims(conv_param, NDimSpatial, false);
|
||||
// Call GPU reference function with ConvParam and layout types
|
||||
using InLayout = InputLayout<NDimSpatial>;
|
||||
using WeiLayout = WeightLayout<NDimSpatial>;
|
||||
using OutLayout = OutputLayout<NDimSpatial>;
|
||||
|
||||
constexpr ck::index_t block_size = 256;
|
||||
const ck::long_index_t weight_length = dims.K * dims.Z * dims.Y * dims.X * dims.C;
|
||||
const ck::index_t grid_size = (weight_length + block_size - 1) / block_size;
|
||||
|
||||
auto gpu_ref_kernel = ck::ref::naive_conv_bwd_weight_ndhwc_kzyxc_ndhwk<InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
float,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>;
|
||||
|
||||
gpu_ref_kernel<<<dim3(grid_size), dim3(block_size), 0, nullptr>>>(
|
||||
ck::ref::naive_conv_bwd_weight<InLayout,
|
||||
WeiLayout,
|
||||
OutLayout,
|
||||
InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>(
|
||||
reinterpret_cast<const InDataType*>(in_device_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<WeiDataType*>(wei_device_ref_buf.GetDeviceBuffer()),
|
||||
reinterpret_cast<const OutDataType*>(out_device_buf.GetDeviceBuffer()),
|
||||
dims);
|
||||
conv_param);
|
||||
|
||||
HIP_CHECK_ERROR(hipDeviceSynchronize());
|
||||
|
||||
std::cout << "GPU reference kernel completed, copying results..." << std::endl;
|
||||
std::cout << "GPU reference function completed successfully, copying results..."
|
||||
<< std::endl;
|
||||
|
||||
// Copy GPU reference result to host
|
||||
wei_device_ref_buf.FromDevice(wei_host_result.mData.data());
|
||||
|
||||
// Copy GPU kernel result to host
|
||||
wei_device_buf.FromDevice(wei_device_result.mData.data());
|
||||
|
||||
std::cout << "Comparing GPU kernel output vs GPU reference..." << std::endl;
|
||||
|
||||
// Compare: Optimized kernel result vs GPU reference result
|
||||
bool pass = ck::utils::check_err(wei_device_result.mData,
|
||||
wei_host_result.mData,
|
||||
"Error: Incorrect results!",
|
||||
get_rtol<WeiDataType, float>(),
|
||||
get_atol<WeiDataType, float>());
|
||||
|
||||
std::cout << "GPU verification result is:" << (pass ? "correct" : "fail") << std::endl;
|
||||
|
||||
return pass;
|
||||
|
||||
@@ -1,353 +0,0 @@
|
||||
// Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Standalone test program for Old CK GPU references
|
||||
// Tests naive_conv_fwd (existing) and future backward ops
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ck/ck.hpp"
|
||||
#include "ck/tensor_operation/gpu/element/element_wise_operation.hpp"
|
||||
#include "ck/library/utility/check_err.hpp"
|
||||
#include "ck/library/utility/device_memory.hpp"
|
||||
#include "ck/library/utility/host_tensor.hpp"
|
||||
#include "ck/library/utility/host_tensor_generator.hpp"
|
||||
|
||||
// CPU reference for validation
|
||||
#include "ck/library/reference_tensor_operation/cpu/reference_conv_fwd.hpp"
|
||||
|
||||
// GPU reference (OLD CK - already exists!)
|
||||
#include "ck/library/reference_tensor_operation/gpu/naive_conv_fwd_gpu.hpp"
|
||||
|
||||
using namespace ck;
|
||||
|
||||
template <index_t NDimSpatial>
|
||||
struct ConvParams
|
||||
{
|
||||
index_t N, K, C;
|
||||
std::vector<index_t> input_spatial;
|
||||
std::vector<index_t> filter_spatial;
|
||||
std::vector<index_t> output_spatial;
|
||||
std::vector<index_t> strides;
|
||||
std::vector<index_t> dilations;
|
||||
std::vector<index_t> pads;
|
||||
};
|
||||
|
||||
template <index_t NDimSpatial, typename InDataType, typename WeiDataType, typename OutDataType>
|
||||
bool test_conv_forward_gpu_ref(const ConvParams<NDimSpatial>& params, const std::string& test_name)
|
||||
{
|
||||
std::cout << "[TEST] " << test_name << std::endl;
|
||||
|
||||
// Calculate dimensions
|
||||
const index_t N = params.N;
|
||||
const index_t K = params.K;
|
||||
const index_t C = params.C;
|
||||
|
||||
// Create tensor descriptors (NDHWC layout for old CK)
|
||||
std::vector<index_t> in_lengths = {N};
|
||||
for(auto d : params.input_spatial)
|
||||
in_lengths.push_back(d);
|
||||
in_lengths.push_back(C);
|
||||
|
||||
std::vector<index_t> wei_lengths = {K};
|
||||
for(auto d : params.filter_spatial)
|
||||
wei_lengths.push_back(d);
|
||||
wei_lengths.push_back(C);
|
||||
|
||||
std::vector<index_t> out_lengths = {N};
|
||||
for(auto d : params.output_spatial)
|
||||
out_lengths.push_back(d);
|
||||
out_lengths.push_back(K);
|
||||
|
||||
// Create host tensors
|
||||
Tensor<InDataType> input(in_lengths);
|
||||
Tensor<WeiDataType> weight(wei_lengths);
|
||||
Tensor<OutDataType> output_gpu(out_lengths);
|
||||
Tensor<OutDataType> output_ref(out_lengths);
|
||||
|
||||
// Initialize with random data
|
||||
input.GenerateTensorValue(GeneratorTensor_2<InDataType>{-5, 5});
|
||||
weight.GenerateTensorValue(GeneratorTensor_2<WeiDataType>{-5, 5});
|
||||
|
||||
// Allocate device memory
|
||||
DeviceMem input_dev(input.mData.size() * sizeof(InDataType));
|
||||
DeviceMem weight_dev(weight.mData.size() * sizeof(WeiDataType));
|
||||
DeviceMem output_dev(output_gpu.mData.size() * sizeof(OutDataType));
|
||||
|
||||
// Copy to device
|
||||
input_dev.ToDevice(input.mData.data());
|
||||
weight_dev.ToDevice(weight.mData.data());
|
||||
|
||||
// Run CPU reference for validation
|
||||
auto ref_conv =
|
||||
tensor_operation::host::ReferenceConvFwd<NDimSpatial,
|
||||
InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
tensor_operation::element_wise::PassThrough,
|
||||
tensor_operation::element_wise::PassThrough,
|
||||
tensor_operation::element_wise::PassThrough>();
|
||||
|
||||
auto ref_invoker = ref_conv.MakeInvoker();
|
||||
auto ref_arg = ref_conv.MakeArgument(input.mData.data(),
|
||||
weight.mData.data(),
|
||||
output_ref.mData.data(),
|
||||
N,
|
||||
K,
|
||||
C,
|
||||
params.input_spatial,
|
||||
params.filter_spatial,
|
||||
params.output_spatial,
|
||||
params.strides,
|
||||
params.dilations,
|
||||
params.pads,
|
||||
params.pads,
|
||||
{},
|
||||
{},
|
||||
{});
|
||||
|
||||
ref_invoker.Run(ref_arg);
|
||||
|
||||
// Run GPU reference (OLD CK)
|
||||
using InElementOp = tensor_operation::element_wise::PassThrough;
|
||||
using WeiElementOp = tensor_operation::element_wise::PassThrough;
|
||||
using OutElementOp = tensor_operation::element_wise::PassThrough;
|
||||
|
||||
constexpr index_t block_size = 256;
|
||||
|
||||
// Extract dimensions based on NDimSpatial
|
||||
index_t Di = 1, Hi = 1, Wi = 1;
|
||||
index_t Z = 1, Y = 1, X = 1;
|
||||
index_t Do = 1, Ho = 1, Wo = 1;
|
||||
index_t stride_z = 1, stride_y = 1, stride_x = 1;
|
||||
index_t dilation_z = 1, dilation_y = 1, dilation_x = 1;
|
||||
index_t pad_z = 0, pad_y = 0, pad_x = 0;
|
||||
|
||||
if(NDimSpatial == 1)
|
||||
{
|
||||
Wi = params.input_spatial[0];
|
||||
X = params.filter_spatial[0];
|
||||
Wo = params.output_spatial[0];
|
||||
stride_x = params.strides[0];
|
||||
dilation_x = params.dilations[0];
|
||||
pad_x = params.pads[0];
|
||||
}
|
||||
else if(NDimSpatial == 2)
|
||||
{
|
||||
Hi = params.input_spatial[0];
|
||||
Wi = params.input_spatial[1];
|
||||
Y = params.filter_spatial[0];
|
||||
X = params.filter_spatial[1];
|
||||
Ho = params.output_spatial[0];
|
||||
Wo = params.output_spatial[1];
|
||||
stride_y = params.strides[0];
|
||||
stride_x = params.strides[1];
|
||||
dilation_y = params.dilations[0];
|
||||
dilation_x = params.dilations[1];
|
||||
pad_y = params.pads[0];
|
||||
pad_x = params.pads[1];
|
||||
}
|
||||
else if(NDimSpatial == 3)
|
||||
{
|
||||
Di = params.input_spatial[0];
|
||||
Hi = params.input_spatial[1];
|
||||
Wi = params.input_spatial[2];
|
||||
Z = params.filter_spatial[0];
|
||||
Y = params.filter_spatial[1];
|
||||
X = params.filter_spatial[2];
|
||||
Do = params.output_spatial[0];
|
||||
Ho = params.output_spatial[1];
|
||||
Wo = params.output_spatial[2];
|
||||
stride_z = params.strides[0];
|
||||
stride_y = params.strides[1];
|
||||
stride_x = params.strides[2];
|
||||
dilation_z = params.dilations[0];
|
||||
dilation_y = params.dilations[1];
|
||||
dilation_x = params.dilations[2];
|
||||
pad_z = params.pads[0];
|
||||
pad_y = params.pads[1];
|
||||
pad_x = params.pads[2];
|
||||
}
|
||||
|
||||
// Launch GPU reference kernel
|
||||
const long_index_t output_length = N * Do * Ho * Wo * K;
|
||||
const index_t grid_size = (output_length + block_size - 1) / block_size;
|
||||
|
||||
hipLaunchKernelGGL(ref::naive_conv_fwd_ndhwc_kzyxc_ndhwk<InDataType,
|
||||
WeiDataType,
|
||||
OutDataType,
|
||||
float,
|
||||
InElementOp,
|
||||
WeiElementOp,
|
||||
OutElementOp>,
|
||||
dim3(grid_size),
|
||||
dim3(block_size),
|
||||
0,
|
||||
nullptr,
|
||||
reinterpret_cast<const InDataType*>(input_dev.GetDeviceBuffer()),
|
||||
reinterpret_cast<const WeiDataType*>(weight_dev.GetDeviceBuffer()),
|
||||
reinterpret_cast<OutDataType*>(output_dev.GetDeviceBuffer()),
|
||||
N,
|
||||
K,
|
||||
C,
|
||||
Di,
|
||||
Hi,
|
||||
Wi,
|
||||
Z,
|
||||
Y,
|
||||
X,
|
||||
Do,
|
||||
Ho,
|
||||
Wo,
|
||||
stride_z,
|
||||
stride_y,
|
||||
stride_x,
|
||||
dilation_z,
|
||||
dilation_y,
|
||||
dilation_x,
|
||||
pad_z,
|
||||
pad_y,
|
||||
pad_x);
|
||||
|
||||
hipDeviceSynchronize();
|
||||
|
||||
// Copy result back
|
||||
output_dev.FromDevice(output_gpu.mData.data());
|
||||
|
||||
// Compare GPU ref vs CPU ref
|
||||
bool pass = check_err(output_gpu.mData, output_ref.mData, "GPU vs CPU ref", 1e-3, 1e-3);
|
||||
|
||||
std::cout << " Result: " << (pass ? "✅ PASS" : "❌ FAIL") << std::endl;
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << "Old CK GPU Reference Test Program" << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// Test 1: 2D Conv, FP16, Small
|
||||
{
|
||||
ConvParams<2> params;
|
||||
params.N = 2;
|
||||
params.K = 8;
|
||||
params.C = 8;
|
||||
params.input_spatial = {7, 7};
|
||||
params.filter_spatial = {3, 3};
|
||||
params.output_spatial = {5, 5};
|
||||
params.strides = {1, 1};
|
||||
params.dilations = {1, 1};
|
||||
params.pads = {0, 0};
|
||||
|
||||
if(test_conv_forward_gpu_ref<2, half_t, half_t, half_t>(params, "2D-FP16-Small"))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
}
|
||||
|
||||
// Test 2: 2D Conv, FP32, Medium
|
||||
{
|
||||
ConvParams<2> params;
|
||||
params.N = 4;
|
||||
params.K = 16;
|
||||
params.C = 16;
|
||||
params.input_spatial = {14, 14};
|
||||
params.filter_spatial = {3, 3};
|
||||
params.output_spatial = {12, 12};
|
||||
params.strides = {1, 1};
|
||||
params.dilations = {1, 1};
|
||||
params.pads = {0, 0};
|
||||
|
||||
if(test_conv_forward_gpu_ref<2, float, float, float>(params, "2D-FP32-Medium"))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
}
|
||||
|
||||
// Test 3: 1D Conv, FP16
|
||||
{
|
||||
ConvParams<1> params;
|
||||
params.N = 2;
|
||||
params.K = 8;
|
||||
params.C = 8;
|
||||
params.input_spatial = {16};
|
||||
params.filter_spatial = {3};
|
||||
params.output_spatial = {14};
|
||||
params.strides = {1};
|
||||
params.dilations = {1};
|
||||
params.pads = {0};
|
||||
|
||||
if(test_conv_forward_gpu_ref<1, half_t, half_t, half_t>(params, "1D-FP16"))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
}
|
||||
|
||||
// Test 4: 3D Conv, FP16, Small
|
||||
{
|
||||
ConvParams<3> params;
|
||||
params.N = 1;
|
||||
params.K = 8;
|
||||
params.C = 8;
|
||||
params.input_spatial = {5, 5, 5};
|
||||
params.filter_spatial = {3, 3, 3};
|
||||
params.output_spatial = {3, 3, 3};
|
||||
params.strides = {1, 1, 1};
|
||||
params.dilations = {1, 1, 1};
|
||||
params.pads = {0, 0, 0};
|
||||
|
||||
if(test_conv_forward_gpu_ref<3, half_t, half_t, half_t>(params, "3D-FP16-Small"))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
}
|
||||
|
||||
// Test 5: 2D Conv with stride
|
||||
{
|
||||
ConvParams<2> params;
|
||||
params.N = 2;
|
||||
params.K = 8;
|
||||
params.C = 8;
|
||||
params.input_spatial = {8, 8};
|
||||
params.filter_spatial = {3, 3};
|
||||
params.output_spatial = {3, 3};
|
||||
params.strides = {2, 2};
|
||||
params.dilations = {1, 1};
|
||||
params.pads = {0, 0};
|
||||
|
||||
if(test_conv_forward_gpu_ref<2, half_t, half_t, half_t>(params, "2D-FP16-Stride2"))
|
||||
passed++;
|
||||
else
|
||||
failed++;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << "SUMMARY" << std::endl;
|
||||
std::cout << "========================================" << std::endl;
|
||||
std::cout << "Total: " << (passed + failed) << std::endl;
|
||||
std::cout << "Passed: " << passed << " ✅" << std::endl;
|
||||
std::cout << "Failed: " << failed << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
if(failed == 0)
|
||||
{
|
||||
std::cout << "🎉 ALL TESTS PASSED!" << std::endl;
|
||||
std::cout << "Old CK Forward GPU Reference: WORKING ✅" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "❌ SOME TESTS FAILED" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user