Files
TheRock/rocm-libraries/projects/miopen/test/gtest/softmax_find20.cpp
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

446 lines
17 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.
*
*******************************************************************************/
#include "random.hpp"
#include "test.hpp"
#include "get_handle.hpp"
#include "tensor_holder.hpp"
#include "../driver/mloSoftmaxHost.hpp"
#include "verify.hpp"
#include <miopen/softmax.hpp>
#include <miopen/miopen.h>
#include <miopen/solution.hpp>
#include <gtest/gtest.h>
#include <vector>
using namespace miopen;
template <typename T = float, typename Tref = double>
class SoftmaxFind20Test
{
public:
SoftmaxFind20Test(bool forward,
miopenSoftmaxAlgorithm_t softmax_algo_arg,
miopenSoftmaxMode_t softmax_mode_arg)
: problem(nullptr),
softmax_algo(softmax_algo_arg),
softmax_mode(softmax_mode_arg),
isForward(forward)
{
Initialize();
}
void AddTensorDescriptors()
{
std::cerr << "Creating softmax tensor descriptors..." << std::endl;
auto test_set_tensor_descriptor = [this](miopenTensorArgumentId_t name,
TensorDescriptor& desc) {
EXPECT_EQUAL(miopenSetProblemTensorDescriptor(problem, name, &desc),
miopenStatusSuccess);
};
if(isForward)
{
test_set_tensor_descriptor(miopenTensorSoftmaxX, xTensor.desc);
test_set_tensor_descriptor(miopenTensorSoftmaxY, yTensor.desc);
}
else
{
test_set_tensor_descriptor(miopenTensorSoftmaxY, yTensor.desc);
test_set_tensor_descriptor(miopenTensorSoftmaxDY, dyTensor.desc);
test_set_tensor_descriptor(miopenTensorSoftmaxDX, dxTensor.desc);
}
std::cerr << "Created softmax tensor descriptors." << std::endl;
}
std::vector<miopenSolution_t> TestFindSolutions(Handle& handle)
{
std::cerr << "Testing miopenFindSolutions..." << std::endl;
auto solutions = std::vector<miopenSolution_t>{};
std::size_t found;
// We expect to get only 1 or 2 solutions for softmax for now. Hardcode value 16 as just big
// enough value
solutions.resize(16);
EXPECT_EQUAL(miopenFindSolutions(
&handle, problem, nullptr, solutions.data(), &found, solutions.size()),
miopenStatusSuccess);
EXPECT_TRUE(found > 0);
solutions.resize(found);
std::cerr << "Finished testing miopenFindSolutions." << std::endl;
return solutions;
}
void TestSolutionAttributes(const std::vector<miopenSolution_t>& solutions)
{
std::cerr << "Testing miopenGetSolution<Attribute>..." << std::endl;
for(const auto& solution : solutions)
{
float time;
std::size_t workspace_size;
uint64_t solver_id;
EXPECT_EQUAL(miopenGetSolutionTime(solution, &time), miopenStatusSuccess);
EXPECT_EQUAL(miopenGetSolutionWorkspaceSize(solution, &workspace_size),
miopenStatusSuccess);
EXPECT_EQUAL(miopenGetSolutionSolverId(solution, &solver_id), miopenStatusSuccess);
}
std::cerr << "Finished testing miopenGetSolution<Attribute>." << std::endl;
}
void TestRunSolutionsForward(Handle& handle, const std::vector<miopenSolution_t>& solutions)
{
std::cerr << "Testing solution functions..." << std::endl;
miopenTensorDescriptor_t x_desc = &xTensor.desc, y_desc = &yTensor.desc;
const unsigned int numTensors = 2;
for(const auto& solution : solutions)
{
auto arguments = std::make_unique<miopenTensorArgument_t[]>(numTensors);
auto in_gpu = handle.Write(xTensor.data);
auto out_gpu = handle.Write(yTensor.data);
miopenTensorArgumentId_t names[numTensors] = {miopenTensorSoftmaxX,
miopenTensorSoftmaxY};
void* buffers[numTensors] = {in_gpu.get(), out_gpu.get()};
miopenTensorDescriptor_t descriptors[numTensors] = {x_desc, y_desc};
for(auto i = 0; i < numTensors; ++i)
{
arguments[i].id = names[i];
arguments[i].descriptor = &descriptors[i];
arguments[i].buffer = buffers[i];
}
std::cerr << "Run a solution." << std::endl;
EXPECT_EQUAL(
miopenRunSolution(&handle, solution, numTensors, arguments.get(), nullptr, 0),
miopenStatusSuccess);
float alpha = softmax_descriptor.GetAlpha();
float beta = softmax_descriptor.GetBeta();
// tensor<T> yTensorDup = yTensor;
tensor<T> yTensorRef = tensor<T>{test_n, test_c, test_h, test_w};
auto out_gpu_ref = handle.Write(yTensorRef.data);
// Run softmax in a usual way (which is tested) and compare results
EXPECT_EQUAL(miopenSoftmaxForward_V2(&handle,
&alpha,
x_desc,
in_gpu.get(),
&beta,
&yTensorRef.desc,
out_gpu_ref.get(),
softmax_descriptor.GetAlgorithm(),
softmax_descriptor.GetMode()),
miopenStatusSuccess);
yTensor.data = handle.Read<T>(out_gpu, yTensor.data.size());
yTensorRef.data = handle.Read<T>(out_gpu_ref, yTensorRef.data.size());
mloSoftmaxForwardRunHost<T, Tref>(&xTensor.desc,
&yTensor.desc,
xTensor.data.data(),
outhost.data(),
alpha,
beta,
softmax_descriptor.GetAlgorithm(),
softmax_descriptor.GetMode());
double error = miopen::rms_range(yTensorRef.data, outhost);
const double tolerance = 1e-3;
EXPECT_TRUE(std::isfinite(error) && error <= tolerance)
<< "Outputs do not match each other. Error:" << error;
}
std::cerr << "Finished testing solution functions." << std::endl;
}
void TestRunSolutionsBackward(Handle& handle, const std::vector<miopenSolution_t>& solutions)
{
std::cerr << "Testing solution functions..." << std::endl;
miopenTensorDescriptor_t y_desc = &yTensor.desc;
miopenTensorDescriptor_t dy_desc = &dyTensor.desc;
miopenTensorDescriptor_t dx_desc = &dxTensor.desc;
const unsigned int numTensors = 3;
for(const auto& solution : solutions)
{
auto arguments = std::make_unique<miopenTensorArgument_t[]>(numTensors);
auto in1_gpu = handle.Write(yTensor.data);
auto in2_gpu = handle.Write(dyTensor.data);
auto out_gpu = handle.Write(dxTensor.data);
miopenTensorArgumentId_t names[numTensors] = {
miopenTensorSoftmaxY, miopenTensorSoftmaxDY, miopenTensorSoftmaxDX};
void* buffers[numTensors] = {in1_gpu.get(), in2_gpu.get(), out_gpu.get()};
miopenTensorDescriptor_t descriptors[numTensors] = {y_desc, dy_desc, dx_desc};
for(auto i = 0; i < numTensors; ++i)
{
arguments[i].id = names[i];
arguments[i].descriptor = &descriptors[i];
arguments[i].buffer = buffers[i];
}
std::cerr << "Run a solution." << std::endl;
EXPECT_EQUAL(
miopenRunSolution(&handle, solution, numTensors, arguments.get(), nullptr, 0),
miopenStatusSuccess);
float alpha = softmax_descriptor.GetAlpha();
float beta = softmax_descriptor.GetBeta();
// tensor<T> yTensorDup = yTensor;
tensor<T> dxTensorRef = tensor<T>{test_n, test_c, test_h, test_w};
// this is dx
auto out_gpu_ref = handle.Write(dxTensorRef.data);
// Run softmax in a usual way (which is tested) and compare results
EXPECT_EQUAL(miopenSoftmaxBackward_V2(&handle,
&alpha,
y_desc,
in1_gpu.get(),
dy_desc,
in2_gpu.get(),
&beta,
&dxTensorRef.desc,
out_gpu_ref.get(),
softmax_descriptor.GetAlgorithm(),
softmax_descriptor.GetMode()),
miopenStatusSuccess);
dxTensorRef.data = handle.Read<T>(out_gpu_ref, dxTensorRef.data.size());
// run softmax cpu
mloSoftmaxBackwardRunHost<T, Tref>(&yTensor.desc,
&dyTensor.desc,
yTensor.data.data(),
dyTensor.data.data(),
dinhost.data(),
alpha,
beta,
softmax_descriptor.GetAlgorithm(),
softmax_descriptor.GetMode());
double error = miopen::rms_range(dxTensorRef.data, dinhost);
const double tolerance = 1e-3;
std::cout << "error = " << error << std::endl;
EXPECT_TRUE(std::isfinite(error) && error <= tolerance)
<< "Outputs do not match each other. Error:" << error;
}
std::cerr << "Finished testing solution functions." << std::endl;
}
void Finalize(std::vector<miopenSolution_t>& solutions)
{
for(auto& solution : solutions)
EXPECT_EQUAL(miopenDestroySolution(solution), miopenStatusSuccess);
EXPECT_EQUAL(miopenDestroyProblem(problem), miopenStatusSuccess);
}
private:
void Initialize()
{
softmax_descriptor.SetParams(1.0f, 0.0f, softmax_algo, softmax_mode);
if(isForward)
{
auto gen_value_fwd = [](auto...) {
return prng::gen_descreet_uniform_sign<T>(0.1, 5.0);
};
xTensor = tensor<T>{test_n, test_c, test_h, test_w}.generate(gen_value_fwd);
yTensor = tensor<T>{test_n, test_c, test_h, test_w};
EXPECT_EQUAL(miopenCreateSoftmaxProblem(
&problem, &softmax_descriptor, miopenProblemDirectionForward),
miopenStatusSuccess);
outhost = std::vector<Tref>(yTensor.data.size(), static_cast<Tref>(0));
}
else
{
yTensor = tensor<T>{test_n, test_c, test_h, test_w};
dyTensor = tensor<T>{test_n, test_c, test_h, test_w};
const T Data_scale = static_cast<T>(0.1);
for(int i = 0; i < dyTensor.data.size(); i++)
{
dyTensor.data[i] =
Data_scale * prng::gen_A_to_B(static_cast<T>(-0.5), static_cast<T>(0.5));
}
for(int i = 0; i < yTensor.data.size(); i++)
{
yTensor.data[i] = prng::gen_A_to_B(static_cast<T>(-0.6), static_cast<T>(0.6));
}
dxTensor = tensor<T>{test_n, test_c, test_h, test_w};
dinhost = std::vector<Tref>(yTensor.data.size(), static_cast<Tref>(0));
EXPECT_EQUAL(miopenCreateSoftmaxProblem(
&problem, &softmax_descriptor, miopenProblemDirectionBackward),
miopenStatusSuccess);
}
AddTensorDescriptors();
}
private:
tensor<T> xTensor;
tensor<T> yTensor;
std::vector<Tref> outhost;
tensor<T> dxTensor;
tensor<T> dyTensor;
std::vector<Tref> dinhost;
SoftmaxDescriptor softmax_descriptor;
miopenProblem_t problem;
miopenSoftmaxAlgorithm_t softmax_algo;
miopenSoftmaxMode_t softmax_mode;
bool isForward;
const unsigned int test_n = 128;
const unsigned int test_c = 1;
const unsigned int test_h = 1;
const unsigned int test_w = 1500;
};
TEST(GPU_SoftmaxFind20_FP32, softmaxForward)
{
Handle& handle = get_handle();
SoftmaxFind20Test<float> test(true, MIOPEN_SOFTMAX_ACCURATE, MIOPEN_SOFTMAX_MODE_CHANNEL);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsForward(handle, solutions);
test.Finalize(solutions);
}
TEST(GPU_SoftmaxFind20_FP32, softmaxBackward_fp32)
{
Handle& handle = get_handle();
SoftmaxFind20Test<float> test(false, MIOPEN_SOFTMAX_ACCURATE, MIOPEN_SOFTMAX_MODE_CHANNEL);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsBackward(handle, solutions);
test.Finalize(solutions);
}
TEST(GPU_SoftmaxFind20_FP16, softmaxBackward_log_instance_mode_fp16)
{
Handle& handle = get_handle();
SoftmaxFind20Test<half> test(false, MIOPEN_SOFTMAX_LOG, MIOPEN_SOFTMAX_MODE_INSTANCE);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsBackward(handle, solutions);
test.Finalize(solutions);
}
TEST(GPU_SoftmaxFind20_FP16, softmaxBackward_log_channel_mode_fp16)
{
Handle& handle = get_handle();
SoftmaxFind20Test<half> test(false, MIOPEN_SOFTMAX_LOG, MIOPEN_SOFTMAX_MODE_CHANNEL);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsBackward(handle, solutions);
test.Finalize(solutions);
}
TEST(GPU_SoftmaxFind20_BFP16, softmaxBackward_log_instance_mode_bfp16)
{
Handle& handle = get_handle();
SoftmaxFind20Test<bfloat16> test(false, MIOPEN_SOFTMAX_LOG, MIOPEN_SOFTMAX_MODE_INSTANCE);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsBackward(handle, solutions);
test.Finalize(solutions);
}
TEST(GPU_SoftmaxFind20_BFP16, softmaxBackward_log_channel_mode_bfp16)
{
Handle& handle = get_handle();
SoftmaxFind20Test<bfloat16> test(false, MIOPEN_SOFTMAX_LOG, MIOPEN_SOFTMAX_MODE_CHANNEL);
std::vector<miopenSolution_t> solutions = test.TestFindSolutions(handle);
test.TestSolutionAttributes(solutions);
test.TestRunSolutionsBackward(handle, solutions);
test.Finalize(solutions);
}