#include #include #include #include #include #include #include #include #include #include #include #include #include #include "test.hpp" #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif // An improved async, that doesn't block template std::future::type> detach_async(Function&& f, bool parallel = true) { if(parallel) { using result_type = typename std::result_of::type; std::packaged_task task(std::forward(f)); auto fut = task.get_future(); std::thread(std::move(task)).detach(); return std::move(fut); } else { return std::async(std::launch::deferred, std::forward(f)); } } struct auto_print { static void set_terminate_handler(const std::string& name) { static std::string pname; pname = name; std::set_terminate(+[] { std::cout << "FAILED: " << pname << std::endl; try { std::rethrow_exception(std::current_exception()); } catch(const std::exception& e) { std::cout << " what(): " << e.what() << std::endl; } std::cout << std::endl; for(auto&& handle : auto_print::handlers) handle(); }); } static std::array, 2> handlers; int index; template auto_print(T& x, int i) : index(i) { handlers[index] = [&x] { std::cout << x << std::endl; }; } ~auto_print() { handlers[index] = [] {}; } }; std::array, 2> auto_print::handlers = {}; void compile_check(migraph::program& p, const migraph::target& t) { auto name = t.name(); auto s = p.get_shape(); std::stringstream ss; p.compile(t, migraph::tracer{ss}); if(p.get_shape() != s) { std::cout << ss.str() << std::endl; throw std::runtime_error("Compiling program with " + name + " alters its shape"); } } template migraph::argument run_cpu() { V v; auto p = v.create_program(); auto_print pp{p, 0}; compile_check(p, migraph::cpu::cpu_target{}); migraph::program::parameter_map m; int seed = 0; for(auto&& x : p.get_parameter_shapes()) { m[x.first] = migraph::generate_argument(x.second, seed++); } return p.eval(m); } template migraph::argument run_gpu() { V v; auto p = v.create_program(); auto_print pp{p, 1}; compile_check(p, migraph::gpu::target{}); migraph::program::parameter_map m; int seed = 0; for(auto&& x : p.get_parameter_shapes()) { m[x.first] = migraph::gpu::to_gpu(migraph::generate_argument(x.second, seed++)); } return migraph::gpu::from_gpu(p.eval(m)); } void verify_args(const std::string& name, const migraph::argument& cpu_arg, const migraph::argument& gpu_arg) { visit_all(cpu_arg, gpu_arg)([&](auto cpu, auto gpu) { if(not migraph::verify_range(cpu, gpu)) { // TODO: Check for nans std::cout << "FAILED: " << name << std::endl; // std::cout << cpu << std::endl; // std::cout << gpu << std::endl; if(migraph::range_zero(cpu)) std::cout << "Cpu data is all zeros" << std::endl; if(migraph::range_zero(gpu)) std::cout << "Gpu data is all zeros" << std::endl; auto idx = migraph::mismatch_idx(cpu, gpu, migraph::float_equal); if(idx < migraph::range_distance(cpu)) { std::cout << "Mismatch at " << idx << ": " << cpu[idx] << " != " << gpu[idx] << std::endl; } auto cpu_nan_idx = find_idx(cpu, migraph::not_finite); if(cpu_nan_idx >= 0) std::cout << "Non finite number found in cpu at " << cpu_nan_idx << ": " << cpu[cpu_nan_idx] << std::endl; auto gpu_nan_idx = find_idx(gpu, migraph::not_finite); if(gpu_nan_idx >= 0) std::cout << "Non finite number found in gpu at " << gpu_nan_idx << ": " << gpu[gpu_nan_idx] << std::endl; } }); } template void verify_program() { auto_print::set_terminate_handler(migraph::get_type_name()); auto cpu_arg_f = detach_async([] { return run_cpu(); }); auto gpu_arg = run_gpu(); verify_args(migraph::get_type_name(), cpu_arg_f.get(), gpu_arg); std::set_terminate(nullptr); } struct test_literals { migraph::program create_program() const { migraph::program p; auto input = p.add_literal( generate_literal(migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}})); auto weights = p.add_literal( generate_literal(migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}})); auto conv = p.add_instruction(migraph::convolution{}, input, weights); p.add_instruction(migraph::activation{"relu"}, conv); return p; } }; struct test_add { migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {3}}; auto x = p.add_parameter("x", s); auto y = p.add_parameter("y", s); p.add_instruction(migraph::add{}, x, y); return p; } }; struct test_add_broadcast { migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {3}}; auto x = p.add_parameter("x", {migraph::shape::float_type, {2, 2, 3}}); auto y = p.add_parameter("y", {migraph::shape::float_type, {2, 2}}); auto by = p.add_instruction(migraph::broadcast{0}, x, y); p.add_instruction(migraph::add{}, x, by); return p; } }; struct test_add_broadcast2 { migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {3}}; auto x = p.add_parameter("x", {migraph::shape::float_type, {2, 3, 4}}); auto y = p.add_parameter("y", {migraph::shape::float_type, {3}}); auto by = p.add_instruction(migraph::broadcast{1}, x, y); p.add_instruction(migraph::add{}, x, by); return p; } }; struct test_conv_relu { migraph::program create_program() const { migraph::program p; auto input = p.add_parameter("x", migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}}); auto weights = p.add_parameter("w", migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}}); auto conv = p.add_instruction(migraph::convolution{}, input, weights); p.add_instruction(migraph::activation{"relu"}, conv); return p; } }; struct test_add_relu { migraph::program create_program() const { migraph::program p; auto x = p.add_parameter("x", migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}}); auto y = p.add_parameter("y", migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}}); auto add = p.add_instruction(migraph::add{}, x, y); p.add_instruction(migraph::activation{"relu"}, add); return p; } }; struct test_conv_pooling { migraph::program create_program() const { migraph::program p; auto input = p.add_parameter("x", migraph::shape{migraph::shape::float_type, {4, 3, 32, 32}}); auto weights = p.add_parameter("w", migraph::shape{migraph::shape::float_type, {4, 3, 3, 3}}); auto conv = p.add_instruction(migraph::convolution{}, input, weights); auto pooling = p.add_instruction(migraph::pooling{"max"}, conv); p.add_instruction(migraph::activation{"relu"}, pooling); return p; } }; struct test_gemm { migraph::program create_program() const { migraph::program p; auto a = p.add_parameter("a", migraph::shape{migraph::shape::float_type, {4, 5}}); auto b = p.add_parameter("b", migraph::shape{migraph::shape::float_type, {5, 3}}); p.add_instruction(migraph::gemm{}, a, b); return p; } }; struct test_gemm_ld { migraph::program create_program() const { migraph::program p; auto a = p.add_parameter("a", migraph::shape{migraph::shape::float_type, {4, 5}, {10, 1}}); auto b = p.add_parameter("b", migraph::shape{migraph::shape::float_type, {5, 3}, {20, 1}}); p.add_instruction(migraph::gemm{}, a, b); return p; } }; struct test_gemm_transposeb { migraph::program create_program() const { migraph::program p; auto a = p.add_parameter("a", migraph::shape{migraph::shape::float_type, {4, 5}}); auto b = p.add_parameter("b", migraph::shape{migraph::shape::float_type, {3, 5}}); auto bt = p.add_instruction(migraph::transpose{{1, 0}}, b); p.add_instruction(migraph::gemm{}, a, bt); return p; } }; struct test_gemm_transposea { migraph::program create_program() const { migraph::program p; auto a = p.add_parameter("a", migraph::shape{migraph::shape::float_type, {5, 4}}); auto b = p.add_parameter("b", migraph::shape{migraph::shape::float_type, {5, 3}}); auto at = p.add_instruction(migraph::transpose{{1, 0}}, a); p.add_instruction(migraph::gemm{}, at, b); return p; } }; struct test_gemm_transposeab { migraph::program create_program() const { migraph::program p; auto a = p.add_parameter("a", migraph::shape{migraph::shape::float_type, {5, 4}}); auto b = p.add_parameter("b", migraph::shape{migraph::shape::float_type, {3, 5}}); auto at = p.add_instruction(migraph::transpose{{1, 0}}, a); auto bt = p.add_instruction(migraph::transpose{{1, 0}}, b); p.add_instruction(migraph::gemm{}, at, bt); return p; } }; struct test_contiguous { migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {4, 4, 4, 3}, {48, 4, 1, 16}}; auto x = p.add_parameter("x", s); p.add_instruction(migraph::contiguous{}, x); EXPECT(p.get_shape().standard()); return p; } }; struct test_transpose { migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {4, 3, 4, 4}}; auto x = p.add_parameter("x", s); std::vector perm = {0, 2, 3, 1}; auto l = p.add_instruction(migraph::transpose{perm}, x); p.add_instruction(migraph::contiguous{}, l); return p; } }; struct test_batchnorm_inference_2 { const size_t width = 14; const size_t height = 14; const size_t channels = 256; const size_t batches = 1; migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {batches, channels, height, width}}; migraph::shape vars{migraph::shape::float_type, {channels}}; auto x = p.add_parameter("x", s); auto scale = p.add_literal(migraph::abs(migraph::generate_literal(vars, 1))); auto bias = p.add_literal(migraph::abs(migraph::generate_literal(vars, 2))); auto mean = p.add_literal(migraph::abs(migraph::generate_literal(vars, 3))); auto variance = p.add_literal(migraph::abs(migraph::generate_literal(vars, 4))); p.add_instruction(migraph::batch_norm_inference{}, x, scale, bias, mean, variance); return p; } }; struct test_batchnorm_inference { const size_t width = 3; const size_t height = 3; const size_t channels = 3; const size_t batches = 4; migraph::program create_program() const { migraph::program p; migraph::shape s{migraph::shape::float_type, {batches, channels, height, width}}; migraph::shape vars{migraph::shape::float_type, {channels}}; auto x = p.add_parameter("x", s); auto scale = p.add_literal(migraph::abs(migraph::generate_literal(vars, 1))); auto bias = p.add_literal(migraph::abs(migraph::generate_literal(vars, 2))); auto mean = p.add_literal(migraph::abs(migraph::generate_literal(vars, 3))); auto variance = p.add_literal(migraph::abs(migraph::generate_literal(vars, 4))); p.add_instruction(migraph::batch_norm_inference{}, x, scale, bias, mean, variance); return p; } }; struct test_conv_bn_relu_pooling { migraph::program create_program() const { migraph::program p; migraph::shape xs{migraph::shape::float_type, {1, 3, 224, 224}}; migraph::shape ws{migraph::shape::float_type, {64, 3, 7, 7}}; migraph::shape vars{migraph::shape::float_type, {64}}; auto x = p.add_parameter("x", xs); auto w = p.add_parameter("w", ws); auto conv = p.add_instruction(migraph::convolution{{3, 3}, {2, 2}, {1, 1}}, x, w); auto scale = p.add_literal(migraph::abs(migraph::generate_literal(vars, 1))); auto bias = p.add_literal(migraph::abs(migraph::generate_literal(vars, 2))); auto mean = p.add_literal(migraph::abs(migraph::generate_literal(vars, 3))); auto variance = p.add_literal(migraph::abs(migraph::generate_literal(vars, 4))); auto bn = p.add_instruction(migraph::batch_norm_inference{}, conv, scale, bias, mean, variance); auto relu = p.add_instruction(migraph::activation{"relu"}, bn); p.add_instruction(migraph::pooling{"average", {1, 1}, {2, 2}, {3, 3}}, relu); return p; } }; int main() { verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); // verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); verify_program(); }