#include "engine/framework/sampling/torch_random.h" #include #include #include #include #include #include namespace { void require_close(float actual, float expected, float tolerance, const char * label) { if (std::fabs(actual - expected) > tolerance) { throw std::runtime_error( std::string(label) + " mismatch: expected " + std::to_string(expected) + ", got " + std::to_string(actual)); } } void require_vector_close( const std::vector & actual, const std::vector & expected, float tolerance, const char * label) { if (actual.size() != expected.size()) { throw std::runtime_error(std::string(label) + " size mismatch"); } for (size_t index = 0; index < actual.size(); ++index) { require_close(actual[index], expected[index], tolerance, label); } } void test_float32_matches_torch_cuda() { const std::vector expected_seed_1234 = { -1.61649048F, 0.56845516F, -0.510224819F, -0.911339402F, -1.15551639F, -0.22615087F, -1.2891326F, 1.065382F, -0.7166605F, -0.533334374F, 0.207757875F, -0.979843318F, 0.744693458F, -0.239484429F, 0.27371496F, 0.092008315F, }; const auto actual = engine::sampling::generate_torch_cuda_randn( expected_seed_1234.size(), 1234, engine::sampling::TorchRandnPrecision::Float32); require_vector_close(actual, expected_seed_1234, 2.0e-6F, "float32 torch_cuda_randn"); const auto extended = engine::sampling::generate_torch_cuda_randn( 300, 1234, engine::sampling::TorchRandnPrecision::Float32); const std::vector> expected_positions = { {16, -0.803610802F}, {17, -1.6377064F}, {31, -0.300402969F}, {32, -0.251393795F}, {63, -0.924830973F}, {64, 0.799798131F}, {127, -0.167921364F}, {128, -0.322486848F}, {255, -1.76037288F}, {256, 0.534284174F}, {299, -0.986868858F}, }; for (const auto & [index, expected] : expected_positions) { require_close(extended[index], expected, 2.0e-6F, "float32 torch_cuda_randn high index"); } } void test_bfloat16_matches_torch_cuda() { const std::vector expected_seed_5678 = { -0.65625F, -0.5625F, 0.384765625F, -0.151367188F, 0.7421875F, 0.244140625F, 0.609375F, 0.00321960449F, -0.46875F, 0.306640625F, -0.225585938F, -0.9140625F, 0.7734375F, 0.120117188F, 0.52734375F, -0.5078125F, }; const auto actual = engine::sampling::generate_torch_cuda_randn( expected_seed_5678.size(), 5678, engine::sampling::TorchRandnPrecision::BFloat16); require_vector_close(actual, expected_seed_5678, 0.0F, "bfloat16 torch_cuda_randn"); const auto extended = engine::sampling::generate_torch_cuda_randn( 300, 1234, engine::sampling::TorchRandnPrecision::BFloat16); const std::vector> expected_positions = { {16, -0.8046875F}, {17, -1.640625F}, {31, -0.30078125F}, {32, -0.251953125F}, {63, -0.92578125F}, {64, 0.80078125F}, {127, -0.16796875F}, {128, -0.322265625F}, {255, -1.7578125F}, {256, 0.53515625F}, {299, -0.98828125F}, }; for (const auto & [index, expected] : expected_positions) { require_close(extended[index], expected, 0.0F, "bfloat16 torch_cuda_randn high index"); } } void test_fill_matches_vector_api() { std::vector filled(257, 0.0F); engine::sampling::fill_torch_cuda_randn( filled.data(), filled.size(), 1, engine::sampling::TorchRandnPrecision::Float32); const auto generated = engine::sampling::generate_torch_cuda_randn( filled.size(), 1, engine::sampling::TorchRandnPrecision::Float32); require_vector_close(filled, generated, 0.0F, "fill/vector torch_cuda_randn"); } void test_start_index_matches_full_generation_slice() { const auto full = engine::sampling::generate_torch_cuda_randn( 300, 1234, engine::sampling::TorchRandnPrecision::Float32); const auto sliced = engine::sampling::generate_torch_cuda_randn( 32, 1234, engine::sampling::TorchRandnPrecision::Float32, 128); for (size_t index = 0; index < sliced.size(); ++index) { require_close(sliced[index], full[128 + index], 0.0F, "torch_cuda_randn start index"); } } void test_uniform_matches_torch_cuda() { const std::vector expected_seed_1234 = { 0.127207950F, 0.816736281F, 0.543999255F, 0.660079062F, 0.272055715F, 0.973670244F, 0.390334547F, 0.339447320F, 0.545121968F, 0.731194019F, 0.386437327F, 0.595885396F, 0.757832348F, 0.212593451F, 0.719796896F, 0.984495401F, }; const auto actual = engine::sampling::generate_torch_cuda_uniform(expected_seed_1234.size(), 1234); require_vector_close(actual, expected_seed_1234, 1.0e-7F, "float32 torch_cuda_uniform"); const auto extended = engine::sampling::generate_torch_cuda_uniform(300, 1234); const std::vector> expected_positions = { {16, 0.551820338F}, {17, 0.0980522931F}, {31, 0.388187110F}, {32, 0.797672272F}, {63, 0.546383321F}, {64, 0.694423795F}, {127, 0.768725276F}, {128, 0.798199594F}, {255, 0.210613519F}, {256, 0.294832915F}, {299, 0.588956773F}, }; for (const auto & [index, expected] : expected_positions) { require_close(extended[index], expected, 1.0e-7F, "float32 torch_cuda_uniform high index"); } const auto full = engine::sampling::generate_torch_cuda_uniform(300, 5678); const auto sliced = engine::sampling::generate_torch_cuda_uniform(32, 5678, 128); for (size_t index = 0; index < sliced.size(); ++index) { require_close(sliced[index], full[128 + index], 0.0F, "torch_cuda_uniform start index"); } } void test_tensor_iterator_exponential_matches_torch_cuda() { constexpr uint64_t seed = 1234; constexpr uint64_t vocab_size = 168565; constexpr uint64_t call_index = 104; constexpr int64_t multiprocessor_count = 128; constexpr int64_t max_threads_per_multiprocessor = 1536; const std::vector> expected_positions = { {167785, 0.301640809F}, {168248, 0.333908796F}, {156088, 0.690724790F}, {162701, 0.975778222F}, {160228, 3.30194235F}, {168039, 0.803459823F}, {163896, 0.841065466F}, {167841, 1.16925406F}, {161373, 0.112876698F}, }; for (const auto & [index, expected] : expected_positions) { const float actual = engine::sampling::torch_cuda_tensor_iterator_exponential_element( seed, vocab_size, index, call_index, multiprocessor_count, max_threads_per_multiprocessor); require_close(actual, expected, 2.0e-6F, "torch_cuda_tensor_iterator_exponential"); } } void test_empty_null_output_is_allowed() { engine::sampling::fill_torch_cuda_randn( nullptr, 0, 0, engine::sampling::TorchRandnPrecision::Float32); engine::sampling::fill_torch_cuda_uniform(nullptr, 0, 0); } } // namespace int main() { try { test_float32_matches_torch_cuda(); test_bfloat16_matches_torch_cuda(); test_fill_matches_vector_api(); test_start_index_matches_full_generation_slice(); test_uniform_matches_torch_cuda(); test_tensor_iterator_exponential_matches_torch_cuda(); test_empty_null_output_is_allowed(); } catch (const std::exception & error) { std::cerr << error.what() << '\n'; return 1; } std::cout << "torch_random_test passed\n"; return 0; }